diff --git a/EvoEngine_App/CMakeLists.txt b/EvoEngine_App/CMakeLists.txt index fba122ce..f7c7c394 100644 --- a/EvoEngine_App/CMakeLists.txt +++ b/EvoEngine_App/CMakeLists.txt @@ -3,6 +3,14 @@ message("=========Checking Apps=========") add_custom_target(AppResourceCopy) add_dependencies(AppResourceCopy EvoEngine_SDK) +string (FIND "${EVOENGINE_DEFS}" "CUDA" CUDA_SUBSTRING_INDEX) +if(NOT CUDA_SUBSTRING_INDEX EQUAL -1) + mark_as_advanced(CUDA_SDK_ROOT_DIR) + enable_language(CUDA) + message("CUDA enabled.") +endif() + + evoengine_copy_resources(AppResourceCopy ${CMAKE_CURRENT_BINARY_DIR}) evoengine_clear_shader_binaries(AppResourceCopy) add_custom_command(TARGET AppResourceCopy POST_BUILD diff --git a/EvoEngine_Plugins/CMakeLists.txt b/EvoEngine_Plugins/CMakeLists.txt index 1079431d..fea4c630 100644 --- a/EvoEngine_Plugins/CMakeLists.txt +++ b/EvoEngine_Plugins/CMakeLists.txt @@ -43,10 +43,11 @@ function(register_evoengine_plugin plugin_name default_enable) set(EVOENGINE_PLUGINS_RESOURCES ${EVOENGINE_PLUGINS_RESOURCES} PARENT_SCOPE) endfunction() +register_evoengine_plugin(CudaModule ON) + if (WIN32) register_evoengine_plugin(MeshRepair ON) register_evoengine_plugin(TextureBaking ON) - register_evoengine_plugin(CudaModule ON) register_evoengine_plugin(Gpr ON) register_evoengine_plugin(BillboardClouds ON) endif() diff --git a/EvoEngine_Plugins/CudaModule/CMakeLists.txt b/EvoEngine_Plugins/CudaModule/CMakeLists.txt index 54e213e3..f66b2430 100644 --- a/EvoEngine_Plugins/CudaModule/CMakeLists.txt +++ b/EvoEngine_Plugins/CudaModule/CMakeLists.txt @@ -13,6 +13,7 @@ endif() message("Found CUDA.") +set(CMAKE_CUDA_ARCHITECTURES 75-real 75-virtual) mark_as_advanced(CUDA_SDK_ROOT_DIR) enable_language(CUDA) @@ -53,16 +54,16 @@ set(CUDA_MODULE_INCLUDES include_directories(${EVOENGINE_SDK_INCLUDES}) include_directories(${CUDA_MODULE_INCLUDES}) -cuda_compile_and_embed(CAMERA_RENDERING_PTX ${RAY_TRACER_DIRECTORY}/src/ptx/CameraRendering.cu) -cuda_compile_and_embed(ILLUMINATION_ESTIMATION_PTX ${RAY_TRACER_DIRECTORY}/src/ptx/IlluminationEstimation.cu) -cuda_compile_and_embed(POINT_CLOUD_SCANNING_PTX ${RAY_TRACER_DIRECTORY}/src/ptx/PointCloudScanning.cu) +cuda_compile_and_embed(camera_rendering_ptx ${RAY_TRACER_DIRECTORY}/src/ptx/CameraRendering.cu) +cuda_compile_and_embed(illumination_estimation_ptx ${RAY_TRACER_DIRECTORY}/src/ptx/IlluminationEstimation.cu) +cuda_compile_and_embed(point_cloud_scanning_ptx ${RAY_TRACER_DIRECTORY}/src/ptx/PointCloudScanning.cu) add_library(CudaModulePlugin STATIC #Default - ${CAMERA_RENDERING_PTX} - ${ILLUMINATION_ESTIMATION_PTX} - ${POINT_CLOUD_SCANNING_PTX} + ${camera_rendering_ptx} + ${illumination_estimation_ptx} + ${point_cloud_scanning_ptx} #C++ ${RAY_TRACER_HEADERS} diff --git a/EvoEngine_Plugins/CudaModule/include/RayTracer/OptiXRayTracer.hpp b/EvoEngine_Plugins/CudaModule/include/RayTracer/OptiXRayTracer.hpp index 08448160..e7a989aa 100644 --- a/EvoEngine_Plugins/CudaModule/include/RayTracer/OptiXRayTracer.hpp +++ b/EvoEngine_Plugins/CudaModule/include/RayTracer/OptiXRayTracer.hpp @@ -89,7 +89,7 @@ struct CameraProperties { void SetDenoiserStrength(float value); - void Resize(const glm::uvec2& newSize); + void Resize(const glm::uvec2& new_size); void Set(const glm::vec3& position, const glm::quat& rotation); void SetSkybox(const std::shared_ptr& cubemap); @@ -235,7 +235,8 @@ struct RayTracedMaterial { void UploadForSbt(); - void BindTexture(unsigned int id, cudaGraphicsResource_t& graphics_resource, cudaTextureObject_t& texture_object); + static void BindTexture(unsigned int id, cudaGraphicsResource_t& graphics_resource, + cudaTextureObject_t& texture_object); }; enum class CurveMode { Linear, Quadratic, Cubic }; @@ -334,10 +335,11 @@ class OptiXRayTracer { CameraProperties& camera_properties, const RayProperties& ray_properties); void EstimateIllumination(const size_t& size, const EnvironmentProperties& environment_properties, - const RayProperties& ray_properties, CudaBuffer& light_probes, unsigned seed, + const RayProperties& ray_properties, const CudaBuffer& light_probes, unsigned seed, float push_normal_distance); - void ScanPointCloud(const size_t& size, const EnvironmentProperties& environment_properties, CudaBuffer& samples); + void ScanPointCloud(const size_t& size, const EnvironmentProperties& environment_properties, + const CudaBuffer& samples); OptiXRayTracer(); ~OptiXRayTracer(); @@ -392,11 +394,11 @@ class OptiXRayTracer { /*! assembles the full pipeline of all programs */ void AssemblePipelines(); - void CreateRayGenProgram(RayTracerPipeline& targetPipeline, char entryFunctionName[]) const; + void CreateRayGenProgram(RayTracerPipeline& target_pipeline, char entry_function_name[]) const; - void CreateModule(RayTracerPipeline& targetPipeline, char ptxCode[], char launchParamsName[]) const; + void CreateModule(RayTracerPipeline& target_pipeline, char ptx_code[], char launch_params_name[]) const; - void AssemblePipeline(RayTracerPipeline& targetPipeline) const; + void AssemblePipeline(RayTracerPipeline& target_pipeline) const; #pragma endregion diff --git a/EvoEngine_Plugins/CudaModule/src/OptiXRayTracer.cu b/EvoEngine_Plugins/CudaModule/src/OptiXRayTracer.cu index 01b15385..ebbd1fa7 100644 --- a/EvoEngine_Plugins/CudaModule/src/OptiXRayTracer.cu +++ b/EvoEngine_Plugins/CudaModule/src/OptiXRayTracer.cu @@ -26,45 +26,45 @@ using namespace evo_engine; void CameraProperties::Set(const glm::vec3 &position, const glm::quat &rotation) { - auto newFront = glm::normalize(rotation * glm::vec3(0, 0, -1)); - auto newUp = glm::normalize(rotation * glm::vec3(0, 1, 0)); + const auto new_front = glm::normalize(rotation * glm::vec3(0, 0, -1)); + const auto new_up = glm::normalize(rotation * glm::vec3(0, 1, 0)); const float aspect = static_cast(target_frame.size.x) / static_cast(target_frame.size.y); const auto projection = glm::perspective(glm::radians(fov * 0.5f), aspect, 0.1f, 100.f); - const auto view = glm::lookAt(position, position + newFront, newUp); - auto inv = glm::inverse(projection * view); + const auto view = glm::lookAt(position, position + new_front, new_up); + const auto inv_proj_view = glm::inverse(projection * view); camera_position = position; - if (inv != inverse_projection_view) + if (inv_proj_view != inverse_projection_view) modified = true; - inverse_projection_view = inv; + inverse_projection_view = inv_proj_view; - const float cosFovY = glm::radians(fov * 0.5f); + const float cos_fov_y = glm::radians(fov * 0.5f); - horizontal_direction = cosFovY * aspect * glm::normalize(glm::cross(newFront, newUp)); - vertical_direction = cosFovY * glm::normalize(newUp); + horizontal_direction = cos_fov_y * aspect * glm::normalize(glm::cross(new_front, new_up)); + vertical_direction = cos_fov_y * glm::normalize(new_up); } -void CameraProperties::Resize(const glm::uvec2 &newSize) { - if (target_frame.size == newSize) +void CameraProperties::Resize(const glm::uvec2 &new_size) { + if (target_frame.size == new_size) return; - target_frame.size = newSize; + target_frame.size = new_size; modified = true; if (denoiser) { OPTIX_CHECK(optixDenoiserDestroy(denoiser)); }; // ------------------------------------------------------------------ // create the denoiser: - OptixDenoiserOptions denoiserOptions = {}; + constexpr OptixDenoiserOptions denoiser_options = {}; OPTIX_CHECK(optixDenoiserCreate(CudaModule::GetRayTracer()->optix_device_context_, OPTIX_DENOISER_MODEL_KIND_LDR, - &denoiserOptions, &denoiser)); + &denoiser_options, &denoiser)); // .. then compute and allocate memory resources for the denoiser - OptixDenoiserSizes denoiserReturnSizes; + OptixDenoiserSizes denoiser_return_sizes; OPTIX_CHECK( - optixDenoiserComputeMemoryResources(denoiser, target_frame.size.x, target_frame.size.y, &denoiserReturnSizes)); + optixDenoiserComputeMemoryResources(denoiser, target_frame.size.x, target_frame.size.y, &denoiser_return_sizes)); - denoiser_scratch.Resize(std::max(denoiserReturnSizes.withOverlapScratchSizeInBytes, - denoiserReturnSizes.withoutOverlapScratchSizeInBytes)); + denoiser_scratch.Resize(std::max(denoiser_return_sizes.withOverlapScratchSizeInBytes, + denoiser_return_sizes.withoutOverlapScratchSizeInBytes)); - denoiser_state.Resize(denoiserReturnSizes.stateSizeInBytes); + denoiser_state.Resize(denoiser_return_sizes.stateSizeInBytes); // ------------------------------------------------------------------ // resize our cuda frame buffer denoised_buffer.Resize(target_frame.size.x * target_frame.size.y * sizeof(glm::vec4)); @@ -74,23 +74,21 @@ void CameraProperties::Resize(const glm::uvec2 &newSize) { // update the launch parameters that we'll pass to the optix // launch: - target_frame.color_buffer = (glm::vec4 *)frame_buffer_color.DevicePointer(); - target_frame.normal_buffer = (glm::vec4 *)frame_buffer_normal.DevicePointer(); - target_frame.albedo_buffer = (glm::vec4 *)frame_buffer_albedo.DevicePointer(); + target_frame.color_buffer = reinterpret_cast(frame_buffer_color.DevicePointer()); + target_frame.normal_buffer = reinterpret_cast(frame_buffer_normal.DevicePointer()); + target_frame.albedo_buffer = reinterpret_cast(frame_buffer_albedo.DevicePointer()); // ------------------------------------------------------------------ - OPTIX_CHECK(optixDenoiserSetup(denoiser, 0, target_frame.size.x, target_frame.size.y, denoiser_state.DevicePointer(), - denoiser_state.size_in_bytes, denoiser_scratch.DevicePointer(), - denoiser_scratch.size_in_bytes)); + OPTIX_CHECK(optixDenoiserSetup(denoiser, nullptr, target_frame.size.x, target_frame.size.y, + denoiser_state.DevicePointer(), denoiser_state.size_in_bytes, + denoiser_scratch.DevicePointer(), denoiser_scratch.size_in_bytes)); } -void CameraProperties::SetFov(float value) { +void CameraProperties::SetFov(const float value) { modified = true; fov = value; } -const char *OutputTypes[]{"Color", "Normal", "Albedo", "Depth"}; - void CameraProperties::OnInspect() { if (ImGui::TreeNode("Camera Properties")) { if (ImGui::Checkbox("Accumulate", &accumulate)) { @@ -99,9 +97,10 @@ void CameraProperties::OnInspect() { if (ImGui::DragFloat("Gamma", &gamma, 0.01f, 0.1f, 5.0f)) { SetGamma(gamma); } - int outputType = (int)output_type; - if (ImGui::Combo("Output Type", &outputType, OutputTypes, IM_ARRAYSIZE(OutputTypes))) { - output_type = static_cast(outputType); + const char *output_types[]{"Color", "Normal", "Albedo", "Depth"}; + int type = static_cast(output_type); + if (ImGui::Combo("Output Type", &type, output_types, IM_ARRAYSIZE(output_types))) { + output_type = static_cast(type); modified = true; } if (ImGui::DragFloat("Max Distance", &max_distance, 0.1f, 0.1f, 10000.0f)) { @@ -124,42 +123,41 @@ void CameraProperties::OnInspect() { } } -void CameraProperties::SetDenoiserStrength(float value) { +void CameraProperties::SetDenoiserStrength(const float value) { denoiser_strength = glm::clamp(value, 0.0f, 1.0f); modified = true; } -void CameraProperties::SetGamma(float value) { +void CameraProperties::SetGamma(const float value) { modified = true; gamma = value; } -void CameraProperties::SetOutputType(OutputType value) { +void CameraProperties::SetOutputType(const OutputType value) { modified = true; output_type = value; } -void CameraProperties::SetAperture(float value) { +void CameraProperties::SetAperture(const float value) { modified = true; aperture = value; } -void CameraProperties::SetFocalLength(float value) { +void CameraProperties::SetFocalLength(const float value) { modified = true; focal_length = value; } -void CameraProperties::SetMaxDistance(float value) { +void CameraProperties::SetMaxDistance(const float value) { max_distance = value; modified = true; } -const char *EnvironmentalLightingTypes[]{"Scene", "Skydome", "SingleLightSource"}; - void EnvironmentProperties::OnInspect() { static int type = 0; - if (ImGui::Combo("Environment Lighting", &type, EnvironmentalLightingTypes, - IM_ARRAYSIZE(EnvironmentalLightingTypes))) { + const char *environmental_lighting_types[]{"Scene", "Skydome", "SingleLightSource"}; + if (ImGui::Combo("Environment Lighting", &type, environmental_lighting_types, + IM_ARRAYSIZE(environmental_lighting_types))) { environmental_lighting_type = static_cast(type); } if (environmental_lighting_type == EnvironmentalLightingType::Skydome) { @@ -188,7 +186,7 @@ void EnvironmentProperties::OnInspect() { if (ImGui::DragInt("Samples light", &atmosphere.num_samples_light, 1, 128)) { atmosphere.num_samples_light = glm::clamp(atmosphere.num_samples_light, 1, 128); } - static glm::vec3 angles = glm::vec3(90, 0, 0); + static auto angles = glm::vec3(90, 0, 0); if (ImGui::DragFloat3("Sun angle", &angles.x, 1.0f)) { sun_direction = glm::quat(glm::radians(angles)) * glm::vec3(0, 0, -1); } @@ -241,21 +239,21 @@ bool OptiXRayTracer::RenderToCamera(const EnvironmentProperties &environment_pro if (!has_acceleration_structure_) return false; BuildSbt(); - bool statusChanged = false; + bool status_changed = false; if (scene_modified) - statusChanged = true; + status_changed = true; camera_rendering_launch_params_.camera_properties = camera_properties; - statusChanged = statusChanged || camera_properties.modified; + status_changed = status_changed || camera_properties.modified; camera_properties.modified = false; if (camera_rendering_launch_params_.ray_tracer_properties.environment.Changed(environment_properties)) { camera_rendering_launch_params_.ray_tracer_properties.environment = environment_properties; - statusChanged = true; + status_changed = true; } if (camera_rendering_launch_params_.ray_tracer_properties.ray_properties.Changed(ray_properties)) { camera_rendering_launch_params_.ray_tracer_properties.ray_properties = ray_properties; - statusChanged = true; + status_changed = true; } - if (!camera_rendering_launch_params_.camera_properties.accumulate || statusChanged) { + if (!camera_rendering_launch_params_.camera_properties.accumulate || status_changed) { camera_rendering_launch_params_.camera_properties.target_frame.frame_id = 0; camera_properties.target_frame.frame_id = 0; } @@ -277,81 +275,81 @@ bool OptiXRayTracer::RenderToCamera(const EnvironmentProperties &environment_pro #pragma endregion CUDA_SYNC_CHECK(); #pragma region Bind output texture - cudaArray_t outputArray; + cudaArray_t output_array; CUDA_CHECK(GetMipmappedArrayLevel( - &outputArray, camera_rendering_launch_params_.camera_properties.target_image->mipmapped_image_array, 0)); + &output_array, camera_rendering_launch_params_.camera_properties.target_image->mipmapped_image_array, 0)); #pragma endregion #pragma region Copy results to output texture - OptixImage2D inputLayer[3]; - inputLayer[0].data = camera_rendering_launch_params_.camera_properties.frame_buffer_color.DevicePointer(); + OptixImage2D input_layer[3]; + input_layer[0].data = camera_rendering_launch_params_.camera_properties.frame_buffer_color.DevicePointer(); /// Width of the image (in pixels) - inputLayer[0].width = camera_rendering_launch_params_.camera_properties.target_frame.size.x; + input_layer[0].width = camera_rendering_launch_params_.camera_properties.target_frame.size.x; /// Height of the image (in pixels) - inputLayer[0].height = camera_rendering_launch_params_.camera_properties.target_frame.size.y; + input_layer[0].height = camera_rendering_launch_params_.camera_properties.target_frame.size.y; /// Stride between subsequent rows of the image (in bytes). - inputLayer[0].rowStrideInBytes = + input_layer[0].rowStrideInBytes = camera_rendering_launch_params_.camera_properties.target_frame.size.x * sizeof(glm::vec4); /// Stride between subsequent pixels of the image (in bytes). /// For now, only 0 or the value that corresponds to a dense packing of pixels /// (no gaps) is supported. - inputLayer[0].pixelStrideInBytes = sizeof(glm::vec4); + input_layer[0].pixelStrideInBytes = sizeof(glm::vec4); /// Pixel format. - inputLayer[0].format = OPTIX_PIXEL_FORMAT_FLOAT4; + input_layer[0].format = OPTIX_PIXEL_FORMAT_FLOAT4; // .................................................................. - inputLayer[1].data = camera_rendering_launch_params_.camera_properties.frame_buffer_albedo.DevicePointer(); + input_layer[1].data = camera_rendering_launch_params_.camera_properties.frame_buffer_albedo.DevicePointer(); /// Width of the image (in pixels) - inputLayer[1].width = camera_rendering_launch_params_.camera_properties.target_frame.size.x; + input_layer[1].width = camera_rendering_launch_params_.camera_properties.target_frame.size.x; /// Height of the image (in pixels) - inputLayer[1].height = camera_rendering_launch_params_.camera_properties.target_frame.size.y; + input_layer[1].height = camera_rendering_launch_params_.camera_properties.target_frame.size.y; /// Stride between subsequent rows of the image (in bytes). - inputLayer[1].rowStrideInBytes = + input_layer[1].rowStrideInBytes = camera_rendering_launch_params_.camera_properties.target_frame.size.x * sizeof(glm::vec4); /// Stride between subsequent pixels of the image (in bytes). /// For now, only 0 or the value that corresponds to a dense packing of pixels /// (no gaps) is supported. - inputLayer[1].pixelStrideInBytes = sizeof(glm::vec4); + input_layer[1].pixelStrideInBytes = sizeof(glm::vec4); /// Pixel format. - inputLayer[1].format = OPTIX_PIXEL_FORMAT_FLOAT4; + input_layer[1].format = OPTIX_PIXEL_FORMAT_FLOAT4; // .................................................................. - inputLayer[2].data = camera_rendering_launch_params_.camera_properties.frame_buffer_normal.DevicePointer(); + input_layer[2].data = camera_rendering_launch_params_.camera_properties.frame_buffer_normal.DevicePointer(); /// Width of the image (in pixels) - inputLayer[2].width = camera_rendering_launch_params_.camera_properties.target_frame.size.x; + input_layer[2].width = camera_rendering_launch_params_.camera_properties.target_frame.size.x; /// Height of the image (in pixels) - inputLayer[2].height = camera_rendering_launch_params_.camera_properties.target_frame.size.y; + input_layer[2].height = camera_rendering_launch_params_.camera_properties.target_frame.size.y; /// Stride between subsequent rows of the image (in bytes). - inputLayer[2].rowStrideInBytes = + input_layer[2].rowStrideInBytes = camera_rendering_launch_params_.camera_properties.target_frame.size.x * sizeof(glm::vec4); /// Stride between subsequent pixels of the image (in bytes). /// For now, only 0 or the value that corresponds to a dense packing of pixels /// (no gaps) is supported. - inputLayer[2].pixelStrideInBytes = sizeof(glm::vec4); + input_layer[2].pixelStrideInBytes = sizeof(glm::vec4); /// Pixel format. - inputLayer[2].format = OPTIX_PIXEL_FORMAT_FLOAT4; + input_layer[2].format = OPTIX_PIXEL_FORMAT_FLOAT4; // ------------------------------------------------------- - OptixImage2D outputLayer; - outputLayer.data = camera_rendering_launch_params_.camera_properties.denoised_buffer.DevicePointer(); + OptixImage2D output_layer; + output_layer.data = camera_rendering_launch_params_.camera_properties.denoised_buffer.DevicePointer(); /// Width of the image (in pixels) - outputLayer.width = camera_rendering_launch_params_.camera_properties.target_frame.size.x; + output_layer.width = camera_rendering_launch_params_.camera_properties.target_frame.size.x; /// Height of the image (in pixels) - outputLayer.height = camera_rendering_launch_params_.camera_properties.target_frame.size.y; + output_layer.height = camera_rendering_launch_params_.camera_properties.target_frame.size.y; /// Stride between subsequent rows of the image (in bytes). - outputLayer.rowStrideInBytes = + output_layer.rowStrideInBytes = camera_rendering_launch_params_.camera_properties.target_frame.size.x * sizeof(glm::vec4); /// Stride between subsequent pixels of the image (in bytes). /// For now, only 0 or the value that corresponds to a dense packing of pixels /// (no gaps) is supported. - outputLayer.pixelStrideInBytes = sizeof(glm::vec4); + output_layer.pixelStrideInBytes = sizeof(glm::vec4); /// Pixel format. - outputLayer.format = OPTIX_PIXEL_FORMAT_FLOAT4; + output_layer.format = OPTIX_PIXEL_FORMAT_FLOAT4; switch (camera_rendering_launch_params_.camera_properties.output_type) { case OutputType::Color: { if (camera_properties.denoiser_strength == 0.0f) { CUDA_CHECK(MemcpyToArray( - outputArray, 0, 0, (void *)camera_rendering_launch_params_.camera_properties.target_frame.color_buffer, + output_array, 0, 0, (void *)camera_rendering_launch_params_.camera_properties.target_frame.color_buffer, sizeof(glm::vec4) * camera_rendering_launch_params_.camera_properties.target_frame.size.x * camera_rendering_launch_params_.camera_properties.target_frame.size.y, cudaMemcpyDeviceToDevice)); @@ -371,30 +369,30 @@ bool OptiXRayTracer::RenderToCamera(const EnvironmentProperties &environment_pro OPTIX_CHECK(optixDenoiserComputeIntensity( camera_rendering_launch_params_.camera_properties.denoiser, - /*stream*/ 0, &inputLayer[0], - (CUdeviceptr)camera_rendering_launch_params_.camera_properties.denoiser_intensity.DevicePointer(), - (CUdeviceptr)camera_rendering_launch_params_.camera_properties.denoiser_scratch.DevicePointer(), + /*stream*/ nullptr, &input_layer[0], + camera_rendering_launch_params_.camera_properties.denoiser_intensity.DevicePointer(), + camera_rendering_launch_params_.camera_properties.denoiser_scratch.DevicePointer(), camera_rendering_launch_params_.camera_properties.denoiser_scratch.size_in_bytes)); - OptixDenoiserLayer denoiserLayer = {}; - denoiserLayer.input = inputLayer[0]; - denoiserLayer.output = outputLayer; + OptixDenoiserLayer denoiser_layer = {}; + denoiser_layer.input = input_layer[0]; + denoiser_layer.output = output_layer; - OptixDenoiserGuideLayer denoiserGuideLayer = {}; - denoiserGuideLayer.albedo = inputLayer[1]; - denoiserGuideLayer.normal = inputLayer[2]; + OptixDenoiserGuideLayer denoiser_guide_layer = {}; + denoiser_guide_layer.albedo = input_layer[1]; + denoiser_guide_layer.normal = input_layer[2]; OPTIX_CHECK(optixDenoiserInvoke( camera_rendering_launch_params_.camera_properties.denoiser, /*stream*/ 0, &denoiserParams, camera_rendering_launch_params_.camera_properties.denoiser_state.DevicePointer(), - camera_rendering_launch_params_.camera_properties.denoiser_state.size_in_bytes, &denoiserGuideLayer, - &denoiserLayer, 1, + camera_rendering_launch_params_.camera_properties.denoiser_state.size_in_bytes, &denoiser_guide_layer, + &denoiser_layer, 1, /*inputOffsetX*/ 0, /*inputOffsetY*/ 0, camera_rendering_launch_params_.camera_properties.denoiser_scratch.DevicePointer(), camera_rendering_launch_params_.camera_properties.denoiser_scratch.size_in_bytes)); CUDA_CHECK( - MemcpyToArray(outputArray, 0, 0, (void *)outputLayer.data, + MemcpyToArray(output_array, 0, 0, (void *)output_layer.data, sizeof(glm::vec4) * camera_rendering_launch_params_.camera_properties.target_frame.size.x * camera_rendering_launch_params_.camera_properties.target_frame.size.y, cudaMemcpyDeviceToDevice)); @@ -402,21 +400,21 @@ bool OptiXRayTracer::RenderToCamera(const EnvironmentProperties &environment_pro } break; case OutputType::Normal: { CUDA_CHECK(MemcpyToArray( - outputArray, 0, 0, (void *)camera_rendering_launch_params_.camera_properties.target_frame.normal_buffer, + output_array, 0, 0, (void *)camera_rendering_launch_params_.camera_properties.target_frame.normal_buffer, sizeof(glm::vec4) * camera_rendering_launch_params_.camera_properties.target_frame.size.x * camera_rendering_launch_params_.camera_properties.target_frame.size.y, cudaMemcpyDeviceToDevice)); } break; case OutputType::Albedo: { CUDA_CHECK(MemcpyToArray( - outputArray, 0, 0, (void *)camera_rendering_launch_params_.camera_properties.target_frame.albedo_buffer, + output_array, 0, 0, (void *)camera_rendering_launch_params_.camera_properties.target_frame.albedo_buffer, sizeof(glm::vec4) * camera_rendering_launch_params_.camera_properties.target_frame.size.x * camera_rendering_launch_params_.camera_properties.target_frame.size.y, cudaMemcpyDeviceToDevice)); } break; case OutputType::Depth: { CUDA_CHECK(MemcpyToArray( - outputArray, 0, 0, (void *)camera_rendering_launch_params_.camera_properties.target_frame.albedo_buffer, + output_array, 0, 0, (void *)camera_rendering_launch_params_.camera_properties.target_frame.albedo_buffer, sizeof(glm::vec4) * camera_rendering_launch_params_.camera_properties.target_frame.size.x * camera_rendering_launch_params_.camera_properties.target_frame.size.y, cudaMemcpyDeviceToDevice)); @@ -428,8 +426,8 @@ bool OptiXRayTracer::RenderToCamera(const EnvironmentProperties &environment_pro } void OptiXRayTracer::EstimateIllumination(const size_t &size, const EnvironmentProperties &environment_properties, - const RayProperties &ray_properties, CudaBuffer &light_probes, unsigned seed, - float push_normal_distance) { + const RayProperties &ray_properties, const CudaBuffer &light_probes, + const unsigned seed, const float push_normal_distance) { if (!has_acceleration_structure_) return; if (size == 0) { @@ -464,7 +462,7 @@ void OptiXRayTracer::EstimateIllumination(const size_t &size, const EnvironmentP } void OptiXRayTracer::ScanPointCloud(const size_t &size, const EnvironmentProperties &environment_properties, - CudaBuffer &samples) { + const CudaBuffer &samples) { if (!has_acceleration_structure_) return; if (size == 0) { @@ -518,37 +516,37 @@ static void context_log_cb(const unsigned int level, const char *tag, const char fprintf(stderr, "[%2d][%12s]: %s\n", static_cast(level), tag, message); } -void printLogMessage(unsigned int level, const char *tag, const char *message, void * /* cbdata */) { +void PrintLogMessage(unsigned int level, const char *tag, const char *message, void * /* cbdata */) { std::cerr << "[" << std::setw(2) << level << "][" << std::setw(12) << tag << "]: " << message << std::endl; } void OptiXRayTracer::CreateContext() { // for this sample, do everything on one device - const int deviceID = 0; + constexpr int device_id = 0; CUDA_CHECK(StreamCreate(&stream_)); - CUDA_CHECK(GetDeviceProperties(&device_props_, deviceID)); + CUDA_CHECK(GetDeviceProperties(&device_props_, device_id)); std::cout << "#Optix: running on device: " << device_props_.name << std::endl; - const CUresult cuRes = cuCtxGetCurrent(&cuda_context_); - if (cuRes != CUDA_SUCCESS) - fprintf(stderr, "Error querying current context: error code %d\n", cuRes); + if (const CUresult cu_res = cuCtxGetCurrent(&cuda_context_); cu_res != CUDA_SUCCESS) + fprintf(stderr, "Error querying current context: error code %d\n", cu_res); OptixDeviceContextOptions options = {}; - options.logCallbackFunction = &printLogMessage; + options.logCallbackFunction = &PrintLogMessage; options.logCallbackLevel = 4; - // options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; - +#ifndef NDEBUG + options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; +#endif OPTIX_CHECK(optixDeviceContextCreate(cuda_context_, &options, &optix_device_context_)); OPTIX_CHECK(optixDeviceContextSetLogCallback(optix_device_context_, context_log_cb, nullptr, 4)); } -extern "C" char CAMERA_RENDERING_PTX[]; -extern "C" char ILLUMINATION_ESTIMATION_PTX[]; -extern "C" char POINT_CLOUD_SCANNING_PTX[]; +extern "C" char camera_rendering_ptx[]; +extern "C" char illumination_estimation_ptx[]; +extern "C" char point_cloud_scanning_ptx[]; void OptiXRayTracer::CreateModules() { - CreateModule(camera_rendering_pipeline_, CAMERA_RENDERING_PTX, "cameraRenderingLaunchParams"); - CreateModule(illumination_estimation_pipeline_, ILLUMINATION_ESTIMATION_PTX, "illuminationEstimationLaunchParams"); - CreateModule(point_cloud_scanning_pipeline_, POINT_CLOUD_SCANNING_PTX, "pointCloudScanningLaunchParams"); + CreateModule(camera_rendering_pipeline_, camera_rendering_ptx, "cameraRenderingLaunchParams"); + CreateModule(illumination_estimation_pipeline_, illumination_estimation_ptx, "illuminationEstimationLaunchParams"); + CreateModule(point_cloud_scanning_pipeline_, point_cloud_scanning_ptx, "pointCloudScanningLaunchParams"); } void OptiXRayTracer::CreateRayGenPrograms() { @@ -560,84 +558,84 @@ void OptiXRayTracer::CreateRayGenPrograms() { void OptiXRayTracer::CreateMissPrograms() { { char log[2048]; - size_t sizeofLog = sizeof(log); + size_t sizeof_log = sizeof(log); - OptixProgramGroupOptions pgOptions = {}; - OptixProgramGroupDesc pgDesc = {}; - pgDesc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; - pgDesc.miss.module = camera_rendering_pipeline_.module; + OptixProgramGroupOptions pg_options = {}; + OptixProgramGroupDesc pg_desc = {}; + pg_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + pg_desc.miss.module = camera_rendering_pipeline_.module; // ------------------------------------------------------------------ // radiance rays // ------------------------------------------------------------------ - pgDesc.miss.entryFunctionName = "__miss__CR_R"; + pg_desc.miss.entryFunctionName = "__miss__CR_R"; - OPTIX_CHECK(optixProgramGroupCreate(optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + OPTIX_CHECK(optixProgramGroupCreate(optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &camera_rendering_pipeline_.miss_program_groups[RayType::Radiance])); - if (sizeofLog > 1) + if (sizeof_log > 1) std::cout << log << std::endl; // ------------------------------------------------------------------ // BSSRDF Spatial sampler rays // ------------------------------------------------------------------ - pgDesc.miss.entryFunctionName = "__miss__CR_SS"; - OPTIX_CHECK(optixProgramGroupCreate(optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + pg_desc.miss.entryFunctionName = "__miss__CR_SS"; + OPTIX_CHECK(optixProgramGroupCreate(optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &camera_rendering_pipeline_.miss_program_groups[RayType::SpacialSampling])); - if (sizeofLog > 1) + if (sizeof_log > 1) std::cout << log << std::endl; } { char log[2048]; - size_t sizeofLog = sizeof(log); + size_t sizeof_log = sizeof(log); - OptixProgramGroupOptions pgOptions = {}; - OptixProgramGroupDesc pgDesc = {}; - pgDesc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; - pgDesc.miss.module = illumination_estimation_pipeline_.module; + OptixProgramGroupOptions pg_options = {}; + OptixProgramGroupDesc pg_desc = {}; + pg_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + pg_desc.miss.module = illumination_estimation_pipeline_.module; // ------------------------------------------------------------------ // radiance rays // ------------------------------------------------------------------ - pgDesc.miss.entryFunctionName = "__miss__IE_R"; + pg_desc.miss.entryFunctionName = "__miss__IE_R"; - OPTIX_CHECK(optixProgramGroupCreate(optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + OPTIX_CHECK(optixProgramGroupCreate(optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &illumination_estimation_pipeline_.miss_program_groups[RayType::Radiance])); - if (sizeofLog > 1) + if (sizeof_log > 1) std::cout << log << std::endl; // ------------------------------------------------------------------ // BSSRDF Spatial sampler rays // ------------------------------------------------------------------ - pgDesc.miss.entryFunctionName = "__miss__IE_SS"; + pg_desc.miss.entryFunctionName = "__miss__IE_SS"; OPTIX_CHECK( - optixProgramGroupCreate(optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optixProgramGroupCreate(optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &illumination_estimation_pipeline_.miss_program_groups[RayType::SpacialSampling])); - if (sizeofLog > 1) + if (sizeof_log > 1) std::cout << log << std::endl; } { char log[2048]; - size_t sizeofLog = sizeof(log); + size_t sizeof_log = sizeof(log); - OptixProgramGroupOptions pgOptions = {}; - OptixProgramGroupDesc pgDesc = {}; - pgDesc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; - pgDesc.miss.module = point_cloud_scanning_pipeline_.module; + OptixProgramGroupOptions pg_options = {}; + OptixProgramGroupDesc pg_desc = {}; + pg_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + pg_desc.miss.module = point_cloud_scanning_pipeline_.module; // ------------------------------------------------------------------ // radiance rays // ------------------------------------------------------------------ - pgDesc.miss.entryFunctionName = "__miss__PCS_R"; + pg_desc.miss.entryFunctionName = "__miss__PCS_R"; - OPTIX_CHECK(optixProgramGroupCreate(optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + OPTIX_CHECK(optixProgramGroupCreate(optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &point_cloud_scanning_pipeline_.miss_program_groups[RayType::Radiance])); - if (sizeofLog > 1) + if (sizeof_log > 1) std::cout << log << std::endl; // ------------------------------------------------------------------ // BSSRDF Spatial sampler rays // ------------------------------------------------------------------ - pgDesc.miss.entryFunctionName = "__miss__PCS_SS"; - OPTIX_CHECK(optixProgramGroupCreate(optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + pg_desc.miss.entryFunctionName = "__miss__PCS_SS"; + OPTIX_CHECK(optixProgramGroupCreate(optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &point_cloud_scanning_pipeline_.miss_program_groups[RayType::SpacialSampling])); - if (sizeofLog > 1) + if (sizeof_log > 1) std::cout << log << std::endl; } } @@ -645,271 +643,267 @@ void OptiXRayTracer::CreateMissPrograms() { void OptiXRayTracer::CreateHitGroupPrograms() { { char log[2048]; - size_t sizeofLog = sizeof(log); + size_t sizeof_log = sizeof(log); - OptixProgramGroupOptions pgOptions = {}; - OptixProgramGroupDesc pgDesc = {}; - pgDesc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; - pgDesc.hitgroup.moduleCH = camera_rendering_pipeline_.module; - pgDesc.hitgroup.moduleAH = camera_rendering_pipeline_.module; + OptixProgramGroupOptions pg_options = {}; + OptixProgramGroupDesc pg_desc = {}; + pg_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + pg_desc.hitgroup.moduleCH = camera_rendering_pipeline_.module; + pg_desc.hitgroup.moduleAH = camera_rendering_pipeline_.module; // ------------------------------------------------------- // radiance rays // ------------------------------------------------------- - pgDesc.hitgroup.entryFunctionNameCH = "__closesthit__CR_R"; - pgDesc.hitgroup.entryFunctionNameAH = "__anyhit__CR_R"; - pgDesc.hitgroup.entryFunctionNameIS = 0; + pg_desc.hitgroup.entryFunctionNameCH = "__closesthit__CR_R"; + pg_desc.hitgroup.entryFunctionNameAH = "__anyhit__CR_R"; + pg_desc.hitgroup.entryFunctionNameIS = 0; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &camera_rendering_pipeline_.hit_group_program_groups[RayType::Radiance][PrimitiveType::Triangle])); - pgDesc.hitgroup.moduleIS = camera_rendering_pipeline_.linear_curve_module; + pg_desc.hitgroup.moduleIS = camera_rendering_pipeline_.linear_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &camera_rendering_pipeline_.hit_group_program_groups[RayType::Radiance][PrimitiveType::Linear])); - pgDesc.hitgroup.moduleIS = camera_rendering_pipeline_.quadratic_curve_module; + pg_desc.hitgroup.moduleIS = camera_rendering_pipeline_.quadratic_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &camera_rendering_pipeline_.hit_group_program_groups[RayType::Radiance][PrimitiveType::QuadraticBSpline])); - pgDesc.hitgroup.moduleIS = camera_rendering_pipeline_.cubic_curve_module; + pg_desc.hitgroup.moduleIS = camera_rendering_pipeline_.cubic_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &camera_rendering_pipeline_.hit_group_program_groups[RayType::Radiance][PrimitiveType::CubicBSpline])); - if (sizeofLog > 1) + if (sizeof_log > 1) std::cout << log << std::endl; // ------------------------------------------------------- // BSSRDF Sampler ray // ------------------------------------------------------- - pgDesc.hitgroup.entryFunctionNameCH = "__closesthit__CR_SS"; - pgDesc.hitgroup.entryFunctionNameAH = "__anyhit__CR_SS"; + pg_desc.hitgroup.entryFunctionNameCH = "__closesthit__CR_SS"; + pg_desc.hitgroup.entryFunctionNameAH = "__anyhit__CR_SS"; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &camera_rendering_pipeline_.hit_group_program_groups[RayType::SpacialSampling][PrimitiveType::Triangle])); - pgDesc.hitgroup.moduleIS = camera_rendering_pipeline_.linear_curve_module; + pg_desc.hitgroup.moduleIS = camera_rendering_pipeline_.linear_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &camera_rendering_pipeline_.hit_group_program_groups[RayType::SpacialSampling][PrimitiveType::Linear])); ; - pgDesc.hitgroup.moduleIS = camera_rendering_pipeline_.quadratic_curve_module; + pg_desc.hitgroup.moduleIS = camera_rendering_pipeline_.quadratic_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &camera_rendering_pipeline_ .hit_group_program_groups[RayType::SpacialSampling][PrimitiveType::QuadraticBSpline])); - pgDesc.hitgroup.moduleIS = camera_rendering_pipeline_.cubic_curve_module; + pg_desc.hitgroup.moduleIS = camera_rendering_pipeline_.cubic_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &camera_rendering_pipeline_.hit_group_program_groups[RayType::SpacialSampling][PrimitiveType::CubicBSpline])); - if (sizeofLog > 1) + if (sizeof_log > 1) std::cout << log << std::endl; } { char log[2048]; - size_t sizeofLog = sizeof(log); + size_t sizeof_log = sizeof(log); - OptixProgramGroupOptions pgOptions = {}; - OptixProgramGroupDesc pgDesc = {}; - pgDesc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; - pgDesc.hitgroup.moduleCH = illumination_estimation_pipeline_.module; - pgDesc.hitgroup.moduleAH = illumination_estimation_pipeline_.module; + OptixProgramGroupOptions pg_options = {}; + OptixProgramGroupDesc pg_desc = {}; + pg_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + pg_desc.hitgroup.moduleCH = illumination_estimation_pipeline_.module; + pg_desc.hitgroup.moduleAH = illumination_estimation_pipeline_.module; // ------------------------------------------------------- // radiance rays // ------------------------------------------------------- - pgDesc.hitgroup.entryFunctionNameCH = "__closesthit__IE_R"; - pgDesc.hitgroup.entryFunctionNameAH = "__anyhit__IE_R"; + pg_desc.hitgroup.entryFunctionNameCH = "__closesthit__IE_R"; + pg_desc.hitgroup.entryFunctionNameAH = "__anyhit__IE_R"; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &illumination_estimation_pipeline_.hit_group_program_groups[RayType::Radiance][PrimitiveType::Triangle])); - pgDesc.hitgroup.moduleIS = illumination_estimation_pipeline_.linear_curve_module; + pg_desc.hitgroup.moduleIS = illumination_estimation_pipeline_.linear_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &illumination_estimation_pipeline_.hit_group_program_groups[RayType::Radiance][PrimitiveType::Linear])); - pgDesc.hitgroup.moduleIS = illumination_estimation_pipeline_.quadratic_curve_module; + pg_desc.hitgroup.moduleIS = illumination_estimation_pipeline_.quadratic_curve_module; OPTIX_CHECK( - optixProgramGroupCreate(optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optixProgramGroupCreate(optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &illumination_estimation_pipeline_ .hit_group_program_groups[RayType::Radiance][PrimitiveType::QuadraticBSpline])); - pgDesc.hitgroup.moduleIS = illumination_estimation_pipeline_.cubic_curve_module; + pg_desc.hitgroup.moduleIS = illumination_estimation_pipeline_.cubic_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &illumination_estimation_pipeline_.hit_group_program_groups[RayType::Radiance][PrimitiveType::CubicBSpline])); - if (sizeofLog > 1) + if (sizeof_log > 1) std::cout << log << std::endl; // ------------------------------------------------------- // BSSRDF Sampler ray // ------------------------------------------------------- - pgDesc.hitgroup.entryFunctionNameCH = "__closesthit__IE_SS"; - pgDesc.hitgroup.entryFunctionNameAH = "__anyhit__IE_SS"; + pg_desc.hitgroup.entryFunctionNameCH = "__closesthit__IE_SS"; + pg_desc.hitgroup.entryFunctionNameAH = "__anyhit__IE_SS"; OPTIX_CHECK( - optixProgramGroupCreate(optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optixProgramGroupCreate(optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &illumination_estimation_pipeline_ .hit_group_program_groups[RayType::SpacialSampling][PrimitiveType::Triangle])); - pgDesc.hitgroup.moduleIS = illumination_estimation_pipeline_.linear_curve_module; + pg_desc.hitgroup.moduleIS = illumination_estimation_pipeline_.linear_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &illumination_estimation_pipeline_.hit_group_program_groups[RayType::SpacialSampling][PrimitiveType::Linear])); - pgDesc.hitgroup.moduleIS = illumination_estimation_pipeline_.quadratic_curve_module; + pg_desc.hitgroup.moduleIS = illumination_estimation_pipeline_.quadratic_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &illumination_estimation_pipeline_ .hit_group_program_groups[RayType::SpacialSampling][PrimitiveType::QuadraticBSpline])); - pgDesc.hitgroup.moduleIS = illumination_estimation_pipeline_.cubic_curve_module; + pg_desc.hitgroup.moduleIS = illumination_estimation_pipeline_.cubic_curve_module; OPTIX_CHECK( - optixProgramGroupCreate(optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optixProgramGroupCreate(optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &illumination_estimation_pipeline_ .hit_group_program_groups[RayType::SpacialSampling][PrimitiveType::CubicBSpline])); - if (sizeofLog > 1) + if (sizeof_log > 1) std::cout << log << std::endl; } { char log[2048]; - size_t sizeofLog = sizeof(log); + size_t sizeof_log = sizeof(log); - OptixProgramGroupOptions pgOptions = {}; - OptixProgramGroupDesc pgDesc = {}; - pgDesc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; - pgDesc.hitgroup.moduleCH = point_cloud_scanning_pipeline_.module; - pgDesc.hitgroup.moduleAH = point_cloud_scanning_pipeline_.module; + OptixProgramGroupOptions pg_options = {}; + OptixProgramGroupDesc pg_desc = {}; + pg_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + pg_desc.hitgroup.moduleCH = point_cloud_scanning_pipeline_.module; + pg_desc.hitgroup.moduleAH = point_cloud_scanning_pipeline_.module; // ------------------------------------------------------- // radiance rays // ------------------------------------------------------- - pgDesc.hitgroup.entryFunctionNameCH = "__closesthit__PCS_R"; - pgDesc.hitgroup.entryFunctionNameAH = "__anyhit__PCS_R"; + pg_desc.hitgroup.entryFunctionNameCH = "__closesthit__PCS_R"; + pg_desc.hitgroup.entryFunctionNameAH = "__anyhit__PCS_R"; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &point_cloud_scanning_pipeline_.hit_group_program_groups[RayType::Radiance][PrimitiveType::Triangle])); - pgDesc.hitgroup.moduleIS = point_cloud_scanning_pipeline_.linear_curve_module; + pg_desc.hitgroup.moduleIS = point_cloud_scanning_pipeline_.linear_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &point_cloud_scanning_pipeline_.hit_group_program_groups[RayType::Radiance][PrimitiveType::Linear])); - pgDesc.hitgroup.moduleIS = point_cloud_scanning_pipeline_.quadratic_curve_module; + pg_desc.hitgroup.moduleIS = point_cloud_scanning_pipeline_.quadratic_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &point_cloud_scanning_pipeline_.hit_group_program_groups[RayType::Radiance][PrimitiveType::QuadraticBSpline])); - pgDesc.hitgroup.moduleIS = point_cloud_scanning_pipeline_.cubic_curve_module; + pg_desc.hitgroup.moduleIS = point_cloud_scanning_pipeline_.cubic_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &point_cloud_scanning_pipeline_.hit_group_program_groups[RayType::Radiance][PrimitiveType::CubicBSpline])); - if (sizeofLog > 1) + if (sizeof_log > 1) std::cout << log << std::endl; // ------------------------------------------------------- // BSSRDF Sampler ray // ------------------------------------------------------- - pgDesc.hitgroup.entryFunctionNameCH = "__closesthit__PCS_SS"; - pgDesc.hitgroup.entryFunctionNameAH = "__anyhit__PCS_SS"; + pg_desc.hitgroup.entryFunctionNameCH = "__closesthit__PCS_SS"; + pg_desc.hitgroup.entryFunctionNameAH = "__anyhit__PCS_SS"; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &point_cloud_scanning_pipeline_.hit_group_program_groups[RayType::SpacialSampling][PrimitiveType::Triangle])); - pgDesc.hitgroup.moduleIS = point_cloud_scanning_pipeline_.linear_curve_module; + pg_desc.hitgroup.moduleIS = point_cloud_scanning_pipeline_.linear_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &point_cloud_scanning_pipeline_.hit_group_program_groups[RayType::SpacialSampling][PrimitiveType::Linear])); - pgDesc.hitgroup.moduleIS = point_cloud_scanning_pipeline_.quadratic_curve_module; + pg_desc.hitgroup.moduleIS = point_cloud_scanning_pipeline_.quadratic_curve_module; OPTIX_CHECK(optixProgramGroupCreate( - optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &point_cloud_scanning_pipeline_ .hit_group_program_groups[RayType::SpacialSampling][PrimitiveType::QuadraticBSpline])); - pgDesc.hitgroup.moduleIS = point_cloud_scanning_pipeline_.cubic_curve_module; + pg_desc.hitgroup.moduleIS = point_cloud_scanning_pipeline_.cubic_curve_module; OPTIX_CHECK( - optixProgramGroupCreate(optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, + optixProgramGroupCreate(optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, &point_cloud_scanning_pipeline_ .hit_group_program_groups[RayType::SpacialSampling][PrimitiveType::CubicBSpline])); - if (sizeofLog > 1) + if (sizeof_log > 1) std::cout << log << std::endl; } } -__global__ void CopyVerticesInstancedKernel(int matricesSize, int verticesSize, InstanceMatrix *matrices, - evo_engine::Vertex *vertices, glm::vec3 *targetPositions, - evo_engine::Vertex *targetVertices) { - const int idx = threadIdx.x + blockIdx.x * blockDim.x; - if (idx < verticesSize * matricesSize) { +__global__ void CopyVerticesInstancedKernel(const int matrices_size, const int vertices_size, + const InstanceMatrix *matrices, const Vertex *vertices, + glm::vec3 *target_positions, Vertex *target_vertices) { + if (const int idx = threadIdx.x + blockIdx.x * blockDim.x; idx < vertices_size * matrices_size) { const glm::vec3 position = - matrices[idx / verticesSize].instance_matrix * glm::vec4(vertices[idx % verticesSize].position, 1.0f); - targetPositions[idx] = position; - glm::vec3 N = glm::normalize(matrices[idx / verticesSize].instance_matrix * - glm::vec4(vertices[idx % verticesSize].normal, 0.0f)); - glm::vec3 T = glm::normalize(matrices[idx / verticesSize].instance_matrix * - glm::vec4(vertices[idx % verticesSize].tangent, 0.0f)); - T = glm::normalize(T - dot(T, N) * N); - targetVertices[idx] = {}; - targetVertices[idx].position = position; - targetVertices[idx].tangent = T; - targetVertices[idx].normal = N; - targetVertices[idx].tex_coord = vertices[idx % verticesSize].tex_coord; - targetVertices[idx].color = matrices[idx / verticesSize].instance_color; + matrices[idx / vertices_size].instance_matrix * glm::vec4(vertices[idx % vertices_size].position, 1.0f); + target_positions[idx] = position; + const glm::vec3 normal = glm::normalize(matrices[idx / vertices_size].instance_matrix * + glm::vec4(vertices[idx % vertices_size].normal, 0.0f)); + glm::vec3 tangent = glm::normalize(matrices[idx / vertices_size].instance_matrix * + glm::vec4(vertices[idx % vertices_size].tangent, 0.0f)); + tangent = glm::normalize(tangent - dot(tangent, normal) * normal); + target_vertices[idx] = {}; + target_vertices[idx].position = position; + target_vertices[idx].tangent = tangent; + target_vertices[idx].normal = normal; + target_vertices[idx].tex_coord = vertices[idx % vertices_size].tex_coord; + target_vertices[idx].color = matrices[idx / vertices_size].instance_color; } } -__global__ void CopyStrandPointsKernel(int size, evo_engine::StrandPoint *strandPoints, float *targetThicknesses) { - const int idx = threadIdx.x + blockIdx.x * blockDim.x; - if (idx < size) { - targetThicknesses[idx] = strandPoints[idx].thickness; +__global__ void CopyStrandPointsKernel(const int size, const StrandPoint *strand_points, float *target_thicknesses) { + if (const int idx = threadIdx.x + blockIdx.x * blockDim.x; idx < size) { + target_thicknesses[idx] = strand_points[idx].thickness; } } -__global__ void CopyVerticesKernel(int size, evo_engine::Vertex *vertices, glm::vec3 *targetPositions) { - const int idx = threadIdx.x + blockIdx.x * blockDim.x; - if (idx < size) { - targetPositions[idx] = vertices[idx].position; +__global__ void CopyVerticesKernel(const int size, const Vertex *vertices, glm::vec3 *target_positions) { + if (const int idx = threadIdx.x + blockIdx.x * blockDim.x; idx < size) { + target_positions[idx] = vertices[idx].position; } } -__global__ void CopySkinnedVerticesKernel(int size, evo_engine::SkinnedVertex *vertices, glm::mat4 *boneMatrices, - glm::vec3 *targetPositions, evo_engine::Vertex *targetVertices) { - const int idx = threadIdx.x + blockIdx.x * blockDim.x; - if (idx < size) { - glm::mat4 boneTransform = boneMatrices[vertices[idx].bond_id[0]] * vertices[idx].weight[0]; +__global__ void CopySkinnedVerticesKernel(const int size, SkinnedVertex *vertices, const glm::mat4 *bone_matrices, + glm::vec3 *target_positions, Vertex *target_vertices) { + if (const int idx = threadIdx.x + blockIdx.x * blockDim.x; idx < size) { + glm::mat4 bone_transform = bone_matrices[vertices[idx].bond_id[0]] * vertices[idx].weight[0]; if (vertices[idx].bond_id[1] != -1) { - boneTransform += boneMatrices[vertices[idx].bond_id[1]] * vertices[idx].weight[1]; + bone_transform += bone_matrices[vertices[idx].bond_id[1]] * vertices[idx].weight[1]; } if (vertices[idx].bond_id[2] != -1) { - boneTransform += boneMatrices[vertices[idx].bond_id[2]] * vertices[idx].weight[2]; + bone_transform += bone_matrices[vertices[idx].bond_id[2]] * vertices[idx].weight[2]; } if (vertices[idx].bond_id[3] != -1) { - boneTransform += boneMatrices[vertices[idx].bond_id[3]] * vertices[idx].weight[3]; + bone_transform += bone_matrices[vertices[idx].bond_id[3]] * vertices[idx].weight[3]; } if (vertices[idx].bond_id2[0] != -1) { - boneTransform += boneMatrices[vertices[idx].bond_id2[0]] * vertices[idx].weight2[0]; + bone_transform += bone_matrices[vertices[idx].bond_id2[0]] * vertices[idx].weight2[0]; } if (vertices[idx].bond_id2[1] != -1) { - boneTransform += boneMatrices[vertices[idx].bond_id2[1]] * vertices[idx].weight2[1]; + bone_transform += bone_matrices[vertices[idx].bond_id2[1]] * vertices[idx].weight2[1]; } if (vertices[idx].bond_id2[2] != -1) { - boneTransform += boneMatrices[vertices[idx].bond_id2[2]] * vertices[idx].weight2[2]; + bone_transform += bone_matrices[vertices[idx].bond_id2[2]] * vertices[idx].weight2[2]; } if (vertices[idx].bond_id2[3] != -1) { - boneTransform += boneMatrices[vertices[idx].bond_id2[3]] * vertices[idx].weight2[3]; + bone_transform += bone_matrices[vertices[idx].bond_id2[3]] * vertices[idx].weight2[3]; } - const glm::vec3 position = boneTransform * glm::vec4(vertices[idx].position, 1.0f); - targetPositions[idx] = position; - glm::vec3 N = glm::normalize(boneTransform * glm::vec4(vertices[idx].normal, 0.0f)); - glm::vec3 T = glm::normalize(boneTransform * glm::vec4(vertices[idx].tangent, 0.0f)); - T = glm::normalize(T - dot(T, N) * N); - targetVertices[idx].position = position; - targetVertices[idx].normal = N; - targetVertices[idx].tangent = T; - targetVertices[idx].tex_coord = vertices[idx].tex_coord; - targetVertices[idx].color = vertices[idx].color; + const glm::vec3 position = bone_transform * glm::vec4(vertices[idx].position, 1.0f); + target_positions[idx] = position; + const glm::vec3 normal = glm::normalize(bone_transform * glm::vec4(vertices[idx].normal, 0.0f)); + glm::vec3 tangent = glm::normalize(bone_transform * glm::vec4(vertices[idx].tangent, 0.0f)); + tangent = glm::normalize(tangent - dot(tangent, normal) * normal); + target_vertices[idx].position = position; + target_vertices[idx].normal = normal; + target_vertices[idx].tangent = tangent; + target_vertices[idx].tex_coord = vertices[idx].tex_coord; + target_vertices[idx].color = vertices[idx].color; } } @@ -925,181 +919,168 @@ void RayTracedGeometry::BuildGas(const OptixDeviceContext &context) { accelerated_structure_buffer.Free(); #pragma endregion - CudaBuffer devicePositionBuffer; - CudaBuffer deviceWidthBuffer; + CudaBuffer device_position_buffer; + CudaBuffer device_width_buffer; + + CUdeviceptr device_vertex_positions; + CUdeviceptr device_vertex_triangles; + CUdeviceptr device_points; + CUdeviceptr device_widths; #pragma region Geometry Inputs // ================================================================== // geometry inputs // ================================================================== - OptixBuildInput buildInput; - const uint32_t triangleInputFlags[1] = {OPTIX_GEOMETRY_FLAG_NONE}; + OptixBuildInput build_input; + constexpr uint32_t triangle_input_flags[1] = {OPTIX_GEOMETRY_FLAG_NONE}; switch (renderer_type) { case RendererType::Curve: { - CUdeviceptr devicePoints; - CUdeviceptr deviceWidths; - CUdeviceptr deviceStrands; - - // curve_strand_u_buffer.Upload(*m_strandU); - // curve_strand_i_buffer.Upload(*m_strandIndices); - // curve_strand_info_buffer.Upload(*m_strandInfos); - - deviceWidthBuffer.Resize(curve_points->size() * sizeof(float)); + CUdeviceptr device_strands; + device_width_buffer.Resize(curve_points->size() * sizeof(float)); vertex_data_buffer.Upload(*curve_points); triangle_buffer.Upload(*curve_segments); - int blockSize = 0; // The launch configurator returned block size - int minGridSize = 0; // The minimum grid size needed to achieve the + int block_size = 0; // The launch configurator returned block size + int min_grid_size = 0; // The minimum grid size needed to achieve the // maximum occupancy for a full device launch - int gridSize = 0; // The actual grid size needed, based on input size + int grid_size = 0; // The actual grid size needed, based on input size int size = curve_points->size(); - cudaOccupancyMaxPotentialBlockSize(&minGridSize, &blockSize, CopyStrandPointsKernel, 0, size); - gridSize = (size + blockSize - 1) / blockSize; - CopyStrandPointsKernel<<>>(size, - static_cast(vertex_data_buffer.d_ptr), - static_cast(deviceWidthBuffer.d_ptr)); + cudaOccupancyMaxPotentialBlockSize(&min_grid_size, &block_size, CopyStrandPointsKernel, 0, size); + grid_size = (size + block_size - 1) / block_size; + CopyStrandPointsKernel<<>>( + size, static_cast(vertex_data_buffer.d_ptr), + static_cast(device_width_buffer.d_ptr)); CUDA_SYNC_CHECK(); - - buildInput.type = OPTIX_BUILD_INPUT_TYPE_CURVES; + build_input.type = OPTIX_BUILD_INPUT_TYPE_CURVES; switch (geometry_type) { case PrimitiveType::Linear: - buildInput.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_LINEAR; + build_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_LINEAR; break; case PrimitiveType::QuadraticBSpline: - buildInput.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_QUADRATIC_BSPLINE; + build_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_QUADRATIC_BSPLINE; break; case PrimitiveType::CubicBSpline: - buildInput.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE; + build_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE; break; } - devicePoints = vertex_data_buffer.DevicePointer(); - deviceWidths = deviceWidthBuffer.DevicePointer(); - deviceStrands = triangle_buffer.DevicePointer(); - buildInput.curveArray.numPrimitives = curve_segments->size(); - buildInput.curveArray.vertexBuffers = &devicePoints; - buildInput.curveArray.numVertices = static_cast(curve_points->size()); - buildInput.curveArray.vertexStrideInBytes = sizeof(evo_engine::StrandPoint); - buildInput.curveArray.widthBuffers = &deviceWidths; - buildInput.curveArray.widthStrideInBytes = sizeof(float); - buildInput.curveArray.normalBuffers = 0; - buildInput.curveArray.normalStrideInBytes = 0; - buildInput.curveArray.indexBuffer = deviceStrands; - buildInput.curveArray.indexStrideInBytes = sizeof(int); - buildInput.curveArray.flag = OPTIX_GEOMETRY_FLAG_NONE; - buildInput.curveArray.endcapFlags = OPTIX_CURVE_ENDCAP_ON; - buildInput.curveArray.primitiveIndexOffset = 0; + device_points = vertex_data_buffer.DevicePointer(); + device_widths = device_width_buffer.DevicePointer(); + device_strands = triangle_buffer.DevicePointer(); + build_input.curveArray.numPrimitives = curve_segments->size(); + build_input.curveArray.vertexBuffers = &device_points; + build_input.curveArray.numVertices = static_cast(curve_points->size()); + build_input.curveArray.vertexStrideInBytes = sizeof(evo_engine::StrandPoint); + build_input.curveArray.widthBuffers = &device_widths; + build_input.curveArray.widthStrideInBytes = sizeof(float); + build_input.curveArray.normalBuffers = 0; + build_input.curveArray.normalStrideInBytes = 0; + build_input.curveArray.indexBuffer = device_strands; + build_input.curveArray.indexStrideInBytes = sizeof(int); + build_input.curveArray.flag = OPTIX_GEOMETRY_FLAG_NONE; + build_input.curveArray.endcapFlags = OPTIX_CURVE_ENDCAP_ON; + build_input.curveArray.primitiveIndexOffset = 0; } break; case RendererType::Default: { - CUdeviceptr deviceVertexPositions; - CUdeviceptr deviceVertexTriangles; - vertex_data_buffer.Upload(*vertices); - int blockSize = 0; // The launch configurator returned block size - int minGridSize = 0; // The minimum grid size needed to achieve the + int block_size = 0; // The launch configurator returned block size + int min_grid_size = 0; // The minimum grid size needed to achieve the // maximum occupancy for a full device launch - int gridSize = 0; // The actual grid size needed, based on input size int size = vertices->size(); - cudaOccupancyMaxPotentialBlockSize(&minGridSize, &blockSize, CopyVerticesKernel, 0, size); - gridSize = (size + blockSize - 1) / blockSize; + cudaOccupancyMaxPotentialBlockSize(&min_grid_size, &block_size, CopyVerticesKernel, 0, size); CUDA_SYNC_CHECK(); triangle_buffer.Upload(*triangles); - buildInput = {}; - buildInput.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + build_input = {}; + build_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; // create local variables, because we need a *pointer* to the // device pointers - deviceVertexPositions = vertex_data_buffer.DevicePointer(); - deviceVertexTriangles = triangle_buffer.DevicePointer(); + device_vertex_positions = vertex_data_buffer.DevicePointer(); + device_vertex_triangles = triangle_buffer.DevicePointer(); - buildInput.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; - buildInput.triangleArray.vertexStrideInBytes = sizeof(evo_engine::Vertex); - buildInput.triangleArray.numVertices = static_cast(vertices->size()); - buildInput.triangleArray.vertexBuffers = &deviceVertexPositions; + build_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + build_input.triangleArray.vertexStrideInBytes = sizeof(Vertex); + build_input.triangleArray.numVertices = static_cast(vertices->size()); + build_input.triangleArray.vertexBuffers = &device_vertex_positions; - buildInput.triangleArray.indexFormat = OPTIX_INDICES_FORMAT_UNSIGNED_INT3; - buildInput.triangleArray.indexStrideInBytes = sizeof(glm::uvec3); - buildInput.triangleArray.numIndexTriplets = static_cast(triangle_buffer.size_in_bytes / sizeof(glm::uvec3)); - buildInput.triangleArray.indexBuffer = deviceVertexTriangles; + build_input.triangleArray.indexFormat = OPTIX_INDICES_FORMAT_UNSIGNED_INT3; + build_input.triangleArray.indexStrideInBytes = sizeof(glm::uvec3); + build_input.triangleArray.numIndexTriplets = static_cast(triangle_buffer.size_in_bytes / sizeof(glm::uvec3)); + build_input.triangleArray.indexBuffer = device_vertex_triangles; // in this example we have one SBT entry, and no per-primitive // materials: - buildInput.triangleArray.flags = triangleInputFlags; - buildInput.triangleArray.numSbtRecords = 1; - buildInput.triangleArray.sbtIndexOffsetBuffer = 0; - buildInput.triangleArray.sbtIndexOffsetSizeInBytes = 0; - buildInput.triangleArray.sbtIndexOffsetStrideInBytes = 0; + build_input.triangleArray.flags = triangle_input_flags; + build_input.triangleArray.numSbtRecords = 1; + build_input.triangleArray.sbtIndexOffsetBuffer = 0; + build_input.triangleArray.sbtIndexOffsetSizeInBytes = 0; + build_input.triangleArray.sbtIndexOffsetStrideInBytes = 0; } break; case RendererType::Skinned: { - CUdeviceptr deviceVertexPositions; - CUdeviceptr deviceVertexTriangles; - - CudaBuffer skinnedVerticesBuffer; - CudaBuffer boneMatricesBuffer; - skinnedVerticesBuffer.Upload(*skinned_vertices); - boneMatricesBuffer.Upload(*bone_matrices); + CudaBuffer skinned_vertices_buffer; + CudaBuffer bone_matrices_buffer; + skinned_vertices_buffer.Upload(*skinned_vertices); + bone_matrices_buffer.Upload(*bone_matrices); vertex_data_buffer.Resize(skinned_vertices->size() * sizeof(evo_engine::Vertex)); - devicePositionBuffer.Resize(skinned_vertices->size() * sizeof(glm::vec3)); - int blockSize = 0; // The launch configurator returned block size - int minGridSize = 0; // The minimum grid size needed to achieve the + device_position_buffer.Resize(skinned_vertices->size() * sizeof(glm::vec3)); + int block_size = 0; // The launch configurator returned block size + int min_grid_size = 0; // The minimum grid size needed to achieve the // maximum occupancy for a full device launch - int gridSize = 0; // The actual grid size needed, based on input size + int grid_size = 0; // The actual grid size needed, based on input size int size = skinned_vertices->size(); - cudaOccupancyMaxPotentialBlockSize(&minGridSize, &blockSize, CopySkinnedVerticesKernel, 0, size); - gridSize = (size + blockSize - 1) / blockSize; - CopySkinnedVerticesKernel<<>>( - size, static_cast(skinnedVerticesBuffer.d_ptr), - static_cast(boneMatricesBuffer.d_ptr), static_cast(devicePositionBuffer.d_ptr), - static_cast(vertex_data_buffer.d_ptr)); + cudaOccupancyMaxPotentialBlockSize(&min_grid_size, &block_size, CopySkinnedVerticesKernel, 0, size); + grid_size = (size + block_size - 1) / block_size; + CopySkinnedVerticesKernel<<>>( + size, static_cast(skinned_vertices_buffer.d_ptr), + static_cast(bone_matrices_buffer.d_ptr), static_cast(device_position_buffer.d_ptr), + static_cast(vertex_data_buffer.d_ptr)); CUDA_SYNC_CHECK(); triangle_buffer.Upload(*triangles); - buildInput = {}; - buildInput.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + build_input = {}; + build_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; // create local variables, because we need a *pointer* to the // device pointers - deviceVertexPositions = devicePositionBuffer.DevicePointer(); - deviceVertexTriangles = triangle_buffer.DevicePointer(); - buildInput.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; - buildInput.triangleArray.vertexStrideInBytes = sizeof(glm::vec3); - buildInput.triangleArray.numVertices = static_cast(devicePositionBuffer.size_in_bytes / sizeof(glm::vec3)); - buildInput.triangleArray.vertexBuffers = &deviceVertexPositions; - buildInput.triangleArray.indexFormat = OPTIX_INDICES_FORMAT_UNSIGNED_INT3; - buildInput.triangleArray.indexStrideInBytes = sizeof(glm::uvec3); - buildInput.triangleArray.numIndexTriplets = static_cast(triangle_buffer.size_in_bytes / sizeof(glm::uvec3)); - buildInput.triangleArray.indexBuffer = deviceVertexTriangles; + device_vertex_positions = device_position_buffer.DevicePointer(); + device_vertex_triangles = triangle_buffer.DevicePointer(); + build_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + build_input.triangleArray.vertexStrideInBytes = sizeof(glm::vec3); + build_input.triangleArray.numVertices = + static_cast(device_position_buffer.size_in_bytes / sizeof(glm::vec3)); + build_input.triangleArray.vertexBuffers = &device_vertex_positions; + build_input.triangleArray.indexFormat = OPTIX_INDICES_FORMAT_UNSIGNED_INT3; + build_input.triangleArray.indexStrideInBytes = sizeof(glm::uvec3); + build_input.triangleArray.numIndexTriplets = static_cast(triangle_buffer.size_in_bytes / sizeof(glm::uvec3)); + build_input.triangleArray.indexBuffer = device_vertex_triangles; // in this example we have one SBT entry, and no per-primitive // materials: - buildInput.triangleArray.flags = triangleInputFlags; - buildInput.triangleArray.numSbtRecords = 1; - buildInput.triangleArray.sbtIndexOffsetBuffer = 0; - buildInput.triangleArray.sbtIndexOffsetSizeInBytes = 0; - buildInput.triangleArray.sbtIndexOffsetStrideInBytes = 0; - skinnedVerticesBuffer.Free(); - boneMatricesBuffer.Free(); + build_input.triangleArray.flags = triangle_input_flags; + build_input.triangleArray.numSbtRecords = 1; + build_input.triangleArray.sbtIndexOffsetBuffer = 0; + build_input.triangleArray.sbtIndexOffsetSizeInBytes = 0; + build_input.triangleArray.sbtIndexOffsetStrideInBytes = 0; + skinned_vertices_buffer.Free(); + bone_matrices_buffer.Free(); } break; case RendererType::Instanced: { - CUdeviceptr deviceVertexPositions; - CUdeviceptr deviceVertexTriangles; - - CudaBuffer verticesBuffer; - CudaBuffer instanceMatricesBuffer; - verticesBuffer.Upload(*vertices); - instanceMatricesBuffer.Upload(*instance_matrices); + CudaBuffer vertices_buffer; + CudaBuffer instance_matrices_buffer; + vertices_buffer.Upload(*vertices); + instance_matrices_buffer.Upload(*instance_matrices); vertex_data_buffer.Resize(instance_matrices->size() * vertices->size() * sizeof(evo_engine::Vertex)); - devicePositionBuffer.Resize(instance_matrices->size() * vertices->size() * sizeof(glm::vec3)); - int blockSize = 0; // The launch configurator returned block verticesSize - int minGridSize = 0; // The minimum grid verticesSize needed to achieve the + device_position_buffer.Resize(instance_matrices->size() * vertices->size() * sizeof(glm::vec3)); + int block_size = 0; // The launch configurator returned block verticesSize + int min_grid_size = 0; // The minimum grid verticesSize needed to achieve the // maximum occupancy for a full device launch - int gridSize = 0; // The actual grid verticesSize needed, based on input verticesSize - int verticesSize = vertices->size(); - int matricesSize = instance_matrices->size(); - int size = verticesSize * matricesSize; - cudaOccupancyMaxPotentialBlockSize(&minGridSize, &blockSize, CopyVerticesInstancedKernel, 0, size); - gridSize = (size + blockSize - 1) / blockSize; - CopyVerticesInstancedKernel<<>>( - matricesSize, verticesSize, static_cast(instanceMatricesBuffer.d_ptr), - static_cast(verticesBuffer.d_ptr), static_cast(devicePositionBuffer.d_ptr), + int grid_size = 0; // The actual grid verticesSize needed, based on input verticesSize + int vertices_size = vertices->size(); + int matrices_size = instance_matrices->size(); + int size = vertices_size * matrices_size; + cudaOccupancyMaxPotentialBlockSize(&min_grid_size, &block_size, CopyVerticesInstancedKernel, 0, size); + grid_size = (size + block_size - 1) / block_size; + CopyVerticesInstancedKernel<<>>( + matrices_size, vertices_size, static_cast(instance_matrices_buffer.d_ptr), + static_cast(vertices_buffer.d_ptr), static_cast(device_position_buffer.d_ptr), static_cast(vertex_data_buffer.d_ptr)); CUDA_SYNC_CHECK(); auto triangles = std::vector(); @@ -1113,30 +1094,31 @@ void RayTracedGeometry::BuildGas(const OptixDeviceContext &context) { offset += vertices->size(); } triangle_buffer.Upload(triangles); - buildInput = {}; - buildInput.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + build_input = {}; + build_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; // create local variables, because we need a *pointer* to the // device pointers - deviceVertexPositions = devicePositionBuffer.DevicePointer(); - deviceVertexTriangles = triangle_buffer.DevicePointer(); - buildInput.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; - buildInput.triangleArray.vertexStrideInBytes = sizeof(glm::vec3); - buildInput.triangleArray.numVertices = static_cast(devicePositionBuffer.size_in_bytes / sizeof(glm::vec3)); - buildInput.triangleArray.vertexBuffers = &deviceVertexPositions; - buildInput.triangleArray.indexFormat = OPTIX_INDICES_FORMAT_UNSIGNED_INT3; - buildInput.triangleArray.indexStrideInBytes = sizeof(glm::uvec3); - buildInput.triangleArray.numIndexTriplets = static_cast(triangle_buffer.size_in_bytes / sizeof(glm::uvec3)); - buildInput.triangleArray.indexBuffer = deviceVertexTriangles; + device_vertex_positions = device_position_buffer.DevicePointer(); + device_vertex_triangles = triangle_buffer.DevicePointer(); + build_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + build_input.triangleArray.vertexStrideInBytes = sizeof(glm::vec3); + build_input.triangleArray.numVertices = + static_cast(device_position_buffer.size_in_bytes / sizeof(glm::vec3)); + build_input.triangleArray.vertexBuffers = &device_vertex_positions; + build_input.triangleArray.indexFormat = OPTIX_INDICES_FORMAT_UNSIGNED_INT3; + build_input.triangleArray.indexStrideInBytes = sizeof(glm::uvec3); + build_input.triangleArray.numIndexTriplets = static_cast(triangle_buffer.size_in_bytes / sizeof(glm::uvec3)); + build_input.triangleArray.indexBuffer = device_vertex_triangles; // in this example we have one SBT entry, and no per-primitive // materials: - buildInput.triangleArray.flags = triangleInputFlags; - buildInput.triangleArray.numSbtRecords = 1; - buildInput.triangleArray.sbtIndexOffsetBuffer = 0; - buildInput.triangleArray.sbtIndexOffsetSizeInBytes = 0; - buildInput.triangleArray.sbtIndexOffsetStrideInBytes = 0; - verticesBuffer.Free(); - instanceMatricesBuffer.Free(); - instanceMatricesBuffer.Free(); + build_input.triangleArray.flags = triangle_input_flags; + build_input.triangleArray.numSbtRecords = 1; + build_input.triangleArray.sbtIndexOffsetBuffer = 0; + build_input.triangleArray.sbtIndexOffsetSizeInBytes = 0; + build_input.triangleArray.sbtIndexOffsetStrideInBytes = 0; + vertices_buffer.Free(); + instance_matrices_buffer.Free(); + instance_matrices_buffer.Free(); } break; } #pragma endregion @@ -1145,52 +1127,52 @@ void RayTracedGeometry::BuildGas(const OptixDeviceContext &context) { // BLAS setup // ================================================================== - OptixAccelBuildOptions accelerateOptions = {}; - accelerateOptions.buildFlags = + OptixAccelBuildOptions accelerate_options = {}; + accelerate_options.buildFlags = OPTIX_BUILD_FLAG_NONE | OPTIX_BUILD_FLAG_ALLOW_COMPACTION | OPTIX_BUILD_FLAG_PREFER_FAST_TRACE; - accelerateOptions.motionOptions.numKeys = 1; - accelerateOptions.operation = OPTIX_BUILD_OPERATION_BUILD; + accelerate_options.motionOptions.numKeys = 1; + accelerate_options.operation = OPTIX_BUILD_OPERATION_BUILD; - OptixAccelBufferSizes blasBufferSizes; - OPTIX_CHECK(optixAccelComputeMemoryUsage(context, &accelerateOptions, &buildInput, + OptixAccelBufferSizes blas_buffer_sizes; + OPTIX_CHECK(optixAccelComputeMemoryUsage(context, &accelerate_options, &build_input, 1, // num_build_inputs - &blasBufferSizes)); + &blas_buffer_sizes)); #pragma endregion #pragma region Prapere compaction // ================================================================== // prepare compaction // ================================================================== - CudaBuffer compactedSizeBuffer; - compactedSizeBuffer.Resize(sizeof(uint64_t)); - OptixAccelEmitDesc emitDesc; - emitDesc.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; - emitDesc.result = compactedSizeBuffer.DevicePointer(); + CudaBuffer compacted_size_buffer; + compacted_size_buffer.Resize(sizeof(uint64_t)); + OptixAccelEmitDesc emit_desc; + emit_desc.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emit_desc.result = compacted_size_buffer.DevicePointer(); #pragma endregion #pragma region Build AS // ================================================================== // execute build (main stage) // ================================================================== - CudaBuffer tempBuffer; - tempBuffer.Resize(blasBufferSizes.tempSizeInBytes); + CudaBuffer temp_buffer; + temp_buffer.Resize(blas_buffer_sizes.tempSizeInBytes); - CudaBuffer outputBuffer; - outputBuffer.Resize(blasBufferSizes.outputSizeInBytes); + CudaBuffer output_buffer; + output_buffer.Resize(blas_buffer_sizes.outputSizeInBytes); OPTIX_CHECK(optixAccelBuild(context, - /* stream */ nullptr, &accelerateOptions, &buildInput, 1, tempBuffer.DevicePointer(), - tempBuffer.size_in_bytes, outputBuffer.DevicePointer(), outputBuffer.size_in_bytes, - &traversable_handle, &emitDesc, 1)); + /* stream */ nullptr, &accelerate_options, &build_input, 1, temp_buffer.DevicePointer(), + temp_buffer.size_in_bytes, output_buffer.DevicePointer(), output_buffer.size_in_bytes, + &traversable_handle, &emit_desc, 1)); CUDA_SYNC_CHECK(); #pragma endregion #pragma region Perform compaction // ================================================================== // perform compaction // ================================================================== - uint64_t compactedSize; - compactedSizeBuffer.Download(&compactedSize, 1); - accelerated_structure_buffer.Resize(compactedSize); + uint64_t compacted_size; + compacted_size_buffer.Download(&compacted_size, 1); + accelerated_structure_buffer.Resize(compacted_size); OPTIX_CHECK(optixAccelCompact(context, /*stream:*/ nullptr, traversable_handle, accelerated_structure_buffer.DevicePointer(), accelerated_structure_buffer.size_in_bytes, &traversable_handle)); @@ -1198,15 +1180,15 @@ void RayTracedGeometry::BuildGas(const OptixDeviceContext &context) { #pragma endregion #pragma region Compaction clean up // ================================================================== - // aaaaaand .... clean up + // and .... clean up // ================================================================== - outputBuffer.Free(); // << the Uncompacted, temporary output buffer - tempBuffer.Free(); - compactedSizeBuffer.Free(); + output_buffer.Free(); // << the Un-compacted, temporary output buffer + temp_buffer.Free(); + compacted_size_buffer.Free(); #pragma endregion - devicePositionBuffer.Free(); - deviceWidthBuffer.Free(); + device_position_buffer.Free(); + device_width_buffer.Free(); update_flag = false; } @@ -1214,28 +1196,25 @@ void RayTracedGeometry::UploadForSbt() { geometry_buffer.Free(); if (geometry_type != PrimitiveType::Triangle) { Curves curves; - curves.strand_points = reinterpret_cast(vertex_data_buffer.DevicePointer()); - // curves.m_strandU = reinterpret_cast(curve_strand_u_buffer.DevicePointer()); - // curves.m_strandIndices = reinterpret_cast(curve_strand_i_buffer.DevicePointer()); - // curves.m_strandInfos = reinterpret_cast(curve_strand_info_buffer.DevicePointer()); + curves.strand_points = reinterpret_cast(vertex_data_buffer.DevicePointer()); curves.segments = reinterpret_cast(triangle_buffer.DevicePointer()); geometry_buffer.Upload(&curves, 1); } else { TriangularMesh mesh; - mesh.vertices = reinterpret_cast(vertex_data_buffer.DevicePointer()); + mesh.vertices = reinterpret_cast(vertex_data_buffer.DevicePointer()); mesh.triangles = reinterpret_cast(triangle_buffer.DevicePointer()); geometry_buffer.Upload(&mesh, 1); } } void OptiXRayTracer::BuildIas() { - std::vector removeQueue; + std::vector remove_queue; for (const auto &i : geometries) { if (i.second.remove_flag) { - removeQueue.emplace_back(i.first); + remove_queue.emplace_back(i.first); } } - for (auto &i : removeQueue) { + for (auto &i : remove_queue) { auto &geometry = geometries.at(i); geometry.geometry_buffer.Free(); geometry.vertex_data_buffer.Free(); @@ -1254,72 +1233,72 @@ void OptiXRayTracer::BuildIas() { i.second.UploadForSbt(); } } - removeQueue.clear(); + remove_queue.clear(); for (const auto &i : instances) { if (i.second.remove_flag) { - removeQueue.emplace_back(i.first); + remove_queue.emplace_back(i.first); } } - for (auto &i : removeQueue) { + for (auto &i : remove_queue) { instances.erase(i); } - std::vector optixInstances; - unsigned int sbtOffset = 0; + std::vector optix_instances; + unsigned int sbt_offset = 0; - OptixInstance optixInstance = {}; + OptixInstance optix_instance = {}; // Common optixInstance settings - optixInstance.instanceId = 0; - optixInstance.visibilityMask = 0xFF; - optixInstance.flags = OPTIX_INSTANCE_FLAG_NONE; + optix_instance.instanceId = 0; + optix_instance.visibilityMask = 0xFF; + optix_instance.flags = OPTIX_INSTANCE_FLAG_NONE; for (auto &instance : instances) { glm::mat3x4 transform = glm::transpose(instance.second.global_transform); - memcpy(optixInstance.transform, &transform, sizeof(glm::mat3x4)); - optixInstance.sbtOffset = sbtOffset; - optixInstance.traversableHandle = geometries.at(instance.second.geometry_map_key).traversable_handle; - sbtOffset += (int)RayType::RayTypeCount; - optixInstances.push_back(optixInstance); + memcpy(optix_instance.transform, &transform, sizeof(glm::mat3x4)); + optix_instance.sbtOffset = sbt_offset; + optix_instance.traversableHandle = geometries.at(instance.second.geometry_map_key).traversable_handle; + sbt_offset += static_cast(RayType::RayTypeCount); + optix_instances.push_back(optix_instance); } - CudaBuffer deviceTempInstances; - deviceTempInstances.Upload(optixInstances); + CudaBuffer device_temp_instances; + device_temp_instances.Upload(optix_instances); // Instance build input. - OptixBuildInput buildInput = {}; + OptixBuildInput build_input = {}; - buildInput.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; - buildInput.instanceArray.instances = deviceTempInstances.DevicePointer(); - buildInput.instanceArray.numInstances = static_cast(optixInstances.size()); + build_input.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; + build_input.instanceArray.instances = device_temp_instances.DevicePointer(); + build_input.instanceArray.numInstances = static_cast(optix_instances.size()); - OptixAccelBuildOptions accelBuildOptions = {}; - accelBuildOptions.buildFlags = OPTIX_BUILD_FLAG_NONE; - accelBuildOptions.operation = OPTIX_BUILD_OPERATION_BUILD; + OptixAccelBuildOptions accel_build_options = {}; + accel_build_options.buildFlags = OPTIX_BUILD_FLAG_NONE; + accel_build_options.operation = OPTIX_BUILD_OPERATION_BUILD; - OptixAccelBufferSizes bufferSizesIAS; - OPTIX_CHECK(optixAccelComputeMemoryUsage(optix_device_context_, &accelBuildOptions, &buildInput, + OptixAccelBufferSizes buffer_sizes_ias; + OPTIX_CHECK(optixAccelComputeMemoryUsage(optix_device_context_, &accel_build_options, &build_input, 1, // Number of build inputs - &bufferSizesIAS)); + &buffer_sizes_ias)); - CudaBuffer deviceTempBufferIAS; - deviceTempBufferIAS.Resize(bufferSizesIAS.tempSizeInBytes); - ias_buffer_.Resize(bufferSizesIAS.outputSizeInBytes); + CudaBuffer device_temp_buffer_ias; + device_temp_buffer_ias.Resize(buffer_sizes_ias.tempSizeInBytes); + ias_buffer_.Resize(buffer_sizes_ias.outputSizeInBytes); - OptixTraversableHandle iASHandle = 0; + OptixTraversableHandle i_as_handle = 0; OPTIX_CHECK(optixAccelBuild(optix_device_context_, - 0, // CUDA stream - &accelBuildOptions, &buildInput, + nullptr, // CUDA stream + &accel_build_options, &build_input, 1, // num build inputs - deviceTempBufferIAS.DevicePointer(), bufferSizesIAS.tempSizeInBytes, - ias_buffer_.DevicePointer(), bufferSizesIAS.outputSizeInBytes, &iASHandle, + device_temp_buffer_ias.DevicePointer(), buffer_sizes_ias.tempSizeInBytes, + ias_buffer_.DevicePointer(), buffer_sizes_ias.outputSizeInBytes, &i_as_handle, nullptr, // emitted property list 0)); // num emitted properties - deviceTempInstances.Free(); - deviceTempBufferIAS.Free(); + device_temp_instances.Free(); + device_temp_buffer_ias.Free(); - camera_rendering_launch_params_.traversable = iASHandle; - illumination_estimation_launch_params_.traversable = iASHandle; - point_cloud_scanning_launch_params_.traversable = iASHandle; + camera_rendering_launch_params_.traversable = i_as_handle; + illumination_estimation_launch_params_.traversable = i_as_handle; + point_cloud_scanning_launch_params_.traversable = i_as_handle; has_acceleration_structure_ = true; scene_modified = true; } @@ -1330,163 +1309,164 @@ void OptiXRayTracer::AssemblePipelines() { AssemblePipeline(point_cloud_scanning_pipeline_); } -void OptiXRayTracer::CreateRayGenProgram(RayTracerPipeline &targetPipeline, char entryFunctionName[]) const { - OptixProgramGroupOptions pgOptions = {}; - OptixProgramGroupDesc pgDesc = {}; - pgDesc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; - pgDesc.raygen.module = targetPipeline.module; - pgDesc.raygen.entryFunctionName = entryFunctionName; +void OptiXRayTracer::CreateRayGenProgram(RayTracerPipeline &target_pipeline, char entry_function_name[]) const { + constexpr OptixProgramGroupOptions pg_options = {}; + OptixProgramGroupDesc pg_desc = {}; + pg_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + pg_desc.raygen.module = target_pipeline.module; + pg_desc.raygen.entryFunctionName = entry_function_name; char log[2048]; - size_t sizeofLog = sizeof(log); - OPTIX_CHECK(optixProgramGroupCreate(optix_device_context_, &pgDesc, 1, &pgOptions, log, &sizeofLog, - &targetPipeline.ray_gen_program_groups)); - if (sizeofLog > 1) + size_t sizeof_log = sizeof(log); + OPTIX_CHECK(optixProgramGroupCreate(optix_device_context_, &pg_desc, 1, &pg_options, log, &sizeof_log, + &target_pipeline.ray_gen_program_groups)); + if (sizeof_log > 1) std::cout << log << std::endl; } -void OptiXRayTracer::CreateModule(RayTracerPipeline &targetPipeline, char ptxCode[], char launchParamsName[]) const { - targetPipeline.launch_params_name = launchParamsName; - - targetPipeline.module_compile_options.maxRegisterCount = 50; - targetPipeline.module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_DEFAULT; - targetPipeline.module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_NONE; - - targetPipeline.pipeline_compile_options = {}; - targetPipeline.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_ANY; - targetPipeline.pipeline_compile_options.usesMotionBlur = false; - targetPipeline.pipeline_compile_options.numPayloadValues = 2; - targetPipeline.pipeline_compile_options.numAttributeValues = 2; - targetPipeline.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; - targetPipeline.pipeline_compile_options.pipelineLaunchParamsVariableName = launchParamsName; - targetPipeline.pipeline_compile_options.usesPrimitiveTypeFlags = +void OptiXRayTracer::CreateModule(RayTracerPipeline &target_pipeline, char ptx_code[], + char launch_params_name[]) const { + target_pipeline.launch_params_name = launch_params_name; + + target_pipeline.module_compile_options.maxRegisterCount = 50; + target_pipeline.module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_DEFAULT; + target_pipeline.module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_NONE; + + target_pipeline.pipeline_compile_options = {}; + target_pipeline.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_ANY; + target_pipeline.pipeline_compile_options.usesMotionBlur = false; + target_pipeline.pipeline_compile_options.numPayloadValues = 2; + target_pipeline.pipeline_compile_options.numAttributeValues = 2; + target_pipeline.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + target_pipeline.pipeline_compile_options.pipelineLaunchParamsVariableName = launch_params_name; + target_pipeline.pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE | OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_LINEAR | OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_QUADRATIC_BSPLINE | OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CUBIC_BSPLINE; - const std::string code = ptxCode; + const std::string code = ptx_code; char log[2048]; size_t sizeof_log = sizeof(log); - OPTIX_CHECK(optixModuleCreate(optix_device_context_, &targetPipeline.module_compile_options, - &targetPipeline.pipeline_compile_options, code.c_str(), code.size(), log, &sizeof_log, - &targetPipeline.module)); - - OptixBuiltinISOptions builtinISOptions = {}; - builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_QUADRATIC_BSPLINE; - builtinISOptions.curveEndcapFlags = OPTIX_CURVE_ENDCAP_ON; - OPTIX_CHECK(optixBuiltinISModuleGet(optix_device_context_, &targetPipeline.module_compile_options, - &targetPipeline.pipeline_compile_options, &builtinISOptions, - &targetPipeline.quadratic_curve_module)); - - builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE; - OPTIX_CHECK(optixBuiltinISModuleGet(optix_device_context_, &targetPipeline.module_compile_options, - &targetPipeline.pipeline_compile_options, &builtinISOptions, - &targetPipeline.cubic_curve_module)); - - builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_LINEAR; - OPTIX_CHECK(optixBuiltinISModuleGet(optix_device_context_, &targetPipeline.module_compile_options, - &targetPipeline.pipeline_compile_options, &builtinISOptions, - &targetPipeline.linear_curve_module)); + OPTIX_CHECK(optixModuleCreate(optix_device_context_, &target_pipeline.module_compile_options, + &target_pipeline.pipeline_compile_options, code.c_str(), code.size(), log, &sizeof_log, + &target_pipeline.module)); + + OptixBuiltinISOptions builtin_is_options = {}; + builtin_is_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_QUADRATIC_BSPLINE; + builtin_is_options.curveEndcapFlags = OPTIX_CURVE_ENDCAP_ON; + OPTIX_CHECK(optixBuiltinISModuleGet(optix_device_context_, &target_pipeline.module_compile_options, + &target_pipeline.pipeline_compile_options, &builtin_is_options, + &target_pipeline.quadratic_curve_module)); + + builtin_is_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE; + OPTIX_CHECK(optixBuiltinISModuleGet(optix_device_context_, &target_pipeline.module_compile_options, + &target_pipeline.pipeline_compile_options, &builtin_is_options, + &target_pipeline.cubic_curve_module)); + + builtin_is_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_LINEAR; + OPTIX_CHECK(optixBuiltinISModuleGet(optix_device_context_, &target_pipeline.module_compile_options, + &target_pipeline.pipeline_compile_options, &builtin_is_options, + &target_pipeline.linear_curve_module)); if (sizeof_log > 1) std::cout << log << std::endl; } -void OptiXRayTracer::AssemblePipeline(RayTracerPipeline &targetPipeline) const { - std::vector programGroups; - programGroups.push_back(targetPipeline.ray_gen_program_groups); - for (auto &i : targetPipeline.miss_program_groups) - programGroups.push_back(i.second); - for (auto &i : targetPipeline.hit_group_program_groups) +void OptiXRayTracer::AssemblePipeline(RayTracerPipeline &target_pipeline) const { + std::vector program_groups; + program_groups.push_back(target_pipeline.ray_gen_program_groups); + for (auto &i : target_pipeline.miss_program_groups) + program_groups.push_back(i.second); + for (auto &i : target_pipeline.hit_group_program_groups) for (auto &j : i.second) - programGroups.push_back(j.second); + program_groups.push_back(j.second); - const uint32_t maxTraceDepth = 31; - targetPipeline.pipeline_link_options.maxTraceDepth = maxTraceDepth; + constexpr uint32_t max_trace_depth = 31; + target_pipeline.pipeline_link_options.maxTraceDepth = max_trace_depth; char log[2048]; - size_t sizeofLog = sizeof(log); - OPTIX_CHECK(optixPipelineCreate(optix_device_context_, &targetPipeline.pipeline_compile_options, - &targetPipeline.pipeline_link_options, programGroups.data(), - static_cast(programGroups.size()), log, &sizeofLog, &targetPipeline.pipeline)); - if (sizeofLog > 1) + size_t sizeof_log = sizeof(log); + OPTIX_CHECK(optixPipelineCreate( + optix_device_context_, &target_pipeline.pipeline_compile_options, &target_pipeline.pipeline_link_options, + program_groups.data(), static_cast(program_groups.size()), log, &sizeof_log, &target_pipeline.pipeline)); + if (sizeof_log > 1) std::cout << log << std::endl; - OptixStackSizes stackSizes = {}; - for (auto &progGroup : programGroups) { - OPTIX_CHECK(optixUtilAccumulateStackSizes(progGroup, &stackSizes, targetPipeline.pipeline)); + OptixStackSizes stack_sizes = {}; + for (const auto &program_group : program_groups) { + OPTIX_CHECK(optixUtilAccumulateStackSizes(program_group, &stack_sizes, target_pipeline.pipeline)); } - uint32_t directCallableStackSizeFromTraversal; - uint32_t directCallableStackSizeFromState; - uint32_t continuationStackSize; - OPTIX_CHECK(optixUtilComputeStackSizes(&stackSizes, maxTraceDepth, + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK(optixUtilComputeStackSizes(&stack_sizes, max_trace_depth, 0, // maxCCDepth 0, // maxDCDEpth - &directCallableStackSizeFromTraversal, &directCallableStackSizeFromState, - &continuationStackSize)); - OPTIX_CHECK(optixPipelineSetStackSize(targetPipeline.pipeline, directCallableStackSizeFromTraversal, - directCallableStackSizeFromState, continuationStackSize, + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size)); + OPTIX_CHECK(optixPipelineSetStackSize(target_pipeline.pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, 2 // maxTraversableDepth )); - if (sizeofLog > 1) + if (sizeof_log > 1) std::cout << log << std::endl; } void OptiXRayTracer::BuildSbt() { - std::vector removeQueue; + std::vector remove_queue; for (auto &i : materials) { auto &material = i.second; material.material_buffer.Free(); if (material.remove_flag) { - removeQueue.emplace_back(i.first); + remove_queue.emplace_back(i.first); } else { material.UploadForSbt(); } } - for (auto &i : removeQueue) { - auto &material = materials.at(i); + for (auto &i : remove_queue) { materials.erase(i); } #pragma region Prepare SBTs - std::map sBTs; - for (auto &instancePair : instances) { - auto &instance = instancePair.second; + std::map shader_binding_tables; + for (auto &instance_pair : instances) { + auto &instance = instance_pair.second; auto &material = materials.at(instance.material_map_key); auto &geometry = geometries.at(instance.geometry_map_key); - auto &sBT = sBTs[instancePair.first]; - sBT.handle = instance.private_component_handle; - sBT.global_transform = instance.global_transform; - sBT.geometry_type = geometry.renderer_type; - sBT.geometry = reinterpret_cast(geometry.geometry_buffer.DevicePointer()); - sBT.material_type = material.material_type; - sBT.material = reinterpret_cast(material.material_buffer.DevicePointer()); + auto &sbt = shader_binding_tables[instance_pair.first]; + sbt.handle = instance.private_component_handle; + sbt.global_transform = instance.global_transform; + sbt.geometry_type = geometry.renderer_type; + sbt.geometry = reinterpret_cast(geometry.geometry_buffer.DevicePointer()); + sbt.material_type = material.material_type; + sbt.material = reinterpret_cast(material.material_buffer.DevicePointer()); } #pragma endregion { // ------------------------------------------------------------------ // build raygen records // ------------------------------------------------------------------ - std::vector raygenRecords; - CameraRenderingRayGenRecord rec; - OPTIX_CHECK(optixSbtRecordPackHeader(camera_rendering_pipeline_.ray_gen_program_groups, &rec)); - rec.data = nullptr; /* for now ... */ - raygenRecords.push_back(rec); - camera_rendering_pipeline_.ray_gen_records_buffer.Upload(raygenRecords); + std::vector raygen_records; + CameraRenderingRayGenRecord camera_rendering_ray_gen_record; + OPTIX_CHECK( + optixSbtRecordPackHeader(camera_rendering_pipeline_.ray_gen_program_groups, &camera_rendering_ray_gen_record)); + camera_rendering_ray_gen_record.data = nullptr; /* for now ... */ + raygen_records.push_back(camera_rendering_ray_gen_record); + camera_rendering_pipeline_.ray_gen_records_buffer.Upload(raygen_records); camera_rendering_pipeline_.sbt.raygenRecord = camera_rendering_pipeline_.ray_gen_records_buffer.DevicePointer(); // ------------------------------------------------------------------ // build miss records // ------------------------------------------------------------------ - std::vector missRecords; + std::vector miss_records; for (auto &i : camera_rendering_pipeline_.miss_program_groups) { - CameraRenderingRayMissRecord rec; - OPTIX_CHECK(optixSbtRecordPackHeader(i.second, &rec)); - rec.data = nullptr; /* for now ... */ - missRecords.push_back(rec); + CameraRenderingRayMissRecord camera_rendering_ray_miss_record; + OPTIX_CHECK(optixSbtRecordPackHeader(i.second, &camera_rendering_ray_miss_record)); + camera_rendering_ray_miss_record.data = nullptr; /* for now ... */ + miss_records.push_back(camera_rendering_ray_miss_record); } - camera_rendering_pipeline_.miss_records_buffer.Upload(missRecords); + camera_rendering_pipeline_.miss_records_buffer.Upload(miss_records); camera_rendering_pipeline_.sbt.missRecordBase = camera_rendering_pipeline_.miss_records_buffer.DevicePointer(); camera_rendering_pipeline_.sbt.missRecordStrideInBytes = sizeof(CameraRenderingRayMissRecord); - camera_rendering_pipeline_.sbt.missRecordCount = static_cast(missRecords.size()); + camera_rendering_pipeline_.sbt.missRecordCount = static_cast(miss_records.size()); // ------------------------------------------------------------------ // build hit records @@ -1496,52 +1476,52 @@ void OptiXRayTracer::BuildSbt() { // create a dummy one so the SBT doesn't have any null pointers // (which the sanity checks in compilation would complain about) - std::vector hitGroupRecords; - for (auto &instancePair : instances) { - for (int rayID = 0; rayID < static_cast(RayType::RayTypeCount); rayID++) { - auto &collection = camera_rendering_pipeline_.hit_group_program_groups[(RayType)rayID]; - auto &geometry = geometries[instancePair.second.geometry_map_key]; + std::vector hit_group_records; + for (auto &instance_pair : instances) { + for (int ray_id = 0; ray_id < static_cast(RayType::RayTypeCount); ray_id++) { + auto &collection = camera_rendering_pipeline_.hit_group_program_groups[static_cast(ray_id)]; + auto &geometry = geometries[instance_pair.second.geometry_map_key]; auto group = collection[geometry.geometry_type]; CameraRenderingRayHitRecord rec; - rec.data = sBTs[instancePair.first]; + rec.data = shader_binding_tables[instance_pair.first]; OPTIX_CHECK(optixSbtRecordPackHeader(group, &rec)); - hitGroupRecords.push_back(rec); + hit_group_records.push_back(rec); } } - camera_rendering_pipeline_.hit_group_records_buffer.Upload(hitGroupRecords); + camera_rendering_pipeline_.hit_group_records_buffer.Upload(hit_group_records); camera_rendering_pipeline_.sbt.hitgroupRecordBase = camera_rendering_pipeline_.hit_group_records_buffer.DevicePointer(); camera_rendering_pipeline_.sbt.hitgroupRecordStrideInBytes = sizeof(CameraRenderingRayHitRecord); - camera_rendering_pipeline_.sbt.hitgroupRecordCount = static_cast(hitGroupRecords.size()); + camera_rendering_pipeline_.sbt.hitgroupRecordCount = static_cast(hit_group_records.size()); } { // ------------------------------------------------------------------ // build raygen records // ------------------------------------------------------------------ - std::vector raygenRecords; + std::vector raygen_records; IlluminationEstimationRayGenRecord rec; OPTIX_CHECK(optixSbtRecordPackHeader(illumination_estimation_pipeline_.ray_gen_program_groups, &rec)); rec.data = nullptr; /* for now ... */ - raygenRecords.push_back(rec); - illumination_estimation_pipeline_.ray_gen_records_buffer.Upload(raygenRecords); + raygen_records.push_back(rec); + illumination_estimation_pipeline_.ray_gen_records_buffer.Upload(raygen_records); illumination_estimation_pipeline_.sbt.raygenRecord = illumination_estimation_pipeline_.ray_gen_records_buffer.DevicePointer(); // ------------------------------------------------------------------ // build miss records // ------------------------------------------------------------------ - std::vector missRecords; + std::vector miss_records; for (auto &i : illumination_estimation_pipeline_.miss_program_groups) { - IlluminationEstimationRayMissRecord rec; - OPTIX_CHECK(optixSbtRecordPackHeader(i.second, &rec)); - rec.data = nullptr; /* for now ... */ - missRecords.push_back(rec); + IlluminationEstimationRayMissRecord illumination_estimation_ray_miss_record; + OPTIX_CHECK(optixSbtRecordPackHeader(i.second, &illumination_estimation_ray_miss_record)); + illumination_estimation_ray_miss_record.data = nullptr; /* for now ... */ + miss_records.push_back(illumination_estimation_ray_miss_record); } - illumination_estimation_pipeline_.miss_records_buffer.Upload(missRecords); + illumination_estimation_pipeline_.miss_records_buffer.Upload(miss_records); illumination_estimation_pipeline_.sbt.missRecordBase = illumination_estimation_pipeline_.miss_records_buffer.DevicePointer(); illumination_estimation_pipeline_.sbt.missRecordStrideInBytes = sizeof(IlluminationEstimationRayMissRecord); - illumination_estimation_pipeline_.sbt.missRecordCount = static_cast(missRecords.size()); + illumination_estimation_pipeline_.sbt.missRecordCount = static_cast(miss_records.size()); // ------------------------------------------------------------------ // build hit records @@ -1550,53 +1530,53 @@ void OptiXRayTracer::BuildSbt() { // we don't actually have any objects in this example, but let's // create a dummy one so the SBT doesn't have any null pointers // (which the sanity checks in compilation would complain about) - std::vector hitGroupRecords; - for (auto &instancePair : instances) { - for (int rayID = 0; rayID < static_cast(RayType::RayTypeCount); rayID++) { - auto &collection = illumination_estimation_pipeline_.hit_group_program_groups[(RayType)rayID]; - auto &geometry = geometries[instancePair.second.geometry_map_key]; + std::vector hit_group_records; + for (auto &instance_pair : instances) { + for (int ray_id = 0; ray_id < static_cast(RayType::RayTypeCount); ray_id++) { + auto &collection = illumination_estimation_pipeline_.hit_group_program_groups[static_cast(ray_id)]; + auto &geometry = geometries[instance_pair.second.geometry_map_key]; auto group = collection[geometry.geometry_type]; - IlluminationEstimationRayHitRecord rec; - rec.data = sBTs[instancePair.first]; - OPTIX_CHECK(optixSbtRecordPackHeader(group, &rec)); - hitGroupRecords.push_back(rec); + IlluminationEstimationRayHitRecord illumination_estimation_ray_hit_record; + illumination_estimation_ray_hit_record.data = shader_binding_tables[instance_pair.first]; + OPTIX_CHECK(optixSbtRecordPackHeader(group, &illumination_estimation_ray_hit_record)); + hit_group_records.push_back(illumination_estimation_ray_hit_record); } } - illumination_estimation_pipeline_.hit_group_records_buffer.Upload(hitGroupRecords); + illumination_estimation_pipeline_.hit_group_records_buffer.Upload(hit_group_records); illumination_estimation_pipeline_.sbt.hitgroupRecordBase = illumination_estimation_pipeline_.hit_group_records_buffer.DevicePointer(); illumination_estimation_pipeline_.sbt.hitgroupRecordStrideInBytes = sizeof(IlluminationEstimationRayHitRecord); - illumination_estimation_pipeline_.sbt.hitgroupRecordCount = static_cast(hitGroupRecords.size()); + illumination_estimation_pipeline_.sbt.hitgroupRecordCount = static_cast(hit_group_records.size()); } { // ------------------------------------------------------------------ // build raygen records // ------------------------------------------------------------------ - std::vector raygenRecords; + std::vector raygen_records; PointCloudScanningRayGenRecord rec; OPTIX_CHECK(optixSbtRecordPackHeader(point_cloud_scanning_pipeline_.ray_gen_program_groups, &rec)); rec.data = nullptr; /* for now ... */ - raygenRecords.push_back(rec); - point_cloud_scanning_pipeline_.ray_gen_records_buffer.Upload(raygenRecords); + raygen_records.push_back(rec); + point_cloud_scanning_pipeline_.ray_gen_records_buffer.Upload(raygen_records); point_cloud_scanning_pipeline_.sbt.raygenRecord = point_cloud_scanning_pipeline_.ray_gen_records_buffer.DevicePointer(); // ------------------------------------------------------------------ // build miss records // ------------------------------------------------------------------ - std::vector missRecords; + std::vector miss_records; for (auto &i : point_cloud_scanning_pipeline_.miss_program_groups) { - PointCloudScanningRayMissRecord rec; - OPTIX_CHECK(optixSbtRecordPackHeader(i.second, &rec)); - rec.data = nullptr; /* for now ... */ - missRecords.push_back(rec); + PointCloudScanningRayMissRecord point_cloud_scanning_ray_miss_record; + OPTIX_CHECK(optixSbtRecordPackHeader(i.second, &point_cloud_scanning_ray_miss_record)); + point_cloud_scanning_ray_miss_record.data = nullptr; /* for now ... */ + miss_records.push_back(point_cloud_scanning_ray_miss_record); } - point_cloud_scanning_pipeline_.miss_records_buffer.Upload(missRecords); + point_cloud_scanning_pipeline_.miss_records_buffer.Upload(miss_records); point_cloud_scanning_pipeline_.sbt.missRecordBase = point_cloud_scanning_pipeline_.miss_records_buffer.DevicePointer(); point_cloud_scanning_pipeline_.sbt.missRecordStrideInBytes = sizeof(PointCloudScanningRayMissRecord); - point_cloud_scanning_pipeline_.sbt.missRecordCount = static_cast(missRecords.size()); + point_cloud_scanning_pipeline_.sbt.missRecordCount = static_cast(miss_records.size()); // ------------------------------------------------------------------ // build hit records @@ -1605,23 +1585,23 @@ void OptiXRayTracer::BuildSbt() { // we don't actually have any objects in this example, but let's // create a dummy one so the SBT doesn't have any null pointers // (which the sanity checks in compilation would complain about) - std::vector hitGroupRecords; - for (auto &instancePair : instances) { - for (int rayID = 0; rayID < static_cast(RayType::RayTypeCount); rayID++) { - auto &collection = point_cloud_scanning_pipeline_.hit_group_program_groups[(RayType)rayID]; - auto &geometry = geometries[instancePair.second.geometry_map_key]; + std::vector hit_group_records; + for (auto &instance_pair : instances) { + for (int ray_id = 0; ray_id < static_cast(RayType::RayTypeCount); ray_id++) { + auto &collection = point_cloud_scanning_pipeline_.hit_group_program_groups[(RayType)ray_id]; + auto &geometry = geometries[instance_pair.second.geometry_map_key]; auto group = collection[geometry.geometry_type]; - PointCloudScanningRayHitRecord rec; - rec.data = sBTs[instancePair.first]; - OPTIX_CHECK(optixSbtRecordPackHeader(group, &rec)); - hitGroupRecords.push_back(rec); + PointCloudScanningRayHitRecord point_cloud_scanning_ray_hit_record; + point_cloud_scanning_ray_hit_record.data = shader_binding_tables[instance_pair.first]; + OPTIX_CHECK(optixSbtRecordPackHeader(group, &point_cloud_scanning_ray_hit_record)); + hit_group_records.push_back(point_cloud_scanning_ray_hit_record); } } - point_cloud_scanning_pipeline_.hit_group_records_buffer.Upload(hitGroupRecords); + point_cloud_scanning_pipeline_.hit_group_records_buffer.Upload(hit_group_records); point_cloud_scanning_pipeline_.sbt.hitgroupRecordBase = point_cloud_scanning_pipeline_.hit_group_records_buffer.DevicePointer(); point_cloud_scanning_pipeline_.sbt.hitgroupRecordStrideInBytes = sizeof(PointCloudScanningRayHitRecord); - point_cloud_scanning_pipeline_.sbt.hitgroupRecordCount = static_cast(hitGroupRecords.size()); + point_cloud_scanning_pipeline_.sbt.hitgroupRecordCount = static_cast(hit_group_records.size()); } } @@ -1684,20 +1664,18 @@ void RayTracedMaterial::UploadForSbt() { void RayTracedMaterial::BindTexture(unsigned int id, cudaGraphicsResource_t &graphics_resource, cudaTextureObject_t &texture_object) { - cudaArray_t textureArray; + cudaArray_t texture_array; CUDA_CHECK(GraphicsGLRegisterImage(&graphics_resource, id, GL_TEXTURE_2D, cudaGraphicsRegisterFlagsReadOnly)); CUDA_CHECK(GraphicsMapResources(1, &graphics_resource, nullptr)); - CUDA_CHECK(GraphicsSubResourceGetMappedArray(&textureArray, graphics_resource, 0, 0)); - struct cudaResourceDesc cudaResourceDesc; - memset(&cudaResourceDesc, 0, sizeof(cudaResourceDesc)); - cudaResourceDesc.resType = cudaResourceTypeArray; - cudaResourceDesc.res.array.array = textureArray; - struct cudaTextureDesc cudaTextureDesc; - memset(&cudaTextureDesc, 0, sizeof(cudaTextureDesc)); - cudaTextureDesc.addressMode[0] = cudaAddressModeWrap; - cudaTextureDesc.addressMode[1] = cudaAddressModeWrap; - cudaTextureDesc.filterMode = cudaFilterModeLinear; - cudaTextureDesc.readMode = cudaReadModeElementType; - cudaTextureDesc.normalizedCoords = 1; - CUDA_CHECK(CreateTextureObject(&texture_object, &cudaResourceDesc, &cudaTextureDesc, nullptr)); + CUDA_CHECK(GraphicsSubResourceGetMappedArray(&texture_array, graphics_resource, 0, 0)); + cudaResourceDesc cuda_resource_desc = {}; + cuda_resource_desc.resType = cudaResourceTypeArray; + cuda_resource_desc.res.array.array = texture_array; + cudaTextureDesc cuda_texture_desc = {}; + cuda_texture_desc.addressMode[0] = cudaAddressModeWrap; + cuda_texture_desc.addressMode[1] = cudaAddressModeWrap; + cuda_texture_desc.filterMode = cudaFilterModeLinear; + cuda_texture_desc.readMode = cudaReadModeElementType; + cuda_texture_desc.normalizedCoords = 1; + CUDA_CHECK(CreateTextureObject(&texture_object, &cuda_resource_desc, &cuda_texture_desc, nullptr)); } diff --git a/EvoEngine_Plugins/EcoSysLab/src/DsColliders.cpp b/EvoEngine_Plugins/EcoSysLab/src/DsColliders.cpp index 3aebb2d8..c629593e 100644 --- a/EvoEngine_Plugins/EcoSysLab/src/DsColliders.cpp +++ b/EvoEngine_Plugins/EcoSysLab/src/DsColliders.cpp @@ -31,7 +31,7 @@ DsBoxCollider::DsBoxCollider() { if (!segment_position_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Colliders/SegmentBox.comp"); @@ -49,7 +49,7 @@ DsBoxCollider::DsBoxCollider() { if (!leaf_position_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Colliders/LeafBox.comp"); @@ -68,7 +68,7 @@ DsBoxCollider::DsBoxCollider() { if (!segment_velocity_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Velocity/Colliders/SegmentBox.comp"); @@ -86,7 +86,7 @@ DsBoxCollider::DsBoxCollider() { if (!leaf_velocity_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Velocity/Colliders/LeafBox.comp"); @@ -288,7 +288,7 @@ DsCylinderCollider::DsCylinderCollider() { if (!segment_position_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Colliders/SegmentCylinder.comp"); @@ -307,7 +307,7 @@ DsCylinderCollider::DsCylinderCollider() { if (!leaf_position_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Colliders/LeafCylinder.comp"); @@ -435,7 +435,7 @@ DsSphereCollider::DsSphereCollider() { if (!segment_position_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Colliders/SegmentSphere.comp"); @@ -454,7 +454,7 @@ DsSphereCollider::DsSphereCollider() { if (!leaf_position_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Colliders/LeafSphere.comp"); diff --git a/EvoEngine_Plugins/EcoSysLab/src/DsConstraints.cpp b/EvoEngine_Plugins/EcoSysLab/src/DsConstraints.cpp index 3bf310b3..f714c0e0 100644 --- a/EvoEngine_Plugins/EcoSysLab/src/DsConstraints.cpp +++ b/EvoEngine_Plugins/EcoSysLab/src/DsConstraints.cpp @@ -24,7 +24,7 @@ DsPivotPoint::DsPivotPoint() { if (!segment_update_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/PivotPoint.comp"); @@ -114,7 +114,7 @@ DsPivotAxis::DsPivotAxis() { if (!segment_update_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/PivotAxis.comp"); @@ -217,7 +217,7 @@ DsPivotTransform::DsPivotTransform() { if (!segment_update_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/PivotTransform.comp"); @@ -313,7 +313,7 @@ DsStiffRod::DsStiffRod() { if (!pipeline) { static std::shared_ptr stretch_shear_shader{}; stretch_shear_shader = std::make_shared(); - stretch_shear_shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + stretch_shear_shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/StiffRod.comp"); pipeline = std::make_shared(); @@ -378,7 +378,7 @@ DsBundle::DsBundle() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/CalculateShearStretchCorrections.comp"); stretch_shear_pipeline = std::make_shared(); @@ -396,7 +396,7 @@ DsBundle::DsBundle() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/CalculateBendTwistCorrections.comp"); bend_twist_pipeline = std::make_shared(); @@ -414,7 +414,7 @@ DsBundle::DsBundle() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/CalculateBundlePositionCorrections.comp"); bundle_position_pipeline = std::make_shared(); @@ -432,7 +432,7 @@ DsBundle::DsBundle() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/CalculateBundleRotationCorrections.comp"); bundle_rotation_pipeline = std::make_shared(); @@ -449,7 +449,7 @@ DsBundle::DsBundle() { if (!apply_rotation_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/ApplyRotationCorrections.comp"); @@ -469,7 +469,7 @@ DsBundle::DsBundle() { if (!apply_position_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/ApplyPositionCorrections.comp"); @@ -489,7 +489,7 @@ DsBundle::DsBundle() { if (!apply_position_rotation_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/ApplyCorrections.comp"); @@ -509,7 +509,7 @@ DsBundle::DsBundle() { if (!connections_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/ConnectionCorrections.comp"); @@ -729,7 +729,7 @@ bool DsBundle::OnInspect(const std::shared_ptr& editor_layer) { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/CalculateShearStretchCorrections.comp"); stretch_shear_pipeline = std::make_shared(); @@ -747,7 +747,7 @@ bool DsBundle::OnInspect(const std::shared_ptr& editor_layer) { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/CalculateBendTwistCorrections.comp"); bend_twist_pipeline = std::make_shared(); @@ -765,7 +765,7 @@ bool DsBundle::OnInspect(const std::shared_ptr& editor_layer) { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/CalculateBundlePositionCorrections.comp"); bundle_position_pipeline = std::make_shared(); @@ -783,7 +783,7 @@ bool DsBundle::OnInspect(const std::shared_ptr& editor_layer) { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/CalculateBundleRotationCorrections.comp"); bundle_rotation_pipeline = std::make_shared(); @@ -801,7 +801,7 @@ bool DsBundle::OnInspect(const std::shared_ptr& editor_layer) { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/ApplyRotationCorrections.comp"); @@ -822,7 +822,7 @@ bool DsBundle::OnInspect(const std::shared_ptr& editor_layer) { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/ApplyPositionCorrections.comp"); @@ -842,7 +842,7 @@ bool DsBundle::OnInspect(const std::shared_ptr& editor_layer) { { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/ApplyCorrections.comp"); @@ -862,7 +862,7 @@ bool DsBundle::OnInspect(const std::shared_ptr& editor_layer) { { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/Bundle/ConnectionCorrections.comp"); @@ -884,7 +884,7 @@ bool DsBundle::OnInspect(const std::shared_ptr& editor_layer) { DsLeafAttachment::DsLeafAttachment() { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Constraints/Position/LeafAttachment.comp"); diff --git a/EvoEngine_Plugins/EcoSysLab/src/DsOperators.cpp b/EvoEngine_Plugins/EcoSysLab/src/DsOperators.cpp index 944d8a36..8c32360d 100644 --- a/EvoEngine_Plugins/EcoSysLab/src/DsOperators.cpp +++ b/EvoEngine_Plugins/EcoSysLab/src/DsOperators.cpp @@ -52,7 +52,7 @@ DsLeafDrop::DsLeafDrop() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/LeafDrop.comp"); pipeline = std::make_shared(); pipeline->compute_shader = shader; @@ -94,7 +94,7 @@ DsAttraction::DsAttraction() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/Attraction.comp"); drag_force_pipeline = std::make_shared(); drag_force_pipeline->compute_shader = shader; @@ -164,7 +164,7 @@ DsBoxSelection::DsBoxSelection() { if (!segment_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/SegmentBoxSelection.comp"); segment_pipeline = std::make_shared(); @@ -180,7 +180,7 @@ DsBoxSelection::DsBoxSelection() { if (!leaf_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/LeafBoxSelection.comp"); leaf_pipeline = std::make_shared(); @@ -242,7 +242,7 @@ DsDrag::DsDrag() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/Drag.comp"); pipeline = std::make_shared(); pipeline->compute_shader = shader; @@ -285,7 +285,7 @@ DsLineCut::DsLineCut() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/LineCut.comp"); pipeline = std::make_shared(); pipeline->compute_shader = shader; @@ -330,7 +330,7 @@ DsPointCut::DsPointCut() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/PointCut.comp"); pipeline = std::make_shared(); pipeline->compute_shader = shader; @@ -401,7 +401,7 @@ DsSaw::DsSaw() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/Saw.comp"); pipeline = std::make_shared(); pipeline->compute_shader = shader; @@ -458,7 +458,7 @@ DsSnow::DsSnow() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/SegmentSnow.comp"); segment_pipeline = std::make_shared(); segment_pipeline->compute_shader = shader; @@ -476,7 +476,7 @@ DsSnow::DsSnow() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/LeafSnow.comp"); leaf_pipeline = std::make_shared(); leaf_pipeline->compute_shader = shader; @@ -548,7 +548,7 @@ DsWind::DsWind() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/SegmentWind.comp"); segment_pipeline = std::make_shared(); segment_pipeline->compute_shader = shader; @@ -566,7 +566,7 @@ DsWind::DsWind() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/LeafWind.comp"); leaf_pipeline = std::make_shared(); leaf_pipeline->compute_shader = shader; @@ -649,7 +649,7 @@ DsStopAll::DsStopAll() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/SegmentStopAll.comp"); segment_pipeline = std::make_shared(); segment_pipeline->compute_shader = shader; @@ -667,7 +667,7 @@ DsStopAll::DsStopAll() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Operators/LeafStopAll.comp"); leaf_pipeline = std::make_shared(); leaf_pipeline->compute_shader = shader; diff --git a/EvoEngine_Plugins/EcoSysLab/src/DsPhysics.cpp b/EvoEngine_Plugins/EcoSysLab/src/DsPhysics.cpp index ff81fde1..c30d863b 100644 --- a/EvoEngine_Plugins/EcoSysLab/src/DsPhysics.cpp +++ b/EvoEngine_Plugins/EcoSysLab/src/DsPhysics.cpp @@ -8,7 +8,7 @@ DsPreStep::DsPreStep() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/PreStep/Segment.comp"); segment_pre_step_pipeline = std::make_shared(); segment_pre_step_pipeline->compute_shader = shader; @@ -26,7 +26,7 @@ DsPreStep::DsPreStep() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/PreStep/Leaf.comp"); leaf_pre_step_pipeline = std::make_shared(); leaf_pre_step_pipeline->compute_shader = shader; @@ -84,7 +84,7 @@ DsPrediction::DsPrediction() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Prediction/Segment.comp"); segment_prediction_pipeline = std::make_shared(); segment_prediction_pipeline->compute_shader = shader; @@ -101,7 +101,7 @@ DsPrediction::DsPrediction() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Prediction/SegmentPair.comp"); segment_pair_prediction_pipeline = std::make_shared(); segment_pair_prediction_pipeline->compute_shader = shader; @@ -118,7 +118,7 @@ DsPrediction::DsPrediction() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Prediction/Leaf.comp"); leaf_prediction_pipeline = std::make_shared(); leaf_prediction_pipeline->compute_shader = shader; @@ -196,7 +196,7 @@ DsStructuralDamage::DsStructuralDamage() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Breaking/SegmentPair.comp"); segment_pair_breaking_pipeline = std::make_shared(); segment_pair_breaking_pipeline->compute_shader = shader; @@ -213,7 +213,7 @@ DsStructuralDamage::DsStructuralDamage() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Breaking/Leaf.comp"); leaf_breaking_pipeline = std::make_shared(); leaf_breaking_pipeline->compute_shader = shader; @@ -275,7 +275,7 @@ DsVelocityUpdate::DsVelocityUpdate() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/VelocityUpdate/Segment.comp"); segment_pipeline = std::make_shared(); segment_pipeline->compute_shader = shader; @@ -292,7 +292,7 @@ DsVelocityUpdate::DsVelocityUpdate() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/VelocityUpdate/Leaf.comp"); leaf_pipeline = std::make_shared(); leaf_pipeline->compute_shader = shader; @@ -354,7 +354,7 @@ DsDynamicHashedGrid::DsDynamicHashedGrid() { if (!partition_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/DynamicHashedGrid/Partition.comp"); @@ -373,28 +373,28 @@ DsDynamicHashedGrid::DsDynamicHashedGrid() { if (!local_merge_sort_shader) { local_merge_sort_shader = std::make_shared(); local_merge_sort_shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/DynamicHashedGrid/Sort/LocalMergeSort.comp"); } if (!big_flip_shader) { big_flip_shader = std::make_shared(); - big_flip_shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + big_flip_shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/DynamicHashedGrid/Sort/BigFlip.comp"); } if (!local_disperse_shader) { local_disperse_shader = std::make_shared(); - local_disperse_shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + local_disperse_shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/DynamicHashedGrid/Sort/LocalDisperse.comp"); } if (!global_disperse_shader) { global_disperse_shader = std::make_shared(); - global_disperse_shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + global_disperse_shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/DynamicHashedGrid/Sort/GlobalDisperse.comp"); } @@ -403,7 +403,7 @@ DsDynamicHashedGrid::DsDynamicHashedGrid() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/DynamicHashedGrid/Offset.comp"); offset_pipeline = std::make_shared(); @@ -593,7 +593,7 @@ DsSegmentCollision::DsSegmentCollision() { if (!spherical_pipeline) { static std::shared_ptr shader{}; shader = std::make_shared(); - shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/SegmentCollision/Spherical.comp"); diff --git a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrands.cpp b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrands.cpp index 921b09a1..3dcb6244 100644 --- a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrands.cpp +++ b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrands.cpp @@ -178,7 +178,7 @@ void DynamicStrands::BuildRenderComputePipelines() { static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Prediction/UniformParticle.comp"); branches_uniform_particle_update_pipeline = std::make_shared(); @@ -195,7 +195,7 @@ void DynamicStrands::BuildRenderComputePipelines() { // Tetrahedrons branches_tetrahedron_filtering_pipeline = std::make_shared(); branches_tetrahedron_filtering_pipeline->compute_shader = - Shader::CreateTemporary(ShaderType::Compute, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Rendering/TetrahedronFiltering.comp"); branches_tetrahedron_filtering_pipeline->descriptor_set_layouts.emplace_back(strands_layout); @@ -211,7 +211,7 @@ void DynamicStrands::BuildRenderComputePipelines() { // Triangles branches_triangle_filtering_pipeline = std::make_shared(); branches_triangle_filtering_pipeline->compute_shader = - Shader::CreateTemporary(ShaderType::Compute, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Rendering/TriangleFiltering.comp"); branches_triangle_filtering_pipeline->descriptor_set_layouts.emplace_back(strands_layout); @@ -586,7 +586,7 @@ void DynamicStrands::CalculateGroups(const PhysicsParameters& physics_parameters std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Grouping/Reset.comp"); reset_pipeline = std::make_shared(); reset_pipeline->compute_shader = shader; @@ -618,7 +618,7 @@ void DynamicStrands::CalculateGroups(const PhysicsParameters& physics_parameters static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Grouping/Step.comp"); step_pipeline = std::make_shared(); step_pipeline->compute_shader = shader; @@ -635,7 +635,7 @@ void DynamicStrands::CalculateGroups(const PhysicsParameters& physics_parameters static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Grouping/DynamicStep.comp"); dynamic_step_pipeline = std::make_shared(); dynamic_step_pipeline->compute_shader = shader; @@ -652,7 +652,7 @@ void DynamicStrands::CalculateGroups(const PhysicsParameters& physics_parameters static std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Grouping/Apply.comp"); apply_pipeline = std::make_shared(); apply_pipeline->compute_shader = shader; diff --git a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsBranchesRendering.cpp b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsBranchesRendering.cpp index ffe98077..7a4b7f32 100644 --- a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsBranchesRendering.cpp +++ b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsBranchesRendering.cpp @@ -91,14 +91,14 @@ struct BranchesRenderPushConstant { void DynamicStrands::BuildBranchesRenderingPipelines() { branches_point_light_render_pipeline = std::make_shared(); branches_point_light_render_pipeline->task_shader = Shader::CreateTemporary( - ShaderType::Task, Platform::Constants::shader_global_defines, + ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/Branches.task"); branches_point_light_render_pipeline->mesh_shader = - Shader::CreateTemporary(ShaderType::Mesh, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/Branches/PointLightShadowMap.mesh"); branches_point_light_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/Empty.frag"); branches_point_light_render_pipeline->geometry_type = GeometryType::Mesh; branches_point_light_render_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); @@ -113,14 +113,14 @@ void DynamicStrands::BuildBranchesRenderingPipelines() { // Descriptor set layout branches_spot_light_render_pipeline = std::make_shared(); branches_spot_light_render_pipeline->task_shader = Shader::CreateTemporary( - ShaderType::Task, Platform::Constants::shader_global_defines, + ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/Branches.task"); branches_spot_light_render_pipeline->mesh_shader = - Shader::CreateTemporary(ShaderType::Mesh, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/Branches/SpotLightShadowMap.mesh"); branches_spot_light_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/Empty.frag"); branches_spot_light_render_pipeline->geometry_type = GeometryType::Mesh; branches_spot_light_render_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); @@ -135,14 +135,14 @@ void DynamicStrands::BuildBranchesRenderingPipelines() { // Descriptor set layout branches_directional_light_render_pipeline = std::make_shared(); branches_directional_light_render_pipeline->task_shader = Shader::CreateTemporary( - ShaderType::Task, Platform::Constants::shader_global_defines, + ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/Branches.task"); branches_directional_light_render_pipeline->mesh_shader = Shader::CreateTemporary( - ShaderType::Mesh, Platform::Constants::shader_global_defines, + ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/Branches/DirectionalLightShadowMap.mesh"); branches_directional_light_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/Empty.frag"); branches_directional_light_render_pipeline->geometry_type = GeometryType::Mesh; branches_directional_light_render_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); @@ -158,14 +158,14 @@ void DynamicStrands::BuildBranchesRenderingPipelines() { // Descriptor set layout branches_render_pipeline = std::make_shared(); branches_render_pipeline->task_shader = Shader::CreateTemporary( - ShaderType::Task, Platform::Constants::shader_global_defines, + ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/Branches.task"); branches_render_pipeline->mesh_shader = - Shader::CreateTemporary(ShaderType::Mesh, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/Branches/Rendering.mesh"); branches_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/DynamicStrands/Rendering/Branches.frag"); branches_render_pipeline->geometry_type = GeometryType::Mesh; diff --git a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsFoliageRendering.cpp b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsFoliageRendering.cpp index c3976f4c..0ae9c204 100644 --- a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsFoliageRendering.cpp +++ b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsFoliageRendering.cpp @@ -32,14 +32,14 @@ void DynamicStrands::BuildFoliageRenderingPipelines() { // Descriptor set layout foliage_point_light_render_pipeline = std::make_shared(); foliage_point_light_render_pipeline->task_shader = Shader::CreateTemporary( - ShaderType::Task, Platform::Constants::shader_global_defines, + ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/Foliage.task"); foliage_point_light_render_pipeline->mesh_shader = - Shader::CreateTemporary(ShaderType::Mesh, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/Foliage/PointLightShadowMap.mesh"); foliage_point_light_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/Empty.frag"); foliage_point_light_render_pipeline->geometry_type = GeometryType::Mesh; foliage_point_light_render_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); @@ -54,14 +54,14 @@ void DynamicStrands::BuildFoliageRenderingPipelines() { // Descriptor set layout foliage_spot_light_render_pipeline = std::make_shared(); foliage_spot_light_render_pipeline->task_shader = Shader::CreateTemporary( - ShaderType::Task, Platform::Constants::shader_global_defines, + ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/Foliage.task"); foliage_spot_light_render_pipeline->mesh_shader = - Shader::CreateTemporary(ShaderType::Mesh, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/Foliage/SpotLightShadowMap.mesh"); foliage_spot_light_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/Empty.frag"); foliage_spot_light_render_pipeline->geometry_type = GeometryType::Mesh; foliage_spot_light_render_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); @@ -76,14 +76,14 @@ void DynamicStrands::BuildFoliageRenderingPipelines() { // Descriptor set layout foliage_directional_light_render_pipeline = std::make_shared(); foliage_directional_light_render_pipeline->task_shader = Shader::CreateTemporary( - ShaderType::Task, Platform::Constants::shader_global_defines, + ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/Foliage.task"); foliage_directional_light_render_pipeline->mesh_shader = Shader::CreateTemporary( - ShaderType::Mesh, Platform::Constants::shader_global_defines, + ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/Foliage/DirectionalLightShadowMap.mesh"); foliage_directional_light_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/Empty.frag"); foliage_directional_light_render_pipeline->geometry_type = GeometryType::Mesh; foliage_directional_light_render_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); @@ -99,14 +99,14 @@ void DynamicStrands::BuildFoliageRenderingPipelines() { // Descriptor set layout foliage_render_pipeline = std::make_shared(); foliage_render_pipeline->task_shader = Shader::CreateTemporary( - ShaderType::Task, Platform::Constants::shader_global_defines, + ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/Foliage.task"); foliage_render_pipeline->mesh_shader = - Shader::CreateTemporary(ShaderType::Mesh, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/Foliage/Rendering.mesh"); foliage_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/DynamicStrands/Rendering/Foliage.frag"); foliage_render_pipeline->geometry_type = GeometryType::Mesh; diff --git a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsInitialize.cpp b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsInitialize.cpp index c1aaf393..fbd7b8d4 100644 --- a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsInitialize.cpp +++ b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsInitialize.cpp @@ -28,7 +28,7 @@ void DynamicStrands::InitializeMesh(const InitializeParameters& initialize_param std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Initialization/Interior.comp"); interior_initialization_pipeline = std::make_shared(); interior_initialization_pipeline->compute_shader = shader; @@ -45,7 +45,7 @@ void DynamicStrands::InitializeMesh(const InitializeParameters& initialize_param std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Initialization/BarkFlag.comp"); bark_flag_initialization_pipeline = std::make_shared(); bark_flag_initialization_pipeline->compute_shader = shader; @@ -63,7 +63,7 @@ void DynamicStrands::InitializeMesh(const InitializeParameters& initialize_param std::shared_ptr shader{}; shader = std::make_shared(); shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Compute/DynamicStrands/Initialization/Normal.comp"); uniform_particle_initialization_pipeline = std::make_shared(); uniform_particle_initialization_pipeline->compute_shader = shader; diff --git a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsSegmentPairsRendering.cpp b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsSegmentPairsRendering.cpp index f033ad89..768370d7 100644 --- a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsSegmentPairsRendering.cpp +++ b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsSegmentPairsRendering.cpp @@ -25,15 +25,15 @@ void DynamicStrands::BuildSegmentPairsRenderingPipeline() { // Descriptor set layout segment_pairs_visualization_render_pipeline = std::make_shared(); segment_pairs_visualization_render_pipeline->task_shader = - Shader::CreateTemporary(ShaderType::Task, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/SegmentPairs.task"); segment_pairs_visualization_render_pipeline->mesh_shader = - Shader::CreateTemporary(ShaderType::Mesh, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/SegmentPairs/Rendering.mesh"); segment_pairs_visualization_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/DynamicStrands/Rendering/SegmentPairs.frag"); segment_pairs_visualization_render_pipeline->geometry_type = GeometryType::Mesh; diff --git a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsSmallSegmentsRendering.cpp b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsSmallSegmentsRendering.cpp index fc7d31e4..9a5f6c7d 100644 --- a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsSmallSegmentsRendering.cpp +++ b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsSmallSegmentsRendering.cpp @@ -325,15 +325,15 @@ void DynamicStrands::BuildSmallSegmentsRenderingPipelines() { // Descriptor set layout small_segments_point_light_render_pipeline = std::make_shared(); small_segments_point_light_render_pipeline->task_shader = - Shader::CreateTemporary(ShaderType::Task, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/SmallSegments.task"); small_segments_point_light_render_pipeline->mesh_shader = Shader::CreateTemporary( - ShaderType::Mesh, Platform::Constants::shader_global_defines, + ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/SmallSegments/PointLightShadowMap.mesh"); small_segments_point_light_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/Empty.frag"); small_segments_point_light_render_pipeline->geometry_type = GeometryType::Mesh; small_segments_point_light_render_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); @@ -349,15 +349,15 @@ void DynamicStrands::BuildSmallSegmentsRenderingPipelines() { // Descriptor set layout small_segments_spot_light_render_pipeline = std::make_shared(); small_segments_spot_light_render_pipeline->task_shader = - Shader::CreateTemporary(ShaderType::Task, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/SmallSegments.task"); small_segments_spot_light_render_pipeline->mesh_shader = Shader::CreateTemporary( - ShaderType::Mesh, Platform::Constants::shader_global_defines, + ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/SmallSegments/SpotLightShadowMap.mesh"); small_segments_spot_light_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/Empty.frag"); small_segments_spot_light_render_pipeline->geometry_type = GeometryType::Mesh; small_segments_spot_light_render_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); @@ -372,15 +372,15 @@ void DynamicStrands::BuildSmallSegmentsRenderingPipelines() { // Descriptor set layout small_segments_directional_light_render_pipeline = std::make_shared(); small_segments_directional_light_render_pipeline->task_shader = - Shader::CreateTemporary(ShaderType::Task, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/SmallSegments.task"); small_segments_directional_light_render_pipeline->mesh_shader = Shader::CreateTemporary( - ShaderType::Mesh, Platform::Constants::shader_global_defines, + ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/SmallSegments/DirectionalLightShadowMap.mesh"); small_segments_directional_light_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/Empty.frag"); small_segments_directional_light_render_pipeline->geometry_type = GeometryType::Mesh; small_segments_directional_light_render_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); @@ -396,15 +396,15 @@ void DynamicStrands::BuildSmallSegmentsRenderingPipelines() { // Descriptor set layout small_segments_render_pipeline = std::make_shared(); small_segments_render_pipeline->task_shader = - Shader::CreateTemporary(ShaderType::Task, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/SmallSegments.task"); small_segments_render_pipeline->mesh_shader = - Shader::CreateTemporary(ShaderType::Mesh, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/SmallSegments/Rendering.mesh"); small_segments_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/DynamicStrands/Rendering/SmallSegments.frag"); small_segments_render_pipeline->geometry_type = GeometryType::Mesh; @@ -423,15 +423,15 @@ void DynamicStrands::BuildSmallSegmentsRenderingPipelines() { // Descriptor set layout small_segments_visualization_render_pipeline = std::make_shared(); small_segments_visualization_render_pipeline->task_shader = - Shader::CreateTemporary(ShaderType::Task, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Rendering/SmallSegmentsVisualization.task"); small_segments_visualization_render_pipeline->mesh_shader = Shader::CreateTemporary( - ShaderType::Mesh, Platform::Constants::shader_global_defines, + ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Rendering/SmallSegments/VisualizationRendering.mesh"); small_segments_visualization_render_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/DynamicStrands/Rendering/SmallSegmentsVisualization.frag"); small_segments_visualization_render_pipeline->geometry_type = GeometryType::Mesh; diff --git a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsVisualization.cpp b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsVisualization.cpp index 50bcc77f..df70b32a 100644 --- a/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsVisualization.cpp +++ b/EvoEngine_Plugins/EcoSysLab/src/DynamicStrandsVisualization.cpp @@ -143,16 +143,16 @@ void DynamicStrands::Visualize(const std::shared_ptr& target_camera, static std::shared_ptr frag_shader{}; // Load shader task_shader = std::make_shared(); - task_shader->TryCompile(ShaderType::Task, Platform::Constants::shader_global_defines, + task_shader->TryCompile(ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Visualization/Segments.task"); mesh_shader = std::make_shared(); - mesh_shader->TryCompile(ShaderType::Mesh, Platform::Constants::shader_global_defines, + mesh_shader->TryCompile(ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Visualization/Segments.mesh"); frag_shader = std::make_shared(); frag_shader->TryCompile( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/DynamicStrands/Visualization.frag"); // Descriptor set layout segment_render_pipeline = std::make_shared(); @@ -193,16 +193,16 @@ void DynamicStrands::Visualize(const std::shared_ptr& target_camera, static std::shared_ptr frag_shader{}; // Load shader task_shader = std::make_shared(); - task_shader->TryCompile(ShaderType::Task, Platform::Constants::shader_global_defines, + task_shader->TryCompile(ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Visualization/SegmentPairs.task"); mesh_shader = std::make_shared(); - mesh_shader->TryCompile(ShaderType::Mesh, Platform::Constants::shader_global_defines, + mesh_shader->TryCompile(ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Visualization/SegmentPairs.mesh"); frag_shader = std::make_shared(); frag_shader->TryCompile( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/DynamicStrands/Visualization.frag"); // Descriptor set layout segment_pair_render_pipeline = std::make_shared(); @@ -243,17 +243,17 @@ void DynamicStrands::Visualize(const std::shared_ptr& target_camera, static std::shared_ptr frag_shader{}; // Load shader task_shader = std::make_shared(); - task_shader->TryCompile(ShaderType::Task, Platform::Constants::shader_global_defines, + task_shader->TryCompile(ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Visualization/UniformParticles.task"); mesh_shader = std::make_shared(); - mesh_shader->TryCompile(ShaderType::Mesh, Platform::Constants::shader_global_defines, + mesh_shader->TryCompile(ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Visualization/UniformParticles.mesh"); frag_shader = std::make_shared(); frag_shader->TryCompile( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/DynamicStrands/Visualization.frag"); // Descriptor set layout uniform_particle_render_pipeline = std::make_shared(); @@ -293,16 +293,16 @@ void DynamicStrands::Visualize(const std::shared_ptr& target_camera, static std::shared_ptr frag_shader{}; // Load shader task_shader = std::make_shared(); - task_shader->TryCompile(ShaderType::Task, Platform::Constants::shader_global_defines, + task_shader->TryCompile(ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Task/DynamicStrands/Visualization/Foliage.task"); mesh_shader = std::make_shared(); - mesh_shader->TryCompile(ShaderType::Mesh, Platform::Constants::shader_global_defines, + mesh_shader->TryCompile(ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Mesh/DynamicStrands/Visualization/Foliage.mesh"); frag_shader = std::make_shared(); frag_shader->TryCompile( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./EcoSysLabResources") / "Shaders/Graphics/Fragment/DynamicStrands/Visualization.frag"); // Descriptor set layout foliage_render_pipeline = std::make_shared(); diff --git a/EvoEngine_SDK/include/Rendering/Platform/Platform.hpp b/EvoEngine_SDK/include/Rendering/Platform/Platform.hpp index 9c501e36..d46a3615 100644 --- a/EvoEngine_SDK/include/Rendering/Platform/Platform.hpp +++ b/EvoEngine_SDK/include/Rendering/Platform/Platform.hpp @@ -5,11 +5,8 @@ #include "ISingleton.hpp" #include "RayTracingPipeline.hpp" -#ifdef EVOENGINE_WINDOWS -# define ENABLE_EXTERNAL_MEMORY true -#else -# define ENABLE_EXTERNAL_MEMORY false -#endif +#define ENABLE_EXTERNAL_MEMORY true + #define ENABLE_NV_RAY_TRACING_VALIDATION false #ifndef USE_RENDERDOC @@ -175,6 +172,10 @@ class Platform final { std::shared_ptr immediate_submit_command_buffer; std::unordered_map> buffer_sync_actions; std::vector> temporary_buffer_sync_actions; + /** + * \brief Defined during Platform::Initialize(); + */ + std::string shader_global_defines = {}; public: static bool Initialized(); @@ -240,10 +241,6 @@ class Platform final { inline static uint32_t max_compute_work_group_invocations = 1; inline static uint32_t max_shared_memory_size = 1; - /** - * \brief Defined during Platform::Initialize(); - */ - inline static std::string shader_global_defines{}; }; static uint32_t DivUp(uint32_t a, uint32_t b); static void EverythingBarrier(VkCommandBuffer vk_command_buffer); @@ -251,7 +248,7 @@ class Platform final { static void TransitImageLayout(VkCommandBuffer vk_command_buffer, VkImage target_image, VkFormat image_format, uint32_t layer_count, VkImageLayout old_layout, VkImageLayout new_layout, uint32_t mip_levels = 1); - + static const std::string& GetShaderGlobalDefines(); static std::string StringifyResultVk(const VkResult& result); static void CheckVk(const VkResult& result); diff --git a/EvoEngine_SDK/src/CpuRayTracer.cpp b/EvoEngine_SDK/src/CpuRayTracer.cpp index 950b113c..45f3b898 100644 --- a/EvoEngine_SDK/src/CpuRayTracer.cpp +++ b/EvoEngine_SDK/src/CpuRayTracer.cpp @@ -944,7 +944,7 @@ void CpuRayTracer::AggregatedScene::TraceGpu(const std::vector& r if (!trace_shader) { trace_shader = AssetManager::CreateTemporaryAsset(); - trace_shader->TryCompile(ShaderType::Compute, Platform::Constants::shader_global_defines, + trace_shader->TryCompile(ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Compute/Trace.comp"); } diff --git a/EvoEngine_SDK/src/GpuRayTracerCamera.cpp b/EvoEngine_SDK/src/GpuRayTracerCamera.cpp index cdab9f09..88116c0b 100644 --- a/EvoEngine_SDK/src/GpuRayTracerCamera.cpp +++ b/EvoEngine_SDK/src/GpuRayTracerCamera.cpp @@ -183,7 +183,7 @@ void GpuRayTracerCamera::Capture() { * std::filesystem::path("./EcoSysLabResources/Shaders/Compute/AlphaShape.comp")); */ ray_tracer_camera_shader->TryCompile( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Compute/RayTracerCamera.comp"); } /** diff --git a/EvoEngine_SDK/src/Platform.cpp b/EvoEngine_SDK/src/Platform.cpp index a8870e97..78b6578c 100644 --- a/EvoEngine_SDK/src/Platform.cpp +++ b/EvoEngine_SDK/src/Platform.cpp @@ -193,7 +193,7 @@ void Platform::Initialize() { Constants::task_subgroup_count = glm::max(task_subgroup_count, 1u); Constants::mesh_subgroup_count = glm::max(mesh_subgroup_count, 1u); Constants::compute_subgroup_count = glm::max(compute_subgroup_count, 1u); - Constants::shader_global_defines = + graphics.shader_global_defines = "\n#define MAX_DIRECTIONAL_LIGHT_SIZE " + std::to_string(Settings::max_directional_light_size) + "\n#define MAX_KERNEL_AMOUNT " + std::to_string(Constants::max_kernel_amount) + "\n#define MESHLET_MAX_VERTICES_SIZE " + std::to_string(Constants::meshlet_max_vertices_size) + @@ -460,6 +460,10 @@ void Platform::TransitImageLayout(VkCommandBuffer vk_command_buffer, const VkIma vkCmdPipelineBarrier(vk_command_buffer, source_stage, destination_stage, 0, 0, nullptr, 0, nullptr, 1, &barrier); } +const std::string& Platform::GetShaderGlobalDefines() { + const auto& graphics = GetInstance(); + return graphics.shader_global_defines; +} size_t Platform::GetMaxBoneAmount() { const auto& graphics = GetInstance(); diff --git a/EvoEngine_SDK/src/PostProcessingStack.cpp b/EvoEngine_SDK/src/PostProcessingStack.cpp index 2a4cc6c8..632d169a 100644 --- a/EvoEngine_SDK/src/PostProcessingStack.cpp +++ b/EvoEngine_SDK/src/PostProcessingStack.cpp @@ -322,7 +322,7 @@ void Bloom::BuildPipelines() { Shader::CreateTemporary(ShaderType::Vertex, std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/TexturePassThrough.vert"); downsampling_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/PostProcessing/BloomDownsampling.frag"); downsampling_pipeline->geometry_type = GeometryType::Mesh; @@ -342,7 +342,7 @@ void Bloom::BuildPipelines() { Shader::CreateTemporary(ShaderType::Vertex, std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/TexturePassThrough.vert"); upsampling_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/PostProcessing/BloomUpsampling.frag"); upsampling_pipeline->geometry_type = GeometryType::Mesh; @@ -362,7 +362,7 @@ void Bloom::BuildPipelines() { Shader::CreateTemporary(ShaderType::Vertex, std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/TexturePassThrough.vert"); copy_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/PostProcessing/BloomCopy.frag"); copy_pipeline->geometry_type = GeometryType::Mesh; copy_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); @@ -377,7 +377,7 @@ void Bloom::BuildPipelines() { Shader::CreateTemporary(ShaderType::Vertex, std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/TexturePassThrough.vert"); mix_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/PostProcessing/BloomMix.frag"); mix_pipeline->geometry_type = GeometryType::Mesh; mix_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); diff --git a/EvoEngine_SDK/src/RenderLayer.cpp b/EvoEngine_SDK/src/RenderLayer.cpp index af885429..342c5a0f 100644 --- a/EvoEngine_SDK/src/RenderLayer.cpp +++ b/EvoEngine_SDK/src/RenderLayer.cpp @@ -54,10 +54,10 @@ void RenderLayer::OnCreate() { if (!point_light_shadow_pipeline_normal) { point_light_shadow_pipeline_normal = std::make_shared(); point_light_shadow_pipeline_normal->vertex_shader = Shader::CreateTemporary( - ShaderType::Vertex, Platform::Constants::shader_global_defines, + ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Lighting/PointLightShadowMap.vert"); point_light_shadow_pipeline_normal->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/ShadowMapPassThrough.frag"); point_light_shadow_pipeline_normal->geometry_type = GeometryType::Mesh; point_light_shadow_pipeline_normal->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -72,13 +72,13 @@ void RenderLayer::OnCreate() { if (Platform::Constants::support_mesh_shader && !point_light_shadow_pipeline_mesh_shader) { point_light_shadow_pipeline_mesh_shader = std::make_shared(); point_light_shadow_pipeline_mesh_shader->task_shader = Shader::CreateTemporary( - ShaderType::Task, Platform::Constants::shader_global_defines, + ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Task/Lighting/PointLightShadowMap.task"); point_light_shadow_pipeline_mesh_shader->mesh_shader = Shader::CreateTemporary( - ShaderType::Mesh, Platform::Constants::shader_global_defines, + ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Mesh/Lighting/PointLightShadowMap.mesh"); point_light_shadow_pipeline_mesh_shader->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Empty.frag"); point_light_shadow_pipeline_mesh_shader->geometry_type = GeometryType::Mesh; point_light_shadow_pipeline_mesh_shader->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -94,10 +94,10 @@ void RenderLayer::OnCreate() { if (!spot_light_shadow_pipeline_normal) { spot_light_shadow_pipeline_normal = std::make_shared(); spot_light_shadow_pipeline_normal->vertex_shader = Shader::CreateTemporary( - ShaderType::Vertex, Platform::Constants::shader_global_defines, + ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Lighting/SpotLightShadowMap.vert"); spot_light_shadow_pipeline_normal->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/ShadowMapPassThrough.frag"); spot_light_shadow_pipeline_normal->geometry_type = GeometryType::Mesh; spot_light_shadow_pipeline_normal->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -112,13 +112,13 @@ void RenderLayer::OnCreate() { if (Platform::Constants::support_mesh_shader && !spot_light_shadow_pipeline_mesh_shader) { spot_light_shadow_pipeline_mesh_shader = std::make_shared(); spot_light_shadow_pipeline_mesh_shader->task_shader = Shader::CreateTemporary( - ShaderType::Task, Platform::Constants::shader_global_defines, + ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Task/Lighting/SpotLightShadowMap.task"); spot_light_shadow_pipeline_mesh_shader->mesh_shader = Shader::CreateTemporary( - ShaderType::Mesh, Platform::Constants::shader_global_defines, + ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Mesh/Lighting/SpotLightShadowMap.mesh"); spot_light_shadow_pipeline_mesh_shader->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Empty.frag"); spot_light_shadow_pipeline_mesh_shader->geometry_type = GeometryType::Mesh; spot_light_shadow_pipeline_mesh_shader->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -134,11 +134,11 @@ void RenderLayer::OnCreate() { if (!directional_light_shadow_pipeline_normal) { directional_light_shadow_pipeline_normal = std::make_shared(); directional_light_shadow_pipeline_normal->vertex_shader = - Shader::CreateTemporary(ShaderType::Vertex, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Lighting/DirectionalLightShadowMap.vert"); directional_light_shadow_pipeline_normal->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/ShadowMapPassThrough.frag"); directional_light_shadow_pipeline_normal->geometry_type = GeometryType::Mesh; directional_light_shadow_pipeline_normal->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -153,13 +153,13 @@ void RenderLayer::OnCreate() { if (Platform::Constants::support_mesh_shader && !directional_light_shadow_pipeline_mesh_shader) { directional_light_shadow_pipeline_mesh_shader = std::make_shared(); directional_light_shadow_pipeline_mesh_shader->task_shader = Shader::CreateTemporary( - ShaderType::Task, Platform::Constants::shader_global_defines, + ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Task/Lighting/DirectionalLightShadowMap.task"); directional_light_shadow_pipeline_mesh_shader->mesh_shader = Shader::CreateTemporary( - ShaderType::Mesh, Platform::Constants::shader_global_defines, + ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Mesh/Lighting/DirectionalLightShadowMap.mesh"); directional_light_shadow_pipeline_mesh_shader->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Empty.frag"); directional_light_shadow_pipeline_mesh_shader->geometry_type = GeometryType::Mesh; directional_light_shadow_pipeline_mesh_shader->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -175,11 +175,11 @@ void RenderLayer::OnCreate() { if (!instanced_point_light_shadow_pipeline) { instanced_point_light_shadow_pipeline = std::make_shared(); instanced_point_light_shadow_pipeline->vertex_shader = - Shader::CreateTemporary(ShaderType::Vertex, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Lighting/PointLightShadowMapInstanced.vert"); instanced_point_light_shadow_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/ShadowMapPassThrough.frag"); instanced_point_light_shadow_pipeline->geometry_type = GeometryType::Mesh; instanced_point_light_shadow_pipeline->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -195,11 +195,11 @@ void RenderLayer::OnCreate() { if (!instanced_spot_light_shadow_pipeline) { instanced_spot_light_shadow_pipeline = std::make_shared(); instanced_spot_light_shadow_pipeline->vertex_shader = - Shader::CreateTemporary(ShaderType::Vertex, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Lighting/SpotLightShadowMapInstanced.vert"); instanced_spot_light_shadow_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/ShadowMapPassThrough.frag"); instanced_spot_light_shadow_pipeline->geometry_type = GeometryType::Mesh; instanced_spot_light_shadow_pipeline->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -215,11 +215,11 @@ void RenderLayer::OnCreate() { if (!instanced_directional_light_shadow_pipeline) { instanced_directional_light_shadow_pipeline = std::make_shared(); instanced_directional_light_shadow_pipeline->vertex_shader = - Shader::CreateTemporary(ShaderType::Vertex, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Lighting/DirectionalLightShadowMapInstanced.vert"); instanced_directional_light_shadow_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/ShadowMapPassThrough.frag"); instanced_directional_light_shadow_pipeline->geometry_type = GeometryType::Mesh; instanced_directional_light_shadow_pipeline->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -236,11 +236,11 @@ void RenderLayer::OnCreate() { if (!skinned_point_light_shadow_pipeline) { skinned_point_light_shadow_pipeline = std::make_shared(); skinned_point_light_shadow_pipeline->vertex_shader = - Shader::CreateTemporary(ShaderType::Vertex, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Lighting/PointLightShadowMapSkinned.vert"); skinned_point_light_shadow_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/ShadowMapPassThrough.frag"); skinned_point_light_shadow_pipeline->geometry_type = GeometryType::SkinnedMesh; skinned_point_light_shadow_pipeline->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -256,11 +256,11 @@ void RenderLayer::OnCreate() { if (!skinned_spot_light_shadow_pipeline) { skinned_spot_light_shadow_pipeline = std::make_shared(); skinned_spot_light_shadow_pipeline->vertex_shader = - Shader::CreateTemporary(ShaderType::Vertex, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Lighting/SpotLightShadowMapSkinned.vert"); skinned_spot_light_shadow_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/ShadowMapPassThrough.frag"); skinned_spot_light_shadow_pipeline->geometry_type = GeometryType::SkinnedMesh; skinned_spot_light_shadow_pipeline->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -276,11 +276,11 @@ void RenderLayer::OnCreate() { if (!skinned_directional_light_shadow_pipeline) { skinned_directional_light_shadow_pipeline = std::make_shared(); skinned_directional_light_shadow_pipeline->vertex_shader = - Shader::CreateTemporary(ShaderType::Vertex, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Lighting/DirectionalLightShadowMapSkinned.vert"); skinned_directional_light_shadow_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/ShadowMapPassThrough.frag"); skinned_directional_light_shadow_pipeline->geometry_type = GeometryType::SkinnedMesh; skinned_directional_light_shadow_pipeline->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -297,23 +297,23 @@ void RenderLayer::OnCreate() { if (!strands_point_light_shadow_pipeline) { strands_point_light_shadow_pipeline = std::make_shared(); strands_point_light_shadow_pipeline->vertex_shader = - Shader::CreateTemporary(ShaderType::Vertex, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Lighting/PointLightShadowMapStrands.vert"); strands_point_light_shadow_pipeline->tessellation_control_shader = - Shader::CreateTemporary(ShaderType::TessellationControl, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::TessellationControl, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationControl/Lighting/ShadowMapStrands.tesc"); strands_point_light_shadow_pipeline->tessellation_evaluation_shader = - Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationEvaluation/Lighting/ShadowMapStrands.tese"); strands_point_light_shadow_pipeline->geometry_shader = - Shader::CreateTemporary(ShaderType::Geometry, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Geometry, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Geometry/Lighting/PointLightShadowMapStrands.geom"); strands_point_light_shadow_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Empty.frag"); strands_point_light_shadow_pipeline->geometry_type = GeometryType::Strands; strands_point_light_shadow_pipeline->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -330,23 +330,23 @@ void RenderLayer::OnCreate() { if (!strands_spot_light_shadow_pipeline) { strands_spot_light_shadow_pipeline = std::make_shared(); strands_spot_light_shadow_pipeline->vertex_shader = - Shader::CreateTemporary(ShaderType::Vertex, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Lighting/SpotLightShadowMapStrands.vert"); strands_spot_light_shadow_pipeline->tessellation_control_shader = - Shader::CreateTemporary(ShaderType::TessellationControl, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::TessellationControl, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationControl/Lighting/ShadowMapStrands.tesc"); strands_spot_light_shadow_pipeline->tessellation_evaluation_shader = - Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationEvaluation/Lighting/ShadowMapStrands.tese"); strands_spot_light_shadow_pipeline->geometry_shader = - Shader::CreateTemporary(ShaderType::Geometry, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Geometry, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Geometry/Lighting/SpotLightShadowMapStrands.geom"); strands_spot_light_shadow_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Empty.frag"); strands_spot_light_shadow_pipeline->geometry_type = GeometryType::Strands; strands_spot_light_shadow_pipeline->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -363,23 +363,23 @@ void RenderLayer::OnCreate() { if (!strands_directional_light_shadow_pipeline) { strands_directional_light_shadow_pipeline = std::make_shared(); strands_directional_light_shadow_pipeline->vertex_shader = - Shader::CreateTemporary(ShaderType::Vertex, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Lighting/DirectionalLightShadowMapStrands.vert"); strands_directional_light_shadow_pipeline->tessellation_control_shader = - Shader::CreateTemporary(ShaderType::TessellationControl, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::TessellationControl, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationControl/Lighting/ShadowMapStrands.tesc"); strands_directional_light_shadow_pipeline->tessellation_evaluation_shader = - Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationEvaluation/Lighting/ShadowMapStrands.tese"); strands_directional_light_shadow_pipeline->geometry_shader = - Shader::CreateTemporary(ShaderType::Geometry, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Geometry, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Geometry/Lighting/DirectionalLightShadowMapStrands.geom"); strands_directional_light_shadow_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Empty.frag"); strands_directional_light_shadow_pipeline->geometry_type = GeometryType::Strands; strands_directional_light_shadow_pipeline->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -398,10 +398,10 @@ void RenderLayer::OnCreate() { if (!deferred_prepass_pipeline_normal) { deferred_prepass_pipeline_normal = std::make_shared(); deferred_prepass_pipeline_normal->vertex_shader = Shader::CreateTemporary( - ShaderType::Vertex, Platform::Constants::shader_global_defines, + ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Standard/Standard.vert"); deferred_prepass_pipeline_normal->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Standard/StandardDeferred.frag"); deferred_prepass_pipeline_normal->geometry_type = GeometryType::Mesh; deferred_prepass_pipeline_normal->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -417,13 +417,13 @@ void RenderLayer::OnCreate() { if (Platform::Constants::support_mesh_shader && !deferred_prepass_pipeline_mesh) { deferred_prepass_pipeline_mesh = std::make_shared(); deferred_prepass_pipeline_mesh->task_shader = Shader::CreateTemporary( - ShaderType::Task, Platform::Constants::shader_global_defines, + ShaderType::Task, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Task/Standard/Standard.task"); deferred_prepass_pipeline_mesh->mesh_shader = Shader::CreateTemporary( - ShaderType::Mesh, Platform::Constants::shader_global_defines, + ShaderType::Mesh, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Mesh/Standard/Standard.mesh"); deferred_prepass_pipeline_mesh->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Standard/StandardDeferred.frag"); deferred_prepass_pipeline_mesh->geometry_type = GeometryType::Mesh; deferred_prepass_pipeline_mesh->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -440,10 +440,10 @@ void RenderLayer::OnCreate() { if (!instanced_deferred_prepass_pipeline) { instanced_deferred_prepass_pipeline = std::make_shared(); instanced_deferred_prepass_pipeline->vertex_shader = Shader::CreateTemporary( - ShaderType::Vertex, Platform::Constants::shader_global_defines, + ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Standard/StandardInstanced.vert"); instanced_deferred_prepass_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Standard/StandardDeferred.frag"); instanced_deferred_prepass_pipeline->geometry_type = GeometryType::Mesh; instanced_deferred_prepass_pipeline->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -460,10 +460,10 @@ void RenderLayer::OnCreate() { if (!skinned_deferred_prepass_pipeline) { skinned_deferred_prepass_pipeline = std::make_shared(); skinned_deferred_prepass_pipeline->vertex_shader = Shader::CreateTemporary( - ShaderType::Vertex, Platform::Constants::shader_global_defines, + ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Standard/StandardSkinned.vert"); skinned_deferred_prepass_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Standard/StandardDeferred.frag"); skinned_deferred_prepass_pipeline->geometry_type = GeometryType::SkinnedMesh; skinned_deferred_prepass_pipeline->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -481,21 +481,21 @@ void RenderLayer::OnCreate() { if (!strands_deferred_prepass_pipeline) { strands_deferred_prepass_pipeline = std::make_shared(); strands_deferred_prepass_pipeline->vertex_shader = Shader::CreateTemporary( - ShaderType::Vertex, Platform::Constants::shader_global_defines, + ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Standard/StandardStrands.vert"); strands_deferred_prepass_pipeline->tessellation_control_shader = - Shader::CreateTemporary(ShaderType::TessellationControl, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::TessellationControl, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationControl/Standard/StandardStrands.tesc"); strands_deferred_prepass_pipeline->tessellation_evaluation_shader = - Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationEvaluation/Standard/StandardStrands.tese"); strands_deferred_prepass_pipeline->geometry_shader = Shader::CreateTemporary( - ShaderType::Geometry, Platform::Constants::shader_global_defines, + ShaderType::Geometry, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Geometry/Standard/StandardStrands.geom"); strands_deferred_prepass_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Standard/StandardDeferred.frag"); strands_deferred_prepass_pipeline->geometry_type = GeometryType::Strands; strands_deferred_prepass_pipeline->descriptor_set_layouts.emplace_back(per_frame_layout); @@ -517,7 +517,7 @@ void RenderLayer::OnCreate() { Shader::CreateTemporary(ShaderType::Vertex, std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/TexturePassThrough.vert"); deferred_lighting_pass_pipeline->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Standard/StandardDeferredLighting.frag"); deferred_lighting_pass_pipeline->geometry_type = GeometryType::Mesh; @@ -539,7 +539,7 @@ void RenderLayer::OnCreate() { Shader::CreateTemporary(ShaderType::Vertex, std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/TexturePassThrough.vert"); deferred_lighting_pass_pipeline_scene_camera->fragment_shader = - Shader::CreateTemporary(ShaderType::Fragment, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Standard/StandardDeferredLightingSceneCamera.frag"); deferred_lighting_pass_pipeline_scene_camera->geometry_type = GeometryType::Mesh; @@ -559,10 +559,10 @@ void RenderLayer::OnCreate() { if (!gizmos) { gizmos = std::make_shared(); gizmos->vertex_shader = Shader::CreateTemporary( - ShaderType::Vertex, Platform::Constants::shader_global_defines, + ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Gizmos/Gizmos.vert"); gizmos->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Gizmos/Gizmos.frag"); gizmos->geometry_type = GeometryType::Mesh; gizmos->depth_attachment_format = Platform::Constants::render_texture_depth; @@ -579,10 +579,10 @@ void RenderLayer::OnCreate() { if (!gizmos_normal_colored) { gizmos_normal_colored = std::make_shared(); gizmos_normal_colored->vertex_shader = Shader::CreateTemporary( - ShaderType::Vertex, Platform::Constants::shader_global_defines, + ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Gizmos/GizmosNormalColored.vert"); gizmos_normal_colored->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Gizmos/GizmosColored.frag"); gizmos_normal_colored->geometry_type = GeometryType::Mesh; gizmos_normal_colored->depth_attachment_format = Platform::Constants::render_texture_depth; @@ -599,10 +599,10 @@ void RenderLayer::OnCreate() { if (!gizmos_vertex_colored) { gizmos_vertex_colored = std::make_shared(); gizmos_vertex_colored->vertex_shader = Shader::CreateTemporary( - ShaderType::Vertex, Platform::Constants::shader_global_defines, + ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Gizmos/GizmosVertexColored.vert"); gizmos_vertex_colored->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Gizmos/GizmosColored.frag"); gizmos_vertex_colored->geometry_type = GeometryType::Mesh; gizmos_vertex_colored->depth_attachment_format = Platform::Constants::render_texture_depth; @@ -618,10 +618,10 @@ void RenderLayer::OnCreate() { if (!gizmos_instanced_colored) { gizmos_instanced_colored = std::make_shared(); gizmos_instanced_colored->vertex_shader = Shader::CreateTemporary( - ShaderType::Vertex, Platform::Constants::shader_global_defines, + ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Gizmos/GizmosInstancedColored.vert"); gizmos_instanced_colored->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Gizmos/GizmosColored.frag"); gizmos_instanced_colored->geometry_type = GeometryType::Mesh; gizmos_instanced_colored->depth_attachment_format = Platform::Constants::render_texture_depth; @@ -640,20 +640,20 @@ void RenderLayer::OnCreate() { if (!gizmos_strands) { gizmos_strands = std::make_shared(); gizmos_strands->vertex_shader = Shader::CreateTemporary( - ShaderType::Vertex, Platform::Constants::shader_global_defines, + ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Gizmos/GizmosStrands.vert"); gizmos_strands->tessellation_control_shader = Shader::CreateTemporary( - ShaderType::TessellationControl, Platform::Constants::shader_global_defines, + ShaderType::TessellationControl, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationControl/Gizmos/GizmosStrands.tesc"); gizmos_strands->tessellation_evaluation_shader = - Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationEvaluation/Gizmos/GizmosStrands.tese"); gizmos_strands->geometry_shader = Shader::CreateTemporary( - ShaderType::Geometry, Platform::Constants::shader_global_defines, + ShaderType::Geometry, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Geometry/Gizmos/GizmosStrands.geom"); gizmos_strands->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Gizmos/Gizmos.frag"); gizmos_strands->geometry_type = GeometryType::Strands; gizmos_strands->depth_attachment_format = Platform::Constants::render_texture_depth; @@ -671,21 +671,21 @@ void RenderLayer::OnCreate() { if (!gizmos_strands_normal_colored) { gizmos_strands_normal_colored = std::make_shared(); gizmos_strands_normal_colored->vertex_shader = Shader::CreateTemporary( - ShaderType::Vertex, Platform::Constants::shader_global_defines, + ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Gizmos/GizmosStrandsNormalColored.vert"); gizmos_strands_normal_colored->tessellation_control_shader = - Shader::CreateTemporary(ShaderType::TessellationControl, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::TessellationControl, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationControl/Gizmos/GizmosStrandsColored.tesc"); gizmos_strands_normal_colored->tessellation_evaluation_shader = - Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationEvaluation/Gizmos/GizmosStrandsColored.tese"); gizmos_strands_normal_colored->geometry_shader = Shader::CreateTemporary( - ShaderType::Geometry, Platform::Constants::shader_global_defines, + ShaderType::Geometry, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Geometry/Gizmos/GizmosStrandsColored.geom"); gizmos_strands_normal_colored->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Gizmos/GizmosColored.frag"); gizmos_strands_normal_colored->geometry_type = GeometryType::Strands; gizmos_strands_normal_colored->depth_attachment_format = Platform::Constants::render_texture_depth; @@ -703,21 +703,21 @@ void RenderLayer::OnCreate() { if (!gizmos_strands_vertex_colored) { gizmos_strands_vertex_colored = std::make_shared(); gizmos_strands_vertex_colored->vertex_shader = Shader::CreateTemporary( - ShaderType::Vertex, Platform::Constants::shader_global_defines, + ShaderType::Vertex, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/Gizmos/GizmosStrandsVertexColored.vert"); gizmos_strands_vertex_colored->tessellation_control_shader = - Shader::CreateTemporary(ShaderType::TessellationControl, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::TessellationControl, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationControl/Gizmos/GizmosStrandsColored.tesc"); gizmos_strands_vertex_colored->tessellation_evaluation_shader = - Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::TessellationEvaluation, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/TessellationEvaluation/Gizmos/GizmosStrandsColored.tese"); gizmos_strands_vertex_colored->geometry_shader = Shader::CreateTemporary( - ShaderType::Geometry, Platform::Constants::shader_global_defines, + ShaderType::Geometry, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Geometry/Gizmos/GizmosStrandsColored.geom"); gizmos_strands_vertex_colored->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/Gizmos/GizmosColored.frag"); gizmos_strands_vertex_colored->geometry_type = GeometryType::Strands; gizmos_strands_vertex_colored->tessellation_patch_control_points = 4; @@ -740,13 +740,13 @@ void RenderLayer::OnCreate() { if (Platform::Constants::support_ray_tracing && !ray_tracing_camera_pipeline) { ray_tracing_camera_pipeline = std::make_shared(); ray_tracing_camera_pipeline->raygen_shader = - Shader::CreateTemporary(ShaderType::RayGen, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::RayGen, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/RayTracing/RayGen/Camera.rgen"); ray_tracing_camera_pipeline->miss_shader = - Shader::CreateTemporary(ShaderType::Miss, Platform::Constants::shader_global_defines, + Shader::CreateTemporary(ShaderType::Miss, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/RayTracing/Miss/Camera.rmiss"); ray_tracing_camera_pipeline->closest_hit_shader = Shader::CreateTemporary( - ShaderType::Miss, Platform::Constants::shader_global_defines, + ShaderType::Miss, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/RayTracing/ClosestHit/Camera.rchit"); ray_tracing_camera_pipeline->descriptor_set_layouts.emplace_back(per_frame_layout); ray_tracing_camera_pipeline->descriptor_set_layouts.emplace_back(ray_tracing_layout); diff --git a/EvoEngine_SDK/src/ScreenSpaceAmbientOcclusion.cpp b/EvoEngine_SDK/src/ScreenSpaceAmbientOcclusion.cpp index 015bdaaf..374a2638 100644 --- a/EvoEngine_SDK/src/ScreenSpaceAmbientOcclusion.cpp +++ b/EvoEngine_SDK/src/ScreenSpaceAmbientOcclusion.cpp @@ -304,7 +304,7 @@ void ScreenSpaceAmbientOcclusion::BuildPipelines() { Shader::CreateTemporary(ShaderType::Vertex, std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/TexturePassThrough.vert"); geometry_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/PostProcessing/SSAOGeometry.frag"); geometry_pipeline->geometry_type = GeometryType::Mesh; geometry_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); @@ -324,7 +324,7 @@ void ScreenSpaceAmbientOcclusion::BuildPipelines() { Shader::CreateTemporary(ShaderType::Vertex, std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/TexturePassThrough.vert"); combine_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/PostProcessing/SSAOCombine.frag"); combine_pipeline->geometry_type = GeometryType::Mesh; combine_pipeline->descriptor_set_layouts.emplace_back(combine_layout); diff --git a/EvoEngine_SDK/src/ScreenSpaceReflection.cpp b/EvoEngine_SDK/src/ScreenSpaceReflection.cpp index c39e1622..37196f32 100644 --- a/EvoEngine_SDK/src/ScreenSpaceReflection.cpp +++ b/EvoEngine_SDK/src/ScreenSpaceReflection.cpp @@ -207,7 +207,7 @@ void ScreenSpaceReflection::BuildPipelines() { Shader::CreateTemporary(ShaderType::Vertex, std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/TexturePassThrough.vert"); reflect_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/PostProcessing/SSRReflect.frag"); reflect_pipeline->geometry_type = GeometryType::Mesh; reflect_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); @@ -227,7 +227,7 @@ void ScreenSpaceReflection::BuildPipelines() { Shader::CreateTemporary(ShaderType::Vertex, std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Vertex/TexturePassThrough.vert"); combine_pipeline->fragment_shader = Shader::CreateTemporary( - ShaderType::Fragment, Platform::Constants::shader_global_defines, + ShaderType::Fragment, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Graphics/Fragment/PostProcessing/SSRCombine.frag"); combine_pipeline->geometry_type = GeometryType::Mesh; combine_pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); diff --git a/EvoEngine_SDK/src/ToneMapping.cpp b/EvoEngine_SDK/src/ToneMapping.cpp index fc3d17d8..2a5c5ff1 100644 --- a/EvoEngine_SDK/src/ToneMapping.cpp +++ b/EvoEngine_SDK/src/ToneMapping.cpp @@ -47,7 +47,7 @@ void ToneMapping::Process(const PostProcessingStack& post_processing_stack, void ToneMapping::BuildPipelines() { pipeline = std::make_shared(); pipeline->compute_shader = Shader::CreateTemporary( - ShaderType::Compute, Platform::Constants::shader_global_defines, + ShaderType::Compute, Platform::GetShaderGlobalDefines(), std::filesystem::path("./DefaultResources") / "Shaders/Compute/PostProcessing/ToneMapping.comp"); pipeline->descriptor_set_layouts.emplace_back(RenderLayer::per_frame_layout); diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/CompilerInfo.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/CompilerInfo.cmake new file mode 100644 index 00000000..c2d775e7 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/CompilerInfo.cmake @@ -0,0 +1,82 @@ + +# +# Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA Corporation and its licensors retain all intellectual property and proprietary +# rights in and to this software, related documentation and any modifications thereto. +# Any use, reproduction, disclosure or distribution of this software and related +# documentation without an express license agreement from NVIDIA Corporation is strictly +# prohibited. +# +# TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* +# AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, +# INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY +# SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT +# LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF +# BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR +# INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGES +# + +# Sets some variables depending on which compiler you are using +# +# USING_GNU_C : gcc is being used for C compiler +# USING_GNU_CXX : g++ is being used for C++ compiler +# USING_CLANG_C : gcc is being used for C compiler +# USING_CLANG_CXX : g++ is being used for C++ compiler +# USING_ICC : icc is being used for C compiler +# USING_ICPC : icpc is being used for C++ compiler +# USING_WINDOWS_CL : Visual Studio's compiler +# USING_WINDOWS_ICL : Intel's Windows compiler + +set(USING_KNOWN_C_COMPILER TRUE) +if(CMAKE_COMPILER_IS_GNUCC) + set(USING_GNU_C TRUE) +elseif( CMAKE_C_COMPILER_ID STREQUAL "Intel" ) + set(USING_ICC TRUE) +elseif( CMAKE_C_COMPILER_ID STREQUAL "Clang" ) + set(USING_CLANG_C TRUE) +elseif( MSVC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC" ) + set(USING_WINDOWS_CL TRUE) +else() + set(USING_KNOWN_C_COMPILER FALSE) +endif() + + +set(USING_KNOWN_CXX_COMPILER TRUE) +if(CMAKE_COMPILER_IS_GNUCXX) + set(USING_GNU_CXX TRUE) +elseif( CMAKE_CXX_COMPILER_ID STREQUAL "Intel" ) + set(USING_ICPC TRUE) +elseif( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" ) + set(USING_CLANG_CXX TRUE) +elseif( MSVC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC" ) + if( NOT USING_WINDOWS_CL ) + message( WARNING "Mixing WinCL C++ compiler with non-matching C compiler" ) + endif() +else() + set(USING_KNOWN_CXX_COMPILER FALSE) +endif() + +if(USING_GNU_C) + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion + OUTPUT_VARIABLE GCC_VERSION) +endif() + +# Using unknown compilers +if(NOT USING_KNOWN_C_COMPILER) + FIRST_TIME_MESSAGE("Specified C compiler ${CMAKE_C_COMPILER} is not recognized (gcc, icc). Using CMake defaults.") +endif() + +if(NOT USING_KNOWN_CXX_COMPILER) + FIRST_TIME_MESSAGE("Specified CXX compiler ${CMAKE_CXX_COMPILER} is not recognized (g++, icpc). Using CMake defaults.") +endif() + + +if(USING_WINDOWS_CL) + # We should set this macro as well to get our nice trig functions + add_definitions(-D_USE_MATH_DEFINES) + # Microsoft does some stupid things like #define min and max. + add_definitions(-DNOMINMAX) +endif() diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/ConfigCompilerFlags.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/ConfigCompilerFlags.cmake new file mode 100644 index 00000000..2cc2ab3b --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/ConfigCompilerFlags.cmake @@ -0,0 +1,418 @@ + +# +# Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA Corporation and its licensors retain all intellectual property and proprietary +# rights in and to this software, related documentation and any modifications thereto. +# Any use, reproduction, disclosure or distribution of this software and related +# documentation without an express license agreement from NVIDIA Corporation is strictly +# prohibited. +# +# TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* +# AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, +# INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY +# SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT +# LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF +# BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR +# INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGES +# + +# This will create a set of default compiler flags based on the system +# and compiler supplied. + +############################################################## +## Compiler libraries +############################################################## + +# Some compilers in non default locations have libraries they need in +# order to run properly. You could change your LD_LIBRARY_PATH or you +# could add the path toth to the rpath of the library or executable. +# This helps with that. + +SET(COMPILER_LIBRARY_PATH "${COMPILER_LIBRARY_PATH}" CACHE PATH "Path to compiler libraries" FORCE) +MARK_AS_ADVANCED(COMPILER_LIBRARY_PATH) + +IF(EXISTS "${COMPILER_LIBRARY_PATH}") + SET(rpath_arg "-Wl,-rpath,\"${COMPILER_LIBRARY_PATH}\"") + # TODO(bigler): remove the old path if there is one + FORCE_ADD_FLAGS(CMAKE_EXE_LINKER_FLAGS ${rpath_arg}) + FORCE_ADD_FLAGS(CMAKE_MODULE_LINKER_FLAGS ${rpath_arg}) + FORCE_ADD_FLAGS(CMAKE_SHARED_LINKER_FLAGS ${rpath_arg}) +ELSE(EXISTS "${COMPILER_LIBRARY_PATH}") + IF(COMPILER_LIBRARY_PATH) + MESSAGE(FATAL_ERROR "COMPILER_LIBRARY_PATH is set, but the path does not exist:\n${COMPILER_LIBRARY_PATH}") + ENDIF(COMPILER_LIBRARY_PATH) +ENDIF(EXISTS "${COMPILER_LIBRARY_PATH}") + +############################################################## +## Helper macros +############################################################## + +macro(set_flags FLAG NEW_VALUE) + if(${NEW_VALUE}) +# first_time_message("Setting compiler flags:") +# first_time_message("${NEW_VALUE} = ${${NEW_VALUE}}") + first_time_set(${FLAG} "${${NEW_VALUE}}" STRING "Default compiler flags" ) + endif() +endmacro() + +# Appends ${new} to the string of flags in ${flag}_INIT, then uses that variable to set +# ${flags} via the set_flags macro. Note that ${flag}_INIT isn't modified outside of the +# function's scope. +function(append_and_set flag new) + APPEND_TO_STRING(${flag}_INIT "${new}") + set_flags(${flag} ${flag}_INIT) +endfunction() + +############################################################## +## System independent +############################################################## + +# Initialize these parameters +SET(C_FLAGS "") +SET(C_FLAGS_DEBUG "") +SET(C_FLAGS_RELEASE "") + +SET(CXX_FLAGS "") +SET(CXX_FLAGS_DEBUG "") +SET(CXX_FLAGS_RELEASE "") + +SET(INTEL_OPT " ") +SET(GCC_OPT " ") +SET(CL_OPT " ") + +# Set some defaults. CMake provides some defaults in the INIT +# versions of the variables. +APPEND_TO_STRING(C_FLAGS "${CMAKE_C_FLAGS_INIT}") +# +APPEND_TO_STRING(CXX_FLAGS "${CMAKE_CXX_FLAGS_INIT}") + +# We want to enable aggressive warnings for everyone to avoid unexpected build +# farm failures. This can only be configured from the command line or from the +# caller's CMakeLists.txt. +if(NOT DEFINED OPTIX_USE_AGGRESSIVE_WARNINGS) + set(OPTIX_USE_AGGRESSIVE_WARNINGS ON) +endif() + +############################################################# +# Set the default warning levels for each compiler. Where the compiler runs on +# multiple architectures, the flags are architecture independent. +############################################################# + +if(OPTIX_USE_AGGRESSIVE_WARNINGS) + if (USING_CLANG_CXX) + # Extra warning suppression that clang warns about + set(clang_warnings "-Wno-unused-function -Wno-unused-private-field -Wno-unused-const-variable -Wno-deprecated-declarations -Wno-missing-braces") + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG(-Wno-inconsistent-missing-override CXX_ACCEPTS_NO_INCONSISTENT_MISSING_OVERRIDE) + if(CXX_ACCEPTS_NO_INCONSISTENT_MISSING_OVERRIDE) + # clang 8.0 warns on missing override decorators + set(clang_warnings "${clang_warnings} -Wno-inconsistent-missing-override") + endif() + endif() + + # Needed for corelib's use of deprecated sysctl.h + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG(-Wno-cpp OPTIX_CXX_ACCEPTS_NO_CPP) + if(OPTIX_CXX_ACCEPTS_NO_CPP) + set(OPTIX_NO_CPP -Wno-cpp) + endif() + + SET(CXX_WARNING_FLAGS "-Wall -Wsign-compare -Wno-multichar ${clang_warnings} ${OPTIX_NO_CPP}") + SET(C_WARNING_FLAGS "${CXX_WARNING_FLAGS} -Wstrict-prototypes -Wdeclaration-after-statement") + if(WARNINGS_AS_ERRORS) + APPEND_TO_STRING(C_WARNING_FLAGS "-Werror") + APPEND_TO_STRING(CXX_WARNING_FLAGS "-Werror") + endif() +else() + set(C_WARNING_FLAGS " ") + set(CXX_WARNING_FLAGS " ") +endif() +SET(DEBUG_FLAGS "-O0 -g3") + +# We might consider adding -ffast-math. + +SET(RELEASE_FLAGS "-O3 -DNDEBUG -g3 -funroll-loops") +IF (USING_GNU_C OR USING_CLANG_C) + APPEND_TO_STRING(C_FLAGS ${C_WARNING_FLAGS}) + APPEND_TO_STRING(C_FLAGS_DEBUG ${DEBUG_FLAGS}) + APPEND_TO_STRING(C_FLAGS_RELEASE ${RELEASE_FLAGS}) +ENDIF() + +IF (USING_GNU_CXX OR USING_CLANG_CXX) + APPEND_TO_STRING(CXX_FLAGS ${CXX_WARNING_FLAGS}) + APPEND_TO_STRING(CXX_FLAGS_DEBUG "${DEBUG_FLAGS}") + APPEND_TO_STRING(CXX_FLAGS_RELEASE ${RELEASE_FLAGS}) + + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG(-Wno-unused-result OPTIX_CXX_ACCEPTS_NO_UNUSED_RESULT) + if(OPTIX_CXX_ACCEPTS_NO_UNUSED_RESULT) + set(OPTIX_NO_UNUSED_RESULT -Wno-unused-result) + endif() + +ENDIF() + +######################## +# Windows flags + +# /W3 - more warnings +# /WX - warnings as errors +# +# Disable these warnings: +# /wd4355 - 'this' used in initializer list +# /wd4996 - strncpy and other functions are unsafe +# /wd4800 - forcing value to bool 'true' or 'false' (performance warning) +# +# Turn on warnings for level /W3 (/w3XXXX): +# /w34101 - unreference local variable +# /w34189 - local variable is initialized but not referenced +# /w34018 - 'expression' : signed/unsigned mismatch +# /w34389 - 'operator' : signed/unsigned mismatch +if( WIN32 ) + set( WARNING_FLAGS "/W3" ) + if( WARNINGS_AS_ERRORS ) + set( WARNING_FLAGS "${WARNING_FLAGS} /WX" ) + endif() + + if(OPTIX_USE_AGGRESSIVE_WARNINGS) + set(WARNING_FLAGS "${WARNING_FLAGS} /wd4355 /wd4996 /wd4800 /w34101 /w34189 /w34018 /w34389") + else() + set(WARNING_FLAGS "${WARNING_FLAGS} /wd4355 /wd4996") + endif() + SET(DEBUG_FLAGS "") +endif() + +# Add /MP to get file-level compilation parallelism +SET(PARALLEL_COMPILE_FLAGS /MP) + +IF (USING_WINDOWS_CL) + APPEND_TO_STRING(C_FLAGS "${PARALLEL_COMPILE_FLAGS} ${WARNING_FLAGS}") + APPEND_TO_STRING(CXX_FLAGS "${PARALLEL_COMPILE_FLAGS} ${WARNING_FLAGS}") + + # /Ox - Full Optimization (should supperseed the /O2 optimization + # /Ot - Favor fast code over small code + # /GL (not used) - Enable link time code generation + # /arch:SSE - Enable SSE instructions (only for 32 bit builds) + # /fp:fast - Use Fast floating point model + string(REPLACE "/O2" "/Ox" CMAKE_C_FLAGS_RELEASE_INIT "${CMAKE_C_FLAGS_RELEASE_INIT}") + string(REPLACE "/O2" "/Ox" CMAKE_CXX_FLAGS_RELEASE_INIT "${CMAKE_CXX_FLAGS_RELEASE_INIT}") + set(CL_OPT "/Ot /fp:fast") + if (CMAKE_SIZEOF_VOID_P EQUAL 4) + APPEND_TO_STRING(CL_OPT "/arch:SSE") + endif() + + append_and_set(CMAKE_C_FLAGS_RELEASE "${CL_OPT}") + append_and_set(CMAKE_CXX_FLAGS_RELEASE "${CL_OPT}") + # Turn these on if you turn /GL on + # append_and_set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/ltcg") + # append_and_set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "/ltcg") + # append_and_set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "/ltcg") +ENDIF(USING_WINDOWS_CL) + +SET(WARNING_FLAGS "/D_CRT_SECURE_NO_DEPRECATE=1 /Qstd=c99") +IF (USING_WINDOWS_ICL) + # These are the warnings + APPEND_TO_STRING(C_FLAGS ${WARNING_FLAGS}) + APPEND_TO_STRING(CXX_FLAGS ${WARNING_FLAGS}) +ENDIF(USING_WINDOWS_ICL) + +############################################################## +## Check for SSE 4.1 support +############################################################## +if(USING_GNU_C OR USING_CLANG_C) + include(CheckCCompilerFlag) + CHECK_C_COMPILER_FLAG(-msse4.1 SSE_41_AVAILABLE) +elseif(USING_WINDOWS_CL) + set(SSE_41_AVAILABLE 1) +else() + message(WARNING "Unknown Compiler. Disabling SSE 4.1 support") + set(SSE_41_AVAILABLE 0) +endif() +get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +configure_file("${CMAKE_CURRENT_LIST_DIR}/sse_support.h.in" "${CMAKE_BINARY_DIR}/include/sse_support.h") + + +############################################################## +## Apple +############################################################## +IF(APPLE) + if (USING_CLANG_CXX) + # We have to use libc++ because the libstdc++ does not support std::move + # https://cplusplusmusings.wordpress.com/2012/07/05/clang-and-standard-libraries-on-mac-os-x/ + APPEND_TO_STRING(CXX_FLAGS "-stdlib=libc++") + APPEND_TO_STRING(CXX_FLAGS "-mmacosx-version-min=10.8") + endif() + APPEND_TO_STRING(GCC_ARCH "nocona") + APPEND_TO_STRING(GCC_ARCH "prescott") + APPEND_TO_STRING(GCC_OPT "-msse -msse2 -msse3") + if( USING_GNU_C OR USING_GNU_CXX) + APPEND_TO_STRING(GCC_OPT "-mfpmath=sse") + endif() +ENDIF(APPLE) + +############################################################## +## X86 +############################################################## + +# On apple machines CMAKE_SYSTEM_PROCESSOR return i386. + +IF (CMAKE_SYSTEM_PROCESSOR MATCHES "i686" OR + CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") + APPEND_TO_STRING(GCC_OPT "-msse -msse2 -msse3 -mfpmath=sse") + + # mtune options + + INCLUDE(LinuxCPUInfo) + + # AMD + IF(VENDOR_ID MATCHES "AuthenticAMD") + APPEND_TO_STRING(GCC_ARCH "opteron") # supports 64 bit instructions + APPEND_TO_STRING(GCC_ARCH "athlon-xp") # no support for 64 bit instructions + APPEND_TO_STRING(INTEL_OPT "-xW -unroll4") + ENDIF(VENDOR_ID MATCHES "AuthenticAMD") + + # Intel + IF(VENDOR_ID MATCHES "GenuineIntel") + + IF(CPU_FAMILY EQUAL 6) + + IF(MODEL EQUAL 15) # (F) + + # This is likely a Core 2 + # APPEND_TO_STRING(GCC_ARCH "kentsfield") # QX6700 + APPEND_TO_STRING(GCC_ARCH "nocona") + APPEND_TO_STRING(GCC_ARCH "prescott") + + # -xT Intel(R) Core(TM)2 Duo processors, Intel(R) Core(TM)2 Quad + # processors, and Intel(R) Xeon(R) processors with SSSE3 + APPEND_TO_STRING(INTEL_OPT "-xT -unroll4") + + ENDIF(MODEL EQUAL 15) + + IF(MODEL EQUAL 14) # (E) + # This is likely a Core Single or Core Duo. This doesn't + # support EM64T. + APPEND_TO_STRING(GCC_ARCH "prescott") + ENDIF(MODEL EQUAL 14) + IF(MODEL LESS 14) #(0-D) + # This is likely a Pentium3, Pentium M. Some pentium 3s don't + # support sse2, in that case fall back to the i686 code. + APPEND_TO_STRING(GCC_ARCH "pentium-m") + APPEND_TO_STRING(INTEL_OPT "-xB") + ENDIF(MODEL LESS 14) + ENDIF(CPU_FAMILY EQUAL 6) + IF(CPU_FAMILY EQUAL 15) + # These are your Pentium 4 and friends + IF(FLAGS MATCHES "em64t") + APPEND_TO_STRING(GCC_ARCH "nocona") + APPEND_TO_STRING(GCC_ARCH "prescott") + ENDIF(FLAGS MATCHES "em64t") + APPEND_TO_STRING(GCC_ARCH "pentium4") + APPEND_TO_STRING(INTEL_OPT "-xP -unroll4 -msse3") + ENDIF(CPU_FAMILY EQUAL 15) + ENDIF(VENDOR_ID MATCHES "GenuineIntel") + APPEND_TO_STRING(GCC_ARCH "i686") + + ########################################################### + # Some x86_64 specific stuff + IF (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") + APPEND_TO_STRING(INTEL_OPT "") + ENDIF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") + ########################################################### + +ENDIF (CMAKE_SYSTEM_PROCESSOR MATCHES "i686" OR + CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") + +############################################################## +## Configure Architecture +############################################################## + +# Cycle through the GCC_ARCH args and see which one will pass first. +# Guard this evaluation with PASSED_FIRST_CONFIGURE, to make sure it +# is only done the first time. +IF(USING_GNU_C OR USING_GNU_CXX OR USING_CLANG_C OR USING_CLANG_CXX AND NOT PASSED_FIRST_CONFIGURE) + SEPARATE_ARGUMENTS(GCC_ARCH) + # Change the extension based of if we are using both gcc and g++. + IF(USING_GNU_C OR USING_CLANG_C) + SET(EXTENSION "c") + ELSE() + SET(EXTENSION "cc") + ENDIF() + SET(COMPILE_TEST_SOURCE ${CMAKE_BINARY_DIR}/test/compile-test.${EXTENSION}) + CONFIGURE_FILE("${CMAKE_CURRENT_LIST_DIR}/testmain.c" + ${COMPILE_TEST_SOURCE} IMMEDIATE COPYONLY) + FOREACH(ARCH ${GCC_ARCH}) + IF(NOT GOOD_ARCH) +# MESSAGE("Testing ARCH = ${ARCH}") + SET(ARCH_FLAG "-march=${ARCH} -mtune=${ARCH}") + SET(COMPILER_ARGS "${ARCH_FLAG} ${C_FLAGS_RELEASE} ${C_FLAGS} ${GCC_OPT}") + TRY_RUN(RUN_RESULT_VAR COMPILE_RESULT_VAR + ${CMAKE_BINARY_DIR}/test ${COMPILE_TEST_SOURCE} + CMAKE_FLAGS + -DCOMPILE_DEFINITIONS:STRING=${COMPILER_ARGS} + OUTPUT_VARIABLE OUTPUT + ) +# MESSAGE("OUTPUT = ${OUTPUT}") +# MESSAGE("COMPILER_ARGS = ${COMPILER_ARGS}") +# MESSAGE("RUN_RESULT_VAR = ${RUN_RESULT_VAR}") +# MESSAGE("COMPILE_RESULT_VAR = ${COMPILE_RESULT_VAR}") + IF(RUN_RESULT_VAR EQUAL 0) + SET(GOOD_ARCH ${ARCH}) + ENDIF(RUN_RESULT_VAR EQUAL 0) + ENDIF(NOT GOOD_ARCH) + ENDFOREACH(ARCH) + IF(GOOD_ARCH) + PREPEND_TO_STRING(GCC_OPT "-march=${GOOD_ARCH} -mtune=${GOOD_ARCH}") + ENDIF(GOOD_ARCH) +# MESSAGE("GOOD_ARCH = ${GOOD_ARCH}") +ENDIF() + +# MESSAGE("CMAKE_SYSTEM_PROCESSOR = ${CMAKE_SYSTEM_PROCESSOR}") +# MESSAGE("APPLE = ${APPLE}") +# MESSAGE("LINUX = ${LINUX}") + +############################################################## +## Set the defaults +############################################################## + +# MESSAGE("CMAKE_C_COMPILER = ${CMAKE_C_COMPILER}") +# MESSAGE("CMAKE_CXX_COMPILER = ${CMAKE_CXX_COMPILER}") + +# MESSAGE("USING_GNU_C = ${USING_GNU_C}") +# MESSAGE("USING_GNU_CXX = ${USING_GNU_CXX}") +# MESSAGE("USING_ICC = ${USING_ICC}") +# MESSAGE("USING_ICPC = ${USING_ICPC}") +# MESSAGE("CMAKE version = ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}") +# MESSAGE("CMAKE_SYSTEM = ${CMAKE_SYSTEM}") +# MESSAGE("CMAKE_SYSTEM_PROCESSOR = ${CMAKE_SYSTEM_PROCESSOR}") + +MACRO(ADD_COMPILER_FLAG COMPILER FLAGS NEW_FLAG) + IF(${COMPILER}) + PREPEND_TO_STRING(${FLAGS} ${${NEW_FLAG}}) + ENDIF(${COMPILER}) +ENDMACRO(ADD_COMPILER_FLAG) + +ADD_COMPILER_FLAG(USING_ICC C_FLAGS_RELEASE INTEL_OPT) +ADD_COMPILER_FLAG(USING_ICPC CXX_FLAGS_RELEASE INTEL_OPT) +ADD_COMPILER_FLAG(USING_GNU_C C_FLAGS_RELEASE GCC_OPT) +ADD_COMPILER_FLAG(USING_GNU_CXX CXX_FLAGS_RELEASE GCC_OPT) +ADD_COMPILER_FLAG(USING_CLANG_C C_FLAGS_RELEASE GCC_OPT) +ADD_COMPILER_FLAG(USING_CLANG_CXX CXX_FLAGS_RELEASE GCC_OPT) + +IF(UNIX) + APPEND_TO_STRING(C_FLAGS "-fPIC") + APPEND_TO_STRING(CXX_FLAGS "-fPIC") +ENDIF(UNIX) + +set_flags(CMAKE_C_FLAGS C_FLAGS) +set_flags(CMAKE_C_FLAGS_DEBUG C_FLAGS_DEBUG) +set_flags(CMAKE_C_FLAGS_RELEASE C_FLAGS_RELEASE) + +set_flags(CMAKE_CXX_FLAGS CXX_FLAGS) +set_flags(CMAKE_CXX_FLAGS_DEBUG CXX_FLAGS_DEBUG) +set_flags(CMAKE_CXX_FLAGS_RELEASE CXX_FLAGS_RELEASE) + + + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/CopyDLL.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/CopyDLL.cmake new file mode 100644 index 00000000..c1cc3b65 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/CopyDLL.cmake @@ -0,0 +1,78 @@ + +# +# Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA Corporation and its licensors retain all intellectual property and proprietary +# rights in and to this software, related documentation and any modifications thereto. +# Any use, reproduction, disclosure or distribution of this software and related +# documentation without an express license agreement from NVIDIA Corporation is strictly +# prohibited. +# +# TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* +# AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, +# INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY +# SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT +# LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF +# BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR +# INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGES +# + +# This script copies one of two supplied dlls into the build directory based on the build configuration. + +# build_configuration - Should be passed in via: + +# if(CMAKE_GENERATOR MATCHES "Visual Studio") +# set( build_configuration "$(ConfigurationName)" ) +# else() +# set( build_configuration "${CMAKE_BUILD_TYPE}") +# endif() +# +# -D build_configuration:STRING=${build_configuration} + +# output_directory - should be passed in via the following. If not supplied the current output directory is used. +# +# -D "output_directory:PATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}" + +# source_dll - should be the release version or the single version if you don't have a debug version +# +# -D "source_dll:FILE=${path_to_source_dll}" + +# source_debug_dll - should be the debug version of the dll (optional) +# +# -D "source_debug_dll:FILE=${path_to_source_debug_dll}" + +if(NOT DEFINED build_configuration) + message(FATAL_ERROR "build_configuration not specified") +endif() + +if(NOT DEFINED output_directory) + set(output_directory ".") +endif() + +if(NOT DEFINED source_dll) + message(FATAL_ERROR "source_dll not specified") +endif() + +if(NOT DEFINED source_debug_dll) + set(source_debug_dll "${source_dll}") +endif() + +# Compute the file name +if(build_configuration STREQUAL Debug) + set(source "${source_debug_dll}") +else() + set(source "${source_dll}") +endif() + +get_filename_component(filename "${source}" NAME) +set(dest "${output_directory}/${filename}") +message(STATUS "Copying if different ${source} to ${dest}") +execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${source}" "${dest}" + RESULT_VARIABLE result + ) +if(result) + message(FATAL_ERROR "Error copying dll") +endif() + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA.cmake new file mode 100644 index 00000000..0ffee079 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA.cmake @@ -0,0 +1,2289 @@ +#.rst: +# FindCUDA +# -------- +# +# Tools for building CUDA C files: libraries and build dependencies. +# +# This script locates the NVIDIA CUDA C tools. It should work on linux, +# windows, and mac and should be reasonably up to date with CUDA C +# releases. +# +# This script makes use of the standard find_package arguments of +# , REQUIRED and QUIET. CUDA_FOUND will report if an +# acceptable version of CUDA was found. +# +# The script will prompt the user to specify CUDA_TOOLKIT_ROOT_DIR if +# the prefix cannot be determined by the location of nvcc in the system +# path and REQUIRED is specified to find_package(). To use a different +# installed version of the toolkit set the environment variable +# CUDA_BIN_PATH before running cmake (e.g. +# CUDA_BIN_PATH=/usr/local/cuda1.0 instead of the default +# /usr/local/cuda) or set CUDA_TOOLKIT_ROOT_DIR after configuring. If +# you change the value of CUDA_TOOLKIT_ROOT_DIR, various components that +# depend on the path will be relocated. +# +# It might be necessary to set CUDA_TOOLKIT_ROOT_DIR manually on certain +# platforms, or to use a cuda runtime not installed in the default +# location. In newer versions of the toolkit the cuda library is +# included with the graphics driver- be sure that the driver version +# matches what is needed by the cuda runtime version. +# +# The following variables affect the behavior of the macros in the +# script (in alphebetical order). Note that any of these flags can be +# changed multiple times in the same directory before calling +# CUDA_ADD_EXECUTABLE, CUDA_ADD_LIBRARY, CUDA_COMPILE, CUDA_COMPILE_PTX, +# CUDA_COMPILE_FATBIN, CUDA_COMPILE_CUBIN or CUDA_WRAP_SRCS:: +# +# CUDA_64_BIT_DEVICE_CODE (Default matches host bit size) +# -- Set to ON to compile for 64 bit device code, OFF for 32 bit device code. +# Note that making this different from the host code when generating object +# or C files from CUDA code just won't work, because size_t gets defined by +# nvcc in the generated source. If you compile to PTX and then load the +# file yourself, you can mix bit sizes between device and host. +# +# CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE (Default ON) +# -- Set to ON if you want the custom build rule to be attached to the source +# file in Visual Studio. Turn OFF if you add the same cuda file to multiple +# targets. +# +# This allows the user to build the target from the CUDA file; however, bad +# things can happen if the CUDA source file is added to multiple targets. +# When performing parallel builds it is possible for the custom build +# command to be run more than once and in parallel causing cryptic build +# errors. VS runs the rules for every source file in the target, and a +# source can have only one rule no matter how many projects it is added to. +# When the rule is run from multiple targets race conditions can occur on +# the generated file. Eventually everything will get built, but if the user +# is unaware of this behavior, there may be confusion. It would be nice if +# this script could detect the reuse of source files across multiple targets +# and turn the option off for the user, but no good solution could be found. +# +# CUDA_BUILD_CUBIN (Default OFF) +# -- Set to ON to enable and extra compilation pass with the -cubin option in +# Device mode. The output is parsed and register, shared memory usage is +# printed during build. +# +# CUDA_BUILD_EMULATION (Default OFF for device mode) +# -- Set to ON for Emulation mode. -D_DEVICEEMU is defined for CUDA C files +# when CUDA_BUILD_EMULATION is TRUE. +# +# CUDA_ENABLE_BATCHING (Default OFF) +# -- Set to ON to enable batch compilation of CUDA source files. This only has +# effect on Visual Studio targets +# +# CUDA_GENERATED_OUTPUT_DIR (Default CMAKE_CURRENT_BINARY_DIR) +# -- Set to the path you wish to have the generated files placed. If it is +# blank output files will be placed in CMAKE_CURRENT_BINARY_DIR. +# Intermediate files will always be placed in +# CMAKE_CURRENT_BINARY_DIR/CMakeFiles. +# +# CUDA_GENERATE_DEPENDENCIES_DURING_CONFIGURE (Default ON for VS, +# OFF otherwise) +# -- Instead of waiting until build time compute dependencies, do it during +# configure time. Note that dependencies are still generated during +# build, so that if they change the build system can be updated. This +# mainly removes the need for configuring once after the first build to +# load the dependies into the build system. +# +# CUDA_CHECK_DEPENDENCIES_DURING_COMPILE (Default ON for VS, +# OFF otherwise) +# -- During build, the file level dependencies are checked. If all +# dependencies are older than the generated file, the generated file isn't +# compiled but touched (time stamp updated) so the driving build system +# thinks it has been compiled. +# +# CUDA_HOST_COMPILATION_CPP (Default ON) +# -- Set to OFF for C compilation of host code. +# +# CUDA_HOST_COMPILER (Default CMAKE_C_COMPILER, $(VCInstallDir)/bin for VS) +# -- Set the host compiler to be used by nvcc. Ignored if -ccbin or +# --compiler-bindir is already present in the CUDA_NVCC_FLAGS or +# CUDA_NVCC_FLAGS_ variables. For Visual Studio targets +# $(VCInstallDir)/bin is a special value that expands out to the path when +# the command is run from within VS. +# +# CUDA_NVCC_FLAGS +# CUDA_NVCC_FLAGS_ +# -- Additional NVCC command line arguments. NOTE: multiple arguments must be +# semi-colon delimited (e.g. --compiler-options;-Wall) +# +# CUDA_PROPAGATE_HOST_FLAGS (Default ON) +# -- Set to ON to propagate CMAKE_{C,CXX}_FLAGS and their configuration +# dependent counterparts (e.g. CMAKE_C_FLAGS_DEBUG) automatically to the +# host compiler through nvcc's -Xcompiler flag. This helps make the +# generated host code match the rest of the system better. Sometimes +# certain flags give nvcc problems, and this will help you turn the flag +# propagation off. This does not affect the flags supplied directly to nvcc +# via CUDA_NVCC_FLAGS or through the OPTION flags specified through +# CUDA_ADD_LIBRARY, CUDA_ADD_EXECUTABLE, or CUDA_WRAP_SRCS. Flags used for +# shared library compilation are not affected by this flag. +# +# CUDA_SEPARABLE_COMPILATION (Default OFF) +# -- If set this will enable separable compilation for all CUDA runtime object +# files. If used outside of CUDA_ADD_EXECUTABLE and CUDA_ADD_LIBRARY +# (e.g. calling CUDA_WRAP_SRCS directly), +# CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME and +# CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS should be called. +# +# CUDA_SOURCE_PROPERTY_FORMAT +# -- If this source file property is set, it can override the format specified +# to CUDA_WRAP_SRCS (OBJ, PTX, CUBIN, or FATBIN). If an input source file +# is not a .cu file, setting this file will cause it to be treated as a .cu +# file. See documentation for set_source_files_properties on how to set +# this property. +# +# CUDA_USE_STATIC_CUDA_RUNTIME (Default ON) +# -- When enabled the static version of the CUDA runtime library will be used +# in CUDA_LIBRARIES. If the version of CUDA configured doesn't support +# this option, then it will be silently disabled. +# +# CUDA_VERBOSE_BUILD (Default OFF) +# -- Set to ON to see all the commands used when building the CUDA file. When +# using a Makefile generator the value defaults to VERBOSE (run make +# VERBOSE=1 to see output), although setting CUDA_VERBOSE_BUILD to ON will +# always print the output. +# +# The script creates the following macros (in alphebetical order):: +# +# CUDA_ADD_CUFFT_TO_TARGET( cuda_target ) +# -- Adds the cufft library to the target (can be any target). Handles whether +# you are in emulation mode or not. +# +# CUDA_ADD_CUBLAS_TO_TARGET( cuda_target ) +# -- Adds the cublas library to the target (can be any target). Handles +# whether you are in emulation mode or not. +# +# CUDA_ADD_EXECUTABLE( cuda_target file0 file1 ... +# [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [OPTIONS ...] ) +# -- Creates an executable "cuda_target" which is made up of the files +# specified. All of the non CUDA C files are compiled using the standard +# build rules specified by CMAKE and the cuda files are compiled to object +# files using nvcc and the host compiler. In addition CUDA_INCLUDE_DIRS is +# added automatically to include_directories(). Some standard CMake target +# calls can be used on the target after calling this macro +# (e.g. set_target_properties and target_link_libraries), but setting +# properties that adjust compilation flags will not affect code compiled by +# nvcc. Such flags should be modified before calling CUDA_ADD_EXECUTABLE, +# CUDA_ADD_LIBRARY or CUDA_WRAP_SRCS. +# +# CUDA_ADD_LIBRARY( cuda_target file0 file1 ... +# [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [OPTIONS ...] ) +# -- Same as CUDA_ADD_EXECUTABLE except that a library is created. +# +# CUDA_BUILD_CLEAN_TARGET() +# -- Creates a convience target that deletes all the dependency files +# generated. You should make clean after running this target to ensure the +# dependency files get regenerated. +# +# CUDA_COMPILE( generated_files file0 file1 ... [STATIC | SHARED | MODULE] +# [OPTIONS ...] ) +# -- Returns a list of generated files from the input source files to be used +# with ADD_LIBRARY or ADD_EXECUTABLE. +# +# CUDA_COMPILE_PTX( generated_files file0 file1 ... [OPTIONS ...] ) +# -- Returns a list of PTX files generated from the input source files. +# +# CUDA_COMPILE_FATBIN( generated_files file0 file1 ... [OPTIONS ...] ) +# -- Returns a list of FATBIN files generated from the input source files. +# +# CUDA_COMPILE_CUBIN( generated_files file0 file1 ... [OPTIONS ...] ) +# -- Returns a list of CUBIN files generated from the input source files. +# +# CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME( output_file_var +# cuda_target +# object_files ) +# -- Compute the name of the intermediate link file used for separable +# compilation. This file name is typically passed into +# CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS. output_file_var is produced +# based on cuda_target the list of objects files that need separable +# compilation as specified by object_files. If the object_files list is +# empty, then output_file_var will be empty. This function is called +# automatically for CUDA_ADD_LIBRARY and CUDA_ADD_EXECUTABLE. Note that +# this is a function and not a macro. +# +# CUDA_INCLUDE_DIRECTORIES( path0 path1 ... ) +# -- Sets the directories that should be passed to nvcc +# (e.g. nvcc -Ipath0 -Ipath1 ... ). These paths usually contain other .cu +# files. +# +# +# CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS( output_file_var cuda_target +# nvcc_flags object_files) +# -- Generates the link object required by separable compilation from the given +# object files. This is called automatically for CUDA_ADD_EXECUTABLE and +# CUDA_ADD_LIBRARY, but can be called manually when using CUDA_WRAP_SRCS +# directly. When called from CUDA_ADD_LIBRARY or CUDA_ADD_EXECUTABLE the +# nvcc_flags passed in are the same as the flags passed in via the OPTIONS +# argument. The only nvcc flag added automatically is the bitness flag as +# specified by CUDA_64_BIT_DEVICE_CODE. Note that this is a function +# instead of a macro. +# +# CUDA_SELECT_NVCC_ARCH_FLAGS(out_variable [target_CUDA_architectures]) +# -- Selects GPU arch flags for nvcc based on target_CUDA_architectures +# target_CUDA_architectures : Auto | Common | All | LIST(ARCH_AND_PTX ...) +# - "Auto" detects local machine GPU compute arch at runtime. +# - "Common" and "All" cover common and entire subsets of architectures +# ARCH_AND_PTX : NAME | NUM.NUM | NUM.NUM(NUM.NUM) | NUM.NUM+PTX +# NAME: Fermi Kepler Maxwell Kepler+Tegra Kepler+Tesla Maxwell+Tegra Pascal +# NUM: Any number. Only those pairs are currently accepted by NVCC though: +# 2.0 2.1 3.0 3.2 3.5 3.7 5.0 5.2 5.3 6.0 6.2 +# Returns LIST of flags to be added to CUDA_NVCC_FLAGS in ${out_variable} +# Additionally, sets ${out_variable}_readable to the resulting numeric list +# Example: +# CUDA_SELECT_NVCC_ARCH_FLAGS(ARCH_FLAGS 3.0 3.5+PTX 5.2(5.0) Maxwell) +# LIST(APPEND CUDA_NVCC_FLAGS ${ARCH_FLAGS}) +# +# More info on CUDA architectures: https://en.wikipedia.org/wiki/CUDA +# Note that this is a function instead of a macro. +# +# CUDA_WRAP_SRCS ( cuda_target format generated_files file0 file1 ... +# [STATIC | SHARED | MODULE] [OPTIONS ...] ) +# -- This is where all the magic happens. CUDA_ADD_EXECUTABLE, +# CUDA_ADD_LIBRARY, CUDA_COMPILE, and CUDA_COMPILE_PTX all call this +# function under the hood. +# +# Given the list of files (file0 file1 ... fileN) this macro generates +# custom commands that generate either PTX or linkable objects (use "PTX" or +# "OBJ" for the format argument to switch). Files that don't end with .cu +# or have the HEADER_FILE_ONLY property are ignored. +# +# The arguments passed in after OPTIONS are extra command line options to +# give to nvcc. You can also specify per configuration options by +# specifying the name of the configuration followed by the options. General +# options must precede configuration specific options. Not all +# configurations need to be specified, only the ones provided will be used. +# +# OPTIONS -DFLAG=2 "-DFLAG_OTHER=space in flag" +# DEBUG -g +# RELEASE --use_fast_math +# RELWITHDEBINFO --use_fast_math;-g +# MINSIZEREL --use_fast_math +# +# For certain configurations (namely VS generating object files with +# CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE set to ON), no generated file will +# be produced for the given cuda file. This is because when you add the +# cuda file to Visual Studio it knows that this file produces an object file +# and will link in the resulting object file automatically. +# +# This script will also generate a separate cmake script that is used at +# build time to invoke nvcc. This is for several reasons. +# +# 1. nvcc can return negative numbers as return values which confuses +# Visual Studio into thinking that the command succeeded. The script now +# checks the error codes and produces errors when there was a problem. +# +# 2. nvcc has been known to not delete incomplete results when it +# encounters problems. This confuses build systems into thinking the +# target was generated when in fact an unusable file exists. The script +# now deletes the output files if there was an error. +# +# 3. By putting all the options that affect the build into a file and then +# make the build rule dependent on the file, the output files will be +# regenerated when the options change. +# +# This script also looks at optional arguments STATIC, SHARED, or MODULE to +# determine when to target the object compilation for a shared library. +# BUILD_SHARED_LIBS is ignored in CUDA_WRAP_SRCS, but it is respected in +# CUDA_ADD_LIBRARY. On some systems special flags are added for building +# objects intended for shared libraries. A preprocessor macro, +# _EXPORTS is defined when a shared library compilation is +# detected. +# +# Flags passed into add_definitions with -D or /D are passed along to nvcc. +# +# +# +# The script defines the following variables:: +# +# CUDA_VERSION_MAJOR -- The major version of cuda as reported by nvcc. +# CUDA_VERSION_MINOR -- The minor version. +# CUDA_VERSION +# CUDA_VERSION_STRING -- CUDA_VERSION_MAJOR.CUDA_VERSION_MINOR +# CUDA_HAS_FP16 -- Whether a short float (float16,fp16) is supported. +# +# CUDA_TOOLKIT_ROOT_DIR -- Path to the CUDA Toolkit (defined if not set). +# CUDA_SDK_ROOT_DIR -- Path to the CUDA SDK. Use this to find files in the +# SDK. This script will not directly support finding +# specific libraries or headers, as that isn't +# supported by NVIDIA. If you want to change +# libraries when the path changes see the +# FindCUDA.cmake script for an example of how to clear +# these variables. There are also examples of how to +# use the CUDA_SDK_ROOT_DIR to locate headers or +# libraries, if you so choose (at your own risk). +# CUDA_INCLUDE_DIRS -- Include directory for cuda headers. Added automatically +# for CUDA_ADD_EXECUTABLE and CUDA_ADD_LIBRARY. +# CUDA_LIBRARIES -- Cuda RT library. +# CUDA_CUDA_LIBRARY -- Cuda driver API library. +# CUDA_CUFFT_LIBRARIES -- Device or emulation library for the Cuda FFT +# implementation (alternative to: +# CUDA_ADD_CUFFT_TO_TARGET macro) +# CUDA_CUBLAS_LIBRARIES -- Device or emulation library for the Cuda BLAS +# implementation (alternative to: +# CUDA_ADD_CUBLAS_TO_TARGET macro). +# CUDA_cudart_static_LIBRARY -- Statically linkable cuda runtime library. +# Only available for CUDA version 5.5+ +# CUDA_cudadevrt_LIBRARY -- Device runtime library. +# Required for separable compilation. +# CUDA_cupti_LIBRARY -- CUDA Profiling Tools Interface library. +# Only available for CUDA version 4.0+. +# CUDA_curand_LIBRARY -- CUDA Random Number Generation library. +# Only available for CUDA version 3.2+. +# CUDA_cusolver_LIBRARY -- CUDA Direct Solver library. +# Only available for CUDA version 7.0+. +# CUDA_cusparse_LIBRARY -- CUDA Sparse Matrix library. +# Only available for CUDA version 3.2+. +# CUDA_npp_LIBRARY -- NVIDIA Performance Primitives lib. +# Only available for CUDA version 4.0+. +# CUDA_nppc_LIBRARY -- NVIDIA Performance Primitives lib (core). +# Only available for CUDA version 5.5+. +# CUDA_nppi_LIBRARY -- NVIDIA Performance Primitives lib (image processing). +# Only available for CUDA version 5.5+. +# CUDA_npps_LIBRARY -- NVIDIA Performance Primitives lib (signal processing). +# Only available for CUDA version 5.5+. +# CUDA_nvcuvenc_LIBRARY -- CUDA Video Encoder library. +# Only available for CUDA version 3.2+. +# Windows only. +# CUDA_nvcuvid_LIBRARY -- CUDA Video Decoder library. +# Only available for CUDA version 3.2+. +# Windows only. +# + +# James Bigler, NVIDIA Corp (nvidia.com - jbigler) +# Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html +# +# Copyright (c) 2008-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +# Copyright (c) 2007-2009 +# Scientific Computing and Imaging Institute, University of Utah +# +# This code is licensed under the MIT License. See the FindCUDA.cmake script +# for the text of the license. + +# The MIT License +# +# SPDX-FileCopyrightText: Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: MIT +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +############################################################################### + +# FindCUDA.cmake + +# This macro helps us find the location of helper files we will need the full path to +macro(CUDA_FIND_HELPER_FILE _name _extension) + set(_full_name "${_name}.${_extension}") + # CMAKE_CURRENT_LIST_FILE contains the full path to the file currently being + # processed. Using this variable, we can pull out the current path, and + # provide a way to get access to the other files we need local to here. + get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) + set(CUDA_${_name} "${CMAKE_CURRENT_LIST_DIR}/FindCUDA/${_full_name}") + if(NOT EXISTS "${CUDA_${_name}}") + set(error_message "${_full_name} not found in ${CMAKE_CURRENT_LIST_DIR}/FindCUDA") + if(CUDA_FIND_REQUIRED) + message(FATAL_ERROR "${error_message}") + else() + if(NOT CUDA_FIND_QUIETLY) + message(STATUS "${error_message}") + endif() + endif() + endif() + # Set this variable as internal, so the user isn't bugged with it. + set(CUDA_${_name} ${CUDA_${_name}} CACHE INTERNAL "Location of ${_full_name}" FORCE) +endmacro() + +##################################################################### +## CUDA_INCLUDE_NVCC_DEPENDENCIES +## + +# So we want to try and include the dependency file if it exists. If +# it doesn't exist then we need to create an empty one, so we can +# include it. + +# If it does exist, then we need to check to see if all the files it +# depends on exist. If they don't then we should clear the dependency +# file and regenerate it later. This covers the case where a header +# file has disappeared or moved. + +macro(CUDA_INCLUDE_NVCC_DEPENDENCIES dependency_file) + set(CUDA_NVCC_DEPEND) + set(CUDA_NVCC_DEPEND_REGENERATE FALSE) + + + # Include the dependency file. Create it first if it doesn't exist . The + # INCLUDE puts a dependency that will force CMake to rerun and bring in the + # new info when it changes. DO NOT REMOVE THIS (as I did and spent a few + # hours figuring out why it didn't work. + if(NOT EXISTS ${dependency_file}) + file(WRITE ${dependency_file} "#FindCUDA.cmake generated file. Do not edit.\n") + endif() + # Always include this file to force CMake to run again next + # invocation and rebuild the dependencies. + #message("including dependency_file = ${dependency_file}") + include(${dependency_file}) + + # Now we need to verify the existence of all the included files + # here. If they aren't there we need to just blank this variable and + # make the file regenerate again. +# if(DEFINED CUDA_NVCC_DEPEND) +# message("CUDA_NVCC_DEPEND set") +# else() +# message("CUDA_NVCC_DEPEND NOT set") +# endif() + if(CUDA_NVCC_DEPEND) + #message("CUDA_NVCC_DEPEND found") + foreach(f ${CUDA_NVCC_DEPEND}) + # message("searching for ${f}") + if(NOT EXISTS ${f}) + #message("file ${f} not found") + set(CUDA_NVCC_DEPEND_REGENERATE TRUE) + endif() + endforeach() + else() + #message("CUDA_NVCC_DEPEND false") + # No dependencies, so regenerate the file. + set(CUDA_NVCC_DEPEND_REGENERATE TRUE) + endif() + + #message("CUDA_NVCC_DEPEND_REGENERATE = ${CUDA_NVCC_DEPEND_REGENERATE}") + # No incoming dependencies, so we need to generate them. Make the + # output depend on the dependency file itself, which should cause the + # rule to re-run. + if(CUDA_NVCC_DEPEND_REGENERATE) + set(CUDA_NVCC_DEPEND ${dependency_file}) + #message("Generating an empty dependency_file: ${dependency_file}") + file(WRITE ${dependency_file} "#FindCUDA.cmake generated file. Do not edit.\n") + endif() + +endmacro() + +############################################################################### +############################################################################### +# Setup variables' defaults +############################################################################### +############################################################################### + +# Allow the user to specify if the device code is supposed to be 32 or 64 bit. +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(CUDA_64_BIT_DEVICE_CODE_DEFAULT ON) +else() + set(CUDA_64_BIT_DEVICE_CODE_DEFAULT OFF) +endif() +option(CUDA_64_BIT_DEVICE_CODE "Compile device code in 64 bit mode" ${CUDA_64_BIT_DEVICE_CODE_DEFAULT}) + +# Attach the build rule to the source file in VS. This option +option(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE "Attach the build rule to the CUDA source file. Enable only when the CUDA source file is added to at most one target." ON) + +# Prints out extra information about the cuda file during compilation +option(CUDA_BUILD_CUBIN "Generate and parse .cubin files in Device mode." OFF) + +# Set whether we are using emulation or device mode. +option(CUDA_BUILD_EMULATION "Build in Emulation mode" OFF) + +# Enable batch builds +option(CUDA_ENABLE_BATCHING "Compile CUDA source files in parallel" OFF) +if(CUDA_ENABLE_BATCHING) + find_package(PythonInterp) + if(NOT PYTHONINTERP_FOUND) + message(SEND_ERROR "CUDA_ENABLE_BATCHING is enabled, but python wasn't found. Disabling") + set(CUDA_ENABLE_BATCHING OFF CACHE BOOL "Compile CUDA source files in parallel" FORCE) + endif() +endif() + +# Where to put the generated output. +set(CUDA_GENERATED_OUTPUT_DIR "" CACHE PATH "Directory to put all the output files. If blank it will default to the CMAKE_CURRENT_BINARY_DIR") + +if(CMAKE_GENERATOR MATCHES "Visual Studio") + set(_cuda_dependencies_default ON) +else() + set(_cuda_dependencies_default OFF) +endif() + +option(CUDA_GENERATE_DEPENDENCIES_DURING_CONFIGURE "Generate dependencies during configure time instead of only during build time." ${_cuda_dependencies_default}) + +option(CUDA_CHECK_DEPENDENCIES_DURING_COMPILE "Checks the dependencies during compilation and suppresses generation if the dependencies have been met." ${_cuda_dependencies_default}) + +# Parse HOST_COMPILATION mode. +option(CUDA_HOST_COMPILATION_CPP "Generated file extension" ON) + +# Extra user settable flags +set(CUDA_NVCC_FLAGS "" CACHE STRING "Semi-colon delimit multiple arguments.") + +if(CMAKE_GENERATOR MATCHES "Visual Studio") + set(_CUDA_MSVC_HOST_COMPILER "$(VCInstallDir)Tools/MSVC/$(VCToolsVersion)/bin/Host$(PreferredToolArchitecture)/$(PlatformTarget)") + if(MSVC_VERSION LESS 1910) + set(_CUDA_MSVC_HOST_COMPILER "$(VCInstallDir)bin") + endif() + + set(CUDA_HOST_COMPILER "${_CUDA_MSVC_HOST_COMPILER}" CACHE FILEPATH "Host side compiler used by NVCC") +else() + if(APPLE + AND "${CMAKE_C_COMPILER_ID}" MATCHES "Clang" + AND "${CMAKE_C_COMPILER}" MATCHES "/cc$") + # Using cc which is symlink to clang may let NVCC think it is GCC and issue + # unhandled -dumpspecs option to clang. Also in case neither + # CMAKE_C_COMPILER is defined (project does not use C language) nor + # CUDA_HOST_COMPILER is specified manually we should skip -ccbin and let + # nvcc use its own default C compiler. + # Only care about this on APPLE with clang to avoid + # following symlinks to things like ccache + if(DEFINED CMAKE_C_COMPILER AND NOT DEFINED CUDA_HOST_COMPILER) + get_filename_component(c_compiler_realpath "${CMAKE_C_COMPILER}" REALPATH) + # if the real path does not end up being clang then + # go back to using CMAKE_C_COMPILER + if(NOT "${c_compiler_realpath}" MATCHES "/clang$") + set(c_compiler_realpath "${CMAKE_C_COMPILER}") + endif() + else() + set(c_compiler_realpath "") + endif() + set(CUDA_HOST_COMPILER "${c_compiler_realpath}" CACHE FILEPATH "Host side compiler used by NVCC") + else() + set(CUDA_HOST_COMPILER "${CMAKE_C_COMPILER}" + CACHE FILEPATH "Host side compiler used by NVCC") + endif() +endif() + +# Set up CUDA_VC_VARS_ALL_BAT if it hasn't been specified. +# set CUDA_VC_VARS_ALL_BAT explicitly to avoid any attempts to locate it via this algorithm. +if(MSVC AND NOT CUDA_VC_VARS_ALL_BAT AND CUDA_ENABLE_BATCHING) + get_filename_component(_cuda_dependency_ccbin_dir "${CMAKE_CXX_COMPILER}" DIRECTORY) + #message(STATUS "_cuda_dependency_ccbin_dir = ${_cuda_dependency_ccbin_dir}") + # In VS 6-12 (1200-1800) the versions were 6 off. Starting in VS 14 (1900) it's only 5. + if(MSVC_VERSION VERSION_LESS 1900) + math(EXPR vs_major_version "${MSVC_VERSION} / 100 - 6") + find_file( CUDA_VC_VARS_ALL_BAT vcvarsall.bat PATHS "${_cuda_dependency_ccbin_dir}/../.." NO_DEFAULT_PATH ) + elseif(MSVC_VERSION VERSION_EQUAL 1900) + # Visual Studio 2015 + set(vs_major_version "15") + find_file( CUDA_VC_VARS_ALL_BAT vcvarsall.bat PATHS "${_cuda_dependency_ccbin_dir}/../.." NO_DEFAULT_PATH ) + elseif(MSVC_VERSION VERSION_LESS 1920) + # Visual Studio 2017 + set(vs_major_version "15") + find_file( CUDA_VC_VARS_ALL_BAT vcvarsall.bat PATHS "${_cuda_dependency_ccbin_dir}/../../../../../../Auxiliary/Build" NO_DEFAULT_PATH ) + else() + # Visual Studio 2019 + set(vs_major_version "16") + find_file( CUDA_VC_VARS_ALL_BAT vcvarsall.bat PATHS "${_cuda_dependency_ccbin_dir}/../../../../../../Auxiliary/Build" NO_DEFAULT_PATH ) + endif() + if( NOT CUDA_VC_VARS_ALL_BAT ) + # See if we can get VS install location from the registry. Registry searches can only + # be accomplished via a CACHE variable, unfortunately. + get_filename_component(_cuda_vs_dir_tmp "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\${vs_major_version}.0\\Setup\\VS;ProductDir]" REALPATH CACHE) + if( _cuda_vs_dir_tmp ) + set( CUDA_VS_DIR ${_cuda_vs_dir_tmp} ) + unset( _cuda_vs_dir_tmp CACHE ) + endif() + find_file( CUDA_VC_VARS_ALL_BAT vcvarsall.bat PATHS ${CUDA_VS_DIR}/VC/bin ${CUDA_VS_DIR}/VC/Auxiliary/Build NO_DEFAULT_PATH ) + endif() + if( NOT CUDA_VC_VARS_ALL_BAT ) + message(FATAL_ERROR "Cannot find path to vcvarsall.bat. Looked in ${CUDA_VS_DIR}/VC/bin ${CUDA_VS_DIR}/VC/Auxiliary/Build") + endif() + #message("CUDA_VS_DIR = ${CUDA_VS_DIR}, CUDA_VC_VARS_ALL_BAT = ${CUDA_VC_VARS_ALL_BAT}") +endif() + +# Propagate the host flags to the host compiler via -Xcompiler +option(CUDA_PROPAGATE_HOST_FLAGS "Propage C/CXX_FLAGS and friends to the host compiler via -Xcompiler" ON) + +# Enable CUDA_SEPARABLE_COMPILATION +option(CUDA_SEPARABLE_COMPILATION "Compile CUDA objects with separable compilation enabled. Requires CUDA 5.0+" OFF) + +# Specifies whether the commands used when compiling the .cu file will be printed out. +option(CUDA_VERBOSE_BUILD "Print out the commands run while compiling the CUDA source file. With the Makefile generator this defaults to VERBOSE variable specified on the command line, but can be forced on with this option." OFF) + +mark_as_advanced( + CUDA_64_BIT_DEVICE_CODE + CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE + CUDA_GENERATED_OUTPUT_DIR + CUDA_HOST_COMPILATION_CPP + CUDA_NVCC_FLAGS + CUDA_PROPAGATE_HOST_FLAGS + CUDA_BUILD_CUBIN + CUDA_BUILD_EMULATION + CUDA_VERBOSE_BUILD + CUDA_SEPARABLE_COMPILATION + ) + +# Makefile and similar generators don't define CMAKE_CONFIGURATION_TYPES, so we +# need to add another entry for the CMAKE_BUILD_TYPE. We also need to add the +# standard set of 4 build types (Debug, MinSizeRel, Release, and RelWithDebInfo) +# for completeness. We need run this loop in order to accomodate the addition +# of extra configuration types. Duplicate entries will be removed by +# REMOVE_DUPLICATES. +set(CUDA_configuration_types ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE} Debug MinSizeRel Release RelWithDebInfo) +list(REMOVE_DUPLICATES CUDA_configuration_types) +foreach(config ${CUDA_configuration_types}) + string(TOUPPER ${config} config_upper) + set(CUDA_NVCC_FLAGS_${config_upper} "" CACHE STRING "Semi-colon delimit multiple arguments.") + mark_as_advanced(CUDA_NVCC_FLAGS_${config_upper}) +endforeach() + +############################################################################### +############################################################################### +# Locate CUDA, Set Build Type, etc. +############################################################################### +############################################################################### + +macro(cuda_unset_include_and_libraries) + unset(CUDA_TOOLKIT_INCLUDE CACHE) + unset(CUDA_CUDART_LIBRARY CACHE) + unset(CUDA_CUDA_LIBRARY CACHE) + # Make sure you run this before you unset CUDA_VERSION. + if(CUDA_VERSION VERSION_EQUAL "3.0") + # This only existed in the 3.0 version of the CUDA toolkit + unset(CUDA_CUDARTEMU_LIBRARY CACHE) + endif() + if( DEFINED CUDA_NVASM_EXECUTABLE ) + unset(CUDA_NVASM_EXECUTABLE) + endif() + if( DEFINED CUDA_FATBINARY_EXECUTABLE ) + unset(CUDA_FATBINARY_EXECUTABLE) + endif() + unset(CUDA_cudart_static_LIBRARY CACHE) + unset(CUDA_cudadevrt_LIBRARY CACHE) + unset(CUDA_cublas_LIBRARY CACHE) + unset(CUDA_cublas_device_LIBRARY CACHE) + unset(CUDA_cublasemu_LIBRARY CACHE) + unset(CUDA_cufft_LIBRARY CACHE) + unset(CUDA_cufftemu_LIBRARY CACHE) + unset(CUDA_cupti_LIBRARY CACHE) + unset(CUDA_curand_LIBRARY CACHE) + unset(CUDA_cusolver_LIBRARY CACHE) + unset(CUDA_cusparse_LIBRARY CACHE) + unset(CUDA_npp_LIBRARY CACHE) + unset(CUDA_nppc_LIBRARY CACHE) + unset(CUDA_nppi_LIBRARY CACHE) + unset(CUDA_npps_LIBRARY CACHE) + unset(CUDA_nvcuvenc_LIBRARY CACHE) + unset(CUDA_nvcuvid_LIBRARY CACHE) + unset(CUDA_nvrtc_LIBRARY CACHE) + unset(CUDA_USE_STATIC_CUDA_RUNTIME CACHE) + unset(CUDA_GPU_DETECT_OUTPUT CACHE) +endmacro() + +# Check to see if the CUDA_TOOLKIT_ROOT_DIR and CUDA_SDK_ROOT_DIR have changed, +# if they have then clear the cache variables, so that will be detected again. +if(NOT "${CUDA_TOOLKIT_ROOT_DIR}" STREQUAL "${CUDA_TOOLKIT_ROOT_DIR_INTERNAL}") + unset(CUDA_TOOLKIT_TARGET_DIR CACHE) + unset(CUDA_NVCC_EXECUTABLE CACHE) + cuda_unset_include_and_libraries() + unset(CUDA_VERSION CACHE) +endif() + +# CUDA_TOOLKIT_TARGET_DIR doesn't always exist in the cache, so in this case we need to +# only check equality if CUDA_TOOLKIT_TARGET_DIR is defined. +if(DEFINED CUDA_TOOLKIT_TARGET_DIR) + if(NOT "${CUDA_TOOLKIT_TARGET_DIR}" STREQUAL "${CUDA_TOOLKIT_TARGET_DIR_INTERNAL}") + cuda_unset_include_and_libraries() + endif() +endif() + +# +# End of unset() +# + +# +# Start looking for things +# + +# Search for the cuda distribution. +if(NOT CUDA_TOOLKIT_ROOT_DIR AND NOT CMAKE_CROSSCOMPILING) + # Search in the CUDA_BIN_PATH first. + find_path(CUDA_TOOLKIT_ROOT_DIR + NAMES nvcc nvcc.exe + PATHS + ENV CUDA_TOOLKIT_ROOT + ENV CUDA_PATH + ENV CUDA_BIN_PATH + PATH_SUFFIXES bin bin64 + DOC "Toolkit location." + NO_DEFAULT_PATH + ) + + # Now search default paths + find_path(CUDA_TOOLKIT_ROOT_DIR + NAMES nvcc nvcc.exe + PATHS /opt/cuda/bin + /usr/local/bin + /usr/local/cuda/bin + DOC "Toolkit location." + ) + + if (CUDA_TOOLKIT_ROOT_DIR) + string(REGEX REPLACE "[/\\\\]?bin[64]*[/\\\\]?$" "" CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT_DIR}) + # We need to force this back into the cache. + set(CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT_DIR} CACHE PATH "Toolkit location." FORCE) + set(CUDA_TOOLKIT_TARGET_DIR ${CUDA_TOOLKIT_ROOT_DIR}) + endif() + + if (NOT EXISTS ${CUDA_TOOLKIT_ROOT_DIR}) + if(CUDA_FIND_REQUIRED) + message(FATAL_ERROR "Specify CUDA_TOOLKIT_ROOT_DIR") + elseif(NOT CUDA_FIND_QUIETLY) + message("CUDA_TOOLKIT_ROOT_DIR not found or specified") + endif() + endif () +endif () + +if(CMAKE_CROSSCOMPILING) + SET (CUDA_TOOLKIT_ROOT $ENV{CUDA_TOOLKIT_ROOT}) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7-a") + # Support for NVPACK + set (CUDA_TOOLKIT_TARGET_NAME "armv7-linux-androideabi") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm") + # Support for arm cross compilation + set(CUDA_TOOLKIT_TARGET_NAME "armv7-linux-gnueabihf") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") + # Support for aarch64 cross compilation + if (ANDROID_ARCH_NAME STREQUAL "arm64") + set(CUDA_TOOLKIT_TARGET_NAME "aarch64-linux-androideabi") + else() + set(CUDA_TOOLKIT_TARGET_NAME "aarch64-linux") + endif (ANDROID_ARCH_NAME STREQUAL "arm64") + endif() + + if (EXISTS "${CUDA_TOOLKIT_ROOT}/targets/${CUDA_TOOLKIT_TARGET_NAME}") + set(CUDA_TOOLKIT_TARGET_DIR "${CUDA_TOOLKIT_ROOT}/targets/${CUDA_TOOLKIT_TARGET_NAME}" CACHE PATH "CUDA Toolkit target location.") + SET (CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT}) + mark_as_advanced(CUDA_TOOLKIT_TARGET_DIR) + endif() + + # add known CUDA targetr root path to the set of directories we search for programs, libraries and headers + set( CMAKE_FIND_ROOT_PATH "${CUDA_TOOLKIT_TARGET_DIR};${CMAKE_FIND_ROOT_PATH}") + macro( cuda_find_host_program ) + find_host_program( ${ARGN} ) + endmacro() +else() + # for non-cross-compile, find_host_program == find_program and CUDA_TOOLKIT_TARGET_DIR == CUDA_TOOLKIT_ROOT_DIR + macro( cuda_find_host_program ) + find_program( ${ARGN} ) + endmacro() + SET (CUDA_TOOLKIT_TARGET_DIR ${CUDA_TOOLKIT_ROOT_DIR}) +endif() + + +# CUDA_NVCC_EXECUTABLE +cuda_find_host_program(CUDA_NVCC_EXECUTABLE + NAMES nvcc + PATHS "${CUDA_TOOLKIT_ROOT_DIR}" + ENV CUDA_PATH + ENV CUDA_BIN_PATH + PATH_SUFFIXES bin bin64 + NO_DEFAULT_PATH + ) +# Search default search paths, after we search our own set of paths. +cuda_find_host_program(CUDA_NVCC_EXECUTABLE nvcc) +mark_as_advanced(CUDA_NVCC_EXECUTABLE) + +# CUDA_NVASM_EXECUTABLE +cuda_find_host_program(CUDA_NVASM_EXECUTABLE + NAMES nvasm_internal + PATHS "${CUDA_TOOLKIT_ROOT_DIR}" + ENV CUDA_PATH + ENV CUDA_BIN_PATH + PATH_SUFFIXES bin bin64 + NO_DEFAULT_PATH + ) +# Search default search paths, after we search our own set of paths. +cuda_find_host_program(CUDA_NVASM_EXECUTABLE nvasm_internal) +mark_as_advanced(CUDA_NVASM_EXECUTABLE) + + +# Find fatbinary from CUDA +cuda_find_host_program(CUDA_FATBINARY_EXECUTABLE + NAMES fatbinary + PATHS "${CUDA_TOOLKIT_ROOT_DIR}" + ENV CUDA_PATH + ENV CUDA_BIN_PATH + PATH_SUFFIXES bin bin64 + NO_DEFAULT_PATH + ) +# Search default search paths, after we search our own set of paths. +cuda_find_host_program(CUDA_FATBINARY_EXECUTABLE fatbinary) +mark_as_advanced(CUDA_FATBINARY_EXECUTABLE) + + +if(CUDA_NVCC_EXECUTABLE AND NOT CUDA_VERSION) + # Compute the version. + execute_process (COMMAND ${CUDA_NVCC_EXECUTABLE} "--version" OUTPUT_VARIABLE NVCC_OUT) + string(REGEX REPLACE ".*release ([0-9]+)\\.([0-9]+).*" "\\1" CUDA_VERSION_MAJOR ${NVCC_OUT}) + string(REGEX REPLACE ".*release ([0-9]+)\\.([0-9]+).*" "\\2" CUDA_VERSION_MINOR ${NVCC_OUT}) + set(CUDA_VERSION "${CUDA_VERSION_MAJOR}.${CUDA_VERSION_MINOR}" CACHE STRING "Version of CUDA as computed from nvcc.") + mark_as_advanced(CUDA_VERSION) +else() + # Need to set these based off of the cached value + string(REGEX REPLACE "([0-9]+)\\.([0-9]+).*" "\\1" CUDA_VERSION_MAJOR "${CUDA_VERSION}") + string(REGEX REPLACE "([0-9]+)\\.([0-9]+).*" "\\2" CUDA_VERSION_MINOR "${CUDA_VERSION}") +endif() + +# Always set this convenience variable +set(CUDA_VERSION_STRING "${CUDA_VERSION}") + +# Here we need to determine if the version we found is acceptable. We will +# assume that is unless CUDA_FIND_VERSION_EXACT or CUDA_FIND_VERSION is +# specified. The presence of either of these options checks the version +# string and signals if the version is acceptable or not. +set(_cuda_version_acceptable TRUE) +# +if(CUDA_FIND_VERSION_EXACT AND NOT CUDA_VERSION VERSION_EQUAL CUDA_FIND_VERSION) + set(_cuda_version_acceptable FALSE) +endif() +# +if(CUDA_FIND_VERSION AND CUDA_VERSION VERSION_LESS CUDA_FIND_VERSION) + set(_cuda_version_acceptable FALSE) +endif() +# +if(NOT _cuda_version_acceptable) + set(_cuda_error_message "Requested CUDA version ${CUDA_FIND_VERSION}, but found unacceptable version ${CUDA_VERSION}") + if(CUDA_FIND_REQUIRED) + message("${_cuda_error_message}") + elseif(NOT CUDA_FIND_QUIETLY) + message("${_cuda_error_message}") + endif() +endif() + +# CUDA_TOOLKIT_INCLUDE +find_path(CUDA_TOOLKIT_INCLUDE + device_functions.h # Header included in toolkit + PATHS ${CUDA_TOOLKIT_TARGET_DIR} + ENV CUDA_PATH + ENV CUDA_INC_PATH + PATH_SUFFIXES include + NO_DEFAULT_PATH + ) +# Search default search paths, after we search our own set of paths. +find_path(CUDA_TOOLKIT_INCLUDE device_functions.h) +mark_as_advanced(CUDA_TOOLKIT_INCLUDE) + +if (CUDA_VERSION VERSION_GREATER "7.0" OR EXISTS "${CUDA_TOOLKIT_INCLUDE}/cuda_fp16.h") + set(CUDA_HAS_FP16 TRUE) +else() + set(CUDA_HAS_FP16 FALSE) +endif() + +# Set the user list of include dir to nothing to initialize it. +set (CUDA_NVCC_INCLUDE_ARGS_USER "") +set (CUDA_INCLUDE_DIRS ${CUDA_TOOLKIT_INCLUDE}) + +macro(cuda_find_library_local_first_with_path_ext _var _names _doc _path_ext ) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + # CUDA 3.2+ on Windows moved the library directories, so we need the new + # and old paths. + set(_cuda_64bit_lib_dir "${_path_ext}lib/x64" "${_path_ext}lib64" "${_path_ext}libx64" ) + endif() + # CUDA 3.2+ on Windows moved the library directories, so we need to new + # (lib/Win32) and the old path (lib). + find_library(${_var} + NAMES ${_names} + PATHS "${CUDA_TOOLKIT_TARGET_DIR}" + ENV CUDA_PATH + ENV CUDA_LIB_PATH + PATH_SUFFIXES ${_cuda_64bit_lib_dir} "${_path_ext}lib/Win32" "${_path_ext}lib" "${_path_ext}libWin32" + DOC ${_doc} + NO_DEFAULT_PATH + ) + if (NOT CMAKE_CROSSCOMPILING) + # Search default search paths, after we search our own set of paths. + find_library(${_var} + NAMES ${_names} + PATHS "/usr/lib/nvidia-current" + DOC ${_doc} + ) + endif() +endmacro() + +macro(cuda_find_library_local_first _var _names _doc) + cuda_find_library_local_first_with_path_ext( "${_var}" "${_names}" "${_doc}" "" ) +endmacro() + +macro(find_library_local_first _var _names _doc ) + cuda_find_library_local_first( "${_var}" "${_names}" "${_doc}" "" ) +endmacro() + + +# CUDA_LIBRARIES +cuda_find_library_local_first(CUDA_CUDART_LIBRARY cudart "\"cudart\" library") +if(CUDA_VERSION VERSION_EQUAL "3.0") + # The cudartemu library only existed for the 3.0 version of CUDA. + cuda_find_library_local_first(CUDA_CUDARTEMU_LIBRARY cudartemu "\"cudartemu\" library") + mark_as_advanced( + CUDA_CUDARTEMU_LIBRARY + ) +endif() + +if(NOT CUDA_VERSION VERSION_LESS "5.5") + cuda_find_library_local_first(CUDA_cudart_static_LIBRARY cudart_static "static CUDA runtime library") + mark_as_advanced(CUDA_cudart_static_LIBRARY) +endif() + + +if(CUDA_cudart_static_LIBRARY) + # If static cudart available, use it by default, but provide a user-visible option to disable it. + option(CUDA_USE_STATIC_CUDA_RUNTIME "Use the static version of the CUDA runtime library if available" ON) + set(CUDA_CUDART_LIBRARY_VAR CUDA_cudart_static_LIBRARY) +else() + # If not available, silently disable the option. + set(CUDA_USE_STATIC_CUDA_RUNTIME OFF CACHE INTERNAL "") + set(CUDA_CUDART_LIBRARY_VAR CUDA_CUDART_LIBRARY) +endif() + +if(NOT CUDA_VERSION VERSION_LESS "5.0") + cuda_find_library_local_first(CUDA_cudadevrt_LIBRARY cudadevrt "\"cudadevrt\" library") + mark_as_advanced(CUDA_cudadevrt_LIBRARY) +endif() + +if(CUDA_USE_STATIC_CUDA_RUNTIME) + if(UNIX) + # Check for the dependent libraries. Here we look for pthreads. + if (DEFINED CMAKE_THREAD_PREFER_PTHREAD) + set(_cuda_cmake_thread_prefer_pthread ${CMAKE_THREAD_PREFER_PTHREAD}) + endif() + set(CMAKE_THREAD_PREFER_PTHREAD 1) + + # Many of the FindXYZ CMake comes with makes use of try_compile with int main(){return 0;} + # as the source file. Unfortunately this causes a warning with -Wstrict-prototypes and + # -Werror causes the try_compile to fail. We will just temporarily disable other flags + # when doing the find_package command here. + set(_cuda_cmake_c_flags ${CMAKE_C_FLAGS}) + set(CMAKE_C_FLAGS "-fPIC") + find_package(Threads REQUIRED) + set(CMAKE_C_FLAGS ${_cuda_cmake_c_flags}) + + if (DEFINED _cuda_cmake_thread_prefer_pthread) + set(CMAKE_THREAD_PREFER_PTHREAD ${_cuda_cmake_thread_prefer_pthread}) + unset(_cuda_cmake_thread_prefer_pthread) + else() + unset(CMAKE_THREAD_PREFER_PTHREAD) + endif() + if (NOT APPLE) + #On Linux, you must link against librt when using the static cuda runtime. + find_library(CUDA_rt_LIBRARY rt) + # CMake has a CMAKE_DL_LIBS, but I'm not sure what version of CMake provides this + find_library(CUDA_dl_LIBRARY dl) + if (NOT CUDA_rt_LIBRARY) + message(WARNING "Expecting to find librt for libcudart_static, but didn't find it.") + endif() + if (NOT CUDA_dl_LIBRARY) + message(WARNING "Expecting to find libdl for libcudart_static, but didn't find it.") + endif() + endif() + endif() +endif() + +# CUPTI library showed up in cuda toolkit 4.0 +if(NOT CUDA_VERSION VERSION_LESS "4.0") + cuda_find_library_local_first_with_path_ext(CUDA_cupti_LIBRARY cupti "\"cupti\" library" "extras/CUPTI/") + mark_as_advanced(CUDA_cupti_LIBRARY) +endif() + +# Set the CUDA_LIBRARIES variable. This is the set of stuff to link against if you are +# using the CUDA runtime. For the dynamic version of the runtime, most of the +# dependencies are brough in, but for the static version there are additional libraries +# and linker commands needed. +# Initialize to empty +set(CUDA_LIBRARIES) + +if(APPLE) + # We need to add the path to cudart to the linker using rpath, since the library name + # for the cuda libraries is prepended with @rpath. We need to add the path to the + # toolkit before we add the path to the driver below, so that we find our toolkit's code + # first. + if(CUDA_BUILD_EMULATION AND CUDA_CUDARTEMU_LIBRARY) + get_filename_component(_cuda_path_to_cudart "${CUDA_CUDARTEMU_LIBRARY}" PATH) + else() + get_filename_component(_cuda_path_to_cudart "${CUDA_CUDART_LIBRARY}" PATH) + endif() + if(_cuda_path_to_cudart) + list(APPEND CUDA_LIBRARIES -Wl,-rpath "-Wl,${_cuda_path_to_cudart}") + endif() +endif() + +# If we are using emulation mode and we found the cudartemu library then use +# that one instead of cudart. +if(CUDA_BUILD_EMULATION AND CUDA_CUDARTEMU_LIBRARY) + list(APPEND CUDA_LIBRARIES ${CUDA_CUDARTEMU_LIBRARY}) +elseif(CUDA_USE_STATIC_CUDA_RUNTIME AND CUDA_cudart_static_LIBRARY) + list(APPEND CUDA_LIBRARIES ${CUDA_cudart_static_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) + if (CUDA_rt_LIBRARY) + list(APPEND CUDA_LIBRARIES ${CUDA_rt_LIBRARY}) + endif() + if (CUDA_dl_LIBRARY) + list(APPEND CUDA_LIBRARIES ${CUDA_dl_LIBRARY}) + endif() + if(APPLE) + # We need to add the default path to the driver (libcuda.dylib) as an rpath, so that + # the static cuda runtime can find it at runtime. + list(APPEND CUDA_LIBRARIES -Wl,-rpath,/usr/local/cuda/lib) + endif() +else() + list(APPEND CUDA_LIBRARIES ${CUDA_CUDART_LIBRARY}) +endif() + +# 1.1 toolkit on linux doesn't appear to have a separate library on +# some platforms. +cuda_find_library_local_first(CUDA_CUDA_LIBRARY cuda "\"cuda\" library (older versions only).") + +mark_as_advanced( + CUDA_CUDA_LIBRARY + CUDA_CUDART_LIBRARY + ) + +####################### +# Look for some of the toolkit helper libraries +macro(FIND_CUDA_HELPER_LIBS _name) + cuda_find_library_local_first(CUDA_${_name}_LIBRARY ${_name} "\"${_name}\" library") + mark_as_advanced(CUDA_${_name}_LIBRARY) +endmacro() + +####################### +# Disable emulation for v3.1 onward +if(CUDA_VERSION VERSION_GREATER "3.0") + if(CUDA_BUILD_EMULATION) + message(FATAL_ERROR "CUDA_BUILD_EMULATION is not supported in version 3.1 and onwards. You must disable it to proceed. You have version ${CUDA_VERSION}.") + endif() +endif() + +# Search for additional CUDA toolkit libraries. +if(CUDA_VERSION VERSION_LESS "3.1") + # Emulation libraries aren't available in version 3.1 onward. + find_cuda_helper_libs(cufftemu) + find_cuda_helper_libs(cublasemu) +endif() +find_cuda_helper_libs(cufft) +find_cuda_helper_libs(cublas) +if(NOT CUDA_VERSION VERSION_LESS "3.2") + # cusparse showed up in version 3.2 + find_cuda_helper_libs(cusparse) + find_cuda_helper_libs(curand) + if (WIN32) + find_cuda_helper_libs(nvcuvenc) + find_cuda_helper_libs(nvcuvid) + endif() +endif() +if(CUDA_VERSION VERSION_GREATER "5.0") + find_cuda_helper_libs(cublas_device) + # In CUDA 5.5 NPP was splitted onto 3 separate libraries. + find_cuda_helper_libs(nppc) + find_cuda_helper_libs(nppi) + find_cuda_helper_libs(npps) + set(CUDA_npp_LIBRARY "${CUDA_nppc_LIBRARY};${CUDA_nppi_LIBRARY};${CUDA_npps_LIBRARY}") +elseif(NOT CUDA_VERSION VERSION_LESS "4.0") + find_cuda_helper_libs(npp) +endif() +if(NOT CUDA_VERSION VERSION_LESS "7.0") + # cusolver showed up in version 7.0 + find_cuda_helper_libs(cusolver) +endif() +if(NOT CUDA_VERSION VERSION_LESS "7.5") + find_cuda_helper_libs(nvrtc) +endif() + +if (CUDA_BUILD_EMULATION) + set(CUDA_CUFFT_LIBRARIES ${CUDA_cufftemu_LIBRARY}) + set(CUDA_CUBLAS_LIBRARIES ${CUDA_cublasemu_LIBRARY}) +else() + set(CUDA_CUFFT_LIBRARIES ${CUDA_cufft_LIBRARY}) + set(CUDA_CUBLAS_LIBRARIES ${CUDA_cublas_LIBRARY} ${CUDA_cublas_device_LIBRARY}) +endif() + +######################## +# Look for the SDK stuff. As of CUDA 3.0 NVSDKCUDA_ROOT has been replaced with +# NVSDKCOMPUTE_ROOT with the old CUDA C contents moved into the C subdirectory +find_path(CUDA_SDK_ROOT_DIR common/inc/cutil.h + HINTS + "$ENV{NVSDKCOMPUTE_ROOT}/C" + ENV NVSDKCUDA_ROOT + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\NVIDIA Corporation\\Installed Products\\NVIDIA SDK 10\\Compute;InstallDir]" + PATHS + "/Developer/GPU\ Computing/C" + ) + +# Keep the CUDA_SDK_ROOT_DIR first in order to be able to override the +# environment variables. +set(CUDA_SDK_SEARCH_PATH + "${CUDA_SDK_ROOT_DIR}" + "${CUDA_TOOLKIT_ROOT_DIR}/local/NVSDK0.2" + "${CUDA_TOOLKIT_ROOT_DIR}/NVSDK0.2" + "${CUDA_TOOLKIT_ROOT_DIR}/NV_CUDA_SDK" + "$ENV{HOME}/NVIDIA_CUDA_SDK" + "$ENV{HOME}/NVIDIA_CUDA_SDK_MACOSX" + "/Developer/CUDA" + ) + +# Example of how to find an include file from the CUDA_SDK_ROOT_DIR + +# find_path(CUDA_CUT_INCLUDE_DIR +# cutil.h +# PATHS ${CUDA_SDK_SEARCH_PATH} +# PATH_SUFFIXES "common/inc" +# DOC "Location of cutil.h" +# NO_DEFAULT_PATH +# ) +# # Now search system paths +# find_path(CUDA_CUT_INCLUDE_DIR cutil.h DOC "Location of cutil.h") + +# mark_as_advanced(CUDA_CUT_INCLUDE_DIR) + + +# Example of how to find a library in the CUDA_SDK_ROOT_DIR + +# # cutil library is called cutil64 for 64 bit builds on windows. We don't want +# # to get these confused, so we are setting the name based on the word size of +# # the build. + +# if(CMAKE_SIZEOF_VOID_P EQUAL 8) +# set(cuda_cutil_name cutil64) +# else() +# set(cuda_cutil_name cutil32) +# endif() + +# find_library(CUDA_CUT_LIBRARY +# NAMES cutil ${cuda_cutil_name} +# PATHS ${CUDA_SDK_SEARCH_PATH} +# # The new version of the sdk shows up in common/lib, but the old one is in lib +# PATH_SUFFIXES "common/lib" "lib" +# DOC "Location of cutil library" +# NO_DEFAULT_PATH +# ) +# # Now search system paths +# find_library(CUDA_CUT_LIBRARY NAMES cutil ${cuda_cutil_name} DOC "Location of cutil library") +# mark_as_advanced(CUDA_CUT_LIBRARY) +# set(CUDA_CUT_LIBRARIES ${CUDA_CUT_LIBRARY}) + + + +############################# +# Check for required components +set(CUDA_FOUND TRUE) + +set(CUDA_TOOLKIT_ROOT_DIR_INTERNAL "${CUDA_TOOLKIT_ROOT_DIR}" CACHE INTERNAL + "This is the value of the last time CUDA_TOOLKIT_ROOT_DIR was set successfully." FORCE) +set(CUDA_TOOLKIT_TARGET_DIR_INTERNAL "${CUDA_TOOLKIT_TARGET_DIR}" CACHE INTERNAL + "This is the value of the last time CUDA_TOOLKIT_TARGET_DIR was set successfully." FORCE) +set(CUDA_SDK_ROOT_DIR_INTERNAL "${CUDA_SDK_ROOT_DIR}" CACHE INTERNAL + "This is the value of the last time CUDA_SDK_ROOT_DIR was set successfully." FORCE) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CUDA + REQUIRED_VARS + CUDA_TOOLKIT_ROOT_DIR + CUDA_NVCC_EXECUTABLE + CUDA_INCLUDE_DIRS + ${CUDA_CUDART_LIBRARY_VAR} + VERSION_VAR + CUDA_VERSION + ) + + + +############################################################################### +############################################################################### +# Macros +############################################################################### +############################################################################### + +############################################################################### +# Add include directories to pass to the nvcc command. +macro(CUDA_INCLUDE_DIRECTORIES) + foreach(dir ${ARGN}) + list(APPEND CUDA_NVCC_INCLUDE_ARGS_USER -I${dir}) + endforeach() +endmacro() + + +############################################################################## +cuda_find_helper_file(parse_cubin cmake) +cuda_find_helper_file(make2cmake cmake) +cuda_find_helper_file(run_nvcc cmake) +include("${CMAKE_CURRENT_LIST_DIR}/FindCUDA/select_compute_arch.cmake") + +############################################################################## +# Separate the OPTIONS out from the sources +# +macro(CUDA_GET_SOURCES_AND_OPTIONS _sources _cmake_options _options) + set( ${_sources} ) + set( ${_cmake_options} ) + set( ${_options} ) + set( _found_options FALSE ) + foreach(arg ${ARGN}) + if("x${arg}" STREQUAL "xOPTIONS") + set( _found_options TRUE ) + elseif( + "x${arg}" STREQUAL "xWIN32" OR + "x${arg}" STREQUAL "xMACOSX_BUNDLE" OR + "x${arg}" STREQUAL "xEXCLUDE_FROM_ALL" OR + "x${arg}" STREQUAL "xSTATIC" OR + "x${arg}" STREQUAL "xSHARED" OR + "x${arg}" STREQUAL "xMODULE" + ) + list(APPEND ${_cmake_options} ${arg}) + else() + if ( _found_options ) + list(APPEND ${_options} ${arg}) + else() + # Assume this is a file + list(APPEND ${_sources} ${arg}) + endif() + endif() + endforeach() +endmacro() + +############################################################################## +# Parse the OPTIONS from ARGN and set the variables prefixed by _option_prefix +# +macro(CUDA_PARSE_NVCC_OPTIONS _option_prefix) + set( _found_config ) + foreach(arg ${ARGN}) + # Determine if we are dealing with a perconfiguration flag + foreach(config ${CUDA_configuration_types}) + string(TOUPPER ${config} config_upper) + if (arg STREQUAL "${config_upper}") + set( _found_config _${arg}) + # Set arg to nothing to keep it from being processed further + set( arg ) + endif() + endforeach() + + if ( arg ) + list(APPEND ${_option_prefix}${_found_config} "${arg}") + endif() + endforeach() +endmacro() + +############################################################################## +# Helper to add the include directory for CUDA only once +function(CUDA_ADD_CUDA_INCLUDE_ONCE) + get_directory_property(_include_directories INCLUDE_DIRECTORIES) + set(_add TRUE) + if(_include_directories) + foreach(dir ${_include_directories}) + if("${dir}" STREQUAL "${CUDA_INCLUDE_DIRS}") + set(_add FALSE) + endif() + endforeach() + endif() + if(_add) + include_directories(${CUDA_INCLUDE_DIRS}) + endif() +endfunction() + +function(CUDA_BUILD_SHARED_LIBRARY shared_flag) + set(cmake_args ${ARGN}) + # If SHARED, MODULE, or STATIC aren't already in the list of arguments, then + # add SHARED or STATIC based on the value of BUILD_SHARED_LIBS. + list(FIND cmake_args SHARED _cuda_found_SHARED) + list(FIND cmake_args MODULE _cuda_found_MODULE) + list(FIND cmake_args STATIC _cuda_found_STATIC) + if( _cuda_found_SHARED GREATER -1 OR + _cuda_found_MODULE GREATER -1 OR + _cuda_found_STATIC GREATER -1) + set(_cuda_build_shared_libs) + else() + if (BUILD_SHARED_LIBS) + set(_cuda_build_shared_libs SHARED) + else() + set(_cuda_build_shared_libs STATIC) + endif() + endif() + set(${shared_flag} ${_cuda_build_shared_libs} PARENT_SCOPE) +endfunction() + +############################################################################## +# Helper to avoid clashes of files with the same basename but different paths. +# This doesn't attempt to do exactly what CMake internals do, which is to only +# add this path when there is a conflict, since by the time a second collision +# in names is detected it's already too late to fix the first one. For +# consistency sake the relative path will be added to all files. +function(CUDA_COMPUTE_BUILD_PATH path build_path) + #message("CUDA_COMPUTE_BUILD_PATH([${path}] ${build_path})") + # Only deal with CMake style paths from here on out + file(TO_CMAKE_PATH "${path}" bpath) + if (IS_ABSOLUTE "${bpath}") + # Absolute paths are generally unnessary, especially if something like + # file(GLOB_RECURSE) is used to pick up the files. + + string(FIND "${bpath}" "${CMAKE_CURRENT_BINARY_DIR}" _binary_dir_pos) + if (_binary_dir_pos EQUAL 0) + file(RELATIVE_PATH bpath "${CMAKE_CURRENT_BINARY_DIR}" "${bpath}") + else() + file(RELATIVE_PATH bpath "${CMAKE_CURRENT_SOURCE_DIR}" "${bpath}") + endif() + endif() + + # This recipe is from cmLocalGenerator::CreateSafeUniqueObjectFileName in the + # CMake source. + + # Remove leading / + string(REGEX REPLACE "^[/]+" "" bpath "${bpath}") + # Avoid absolute paths by removing ':' + string(REPLACE ":" "_" bpath "${bpath}") + # Avoid relative paths that go up the tree + string(REPLACE "../" "__/" bpath "${bpath}") + # Avoid spaces + string(REPLACE " " "_" bpath "${bpath}") + + # Strip off the filename. I wait until here to do it, since removin the + # basename can make a path that looked like path/../basename turn into + # path/.. (notice the trailing slash). + get_filename_component(bpath "${bpath}" PATH) + + set(${build_path} "${bpath}" PARENT_SCOPE) + #message("${build_path} = ${bpath}") +endfunction() + +############################################################################## +############################################################################## +# CUDA WRAP SRCS +# +# This helper macro populates the following variables and setups up custom +# commands and targets to invoke the nvcc compiler to generate C or PTX source +# dependent upon the format parameter. The compiler is invoked once with -M +# to generate a dependency file and a second time with -cuda or -ptx to generate +# a .cpp or .ptx file. +# INPUT: +# cuda_target - Target name +# format - PTX, CUBIN, FATBIN or OBJ +# FILE1 .. FILEN - The remaining arguments are the sources to be wrapped. +# OPTIONS - Extra options to NVCC +# OUTPUT: +# generated_files - List of generated files +############################################################################## +############################################################################## + +macro(CUDA_WRAP_SRCS cuda_target format generated_files) + + # If CMake doesn't support separable compilation, complain + if(CUDA_SEPARABLE_COMPILATION AND CMAKE_VERSION VERSION_LESS "2.8.10.1") + message(SEND_ERROR "CUDA_SEPARABLE_COMPILATION isn't supported for CMake versions less than 2.8.10.1") + endif() + + # Set up all the command line flags here, so that they can be overridden on a per target basis. + + set(nvcc_flags "") + + # Emulation if the card isn't present. + if (CUDA_BUILD_EMULATION) + # Emulation. + set(nvcc_flags ${nvcc_flags} --device-emulation -D_DEVICEEMU -g) + else() + # Device mode. No flags necessary. + endif() + + if(CUDA_HOST_COMPILATION_CPP) + set(CUDA_C_OR_CXX CXX) + else() + if(CUDA_VERSION VERSION_LESS "3.0") + set(nvcc_flags ${nvcc_flags} --host-compilation C) + else() + message(WARNING "--host-compilation flag is deprecated in CUDA version >= 3.0. Removing --host-compilation C flag" ) + endif() + set(CUDA_C_OR_CXX C) + endif() + + set(generated_extension ${CMAKE_${CUDA_C_OR_CXX}_OUTPUT_EXTENSION}) + + if(CUDA_64_BIT_DEVICE_CODE) + set(nvcc_flags ${nvcc_flags} -m64) + else() + set(nvcc_flags ${nvcc_flags} -m32) + endif() + + if(CUDA_TARGET_CPU_ARCH) + set(nvcc_flags ${nvcc_flags} "--target-cpu-architecture=${CUDA_TARGET_CPU_ARCH}") + endif() + + # This needs to be passed in at this stage, because VS needs to fill out the + # value of VCInstallDir from within VS. Note that CCBIN is only used if + # -ccbin or --compiler-bindir isn't used and CUDA_HOST_COMPILER matches + # $(VCInstallDir)/bin. + if(CMAKE_GENERATOR MATCHES "Visual Studio") + set(ccbin_flags -D "\"CCBIN:PATH=${CUDA_HOST_COMPILER}\"" ) + else() + set(ccbin_flags) + endif() + + # Figure out which configure we will use and pass that in as an argument to + # the script. We need to defer the decision until compilation time, because + # for VS projects we won't know if we are making a debug or release build + # until build time. + if(CMAKE_GENERATOR MATCHES "Visual Studio") + set( CUDA_build_configuration "$(ConfigurationName)" ) + else() + set( CUDA_build_configuration "${CMAKE_BUILD_TYPE}") + endif() + + # Initialize our list of includes with the user ones followed by the CUDA system ones. + set(CUDA_NVCC_INCLUDE_ARGS ${CUDA_NVCC_INCLUDE_ARGS_USER} "-I${CUDA_INCLUDE_DIRS}") + # Get the include directories for this directory and use them for our nvcc command. + get_directory_property(CUDA_NVCC_INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES) + if(CUDA_NVCC_INCLUDE_DIRECTORIES) + foreach(dir ${CUDA_NVCC_INCLUDE_DIRECTORIES}) + list(APPEND CUDA_NVCC_INCLUDE_ARGS -I${dir}) + endforeach() + endif() + + # Reset these variables + set(CUDA_WRAP_OPTION_NVCC_FLAGS) + foreach(config ${CUDA_configuration_types}) + string(TOUPPER ${config} config_upper) + set(CUDA_WRAP_OPTION_NVCC_FLAGS_${config_upper}) + endforeach() + + CUDA_GET_SOURCES_AND_OPTIONS(_cuda_wrap_sources _cuda_wrap_cmake_options _cuda_wrap_options ${ARGN}) + CUDA_PARSE_NVCC_OPTIONS(CUDA_WRAP_OPTION_NVCC_FLAGS ${_cuda_wrap_options}) + + # Figure out if we are building a shared library. BUILD_SHARED_LIBS is + # respected in CUDA_ADD_LIBRARY. + set(_cuda_build_shared_libs FALSE) + # SHARED, MODULE + list(FIND _cuda_wrap_cmake_options SHARED _cuda_found_SHARED) + list(FIND _cuda_wrap_cmake_options MODULE _cuda_found_MODULE) + if(_cuda_found_SHARED GREATER -1 OR _cuda_found_MODULE GREATER -1) + set(_cuda_build_shared_libs TRUE) + endif() + # STATIC + list(FIND _cuda_wrap_cmake_options STATIC _cuda_found_STATIC) + if(_cuda_found_STATIC GREATER -1) + set(_cuda_build_shared_libs FALSE) + endif() + + # CUDA_HOST_FLAGS + if(_cuda_build_shared_libs) + # If we are setting up code for a shared library, then we need to add extra flags for + # compiling objects for shared libraries. + set(CUDA_HOST_SHARED_FLAGS ${CMAKE_SHARED_LIBRARY_${CUDA_C_OR_CXX}_FLAGS}) + else() + set(CUDA_HOST_SHARED_FLAGS) + endif() + + # If we are using batch building and we are using VS 2013+ we could have problems with + # parallel accesses to the PDB files which comes from the parallel batch building. /FS + # serializes the builds which fixes this. There doesn't seem any harm to add this for + # PTX targets or for builds that don't do parallel building. + set( EXTRA_FS_ARG ) + if( CUDA_BATCH_BUILD_LOG AND MSVC ) + if(NOT MSVC_VERSION VERSION_LESS 1800) + set( EXTRA_FS_ARG "/FS" ) + endif() + endif() + + + # Only add the CMAKE_{C,CXX}_FLAGS if we are propagating host flags. We + # always need to set the SHARED_FLAGS, though. + if(CUDA_PROPAGATE_HOST_FLAGS) + set(_cuda_host_flags "set(CMAKE_HOST_FLAGS ${CMAKE_${CUDA_C_OR_CXX}_FLAGS} ${CUDA_HOST_SHARED_FLAGS} ${EXTRA_FS_ARG})") + else() + set(_cuda_host_flags "set(CMAKE_HOST_FLAGS ${CUDA_HOST_SHARED_FLAGS} ${EXTRA_FS_ARG})") + endif() + + set(_cuda_nvcc_flags_config "# Build specific configuration flags") + # Loop over all the configuration types to generate appropriate flags for run_nvcc.cmake + foreach(config ${CUDA_configuration_types}) + string(TOUPPER ${config} config_upper) + # CMAKE_FLAGS are strings and not lists. By not putting quotes around CMAKE_FLAGS + # we convert the strings to lists (like we want). + + if(CUDA_PROPAGATE_HOST_FLAGS) + # nvcc chokes on -g3 in versions previous to 3.0, so replace it with -g + set(_cuda_fix_g3 FALSE) + + if(CMAKE_COMPILER_IS_GNUCC) + if (CUDA_VERSION VERSION_LESS "3.0" OR + CUDA_VERSION VERSION_EQUAL "4.1" OR + CUDA_VERSION VERSION_EQUAL "4.2" + ) + set(_cuda_fix_g3 TRUE) + endif() + endif() + if(_cuda_fix_g3) + string(REPLACE "-g3" "-g" _cuda_C_FLAGS "${CMAKE_${CUDA_C_OR_CXX}_FLAGS_${config_upper}}") + else() + set(_cuda_C_FLAGS "${CMAKE_${CUDA_C_OR_CXX}_FLAGS_${config_upper}}") + endif() + + # Using the optimized debug information flag causes problems. + if (MSVC) + string(REPLACE "/Zo" "" _cuda_C_FLAGS "${_cuda_C_FLAGS}") + endif() + + set(_cuda_host_flags "${_cuda_host_flags}\nset(CMAKE_HOST_FLAGS_${config_upper} ${_cuda_C_FLAGS})") + endif() + + # Note that if we ever want CUDA_NVCC_FLAGS_ to be string (instead of a list + # like it is currently), we can remove the quotes around the + # ${CUDA_NVCC_FLAGS_${config_upper}} variable like the CMAKE_HOST_FLAGS_ variable. + set(_cuda_nvcc_flags_config "${_cuda_nvcc_flags_config}\nset(CUDA_NVCC_FLAGS_${config_upper} ${CUDA_NVCC_FLAGS_${config_upper}} ;; ${CUDA_WRAP_OPTION_NVCC_FLAGS_${config_upper}})") + endforeach() + + # NVCC can't handle this C++ argument, because it uses during certain phases where the C + # compiler is invoked and complains about it. + if( CMAKE_COMPILER_IS_GNUCXX ) + string(REPLACE "-fvisibility-inlines-hidden" "" _cuda_host_flags "${_cuda_host_flags}") + endif() + + # Process the C++11 flag. If the host sets the flag, we need to add it to nvcc and + # remove it from the host. This is because -Xcompiler -std=c++ will choke nvcc (it uses + # the C preprocessor). In order to get this to work correctly, we need to use nvcc's + # specific c++11 flag. + if( "${_cuda_host_flags}" MATCHES "-std=c\\+\\+11" OR ( CMAKE_CXX_STANDARD EQUAL 11 AND NOT USING_WINDOWS_CL ) ) + # Add the c++11 flag to nvcc if it isn't already present. Note that we only look at + # the main flag instead of the configuration specific flags. + if( NOT "${CUDA_NVCC_FLAGS}" MATCHES "-std;c\\+\\+11" ) + list(APPEND nvcc_flags --std c++11) + endif() + string(REGEX REPLACE "[-]+std=c\\+\\+11" "" _cuda_host_flags "${_cuda_host_flags}") + endif() + + # Get the list of definitions from the directory property + get_directory_property(CUDA_NVCC_DEFINITIONS COMPILE_DEFINITIONS) + if(CUDA_NVCC_DEFINITIONS) + foreach(_definition ${CUDA_NVCC_DEFINITIONS}) + list(APPEND nvcc_flags "-D${_definition}") + endforeach() + endif() + + if(_cuda_build_shared_libs) + list(APPEND nvcc_flags "-D${cuda_target}_EXPORTS") + endif() + + # Reset the output variable + set(_cuda_wrap_generated_files "") + + # Iterate over the macro arguments and create custom + # commands for all the .cu files. + foreach(file ${ARGN}) + # Ignore any file marked as a HEADER_FILE_ONLY + get_source_file_property(_is_header ${file} HEADER_FILE_ONLY) + # Allow per source file overrides of the format. Also allows compiling non-.cu files. + get_source_file_property(_cuda_source_format ${file} CUDA_SOURCE_PROPERTY_FORMAT) + if((${file} MATCHES "\\.cu$" OR _cuda_source_format) AND NOT _is_header) + + if(NOT _cuda_source_format) + set(_cuda_source_format ${format}) + endif() + # If file isn't a .cu file, we need to tell nvcc to treat it as such. + if(NOT ${file} MATCHES "\\.cu$") + set(cuda_language_flag -x=cu) + else() + set(cuda_language_flag) + endif() + + if( ${_cuda_source_format} STREQUAL "OBJ") + set( cuda_compile_to_external_module OFF ) + set( cuda_compile_to_external_module_multi_config_build ON ) + else() + set( cuda_compile_to_external_module ON ) + set( cuda_compile_to_external_module_multi_config_build OFF ) + if( ${_cuda_source_format} STREQUAL "PTX" ) + set( cuda_compile_to_external_module_flag "-ptx") + set( cuda_compile_to_external_module_type "ptx" ) + elseif( ${_cuda_source_format} STREQUAL "CUBIN") + set( cuda_compile_to_external_module_flag "-cubin" ) + set( cuda_compile_to_external_module_type "cubin" ) + elseif( ${_cuda_source_format} STREQUAL "FATBIN") + set( cuda_compile_to_external_module_flag "-fatbin" ) + set( cuda_compile_to_external_module_type "fatbin" ) + elseif( ${_cuda_source_format} STREQUAL "OPTIXIR") + set( cuda_compile_to_external_module_flag "-optix-ir" ) + set( cuda_compile_to_external_module_type "optixir" ) + set( cuda_compile_to_external_module_multi_config_build ON ) + else() + if(DEFINED CUDA_CUSTOM_SOURCE_FORMAT_FLAG_${_cuda_source_format} AND DEFINED CUDA_CUSTOM_SOURCE_FORMAT_TYPE_${_cuda_source_format}) + set( cuda_compile_to_external_module_flag "${CUDA_CUSTOM_SOURCE_FORMAT_FLAG_${_cuda_source_format}}" ) + set( cuda_compile_to_external_module_type "${CUDA_CUSTOM_SOURCE_FORMAT_TYPE_${_cuda_source_format}}" ) + else() + message( FATAL_ERROR "Invalid format flag passed to CUDA_WRAP_SRCS or set with CUDA_SOURCE_PROPERTY_FORMAT file property for file '${file}': '${_cuda_source_format}'. Use OBJ, PTX, CUBIN or FATBIN.") + endif() + endif() + endif() + + if(cuda_compile_to_external_module) + # Don't use any of the host compilation flags for PTX targets. + set(CUDA_HOST_FLAGS) + else() + set(CUDA_HOST_FLAGS ${_cuda_host_flags}) + endif() + + if(cuda_compile_to_external_module_multi_config_build) + set(CUDA_NVCC_FLAGS_CONFIG ${_cuda_nvcc_flags_config}) + set( cuda_compile_cfg_intdir "${CMAKE_CFG_INTDIR}" ) + else() + set(CUDA_NVCC_FLAGS_CONFIG) + set( cuda_compile_cfg_intdir "." ) + endif() + + # Determine output directory + cuda_compute_build_path("${file}" cuda_build_path) + set(cuda_compile_intermediate_directory "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${cuda_target}.dir/${cuda_build_path}") + if(CUDA_GENERATED_OUTPUT_DIR) + set(cuda_compile_output_dir "${CUDA_GENERATED_OUTPUT_DIR}") + else() + if ( cuda_compile_to_external_module ) + set(cuda_compile_output_dir "${CMAKE_CURRENT_BINARY_DIR}") + else() + set(cuda_compile_output_dir "${cuda_compile_intermediate_directory}") + endif() + endif() + + # Add a custom target to generate a c or ptx file. ###################### + + get_filename_component( basename ${file} NAME ) + set(generated_file_path "${cuda_compile_output_dir}/${cuda_compile_cfg_intdir}") + if( cuda_compile_to_external_module ) + set(generated_file_basename "${cuda_target}_generated_${basename}.${cuda_compile_to_external_module_type}") + set(format_flag "${cuda_compile_to_external_module_flag}") + file(MAKE_DIRECTORY "${cuda_compile_output_dir}") + else() + set(generated_file_basename "${cuda_target}_generated_${basename}${generated_extension}") + if(CUDA_SEPARABLE_COMPILATION) + set(format_flag "-dc") + else() + set(format_flag "-c") + endif() + endif() + + # Set all of our file names. Make sure that whatever filenames that have + # generated_file_path in them get passed in through as a command line + # argument, so that the ${CMAKE_CFG_INTDIR} gets expanded at run time + # instead of configure time. + set(generated_file "${generated_file_path}/${generated_file_basename}") + set(cmake_dependency_file "${cuda_compile_intermediate_directory}/${generated_file_basename}.depend") + set(NVCC_generated_dependency_file "${cuda_compile_intermediate_directory}/${generated_file_basename}.NVCC-depend") + set(generated_cubin_file "${generated_file_path}/${generated_file_basename}.cubin.txt") + set(generated_fatbin_file "${generated_file_path}/${generated_file_basename}.fatbin.txt") + set(custom_target_script "${cuda_compile_intermediate_directory}/${generated_file_basename}.cmake") + + # Setup properties for obj files: + if( NOT cuda_compile_to_external_module ) + set_source_files_properties("${generated_file}" + PROPERTIES + EXTERNAL_OBJECT true # This is an object file not to be compiled, but only be linked. + ) + endif() + + # Don't add CMAKE_CURRENT_SOURCE_DIR if the path is already an absolute path. + get_filename_component(file_path "${file}" PATH) + if(IS_ABSOLUTE "${file_path}") + set(source_file "${file}") + else() + set(source_file "${CMAKE_CURRENT_SOURCE_DIR}/${file}") + endif() + + if( NOT cuda_compile_to_external_module AND CUDA_SEPARABLE_COMPILATION) + list(APPEND ${cuda_target}_SEPARABLE_COMPILATION_OBJECTS "${generated_file}") + endif() + + # Convience string for output ########################################### + if(CUDA_BUILD_EMULATION) + set(cuda_build_type "Emulation") + else() + set(cuda_build_type "Device") + endif() + + # Build the NVCC made dependency file ################################### + set(build_cubin OFF) + if ( NOT CUDA_BUILD_EMULATION AND CUDA_BUILD_CUBIN ) + if ( NOT cuda_compile_to_external_module ) + set ( build_cubin ON ) + endif() + endif() + + # Configure the build script + configure_file("${CUDA_run_nvcc}" "${custom_target_script}" @ONLY) + + # So if a user specifies the same cuda file as input more than once, you + # can have bad things happen with dependencies. Here we check an option + # to see if this is the behavior they want. + if(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE) + set(main_dep MAIN_DEPENDENCY ${source_file}) + else() + set(main_dep DEPENDS ${source_file}) + endif() + + if(CUDA_VERBOSE_BUILD) + set(verbose_output ON) + elseif(CMAKE_GENERATOR MATCHES "Makefiles") + set(verbose_output "$(VERBOSE)") + else() + set(verbose_output OFF) + endif() + + # Create up the comment string + file(RELATIVE_PATH generated_file_relative_path "${CMAKE_BINARY_DIR}" "${generated_file}") + if(cuda_compile_to_external_module) + set(cuda_build_comment_string "Building NVCC ${cuda_compile_to_external_module_type} file ${generated_file_relative_path}") + else() + set(cuda_build_comment_string "Building NVCC (${cuda_build_type}) object ${generated_file_relative_path}") + endif() + + # Bring in the dependencies. Creates a variable CUDA_NVCC_DEPEND ####### + cuda_include_nvcc_dependencies(${cmake_dependency_file}) + + # Check to see if the build script is newer than the dependency file. If + # it is, regenerate it. + # message("CUDA_GENERATE_DEPENDENCIES_DURING_CONFIGURE = ${CUDA_GENERATE_DEPENDENCIES_DURING_CONFIGURE}") + # message("CUDA_NVCC_DEPEND_REGENERATE = ${CUDA_NVCC_DEPEND_REGENERATE}") + # execute_process(COMMAND ls -lTtr "${custom_target_script}" "${cmake_dependency_file}" "${NVCC_generated_dependency_file}") + set(_cuda_generate_dependencies FALSE) + # Note that NVCC_generated_dependency_file is always generated. + if(CUDA_GENERATE_DEPENDENCIES_DURING_CONFIGURE + AND "${custom_target_script}" IS_NEWER_THAN "${NVCC_generated_dependency_file}") + # If the two files were generated about the same time then reversing the + # comparison will also be true, so check the CUDA_NVCC_DEPEND_REGENERATE + # flag. + if ("${NVCC_generated_dependency_file}" IS_NEWER_THAN "${custom_target_script}") + # message("************************************************************************") + # message("Same modification time: ${custom_target_script} ${NVCC_generated_dependency_file}") + if (CUDA_NVCC_DEPEND_REGENERATE OR NOT EXISTS "${NVCC_generated_dependency_file}") + set(_cuda_generate_dependencies TRUE) + endif() + else() + # The timestamp check is valid + set(_cuda_generate_dependencies TRUE) + endif() + endif() + # message("_cuda_generate_dependencies = ${_cuda_generate_dependencies}") + + # If we needed to regenerate the dependency file, do so now. + if (_cuda_generate_dependencies) + set(_cuda_dependency_ccbin) + # message("CUDA_HOST_COMPILER = ${CUDA_HOST_COMPILER}") + if(ccbin_flags MATCHES "\\$\\(VCInstallDir\\)") + set(_cuda_dependency_ccbin_dir) + if (CUDA_VS_DIR AND EXISTS "${CUDA_VS_DIR}/VC/bin") + set(_cuda_dependency_ccbin_dir "${CUDA_VS_DIR}/VC/bin") + elseif( EXISTS "${CMAKE_CXX_COMPILER}" ) + get_filename_component(_cuda_dependency_ccbin_dir "${CMAKE_CXX_COMPILER}" DIRECTORY) + endif() + if( _cuda_dependency_ccbin_dir ) + set(_cuda_dependency_ccbin -D "CCBIN:PATH=${_cuda_dependency_ccbin_dir}") + endif() + elseif(ccbin_flags) + # The CUDA_HOST_COMPILER is set to something interesting, so use the + # ccbin_flags as-is. + set(_cuda_dependency_ccbin ${ccbin_flags}) + endif() + # message("_cuda_dependency_ccbin = ${_cuda_dependency_ccbin}") + if(_cuda_dependency_ccbin OR NOT ccbin_flags) + # Only do this if we have some kind of host compiler defined in + # _cuda_dependency_ccbin or ccbin_flags isn't set. + + set( _execute_process_args + COMMAND ${CMAKE_COMMAND} + -D generate_dependency_only:BOOL=TRUE + -D verbose:BOOL=TRUE + ${_cuda_dependency_ccbin} + -D "generated_file:STRING=${generated_file}" + -D "generated_cubin_file:STRING=${generated_cubin_file}" + -P "${custom_target_script}" + WORKING_DIRECTORY "${cuda_compile_intermediate_directory}" + RESULT_VARIABLE _cuda_dependency_error + OUTPUT_VARIABLE _cuda_dependency_output + ERROR_VARIABLE _cuda_dependency_output + ) + if( CUDA_BATCH_DEPENDS_LOG ) + file( APPEND ${CUDA_BATCH_DEPENDS_LOG} "COMMENT;Generating dependencies for ${file};${_execute_process_args}\n" ) + else() + message(STATUS "Generating dependencies for ${file}") + execute_process( + ${_execute_process_args} + ) + endif() + if (_cuda_dependency_error) + message(WARNING "Error (${_cuda_dependency_error}) generating dependencies for ${file}:\n\n${_cuda_dependency_output}. This will be postponed until build time.") + else() + # Try and reload the dependies + cuda_include_nvcc_dependencies(${cmake_dependency_file}) + endif() + endif() + endif() + + # Build the generated file and dependency file ########################## + set( _custom_command_args + OUTPUT ${generated_file} + # These output files depend on the source_file and the contents of cmake_dependency_file + ${main_dep} + DEPENDS ${CUDA_NVCC_DEPEND} + DEPENDS ${custom_target_script} + # Make sure the output directory exists before trying to write to it. + COMMAND ${CMAKE_COMMAND} -E make_directory "${generated_file_path}" + COMMAND ${CMAKE_COMMAND} + -D verbose:BOOL=${verbose_output} + -D check_dependencies:BOOL=${CUDA_CHECK_DEPENDENCIES_DURING_COMPILE} + ${ccbin_flags} + -D build_configuration:STRING=${CUDA_build_configuration} + -D "generated_file:STRING=${generated_file}" + -D "generated_cubin_file:STRING=${generated_cubin_file}" + -D "generated_fatbin_file:STRING=${generated_fatbin_file}" + -P "${custom_target_script}" + WORKING_DIRECTORY "${cuda_compile_intermediate_directory}" + COMMENT "${cuda_build_comment_string}" + ) + if( CUDA_BATCH_BUILD_LOG ) + list(APPEND CUDA_BATCH_BUILD_OUTPUTS ${generated_file}) + set_property( GLOBAL APPEND PROPERTY CUDA_BATCH_BUILD_DEPENDS ${source_file} ${CUDA_NVCC_DEPEND} ${custom_target_script}) + file( APPEND ${CUDA_BATCH_BUILD_LOG} "${_custom_command_args}\n" ) + endif() + add_custom_command( ${_custom_command_args} ) + + # Make sure the build system knows the file is generated. + set_source_files_properties(${generated_file} PROPERTIES GENERATED TRUE) + + list(APPEND _cuda_wrap_generated_files ${generated_file}) + + # Add the other files that we want cmake to clean on a cleanup ########## + list(APPEND CUDA_ADDITIONAL_CLEAN_FILES "${cmake_dependency_file}") + list(REMOVE_DUPLICATES CUDA_ADDITIONAL_CLEAN_FILES) + set(CUDA_ADDITIONAL_CLEAN_FILES ${CUDA_ADDITIONAL_CLEAN_FILES} CACHE INTERNAL "List of intermediate files that are part of the cuda dependency scanning.") + + endif() + endforeach() + + # Set the return parameter + set(${generated_files} ${_cuda_wrap_generated_files}) +endmacro() + +function(_cuda_get_important_host_flags important_flags flag_string) + if(CMAKE_GENERATOR MATCHES "Visual Studio") + string(REGEX MATCHALL "/M[DT][d]?" flags "${flag_string}") + list(APPEND ${important_flags} ${flags}) + else() + string(REGEX MATCHALL "-fPIC" flags "${flag_string}") + list(APPEND ${important_flags} ${flags}) + endif() + set(${important_flags} ${${important_flags}} PARENT_SCOPE) +endfunction() + +############################################################################### +############################################################################### +# Separable Compilation Link +############################################################################### +############################################################################### + +# Compute the filename to be used by CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS +function(CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME output_file_var cuda_target object_files) + if (object_files) + set(generated_extension ${CMAKE_${CUDA_C_OR_CXX}_OUTPUT_EXTENSION}) + set(output_file "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${cuda_target}.dir/${CMAKE_CFG_INTDIR}/${cuda_target}_intermediate_link${generated_extension}") + else() + set(output_file) + endif() + + set(${output_file_var} "${output_file}" PARENT_SCOPE) +endfunction() + +# Setup the build rule for the separable compilation intermediate link file. +function(CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS output_file cuda_target options object_files) + if (object_files) + + set_source_files_properties("${output_file}" + PROPERTIES + EXTERNAL_OBJECT TRUE # This is an object file not to be compiled, but only + # be linked. + GENERATED TRUE # This file is generated during the build + ) + + # For now we are ignoring all the configuration specific flags. + set(nvcc_flags) + CUDA_PARSE_NVCC_OPTIONS(nvcc_flags ${options}) + if(CUDA_64_BIT_DEVICE_CODE) + list(APPEND nvcc_flags -m64) + else() + list(APPEND nvcc_flags -m32) + endif() + # If -ccbin, --compiler-bindir has been specified, don't do anything. Otherwise add it here. + list( FIND nvcc_flags "-ccbin" ccbin_found0 ) + list( FIND nvcc_flags "--compiler-bindir" ccbin_found1 ) + if( ccbin_found0 LESS 0 AND ccbin_found1 LESS 0 AND CUDA_HOST_COMPILER ) + # Match VERBATIM check below. + if(CUDA_HOST_COMPILER MATCHES "\\$\\(VCInstallDir\\)") + list(APPEND nvcc_flags -ccbin "\"${CUDA_HOST_COMPILER}\"") + else() + list(APPEND nvcc_flags -ccbin "${CUDA_HOST_COMPILER}") + endif() + endif() + + # Create a list of flags specified by CUDA_NVCC_FLAGS_${CONFIG} and CMAKE_${CUDA_C_OR_CXX}_FLAGS* + set(config_specific_flags) + set(flags) + foreach(config ${CUDA_configuration_types}) + string(TOUPPER ${config} config_upper) + # Add config specific flags + foreach(f ${CUDA_NVCC_FLAGS_${config_upper}}) + list(APPEND config_specific_flags $<$:${f}>) + endforeach() + set(important_host_flags) + _cuda_get_important_host_flags(important_host_flags "${CMAKE_${CUDA_C_OR_CXX}_FLAGS_${config_upper}}") + foreach(f ${important_host_flags}) + list(APPEND flags $<$:-Xcompiler> $<$:${f}>) + endforeach() + endforeach() + # Add CMAKE_${CUDA_C_OR_CXX}_FLAGS + set(important_host_flags) + _cuda_get_important_host_flags(important_host_flags "${CMAKE_${CUDA_C_OR_CXX}_FLAGS}") + foreach(f ${important_host_flags}) + list(APPEND flags -Xcompiler ${f}) + endforeach() + + # Add our general CUDA_NVCC_FLAGS with the configuration specifig flags + set(nvcc_flags ${CUDA_NVCC_FLAGS} ${config_specific_flags} ${nvcc_flags}) + + file(RELATIVE_PATH output_file_relative_path "${CMAKE_BINARY_DIR}" "${output_file}") + + # Some generators don't handle the multiple levels of custom command + # dependencies correctly (obj1 depends on file1, obj2 depends on obj1), so + # we work around that issue by compiling the intermediate link object as a + # pre-link custom command in that situation. + set(do_obj_build_rule TRUE) + if (MSVC_VERSION GREATER 1599 AND MSVC_VERSION LESS 1800) + # VS 2010 and 2012 have this problem. + set(do_obj_build_rule FALSE) + endif() + + set(_verbatim VERBATIM) + if(nvcc_flags MATCHES "\\$\\(VCInstallDir\\)") + set(_verbatim "") + endif() + + if (do_obj_build_rule) + add_custom_command( + OUTPUT ${output_file} + DEPENDS ${object_files} + COMMAND ${CUDA_NVCC_EXECUTABLE} ${nvcc_flags} -dlink ${object_files} -o ${output_file} + ${flags} + COMMENT "Building NVCC intermediate link file ${output_file_relative_path}" + ${_verbatim} + ) + else() + get_filename_component(output_file_dir "${output_file}" DIRECTORY) + add_custom_command( + TARGET ${cuda_target} + PRE_LINK + COMMAND ${CMAKE_COMMAND} -E echo "Building NVCC intermediate link file ${output_file_relative_path}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${output_file_dir}" + COMMAND ${CUDA_NVCC_EXECUTABLE} ${nvcc_flags} ${flags} -dlink ${object_files} -o "${output_file}" + ${_verbatim} + ) + endif() + endif() +endfunction() + +############################################################################### +############################################################################### +# ADD LIBRARY +############################################################################### +############################################################################### +macro(CUDA_ADD_LIBRARY cuda_target) + + CUDA_ADD_CUDA_INCLUDE_ONCE() + + # Separate the sources from the options + CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) + CUDA_BUILD_SHARED_LIBRARY(_cuda_shared_flag ${ARGN}) + # Create custom commands and targets for each file. + CUDA_WRAP_SRCS( ${cuda_target} OBJ _generated_files ${_sources} + ${_cmake_options} ${_cuda_shared_flag} + OPTIONS ${_options} ) + + # Compute the file name of the intermedate link file used for separable + # compilation. + CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME(link_file ${cuda_target} "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}") + + # Add the library. + add_library(${cuda_target} ${_cmake_options} + ${_generated_files} + ${_sources} + ${link_file} + ) + + # Add a link phase for the separable compilation if it has been enabled. If + # it has been enabled then the ${cuda_target}_SEPARABLE_COMPILATION_OBJECTS + # variable will have been defined. + CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS("${link_file}" ${cuda_target} "${_options}" "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}") + + target_link_libraries(${cuda_target} + ${CUDA_LIBRARIES} + ) + + if(CUDA_SEPARABLE_COMPILATION) + target_link_libraries(${cuda_target} + ${CUDA_cudadevrt_LIBRARY} + ) + endif() + + # We need to set the linker language based on what the expected generated file + # would be. CUDA_C_OR_CXX is computed based on CUDA_HOST_COMPILATION_CPP. + set_target_properties(${cuda_target} + PROPERTIES + LINKER_LANGUAGE ${CUDA_C_OR_CXX} + ) + +endmacro() + + +############################################################################### +############################################################################### +# ADD EXECUTABLE +############################################################################### +############################################################################### +macro(CUDA_ADD_EXECUTABLE cuda_target) + + CUDA_ADD_CUDA_INCLUDE_ONCE() + + # Separate the sources from the options + CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) + # Create custom commands and targets for each file. + CUDA_WRAP_SRCS( ${cuda_target} OBJ _generated_files ${_sources} OPTIONS ${_options} ) + + # Compute the file name of the intermedate link file used for separable + # compilation. + CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME(link_file ${cuda_target} "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}") + + # Add the library. + add_executable(${cuda_target} ${_cmake_options} + ${_generated_files} + ${_sources} + ${link_file} + ) + + # Add a link phase for the separable compilation if it has been enabled. If + # it has been enabled then the ${cuda_target}_SEPARABLE_COMPILATION_OBJECTS + # variable will have been defined. + CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS("${link_file}" ${cuda_target} "${_options}" "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}") + + target_link_libraries(${cuda_target} + ${CUDA_LIBRARIES} + ) + + # We need to set the linker language based on what the expected generated file + # would be. CUDA_C_OR_CXX is computed based on CUDA_HOST_COMPILATION_CPP. + set_target_properties(${cuda_target} + PROPERTIES + LINKER_LANGUAGE ${CUDA_C_OR_CXX} + ) + +endmacro() + + +############################################################################### +############################################################################### +# (Internal) helper for manually added cuda source files with specific targets +############################################################################### +############################################################################### +macro(cuda_compile_base cuda_target format generated_files) + # Separate the sources from the options + CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) + + # Create custom commands and targets for each file. + CUDA_WRAP_SRCS( ${cuda_target} ${format} _generated_files ${_sources} + ${_cmake_options} OPTIONS ${_options}) + + set( ${generated_files} ${_generated_files}) + +endmacro() + +############################################################################### +############################################################################### +# CUDA COMPILE +############################################################################### +############################################################################### +macro(CUDA_COMPILE generated_files) + cuda_compile_base(cuda_compile OBJ ${generated_files} ${ARGN}) +endmacro() + +############################################################################### +############################################################################### +# CUDA COMPILE PTX +############################################################################### +############################################################################### +macro(CUDA_COMPILE_PTX generated_files) + cuda_compile_base(cuda_compile_ptx PTX ${generated_files} ${ARGN}) +endmacro() + +############################################################################### +############################################################################### +# CUDA COMPILE FATBIN +############################################################################### +############################################################################### +macro(CUDA_COMPILE_FATBIN generated_files) + cuda_compile_base(cuda_compile_fatbin FATBIN ${generated_files} ${ARGN}) +endmacro() + +############################################################################### +############################################################################### +# CUDA COMPILE CUBIN +############################################################################### +############################################################################### +macro(CUDA_COMPILE_CUBIN generated_files) + cuda_compile_base(cuda_compile_cubin CUBIN ${generated_files} ${ARGN}) +endmacro() + + +############################################################################### +############################################################################### +# CUDA ADD CUFFT TO TARGET +############################################################################### +############################################################################### +macro(CUDA_ADD_CUFFT_TO_TARGET target) + if (CUDA_BUILD_EMULATION) + target_link_libraries(${target} ${CUDA_cufftemu_LIBRARY}) + else() + target_link_libraries(${target} ${CUDA_cufft_LIBRARY}) + endif() +endmacro() + +############################################################################### +############################################################################### +# CUDA ADD CUBLAS TO TARGET +############################################################################### +############################################################################### +macro(CUDA_ADD_CUBLAS_TO_TARGET target) + if (CUDA_BUILD_EMULATION) + target_link_libraries(${target} ${CUDA_cublasemu_LIBRARY}) + else() + target_link_libraries(${target} ${CUDA_cublas_LIBRARY} ${CUDA_cublas_device_LIBRARY}) + endif() +endmacro() + +############################################################################### +############################################################################### +# CUDA BUILD CLEAN TARGET +############################################################################### +############################################################################### +macro(CUDA_BUILD_CLEAN_TARGET) + # Call this after you add all your CUDA targets, and you will get a convience + # target. You should also make clean after running this target to get the + # build system to generate all the code again. + + set(cuda_clean_target_name clean_cuda_depends) + if (CMAKE_GENERATOR MATCHES "Visual Studio") + string(TOUPPER ${cuda_clean_target_name} cuda_clean_target_name) + endif() + add_custom_target(${cuda_clean_target_name} + COMMAND ${CMAKE_COMMAND} -E remove ${CUDA_ADDITIONAL_CLEAN_FILES}) + + # Clear out the variable, so the next time we configure it will be empty. + # This is useful so that the files won't persist in the list after targets + # have been removed. + set(CUDA_ADDITIONAL_CLEAN_FILES "" CACHE INTERNAL "List of intermediate files that are part of the cuda dependency scanning.") +endmacro() + + +############################################################################## +############################################################################### +# CUDA BATCH BUILD BEGIN +############################################################################### +############################################################################### +function(CUDA_BATCH_BUILD_BEGIN target) + if(MSVC AND CUDA_ENABLE_BATCHING) + set( CUDA_BATCH_BUILD_LOG "${CMAKE_BINARY_DIR}/CMakeFiles/${target}.dir/cudaBatchBuild.log" ) + file( REMOVE ${CUDA_BATCH_BUILD_LOG} ) + set( CUDA_BATCH_BUILD_LOG "${CUDA_BATCH_BUILD_LOG}" PARENT_SCOPE ) # export variable + set_property( GLOBAL PROPERTY CUDA_BATCH_BUILD_DEPENDS "" ) + endif() +endfunction() + + +############################################################################### +############################################################################### +# CUDA BATCH BUILD END +############################################################################### +############################################################################### +function(CUDA_BATCH_BUILD_END target) + set(BATCH_CMAKE_SCRIPT "${CMAKE_SOURCE_DIR}/CMake/cuda/FindCUDA/batchCMake.py") + find_package(PythonInterp) + + if( CUDA_BATCH_BUILD_LOG ) + set(cuda_batch_build_target "_${target}_cudaBatchBuild") + set(stamp_dir "${CMAKE_BINARY_DIR}/CMakeFiles/${target}.dir/${CMAKE_CFG_INTDIR}") + set(stamp_file ${stamp_dir}/cuda-batch-build.stamp) + get_property(cuda_depends GLOBAL PROPERTY CUDA_BATCH_BUILD_DEPENDS) + list(REMOVE_DUPLICATES cuda_depends) + add_custom_target( ${cuda_batch_build_target} + COMMENT "CUDA batch build ${cuda_batch_build_target}..." + COMMAND "${PYTHON_EXECUTABLE}" "${BATCH_CMAKE_SCRIPT}" -t ${cuda_batch_build_target} -c ${CUDA_BATCH_BUILD_LOG} -s "\"%24(VCInstallDir)=$(VCInstallDir)\\\"" -s "%24(ConfigurationName)=$(ConfigurationName)" -s "%24(Configuration)=$(Configuration)" -s "%24(VCToolsVersion)=$(VCToolsVersion)" -s "%24(PreferredToolArchitecture)=$(PreferredToolArchitecture)" -s "%24(PlatformTarget)=$(PlatformTarget)" # %24 is the '$' character - needed to escape '$' in VS rule + DEPENDS ${cuda_depends} + ) + add_dependencies( ${target} ${cuda_batch_build_target} ) + set_property(TARGET ${cuda_batch_build_target} PROPERTY FOLDER "CUDA Batch Build") + endif() + + set( CUDA_BATCH_BUILD_LOG "" PARENT_SCOPE ) + set_property( GLOBAL PROPERTY CUDA_BATCH_BUILD_DEPENDS "" ) +endfunction() + +############################################################################## +############################################################################### +# CUDA BATCH DEPENDS BEGIN +############################################################################### +############################################################################### +function(CUDA_BATCH_DEPENDS_BEGIN) + if(MSVC AND CUDA_ENABLE_BATCHING) + set( CUDA_BATCH_DEPENDS_LOG "${CMAKE_BINARY_DIR}/CMakeFiles/cudaBatchDepends.log" ) + file( REMOVE ${CUDA_BATCH_DEPENDS_LOG} ) + set( CUDA_BATCH_DEPENDS_LOG "${CUDA_BATCH_DEPENDS_LOG}" PARENT_SCOPE ) # export variable + + set(BATCH_CMAKE_SCRIPT "${CMAKE_SOURCE_DIR}/CMake/cuda/FindCUDA/batchCMake.py") + # Create batch file to setup VS environment, since CUDA 8 broke running nvcc outside + # of VS environment. You could get around this with the following command with newer + # versions of cmake (3.5.2 worked for me, but 3.2.1 didn't like the && ): + # execute_process( COMMAND ${CUDA_VC_VARS_ALL_BAT} && ${PYTHON_EXECUTABLE} ... ) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(BUILD_BITS amd64) + else() + set(BUILD_BITS x86) + endif() + file(WRITE ${CUDA_BATCH_DEPENDS_LOG}.vsconfigure.bat + "@echo OFF\n" + "REM Created by FindCUDA.cmake\n" + "@call \"${CUDA_VC_VARS_ALL_BAT}\" ${BUILD_BITS}\n" + "\"${PYTHON_EXECUTABLE}\" \"${BATCH_CMAKE_SCRIPT}\" -e \"${CUDA_BATCH_DEPENDS_LOG}\" -t \"CUDA batch dependencies\"" + ) + endif() +endfunction() + +############################################################################### +############################################################################### +# CUDA BATCH DEPENDS END +############################################################################### +############################################################################### +function(CUDA_BATCH_DEPENDS_END) + if( CUDA_BATCH_DEPENDS_LOG ) + if( EXISTS ${CUDA_BATCH_DEPENDS_LOG} ) + message(STATUS "CUDA batch dependencies ...") + execute_process( + COMMAND ${CUDA_BATCH_DEPENDS_LOG}.vsconfigure.bat + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE _cuda_batch_depends_output + ERROR_VARIABLE _cuda_batch_depends_output + RESULT_VARIABLE _cuda_batch_depends_result + ) + message(STATUS ${_cuda_batch_depends_output}) + if( ${_cuda_batch_depends_result} ) + message(FATAL_ERROR "Failed") + else() + message(SEND_ERROR "Please reconfigure to ensure that dependencies are incorporated into the build files") + endif() + endif() + endif() + + set( CUDA_BATCH_DEPENDS_LOG ) + +endfunction() diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA/make2cmake.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA/make2cmake.cmake new file mode 100644 index 00000000..b161306f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA/make2cmake.cmake @@ -0,0 +1,108 @@ +# James Bigler, NVIDIA Corp (nvidia.com - jbigler) +# Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html +# +# Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# Copyright (c) 2007-2009 +# Scientific Computing and Imaging Institute, University of Utah +# +# This code is licensed under the MIT License. See the FindCUDA.cmake script +# for the text of the license. + +# The MIT License +# +# SPDX-FileCopyrightText: Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: MIT +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +####################################################################### +# This converts a file written in makefile syntax into one that can be included +# by CMake. + +# Input variables +# +# verbose:BOOL=<> OFF: Be as quiet as possible (default) +# ON : Extra output +# +# input_file:FILEPATH=<> Path to dependecy file in makefile format +# +# output_file:FILEPATH=<> Path to file with dependencies in CMake readable variable +# + +file(READ ${input_file} depend_text) + +if (NOT "${depend_text}" STREQUAL "") + + # message("FOUND DEPENDS") + + string(REPLACE "\\ " " " depend_text ${depend_text}) + + # This works for the nvcc -M generated dependency files. + string(REGEX REPLACE "^.* : " "" depend_text ${depend_text}) + string(REGEX REPLACE "[ \\\\]*\n" ";" depend_text ${depend_text}) + + set(dependency_list "") + + foreach(file ${depend_text}) + + string(REGEX REPLACE "^ +" "" file ${file}) + + # OK, now if we had a UNC path, nvcc has a tendency to only output the first '/' + # instead of '//'. Here we will test to see if the file exists, if it doesn't then + # try to prepend another '/' to the path and test again. If it still fails remove the + # path. + + if(NOT EXISTS "${file}") + if (EXISTS "/${file}") + set(file "/${file}") + else() + if(verbose) + message(WARNING " Removing non-existent dependency file: ${file}") + endif() + set(file "") + endif() + endif() + + # Make sure we check to see if we have a file, before asking if it is not a directory. + # if(NOT IS_DIRECTORY "") will return TRUE. + if(file AND NOT IS_DIRECTORY "${file}") + # If softlinks start to matter, we should change this to REALPATH. For now we need + # to flatten paths, because nvcc can generate stuff like /bin/../include instead of + # just /include. + get_filename_component(file_absolute "${file}" ABSOLUTE) + list(APPEND dependency_list "${file_absolute}") + endif() + + endforeach() + +else() + # message("FOUND NO DEPENDS") +endif() + +# Remove the duplicate entries and sort them. +list(REMOVE_DUPLICATES dependency_list) +list(SORT dependency_list) + +foreach(file ${dependency_list}) + set(cuda_nvcc_depend "${cuda_nvcc_depend} \"${file}\"\n") +endforeach() + +file(WRITE ${output_file} "# Generated by: make2cmake.cmake\nSET(CUDA_NVCC_DEPEND\n ${cuda_nvcc_depend})\n\n") diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA/parse_cubin.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA/parse_cubin.cmake new file mode 100644 index 00000000..cf16cfd9 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA/parse_cubin.cmake @@ -0,0 +1,113 @@ +# James Bigler, NVIDIA Corp (nvidia.com - jbigler) +# Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html +# +# Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# Copyright (c) 2007-2009 +# Scientific Computing and Imaging Institute, University of Utah +# +# This code is licensed under the MIT License. See the FindCUDA.cmake script +# for the text of the license. + +# The MIT License +# +# SPDX-FileCopyrightText: Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: MIT +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +####################################################################### +# Parses a .cubin file produced by nvcc and reports statistics about the file. + + +file(READ ${input_file} file_text) + +if (NOT "${file_text}" STREQUAL "") + + string(REPLACE ";" "\\;" file_text ${file_text}) + string(REPLACE "\ncode" ";code" file_text ${file_text}) + + list(LENGTH file_text len) + + foreach(line ${file_text}) + + # Only look at "code { }" blocks. + if(line MATCHES "^code") + + # Break into individual lines. + string(REGEX REPLACE "\n" ";" line ${line}) + + foreach(entry ${line}) + + # Extract kernel names. + if (${entry} MATCHES "[^g]name = ([^ ]+)") + set(entry "${CMAKE_MATCH_1}") + + # Check to see if the kernel name starts with "_" + set(skip FALSE) + # if (${entry} MATCHES "^_") + # Skip the rest of this block. + # message("Skipping ${entry}") + # set(skip TRUE) + # else () + message("Kernel: ${entry}") + # endif () + + endif() + + # Skip the rest of the block if necessary + if(NOT skip) + + # Registers + if (${entry} MATCHES "reg([ ]+)=([ ]+)([^ ]+)") + set(entry "${CMAKE_MATCH_3}") + message("Registers: ${entry}") + endif() + + # Local memory + if (${entry} MATCHES "lmem([ ]+)=([ ]+)([^ ]+)") + set(entry "${CMAKE_MATCH_3}") + message("Local: ${entry}") + endif() + + # Shared memory + if (${entry} MATCHES "smem([ ]+)=([ ]+)([^ ]+)") + set(entry "${CMAKE_MATCH_3}") + message("Shared: ${entry}") + endif() + + if (${entry} MATCHES "^}") + message("") + endif() + + endif() + + + endforeach() + + endif() + + endforeach() + +else() + # message("FOUND NO DEPENDS") +endif() + + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA/run_nvcc.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA/run_nvcc.cmake new file mode 100644 index 00000000..231a33c6 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA/run_nvcc.cmake @@ -0,0 +1,400 @@ +# James Bigler, NVIDIA Corp (nvidia.com - jbigler) +# +# Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# This code is licensed under the MIT License. See the FindCUDA.cmake script +# for the text of the license. + +# The MIT License +# +# SPDX-FileCopyrightText: Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: MIT +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +########################################################################## +# This file runs the nvcc commands to produce the desired output file along with +# the dependency file needed by CMake to compute dependencies. In addition the +# file checks the output of each command and if the command fails it deletes the +# output files. + +# Input variables +# +# verbose:BOOL=<> OFF: Be as quiet as possible (default) +# ON : Describe each step +# +# build_configuration:STRING=<> Typically one of Debug, MinSizeRel, Release, or +# RelWithDebInfo, but it should match one of the +# entries in CUDA_HOST_FLAGS. This is the build +# configuration used when compiling the code. If +# blank or unspecified Debug is assumed as this is +# what CMake does. +# +# generated_file:STRING=<> File to generate. This argument must be passed in. +# +# generated_cubin_file:STRING=<> File to generate. This argument must be passed +# in if build_cubin is true. +# generate_dependency_only:BOOL=<> Only generate the dependency file. +# +# check_dependencies:BOOL=<> Check the dependencies. If everything is up to +# date, simply touch the output file instead of +# generating it. + +# Support IN_LIST +cmake_policy(SET CMP0057 NEW) + +if(NOT generated_file) + message(FATAL_ERROR "You must specify generated_file on the command line") +endif() + +# Set these up as variables to make reading the generated file easier +set(CMAKE_COMMAND "@CMAKE_COMMAND@") # path +set(source_file "@source_file@") # path +set(NVCC_generated_dependency_file "@NVCC_generated_dependency_file@") # path +set(cmake_dependency_file "@cmake_dependency_file@") # path +set(CUDA_make2cmake "@CUDA_make2cmake@") # path +set(CUDA_parse_cubin "@CUDA_parse_cubin@") # path +set(build_cubin @build_cubin@) # bool +set(CUDA_HOST_COMPILER "@CUDA_HOST_COMPILER@") # path +# We won't actually use these variables for now, but we need to set this, in +# order to force this file to be run again if it changes. +set(generated_file_path "@generated_file_path@") # path +set(generated_file_internal "@generated_file@") # path +set(generated_cubin_file_internal "@generated_cubin_file@") # path + +set(CUDA_REMOVE_GLOBAL_MEMORY_SPACE_WARNING @CUDA_REMOVE_GLOBAL_MEMORY_SPACE_WARNING@) + +set(CUDA_NVCC_EXECUTABLE "@CUDA_NVCC_EXECUTABLE@") # path +set(CUDA_NVCC_FLAGS @CUDA_NVCC_FLAGS@ ;; @CUDA_WRAP_OPTION_NVCC_FLAGS@) # list +@CUDA_NVCC_FLAGS_CONFIG@ +set(nvcc_flags @nvcc_flags@) # list +set(CUDA_NVCC_INCLUDE_ARGS "@CUDA_NVCC_INCLUDE_ARGS@") # list (needs to be in quotes to handle spaces properly). +set(format_flag "@format_flag@") # string +set(cuda_language_flag @cuda_language_flag@) # list + +if(build_cubin AND NOT generated_cubin_file) + message(FATAL_ERROR "You must specify generated_cubin_file on the command line") +endif() + +# This is the list of host compilation flags. It C or CXX should already have +# been chosen by FindCUDA.cmake. +@CUDA_HOST_FLAGS@ + +# Take the compiler flags and package them up to be sent to the compiler via -Xcompiler +set(nvcc_host_compiler_flags "") +# If we weren't given a build_configuration, use Debug. +if(NOT build_configuration) + set(build_configuration Debug) +endif() +string(TOUPPER "${build_configuration}" build_configuration) +#message("CUDA_NVCC_HOST_COMPILER_FLAGS = ${CUDA_NVCC_HOST_COMPILER_FLAGS}") +foreach(flag ${CMAKE_HOST_FLAGS} ${CMAKE_HOST_FLAGS_${build_configuration}}) + # Extra quotes are added around each flag to help nvcc parse out flags with spaces. + if ("${nvcc_host_compiler_flags}" STREQUAL "") + set(nvcc_host_compiler_flags "\"${flag}\"") + else() + set(nvcc_host_compiler_flags "${nvcc_host_compiler_flags},\"${flag}\"") + endif() +endforeach() +if (nvcc_host_compiler_flags) + set(nvcc_host_compiler_flags "-Xcompiler" ${nvcc_host_compiler_flags}) +endif() +#message("nvcc_host_compiler_flags = \"${nvcc_host_compiler_flags}\"") + +set(depends_nvcc_host_compiler_flags "") +foreach(flag ${CMAKE_HOST_FLAGS} ) + # Extra quotes are added around each flag to help nvcc parse out flags with spaces. + if ("${depends_nvcc_host_compiler_flags}" STREQUAL "") + set(depends_nvcc_host_compiler_flags "\"${flag}\"") + else() + set(depends_nvcc_host_compiler_flags "${depends_nvcc_host_compiler_flags},\"${flag}\"") + endif() +endforeach() +if (depends_nvcc_host_compiler_flags) + set(depends_nvcc_host_compiler_flags "-Xcompiler" ${depends_nvcc_host_compiler_flags}) +endif() + +list(APPEND depends_CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS}) +# Add the build specific configuration flags +list(APPEND CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS_${build_configuration}}) + +# Any -ccbin existing in CUDA_NVCC_FLAGS gets highest priority +list( FIND CUDA_NVCC_FLAGS "-ccbin" ccbin_found0 ) +list( FIND CUDA_NVCC_FLAGS "--compiler-bindir" ccbin_found1 ) +if( ccbin_found0 LESS 0 AND ccbin_found1 LESS 0 AND CUDA_HOST_COMPILER ) + if (CUDA_HOST_COMPILER STREQUAL "@_CUDA_MSVC_HOST_COMPILER@" AND DEFINED CCBIN) + set(CCBIN -ccbin "${CCBIN}") + else() + set(CCBIN -ccbin "${CUDA_HOST_COMPILER}") + endif() +endif() + +# cuda_execute_process - Executes a command with optional command echo and status message. +# +# status - Status message to print if verbose is true +# command - COMMAND argument from the usual execute_process argument structure +# ARGN - Remaining arguments are the command with arguments +# +# CUDA_result - return value from running the command +# +# Make this a macro instead of a function, so that things like RESULT_VARIABLE +# and other return variables are present after executing the process. +macro(cuda_execute_process status command) + set(_command ${command}) + if(NOT "x${_command}" STREQUAL "xCOMMAND") + message(FATAL_ERROR "Malformed call to cuda_execute_process. Missing COMMAND as second argument. (command = ${command})") + endif() + # ARGN isn't like a normal variable in macros, so use a proxy variable that we can use instead. + set(_arguments ${ARGN}) + # nvcc warns when specifying -G and --lineinfo, which is annoying. + if("-G" IN_LIST _arguments) + list(REMOVE_ITEM _arguments "-lineinfo") + list(REMOVE_ITEM _arguments "--lineinfo") + endif() + if(verbose) + execute_process(COMMAND "${CMAKE_COMMAND}" -E echo -- ${status}) + # Now we need to build up our command string. We are accounting for quotes + # and spaces, anything else is left up to the user to fix if they want to + # copy and paste a runnable command line. + set(cuda_execute_process_string) + foreach(arg ${_arguments}) + # If there are quotes, excape them, so they come through. + string(REPLACE "\"" "\\\"" arg ${arg}) + # Args with spaces need quotes around them to get them to be parsed as a single argument. + if(arg MATCHES " ") + list(APPEND cuda_execute_process_string "\"${arg}\"") + else() + list(APPEND cuda_execute_process_string ${arg}) + endif() + endforeach() + # Echo the command + execute_process(COMMAND ${CMAKE_COMMAND} -E echo ${cuda_execute_process_string}) + endif() + # Run the command + execute_process(COMMAND ${_arguments} RESULT_VARIABLE CUDA_result ) +endmacro() + +# For CUDA 2.3 and below, -G -M doesn't work, so remove the -G flag +# for dependency generation and hope for the best. +set(CUDA_VERSION @CUDA_VERSION@) +if(CUDA_VERSION VERSION_LESS "3.0") + cmake_policy(PUSH) + # CMake policy 0007 NEW states that empty list elements are not + # ignored. I'm just setting it to avoid the warning that's printed. + cmake_policy(SET CMP0007 NEW) + # Note that this will remove all occurances of -G. + list(REMOVE_ITEM depends_CUDA_NVCC_FLAGS "-G") + cmake_policy(POP) +endif() + +# If we need to create relocatible code, the dependency phase doesn't like this argument. +# We need to filter it out here. +list(REMOVE_ITEM depends_CUDA_NVCC_FLAGS "-dc") +list(REMOVE_ITEM depends_CUDA_NVCC_FLAGS "--device-c") + +# nvcc doesn't define __CUDACC__ for some reason when generating dependency files. This +# can cause incorrect dependencies when #including files based on this macro which is +# defined in the generating passes of nvcc invokation. We will go ahead and manually +# define this for now until a future version fixes this bug. +set(CUDACC_DEFINE -D__CUDACC__) + + +if (check_dependencies) + set(rebuild FALSE) + include(${cmake_dependency_file}) + if(NOT CUDA_NVCC_DEPEND) + # CUDA_NVCC_DEPEND should have something useful in it by now. If not we + # should force the rebuild. + if (verbose) + message(WARNING "CUDA_NVCC_DEPEND not found for ${generated_file}") + endif() + set(rebuild TRUE) + endif() + # Rebuilding is also dependent on this file changing. + list(APPEND CUDA_NVCC_DEPEND "${CMAKE_CURRENT_LIST_FILE}") + foreach(f ${CUDA_NVCC_DEPEND}) + # True if file1 is newer than file2 or if one of the two files doesn't + # exist. Behavior is well-defined only for full paths. If the file time + # stamps are exactly the same, an IS_NEWER_THAN comparison returns true, so + # that any dependent build operations will occur in the event of a tie. This + # includes the case of passing the same file name for both file1 and file2. + if("${f}" IS_NEWER_THAN "${generated_file}") + #message("file ${f} is newer than ${generated_file}") + set(rebuild TRUE) + endif() + endforeach() + if (NOT rebuild) + #message("Not rebuilding ${generated_file}") + cuda_execute_process( + "Dependencies up to date. Not rebuilding ${generated_file}" + COMMAND "${CMAKE_COMMAND}" -E touch "${generated_file}" + ) + return() + endif() +endif() + + +# Generate the dependency file +cuda_execute_process( + "Generating dependency file: ${NVCC_generated_dependency_file}" + COMMAND "${CUDA_NVCC_EXECUTABLE}" + -M + ${CUDACC_DEFINE} + "${source_file}" + -o "${NVCC_generated_dependency_file}" + ${CCBIN} + ${nvcc_flags} + ${depends_nvcc_host_compiler_flags} + ${depends_CUDA_NVCC_FLAGS} + -DNVCC + ${CUDA_NVCC_INCLUDE_ARGS} + ) + +if(CUDA_result) + message(FATAL_ERROR "Error generating ${generated_file}") +endif() + +# Generate the cmake readable dependency file to a temp file. Don't put the +# quotes just around the filenames for the input_file and output_file variables. +# CMake will pass the quotes through and not be able to find the file. +cuda_execute_process( + "Generating temporary cmake readable file: ${cmake_dependency_file}.tmp" + COMMAND "${CMAKE_COMMAND}" + -D "input_file:FILEPATH=${NVCC_generated_dependency_file}" + -D "output_file:FILEPATH=${cmake_dependency_file}.tmp" + -P "${CUDA_make2cmake}" + ) + +if(CUDA_result) + message(FATAL_ERROR "Error generating ${generated_file}") +endif() + +# Copy the file if it is different +cuda_execute_process( + "Copy if different ${cmake_dependency_file}.tmp to ${cmake_dependency_file}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${cmake_dependency_file}.tmp" "${cmake_dependency_file}" + ) + +if(CUDA_result) + message(FATAL_ERROR "Error generating ${generated_file}") +endif() + +# Delete the temporary file +cuda_execute_process( + "Removing ${cmake_dependency_file}.tmp" + COMMAND "${CMAKE_COMMAND}" -E remove "${cmake_dependency_file}.tmp" + ) + +if(CUDA_result) + message(FATAL_ERROR "Error generating ${generated_file}") +endif() + +if (generate_dependency_only) + return() +endif() + + +if(CUDA_REMOVE_GLOBAL_MEMORY_SPACE_WARNING) + set(get_error ERROR_VARIABLE stderr) +endif() + +# Delete the target file +cuda_execute_process( + "Removing ${generated_file}" + COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}" + ) + +# Generate the code +cuda_execute_process( + "Generating ${generated_file}" + COMMAND "${CUDA_NVCC_EXECUTABLE}" + "${source_file}" + ${cuda_language_flag} + ${format_flag} -o "${generated_file}" + ${CCBIN} + ${nvcc_flags} + ${nvcc_host_compiler_flags} + ${CUDA_NVCC_FLAGS} + -DNVCC + ${CUDA_NVCC_INCLUDE_ARGS} + ${get_error} + ) + +if(get_error) + if(stderr) + # Filter out the annoying Advisory about pointer stuff. + # Advisory: Cannot tell what pointer points to, assuming global memory space + string(REGEX REPLACE "(^|\n)[^\n]*\(Advisory|Warning\): Cannot tell what pointer points to, assuming global memory space\n\n" "\\1" stderr "${stderr}") + + # Filter out warning we do not care about + string(REGEX REPLACE "(^|\n)[^\n]*: Warning: Function [^\n]* has a large return size, so overriding noinline attribute. The function may be inlined when called.\n\n" "\\1" stderr "${stderr}") + + # To be investigated (OP-1999) + string(REGEX REPLACE "(^|\n)[^\n]*: warning: function [^\n]*\n[^\n]*: here was declared deprecated \(.[^\n]* is not valid on compute_70 and above, and should be replaced with [^\n]*.To continue using [^\n]*, specify virtual architecture compute_60 when targeting sm_70 and above, for example, using the pair of compiler options.[^\n]*..\)\n( *detected during instantiation of [^\n]*\n[^\n]*: here\n)?( *detected during:\n( *instantiation of [^\n]*\n[^\n]*: here\n([^\n]*instantiation contexts not shown[^\n]*\n)?)+)?\n" "\\1" stderr "${stderr}") + string(REGEX REPLACE "(^|\n)[^\n]*: warning: function [^\n]*\n[^\n]*: here was declared deprecated \(.[^\n]* is deprecated in favor of [^\n]* and may be removed in a future release [^\n]*\)\n( *detected during instantiation of [^\n]*\n[^\n]*: here\n)?( *detected during:\n( *instantiation of [^\n]*\n[^\n]*: here\n([^\n]*instantiation contexts not shown[^\n]*\n)?)+)?\n" "\\1" stderr "${stderr}") + + # If there is error output, there is usually a stray newline at the end. Eliminate it if it is the only content of ${stderr}. + string(REGEX REPLACE "^\n$" "" stderr "${stderr}") + + if(stderr) + message("${stderr}") + endif() + endif() +endif() + +if(CUDA_result) + # Since nvcc can sometimes leave half done files make sure that we delete the output file. + cuda_execute_process( + "Removing ${generated_file}" + COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}" + ) + message(FATAL_ERROR "Error generating file ${generated_file}") +else() + if(verbose) + message("Generated ${generated_file} successfully.") + endif() +endif() + +# Cubin resource report commands. +if( build_cubin ) + # Run with -cubin to produce resource usage report. + cuda_execute_process( + "Generating ${generated_cubin_file}" + COMMAND "${CUDA_NVCC_EXECUTABLE}" + "${source_file}" + ${CUDA_NVCC_FLAGS} + ${nvcc_flags} + ${CCBIN} + ${nvcc_host_compiler_flags} + -DNVCC + -cubin + -o "${generated_cubin_file}" + ${CUDA_NVCC_INCLUDE_ARGS} + ) + + # Execute the parser script. + cuda_execute_process( + "Executing the parser script" + COMMAND "${CMAKE_COMMAND}" + -D "input_file:STRING=${generated_cubin_file}" + -P "${CUDA_parse_cubin}" + ) + +endif() diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA/select_compute_arch.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA/select_compute_arch.cmake new file mode 100644 index 00000000..5ce71a91 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindCUDA/select_compute_arch.cmake @@ -0,0 +1,195 @@ +# Synopsis: +# CUDA_SELECT_NVCC_ARCH_FLAGS(out_variable [target_CUDA_architectures]) +# -- Selects GPU arch flags for nvcc based on target_CUDA_architectures +# target_CUDA_architectures : Auto | Common | All | LIST(ARCH_AND_PTX ...) +# - "Auto" detects local machine GPU compute arch at runtime. +# - "Common" and "All" cover common and entire subsets of architectures +# ARCH_AND_PTX : NAME | NUM.NUM | NUM.NUM(NUM.NUM) | NUM.NUM+PTX +# NAME: Fermi Kepler Maxwell Kepler+Tegra Kepler+Tesla Maxwell+Tegra Pascal +# NUM: Any number. Only those pairs are currently accepted by NVCC though: +# 2.0 2.1 3.0 3.2 3.5 3.7 5.0 5.2 5.3 6.0 6.2 +# Returns LIST of flags to be added to CUDA_NVCC_FLAGS in ${out_variable} +# Additionally, sets ${out_variable}_readable to the resulting numeric list +# Example: +# CUDA_SELECT_NVCC_ARCH_FLAGS(ARCH_FLAGS 3.0 3.5+PTX 5.2(5.0) Maxwell) +# LIST(APPEND CUDA_NVCC_FLAGS ${ARCH_FLAGS}) +# +# More info on CUDA architectures: https://en.wikipedia.org/wiki/CUDA +# + +# This list will be used for CUDA_ARCH_NAME = All option +set(CUDA_KNOWN_GPU_ARCHITECTURES "Fermi" "Kepler" "Maxwell") + +# This list will be used for CUDA_ARCH_NAME = Common option (enabled by default) +set(CUDA_COMMON_GPU_ARCHITECTURES "3.0" "3.5" "5.0") + +if (CUDA_VERSION VERSION_GREATER "6.5") + list(APPEND CUDA_KNOWN_GPU_ARCHITECTURES "Kepler+Tegra" "Kepler+Tesla" "Maxwell+Tegra") + list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "5.2") +endif () + +if (CUDA_VERSION VERSION_GREATER "7.5") + list(APPEND CUDA_KNOWN_GPU_ARCHITECTURES "Pascal") + list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "6.0" "6.1" "6.1+PTX") +else() + list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "5.2+PTX") +endif () + + + +################################################################################################ +# A function for automatic detection of GPUs installed (if autodetection is enabled) +# Usage: +# CUDA_DETECT_INSTALLED_GPUS(OUT_VARIABLE) +# +function(CUDA_DETECT_INSTALLED_GPUS OUT_VARIABLE) + if(NOT CUDA_GPU_DETECT_OUTPUT) + set(cufile ${PROJECT_BINARY_DIR}/detect_cuda_archs.cu) + + file(WRITE ${cufile} "" + "#include \n" + "int main()\n" + "{\n" + " int count = 0;\n" + " if (cudaSuccess != cudaGetDeviceCount(&count)) return -1;\n" + " if (count == 0) return -1;\n" + " for (int device = 0; device < count; ++device)\n" + " {\n" + " cudaDeviceProp prop;\n" + " if (cudaSuccess == cudaGetDeviceProperties(&prop, device))\n" + " std::printf(\"%d.%d \", prop.major, prop.minor);\n" + " }\n" + " return 0;\n" + "}\n") + + execute_process(COMMAND "${CUDA_NVCC_EXECUTABLE}" "--run" "${cufile}" + WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/CMakeFiles/" + RESULT_VARIABLE nvcc_res OUTPUT_VARIABLE nvcc_out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(nvcc_res EQUAL 0) + string(REPLACE "2.1" "2.1(2.0)" nvcc_out "${nvcc_out}") + set(CUDA_GPU_DETECT_OUTPUT ${nvcc_out} CACHE INTERNAL "Returned GPU architetures from detect_gpus tool" FORCE) + endif() + endif() + + if(NOT CUDA_GPU_DETECT_OUTPUT) + message(STATUS "Automatic GPU detection failed. Building for common architectures.") + set(${OUT_VARIABLE} ${CUDA_COMMON_GPU_ARCHITECTURES} PARENT_SCOPE) + else() + set(${OUT_VARIABLE} ${CUDA_GPU_DETECT_OUTPUT} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################################ +# Function for selecting GPU arch flags for nvcc based on CUDA architectures from parameter list +# Usage: +# SELECT_NVCC_ARCH_FLAGS(out_variable [list of CUDA compute archs]) +function(CUDA_SELECT_NVCC_ARCH_FLAGS out_variable) + set(CUDA_ARCH_LIST "${ARGN}") + + if("X${CUDA_ARCH_LIST}" STREQUAL "X" ) + set(CUDA_ARCH_LIST "Auto") + endif() + + set(cuda_arch_bin) + set(cuda_arch_ptx) + + if("${CUDA_ARCH_LIST}" STREQUAL "All") + set(CUDA_ARCH_LIST ${CUDA_KNOWN_GPU_ARCHITECTURES}) + elseif("${CUDA_ARCH_LIST}" STREQUAL "Common") + set(CUDA_ARCH_LIST ${CUDA_COMMON_GPU_ARCHITECTURES}) + elseif("${CUDA_ARCH_LIST}" STREQUAL "Auto") + CUDA_DETECT_INSTALLED_GPUS(CUDA_ARCH_LIST) + message(STATUS "Autodetected CUDA architecture(s): ${CUDA_ARCH_LIST}") + endif() + + # Now process the list and look for names + string(REGEX REPLACE "[ \t]+" ";" CUDA_ARCH_LIST "${CUDA_ARCH_LIST}") + list(REMOVE_DUPLICATES CUDA_ARCH_LIST) + foreach(arch_name ${CUDA_ARCH_LIST}) + set(arch_bin) + set(add_ptx FALSE) + # Check to see if we are compiling PTX + if(arch_name MATCHES "(.*)\\+PTX$") + set(add_ptx TRUE) + set(arch_name ${CMAKE_MATCH_1}) + endif() + if(arch_name MATCHES "^([0-9]\\.[0-9](\\([0-9]\\.[0-9]\\))?)$") + set(arch_bin ${CMAKE_MATCH_1}) + set(arch_ptx ${arch_bin}) + else() + # Look for it in our list of known architectures + if(${arch_name} STREQUAL "Fermi") + set(arch_bin 2.0 "2.1(2.0)") + elseif(${arch_name} STREQUAL "Kepler+Tegra") + set(arch_bin 3.2) + elseif(${arch_name} STREQUAL "Kepler+Tesla") + set(arch_bin 3.7) + elseif(${arch_name} STREQUAL "Kepler") + set(arch_bin 3.0 3.5) + set(arch_ptx 3.5) + elseif(${arch_name} STREQUAL "Maxwell+Tegra") + set(arch_bin 5.3) + elseif(${arch_name} STREQUAL "Maxwell") + set(arch_bin 5.0 5.2) + set(arch_ptx 5.2) + elseif(${arch_name} STREQUAL "Pascal") + set(arch_bin 6.0 6.1) + set(arch_ptx 6.1) + else() + message(SEND_ERROR "Unknown CUDA Architecture Name ${arch_name} in CUDA_SELECT_NVCC_ARCH_FLAGS") + endif() + endif() + if(NOT arch_bin) + message(SEND_ERROR "arch_bin wasn't set for some reason") + endif() + list(APPEND cuda_arch_bin ${arch_bin}) + if(add_ptx) + if (NOT arch_ptx) + set(arch_ptx ${arch_bin}) + endif() + list(APPEND cuda_arch_ptx ${arch_ptx}) + endif() + endforeach() + + # remove dots and convert to lists + string(REGEX REPLACE "\\." "" cuda_arch_bin "${cuda_arch_bin}") + string(REGEX REPLACE "\\." "" cuda_arch_ptx "${cuda_arch_ptx}") + string(REGEX MATCHALL "[0-9()]+" cuda_arch_bin "${cuda_arch_bin}") + string(REGEX MATCHALL "[0-9]+" cuda_arch_ptx "${cuda_arch_ptx}") + + if(cuda_arch_bin) + list(REMOVE_DUPLICATES cuda_arch_bin) + endif() + if(cuda_arch_ptx) + list(REMOVE_DUPLICATES cuda_arch_ptx) + endif() + + set(nvcc_flags "") + set(nvcc_archs_readable "") + + # Tell NVCC to add binaries for the specified GPUs + foreach(arch ${cuda_arch_bin}) + if(arch MATCHES "([0-9]+)\\(([0-9]+)\\)") + # User explicitly specified ARCH for the concrete CODE + list(APPEND nvcc_flags -gencode arch=compute_${CMAKE_MATCH_2},code=sm_${CMAKE_MATCH_1}) + list(APPEND nvcc_archs_readable sm_${CMAKE_MATCH_1}) + else() + # User didn't explicitly specify ARCH for the concrete CODE, we assume ARCH=CODE + list(APPEND nvcc_flags -gencode arch=compute_${arch},code=sm_${arch}) + list(APPEND nvcc_archs_readable sm_${arch}) + endif() + endforeach() + + # Tell NVCC to add PTX intermediate code for the specified architectures + foreach(arch ${cuda_arch_ptx}) + list(APPEND nvcc_flags -gencode arch=compute_${arch},code=compute_${arch}) + list(APPEND nvcc_archs_readable compute_${arch}) + endforeach() + + string(REPLACE ";" " " nvcc_archs_readable "${nvcc_archs_readable}") + set(${out_variable} ${nvcc_flags} PARENT_SCOPE) + set(${out_variable}_readable ${nvcc_archs_readable} PARENT_SCOPE) +endfunction() diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindDX.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindDX.cmake new file mode 100644 index 00000000..05cf2b18 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindDX.cmake @@ -0,0 +1,42 @@ +IF (WIN32 AND MSVC_VERSION LESS 1700) + # Starting with Windows 8, the DirectX SDK is included as part of the Windows SDK + # (http://msdn.microsoft.com/en-us/library/windows/desktop/ee663275.aspx) + # and, in turn, Visual Studio 2012 (even Express) includes the appropriate components of the Windows SDK + # (http://msdn.microsoft.com/en-us/windows/desktop/hh852363.aspx) + # so we don't need a DX include path if we're targeting VS2012+ + + FIND_PATH(DX9_INCLUDE_PATH d3d9.h + HINTS + "$ENV{DXSDK_DIR}/Include" + "$ENV{PROGRAMFILES}/Microsoft DirectX SDK/Include" + DOC "The directory where d3d9.h resides") + FIND_PATH(DX10_INCLUDE_PATH D3D10.h + HINTS + "$ENV{DXSDK_DIR}/Include" + "$ENV{PROGRAMFILES}/Microsoft DirectX SDK/Include" + DOC "The directory where D3D10.h resides") + FIND_PATH(DX11_INCLUDE_PATH D3D11.h + HINTS + "$ENV{DXSDK_DIR}/Include" + "$ENV{PROGRAMFILES}/Microsoft DirectX SDK/Include" + DOC "The directory where D3D11.h resides") + + IF (DX9_INCLUDE_PATH) + SET( DX9_FOUND 1 ) + ELSE (DX9_INCLUDE_PATH) + SET( DX9_FOUND 0 ) + ENDIF (DX9_INCLUDE_PATH) + + IF (DX10_INCLUDE_PATH) + SET( DX10_FOUND 1 ) + ELSE (DX10_INCLUDE_PATH) + SET( DX10_FOUND 0 ) + ENDIF (DX10_INCLUDE_PATH) + + IF (DX11_INCLUDE_PATH) + SET( DX11_FOUND 1 ) + ELSE (DX11_INCLUDE_PATH) + SET( DX11_FOUND 0 ) + ENDIF (DX11_INCLUDE_PATH) +ENDIF (WIN32 AND MSVC_VERSION LESS 1700) + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindNVTX.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindNVTX.cmake new file mode 100644 index 00000000..a6ec3ff5 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindNVTX.cmake @@ -0,0 +1,53 @@ +# +# Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA Corporation and its licensors retain all intellectual property and proprietary +# rights in and to this software, related documentation and any modifications thereto. +# Any use, reproduction, disclosure or distribution of this software and related +# documentation without an express license agreement from NVIDIA Corporation is strictly +# prohibited. +# +# TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* +# AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, +# INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY +# SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT +# LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF +# BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR +# INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGES +# + +# Output variables: +# NVTX_FOUND +# NVTX_INCLUDE_DIR + +if( WIN32 ) + # On Windows, the NVTX headers are in the include directory of the CUDA Toolkit + find_path( NVTX_INCLUDE_DIR + NAMES device_functions.h + PATHS + ${CUDA_TOOLKIT_ROOT_DIR} + ENV CUDA_PATH + ENV CUDA_INC_PATH + PATH_SUFFIXES include + NO_DEFAULT_PATH + ) +elseif( UNIX ) + # On Linux, the NVTX headers are in a separate 'targets' directory + find_path( NVTX_INCLUDE_DIR + NAMES nvToolsExt.h + PATHS + ${CUDA_TOOLKIT_ROOT_DIR}/targets/x86_64-linux/include + ENV CUDA_PATH + ENV CUDA_INC_PATH + PATH_SUFFIXES include + NO_DEFAULT_PATH + ) +endif() + +if( NVTX_INCLUDE_DIR ) + set( NVTX_FOUND TRUE ) +endif() + +mark_as_advanced( NVTX_INCLUDE_DIR ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindOpenEXR.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindOpenEXR.cmake new file mode 100644 index 00000000..c8a2d19f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindOpenEXR.cmake @@ -0,0 +1,170 @@ +# +# Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA Corporation and its licensors retain all intellectual property and proprietary +# rights in and to this software, related documentation and any modifications thereto. +# Any use, reproduction, disclosure or distribution of this software and related +# documentation without an express license agreement from NVIDIA Corporation is strictly +# prohibited. +# +# TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* +# AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, +# INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY +# SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT +# LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF +# BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR +# INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGES +# + +# Find OpenEXR package. + +# Optional input variable: OpenEXR_ROOT +# Output variables: +# OpenEXR_FOUND +# OpenEXR_IMATH_INCLUDE_DIR (3.1+) +# OpenEXR_INCLUDE_DIR +# OpenEXR_LIBRARIES +# OpenEXR_VERSION + +if( OpenEXR_FOUND ) + return() +endif() + +# Find OpenEXR includes. +find_path( OpenEXR_INCLUDE_DIR OpenEXRConfig.h + PATHS "${OpenEXR_ROOT}/include/OpenEXR" NO_DEFAULT_PATH ) +if( NOT OpenEXR_INCLUDE_DIR ) + find_path( OpenEXR_INCLUDE_DIR ImfOutputFile.h + HINTS "${OpenEXR_ROOT}/include/OpenEXR" + PATH_SUFFIXES OpenEXR + ) +endif() +mark_as_advanced( OpenEXR_INCLUDE_DIR ) + +# We cannot proceed if the headers are not found +if( NOT OpenEXR_INCLUDE_DIR ) + return() +endif() + +# Get version number from header, which we need for the library names. +set( OpenEXR_VERSION "" CACHE STRING "OpenEXR version string" ) +set( CONFIG_H "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h" ) +if( NOT OpenEXR_VERSION AND EXISTS "${CONFIG_H}" ) + message( "Reading OpenEXR version from ${CONFIG_H}" ) + file( STRINGS "${CONFIG_H}" VERSION_STRING + REGEX "#define OPENEXR_VERSION_STRING" ) + string( REGEX REPLACE ".*\"([0-9.]+)\".*" "\\1" VERSION_STRING "${VERSION_STRING}" ) + set( OpenEXR_VERSION "${VERSION_STRING}" CACHE STRING "OpenEXR version string" FORCE ) +endif() +string( REGEX REPLACE "^([0-9]+).*" "\\1" VERSION_MAJOR "${OpenEXR_VERSION}" ) +string( REGEX REPLACE "^[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${OpenEXR_VERSION}" ) +set( VERSION_SUFFIX "${VERSION_MAJOR}_${VERSION_MINOR}" ) + +if( ${OpenEXR_VERSION} VERSION_GREATER_EQUAL "3.1.0" ) + set( OpenEXR_LIB_NAMES OpenEXR OpenEXRCore Iex Imath IlmThread ) +else() + set( OpenEXR_LIB_NAMES IlmImf Half Iex Imath IlmThread ) +endif() + +if( ${OpenEXR_VERSION} VERSION_GREATER_EQUAL "3.1.0" ) + # Find Imath includes (OpenEXR 3.1+). + find_path( OpenEXR_IMATH_INCLUDE_DIR ImathMath.h + PATHS "${OpenEXR_ROOT}/include/Imath" NO_DEFAULT_PATH ) + mark_as_advanced( OpenEXR_IMATH_INCLUDE_DIR ) +endif() + +# Allow location of library directory to be overridden. +set( OpenEXR_LIB_DIR "${OpenEXR_ROOT}/lib" CACHE PATH "Path to OpenEXR libraries" ) +mark_as_advanced( OpenEXR_LIB_DIR ) + +# Find OpenEXR libraries. +set( OpenEXR_LIBRARIES "" ) +foreach( LIB ${OpenEXR_LIB_NAMES} ) + find_library( OpenEXR_${LIB}_RELEASE + NAMES "${LIB}-${VERSION_SUFFIX}_s" "${LIB}-${VERSION_SUFFIX}" "${LIB}_s" "${LIB}" + HINTS "${OpenEXR_LIB_DIR}" ) + mark_as_advanced( OpenEXR_${LIB}_RELEASE ) + if( OpenEXR_${LIB}_RELEASE ) + list( APPEND OpenEXR_LIBRARIES optimized "${OpenEXR_${LIB}_RELEASE}" ) + endif() + + find_library( OpenEXR_${LIB}_DEBUG + NAMES "${LIB}-${VERSION_SUFFIX}_s_d" "${LIB}-${VERSION_SUFFIX}_d" "${LIB}_s_d" "${LIB}_d" + HINTS "${OpenEXR_LIB_DIR}" ) + mark_as_advanced( OpenEXR_${LIB}_DEBUG ) + if( OpenEXR_${LIB}_DEBUG ) + list( APPEND OpenEXR_LIBRARIES debug "${OpenEXR_${LIB}_DEBUG}" ) + elseif( OpenEXR_${LIB}_RELEASE ) + # Fallback: use release libraries if no debug libraries were found. + list( APPEND OpenEXR_LIBRARIES debug "${OpenEXR_${LIB}_RELEASE}" ) + endif() +endforeach( LIB ) + +include( FindPackageHandleStandardArgs ) + +# find_package_handle_standard_args reports the value of the first variable +# on success, so make sure this is the actual OpenEXR library +if( ${OpenEXR_VERSION} VERSION_GREATER_EQUAL "3.1.0" ) + find_package_handle_standard_args( OpenEXR + REQUIRED_VARS + OpenEXR_OpenEXR_RELEASE OpenEXR_Iex_RELEASE OpenEXR_Imath_RELEASE OpenEXR_IlmThread_RELEASE + OpenEXR_INCLUDE_DIR OpenEXR_IMATH_INCLUDE_DIR + VERSION_VAR OpenEXR_VERSION ) +else() + find_package_handle_standard_args( OpenEXR + REQUIRED_VARS + OpenEXR_IlmImf_RELEASE OpenEXR_Half_RELEASE OpenEXR_Iex_RELEASE OpenEXR_Imath_RELEASE OpenEXR_IlmThread_RELEASE + OpenEXR_INCLUDE_DIR + VERSION_VAR OpenEXR_VERSION ) +endif() + +foreach( LIB ${OpenEXR_LIB_NAMES} ) + if( OpenEXR_${LIB}_RELEASE ) + set( target OpenEXR::${LIB} ) + # Remap IlmImf to OpenEXR to unify the exported targets between old and new versions + if( ${LIB} STREQUAL IlmImf ) + set( target OpenEXR::OpenEXR ) + endif() + add_library( ${target} STATIC IMPORTED ) + if( WIN32 ) + set_target_properties( ${target} PROPERTIES + IMPORTED_LOCATION_RELEASE ${OpenEXR_${LIB}_RELEASE} + IMPORTED_LOCATION_DEBUG ${OpenEXR_${LIB}_DEBUG} + MAP_IMPORTED_CONFIG_MINSIZEREL Release + MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release ) + # We don't have PDB files for debug builds, so ignore + # LNK4099 PDB 'filename' was not found with 'object/library' or at 'path'; linking object as if no debug info + set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_OPTIONS $<$:/ignore:4099> ) + else() + if( ${OpenEXR_${LIB}_DEBUG} ) + set_target_properties( ${target} PROPERTIES + IMPORTED_LOCATION ${OpenEXR_${LIB}_RELEASE} + IMPORTED_LOCATION_DEBUG ${OpenEXR_${LIB}_DEBUG} + MAP_IMPORTED_CONFIG_MINSIZEREL "" + MAP_IMPORTED_CONFIG_RELWITHDEBINFO "" ) + else() + set_target_properties( ${target} PROPERTIES + IMPORTED_LOCATION ${OpenEXR_${LIB}_RELEASE} + MAP_IMPORTED_CONFIG_DEBUG "" + MAP_IMPORTED_CONFIG_MINSIZEREL "" + MAP_IMPORTED_CONFIG_RELWITHDEBINFO "" ) + endif() + endif() + if( ${OpenEXR_VERSION} VERSION_GREATER_EQUAL "3.1.0" ) + set_property( TARGET ${target} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${OpenEXR_INCLUDE_DIR} ${OpenEXR_IMATH_INCLUDE_DIR} ) + else() + set_property( TARGET ${target} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${OpenEXR_INCLUDE_DIR} ) + endif() + endif() +endforeach() + +# Record the library dependencies for OpenEXR on the other OpenEXR libraries +if( OpenEXR_OpenEXR_RELEASE AND ${OpenEXR_VERSION} VERSION_GREATER_EQUAL "3.1.0") + set_property( TARGET OpenEXR::OpenEXR PROPERTY INTERFACE_LINK_LIBRARIES + OpenEXR::OpenEXRCore OpenEXR::Iex OpenEXR::Imath OpenEXR::IlmThread ) +elseif( OpenEXR_IlmImf_RELEASE AND OpenEXR_IlmThread_RELEASE ) + set_property( TARGET OpenEXR::OpenEXR PROPERTY INTERFACE_LINK_LIBRARIES + OpenEXR::Half OpenEXR::Iex OpenEXR::Imath OpenEXR::IlmThread ) +endif() diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindOptiX.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindOptiX.cmake new file mode 100644 index 00000000..b2920656 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindOptiX.cmake @@ -0,0 +1,79 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2010 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Locate the OptiX distribution. Search relative to the SDK first, then look in the system. + +# Our initial guess will be within the SDK. +set(OptiX_INSTALL_DIR "${CMAKE_SOURCE_DIR}/../" CACHE PATH "Path to OptiX installed location.") + +# The distribution contains only 64 bit libraries. Error when we have been mis-configured. +if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8) + if(WIN32) + message(SEND_ERROR "Make sure when selecting the generator, you select one with Win64 or x64.") + endif() + message(FATAL_ERROR "OptiX only supports builds configured for 64 bits.") +endif() + +# search path based on the bit-ness of the build. (i.e. 64: bin64, lib64; 32: +# bin, lib). Note that on Mac, the OptiX library is a universal binary, so we +# only need to look in lib and not lib64 for 64 bit builds. +if(NOT APPLE) + set(bit_dest "64") +else() + set(bit_dest "") +endif() + +# Include +find_path(OptiX_INCLUDE + NAMES optix.h + PATHS "${OptiX_INSTALL_DIR}/include" + NO_DEFAULT_PATH + ) +find_path(OptiX_INCLUDE + NAMES optix.h + ) + +# Check to make sure we found what we were looking for +function(OptiX_report_error error_message required component ) + if(DEFINED OptiX_FIND_REQUIRED_${component} AND NOT OptiX_FIND_REQUIRED_${component}) + set(required FALSE) + endif() + if(OptiX_FIND_REQUIRED AND required) + message(FATAL_ERROR "${error_message} Please locate before proceeding.") + else() + if(NOT OptiX_FIND_QUIETLY) + message(STATUS "${error_message}") + endif(NOT OptiX_FIND_QUIETLY) + endif() +endfunction() + +if(NOT OptiX_INCLUDE) + OptiX_report_error("OptiX headers (optix.h and friends) not found." TRUE headers ) +endif() + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindZlibStatic.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindZlibStatic.cmake new file mode 100644 index 00000000..0db4d01b --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/FindZlibStatic.cmake @@ -0,0 +1,83 @@ +# +# Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA Corporation and its licensors retain all intellectual property and proprietary +# rights in and to this software, related documentation and any modifications thereto. +# Any use, reproduction, disclosure or distribution of this software and related +# documentation without an express license agreement from NVIDIA Corporation is strictly +# prohibited. +# +# TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* +# AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, +# INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY +# SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT +# LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF +# BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR +# INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGES +# + +# This is a wrapper for FindZLIB that returns the static library instead of the DSO/DLL. + +# Optional input variable: ZlibStatic_ROOT +# Output variables: +# ZlibStatic_FOUND +# ZlibStatic_INCLUDE_DIR +# ZlibStatic_LIBRARIES +# ZlibStatic_VERSION + +# FindZLIB honors ZLIB_ROOT, but the lack of a pre-existing cache entry for it is not user-friendly. +set( ZlibStatic_ROOT "" CACHE PATH "Path to Zlib installation directory" ) +if( ZlibStatic_ROOT AND NOT ZLIB_ROOT ) + set( ZLIB_ROOT "${ZlibStatic_ROOT}" CACHE PATH "Path to Zlib installation directory" FORCE ) + unset( ZLIB_INCLUDE_DIR CACHE ) + unset( ZLIB_LIBRARY_RELEASE CACHE ) + unset( ZLIB_LIBRARY_DEBUG CACHE ) +endif() + +find_package( ZLIB ) +if( NOT ZLIB_FOUND OR NOT ZLIB_LIBRARY_RELEASE ) + return() +endif() + +# Verify that zlibstatic exists alongside the zlib library. +get_filename_component( LIB_DIR ${ZLIB_LIBRARY_RELEASE} DIRECTORY ) + +get_filename_component( LIB_FILE_RELEASE ${ZLIB_LIBRARY_RELEASE} NAME ) +string( REGEX REPLACE "zlib" "zlibstatic" LIB_FILE_RELEASE "${LIB_FILE_RELEASE}" ) +file( GLOB ZlibStatic_LIBRARY_RELEASE "${LIB_DIR}/${LIB_FILE_RELEASE}" ) + +if( ZLIB_LIBRARY_DEBUG ) + get_filename_component( LIB_FILE_DEBUG ${ZLIB_LIBRARY_DEBUG} NAME ) + string( REGEX REPLACE "zlib" "zlibstatic" LIB_FILE_DEBUG "${LIB_FILE_DEBUG}" ) + file( GLOB ZlibStatic_LIBRARY_DEBUG "${LIB_DIR}/${LIB_FILE_DEBUG}" ) +else() + # Fall back on release library if debug library is not found. + set( ZlibStatic_LIBRARY_DEBUG "${ZlibStatic_LIBRARY_RELEASE}" + CACHE FILEPATH "Path to debug Zlib library" ) +endif() + +if ( ZlibStatic_LIBRARY_RELEASE AND ZlibStatic_LIBRARY_DEBUG ) + set( ZlibStatic_LIBRARIES "optimized;${ZlibStatic_LIBRARY_RELEASE};debug;${ZlibStatic_LIBRARY_DEBUG}" + CACHE STRING "Zlib static libraries" ) +endif() +set( ZlibStatic_INCLUDE_DIR "${ZLIB_INCLUDE_DIR}" + CACHE PATH "Path to Zlib include directory" ) +set( ZlibStatic_VERSION "${ZLIB_VERSION_STRING}" + CACHE STRING "Zlib version number" ) + +find_package_handle_standard_args( ZlibStatic + REQUIRED_VARS + ZlibStatic_LIBRARY_RELEASE + ZlibStatic_INCLUDE_DIR + VERSION_VAR ZlibStatic_VERSION ) + +if( ZlibStatic_FOUND ) + add_library( Zlib::Static STATIC IMPORTED ) + set_target_properties( Zlib::Static PROPERTIES + # Use the release configuration by default + IMPORTED_LOCATION ${ZlibStatic_LIBRARY_RELEASE} + IMPORTED_LOCATION_DEBUG ${ZlibStatic_LIBRARY_DEBUG} ) + set_property( TARGET Zlib::Static APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${ZLIB_INCLUDE_DIR} ) +endif() diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/LinuxCPUInfo.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/LinuxCPUInfo.cmake new file mode 100644 index 00000000..4f551b0d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/LinuxCPUInfo.cmake @@ -0,0 +1,51 @@ + +# +# Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA Corporation and its licensors retain all intellectual property and proprietary +# rights in and to this software, related documentation and any modifications thereto. +# Any use, reproduction, disclosure or distribution of this software and related +# documentation without an express license agreement from NVIDIA Corporation is strictly +# prohibited. +# +# TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* +# AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, +# INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY +# SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT +# LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF +# BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR +# INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGES +# + +IF(EXISTS "/proc/cpuinfo") + + FILE(READ /proc/cpuinfo PROC_CPUINFO) + + SET(VENDOR_ID_RX "vendor_id[ \t]*:[ \t]*([a-zA-Z]+)\n") + STRING(REGEX MATCH "${VENDOR_ID_RX}" VENDOR_ID "${PROC_CPUINFO}") + STRING(REGEX REPLACE "${VENDOR_ID_RX}" "\\1" VENDOR_ID "${VENDOR_ID}") + + SET(CPU_FAMILY_RX "cpu family[ \t]*:[ \t]*([0-9]+)") + STRING(REGEX MATCH "${CPU_FAMILY_RX}" CPU_FAMILY "${PROC_CPUINFO}") + STRING(REGEX REPLACE "${CPU_FAMILY_RX}" "\\1" CPU_FAMILY "${CPU_FAMILY}") + + SET(MODEL_RX "model[ \t]*:[ \t]*([0-9]+)") + STRING(REGEX MATCH "${MODEL_RX}" MODEL "${PROC_CPUINFO}") + STRING(REGEX REPLACE "${MODEL_RX}" "\\1" MODEL "${MODEL}") + + SET(FLAGS_RX "flags[ \t]*:[ \t]*([a-zA-Z0-9 _]+)\n") + STRING(REGEX MATCH "${FLAGS_RX}" FLAGS "${PROC_CPUINFO}") + STRING(REGEX REPLACE "${FLAGS_RX}" "\\1" FLAGS "${FLAGS}") + + # Debug output. + IF(LINUX_CPUINFO) + MESSAGE(STATUS "LinuxCPUInfo.cmake:") + MESSAGE(STATUS "VENDOR_ID : ${VENDOR_ID}") + MESSAGE(STATUS "CPU_FAMILY : ${CPU_FAMILY}") + MESSAGE(STATUS "MODEL : ${MODEL}") + MESSAGE(STATUS "FLAGS : ${FLAGS}") + ENDIF(LINUX_CPUINFO) + +ENDIF(EXISTS "/proc/cpuinfo") diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/Macros.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/Macros.cmake new file mode 100644 index 00000000..f0f7e192 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/Macros.cmake @@ -0,0 +1,1065 @@ + +# +# Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA Corporation and its licensors retain all intellectual property and proprietary +# rights in and to this software, related documentation and any modifications thereto. +# Any use, reproduction, disclosure or distribution of this software and related +# documentation without an express license agreement from NVIDIA Corporation is strictly +# prohibited. +# +# TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* +# AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, +# INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY +# SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT +# LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF +# BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR +# INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGES +# + +# Appends VAL to the string contained in STR +MACRO(APPEND_TO_STRING STR VAL) + if (NOT "${ARGN}" STREQUAL "") + message(SEND_ERROR "APPEND_TO_STRING takes only a single argument to append. Offending args: ${ARGN}") + endif() + # You need to double ${} STR to get the value. The first one gets + # the variable, the second one gets the value. + if (${STR}) + set(${STR} "${${STR}} ${VAL}") + else() + set(${STR} "${VAL}") + endif() +ENDMACRO(APPEND_TO_STRING) + +# Prepends VAL to the string contained in STR +MACRO(PREPEND_TO_STRING STR VAL) + if (NOT "${ARGN}" STREQUAL "") + message(SEND_ERROR "PREPEND_TO_STRING takes only a single argument to append. Offending args: ${ARGN}") + endif() + # You need to double ${} STR to get the value. The first one gets + # the variable, the second one gets the value. + if (${STR}) + set(${STR} "${VAL} ${${STR}}") + else() + set(${STR} "${VAL}") + endif() +ENDMACRO(PREPEND_TO_STRING) + +# Prepends a prefix to items in a list and appends the result to list_out +macro( prepend list_out prefix ) + set( _results ) + foreach( str ${ARGN} ) + list( APPEND _results "${prefix}${str}" ) + endforeach() + list( APPEND ${list_out} ${_results} ) +endmacro() + + +################################################################# +# FORCE_ADD_FLAGS(parameter flags) +# +# This will add arguments not found in ${parameter} to the end. It +# does not attempt to remove duplicate arguments already existing in +# ${parameter}. +################################################################# +MACRO(FORCE_ADD_FLAGS parameter) + # Create a separated list of the arguments to loop over + SET(p_list ${${parameter}}) + SEPARATE_ARGUMENTS(p_list) + # Make a copy of the current arguments in ${parameter} + SET(new_parameter ${${parameter}}) + # Now loop over each required argument and see if it is in our + # current list of arguments. + FOREACH(required_arg ${ARGN}) + # This helps when we get arguments to the function that are + # grouped as a string: + # + # ["-msse -msse2"] instead of [-msse -msse2] + SET(TMP ${required_arg}) #elsewise the Seperate command doesn't work) + SEPARATE_ARGUMENTS(TMP) + FOREACH(option ${TMP}) + # Look for the required argument in our list of existing arguments + SET(found FALSE) + FOREACH(p_arg ${p_list}) + IF (${p_arg} STREQUAL ${option}) + SET(found TRUE) + ENDIF (${p_arg} STREQUAL ${option}) + ENDFOREACH(p_arg) + IF(NOT found) + # The required argument wasn't found, so we need to add it in. + SET(new_parameter "${new_parameter} ${option}") + ENDIF(NOT found) + ENDFOREACH(option ${TMP}) + ENDFOREACH(required_arg ${ARGN}) + SET(${parameter} ${new_parameter} CACHE STRING "" FORCE) +ENDMACRO(FORCE_ADD_FLAGS) + +# This MACRO is designed to set variables to default values only on +# the first configure. Subsequent configures will produce no ops. +MACRO(FIRST_TIME_SET VARIABLE VALUE TYPE COMMENT) + IF(NOT PASSED_FIRST_CONFIGURE) + SET(${VARIABLE} ${VALUE} CACHE ${TYPE} ${COMMENT} FORCE) + ENDIF(NOT PASSED_FIRST_CONFIGURE) +ENDMACRO(FIRST_TIME_SET) + +MACRO(FIRST_TIME_MESSAGE) + IF(NOT PASSED_FIRST_CONFIGURE) + MESSAGE(${ARGV}) + ENDIF(NOT PASSED_FIRST_CONFIGURE) +ENDMACRO(FIRST_TIME_MESSAGE) + +# Used by ll_to_cpp and bc_to_cpp +find_file(bin2cpp_cmake bin2cpp.cmake ${CMAKE_MODULE_PATH} ) +set(bin2cpp_cmake "${bin2cpp_cmake}" CACHE INTERNAL "Path to internal bin2cpp.cmake" FORCE) + +# Converts input_ll file to llvm bytecode encoded as a string in the outputSource file +# defined with the export symbol provided. +function(ll_to_cpp input outputSource outputInclude exportSymbol) + # message("input = ${input}") + # message("outputSource = ${outputSource}") + # message("outputInclude = ${outputInclude}") + # message("exportSymbol = ${exportSymbol}") + get_filename_component(outputABS "${outputSource}" ABSOLUTE ) + get_filename_component(outputDir "${outputSource}" PATH ) + get_filename_component(outputName "${outputSource}" NAME ) + file(RELATIVE_PATH outputRelPath "${CMAKE_BINARY_DIR}" "${outputDir}") + + set(bc_filename "${outputName}.tmp.bc") + + # Generate header file (configure time) + include(bin2cpp) + bin2h(${outputInclude} ${exportSymbol} "${bc_filename}") + + # Convert ll to byte code + add_custom_command( + OUTPUT ${outputSource} + + # convert ll to bc + COMMAND ${LLVM_llvm-as} "${input}" -o "${bc_filename}" + # convert bc file to cpp + COMMAND ${CMAKE_COMMAND} -DCUDA_BIN2C_EXECUTABLE:STRING="${CUDA_BIN2C_EXECUTABLE}" + -DCPP_FILE:STRING="${outputSource}" + -DCPP_SYMBOL:STRING="${exportSymbol}" + -DSOURCE_BASE:STRING="${outputDir}" + -DSOURCES:STRING="${bc_filename}" + -P "${bin2cpp_cmake}" + # Remove temp bc file + COMMAND ${CMAKE_COMMAND} -E remove -f "${bc_filename}" + + WORKING_DIRECTORY ${outputDir} + MAIN_DEPENDENCY ${input} + DEPENDS ${bin2cpp_cmake} + COMMENT "Generating ${outputRelPath}/${outputName}" + ) +endfunction() + +function(bc_to_cpp input outputSource outputInclude exportSymbol) + # message("input = ${input}") + # message("outputSource = ${outputSource}") + # message("outputInclude = ${outputInclude}") + # message("exportSymbol = ${exportSymbol}") + get_filename_component(outputABS "${outputSource}" ABSOLUTE ) + get_filename_component(outputDir "${outputABS}" PATH ) + get_filename_component(outputName "${outputABS}" NAME ) + file(RELATIVE_PATH outputRelPath "${EXTERNAL_BINARY_DIR}" "${outputDir}") + get_filename_component(inputABS "${input}" ABSOLUTE) + get_filename_component(inputDir "${inputABS}" PATH) + get_filename_component(inputName "${inputABS}" NAME) + + set(bc_filename "${inputName}") + + # Generate header file (configure time) + include(bin2cpp) + bin2h(${outputInclude} ${exportSymbol} "${bc_filename}") + + # Convert ll to byte code + add_custom_command( + OUTPUT ${outputSource} + + # convert bc file to cpp + COMMAND ${CMAKE_COMMAND} -DCUDA_BIN2C_EXECUTABLE:STRING="${CUDA_BIN2C_EXECUTABLE}" + -DCPP_FILE:STRING="${outputSource}" + -DCPP_SYMBOL:STRING="${exportSymbol}" + -DSOURCE_BASE:STRING="${inputDir}" + -DSOURCES:STRING="${bc_filename}" + -P "${bin2cpp_cmake}" + + WORKING_DIRECTORY ${outputDir} + MAIN_DEPENDENCY ${input} + DEPENDS ${bin2cpp_cmake} + COMMENT "Generating ${outputRelPath}/${outputName}" + ) +endfunction() + +################################################################################ +# Compile the cpp file using clang, run an optimization pass and use bin2c to take the +# resulting code and embed it into a cpp for loading at runtime. +# +# Usage: compile_llvm_runtime( input symbol symbol output_var [clang args] ) +# input : [in] File to be compiled by clang +# symbol : [in] Name of C symbol to use for accessing the generated code. Also used to generate the output file names. +# output_var : [out] Generated cpp and header files used to access compiled code at runtime +# clang args : [in] list of arguments to clang +# + +function(compile_llvm_runtime input symbol output_var) + set(OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") + get_filename_component(base "${input}" NAME_WE) + get_filename_component(name "${input}" NAME) + + set(bc "${OUTPUT_DIR}/${base}.bc") + set(opt_bc "${OUTPUT_DIR}/${base}_opt.bc") + set(opt_ll "${OUTPUT_DIR}/${base}_opt.ll") + add_custom_command( OUTPUT ${bc} ${opt_bc} ${opt_ll} + COMMAND ${LLVM_TOOLS_BINARY_DIR}/clang ${input} -o ${bc} ${ARGN} + COMMAND ${LLVM_TOOLS_BINARY_DIR}/opt ${bc} -o ${opt_bc} -always-inline -mem2reg -scalarrepl + COMMAND ${LLVM_TOOLS_BINARY_DIR}/llvm-dis ${opt_bc} -o ${opt_ll} + COMMENT "Compiling ${name} to ${base}_opt.ll" + WORKING_DIRECTORY "${OUTPUT_DIR}" + MAIN_DEPENDENCY "${input}" + ) + + set(bin2c_files + "${CMAKE_CURRENT_BINARY_DIR}/${symbol}.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${symbol}.h" + ) + #bc_to_cpp(${opt_bc} ${bin2c_files} ${symbol}) + ll_to_cpp(${opt_ll} ${bin2c_files} ${symbol}) + + set_source_files_properties( ${bin2c_files} PROPERTIES GENERATED TRUE ) + + set(${output_var} ${bin2c_files} PARENT_SCOPE) +endfunction() + + +################################################################################ +# Assemble the ll file to bitcode using llvm-as and use bin2c to take the +# resulting code and embed it into a cpp for loading at runtime. +# +# Usage: compile_llvm( input symbol symbol output_var [clang args] ) +# input : [in] File to be assembled +# symbol : [in] Name of C symbol to use for accessing the generated code. Also used to generate the output file names. +# output_var : [out] Generated cpp and header files used to access compiled code at runtime +# + +function(assemble_llvm input symbol output_var) + set(OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") + get_filename_component(base "${input}" NAME_WE) + get_filename_component(name "${input}" NAME) + + set(bin2c_files + "${CMAKE_CURRENT_BINARY_DIR}/${symbol}.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${symbol}.h" + ) + #bc_to_cpp(${opt_bc} ${bin2c_files} ${symbol}) + ll_to_cpp(${input} ${bin2c_files} ${symbol}) + + set_source_files_properties( ${bin2c_files} PROPERTIES GENERATED TRUE ) + + set(${output_var} ${bin2c_files} PARENT_SCOPE) +endfunction() + +################################################################################ +# Compile the cpp file using clang +# +# Usage: cpp_to_bc( input output_var [clang args] ) +# input : [in] File to be compiled by clang +# output_var : [out] Generated bc file +# clang args : [in] list of arguments to clang +# + +function(cpp_to_bc input output_var) + set(OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") + get_filename_component(base "${input}" NAME_WE) + get_filename_component(name "${input}" NAME) + + set(bc "${OUTPUT_DIR}/${base}.bc") + add_custom_command( OUTPUT ${bc} + COMMAND ${LLVM_TOOLS_BINARY_DIR}/clang ${input} -c -o ${bc} ${ARGN} + COMMENT "Compiling ${name} to ${base}.bc" + WORKING_DIRECTORY "${OUTPUT_DIR}" + MAIN_DEPENDENCY "${input}" + ) + + set(${output_var} ${bc} PARENT_SCOPE) +endfunction() + +################################################################################ +# Copy ptx scripts into a string in a cpp header file. +# +# Usage: ptx_to_cpp( ptx_cpp_headers my_directory FILE1 FILE2 ... FILEN ) +# ptx_cpp_files : [out] List of cpp files created (Note: new files are appended to this list) +# directory : [in] Directory in which to place the resulting headers +# FILE1 .. FILEN : [in] ptx files to be cpp stringified +# +# FILE1 -> filename: ${FILE1}_ptx.cpp +# -> string : const char* nvrt::${FILE1}_ptx = "..."; + +macro( ptx_to_cpp ptx_cpp_files directory ) + foreach( file ${ARGN} ) + if( ${file} MATCHES ".*\\.ptx$" ) + + #message( "file_name : ${file}" ) + + # Create the output cpp file name + get_filename_component( base_name ${file} NAME_WE ) + set( cpp_filename ${directory}/${base_name}_ptx.cpp ) + set( variable_name ${base_name}_ptx ) + set( ptx2cpp ${CMAKE_SOURCE_DIR}/CMake/ptx2cpp.cmake ) + + #message( "base_name : ${base_name}" ) + #message( "cpp_file_name : ${cpp_filename}" ) + #message( "variable_name : ${variable_name}" ) + + add_custom_command( OUTPUT ${cpp_filename} + COMMAND ${CMAKE_COMMAND} + -DCUDA_BIN2C_EXECUTABLE:STRING="${CUDA_BIN2C_EXECUTABLE}" + -DCPP_FILE:STRING="${cpp_filename}" + -DPTX_FILE:STRING="${file}" + -DVARIABLE_NAME:STRING=${variable_name} + -DNAMESPACE:STRING=optix + -P ${ptx2cpp} + DEPENDS ${file} + DEPENDS ${ptx2cpp} + COMMENT "${ptx2cpp}: converting ${file} to ${cpp_filename}" + ) + + list(APPEND ${ptx_cpp_files} ${cpp_filename} ) + #message( "ptx_cpp_files : ${${ptx_cpp_files}}" ) + + endif( ${file} MATCHES ".*\\.ptx$" ) + endforeach( file ) +endmacro( ptx_to_cpp ) + + +################################################################################ +# Strip library of all local symbols +# +# Usage: strip_symbols( target ) +# target : [out] target name for the library to be stripped + +function( strip_symbols target ) + if( NOT WIN32 ) + add_custom_command( TARGET ${target} + POST_BUILD + # using -x to strip all local symbols + COMMAND ${CMAKE_STRIP} -x $ + COMMENT "Stripping symbols from ${target}" + ) + endif() +endfunction( strip_symbols ) + +################################################################################ +# Only export the symbols that we need. +# +# Usage: optix_setup_exports( target export_file hidden_file ) +# target : [in] target name for the library to be stripped +# export_file : [in] name of the file that contains the export symbol names +# hidden_file : [in] name of the file that contains the hidden symbol names. +# Might be empty string in which all non-exported symbols +# are hidden. Only used for UNIX and NOT APPLE. +# +# Do not use this macro with WIN32 DLLs unless you are not using the dllexport +# macros. The DLL name will be set using the SOVERSION property of the target, +# so be sure to set that before calling this macro +# +function( optix_setup_exports target export_file hidden_file) + # Suck in the exported symbol list. It should define exported_symbols. + include(${export_file}) + # Suck in the hidden symbol list unless hidden_file is empty. It should + # definde hidden_symbols. + if (NOT "${hidden_file}" STREQUAL "") + include(${hidden_file}) + endif() + + if( UNIX ) + if ( APPLE ) + # -exported_symbols_list lists the exact set of symbols to export. You can call it + # more than once if needed. + set( export_arg -exported_symbols_list ) + else() + # -Bsymbolic tells the linker to resolve any local symbols locally first. + # --version-script allows us to be explicit about which symbols to export. + set( export_arg -Bsymbolic,--version-script ) + endif() + + # Create the symbol export file. Since Apple and Linux have different file formats + # for doing this we will have to specify the information in the file differently. + set(exported_symbol_file ${CMAKE_CURRENT_BINARY_DIR}/${target}_exported_symbols.txt) + if(APPLE) + # The base name of the symbols just has the name. We need to prefix them with "_". + set(modified_symbols) + foreach(symbol ${exported_symbols}) + list(APPEND modified_symbols "_${symbol}") + endforeach() + # Just list the symbols. One per line. Since we are treating the list as a string + # here we can replace the ';' character with a newline. + string(REPLACE ";" "\n" exported_symbol_file_content "${modified_symbols}") + file(WRITE ${exported_symbol_file} "${exported_symbol_file_content}\n") + else() + # Format is: + # + # { + # global: + # extern "C" { + # exported_symbol; + # }; + # local: + # hidden_symbol; // or "*"; + # }; + # Just list the symbols. One per line. Since we are treating the list as a string + # here we can insert the newline after the ';' character. + string(REPLACE ";" ";\n" exported_symbol_file_content "${exported_symbols}") + if (NOT "${hidden_file}" STREQUAL "") + string(REPLACE ";" ";\n" hidden_symbol_file_content "${hidden_symbols}") + else() + set( hidden_symbol_file_content "*" ) + endif() + file(WRITE ${exported_symbol_file} "{\nglobal:\nextern \"C\" {\n${exported_symbol_file_content};\n};\nlocal:\n${hidden_symbol_file_content};\n};\n") + endif() + + # Add the command to the LINK_FLAGS + set_property( TARGET ${target} + APPEND_STRING + PROPERTY LINK_FLAGS + " -Wl,${export_arg},${exported_symbol_file}" + ) + elseif( WIN32 ) + set(exported_symbol_file ${CMAKE_CURRENT_BINARY_DIR}/${target}.def) + set(name ${target} ) + get_property( abi_version TARGET ${target} PROPERTY SOVERSION ) + if( abi_version ) + set(name "${name}.${abi_version}") + endif() + # Format is: + # + # NAME + # EXPORTS + # + # + string(REPLACE ";" "\n" def_file_content "${exported_symbols}" ) + file(WRITE ${exported_symbol_file} "NAME ${name}.dll\nEXPORTS\n${def_file_content}") + + # Add the command to the LINK_FLAGS + set_property( TARGET ${target} + APPEND_STRING + PROPERTY LINK_FLAGS + " /DEF:${exported_symbol_file}" + ) + endif() + + # Make sure that if the exported_symbol_file changes we relink the library. + set_property( TARGET ${target} + APPEND + PROPERTY LINK_DEPENDS + "${exported_symbol_file}" + ) +endfunction() + +################################################################################ +# Some helper functions for pushing and popping variable values +# +function(push_variable variable) + #message("push before: ${variable} = ${${variable}}, ${variable}_STACK = ${${variable}_STACK}") + #message(" ARGN = ${ARGN}") + #message(" ARGC = ${ARGC}, ARGV = ${ARGV}") + if(ARGC LESS 2) + message(FATAL_ERROR "push_variable requires at least one value to push.") + endif() + # Because the old value may be a list, we need to indicate how many items + # belong to this push. We do this by marking the start of the new push. + list(LENGTH ${variable}_STACK start_index) + # If the value of variable is empty, then we need to leave a placeholder, + # because CMake doesn't have an "empty" token. + if (DEFINED ${variable} AND NOT ${variable} STREQUAL "") + list(APPEND ${variable}_STACK ${${variable}} ${start_index}) + else() + list(APPEND ${variable}_STACK ${variable}_EMPTY ${start_index}) + endif() + # Make the stack visible outside of the function's scope. + set(${variable}_STACK ${${variable}_STACK} PARENT_SCOPE) + # Set the new value of the variable. + set(${variable} ${ARGN} PARENT_SCOPE) + #set(${variable} ${ARGN}) # use for the output message below + #message("push after : ${variable} = ${${variable}}, ${variable}_STACK = ${${variable}_STACK}") +endfunction() + +function(pop_variable variable) + #message("pop before: ${variable} = ${${variable}}, ${variable}_STACK = ${${variable}_STACK}") + # Find the length of the stack to use as an index to the end of the list. + list(LENGTH ${variable}_STACK stack_length) + if(stack_length LESS 2) + message(FATAL_ERROR "${variable}_STACK is empty. Can't pop any more values.") + endif() + math(EXPR stack_end "${stack_length} - 1") + # Get the start of where the old value begins in the stack. + list(GET ${variable}_STACK ${stack_end} variable_start) + math(EXPR variable_end "${stack_end} - 1") + foreach(index RANGE ${variable_start} ${variable_end}) + list(APPEND list_indices ${index}) + endforeach() + list(GET ${variable}_STACK ${list_indices} stack_popped) + # If the first element is our special EMPTY token, then we should empty it out + if(stack_popped STREQUAL "${variable}_EMPTY") + set(stack_popped "") + endif() + # Remove all the items + list(APPEND list_indices ${stack_end}) + list(REMOVE_AT ${variable}_STACK ${list_indices}) + # Make sthe stack visible outside of the function's scope. + set(${variable}_STACK ${${variable}_STACK} PARENT_SCOPE) + # Assign the old value to the variable + set(${variable} ${stack_popped} PARENT_SCOPE) + #set(${variable} ${stack_popped}) # use for the output message below + #message("pop after : ${variable} = ${${variable}}, ${variable}_STACK = ${${variable}_STACK}") +endfunction() + + +# Helper function to generate ptx for a particular sm versions. +# +# sm_versions[input]: a list of version, such as sm_13;sm_20. These will be used to +# generate the names of the output files. +# generate_files[output]: list of generated source files +# ARGN[input]: list of input CUDA C files and other options to pass to nvcc. +# +function(compile_ptx sm_versions_in generated_files) + # CUDA_GET_SOURCES_AND_OPTIONS is a FindCUDA internal command that we are going to + # borrow. There are no guarantees on backward compatibility using this macro. + CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) + # Check to see if they specified an sm version, and spit out an error. + list(FIND _options -arch arch_index) + if(arch_index GREATER -1) + math(EXPR sm_index "${arch_index}+1") + list(GET _options ${sm_index} sm_value) + message(FATAL_ERROR "-arch ${sm_value} has been specified to compile_ptx. Please remove that option and put it in the sm_versions argument.") + endif() + set(${generated_files}) + set(sm_versions ${sm_versions_in}) + if(NOT CUDA_SM_20) + list(REMOVE_ITEM sm_versions sm_20) + endif() + push_variable(CUDA_64_BIT_DEVICE_CODE ON) + foreach(source ${_sources}) + set(ptx_generated_files) + #message("\n\nProcessing ${source}") + foreach(sm ${sm_versions}) + + # Generate the 32 bit ptx for 32 bit builds and when the CMAKE_OSX_ARCHITECTURES + # specifies it. + list(FIND CMAKE_OSX_ARCHITECTURES i386 osx_build_32_bit_ptx) + if( CMAKE_SIZEOF_VOID_P EQUAL 4 OR NOT osx_build_32_bit_ptx LESS 0) + set(CUDA_64_BIT_DEVICE_CODE OFF) + CUDA_WRAP_SRCS( ptx_${sm}_32 PTX _generated_files ${source} ${_cmake_options} + OPTIONS -arch ${sm} ${_options} + ) + # Add these files onto the list of files. + list(APPEND ptx_generated_files ${_generated_files}) + endif() + + # Generate the 64 bit ptx for 64 bit builds and when the CMAKE_OSX_ARCHITECTURES + # specifies it. + list(FIND CMAKE_OSX_ARCHITECTURES x86_64 osx_build_64_bit_ptx) + if( CMAKE_SIZEOF_VOID_P EQUAL 8 OR NOT osx_build_64_bit_ptx LESS 0) + set(CUDA_64_BIT_DEVICE_CODE ON) + CUDA_WRAP_SRCS( ptx_${sm}_64 PTX _generated_files ${source} ${_cmake_options} + OPTIONS -arch ${sm} ${_options} + ) + # Add these files onto the list of files. + list(APPEND ptx_generated_files ${_generated_files}) + endif() + endforeach() + + get_filename_component(source_basename "${source}" NAME_WE) + set(cpp_wrap "${CMAKE_CURRENT_BINARY_DIR}/${source_basename}_ptx.cpp") + set(h_wrap "${CMAKE_CURRENT_BINARY_DIR}/${source_basename}_ptx.h") + + set(relative_ptx_generated_files) + foreach(file ${ptx_generated_files}) + get_filename_component(fname "${file}" NAME) + list(APPEND relative_ptx_generated_files "${fname}") + endforeach() + + # Now generate a target that will generate the wrapped version of the ptx + # files at build time + set(symbol "${source_basename}_source") + add_custom_command( OUTPUT ${cpp_wrap} + COMMAND ${CMAKE_COMMAND} -DCUDA_BIN2C_EXECUTABLE:STRING="${CUDA_BIN2C_EXECUTABLE}" + -DCPP_FILE:STRING="${cpp_wrap}" + -DCPP_SYMBOL:STRING="${symbol}" + -DSOURCE_BASE:STRING="${CMAKE_CURRENT_BINARY_DIR}" + -DSOURCES:STRING="${relative_ptx_generated_files}" + ARGS -P "${CMAKE_SOURCE_DIR}/CMake/bin2cpp.cmake" + DEPENDS ${CMAKE_SOURCE_DIR}/CMake/bin2cpp.cmake ${ptx_generated_files} + ) + # We know the list of files at configure time, so generate the files here + include(bin2cpp) + bin2h("${h_wrap}" ${symbol} ${relative_ptx_generated_files}) + + list(APPEND ${generated_files} ${ptx_generated_files} ${cpp_wrap} ${h_wrap}) + endforeach(source) + pop_variable(CUDA_64_BIT_DEVICE_CODE) + + set(${generated_files} ${${generated_files}} PARENT_SCOPE) +endfunction() + +# Helper function to generate the appropiate options for a CUDA compile +# based on the target architectures. +# +# Function selects the higher compute capability available and generates code for that one. +# +# Usage: cuda_generate_runtime_target_options( output_var target_list ) +# +# output[output] is a list-variable to fill with options for CUDA_COMPILE +# ARGN[input] is a list of targets, i.e. sm_11 sm_20 sm_30 +# NO_PTX in the input list will not add PTX to the highest SM version + +function( cuda_generate_runtime_target_options output ) + # remove anything that is not sm_XX, and look for NO_PTX option + set( no_ptx FALSE ) + foreach(target ${ARGN}) + string( REGEX MATCH "^(sm_[0-9][0-9])$" match ${target} ) + if( NOT CMAKE_MATCH_1 ) + list( REMOVE_ITEM ARGN ${target} ) + endif( NOT CMAKE_MATCH_1 ) + if( target STREQUAL "NO_PTX" ) + set( no_ptx TRUE ) + endif() + endforeach(target) + + list( LENGTH ARGN valid_target_count ) + if( valid_target_count GREATER 0 ) + +# We will add compute_XX automatically, infer max compatible compute capability. + # check targets for max compute capability + set( smver_max "0" ) + foreach(target ${ARGN}) + string( REGEX MATCH "sm_([0-9][0-9])$" sm_ver_match ${target} ) + if( CMAKE_MATCH_1 ) + if( ${CMAKE_MATCH_1} STRGREATER smver_max ) + set( smver_max ${CMAKE_MATCH_1} ) + endif( ${CMAKE_MATCH_1} STRGREATER smver_max ) + endif( CMAKE_MATCH_1 ) + unset( sm_ver_match ) + endforeach(target) + + if( no_ptx ) + set( smver_max "You can't match me, I'm the ginger bread man!" ) + endif() + + # copy the input list to a new one and sort it + set( sm_versions ${ARGN} ) + list( SORT sm_versions ) + + # walk to SM versions to generate the entries of gencode + set( options "" ) + foreach( sm_ver ${sm_versions} ) + string( REGEX MATCH "sm_([0-9][0-9])$" sm_ver_num ${sm_ver} ) + +# This adds compute_XX automatically, in order to generate PTX. + if( ${CMAKE_MATCH_1} STREQUAL ${smver_max} ) + # append the max compute capability, to get compute_XX too. + # this appends the PTX code for the higher SM_ version + set(entry -gencode=arch=compute_${CMAKE_MATCH_1},code=\\\"${sm_ver},compute_${smver_max}\\\") + else( ${CMAKE_MATCH_1} STREQUAL ${smver_max} ) + set(entry -gencode=arch=compute_${CMAKE_MATCH_1},code=\\\"${sm_ver}\\\") + endif( ${CMAKE_MATCH_1} STREQUAL ${smver_max} ) + list( APPEND options ${entry} ) + endforeach( sm_ver ${sm_versions} ) + + # return the generated option string + set( ${output} ${options} PARENT_SCOPE ) + + unset( smver_max ) + unset( sm_versions ) + else( valid_target_count GREATER 0 ) + # return empty string + set( ${output} "" PARENT_SCOPE ) + endif( valid_target_count GREATER 0 ) + +endfunction(cuda_generate_runtime_target_options) + + +# Compile the list of SASS assembler files to cubins. +# Then take the resulting file and store it in a cpp file using bin2c. +# +# Usage: compile_sass_to_cpp( _generated_files files [files...] [OPTIONS ...] ) +# +# _generated_files[output] is a list-variable to fill with the names of the generated files +# ARGN[input] is a list of files and nvasm_internal options. + +function(compile_sass_to_cpp _generated_files ) + # CUDA_GET_SOURCES_AND_OPTIONS is a FindCUDA internal command that we are going to + # borrow. There are no guarantees on backward compatibility using this macro. + CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) + + set(generated_files) + foreach(source ${_sources}) + + get_filename_component(source_basename ${source} NAME_WE) + set(cubinfile ${CMAKE_CURRENT_BINARY_DIR}/${source_basename}.cubin) + + set(source ${CMAKE_CURRENT_SOURCE_DIR}/${source}) + + set(cuda_build_comment_string "Assembling to cubin file ${source}" ) + set_source_files_properties(${source} PROPERTIES HEADER_FILE_ONLY TRUE) + + add_custom_command(OUTPUT ${cubinfile} + COMMAND ${CUDA_NVASM_EXECUTABLE} ${_options} ${source} -o ${cubinfile} + DEPENDS ${source} + COMMENT "${cuda_build_comment_string}" + ) + + set(cpp_wrap "${CMAKE_CURRENT_BINARY_DIR}/${source_basename}_cuda.cpp") + set(h_wrap "${CMAKE_CURRENT_BINARY_DIR}/${source_basename}_cuda.h") + + get_filename_component(generated_file_path "${cubinfile}" DIRECTORY) + get_filename_component(relative_cuda_generated_file "${cubinfile}" NAME) + + # Now generate a target that will generate the wrapped version of the cuda + # files at build time + set(symbol "${source_basename}_cuda_source") + add_custom_command( OUTPUT ${cpp_wrap} + COMMAND ${CMAKE_COMMAND} -DCUDA_BIN2C_EXECUTABLE:STRING="${CUDA_BIN2C_EXECUTABLE}" + -DCPP_FILE:STRING="${cpp_wrap}" + -DCPP_SYMBOL:STRING="${symbol}" + -DSOURCE_BASE:STRING="${generated_file_path}" + -DSOURCES:STRING="${relative_cuda_generated_file}" + ARGS -P "${CMAKE_SOURCE_DIR}/CMake/bin2cpp.cmake" + DEPENDS ${CMAKE_SOURCE_DIR}/CMake/bin2cpp.cmake ${cubinfile} + ) + # We know the list of files at configure time, so generate the files here + include(bin2cpp) + bin2h("${h_wrap}" ${symbol} ${relative_cuda_generated_files}) + + list(APPEND generated_files ${cubinfile} ${cpp_wrap} ${h_wrap}) + + endforeach() + + set_source_files_properties(${generated_files} PROPERTIES GENERATED TRUE) + set(${_generated_files} ${generated_files} PARENT_SCOPE) +endfunction() + + +# Compile the list of cuda files using the specified format. Then take the resulting file +# and store it in a cpp file using bin2c. This is not appropriate for PTX formats. Use +# compile_ptx for that. +# +# Usage: compile_cuda_to_cpp( target_name format _generated_files files [files...] [OPTIONS ...] ) +# +# target_name[input] name to use for mangling output files. +# format[input] OBJ SEPARABLE_OBJ CUBIN FATBIN +# _generated_files[output] is a list-variable to fill with the names of the generated files +# ARGN[input] is a list of files and optional CUDA_WRAP_SRCS options. See documentation +# for CUDA_WRAP_SRCS in FindCUDA.cmake. + +function(compile_cuda_to_cpp target_name format _generated_files) + # CUDA_GET_SOURCES_AND_OPTIONS is a FindCUDA internal command that we are going to + # borrow. There are no guarantees on backward compatibility using this macro. + CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) + + if(${format} MATCHES "SEPARABLE_OBJ") + # It's OK to set this without resetting it later, since this is a function with a + # localized scope. + set(CUDA_SEPARABLE_COMPILATION ON) + set(format OBJ) + elseif(${format} MATCHES "PTX") + message(FATAL_ERROR "compile_cuda_to_cpp called with PTX format which is unsupported. Try compile_ptx instead.") + endif() + + set(${_generated_files}) + foreach(source ${_sources}) + CUDA_WRAP_SRCS(${target_name} ${format} objfile ${source} OPTIONS ${_options} ) + + get_filename_component(source_basename "${source}" NAME_WE) + set(cpp_wrap "${CMAKE_CURRENT_BINARY_DIR}/${source_basename}_cuda.cpp") + set(h_wrap "${CMAKE_CURRENT_BINARY_DIR}/${source_basename}_cuda.h") + + get_filename_component(generated_file_path "${objfile}" DIRECTORY) + get_filename_component(relative_cuda_generated_file "${objfile}" NAME) + + # Now generate a target that will generate the wrapped version of the cuda + # files at build time + set(symbol "${source_basename}_cuda_source") + add_custom_command( OUTPUT ${cpp_wrap} + COMMAND ${CMAKE_COMMAND} -DCUDA_BIN2C_EXECUTABLE:STRING="${CUDA_BIN2C_EXECUTABLE}" + -DCPP_FILE:STRING="${cpp_wrap}" + -DCPP_SYMBOL:STRING="${symbol}" + -DSOURCE_BASE:STRING="${generated_file_path}" + -DSOURCES:STRING="${relative_cuda_generated_file}" + ARGS -P "${CMAKE_SOURCE_DIR}/CMake/bin2cpp.cmake" + DEPENDS ${CMAKE_SOURCE_DIR}/CMake/bin2cpp.cmake ${objfile} + ) + # We know the list of files at configure time, so generate the files here + include(bin2cpp) + bin2h("${h_wrap}" ${symbol} ${relative_cuda_generated_files}) + + list(APPEND ${_generated_files} ${objfile} ${cpp_wrap} ${h_wrap}) + endforeach() + set(${_generated_files} ${${_generated_files}} PARENT_SCOPE) +endfunction() + +# Compile the list of cuda files using the specified format. Then take the resulting file +# and store it in a cpp file using bin2c. Appends the variant name to the source file name. +# +# Usage: compile_cuda_to_cpp_variant( target_name variant_name format _generated_files files [files...] [OPTIONS ...] ) +# +# target_name[input] name to use for mangling output files. +# variant_name[input] name to append to filenames. +# format[input] OBJ SEPARABLE_OBJ CUBIN FATBIN +# _generated_files[output] is a list-variable to fill with the names of the generated files +# ARGN[input] is a list of files and optional CUDA_WRAP_SRCS options. See documentation +# for CUDA_WRAP_SRCS in FindCUDA.cmake. + +function(compile_cuda_to_cpp_variant target_name variant_name format _generated_files) + # CUDA_GET_SOURCES_AND_OPTIONS is a FindCUDA internal command that we are going to + # borrow. There are no guarantees on backward compatibility using this macro. + CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) + + if(${format} MATCHES "SEPARABLE_OBJ") + # It's OK to set this without resetting it later, since this is a function with a + # localized scope. + set(CUDA_SEPARABLE_COMPILATION ON) + set(format OBJ) + elseif(${format} MATCHES "PTX") + message(FATAL_ERROR "compile_cuda_to_cpp called with PTX format which is unsupported. Try compile_ptx instead.") + endif() + + set(${_generated_files}) + foreach(source ${_sources}) + get_filename_component(source_basename "${source}" NAME_WE) + + CUDA_WRAP_SRCS(${target_name}_${variant_name} ${format} objfile ${source} OPTIONS ${_options} ) + + set(cpp_wrap "${CMAKE_CURRENT_BINARY_DIR}/${source_basename}_${variant_name}_cuda.cpp") + set(h_wrap "${CMAKE_CURRENT_BINARY_DIR}/${source_basename}_${variant_name}_cuda.h") + + get_filename_component(generated_file_path "${objfile}" DIRECTORY) + get_filename_component(relative_cuda_generated_file "${objfile}" NAME) + + # Now generate a target that will generate the wrapped version of the cuda + # files at build time + set(symbol "${source_basename}_${variant_name}_cuda_source") + add_custom_command( OUTPUT ${cpp_wrap} + COMMAND ${CMAKE_COMMAND} -DCUDA_BIN2C_EXECUTABLE:STRING="${CUDA_BIN2C_EXECUTABLE}" + -DCPP_FILE:STRING="${cpp_wrap}" + -DCPP_SYMBOL:STRING="${symbol}" + -DSOURCE_BASE:STRING="${generated_file_path}" + -DSOURCES:STRING="${relative_cuda_generated_file}" + ARGS -P "${CMAKE_SOURCE_DIR}/CMake/bin2cpp.cmake" + DEPENDS ${CMAKE_SOURCE_DIR}/CMake/bin2cpp.cmake ${objfile} + ) + # We know the list of files at configure time, so generate the files here + include(bin2cpp) + bin2h("${h_wrap}" ${symbol} ${relative_cuda_generated_files}) + + list(APPEND ${_generated_files} ${objfile} ${cpp_wrap} ${h_wrap}) + endforeach() + set(${_generated_files} ${${_generated_files}} PARENT_SCOPE) +endfunction() + +# Compile the list of ptx files. Then take the resulting file +# and store it in a cpp file using bin2c. +# + +function(compile_ptx_to_cpp input_ptx _generated_files extra_dependencies ) + get_filename_component(source_ptx "${input_ptx}" REALPATH ) + get_filename_component(source_basename "${source_ptx}" NAME_WE) + message("source_ptx ${source_ptx}") + message("source_basename ${source_basename}") + set(fatbin ${CMAKE_CURRENT_BINARY_DIR}/${source_basename}.fatbin) + set(build_directory "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles") + + # the source is passed in as the first parameter + # use this function to easily extract options + CUDA_GET_SOURCES_AND_OPTIONS( _ptx_wrap_sources _ptx_wrap_cmake_options _ptx_wrap_options ${ARGN}) + + # extract all macro definitions so we can pass these to the c preprocessor + string(REGEX MATCHALL "-D[A-z_][A-z_0-9]*(=[A-z_0-9]*)?" macros ${ARGN}) + + set(fatbin_command) + set(cubin_commands) + + if (MSVC) + set(preprocess_command CL /nologo /E /EP) + elseif(CMAKE_COMPILER_IS_GNUCC) + set(preprocess_command gcc -P -E -x assembler-with-cpp ) + else() + message(FATAL_ERROR "Unknown preprocessor command") + endif() + + foreach(cuda_sm_target ${cuda_sm_targets}) + string(REGEX REPLACE "sm_" "" cuda_sm "${cuda_sm_target}") + + # Take input PTX and generate cubin + set(preprocessed_ptx ${build_directory}/${source_basename}.${cuda_sm}.ptx) + set(cubin ${build_directory}/${source_basename}.${cuda_sm}.cubin) + + list(APPEND cubin_commands + COMMAND ${preprocess_command} -DPTXAS ${macros} ${PTXAS_INCLUDES} -D__CUDA_TARGET__=${cuda_sm} -D__CUDA_ARCH__=${cuda_sm}0 ${source_ptx} > ${preprocessed_ptx} + COMMAND ${CUDA_NVCC_EXECUTABLE} ${_ptx_wrap_options} -arch=sm_${cuda_sm} --cubin ${preprocessed_ptx} -dc -o ${cubin} + ) + list(APPEND fatbin_command "--image=profile=sm_${cuda_sm},file=${cubin}") + endforeach() + + add_custom_command( + OUTPUT ${fatbin} + ${cubin_commands} + COMMAND ${CUDA_FATBINARY_EXECUTABLE} --create="${fatbin}" -64 -c --cmdline="" ${fatbin_command} + MAIN_DEPENDENCY ${source_ptx} + DEPENDS ${extra_dependencies} + ) + + set(cpp_wrap "${CMAKE_CURRENT_BINARY_DIR}/${source_basename}.cpp") + set(h_wrap "${CMAKE_CURRENT_BINARY_DIR}/${source_basename}.h") + get_filename_component(generated_file_path "${fatbin}" DIRECTORY) + get_filename_component(relative_generated_file "${fatbin}" NAME) + + set(symbol "${source_basename}") + add_custom_command( OUTPUT ${cpp_wrap} + COMMAND ${CMAKE_COMMAND} -DCUDA_BIN2C_EXECUTABLE:STRING="${CUDA_BIN2C_EXECUTABLE}" + -DCPP_FILE:STRING="${cpp_wrap}" + -DCPP_SYMBOL:STRING="${symbol}" + -DSOURCE_BASE:STRING="${generated_file_path}" + -DSOURCES:STRING="${relative_generated_file}" + ARGS -P "${bin2cpp_cmake}" + DEPENDS ${CMAKE_SOURCE_DIR}/CMake/bin2cpp.cmake ${fatbin} + ) + + bin2h("${h_wrap}" "${symbol}" "${relative_generated_file}") + + set(${_generated_files} ${cpp_wrap} ${h_wrap} PARENT_SCOPE) +endfunction() + +# Create multiple bitness targets for mac universal builds +# +# Usage: OPTIX_MAKE_UNIVERSAL_CUDA_RUNTIME_OBJECTS( +# target_name +# generated_files_var +# FILE0.cu FILE1.cu ... FILEN.cu +# OPTIONS +# option1 option2 +# ) +# +# target_name [input ] name prefix for the resulting files +# generated_files [output] list of filenames of resulting object files +# ARGN [input ] is a list of source files plus possibly options +function( OPTIX_MAKE_UNIVERSAL_CUDA_RUNTIME_OBJECTS target_name generated_files ) + + # If you specified CMAKE_OSX_ARCHITECTURES that means you want a universal build (though + # this should work for a single architecture). + if (CMAKE_OSX_ARCHITECTURES) + set(cuda_files) + + push_variable(CUDA_64_BIT_DEVICE_CODE OFF) + list(LENGTH CMAKE_OSX_ARCHITECTURES num_arches) + if (num_arches GREATER 1) + # If you have more than one architecture then you don't want to attach the build rule + # to the file itself otherwise you could compile some files in multiple targets. + set(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE OFF) + endif() + foreach(arch ${CMAKE_OSX_ARCHITECTURES}) + # Set the bitness of the build specified by nvcc to the one matching the OSX + # architecture. + if (arch STREQUAL "i386") + set(CUDA_64_BIT_DEVICE_CODE OFF) + elseif (arch STREQUAL "x86_64") + set(CUDA_64_BIT_DEVICE_CODE ON) + else() + message(SEND_ERROR "Unknown OSX arch ${arch}") + endif() + + CUDA_WRAP_SRCS( + ${target_name}_${arch} + OBJ + cuda_sources + ${ARGN} + ) + list( APPEND cuda_files ${cuda_sources} ) + endforeach() + pop_variable(CUDA_64_BIT_DEVICE_CODE) + + else() + CUDA_WRAP_SRCS( + ${target_name} + OBJ + cuda_files + ${ARGN} + ) + endif() + + set( ${generated_files} ${cuda_files} PARENT_SCOPE ) +endfunction() + +################################################################ +# Simple debugging function for printing the value of a variable +# +# USAGE: print_var( +# var +# msg (optional) +# ) +function(print_var var) + set(msg "") + if (ARGC GREATER 1) + set(msg "${ARGV1}\n ") + endif() + message("${msg}${var}:${${var}}") +endfunction() + +################################################################ +# Function for adding a list of files from a subdirectory. Also adds an IDE source group. +# +# dir - name of the sub directory +# source_list_var - name of the variable to set the list of sources to +# ARGN - list of sources relative to the sub directory +function(optix_add_subdirectory_sources dir source_list_var) + set(files ${ARGN}) + set(sources) + string( REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" rel_dir ${dir} ) + + foreach(filename ${files}) + if(NOT IS_ABSOLUTE ${filename}) + set(filename ${rel_dir}/${filename}) + endif() + list(APPEND sources ${filename}) + endforeach() + + # Make a source group + string( REPLACE "/" "\\\\" group_name ${rel_dir} ) + if( group_name ) + source_group( ${group_name} FILES ${sources} ) + endif() + + set(${source_list_var} ${sources} PARENT_SCOPE) +endfunction() + +################################################################ +# optixSharedLibraryResources +# +# Handle common logic for Windows resource script generation for shared +# libraries. The variable 'resourceFiles' is set on the parent scope for +# use in add_library. +# +# outputName - The value to assign to 'output_name' in the parent scope +# and used to locate the resource script template to configure. +# +# Side effects: +# +# output_name - Value to be used for the OUTPUT_NAME property of the target. +# resourceFiles - List of resource files to be added to the target. +# +macro( optixSharedLibraryResources outputName ) + set( resourceFiles ) + set( output_name ${outputName} ) + if( WIN32 ) + # On Windows, we want the version number in the DLL filename. + # Windows ignores the SOVERSION property and only uses the OUTPUT_NAME property. + # Linux puts the version number in the filename from the SOVERSION property. + # We need to adjust this variable before we call configure_file. + set( output_name "${outputName}.${OPTIX_SO_VERSION}" ) + configure_file( "${outputName}.rc.in" "${outputName}.rc" @ONLY ) + set( resourceFiles "${CMAKE_CURRENT_BINARY_DIR}/${outputName}.rc" "${CMAKE_BINARY_DIR}/include/optix_rc.h" ) + source_group( Resources FILES ${resourceFiles} ) + endif() +endmacro() diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/ptx2cpp.cmake b/Extern/3rdParty/OptiX/Linux/SDK/CMake/ptx2cpp.cmake new file mode 100644 index 00000000..d5999089 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/ptx2cpp.cmake @@ -0,0 +1,51 @@ + +# +# Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA Corporation and its licensors retain all intellectual property and proprietary +# rights in and to this software, related documentation and any modifications thereto. +# Any use, reproduction, disclosure or distribution of this software and related +# documentation without an express license agreement from NVIDIA Corporation is strictly +# prohibited. +# +# TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* +# AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, +# INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY +# SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT +# LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF +# BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR +# INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGES +# + +# This script produces a string variable from the contents of a ptx +# script. The variable is defined in the .cc file and the .h file. + +# This script excepts the following variable to be passed in like +# -DVAR:TYPE=VALUE +# +# CPP_FILE +# PTX_FILE +# VARIABLE_NAME +# NAMESPACE +# CUDA_BIN2C_EXECUTABLE + +# message("PTX_FILE = ${PTX_FILE}") +# message("CPP_FILE = ${C_FILE}") +# message("VARIABLE_NAME = ${VARIABLE_NAME}") +# message("NAMESPACE = ${NAMESPACE}") + +execute_process( COMMAND ${CUDA_BIN2C_EXECUTABLE} -p 0 -st -c -n ${VARIABLE_NAME}_static "${PTX_FILE}" + OUTPUT_VARIABLE bindata + RESULT_VARIABLE result + ERROR_VARIABLE error + ) +if(result) + message(FATAL_ERROR "bin2c error:\n" ${error}) +endif() + +set(BODY + "${bindata}\n" + "namespace ${NAMESPACE} {\n\nstatic const char* const ${VARIABLE_NAME} = reinterpret_cast(&${VARIABLE_NAME}_static[0]);\n} // end namespace ${NAMESPACE}\n") +file(WRITE ${CPP_FILE} "${BODY}") diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/sse_support.h.in b/Extern/3rdParty/OptiX/Linux/SDK/CMake/sse_support.h.in new file mode 100644 index 00000000..2b3ae62d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/sse_support.h.in @@ -0,0 +1 @@ +#cmakedefine SSE_41_AVAILABLE diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMake/testmain.c b/Extern/3rdParty/OptiX/Linux/SDK/CMake/testmain.c new file mode 100644 index 00000000..7f0201fa --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMake/testmain.c @@ -0,0 +1,16 @@ + +/* +* SPDX-FileCopyrightText: Copyright (c) 2008 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* SPDX-License-Identifier: LicenseRef-NvidiaProprietary +* +* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +* property and proprietary rights in and to this material, related +* documentation and any modifications thereto. Any use, reproduction, +* disclosure or distribution of this material and related documentation +* without an express license agreement from NVIDIA CORPORATION or +* its affiliates is strictly prohibited. +*/ +int main() +{ + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/CMakeLists.txt new file mode 100644 index 00000000..055880a1 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/CMakeLists.txt @@ -0,0 +1,581 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Welcome to the OptiX SDK build. We have chosen CMake, because it can generate multiple +# build systems for multiple architectures from a single script. There are many resources +# for CMake on-line at http://www.cmake.org and their wiki page, +# http://www.cmake.org/Wiki/CMake, in addition to the documentation that comes with the +# distribution. There is also a book available if you wish to delve more deeply into +# various topics. + +# If you wish to create your own project and use the SDK as a template there are a number +# of things you should do. +# +# 1. You should copy the contents of the SDK to a place of your choice. +# +# 2. You can remove any sample's directory you don't wish to build. Be careful about +# the following directories. +# +# a. CMake - contains helper scripts that make this all work. You should keep this. +# +# b. sutil and putil +# - Almost all of the samples make use of this shared code one way or another, so +# you should probably keep them until you have your own frameowrk for your +# code. +# +# d. data - This directory contains the cow.obj file used as an example for +# many of the samples. You can move cow.obj anywhere as long as +# you fix all the file paths in the samples you wish to use it in. +# +# 3. You should update the list of sub directories that CMake needs to process below (look +# for the comment "List of samples found in subdirectories.") +# + +# The basic flow of execution of this file is to do the following. +# +# 1. Setup the project and other global settings. This involves processing some helper +# scripts. +# +# 2. Look for external dependencies, CUDA, and OptiX. +# +# 3. Process all the subdirectories' CMakeLists.txt files. These files create all the +# executable and library targets that are used to build the SDK. +# +# 4. As a convenience on Windows, copy the OptiX dlls into the build directories, so OptiX +# doesn't have to be in the path to run the samples. +# +# 5. Set a CMake variable that indicates we have configured for the first time. This +# allows us to override and set varibles' defaults while allowing them to be modified +# later. + +# If you have any questions, don't feel shy about posting to the OptiX forums: +# https://devtalk.nvidia.com/default/board/90/ + + +# This sets up the name of our project. For our purposes the main thing this controls is +# the name of the VS solution file. +project(OptiX-Samples) + +# This enforces a particular version of CMake that we require to process the script files +# properly. We rely on VERSION_GREATER_EQUAL which requires CMake v. 3.7. +cmake_minimum_required(VERSION 3.7 FATAL_ERROR) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) +set(CMAKE_CXX_EXTENSIONS OFF) + +# As of CMake 2.6 policies were introduced in order to provide a mechanism for +# adding backwards compatibility one feature at a time. We will just specify +# that all policies will use version 2.8.12 semantics. +cmake_policy(VERSION 2.8.12) + +if( POLICY CMP0072 ) + # FindOpenGL prefers GLVND by default when available + cmake_policy(SET CMP0072 NEW) +endif() + +if( POLICY CMP0074 ) + # find_package uses _ROOT variables. + cmake_policy(SET CMP0074 NEW) +endif() + +# Add paths to our CMake code to the module path, so they can be found automatically by +# CMake. +set(CMAKE_MODULE_PATH + "${CMAKE_SOURCE_DIR}/../SDK/CMake" + ${CMAKE_MODULE_PATH} + ) + +# Set the default build to Release. Note this doesn't do anything for the VS +# default build target which defaults to Debug when you first start it. +IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE "Release" CACHE STRING + "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." + FORCE) +ENDIF(NOT CMAKE_BUILD_TYPE) + +# Tells CMake to build all the libraries as shared libraries by default. This can be +# overrided by individual libraries later. +option(BUILD_SHARED_LIBS "Build shared libraries" ON) + +########## +# Process our custom setup scripts here. + +# Enable C++11. Needs to be done before the include of ConfigCompilerFlags.cmake below. +set(GCC_LIBSTDCPP11 ON) + +# Include all CMake Macros. +include(Macros) +# Determine information about the compiler +include (CompilerInfo) +# Check for specific machine/compiler options. +include (ConfigCompilerFlags) + +# Turn off the warning that NVCC issues when generating PTX from our CUDA samples. This +# is a custom extension to the FindCUDA code distributed by CMake. +OPTION(CUDA_REMOVE_GLOBAL_MEMORY_SPACE_WARNING "Suppress the \"Advisory: Cannot tell what pointer points to, assuming global memory space\" warning nvcc makes." ON) + +# For Xcode 5, gcc is actually clang, so we have to tell CUDA to treat the compiler as +# clang, so that it doesn't mistake it for something else. +if(USING_CLANG_C) + set(CUDA_HOST_COMPILER "clang" CACHE FILEPATH "Host side compiler used by NVCC") +endif() + +# CUDA 8 is broken for generating dependencies during configure +option(CUDA_GENERATE_DEPENDENCIES_DURING_CONFIGURE "Generate dependencies during configure time instead of only during build time." OFF) + +# Passing the --use-local-env option to NVCC can dramatically speed up CUDA compilation +if(WIN32) + option(CUDA_USE_LOCAL_ENV "Pass the '--use-local-env' option to NVCC; only applies to initial configure" ON) +endif() + +# Find at least a 5.0 version of CUDA. +find_package(CUDA 5.0 REQUIRED) + +# If NVRTC was enabled/disabled, reset OPTIXIR/PTX to default +set( CUDA_NVRTC_ENABLED OFF CACHE BOOL "Use NVRTC to compile OPTIXIR/PTX at run-time instead of NVCC at build-time" ) +if( NOT ( NOT ( NOT CUDA_NVRTC_ENABLED ) ) EQUAL ( NOT ( NOT CUDA_NVRTC_ENABLED_INTERNAL ) ) ) + message( STATUS "Resetting OPTIXIR/PTX support" ) + unset( SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT CACHE ) +endif() +set( CUDA_NVRTC_ENABLED_INTERNAL ${CUDA_NVRTC_ENABLED} CACHE INTERNAL "Previous configured value (NVRTC)" FORCE ) + +if( CUDA_NVRTC_ENABLED ) + if( CUDA_VERSION VERSION_LESS 12.0 ) + if( SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT ) + message( SEND_ERROR "CUDA_NVRTC_ENABLED is not compatible with SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT in CUDA versions less than 12.0" ) + else() + option( SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT "Enable support for generating OptiX-IR targetted input files" OFF ) + endif() + else() + option( SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT "Enable support for generating OptiX-IR targetted input files" ON ) + endif() +else() + if( CUDA_VERSION VERSION_LESS 11.7 ) + if( SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT ) + message( SEND_ERROR "SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT is not supported in CUDA versions less than 11.7" ) + else() + option( SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT "Enable support for generating OptiX-IR targetted input files" OFF ) + endif() + else() + option( SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT "Enable support for generating OptiX-IR targetted input files" ON ) + endif() +endif() + +# This code looks funny, but CMake doesn't have an equality operator for boolean types +# (only integer and string). By doing NOT NOT VAL, you can force the original value into 0 +# or 1 and allow the EQUAL operator to function correctly. +if( NOT ( NOT ( NOT SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT ) ) EQUAL ( NOT ( NOT SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT_INTERNAL ) ) ) + message( STATUS "Unsetting values associated with OptiX code generation" ) + # This allows us to reset dependent options if you change it. + unset( SAMPLES_INPUT_GENERATE_OPTIXIR CACHE ) + unset( SAMPLES_INPUT_GENERATE_PTX CACHE ) + unset( GENERATE_DEBUG_DEVICE_CODE CACHE ) +endif() +set(SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT_INTERNAL ${SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT} CACHE INTERNAL "Previous configured value (OPTIXIR)" FORCE) + +if( SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT ) + option( SAMPLES_INPUT_GENERATE_OPTIXIR "Generate Optix-IR OptiX shaders" ON ) + option( SAMPLES_INPUT_GENERATE_PTX "Generate PTX OptiX shaders" OFF ) +else() + option( SAMPLES_INPUT_GENERATE_OPTIXIR "Generate Optix-IR OptiX shaders" OFF ) + option( SAMPLES_INPUT_GENERATE_PTX "Generate PTX OptiX shaders" ON ) +endif() + +# Determine if we are going to use the static CRT on windows. +if(WIN32) + option(RELEASE_USE_STATIC_CRT "Build using the static CRT library" ON) +endif() + +# Helper for fixing compiler flags +function(replace_flag var old_flag new_flag) + string(REPLACE "${old_flag}" "${new_flag}" ${var} ${${var}}) + set(${var} "${${var}}" CACHE STRING "Default compiler flags" FORCE) +endfunction() + +function(replace_flags old_flag new_flag) + foreach(build "" _DEBUG _MINSIZEREL _RELEASE _RELWITHDEBINFO) + replace_flag(CMAKE_C_FLAGS${build} "${old_flag}" "${new_flag}") + replace_flag(CMAKE_CXX_FLAGS${build} "${old_flag}" "${new_flag}") + endforeach() +endfunction() + +if(WIN32) + if(RELEASE_USE_STATIC_CRT) + replace_flags("/MD" "/MT") + else() + replace_flags("/MT" "/MD") + endif() +endif(WIN32) + +# Present the CUDA_64_BIT_DEVICE_CODE on the default set of options. +mark_as_advanced(CLEAR CUDA_64_BIT_DEVICE_CODE) + +set(CUDA_MIN_SM_TARGET sm_50 CACHE STRING "Minimum CUDA SM architecture to use for compilation.") + +function(optix_add_cuda_flag_config config flag) + string(TOUPPER "${config}" config) + list(FIND CUDA_NVCC_FLAGS${config} ${flag} index) + if(index EQUAL -1) + list(APPEND CUDA_NVCC_FLAGS${config} ${flag}) + set(CUDA_NVCC_FLAGS${config} ${CUDA_NVCC_FLAGS${config}} CACHE STRING ${CUDA_NVCC_FLAGS_DESCRIPTION} FORCE) + endif() +endfunction() + +function(optix_add_cuda_flag flag) + optix_add_cuda_flag_config( "" ${flag} ) +endfunction() + +# Add some useful default arguments to the NVCC and NVRTC flags. This is an example of +# how we use PASSED_FIRST_CONFIGURE. Once you have configured, this variable is TRUE +# and following block of code will not be executed leaving you free to edit the values +# as much as you wish from the GUI or from ccmake. +if( NOT PASSED_FIRST_CONFIGURE ) + set(CUDA_NVCC_FLAGS_DESCRIPTION "Semi-colon delimit multiple arguments.") + string(REPLACE "sm_" "compute_" CUDA_MIN_SM_COMPUTE_TARGET ${CUDA_MIN_SM_TARGET}) + + list(FIND CUDA_NVCC_FLAGS "-arch" index) + if(index EQUAL -1) + list(APPEND CUDA_NVCC_FLAGS -arch ${CUDA_MIN_SM_TARGET}) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} CACHE STRING "Semi-colon delimit multiple arguments." FORCE) + endif() + + optix_add_cuda_flag("--use_fast_math") + optix_add_cuda_flag("-lineinfo") + + # CMAKE_CONFIGURATION_TYPES is only defined for multi-config build systems like + # MSVC and Ninja, but we need to generate flags for each configuration + # regardless. + if( DEFINED CMAKE_CONFIGURATION_TYPES ) + set( OPTIX_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES} ) + else() + set( OPTIX_CONFIGURATION_TYPES "Debug" "Release" "RelWithDebInfo" "MinSizeRel" ) + endif() + + foreach( config ${OPTIX_CONFIGURATION_TYPES} ) + if( ${config} STREQUAL "Debug" ) + optix_add_cuda_flag_config( _${config} "-G" ) + optix_add_cuda_flag_config( _${config} "-O0" ) + endif() + endforeach() + + if( CUDA_VERSION VERSION_LESS "3.0" ) + optix_add_cuda_flag("--keep") + endif() + + # Some CUDA 11.x toolkits erroneously complain about sm_50 being deprecated + if(CUDA_VERSION VERSION_GREATER "11.0") + optix_add_cuda_flag("-Wno-deprecated-gpu-targets") + endif() + + if(CUDA_USE_LOCAL_ENV) + optix_add_cuda_flag("--use-local-env") + endif() + + if(CMAKE_CXX_STANDARD EQUAL 11) + set(SAMPLES_NVRTC_CXX "-std=c++11") + else() + set(SAMPLES_NVRTC_CXX "") + endif() + + if( NOT DEFINED CMAKE_CONFIGURATION_TYPES ) + if( NOT CMAKE_BUILD_TYPE STREQUAL CMAKE_BUILD_TYPE_PREVIOUS ) + message( STATUS "Resetting CUDA_NVRTC_FLAGS" ) + unset( CUDA_NVRTC_FLAGS CACHE ) + endif() + set( CMAKE_BUILD_TYPE_PREVIOUS ${CMAKE_BUILD_TYPE} CACHE INTERNAL "Previous configured value (CMAKE_BUILD_TYPE)" FORCE ) + + set( configs "Debug" "Release" "RelWithDebInfo" "MinSizeRel" ) + foreach( config ${configs} ) + if( ${config} STREQUAL "Debug" ) + set( SAMPLES_NVRTC_DEBUG "-G" ) + else() + set( SAMPLES_NVRTC_DEBUG "-lineinfo" ) + endif() + + string( TOUPPER ${config} config_upper ) + set( CUDA_NVRTC_FLAGS_${config_upper} ${SAMPLES_NVRTC_CXX} -arch ${CUDA_MIN_SM_COMPUTE_TARGET} ${SAMPLES_NVRTC_DEBUG} -use_fast_math -default-device -rdc true -D__x86_64 CACHE STRING "List of NVRTC options just for the samples" FORCE ) + + if( ${config} STREQUAL ${CMAKE_BUILD_TYPE} ) + set( CUDA_NVRTC_FLAGS ${CUDA_NVRTC_FLAGS_${config_upper}} CACHE STRING "List of NVRTC options just for the samples" ) + endif() + endforeach() + else() + set( CUDA_NVRTC_FLAGS ${SAMPLES_NVRTC_CXX} -arch ${CUDA_MIN_SM_COMPUTE_TARGET} -lineinfo -use_fast_math -default-device -rdc true -D__x86_64 CACHE STRING "List of NVRTC options just for the samples" FORCE ) + set( CUDA_NVRTC_FLAGS_DEBUG ${SAMPLES_NVRTC_CXX} -arch ${CUDA_MIN_SM_COMPUTE_TARGET} -G -use_fast_math -default-device -rdc true -D__x86_64 CACHE STRING "List of NVRTC options just for the samples" FORCE ) + endif() +endif() + +mark_as_advanced(CUDA_NVRTC_FLAGS) + +# This passes a preprocessor definition to cl.exe when processing CUDA code. +if(USING_WINDOWS_CL) + list(APPEND CUDA_NVCC_FLAGS --compiler-options /D_USE_MATH_DEFINES) +endif() + +# Put all the runtime stuff in the same directory. By default, CMake puts each targets' +# output into their own directory. We want all the targets to be put in the same +# directory, and we can do this by setting these variables. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") + +# Create a flag for mac which will allow apps to add the local cuda toolkit +# install path to the app's rpath. +if( APPLE ) + set( CUDA_TOOLKIT_RPATH_FLAG "-Wl,-rpath,${CUDA_TOOLKIT_ROOT_DIR}/lib" ) +endif() + +# Locate the NVRT distribution. Search the SDK first, then look in the system. +set(OptiX_INSTALL_DIR "${CMAKE_SOURCE_DIR}/../" CACHE PATH "Path to OptiX installed location.") + +# Search for the OptiX libraries and include files. +find_package(OptiX REQUIRED) + +# Add the path to the OptiX headers to our include paths. +include_directories( + "${OptiX_INCLUDE}" + "${CMAKE_CURRENT_SOURCE_DIR}/cuda" + ) + +# Select whether to use NVRTC or NVCC to generate PTX +if( NOT SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT AND SAMPLES_INPUT_GENERATE_OPTIXIR ) + message( SEND_ERROR "Must enable SAMPLES_INPUT_ENABLE_OPTIXIR_SUPPORT to enable SAMPLES_INPUT_GENERATE_OPTIXIR" ) +endif() + + +################################################################## +# SUtil compilation + +set(SAMPLES_PTX_DIR "${CMAKE_BINARY_DIR}/lib/ptx") +set(SAMPLES_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + +set(CUDA_GENERATED_OUTPUT_DIR ${SAMPLES_PTX_DIR}) + +if( WIN32 ) + string(REPLACE "/" "\\\\" SAMPLES_PTX_DIR ${SAMPLES_PTX_DIR}) +else( WIN32 ) + if( USING_GNU_C AND NOT APPLE ) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DM_PI=3.14159265358979323846" ) + endif() +endif( WIN32 ) + +set(SAMPLES_CUDA_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cuda") + +set(SAMPLES_SUPPORT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../SDK/support") + +# NVRTC include paths relative to the sample path +set(SAMPLES_RELATIVE_INCLUDE_DIRS "\\ + \"cuda\", \\ + \"sutil\", \\ + \".\", ") + +# NVRTC absolute include paths to the headers used to build the samples +set(SAMPLES_ABSOLUTE_INCLUDE_DIRS "\\ + \"${OptiX_INCLUDE}\", \\ + \"${CUDA_INCLUDE_DIRS}\", ") + +# Build a null-terminated option list for NVRTC +set( config_suffixes "_RELEASE" "_DEBUG" ) +foreach( config_suffix ${config_suffixes} ) + # CMake doesn't allow empty strings in lists, so use a dummy suffix + if( ${config_suffix} STREQUAL "_RELEASE" ) + set( config_suffix "" ) + endif() + set(CUDA_NVRTC_OPTIONS${config_suffix}) + foreach(flag ${CUDA_NVRTC_FLAGS${config_suffix}}) + set(CUDA_NVRTC_OPTIONS${config_suffix} "${CUDA_NVRTC_OPTIONS${config_suffix}} \\\n \"${flag}\",") + endforeach() + set(CUDA_NVRTC_OPTIONS${config_suffix} "${CUDA_NVRTC_OPTIONS${config_suffix}}") +endforeach() + +configure_file(sampleConfig.h.in sampleConfig.h @ONLY) + +# Path to sutil.h that all the samples need +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} + "${CMAKE_BINARY_DIR}/include" + ${CMAKE_CURRENT_BINARY_DIR} + ${CUDA_INCLUDE_DIRS} + ) + +set(SAMPLES_CUDA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cuda) + +# Helper macro to generate PTX from the CUDA files in sutil. +macro(OPTIX_sutil_compile_to_optix_input generated_files) + if( NOT CUDA_NVRTC_ENABLED ) + if( SAMPLES_INPUT_GENERATE_OPTIXIR ) + message("sutil OPTIXIR") + CUDA_WRAP_SRCS( sutil OPTIXIR generated_files2 ${ARGN} ) + list(APPEND ${generated_files} ${generated_files2}) + endif() + if( SAMPLES_INPUT_GENERATE_PTX ) + message("sutil PTX") + CUDA_WRAP_SRCS( sutil PTX generated_files3 ${ARGN} ) + list(APPEND ${generated_files} ${generated_files3}) + endif() + endif() + message("${generated_files} = ${${generated_files}}") +endmacro() + +# These calls will group PTX and CUDA files into their own directories in the Visual +# Studio projects. +macro(OPTIX_add_source_groups) + if( NOT CUDA_NVRTC_ENABLED ) + if( SAMPLES_INPUT_GENERATE_PTX ) + source_group("PTX Files" REGULAR_EXPRESSION ".+\\.ptx$") + endif() + if( SAMPLES_INPUT_GENERATE_OPTIXIR ) + source_group("OptixIR Files" REGULAR_EXPRESSION ".+\\.optixir$") + endif() + endif() + source_group("CUDA Files" REGULAR_EXPRESSION ".+\\.cu$") +endmacro() + +######################################################### +# OPTIX_add_sample_executable +# +# Convience function for adding samples to the code. You can copy the contents of this +# funtion into your individual project if you wish to customize the behavior. Note that +# in CMake, functions have their own scope, whereas macros use the scope of the caller. +function(OPTIX_add_sample_executable target_name_base target_name_var) + + set( target_name ${target_name_base} ) + set( ${target_name_var} ${target_name} PARENT_SCOPE ) + + OPTIX_add_source_groups() + + # Separate the sources from the CMake and CUDA options fed to the macro. This code + # comes from the CUDA_COMPILE_PTX macro found in FindCUDA.cmake. We are copying the + # code here, so that we can use our own name for the target. target_name is used in the + # creation of the output file names, and we want this to be unique for each target in + # the SDK. + CUDA_GET_SOURCES_AND_OPTIONS(source_files cmake_options options ${ARGN}) + + # Isolate OBJ target files. NVCC should only process these files and leave PTX targets for NVRTC + set(cu_obj_source_files) + set(cu_optix_source_files) + foreach(file ${source_files}) + get_source_file_property(_cuda_source_format ${file} CUDA_SOURCE_PROPERTY_FORMAT) + if(${_cuda_source_format} MATCHES "OBJ") + list(APPEND cu_obj_source_files ${file}) + else() + list(APPEND cu_optix_source_files ${file}) + endif() + endforeach() + + # Create the rules to build the OBJ from the CUDA files. + CUDA_WRAP_SRCS( ${target_name} OBJ generated_files ${cu_obj_source_files} ${cmake_options} OPTIONS ${options} ) + + # Create the rules to build the PTX and/or OPTIX files. + if( SAMPLES_INPUT_GENERATE_OPTIXIR ) + CUDA_WRAP_SRCS( ${target_name} OPTIXIR generated_files2 ${cu_optix_source_files} ${cmake_options} OPTIONS ${options} ) + list(APPEND generated_files ${generated_files2}) + endif() + if( SAMPLES_INPUT_GENERATE_PTX AND NOT CUDA_NVRTC_ENABLED) + CUDA_WRAP_SRCS( ${target_name} PTX generated_files3 ${cu_optix_source_files} ${cmake_options} OPTIONS ${options} ) + list(APPEND generated_files ${generated_files3}) + endif() + + # Here is where we create the rule to make the executable. We define a target name and + # list all the source files used to create the target. In addition we also pass along + # the cmake_options parsed out of the arguments. + add_executable(${target_name} + ${source_files} + ${generated_files} + ${cmake_options} + ) + + # Most of the samples link against the sutil library and the optix library. Here is the + # rule that specifies this linkage. + target_link_libraries( ${target_name} + ${GLFW_LIB_NAME} + imgui + sutil_7_sdk + ) + + set_target_properties( ${target_name} PROPERTIES + COMPILE_DEFINITIONS + "OPTIX_SAMPLE_NAME_DEFINE=${target_name};OPTIX_SAMPLE_DIR_DEFINE=${target_name}" ) + + if( UNIX AND NOT APPLE ) + # Force using RPATH instead of RUNPATH on Debian + target_link_libraries( ${target_name} "-Wl,--disable-new-dtags" ) + endif() + + if(USING_GNU_CXX) + target_link_libraries( ${target_name} m ) # Explicitly link against math library (C samples don't do that by default) + endif() +endfunction() + +######################################################### +# List of samples found in subdirectories. +# +# If you wish to start your own sample, you can copy one of the sample's directories. +# Just make sure you rename all the occurances of the sample's name in the C code as well +# and the CMakeLists.txt file. +add_subdirectory( optixBoundValues ) +add_subdirectory( optixCallablePrograms ) +add_subdirectory( optixCompileWithTasks ) +add_subdirectory( optixConsole ) +add_subdirectory( optixCurves ) +add_subdirectory( optixCustomPrimitive ) +add_subdirectory( optixCutouts ) +add_subdirectory( optixDenoiser ) +add_subdirectory( optixDisplacedMicromesh ) +add_subdirectory( optixDynamicGeometry ) +add_subdirectory( optixDynamicMaterials ) +add_subdirectory( optixHair ) +add_subdirectory( optixHello ) +add_subdirectory( optixMeshViewer ) +add_subdirectory( optixMixSDKs ) +add_subdirectory( optixModuleCreateAbort ) +add_subdirectory( optixMotionGeometry ) +add_subdirectory( optixMultiGPU ) +add_subdirectory( optixNVLink ) +add_subdirectory( optixOpticalFlow ) +add_subdirectory( optixOpacityMicromap ) +add_subdirectory( optixPathTracer ) +add_subdirectory( optixRaycasting ) +add_subdirectory( optixRibbons ) +add_subdirectory( optixSimpleMotionBlur ) +add_subdirectory( optixSphere ) +add_subdirectory( optixTriangle ) +add_subdirectory( optixVolumeViewer ) +add_subdirectory( optixWhitted ) + +# Our sutil library. The rules to build it are found in the subdirectory. +add_subdirectory(sutil) +# Third-party support libraries. +add_subdirectory(support) + +################################################################# + +# Now that everything is done, indicate that we have finished configuring at least once. +# We use this variable to set certain defaults only on the first pass, so that we don't +# continually set them over and over again. +set(PASSED_FIRST_CONFIGURE ON CACHE INTERNAL "Already Configured once?") diff --git a/Extern/3rdParty/OptiX/Linux/SDK/INSTALL-LINUX.txt b/Extern/3rdParty/OptiX/Linux/SDK/INSTALL-LINUX.txt new file mode 100644 index 00000000..d16084dc --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/INSTALL-LINUX.txt @@ -0,0 +1,29 @@ +In order to compile the samples in the SDK you need the following: + +1. CUDA Toolkit. Supported versions are listed in the release notes. + +2. CMake 3.0 minimum (http://www.cmake.org/cmake/resources/software.html). + +3. C++ compiler (gcc 4.4 and 4.8 been tested) + +To compile: + +Instructions for building. +1. Create a build directory other than the SDK/ directory. Using a separate + build directory allows multiple builds, differing in flavor, platform, etc. +2. cd to new directory. +3. Run + $ ccmake + where path is the path to the SDK/ directory. This will bring up + the cmake interface. +4. Press 'c' within ccmake to begin configure process. +5. Adjust any options, such as build flavor, by moving cursor to field and + hitting , changing value, and hitting again. One field you + may want to change is CMAKE_BUILD_TYPE to select a Debug build (it defaults + to Release which is an optimized build). +6. Press 'c' again to finish configure. +7. Press 'g' to generate Makefiles and exit. +8. Run + $ make + to build. +9. Executables should be found in the bin directory. diff --git a/Extern/3rdParty/OptiX/Linux/SDK/INSTALL-WIN.txt b/Extern/3rdParty/OptiX/Linux/SDK/INSTALL-WIN.txt new file mode 100644 index 00000000..1819b25a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/INSTALL-WIN.txt @@ -0,0 +1,53 @@ +In order to compile the samples in the SDK you need the following. + +1. Visual Studio. Supported versions are listed in the release notes. + +2. CUDA Toolkit. Supported versions are listed in the release notes. + +3. CMake 3.0 minimum (http://www.cmake.org/cmake/resources/software.html). +I suggest the executable installer. + + +Instructions for building. + +1. Start up cmake-gui from the Start Menu. + +2. Select the C:\ProgramData\NVIDIA Corporation\OptiX SDK \SDK directory + from the installation for the source file location. + +3. Create a build directory that isn't the same as the source directory. For + example, C:\ProgramData\NVIDIA Corporation\OptiX SDK \SDK\build. + If you don't have permissions to write into the this directory (writing into + the "C:/Program Files" directory can be restricted in some cases), pick a different + directory where you do have write permissions. If you type in the directory + (instead of using the "Browse Build..." button), CMake will ask you at the + next step to create the directory for you if it doesn't already exist. + +4. Press "Configure" button and select the version of Visual Studio you wish to + use. Note that the 64-bit compiles are separate from the 32-bit compiles. + The difference between the bitnesses of the build will be marked with "Win64" + for 64 bit builds (e.g. "Visual Studio 14 2015 Win64" for 64 bit builds and + "Visual Studio 14 2013" for 32 bit builds). Also note that OptiX only + supports 64 bit builds, and CMake defaults to 32 bit configures, so you must + change it. Leave all other options on their default. Press "OK". This can + take awhile while source level dependencies for CUDA files are computed. + +5. Press "Configure" again. Followed by "Generate". + +6. Open the OptiX-Samples.sln solution file in the build directory you created. + +7. Select "Build Solution" from the IDE. + +8. Right click on one of the sample program targets in the solution explorer and + select "Set as start up project". + +9. Run the sample. "q" or "Esc" will close the window. + +Note that due to the way dependencies are automatically handled for CUDA +compilation in Visual Studio, if you build again Visual Studio will likely ask +you to reload your projects. Please do so. Subsequent compiles should not +result in reloading unless you change the files that are included by a CUDA +file. + +Further instructions regarding the build system can be found in comments in the +SDK's CMakeLists.txt file. diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/BufferView.h b/Extern/3rdParty/OptiX/Linux/SDK/cuda/BufferView.h new file mode 100644 index 00000000..67b63c9e --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/BufferView.h @@ -0,0 +1,55 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +template +struct BufferView +{ + CUdeviceptr data CONST_STATIC_INIT( 0 ); + unsigned int count CONST_STATIC_INIT( 0 ); + unsigned short byte_stride CONST_STATIC_INIT( 0 ); + unsigned short elmt_byte_size CONST_STATIC_INIT( 0 ); + + SUTIL_HOSTDEVICE bool isValid() const + { return static_cast( data ); } + + SUTIL_HOSTDEVICE operator bool() const + { return isValid(); } + + SUTIL_HOSTDEVICE const T& operator[]( unsigned int idx ) const + { return *reinterpret_cast( data + idx*(byte_stride ? byte_stride : sizeof( T ) ) ); } +}; + +typedef BufferView GenericBufferView; + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/GeometryData.h b/Extern/3rdParty/OptiX/Linux/SDK/cuda/GeometryData.h new file mode 100644 index 00000000..3445b595 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/GeometryData.h @@ -0,0 +1,262 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#include + +#include + +#ifndef __CUDACC_RTC__ +#include +#else +#define assert(x) /*nop*/ +#endif + +// unaligned equivalent of float2 +struct Vec2f +{ + SUTIL_HOSTDEVICE operator float2() const { return { x, y }; } + + float x, y; +}; + +struct Vec4f +{ + SUTIL_HOSTDEVICE operator float4() const { return { x, y, z, w }; } + + float x, y, z, w; +}; + +struct GeometryData +{ + enum Type + { + TRIANGLE_MESH = 0, + SPHERE = 1, + SPHERE_SHELL = 2, + PARALLELOGRAM = 3, + LINEAR_CURVE_ARRAY = 4, + QUADRATIC_CURVE_ARRAY = 5, + CUBIC_CURVE_ARRAY = 6, + CATROM_CURVE_ARRAY = 7, + UNKNOWN_TYPE = 8 + }; + + // The number of supported texture spaces per mesh. + static const unsigned int num_texcoords = 2; + + struct TriangleMesh + { + GenericBufferView indices; + BufferView positions; + BufferView normals; + BufferView texcoords[num_texcoords]; // The buffer view may not be aligned, so don't use float2 + BufferView colors; // The buffer view may not be aligned, so don't use float4 + }; + + + struct Sphere + { + float3 center; + float radius; + }; + + + struct SphereShell + { + enum HitType + { + HIT_OUTSIDE_FROM_OUTSIDE = 1u << 0, + HIT_OUTSIDE_FROM_INSIDE = 1u << 1, + HIT_INSIDE_FROM_OUTSIDE = 1u << 2, + HIT_INSIDE_FROM_INSIDE = 1u << 3 + }; + + float3 center; + float radius1; + float radius2; + }; + + + struct Parallelogram + { + Parallelogram() = default; + Parallelogram( float3 v1, float3 v2, float3 anchor ) + : v1( v1 ) + , v2( v2 ) + , anchor( anchor ) + { + float3 normal = normalize( cross( v1, v2 ) ); + float d = dot( normal, anchor ); + this->v1 *= 1.0f / dot( v1, v1 ); + this->v2 *= 1.0f / dot( v2, v2 ); + plane = make_float4( normal, d ); + } + float4 plane; + float3 v1; + float3 v2; + float3 anchor; + }; + + + struct Curves + { + BufferView strand_u; // strand_u at segment start per segment + GenericBufferView strand_i; // strand index per segment + BufferView strand_info; // info.x = segment base + // info.y = strand length (segments) + }; + + GeometryData() {}; + + void setTriangleMesh( const TriangleMesh& t ) + { + assert( type == UNKNOWN_TYPE ); + type = TRIANGLE_MESH; + triangle_mesh = t; + } + + SUTIL_HOSTDEVICE const TriangleMesh& getTriangleMesh() const + { + assert( type == TRIANGLE_MESH ); + return triangle_mesh; + } + + void setSphere( const Sphere& s ) + { + assert( type == UNKNOWN_TYPE ); + type = SPHERE; + sphere = s; + } + + SUTIL_HOSTDEVICE const Sphere& getSphere() const + { + assert( type == SPHERE ); + return sphere; + } + + void setSphereShell( const SphereShell& s ) + { + assert( type == UNKNOWN_TYPE ); + type = SPHERE_SHELL; + sphere_shell = s; + } + + SUTIL_HOSTDEVICE const SphereShell& getSphereShell() const + { + assert( type == SPHERE_SHELL ); + return sphere_shell; + } + + void setParallelogram( const Parallelogram& p ) + { + assert( type == UNKNOWN_TYPE ); + type = PARALLELOGRAM; + parallelogram = p; + } + + SUTIL_HOSTDEVICE const Parallelogram& getParallelogram() const + { + assert( type == PARALLELOGRAM ); + return parallelogram; + } + + SUTIL_HOSTDEVICE const Curves& getCurveArray() const + { + assert( type == LINEAR_CURVE_ARRAY || type == QUADRATIC_CURVE_ARRAY || type == CUBIC_CURVE_ARRAY || type == CATROM_CURVE_ARRAY ); + return curves; + } + + + void setLinearCurveArray( const Curves& c ) + { + assert( type == UNKNOWN_TYPE ); + type = LINEAR_CURVE_ARRAY; + curves = c; + } + + SUTIL_HOSTDEVICE const Curves& getLinearCurveArray() const + { + assert( type == LINEAR_CURVE_ARRAY ); + return curves; + } + + void setQuadraticCurveArray( const Curves& c ) + { + assert( type == UNKNOWN_TYPE ); + type = QUADRATIC_CURVE_ARRAY; + curves = c; + } + + SUTIL_HOSTDEVICE const Curves& getQuadraticCurveArray() const + { + assert( type == QUADRATIC_CURVE_ARRAY ); + return curves; + } + + void setCubicCurveArray( const Curves& c ) + { + assert( type == UNKNOWN_TYPE ); + type = CUBIC_CURVE_ARRAY; + curves = c; + } + + SUTIL_HOSTDEVICE const Curves& getCubicCurveArray() const + { + assert( type == CUBIC_CURVE_ARRAY ); + return curves; + } + + void setCatromCurveArray( const Curves& c ) + { + assert( type == UNKNOWN_TYPE ); + type = CATROM_CURVE_ARRAY; + curves = c; + } + + SUTIL_HOSTDEVICE const Curves& getCatromCurveArray() const + { + assert( type == CATROM_CURVE_ARRAY ); + return curves; + } + + Type type = UNKNOWN_TYPE; + + private: + union + { + TriangleMesh triangle_mesh; + Sphere sphere; + SphereShell sphere_shell; + Parallelogram parallelogram; + Curves curves; + }; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/Light.h b/Extern/3rdParty/OptiX/Linux/SDK/cuda/Light.h new file mode 100644 index 00000000..4b35abee --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/Light.h @@ -0,0 +1,74 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once +#include + +struct Light +{ + Light() {} + + enum class Falloff : int + { + NONE = 0, + LINEAR, + QUADRATIC + }; + + + enum class Type : int + { + POINT = 0, + AMBIENT = 1 + }; + + struct Point + { + float3 color CONST_STATIC_INIT( { 1.0f, 1.0f, 1.0f } ); + float intensity CONST_STATIC_INIT( 1.0f ); + float3 position CONST_STATIC_INIT( {} ); + Falloff falloff CONST_STATIC_INIT( Falloff::QUADRATIC ); + }; + + + struct Ambient + { + float3 color CONST_STATIC_INIT( {1.0f, 1.0f, 1.0f} ); + }; + + + Type type; + + union + { + Point point; + Ambient ambient; + }; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/LocalGeometry.h b/Extern/3rdParty/OptiX/Linux/SDK/cuda/LocalGeometry.h new file mode 100644 index 00000000..ef4a4eb1 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/LocalGeometry.h @@ -0,0 +1,181 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + + +struct LocalGeometry +{ + float3 P; + float3 N; + float3 Ng; + + struct Texcoord + { + float2 UV; + float3 dndu; + float3 dndv; + float3 dpdu; + float3 dpdv; + } texcoord[GeometryData::num_texcoords]; + + float4 color; +}; + + +__forceinline__ __device__ LocalGeometry getLocalGeometry( const GeometryData& geometry_data ) +{ + LocalGeometry lgeom; + switch( geometry_data.type ) + { + case GeometryData::TRIANGLE_MESH: + { + const GeometryData::TriangleMesh& mesh_data = geometry_data.getTriangleMesh(); + + const unsigned int prim_idx = optixGetPrimitiveIndex(); + const float2 barys = optixGetTriangleBarycentrics(); + + uint3 tri = make_uint3(0u, 0u, 0u); + if( mesh_data.indices.elmt_byte_size == 4 ) + { + const uint3* indices = reinterpret_cast( mesh_data.indices.data ); + tri = indices[ prim_idx ]; + } + else if( mesh_data.indices.elmt_byte_size == 2 ) + { + const ushort3* indices = reinterpret_cast( mesh_data.indices.data ); + tri = make_uint3( indices[prim_idx].x, indices[prim_idx].y, indices[prim_idx].z ); + } + else if( mesh_data.indices.elmt_byte_size == 1 ) + { + const uchar3* indices = reinterpret_cast( mesh_data.indices.data ); + tri = make_uint3( indices[prim_idx].x, indices[prim_idx].y, indices[prim_idx].z ); + } + else + { + const unsigned int base_idx = prim_idx * 3; + tri = make_uint3( base_idx + 0, base_idx + 1, base_idx + 2 ); + } + + const float3 P0 = mesh_data.positions[ tri.x ]; + const float3 P1 = mesh_data.positions[ tri.y ]; + const float3 P2 = mesh_data.positions[ tri.z ]; + lgeom.P = ( 1.0f-barys.x-barys.y)*P0 + barys.x*P1 + barys.y*P2; + lgeom.P = optixTransformPointFromObjectToWorldSpace( lgeom.P ); + + if( mesh_data.colors ) + { + const float4 COLOR0 = mesh_data.colors[tri.x]; + const float4 COLOR1 = mesh_data.colors[tri.y]; + const float4 COLOR2 = mesh_data.colors[tri.z]; + lgeom.color = ( 1.0f - barys.x - barys.y )*COLOR0 + barys.x*COLOR1 + barys.y*COLOR2; + } + else + { + lgeom.color = make_float4(1); + } + + lgeom.Ng = cross( P1-P0, P2-P0 ); + lgeom.Ng = normalize( optixTransformNormalFromObjectToWorldSpace( lgeom.Ng ) ); + + float3 N0, N1, N2; + if( mesh_data.normals ) + { + N0 = mesh_data.normals[ tri.x ]; + N1 = mesh_data.normals[ tri.y ]; + N2 = mesh_data.normals[ tri.z ]; + lgeom.N = ( 1.0f-barys.x-barys.y)*N0 + barys.x*N1 + barys.y*N2; + lgeom.N = normalize( optixTransformNormalFromObjectToWorldSpace( lgeom.N ) ); + } + else + { + lgeom.N = N0 = N1 = N2 = lgeom.Ng; + } + + const float3 dp1 = P0 - P2; + const float3 dp2 = P1 - P2; + + const float3 dn1 = N0 - N2; + const float3 dn2 = N1 - N2; + + for( size_t j = 0; j < GeometryData::num_texcoords; j++ ) + { + float2 UV0, UV1, UV2; + if( mesh_data.texcoords[j] ) + { + UV0 = mesh_data.texcoords[j][tri.x]; + UV1 = mesh_data.texcoords[j][tri.y]; + UV2 = mesh_data.texcoords[j][tri.z]; + lgeom.texcoord[j].UV = ( 1.0f - barys.x - barys.y )*UV0 + barys.x*UV1 + barys.y*UV2; + + const float du1 = UV0.x - UV2.x; + const float du2 = UV1.x - UV2.x; + const float dv1 = UV0.y - UV2.y; + const float dv2 = UV1.y - UV2.y; + + const float det = du1 * dv2 - dv1 * du2; + + const float invdet = 1.f / det; + lgeom.texcoord[j].dpdu = ( dv2 * dp1 - dv1 * dp2 ) * invdet; + lgeom.texcoord[j].dpdv = ( -du2 * dp1 + du1 * dp2 ) * invdet; + lgeom.texcoord[j].dndu = ( dv2 * dn1 - dv1 * dn2 ) * invdet; + lgeom.texcoord[j].dndv = ( -du2 * dn1 + du1 * dn2 ) * invdet; + } + else + { + lgeom.texcoord[j].UV = barys; + lgeom.texcoord[j].dpdu = -dp1; + lgeom.texcoord[j].dpdv = -dp1 + dp2; + lgeom.texcoord[j].dndu = -dn1; + lgeom.texcoord[j].dndv = -dn1 + dn2; + } + } + + break; + } + case GeometryData::SPHERE: + { + break; + } + default: break; + } + + + return lgeom; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/LocalShading.h b/Extern/3rdParty/OptiX/Linux/SDK/cuda/LocalShading.h new file mode 100644 index 00000000..838fabac --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/LocalShading.h @@ -0,0 +1,54 @@ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of NVIDIA CORPORATION nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +#pragma once + +#include +#include + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +template +__device__ __forceinline__ T sampleTexture( MaterialData::Texture tex, const LocalGeometry &geom ) +{ + if( tex.tex ) + { + const float2 UV = geom.texcoord[tex.texcoord].UV * tex.texcoord_scale; + const float2 rotation = tex.texcoord_rotation; + const float2 UV_trans = make_float2( + dot( UV, make_float2( rotation.y, rotation.x ) ), + dot( UV, make_float2( -rotation.x, rotation.y ) ) ) + tex.texcoord_offset; + return tex2D( tex.tex, UV_trans.x, UV_trans.y ); + } + else + { + return T(); + } +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/MaterialData.h b/Extern/3rdParty/OptiX/Linux/SDK/cuda/MaterialData.h new file mode 100644 index 00000000..5bf1fbed --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/MaterialData.h @@ -0,0 +1,143 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + + +struct MaterialData +{ + enum Type + { + PBR = 0, + GLASS = 1, + PHONG = 2, + CHECKER_PHONG = 3 + }; + + MaterialData() + { + type = MaterialData::PBR; + pbr.base_color = { 1.0f, 1.0f, 1.0f, 1.0f }; + pbr.metallic = 1.0f; + pbr.roughness = 1.0f; + pbr.base_color_tex = { 0, 0 }; + pbr.metallic_roughness_tex = { 0, 0 }; + } + + enum AlphaMode + { + ALPHA_MODE_OPAQUE = 0, + ALPHA_MODE_MASK = 1, + ALPHA_MODE_BLEND = 2 + }; + + struct Texture + { + __device__ __forceinline__ operator bool() const + { + return tex != 0; + } + + int texcoord; + cudaTextureObject_t tex; + + float2 texcoord_offset; + float2 texcoord_rotation; // sin,cos + float2 texcoord_scale; + }; + + struct Pbr + { + float4 base_color; + float metallic; + float roughness; + + Texture base_color_tex; + Texture metallic_roughness_tex; + }; + + struct CheckerPhong + { + float3 Kd1, Kd2; + float3 Ka1, Ka2; + float3 Ks1, Ks2; + float3 Kr1, Kr2; + float phong_exp1, phong_exp2; + float2 inv_checker_size; + }; + + struct Glass + { + float importance_cutoff; + float3 cutoff_color; + float fresnel_exponent; + float fresnel_minimum; + float fresnel_maximum; + float refraction_index; + float3 refraction_color; + float3 reflection_color; + float3 extinction_constant; + float3 shadow_attenuation; + int refraction_maxdepth; + int reflection_maxdepth; + }; + + struct Phong + { + float3 Ka; + float3 Kd; + float3 Ks; + float3 Kr; + float phong_exp; + }; + + Type type = PBR; + + Texture normal_tex = { 0 , 0 }; + + AlphaMode alpha_mode = ALPHA_MODE_OPAQUE; + float alpha_cutoff = 0.f; + + float3 emissive_factor = { 0.f, 0.f, 0.f }; + Texture emissive_tex = { 0, 0 }; + + bool doubleSided = false; + + union + { + Pbr pbr; + Glass glass; + Phong metal; + CheckerPhong checker; + }; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/camera.cu b/Extern/3rdParty/OptiX/Linux/SDK/cuda/camera.cu new file mode 100644 index 00000000..ee817405 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/camera.cu @@ -0,0 +1,80 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "helpers.h" +#include "random.h" +#include "whitted.h" + +extern "C" { +__constant__ whitted::LaunchParams params; +} + +extern "C" __global__ void __raygen__pinhole_camera() +{ + const uint3 idx = optixGetLaunchIndex(); + const uint3 dim = optixGetLaunchDimensions(); + + const unsigned int image_index = params.width * idx.y + idx.x; + unsigned int seed = tea<16>( image_index, params.subframe_index ); + + // Subpixel jitter: send the ray through a different position inside the pixel each time, + // to provide antialiasing. The center of each pixel is at fraction (0.5,0.5) + float2 subpixel_jitter = params.subframe_index == 0 ? make_float2( 0.5f, 0.5f ) : make_float2( rnd( seed ), rnd( seed ) ); + + float2 d = ( ( make_float2( idx.x, idx.y ) + subpixel_jitter ) / make_float2( params.width, params.height ) ) * 2.f - 1.f; + + float3 ray_origin = params.eye; + float3 ray_direction = normalize( d.x * params.U + d.y * params.V + params.W ); + + whitted::PayloadRadiance prd; + prd.importance = 1.f; + prd.depth = 0; + + optixTrace( params.handle, ray_origin, ray_direction, params.scene_epsilon, 1e16f, 0.0f, OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_NONE, whitted::RAY_TYPE_RADIANCE, whitted::RAY_TYPE_COUNT, whitted::RAY_TYPE_RADIANCE, + float3_as_args( prd.result ), reinterpret_cast( prd.importance ), + reinterpret_cast( prd.depth ) ); + + float4 acc_val = params.accum_buffer[image_index]; + if( params.subframe_index > 0 ) + { + acc_val = lerp( acc_val, make_float4( prd.result, 0.f ), 1.0f / static_cast( params.subframe_index + 1 ) ); + } + else + { + acc_val = make_float4( prd.result, 0.f ); + } + params.frame_buffer[image_index] = make_color( acc_val ); + params.accum_buffer[image_index] = acc_val; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/curve.h b/Extern/3rdParty/OptiX/Linux/SDK/cuda/curve.h new file mode 100644 index 00000000..69b90e4c --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/curve.h @@ -0,0 +1,446 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#include +#include +#include + + +// +// First order polynomial interpolator +// +struct LinearInterpolator +{ + __device__ __forceinline__ LinearInterpolator() {} + + __device__ __forceinline__ void initialize( const float4* q ) + { + p[0] = q[0]; + p[1] = q[1] - q[0]; + } + + + __device__ __forceinline__ float4 position4( float u ) const + { + return p[0] + u * p[1]; // Horner scheme + } + + __device__ __forceinline__ float3 position3( float u ) const + { + return make_float3( position4( u ) ); + } + + __device__ __forceinline__ float radius( const float& u ) const + { + return position4( u ).w; + } + + __device__ __forceinline__ float4 velocity4( float u ) const + { + return p[1]; + } + + __device__ __forceinline__ float3 velocity3( float u ) const + { + return make_float3( velocity4( u ) ); + } + + __device__ __forceinline__ float derivative_of_radius( float u ) const + { + return velocity4( u ).w; + } + + __device__ __forceinline__ float3 acceleration3( float u ) const { return make_float3( 0.f ); } + __device__ __forceinline__ float4 acceleration4( float u ) const { return make_float4( 0.f ); } + + + float4 p[2]; +}; + + +// +// Second order polynomial interpolator +// +struct QuadraticInterpolator +{ + __device__ __forceinline__ QuadraticInterpolator() {} + + __device__ __forceinline__ void initializeFromBSpline( const float4* q ) + { + // Bspline-to-Poly = Matrix([[1/2, -1, 1/2], + // [-1, 1, 0], + // [1/2, 1/2, 0]]) + p[0] = ( q[0] - 2.0f * q[1] + q[2] ) / 2.0f; + p[1] = ( -2.0f * q[0] + 2.0f * q[1] ) / 2.0f; + p[2] = ( q[0] + q[1] ) / 2.0f; + } + + __device__ __forceinline__ void export2BSpline( float4 bs[3] ) const + { + // inverse of initializeFromBSpline + // Bspline-to-Poly = Matrix([[1/2, -1, 1/2], + // [-1, 1, 0], + // [1/2, 1/2, 0]]) + // invert to get: + // Poly-to-Bspline = Matrix([[0, -1/2, 1], + // [0, 1/2, 1], + // [2, 3/2, 1]]) + bs[0] = p[0] - p[1] / 2; + bs[1] = p[0] + p[1] / 2; + bs[2] = p[0] + 1.5f * p[1] + 2 * p[2]; + } + + __device__ __forceinline__ float4 position4( float u ) const + { + return ( p[0] * u + p[1] ) * u + p[2]; // Horner scheme + } + + __device__ __forceinline__ float3 position3( float u ) const + { + return make_float3( position4( u ) ); + } + + __device__ __forceinline__ float radius( float u ) const + { + return position4( u ).w; + } + + __device__ __forceinline__ float4 velocity4( float u ) const + { + return 2.0f * p[0] * u + p[1]; + } + + __device__ __forceinline__ float3 velocity3( float u ) const + { + return make_float3( velocity4( u ) ); + } + + __device__ __forceinline__ float derivative_of_radius( float u ) const + { + return velocity4( u ).w; + } + + __device__ __forceinline__ float4 acceleration4( float u ) const + { + return 2.0f * p[0]; + } + + __device__ __forceinline__ float3 acceleration3( float u ) const + { + return make_float3( acceleration4( u ) ); + } + + + float4 p[3]; +}; + +// +// Third order polynomial interpolator +// +// Storing {p0, p1, p2, p3} for evaluation: +// P(u) = p0 * u^3 + p1 * u^2 + p2 * u + p3 +// +struct CubicInterpolator +{ + __device__ __forceinline__ CubicInterpolator() {} + + __device__ __forceinline__ void initializeFromBSpline( const float4* q ) + { + // Bspline-to-Poly = Matrix([[-1/6, 1/2, -1/2, 1/6], + // [ 1/2, -1, 1/2, 0], + // [-1/2, 0, 1/2, 0], + // [ 1/6, 2/3, 1/6, 0]]) + p[0] = ( q[0] * ( -1.0f ) + q[1] * ( 3.0f ) + q[2] * ( -3.0f ) + q[3] ) / 6.0f; + p[1] = ( q[0] * ( 3.0f ) + q[1] * ( -6.0f ) + q[2] * ( 3.0f ) ) / 6.0f; + p[2] = ( q[0] * ( -3.0f ) + q[2] * ( 3.0f ) ) / 6.0f; + p[3] = ( q[0] * ( 1.0f ) + q[1] * ( 4.0f ) + q[2] * ( 1.0f ) ) / 6.0f; + } + + __device__ __forceinline__ void export2BSpline( float4 bs[4] ) const + { + // inverse of initializeFromBSpline + // Bspline-to-Poly = Matrix([[-1/6, 1/2, -1/2, 1/6], + // [ 1/2, -1, 1/2, 0], + // [-1/2, 0, 1/2, 0], + // [ 1/6, 2/3, 1/6, 0]]) + // invert to get: + // Poly-to-Bspline = Matrix([[0, 2/3, -1, 1], + // [0, -1/3, 0, 1], + // [0, 2/3, 1, 1], + // [6, 11/3, 2, 1]]) + bs[0] = ( p[1] * ( 2.0f ) + p[2] * ( -1.0f ) + p[3] ) / 3.0f; + bs[1] = ( p[1] * ( -1.0f ) + p[3] ) / 3.0f; + bs[2] = ( p[1] * ( 2.0f ) + p[2] * ( 1.0f ) + p[3] ) / 3.0f; + bs[3] = ( p[0] + p[1] * ( 11.0f ) + p[2] * ( 2.0f ) + p[3] ) / 3.0f; + } + + + __device__ __forceinline__ void initializeFromCatrom(const float4* q) + { + // Catrom-to-Poly = Matrix([[-1/2, 3/2, -3/2, 1/2], + // [1, -5/2, 2, -1/2], + // [-1/2, 0, 1/2, 0], + // [0, 1, 0, 0]]) + p[0] = ( -1.0f * q[0] + ( 3.0f ) * q[1] + ( -3.0f ) * q[2] + ( 1.0f ) * q[3] ) / 2.0f; + p[1] = ( 2.0f * q[0] + ( -5.0f ) * q[1] + ( 4.0f ) * q[2] + ( -1.0f ) * q[3] ) / 2.0f; + p[2] = ( -1.0f * q[0] + ( 1.0f ) * q[2] ) / 2.0f; + p[3] = ( ( 2.0f ) * q[1] ) / 2.0f; + } + + __device__ __forceinline__ void export2Catrom(float4 cr[4]) const + { + // Catrom-to-Poly = Matrix([[-1/2, 3/2, -3/2, 1/2], + // [1, -5/2, 2, -1/2], + // [-1/2, 0, 1/2, 0], + // [0, 1, 0, 0]]) + // invert to get: + // Poly-to-Catrom = Matrix([[1, 1, -1, 1], + // [0, 0, 0, 1], + // [1, 1, 1, 1], + // [6, 4, 2, 1]]) + cr[0] = ( p[0] * 6.f/6.f ) - ( p[1] * 5.f/6.f ) + ( p[2] * 2.f/6.f ) + ( p[3] * 1.f/6.f ); + cr[1] = ( p[0] * 6.f/6.f ) ; + cr[2] = ( p[0] * 6.f/6.f ) + ( p[1] * 1.f/6.f ) + ( p[2] * 2.f/6.f ) + ( p[3] * 1.f/6.f ); + cr[3] = ( p[0] * 6.f/6.f ) + ( p[3] * 6.f/6.f ); + } + + __device__ __forceinline__ void initializeFromBezier(const float4* q) + { + // Bezier-to-Poly = Matrix([[-1, 3, -3, 1], + // [ 3, -6, 3, 0], + // [-3, 3, 0, 0], + // [ 1, 0, 0, 0]]) + p[0] = q[0] * ( -1.0f ) + q[1] * ( 3.0f ) + q[2] * ( -3.0f ) + q[3]; + p[1] = q[0] * ( 3.0f ) + q[1] * ( -6.0f ) + q[2] * ( 3.0f ); + p[2] = q[0] * ( -3.0f ) + q[1] * ( 3.0f ); + p[3] = q[0]; + } + + __device__ __forceinline__ void export2Bezier(float4 bz[4]) const + { + // inverse of initializeFromBezier + // Bezier-to-Poly = Matrix([[-1, 3, -3, 1], + // [ 3, -6, 3, 0], + // [-3, 3, 0, 0], + // [ 1, 0, 0, 0]]) + // invert to get: + // Poly-to-Bezier = Matrix([[0, 0, 0, 1], + // [0, 0, 1/3, 1], + // [0, 1/3, 2/3, 1], + // [1, 1, 1, 1]]) + bz[0] = p[3]; + bz[1] = p[2] * (1.f/3.f) + p[3]; + bz[2] = p[1] * (1.f/3.f) + p[2] * (2.f/3.f) + p[3]; + bz[3] = p[0] + p[1] + p[2] + p[3]; + } + + __device__ __forceinline__ float4 position4( float u ) const + { + return ( ( ( p[0] * u ) + p[1] ) * u + p[2] ) * u + p[3]; // Horner scheme + } + + __device__ __forceinline__ float3 position3( float u ) const + { + // rely on compiler and inlining for dead code removal + return make_float3( position4( u ) ); + } + __device__ __forceinline__ float radius( float u ) const + { + return position4( u ).w; + } + + __device__ __forceinline__ float4 velocity4( float u ) const + { + // adjust u to avoid problems with tripple knots. + if( u == 0 ) + u = 0.000001f; + if( u == 1 ) + u = 0.999999f; + return ( ( 3.0f * p[0] * u ) + 2.0f * p[1] ) * u + p[2]; + } + + __device__ __forceinline__ float3 velocity3( float u ) const + { + return make_float3( velocity4( u ) ); + } + + __device__ __forceinline__ float derivative_of_radius( float u ) const + { + return velocity4( u ).w; + } + + __device__ __forceinline__ float4 acceleration4( float u ) const + { + return 6.0f * p[0] * u + 2.0f * p[1]; // Horner scheme + } + + __device__ __forceinline__ float3 acceleration3( float u ) const + { + return make_float3( acceleration4( u ) ); + } + + float4 p[4]; +}; + + +// Compute curve primitive surface normal in object space. +// +// Template parameters: +// CurveType - A B-Spline evaluator class. +// type - 0 ~ cylindrical approximation (correct if radius' == 0) +// 1 ~ conic approximation (correct if curve'' == 0) +// other ~ the bona fide surface normal +// +// Parameters: +// bc - A B-Spline evaluator object. +// u - segment parameter of hit-point. +// ps - hit-point on curve's surface in object space; usually +// computed like this. +// float3 ps = ray_orig + t_hit * ray_dir; +// the resulting point is slightly offset away from the +// surface. For this reason (Warning!) ps gets modified by this +// method, projecting it onto the surface +// in case it is not already on it. (See also inline +// comments.) +// +template +__device__ __forceinline__ float3 surfaceNormal( const CurveType& bc, float u, float3& ps ) +{ + float3 normal; + if( u == 0.0f ) + { + normal = -bc.velocity3( 0 ); // special handling for flat endcaps + } + else if( u == 1.0f ) + { + normal = bc.velocity3( 1 ); // special handling for flat endcaps + } + else + { + // ps is a point that is near the curve's offset surface, + // usually ray.origin + ray.direction * rayt. + // We will push it exactly to the surface by projecting it to the plane(p,d). + // The function derivation: + // we (implicitly) transform the curve into coordinate system + // {p, o1 = normalize(ps - p), o2 = normalize(curve'(t)), o3 = o1 x o2} in which + // curve'(t) = (0, length(d), 0); ps = (r, 0, 0); + float4 p4 = bc.position4( u ); + float3 p = make_float3( p4 ); + float r = p4.w; // == length(ps - p) if ps is already on the surface + float4 d4 = bc.velocity4( u ); + float3 d = make_float3( d4 ); + float dr = d4.w; + float dd = dot( d, d ); + + float3 o1 = ps - p; // dot(modified_o1, d) == 0 by design: + o1 -= ( dot( o1, d ) / dd ) * d; // first, project ps to the plane(p,d) + o1 *= r / length( o1 ); // and then drop it to the surface + ps = p + o1; // fine-tuning the hit point + if( type == 0 ) + { + normal = o1; // cylindrical approximation + } + else + { + if( type != 1 ) + { + dd -= dot( bc.acceleration3( u ), o1 ); + } + normal = dd * o1 - ( dr * r ) * d; + } + } + return normalize( normal ); +} + +template +__device__ __forceinline__ float3 surfaceNormal( const LinearInterpolator& bc, float u, float3& ps ) +{ + float3 normal; + if( u == 0.0f ) + { + normal = ps - ( float3 & )( bc.p[0] ); // special handling for round endcaps + } + else if( u >= 1.0f ) + { + // reconstruct second control point (Note: the interpolator pre-transforms + // the control-points to speed up repeated evaluation. + const float3 p1 = ( float3 & ) (bc.p[1] ) + ( float3 & )( bc.p[0] ); + normal = ps - p1; // special handling for round endcaps + } + else + { + // ps is a point that is near the curve's offset surface, + // usually ray.origin + ray.direction * rayt. + // We will push it exactly to the surface by projecting it to the plane(p,d). + // The function derivation: + // we (implicitly) transform the curve into coordinate system + // {p, o1 = normalize(ps - p), o2 = normalize(curve'(t)), o3 = o1 x o2} in which + // curve'(t) = (0, length(d), 0); ps = (r, 0, 0); + float4 p4 = bc.position4( u ); + float3 p = make_float3( p4 ); + float r = p4.w; // == length(ps - p) if ps is already on the surface + float4 d4 = bc.velocity4( u ); + float3 d = make_float3( d4 ); + float dr = d4.w; + float dd = dot( d, d ); + + float3 o1 = ps - p; // dot(modified_o1, d) == 0 by design: + o1 -= ( dot( o1, d ) / dd ) * d; // first, project ps to the plane(p,d) + o1 *= r / length( o1 ); // and then drop it to the surface + ps = p + o1; // fine-tuning the hit point + if( type == 0 ) + { + normal = o1; // cylindrical approximation + } + else + { + normal = dd * o1 - ( dr * r ) * d; + } + } + return normalize( normal ); +} + +// Compute curve primitive tangent in object space. +// +// Template parameters: +// CurveType - A B-Spline evaluator class. +// +// Parameters: +// bc - A B-Spline evaluator object. +// u - segment parameter of tangent location on curve. +// +template +__device__ __forceinline__ float3 curveTangent( const CurveType& bc, float u ) +{ + float3 tangent = bc.velocity3( u ); + return normalize( tangent ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/geometry.cu b/Extern/3rdParty/OptiX/Linux/SDK/cuda/geometry.cu new file mode 100644 index 00000000..05ebc27b --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/geometry.cu @@ -0,0 +1,147 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "helpers.h" +#include "whitted.h" + +extern "C" { +__constant__ whitted::LaunchParams params; +} + +extern "C" __global__ void __intersection__parallelogram() +{ + const whitted::HitGroupData* sbt_data = reinterpret_cast( optixGetSbtDataPointer() ); + const GeometryData::Parallelogram& floor = sbt_data->geometry_data.getParallelogram(); + + const float3 ray_orig = optixGetWorldRayOrigin(); + const float3 ray_dir = optixGetWorldRayDirection(); + const float ray_tmin = optixGetRayTmin(), ray_tmax = optixGetRayTmax(); + + float3 n = make_float3( floor.plane ); + float dt = dot( ray_dir, n ); + float t = ( floor.plane.w - dot( n, ray_orig ) ) / dt; + if( t > ray_tmin && t < ray_tmax ) + { + float3 p = ray_orig + ray_dir * t; + float3 vi = p - floor.anchor; + float a1 = dot( floor.v1, vi ); + if( a1 >= 0 && a1 <= 1 ) + { + float a2 = dot( floor.v2, vi ); + if( a2 >= 0 && a2 <= 1 ) + { + optixReportIntersection( t, 0, float3_as_args( n ), __float_as_uint( a1 ), __float_as_uint( a2 ) ); + } + } + } +} + + +extern "C" __global__ void __intersection__sphere_shell() +{ + const whitted::HitGroupData* sbt_data = reinterpret_cast( optixGetSbtDataPointer() ); + const GeometryData::SphereShell& sphere_shell = sbt_data->geometry_data.getSphereShell(); + + const float3 ray_orig = optixGetWorldRayOrigin(); + const float3 ray_dir = optixGetWorldRayDirection(); + const float ray_tmin = optixGetRayTmin(), ray_tmax = optixGetRayTmax(); + + float3 O = ray_orig - sphere_shell.center; + float l = 1 / length( ray_dir ); + float3 D = ray_dir * l; + + float b = dot( O, D ), sqr_b = b * b; + float O_dot_O = dot( O, O ); + float radius1 = sphere_shell.radius1, radius2 = sphere_shell.radius2; + float sqr_radius1 = radius1 * radius1, sqr_radius2 = radius2 * radius2; + + // check if we are outside of outer sphere + if( O_dot_O > sqr_radius2 + params.scene_epsilon ) + { + if( O_dot_O - sqr_b < sqr_radius2 - params.scene_epsilon ) + { + float c = O_dot_O - sqr_radius2; + float root = sqr_b - c; + if( root > 0.0f ) + { + float t = -b - sqrtf( root ); + float3 normal = ( O + t * D ) / radius2; + optixReportIntersection( t * l, GeometryData::SphereShell::HIT_OUTSIDE_FROM_OUTSIDE, float3_as_args( normal ) ); + } + } + } + // else we are inside of the outer sphere + else + { + float c = O_dot_O - sqr_radius1; + float root = b * b - c; + if( root > 0.0f ) + { + float t = -b - sqrtf( root ); + // do we hit inner sphere from between spheres? + if( t * l > ray_tmin && t * l < ray_tmax ) + { + float3 normal = ( O + t * D ) / ( -radius1 ); + optixReportIntersection( t * l, GeometryData::SphereShell::HIT_INSIDE_FROM_OUTSIDE, float3_as_args( normal ) ); + } + else + { + // do we hit inner sphere from within both spheres? + t = -b + ( root > 0 ? sqrtf( root ) : 0.f ); + if( t * l > ray_tmin && t * l < ray_tmax ) + { + float3 normal = ( O + t * D ) / ( -radius1 ); + optixReportIntersection( t * l, GeometryData::SphereShell::HIT_INSIDE_FROM_INSIDE, float3_as_args( normal ) ); + } + else + { + // do we hit outer sphere from between spheres? + c = O_dot_O - sqr_radius2; + root = b * b - c; + t = -b + ( root > 0 ? sqrtf( root ) : 0.f ); + float3 normal = ( O + t * D ) / radius2; + optixReportIntersection( t * l, GeometryData::SphereShell::HIT_OUTSIDE_FROM_INSIDE, float3_as_args( normal ) ); + } + } + } + else + { + // do we hit outer sphere from between spheres? + c = O_dot_O - sqr_radius2; + root = b * b - c; + float t = -b + ( root > 0 ? sqrtf( root ) : 0.f ); + float3 normal = ( O + t * D ) / radius2; + optixReportIntersection( t * l, GeometryData::SphereShell::HIT_OUTSIDE_FROM_INSIDE, float3_as_args( normal ) ); + } + } +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/helpers.h b/Extern/3rdParty/OptiX/Linux/SDK/cuda/helpers.h new file mode 100644 index 00000000..23bfe857 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/helpers.h @@ -0,0 +1,141 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + + +__forceinline__ __device__ float3 toSRGB( const float3& c ) +{ + float invGamma = 1.0f / 2.4f; + float3 powed = make_float3( powf( c.x, invGamma ), powf( c.y, invGamma ), powf( c.z, invGamma ) ); + return make_float3( + c.x < 0.0031308f ? 12.92f * c.x : 1.055f * powed.x - 0.055f, + c.y < 0.0031308f ? 12.92f * c.y : 1.055f * powed.y - 0.055f, + c.z < 0.0031308f ? 12.92f * c.z : 1.055f * powed.z - 0.055f ); +} + +//__forceinline__ __device__ float dequantizeUnsigned8Bits( const unsigned char i ) +//{ +// enum { N = (1 << 8) - 1 }; +// return min((float)i / (float)N), 1.f) +//} +__forceinline__ __device__ unsigned char quantizeUnsigned8Bits( float x ) +{ + x = clamp( x, 0.0f, 1.0f ); + enum { N = (1 << 8) - 1, Np1 = (1 << 8) }; + return (unsigned char)min((unsigned int)(x * (float)Np1), (unsigned int)N); +} + +__forceinline__ __device__ uchar4 make_color( const float3& c ) +{ + // first apply gamma, then convert to unsigned char + float3 srgb = toSRGB( clamp( c, 0.0f, 1.0f ) ); + return make_uchar4( quantizeUnsigned8Bits( srgb.x ), quantizeUnsigned8Bits( srgb.y ), quantizeUnsigned8Bits( srgb.z ), 255u ); +} +__forceinline__ __device__ uchar4 make_color( const float4& c ) +{ + return make_color( make_float3( c.x, c.y, c.z ) ); +} + +__forceinline__ __device__ float luminance( const float3& rgb ) +{ + const float3 ntsc_luminance = { 0.30f, 0.59f, 0.11f }; + return dot( rgb, ntsc_luminance ); +} + +__forceinline__ __device__ float fresnel_schlick( const float cos_theta, + const float exponent = 5.0f, + const float minimum = 0.0f, + const float maximum = 1.0f ) +{ + /** + Clamp the result of the arithmetic due to floating point precision: + the result should lie strictly within [minimum, maximum] + return clamp(minimum + (maximum - minimum) * powf(1.0f - cos_theta, exponent), + minimum, maximum); + */ + + /** The max doesn't seem like it should be necessary, but without it you get + annoying broken pixels at the center of reflective spheres where cos_theta ~ 1. + */ + return clamp( minimum + ( maximum - minimum ) * powf( fmaxf( 0.0f, 1.0f - cos_theta ), exponent ), minimum, maximum ); +} + +__forceinline__ __device__ float3 fresnel_schlick( const float cos_theta, const float exponent, const float3& minimum, const float3& maximum ) +{ + return make_float3( fresnel_schlick( cos_theta, exponent, minimum.x, maximum.x ), + fresnel_schlick( cos_theta, exponent, minimum.y, maximum.y ), + fresnel_schlick( cos_theta, exponent, minimum.z, maximum.z ) ); +} + +__forceinline__ __device__ bool refract( float3& r, const float3& i, const float3& n, const float ior ) +{ + float3 nn = n; + float negNdotV = dot( i, nn ); + float eta; + + if( negNdotV > 0.0f ) + { + eta = ior; + nn = -n; + negNdotV = -negNdotV; + } + else + { + eta = 1.f / ior; + } + + const float k = 1.f - eta * eta * ( 1.f - negNdotV * negNdotV ); + + if( k < 0.0f ) + { + // Initialize this value, so that r always leaves this function initialized. + r = make_float3( 0.f ); + return false; + } + else + { + r = normalize( eta * i - ( eta * negNdotV + sqrtf( k ) ) * nn ); + return true; + } +} + +__forceinline__ __device__ float3 exp( const float3& x ) +{ + return make_float3( exp( x.x ), exp( x.y ), exp( x.z ) ); +} + +#define float3_as_args( u ) \ + reinterpret_cast( ( u ).x ), reinterpret_cast( ( u ).y ), \ + reinterpret_cast( ( u ).z ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/random.h b/Extern/3rdParty/OptiX/Linux/SDK/cuda/random.h new file mode 100644 index 00000000..6b34b694 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/random.h @@ -0,0 +1,75 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +template +static __host__ __device__ __inline__ unsigned int tea( unsigned int val0, unsigned int val1 ) +{ + unsigned int v0 = val0; + unsigned int v1 = val1; + unsigned int s0 = 0; + + for( unsigned int n = 0; n < N; n++ ) + { + s0 += 0x9e3779b9; + v0 += ((v1<<4)+0xa341316c)^(v1+s0)^((v1>>5)+0xc8013ea4); + v1 += ((v0<<4)+0xad90777d)^(v0+s0)^((v0>>5)+0x7e95761e); + } + + return v0; +} + +// Generate random unsigned int in [0, 2^24) +static __host__ __device__ __inline__ unsigned int lcg(unsigned int &prev) +{ + const unsigned int LCG_A = 1664525u; + const unsigned int LCG_C = 1013904223u; + prev = (LCG_A * prev + LCG_C); + return prev & 0x00FFFFFF; +} + +static __host__ __device__ __inline__ unsigned int lcg2(unsigned int &prev) +{ + prev = (prev*8121 + 28411) % 134456; + return prev; +} + +// Generate random float in [0, 1) +static __host__ __device__ __inline__ float rnd(unsigned int &prev) +{ + return ((float) lcg(prev) / (float) 0x01000000); +} + +static __host__ __device__ __inline__ unsigned int rot_seed( unsigned int seed, unsigned int frame ) +{ + return seed ^ frame; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/shading.cu b/Extern/3rdParty/OptiX/Linux/SDK/cuda/shading.cu new file mode 100644 index 00000000..9e9cdbe9 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/shading.cu @@ -0,0 +1,363 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "helpers.h" +#include "whitted.h" + +extern "C" { +__constant__ whitted::LaunchParams params; +} + +static __device__ __inline__ whitted::PayloadRadiance getPayloadRadiance() +{ + whitted::PayloadRadiance prd; + prd.result.x = __uint_as_float( optixGetPayload_0() ); + prd.result.y = __uint_as_float( optixGetPayload_1() ); + prd.result.z = __uint_as_float( optixGetPayload_2() ); + prd.importance = __uint_as_float( optixGetPayload_3() ); + prd.depth = optixGetPayload_4(); + return prd; +} + +static __device__ __inline__ void setPayloadRadiance( const whitted::PayloadRadiance& prd ) +{ + optixSetPayload_0( __float_as_uint( prd.result.x ) ); + optixSetPayload_1( __float_as_uint( prd.result.y ) ); + optixSetPayload_2( __float_as_uint( prd.result.z ) ); + optixSetPayload_3( __float_as_uint( prd.importance ) ); + optixSetPayload_4( prd.depth ); +} + +static __device__ __inline__ whitted::PayloadOcclusion getPayloadOcclusion() +{ + whitted::PayloadOcclusion prd; + prd.result.x = __uint_as_float( optixGetPayload_0() ); + prd.result.y = __uint_as_float( optixGetPayload_1() ); + prd.result.z = __uint_as_float( optixGetPayload_2() ); + return prd; +} + +static __device__ __inline__ void setPayloadOcclusion( const whitted::PayloadOcclusion& prd ) +{ + optixSetPayload_0( __float_as_uint( prd.result.x ) ); + optixSetPayload_1( __float_as_uint( prd.result.y ) ); + optixSetPayload_2( __float_as_uint( prd.result.z ) ); +} + +static __device__ __inline__ float3 traceRadianceRay( float3 origin, float3 direction, int depth, float importance ) +{ + whitted::PayloadRadiance prd; + prd.depth = depth; + prd.importance = importance; + + optixTrace( params.handle, origin, direction, params.scene_epsilon, 1e16f, 0.0f, OptixVisibilityMask( 1 ), OPTIX_RAY_FLAG_NONE, + whitted::RAY_TYPE_RADIANCE, whitted::RAY_TYPE_COUNT, whitted::RAY_TYPE_RADIANCE, float3_as_args( prd.result ), + /* Can't use __float_as_uint() because it returns rvalue but payload requires a lvalue */ + reinterpret_cast( prd.importance ), reinterpret_cast( prd.depth ) ); + + return prd.result; +} + +static __device__ void phongShadowed() +{ + // this material is opaque, so it fully attenuates all shadow rays + whitted::PayloadOcclusion prd; + prd.result = make_float3( 0.f ); + setPayloadOcclusion( prd ); +} + +static __device__ void phongShade( float3 p_Kd, float3 p_Ka, float3 p_Ks, float3 p_Kr, float p_phong_exp, float3 p_normal ) +{ + const float3 ray_orig = optixGetWorldRayOrigin(); + const float3 ray_dir = optixGetWorldRayDirection(); + const float ray_t = optixGetRayTmax(); + + whitted::PayloadRadiance prd = getPayloadRadiance(); + + float3 hit_point = ray_orig + ray_t * ray_dir; + + // ambient contribution + Light::Ambient ambient_light = params.lights[0].ambient; + float3 result = p_Ka * ambient_light.color; + + // compute direct lighting + Light::Point point_light = params.lights[1].point; + float Ldist = length( point_light.position - hit_point ); + float3 L = normalize( point_light.position - hit_point ); + float nDl = dot( p_normal, L ); + + // cast shadow ray + float3 light_attenuation = make_float3( static_cast( nDl > 0.0f ) ); + if( nDl > 0.0f ) + { + whitted::PayloadOcclusion shadow_prd; + shadow_prd.result = make_float3( 1.0f ); + + optixTrace( params.handle, hit_point, L, 0.01f, Ldist, 0.0f, OptixVisibilityMask( 1 ), OPTIX_RAY_FLAG_NONE, + whitted::RAY_TYPE_OCCLUSION, whitted::RAY_TYPE_COUNT, whitted::RAY_TYPE_OCCLUSION, + float3_as_args( shadow_prd.result ) ); + + light_attenuation = shadow_prd.result; + } + + // If not completely shadowed, light the hit point + if( fmaxf( light_attenuation ) > 0.0f ) + { + float3 Lc = point_light.color * light_attenuation; + + result += p_Kd * nDl * Lc; + + float3 H = normalize( L - ray_dir ); + float nDh = dot( p_normal, H ); + if( nDh > 0 ) + { + float power = pow( nDh, p_phong_exp ); + result += p_Ks * power * Lc; + } + } + + if( fmaxf( p_Kr ) > 0 ) + { + + // ray tree attenuation + float new_importance = prd.importance * luminance( p_Kr ); + int new_depth = prd.depth + 1; + + // reflection ray + // compare new_depth to max_depth - 1 to leave room for a potential shadow ray trace + if( new_importance >= 0.01f && new_depth <= params.max_depth - 1 ) + { + float3 R = reflect( ray_dir, p_normal ); + + result += p_Kr * traceRadianceRay( hit_point, R, new_depth, new_importance ); + } + } + + // pass the color back + prd.result = result; + setPayloadRadiance( prd ); +} + +extern "C" __global__ void __closesthit__checker_radiance() +{ + const whitted::HitGroupData* sbt_data = (whitted::HitGroupData*)optixGetSbtDataPointer(); + const MaterialData::CheckerPhong& checker = sbt_data->material_data.checker; + + float3 Kd, Ka, Ks, Kr; + float phong_exp; + + float2 texcoord = make_float2( __uint_as_float( optixGetAttribute_3() ), __uint_as_float( optixGetAttribute_4() ) ); + float2 t = texcoord * checker.inv_checker_size; + t.x = floorf( t.x ); + t.y = floorf( t.y ); + + int which_check = ( static_cast( t.x ) + static_cast( t.y ) ) & 1; + + if( which_check ) + { + Kd = checker.Kd1; + Ka = checker.Ka1; + Ks = checker.Ks1; + Kr = checker.Kr1; + phong_exp = checker.phong_exp1; + } + else + { + Kd = checker.Kd2; + Ka = checker.Ka2; + Ks = checker.Ks2; + Kr = checker.Kr2; + phong_exp = checker.phong_exp2; + } + + float3 object_normal = make_float3( __uint_as_float( optixGetAttribute_0() ), __uint_as_float( optixGetAttribute_1() ), + __uint_as_float( optixGetAttribute_2() ) ); + float3 world_normal = normalize( optixTransformNormalFromObjectToWorldSpace( object_normal ) ); + float3 ffnormal = faceforward( world_normal, -optixGetWorldRayDirection(), world_normal ); + phongShade( Kd, Ka, Ks, Kr, phong_exp, ffnormal ); +} + +extern "C" __global__ void __closesthit__metal_radiance() +{ + const whitted::HitGroupData* sbt_data = (whitted::HitGroupData*)optixGetSbtDataPointer(); + const MaterialData::Phong& phong = sbt_data->material_data.metal; + + float3 object_normal = make_float3( __uint_as_float( optixGetAttribute_0() ), __uint_as_float( optixGetAttribute_1() ), + __uint_as_float( optixGetAttribute_2() ) ); + + float3 world_normal = normalize( optixTransformNormalFromObjectToWorldSpace( object_normal ) ); + float3 ffnormal = faceforward( world_normal, -optixGetWorldRayDirection(), world_normal ); + phongShade( phong.Kd, phong.Ka, phong.Ks, phong.Kr, phong.phong_exp, ffnormal ); +} + +extern "C" __global__ void __closesthit__full_occlusion() +{ + phongShadowed(); +} + +extern "C" __global__ void __closesthit__glass_radiance() +{ + const whitted::HitGroupData* sbt_data = (whitted::HitGroupData*)optixGetSbtDataPointer(); + const MaterialData::Glass& glass = sbt_data->material_data.glass; + + whitted::PayloadRadiance prd_radiance = getPayloadRadiance(); + + float3 object_normal = make_float3( __uint_as_float( optixGetAttribute_0() ), __uint_as_float( optixGetAttribute_1() ), + __uint_as_float( optixGetAttribute_2() ) ); + object_normal = normalize( object_normal ); + + // intersection vectors + const float3 n = normalize( optixTransformNormalFromObjectToWorldSpace( object_normal ) ); // normal + const float3 ray_orig = optixGetWorldRayOrigin(); + const float3 ray_dir = optixGetWorldRayDirection(); // incident direction + const float ray_t = optixGetRayTmax(); + float3 t; // transmission direction + float3 r; // reflection direction + + float3 hit_point = ray_orig + ray_t * ray_dir; + GeometryData::SphereShell::HitType hit_type = (GeometryData::SphereShell::HitType)optixGetHitKind(); + float3 front_hit_point = hit_point, back_hit_point = hit_point; + + if( hit_type & GeometryData::SphereShell::HIT_OUTSIDE_FROM_OUTSIDE || hit_type & GeometryData::SphereShell::HIT_INSIDE_FROM_INSIDE ) + { + front_hit_point += params.scene_epsilon * object_normal; + back_hit_point -= params.scene_epsilon * object_normal; + } + else + { + front_hit_point -= params.scene_epsilon * object_normal; + back_hit_point += params.scene_epsilon * object_normal; + } + + const float3 fhp = optixTransformPointFromObjectToWorldSpace( front_hit_point ); + const float3 bhp = optixTransformPointFromObjectToWorldSpace( back_hit_point ); + + float reflection = 1.0f; + float3 result = make_float3( 0.0f ); + + const int depth = prd_radiance.depth; + + float3 beer_attenuation; + if( dot( n, ray_dir ) > 0 ) + { + // Beer's law attenuation + beer_attenuation = exp( glass.extinction_constant * ray_t ); + } + else + { + beer_attenuation = make_float3( 1 ); + } + + // refraction + // compare depth to max_depth - 1 to leave room for a potential shadow ray trace + if( depth < min( glass.refraction_maxdepth, params.max_depth - 1 ) ) + { + if( refract( t, ray_dir, n, glass.refraction_index ) ) + { + // check for external or internal reflection + float cos_theta = dot( ray_dir, n ); + if( cos_theta < 0.0f ) + cos_theta = -cos_theta; + else + cos_theta = dot( t, n ); + + reflection = fresnel_schlick( cos_theta, glass.fresnel_exponent, glass.fresnel_minimum, glass.fresnel_maximum ); + + float importance = + prd_radiance.importance * ( 1.0f - reflection ) * luminance( glass.refraction_color * beer_attenuation ); + float3 color = glass.cutoff_color; + if( importance > glass.importance_cutoff ) + { + color = traceRadianceRay( bhp, t, depth + 1, importance ); + } + result += ( 1.0f - reflection ) * glass.refraction_color * color; + } + // else TIR + } // else reflection==1 so refraction has 0 weight + + // reflection + // compare depth to max_depth - 1 to leave room for a potential shadow ray trace + float3 color = glass.cutoff_color; + if( depth < min( glass.reflection_maxdepth, params.max_depth - 1 ) ) + { + r = reflect( ray_dir, n ); + + float importance = prd_radiance.importance * reflection * luminance( glass.reflection_color * beer_attenuation ); + if( importance > glass.importance_cutoff ) + { + color = traceRadianceRay( fhp, r, depth + 1, importance ); + } + } + result += reflection * glass.reflection_color * color; + + result = result * beer_attenuation; + + prd_radiance.result = result; + setPayloadRadiance( prd_radiance ); +} + +extern "C" __global__ void __anyhit__glass_occlusion() +{ + const whitted::HitGroupData* sbt_data = (whitted::HitGroupData*)optixGetSbtDataPointer(); + const MaterialData::Glass& glass = sbt_data->material_data.glass; + + float3 object_normal = make_float3( __uint_as_float( optixGetAttribute_0() ), __uint_as_float( optixGetAttribute_1() ), + __uint_as_float( optixGetAttribute_2() ) ); + + whitted::PayloadOcclusion shadow_prd = getPayloadOcclusion(); + + float3 world_normal = normalize( optixTransformNormalFromObjectToWorldSpace( object_normal ) ); + float nDi = fabs( dot( world_normal, optixGetWorldRayDirection() ) ); + + shadow_prd.result *= 1 - fresnel_schlick( nDi, 5, 1 - glass.shadow_attenuation, make_float3( 1 ) ); + setPayloadOcclusion( shadow_prd ); + + // Test the attenuation of the light from the glass shell + if( luminance( shadow_prd.result ) < glass.importance_cutoff ) + // The attenuation is so high, > 99% blocked, that we can consider testing to be done. + optixTerminateRay(); + else + // There is still some light coming through the glass shell that we should test other occluders. + // We "ignore" the intersection with the glass shell, meaning that shadow testing will continue. + // If the ray does not hit another occluder, the light's attenuation from this glass shell + // (along with other glass shells) is then used. + optixIgnoreIntersection(); +} + +extern "C" __global__ void __miss__constant_bg() +{ + whitted::PayloadRadiance prd = getPayloadRadiance(); + prd.result = params.miss_color; + setPayloadRadiance( prd ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/sphere.cu b/Extern/3rdParty/OptiX/Linux/SDK/cuda/sphere.cu new file mode 100644 index 00000000..ef8fd015 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/sphere.cu @@ -0,0 +1,100 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include + +#include "whitted.h" + +#define float3_as_uints( u ) __float_as_uint( u.x ), __float_as_uint( u.y ), __float_as_uint( u.z ) + +extern "C" __global__ void __intersection__sphere() +{ + const whitted::HitGroupData* hit_group_data = reinterpret_cast( optixGetSbtDataPointer() ); + + const float3 ray_orig = optixGetWorldRayOrigin(); + const float3 ray_dir = optixGetWorldRayDirection(); + const float ray_tmin = optixGetRayTmin(); + const float ray_tmax = optixGetRayTmax(); + + const float3 O = ray_orig - hit_group_data->geometry_data.getSphere().center; + const float l = 1.0f / length( ray_dir ); + const float3 D = ray_dir * l; + const float radius = hit_group_data->geometry_data.getSphere().radius; + + float b = dot( O, D ); + float c = dot( O, O ) - radius * radius; + float disc = b * b - c; + if( disc > 0.0f ) + { + float sdisc = sqrtf( disc ); + float root1 = ( -b - sdisc ); + float root11 = 0.0f; + bool check_second = true; + + const bool do_refine = fabsf( root1 ) > ( 10.0f * radius ); + + if( do_refine ) + { + // refine root1 + float3 O1 = O + root1 * D; + b = dot( O1, D ); + c = dot( O1, O1 ) - radius * radius; + disc = b * b - c; + + if( disc > 0.0f ) + { + sdisc = sqrtf( disc ); + root11 = ( -b - sdisc ); + } + } + + float t; + float3 normal; + t = ( root1 + root11 ) * l; + if( t > ray_tmin && t < ray_tmax ) + { + normal = ( O + ( root1 + root11 ) * D ) / radius; + if( optixReportIntersection( t, 0, float3_as_uints( normal ), __float_as_uint( radius ) ) ) + check_second = false; + } + + if( check_second ) + { + float root2 = ( -b + sdisc ) + ( do_refine ? root1 : 0 ); + t = root2 * l; + normal = ( O + root2 * D ) / radius; + if( t > ray_tmin && t < ray_tmax ) + optixReportIntersection( t, 0, float3_as_uints( normal ), __float_as_uint( radius ) ); + } + } +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/util.h b/Extern/3rdParty/OptiX/Linux/SDK/cuda/util.h new file mode 100644 index 00000000..83440904 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/util.h @@ -0,0 +1,51 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#ifndef __CUDACC_RTC__ +#include +#endif + +#define if_pixel( x_, y_ ) \ + const uint3 launch_idx__ = optixGetLaunchIndex(); \ + if( launch_idx__.x == (x_) && launch_idx__.y == (y_) ) \ + +#define print_pixel( x_, y_, str, ... ) \ +do \ +{ \ + const uint3 launch_idx = optixGetLaunchIndex(); \ + if( launch_idx.x == (x_) && launch_idx.y == (y_) ) \ + { \ + printf( str, __VA_ARGS__ ); \ + } \ +} while(0); + + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/whitted.cu b/Extern/3rdParty/OptiX/Linux/SDK/cuda/whitted.cu new file mode 100644 index 00000000..d0e599d6 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/whitted.cu @@ -0,0 +1,292 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include +#include +#include +#include +#include + +#include "whitted_cuda.h" + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +extern "C" __global__ void __raygen__pinhole() +{ + const uint3 launch_idx = optixGetLaunchIndex(); + const uint3 launch_dims = optixGetLaunchDimensions(); + const float3 eye = whitted::params.eye; + const float3 U = whitted::params.U; + const float3 V = whitted::params.V; + const float3 W = whitted::params.W; + const int subframe_index = whitted::params.subframe_index; + + // + // Generate camera ray + // + unsigned int seed = tea<4>( launch_idx.y * launch_dims.x + launch_idx.x, subframe_index ); + + // The center of each pixel is at fraction (0.5,0.5) + const float2 subpixel_jitter = + subframe_index == 0 ? make_float2( 0.5f, 0.5f ) : make_float2( rnd( seed ), rnd( seed ) ); + + const float2 d = + 2.0f + * make_float2( ( static_cast( launch_idx.x ) + subpixel_jitter.x ) / static_cast( launch_dims.x ), + ( static_cast( launch_idx.y ) + subpixel_jitter.y ) / static_cast( launch_dims.y ) ) + - 1.0f; + const float3 ray_direction = normalize( d.x * U + d.y * V + W ); + const float3 ray_origin = eye; + + // + // Trace camera ray + // + whitted::PayloadRadiance payload; + payload.result = make_float3( 0.0f ); + payload.depth = 0; + + traceRadiance( whitted::params.handle, ray_origin, ray_direction, + 0.00f, // tmin + 1e16f, // tmax + &payload ); + + // + // Update results + // TODO: timview mode + // + const unsigned int image_index = launch_idx.y * launch_dims.x + launch_idx.x; + float3 accum_color = payload.result; + + if( subframe_index > 0 ) + { + const float a = 1.0f / static_cast( subframe_index + 1 ); + const float3 accum_color_prev = make_float3( whitted::params.accum_buffer[image_index] ); + accum_color = lerp( accum_color_prev, accum_color, a ); + } + whitted::params.accum_buffer[image_index] = make_float4( accum_color, 1.0f ); + whitted::params.frame_buffer[image_index] = make_color( accum_color ); +} + +extern "C" __global__ void __anyhit__radiance() +{ + const whitted::HitGroupData* hit_group_data = reinterpret_cast< whitted::HitGroupData* >( optixGetSbtDataPointer() ); + if( hit_group_data->material_data.pbr.base_color_tex ) + { + const LocalGeometry geom = getLocalGeometry( hit_group_data->geometry_data ); + const float base_alpha = sampleTexture( hit_group_data->material_data.pbr.base_color_tex, geom ).w; + // force mask mode, even for blend mode, as we don't do recursive traversal. + if( base_alpha < hit_group_data->material_data.alpha_cutoff ) + optixIgnoreIntersection(); + } +} + +extern "C" __global__ void __anyhit__occlusion() +{ + const whitted::HitGroupData* hit_group_data = reinterpret_cast< whitted::HitGroupData* >( optixGetSbtDataPointer() ); + if( hit_group_data->material_data.pbr.base_color_tex ) + { + const LocalGeometry geom = getLocalGeometry( hit_group_data->geometry_data ); + const float base_alpha = sampleTexture( hit_group_data->material_data.pbr.base_color_tex, geom ).w; + + if( hit_group_data->material_data.alpha_mode != MaterialData::ALPHA_MODE_OPAQUE ) + { + if( hit_group_data->material_data.alpha_mode == MaterialData::ALPHA_MODE_MASK ) + { + if( base_alpha < hit_group_data->material_data.alpha_cutoff ) + optixIgnoreIntersection(); + } + + float attenuation = whitted::getPayloadOcclusion() * (1.f - base_alpha); + if( attenuation > 0.f ) + { + whitted::setPayloadOcclusion( attenuation ); + optixIgnoreIntersection(); + } + } + } +} + +extern "C" __global__ void __miss__constant_radiance() +{ + whitted::setPayloadResult( whitted::params.miss_color ); +} + +extern "C" __global__ void __miss__occlusion() +{ + whitted::setPayloadOcclusionCommit(); +} + +extern "C" __global__ void __closesthit__radiance() +{ + const whitted::HitGroupData* hit_group_data = reinterpret_cast( optixGetSbtDataPointer() ); + const LocalGeometry geom = getLocalGeometry( hit_group_data->geometry_data ); + + // + // Retrieve material data + // + float4 base_color = hit_group_data->material_data.pbr.base_color * geom.color; + if( hit_group_data->material_data.pbr.base_color_tex ) + { + const float4 base_color_tex = sampleTexture( hit_group_data->material_data.pbr.base_color_tex, geom ); + + // don't gamma correct the alpha channel. + const float3 base_color_tex_linear = whitted::linearize( make_float3( base_color_tex ) ); + + base_color *= make_float4( base_color_tex_linear.x, base_color_tex_linear.y, base_color_tex_linear.z, base_color_tex.w ); + } + + float metallic = hit_group_data->material_data.pbr.metallic; + float roughness = hit_group_data->material_data.pbr.roughness; + float4 mr_tex = make_float4( 1.0f ); + if( hit_group_data->material_data.pbr.metallic_roughness_tex ) + // MR tex is (occlusion, roughness, metallic ) + mr_tex = sampleTexture( hit_group_data->material_data.pbr.metallic_roughness_tex, geom ); + roughness *= mr_tex.y; + metallic *= mr_tex.z; + + // + // Convert to material params + // + const float F0 = 0.04f; + const float3 diff_color = make_float3( base_color ) * ( 1.0f - F0 ) * ( 1.0f - metallic ); + const float3 spec_color = lerp( make_float3( F0 ), make_float3( base_color ), metallic ); + const float alpha = roughness * roughness; + + float3 result = make_float3( 0.0f ); + + // + // compute emission + // + + float3 emissive_factor = hit_group_data->material_data.emissive_factor; + float4 emissive_tex = make_float4( 1.0f ); + if( hit_group_data->material_data.emissive_tex ) + emissive_tex = sampleTexture( hit_group_data->material_data.emissive_tex, geom ); + result += emissive_factor * make_float3( emissive_tex ); + + // + // compute direct lighting + // + + float3 N = geom.N; + if( hit_group_data->material_data.normal_tex ) + { + const int texcoord_idx = hit_group_data->material_data.normal_tex.texcoord; + const float4 NN = + 2.0f * sampleTexture( hit_group_data->material_data.normal_tex, geom ) - make_float4( 1.0f ); + + // Transform normal from texture space to rotated UV space. + const float2 rotation = hit_group_data->material_data.normal_tex.texcoord_rotation; + const float2 NN_proj = make_float2( NN.x, NN.y ); + const float3 NN_trns = make_float3( + dot( NN_proj, make_float2( rotation.y, -rotation.x ) ), + dot( NN_proj, make_float2( rotation.x, rotation.y ) ), + NN.z ); + + N = normalize( NN_trns.x * normalize( geom.texcoord[texcoord_idx].dpdu ) + NN_trns.y * normalize( geom.texcoord[texcoord_idx].dpdv ) + NN_trns.z * geom.N ); + } + + // Flip normal to the side of the incomming ray + if( dot( N, optixGetWorldRayDirection() ) > 0.f ) + N = -N; + + unsigned int depth = whitted::getPayloadDepth() + 1; + + for( int i = 0; i < whitted::params.lights.count; ++i ) + { + Light light = whitted::params.lights[i]; + if( light.type == Light::Type::POINT ) + { + if( depth < whitted::MAX_TRACE_DEPTH ) + { + // TODO: optimize + const float L_dist = length( light.point.position - geom.P ); + const float3 L = ( light.point.position - geom.P ) / L_dist; + const float3 V = -normalize( optixGetWorldRayDirection() ); + const float3 H = normalize( L + V ); + const float N_dot_L = dot( N, L ); + const float N_dot_V = dot( N, V ); + const float N_dot_H = dot( N, H ); + const float V_dot_H = dot( V, H ); + + if( N_dot_L > 0.0f && N_dot_V > 0.0f ) + { + const float tmin = 0.001f; // TODO + const float tmax = L_dist - 0.001f; // TODO + const float attenuation = whitted::traceOcclusion( whitted::params.handle, geom.P, L, tmin, tmax ); + if( attenuation > 0.f ) + { + const float3 F = whitted::schlick( spec_color, V_dot_H ); + const float G_vis = whitted::vis( N_dot_L, N_dot_V, alpha ); + const float D = whitted::ggxNormal( N_dot_H, alpha ); + + const float3 diff = ( 1.0f - F ) * diff_color / M_PIf; + const float3 spec = F * G_vis * D; + + result += light.point.color * attenuation * light.point.intensity * N_dot_L * ( diff + spec ); + } + } + } + } + else if( light.type == Light::Type::AMBIENT ) + { + result += light.ambient.color * make_float3( base_color ); + } + } + + if( hit_group_data->material_data.alpha_mode == MaterialData::ALPHA_MODE_BLEND ) + { + result *= base_color.w; + + if( depth < whitted::MAX_TRACE_DEPTH ) + { + whitted::PayloadRadiance alpha_payload; + alpha_payload.result = make_float3( 0.0f ); + alpha_payload.depth = depth; + whitted::traceRadiance( + whitted::params.handle, + optixGetWorldRayOrigin(), + optixGetWorldRayDirection(), + optixGetRayTmax(), // tmin + 1e16f, // tmax + &alpha_payload ); + + result += alpha_payload.result * make_float3( 1.f - base_color.w ); + } + } + + whitted::setPayloadResult( result ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/whitted.h b/Extern/3rdParty/OptiX/Linux/SDK/cuda/whitted.h new file mode 100644 index 00000000..c31a376a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/whitted.h @@ -0,0 +1,97 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#include + +#include +#include +#include +#include + +namespace whitted +{ + +const unsigned int NUM_ATTRIBUTE_VALUES = 4u; +const unsigned int NUM_PAYLOAD_VALUES = 4u; +const unsigned int MAX_TRACE_DEPTH = 8u; + +struct HitGroupData +{ + GeometryData geometry_data; + MaterialData material_data; +}; + + +enum RayType +{ + RAY_TYPE_RADIANCE = 0, + RAY_TYPE_OCCLUSION = 1, + RAY_TYPE_COUNT = 2 +}; + + +struct LaunchParams +{ + unsigned int width; + unsigned int height; + unsigned int subframe_index; + float4* accum_buffer; + uchar4* frame_buffer; + int max_depth; + float scene_epsilon; + + float3 eye; + float3 U; + float3 V; + float3 W; + + BufferView lights; + float3 miss_color; + OptixTraversableHandle handle; +}; + + +struct PayloadRadiance +{ + float3 result; + float importance; + int depth; +}; + + +struct PayloadOcclusion +{ + float3 result; +}; + + +} // end namespace whitted diff --git a/Extern/3rdParty/OptiX/Linux/SDK/cuda/whitted_cuda.h b/Extern/3rdParty/OptiX/Linux/SDK/cuda/whitted_cuda.h new file mode 100644 index 00000000..6684c1b8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/cuda/whitted_cuda.h @@ -0,0 +1,187 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +#include "whitted.h" + +namespace whitted { + +extern "C" { +__constant__ whitted::LaunchParams params; +} + +//------------------------------------------------------------------------------ +// +// GGX/smith shading helpers +// TODO: move into header so can be shared by path tracer and bespoke renderers +// +//------------------------------------------------------------------------------ + +__device__ __forceinline__ float3 schlick( const float3 spec_color, const float V_dot_H ) +{ + return spec_color + ( make_float3( 1.0f ) - spec_color ) * powf( 1.0f - V_dot_H, 5.0f ); +} + +__device__ __forceinline__ float vis( const float N_dot_L, const float N_dot_V, const float alpha ) +{ + const float alpha_sq = alpha*alpha; + + const float ggx0 = N_dot_L * sqrtf( N_dot_V*N_dot_V * ( 1.0f - alpha_sq ) + alpha_sq ); + const float ggx1 = N_dot_V * sqrtf( N_dot_L*N_dot_L * ( 1.0f - alpha_sq ) + alpha_sq ); + + return 2.0f * N_dot_L * N_dot_V / (ggx0+ggx1); +} + + +__device__ __forceinline__ float ggxNormal( const float N_dot_H, const float alpha ) +{ + const float alpha_sq = alpha*alpha; + const float N_dot_H_sq = N_dot_H*N_dot_H; + const float x = N_dot_H_sq*( alpha_sq - 1.0f ) + 1.0f; + return alpha_sq/( M_PIf*x*x ); +} + + +__device__ __forceinline__ float3 linearize( float3 c ) +{ + return make_float3( + powf( c.x, 2.2f ), + powf( c.y, 2.2f ), + powf( c.z, 2.2f ) + ); +} + + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + + +static __forceinline__ __device__ void traceRadiance( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax, + whitted::PayloadRadiance* payload + ) +{ + unsigned int u0 = 0; // output only + unsigned int u1 = 0; // output only + unsigned int u2 = 0; // output only + unsigned int u3 = payload->depth; + optixTrace( + handle, + ray_origin, ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_CULL_BACK_FACING_TRIANGLES, + whitted::RAY_TYPE_RADIANCE, // SBT offset + whitted::RAY_TYPE_COUNT, // SBT stride + whitted::RAY_TYPE_RADIANCE, // missSBTIndex + u0, u1, u2, u3 ); + + payload->result.x = __uint_as_float( u0 ); + payload->result.y = __uint_as_float( u1 ); + payload->result.z = __uint_as_float( u2 ); + payload->depth = 0; // input only +} + +__forceinline__ __device__ unsigned int getPayloadDepth() +{ + return optixGetPayload_3(); +} + +static __forceinline__ __device__ float traceOcclusion( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax + ) +{ + // Introduce the concept of 'pending' and 'committed' attenuation. + // This avoids the usage of closesthit shaders and allows the usage of the OPTIX_RAY_FLAG_DISABLE_CLOSESTHIT flag. + // The attenuation is marked as pending with a positive sign bit and marked committed by switching the sign bit. + // Attenuation magnitude can be changed in anyhit programs and stays pending. + // The final attenuation gets committed in the miss shader (by setting the sign bit). + // If no miss shader is invoked (traversal was terminated due to an opaque hit) + // the attenuation is not committed and the ray is deemed fully occluded. + unsigned int attenuation = __float_as_uint(1.f); + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT | OPTIX_RAY_FLAG_DISABLE_CLOSESTHIT, + whitted::RAY_TYPE_OCCLUSION, // SBT offset + whitted::RAY_TYPE_COUNT, // SBT stride + whitted::RAY_TYPE_OCCLUSION, // missSBTIndex + attenuation ); + + // committed attenuation is negated + return fmaxf(0, -__uint_as_float(attenuation)); +} + +__forceinline__ __device__ void setPayloadResult( float3 p ) +{ + optixSetPayload_0( __float_as_uint( p.x ) ); + optixSetPayload_1( __float_as_uint( p.y ) ); + optixSetPayload_2( __float_as_uint( p.z ) ); +} + +__forceinline__ __device__ float getPayloadOcclusion() +{ + return __uint_as_float( optixGetPayload_0() ); +} + +__forceinline__ __device__ void setPayloadOcclusion( float attenuation ) +{ + optixSetPayload_0( __float_as_uint( attenuation ) ); +} + +__forceinline__ __device__ void setPayloadOcclusionCommit() +{ + // set the sign + optixSetPayload_0( optixGetPayload_0() | 0x80000000 ); +} + +} // namespace whitted diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/Duck.gltf b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/Duck.gltf new file mode 100644 index 00000000..294ad6c2 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/Duck.gltf @@ -0,0 +1,219 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 2, + 1 + ], + "matrix": [ + 0.009999999776482582, + 0.0, + 0.0, + 0.0, + 0.0, + 0.009999999776482582, + 0.0, + 0.0, + 0.0, + 0.0, + 0.009999999776482582, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "matrix": [ + -0.7289686799049377, + 0.0, + -0.6845470666885376, + 0.0, + -0.4252049028873444, + 0.7836934328079224, + 0.4527972936630249, + 0.0, + 0.5364750623703003, + 0.6211478114128113, + -0.571287989616394, + 0.0, + 400.1130065917969, + 463.2640075683594, + -431.0780334472656, + 1.0 + ], + "camera": 0 + }, + { + "mesh": 0 + } + ], + "cameras": [ + { + "perspective": { + "aspectRatio": 1.5, + "yfov": 0.6605925559997559, + "zfar": 10000.0, + "znear": 1.0 + }, + "type": "perspective" + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "LOD3spShape" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 12636, + "max": [ + 2398 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 2399, + "max": [ + 0.9995989799499512, + 0.999580979347229, + 0.9984359741210938 + ], + "min": [ + -0.9990839958190918, + -1.0, + -0.9998319745063782 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 28788, + "componentType": 5126, + "count": 2399, + "max": [ + 96.17990112304688, + 163.97000122070313, + 53.92519760131836 + ], + "min": [ + -69.29850006103516, + 9.929369926452637, + -61.32819747924805 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 2399, + "max": [ + 0.9833459854125976, + 0.9800369739532472 + ], + "min": [ + 0.026409000158309938, + 0.01996302604675293 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0.0 + }, + "emissiveFactor": [ + 0.0, + 0.0, + 0.0 + ], + "name": "blinn3-fx" + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "Duck.png" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 76768, + "byteLength": 25272, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 57576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 57576, + "byteLength": 19192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 102040, + "uri": "Duck0.bin" + } + ] +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/Duck.png b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/Duck.png new file mode 100644 index 00000000..9fa2dd4c Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/Duck.png differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/Duck0.bin b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/Duck0.bin new file mode 100644 index 00000000..5f01f88a Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/Duck0.bin differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/DuckCM.png b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/DuckCM.png new file mode 100644 index 00000000..9fa2dd4c Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/DuckCM.png differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/DuckHole.gltf b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/DuckHole.gltf new file mode 100644 index 00000000..e12afb7a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/DuckHole.gltf @@ -0,0 +1,221 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 2, + 1 + ], + "matrix": [ + 0.009999999776482582, + 0.0, + 0.0, + 0.0, + 0.0, + 0.009999999776482582, + 0.0, + 0.0, + 0.0, + 0.0, + 0.009999999776482582, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "matrix": [ + -0.7289686799049377, + 0.0, + -0.6845470666885376, + 0.0, + -0.4252049028873444, + 0.7836934328079224, + 0.4527972936630249, + 0.0, + 0.5364750623703003, + 0.6211478114128113, + -0.571287989616394, + 0.0, + 400.1130065917969, + 463.2640075683594, + -431.0780334472656, + 1.0 + ], + "camera": 0 + }, + { + "mesh": 0 + } + ], + "cameras": [ + { + "perspective": { + "aspectRatio": 1.5, + "yfov": 0.6605925559997559, + "zfar": 10000.0, + "znear": 1.0 + }, + "type": "perspective" + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "LOD3spShape" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 12636, + "max": [ + 2398 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 2399, + "max": [ + 0.9995989799499512, + 0.999580979347229, + 0.9984359741210938 + ], + "min": [ + -0.9990839958190918, + -1.0, + -0.9998319745063782 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 28788, + "componentType": 5126, + "count": 2399, + "max": [ + 96.17990112304688, + 163.97000122070313, + 53.92519760131836 + ], + "min": [ + -69.29850006103516, + 9.929369926452637, + -61.32819747924805 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 2399, + "max": [ + 0.9833459854125976, + 0.9800369739532472 + ], + "min": [ + 0.026409000158309938, + 0.01996302604675293 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "alphaCutoff": 0.5, + "alphaMode": "MASK", + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0.0 + }, + "emissiveFactor": [ + 0.0, + 0.0, + 0.0 + ], + "name": "blinn3-fx" + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "DuckHole.png" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 76768, + "byteLength": 25272, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 57576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 57576, + "byteLength": 19192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 102040, + "uri": "Duck0.bin" + } + ] +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/DuckHole.png b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/DuckHole.png new file mode 100644 index 00000000..8e481ce4 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/DuckHole.png differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/LICENSE.txt b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/LICENSE.txt new file mode 100644 index 00000000..fa0335b8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/data/Duck/LICENSE.txt @@ -0,0 +1,11 @@ +CC0 1.0 Universal (CC0 1.0) +Public Domain Dedication + +No Copyright +The person who associated a work with this deed has dedicated the work to the +public domain by waiving all of his or her rights to the work worldwide under +copyright law, including all related and neighboring rights, to the extent +allowed by law. + +You can copy, modify, distribute and perform the work, even for commercial +purposes, all without asking permission. See Other Information below. diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Hair/README.TXT b/Extern/3rdParty/OptiX/Linux/SDK/data/Hair/README.TXT new file mode 100644 index 00000000..74795992 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/data/Hair/README.TXT @@ -0,0 +1,7 @@ +The hair model file for this SDK sample are from Cem Yuksel's web page: + + www.cemyuksel.com/research/hairmodels + +You can download three additional .hair definitions from there to be used +by the sample code. Other hair files than the default can be passed to +the executable via its "--hair" command-line parameter. diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Hair/wStraight.hair b/Extern/3rdParty/OptiX/Linux/SDK/data/Hair/wStraight.hair new file mode 100644 index 00000000..1baae1ef Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Hair/wStraight.hair differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Hair/woman.bin b/Extern/3rdParty/OptiX/Linux/SDK/data/Hair/woman.bin new file mode 100644 index 00000000..b5a0a7be Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Hair/woman.bin differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Hair/woman.gltf b/Extern/3rdParty/OptiX/Linux/SDK/data/Hair/woman.gltf new file mode 100644 index 00000000..ce37defc --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/data/Hair/woman.gltf @@ -0,0 +1,93 @@ +{ + "asset" : { + "version" : "2.0" + }, + "scene" : 0, + "scenes" : [ + { + "name" : "Scene", + "nodes" : [ + 0 + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "woman", + "rotation" : [ + 0.7071067690849304, + 0, + 0, + 0.7071067690849304 + ] + } + ], + "meshes" : [ + { + "name" : "woman", + "primitives" : [ + { + "attributes" : { + "POSITION" : 0, + "NORMAL" : 1 + }, + "indices" : 2 + } + ] + } + ], + "accessors" : [ + { + "bufferView" : 0, + "componentType" : 5126, + "count" : 31326, + "max" : [ + 37.4716796875, + 48.062747955322266, + 60.134830474853516 + ], + "min" : [ + -48.471412658691406, + -48.249229431152344, + -59.86256790161133 + ], + "type" : "VEC3" + }, + { + "bufferView" : 1, + "componentType" : 5126, + "count" : 31326, + "type" : "VEC3" + }, + { + "bufferView" : 2, + "componentType" : 5123, + "count" : 182640, + "type" : "SCALAR" + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 375912, + "byteOffset" : 0 + }, + { + "buffer" : 0, + "byteLength" : 375912, + "byteOffset" : 375912 + }, + { + "buffer" : 0, + "byteLength" : 365280, + "byteOffset" : 751824 + } + ], + "buffers" : [ + { + "byteLength" : 1117104, + "uri" : "woman.bin" + } + ] +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Plane/biplane.bin b/Extern/3rdParty/OptiX/Linux/SDK/data/Plane/biplane.bin new file mode 100644 index 00000000..0bb67c25 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Plane/biplane.bin differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Plane/biplane.gltf b/Extern/3rdParty/OptiX/Linux/SDK/data/Plane/biplane.gltf new file mode 100644 index 00000000..2741dc7e --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/data/Plane/biplane.gltf @@ -0,0 +1,2906 @@ +{ + "accessors": [ + { + "bufferView": 0, + "componentType": 5126, + "count": 1350, + "max": [ + 0.9298949837684631, + -2.255579948425293, + 3.319920063018799 + ], + "min": [ + 0.70660799741745, + -3.2304298877716064, + 2.3450698852539063 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "componentType": 5126, + "count": 1350, + "type": "VEC3" + }, + { + "bufferView": 2, + "componentType": 5126, + "count": 1350, + "type": "VEC2" + }, + { + "bufferView": 3, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 4, + "componentType": 5126, + "count": 1392, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -1.0, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 5, + "componentType": 5126, + "count": 1392, + "type": "VEC3" + }, + { + "bufferView": 6, + "componentType": 5126, + "count": 1392, + "type": "VEC2" + }, + { + "bufferView": 7, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 8, + "componentType": 5126, + "count": 3324, + "max": [ + 0.9663580060005188, + 0.9663569927215576, + 0.9940149784088135 + ], + "min": [ + -0.9663580060005188, + -0.9663569927215576, + -0.006445410195738077 + ], + "type": "VEC3" + }, + { + "bufferView": 9, + "componentType": 5126, + "count": 3324, + "type": "VEC3" + }, + { + "bufferView": 10, + "componentType": 5126, + "count": 3324, + "type": "VEC2" + }, + { + "bufferView": 11, + "componentType": 5125, + "count": 14592, + "type": "SCALAR" + }, + { + "bufferView": 12, + "componentType": 5126, + "count": 6715, + "max": [ + 1.465649962425232, + 2.0121400356292725, + 4.9845499992370605 + ], + "min": [ + -1.465649962425232, + -1.8972899913787842, + -5.935830116271973 + ], + "type": "VEC3" + }, + { + "bufferView": 13, + "componentType": 5126, + "count": 6715, + "type": "VEC3" + }, + { + "bufferView": 14, + "componentType": 5126, + "count": 6715, + "type": "VEC2" + }, + { + "bufferView": 15, + "componentType": 5125, + "count": 37632, + "type": "SCALAR" + }, + { + "bufferView": 16, + "componentType": 5126, + "count": 995, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -1.0, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 17, + "componentType": 5126, + "count": 995, + "type": "VEC3" + }, + { + "bufferView": 18, + "componentType": 5126, + "count": 995, + "type": "VEC2" + }, + { + "bufferView": 19, + "componentType": 5125, + "count": 4608, + "type": "SCALAR" + }, + { + "bufferView": 20, + "componentType": 5126, + "count": 2310, + "max": [ + 2.8061699867248535, + 1.203879952430725, + -4.365079879760742 + ], + "min": [ + -2.8061699867248535, + 0.893314003944397, + -5.9963698387146 + ], + "type": "VEC3" + }, + { + "bufferView": 21, + "componentType": 5126, + "count": 2310, + "type": "VEC3" + }, + { + "bufferView": 22, + "componentType": 5126, + "count": 2310, + "type": "VEC2" + }, + { + "bufferView": 23, + "componentType": 5125, + "count": 10752, + "type": "SCALAR" + }, + { + "bufferView": 24, + "componentType": 5126, + "count": 3654, + "max": [ + 6.321770191192627, + 2.2598400115966797, + 4.0313801765441895 + ], + "min": [ + -6.321770191192627, + 1.9169800281524658, + 1.1481599807739258 + ], + "type": "VEC3" + }, + { + "bufferView": 25, + "componentType": 5126, + "count": 3654, + "type": "VEC3" + }, + { + "bufferView": 26, + "componentType": 5126, + "count": 3654, + "type": "VEC2" + }, + { + "bufferView": 27, + "componentType": 5125, + "count": 17664, + "type": "SCALAR" + }, + { + "bufferView": 28, + "componentType": 5126, + "count": 1251, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -0.022411100566387177, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 29, + "componentType": 5126, + "count": 1251, + "type": "VEC3" + }, + { + "bufferView": 30, + "componentType": 5126, + "count": 1251, + "type": "VEC2" + }, + { + "bufferView": 31, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 32, + "componentType": 5126, + "count": 1350, + "max": [ + -0.5491830110549927, + -2.255579948425293, + 3.319920063018799 + ], + "min": [ + -0.7724699974060059, + -3.2304298877716064, + 2.3450698852539063 + ], + "type": "VEC3" + }, + { + "bufferView": 33, + "componentType": 5126, + "count": 1350, + "type": "VEC3" + }, + { + "bufferView": 34, + "componentType": 5126, + "count": 1350, + "type": "VEC2" + }, + { + "bufferView": 35, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 36, + "componentType": 5126, + "count": 1251, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -0.022411100566387177, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 37, + "componentType": 5126, + "count": 1251, + "type": "VEC3" + }, + { + "bufferView": 38, + "componentType": 5126, + "count": 1251, + "type": "VEC2" + }, + { + "bufferView": 39, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 40, + "componentType": 5126, + "count": 1350, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -0.022411100566387177, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 41, + "componentType": 5126, + "count": 1350, + "type": "VEC3" + }, + { + "bufferView": 42, + "componentType": 5126, + "count": 1350, + "type": "VEC2" + }, + { + "bufferView": 43, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 44, + "componentType": 5126, + "count": 9449, + "max": [ + 0.5739319920539856, + -1.3657000064849854, + 3.06112003326416 + ], + "min": [ + 0.13625599443912506, + -3.1994800567626953, + 0.7208960056304932 + ], + "type": "VEC3" + }, + { + "bufferView": 45, + "componentType": 5126, + "count": 9449, + "type": "VEC3" + }, + { + "bufferView": 46, + "componentType": 5126, + "count": 9449, + "type": "VEC2" + }, + { + "bufferView": 47, + "componentType": 5125, + "count": 46080, + "type": "SCALAR" + }, + { + "bufferView": 48, + "componentType": 5126, + "count": 9449, + "max": [ + 0.5739319920539856, + -1.3657000064849854, + 3.06112003326416 + ], + "min": [ + 0.13625599443912506, + -3.1994800567626953, + 0.7208960056304932 + ], + "type": "VEC3" + }, + { + "bufferView": 49, + "componentType": 5126, + "count": 9449, + "type": "VEC3" + }, + { + "bufferView": 50, + "componentType": 5126, + "count": 9449, + "type": "VEC2" + }, + { + "bufferView": 51, + "componentType": 5125, + "count": 46080, + "type": "SCALAR" + }, + { + "bufferView": 52, + "componentType": 5126, + "count": 3654, + "max": [ + 6.321770191192627, + 2.2598400115966797, + 4.0313801765441895 + ], + "min": [ + -6.321770191192627, + 1.9169800281524658, + 1.1481599807739258 + ], + "type": "VEC3" + }, + { + "bufferView": 53, + "componentType": 5126, + "count": 3654, + "type": "VEC3" + }, + { + "bufferView": 54, + "componentType": 5126, + "count": 3654, + "type": "VEC2" + }, + { + "bufferView": 55, + "componentType": 5125, + "count": 17664, + "type": "SCALAR" + }, + { + "bufferView": 56, + "componentType": 5126, + "count": 8550, + "max": [ + 0.0804138034582138, + -0.7259989976882935, + -0.9384599924087524 + ], + "min": [ + -0.09670309722423553, + -2.265239953994751, + -3.284600019454956 + ], + "type": "VEC3" + }, + { + "bufferView": 57, + "componentType": 5126, + "count": 8550, + "type": "VEC3" + }, + { + "bufferView": 58, + "componentType": 5126, + "count": 8550, + "type": "VEC2" + }, + { + "bufferView": 59, + "componentType": 5125, + "count": 41472, + "type": "SCALAR" + }, + { + "bufferView": 60, + "componentType": 5126, + "count": 1878, + "max": [ + 0.9258729815483093, + 0.9477850198745728, + 0.9258729815483093 + ], + "min": [ + -0.9258729815483093, + -0.9124799966812134, + -0.9258729815483093 + ], + "type": "VEC3" + }, + { + "bufferView": 61, + "componentType": 5126, + "count": 1878, + "type": "VEC3" + }, + { + "bufferView": 62, + "componentType": 5126, + "count": 1878, + "type": "VEC2" + }, + { + "bufferView": 63, + "componentType": 5125, + "count": 8448, + "type": "SCALAR" + }, + { + "bufferView": 64, + "componentType": 5126, + "count": 1878, + "max": [ + 0.9258729815483093, + 0.9477850198745728, + 0.9258729815483093 + ], + "min": [ + -0.9258729815483093, + -0.9124799966812134, + -0.9258729815483093 + ], + "type": "VEC3" + }, + { + "bufferView": 65, + "componentType": 5126, + "count": 1878, + "type": "VEC3" + }, + { + "bufferView": 66, + "componentType": 5126, + "count": 1878, + "type": "VEC2" + }, + { + "bufferView": 67, + "componentType": 5125, + "count": 8448, + "type": "SCALAR" + }, + { + "bufferView": 68, + "componentType": 5126, + "count": 1251, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -0.022411100566387177, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 69, + "componentType": 5126, + "count": 1251, + "type": "VEC3" + }, + { + "bufferView": 70, + "componentType": 5126, + "count": 1251, + "type": "VEC2" + }, + { + "bufferView": 71, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 72, + "componentType": 5126, + "count": 8150, + "max": [ + 2.6431798934936523, + -0.1942950040102005, + 6.410470008850098 + ], + "min": [ + -2.6426498889923096, + -1.0471400022506714, + 6.1552300453186035 + ], + "type": "VEC3" + }, + { + "bufferView": 73, + "componentType": 5126, + "count": 8150, + "type": "VEC3" + }, + { + "bufferView": 74, + "componentType": 5126, + "count": 8150, + "type": "VEC2" + }, + { + "bufferView": 75, + "componentType": 5125, + "count": 41472, + "type": "SCALAR" + }, + { + "bufferView": 76, + "componentType": 5126, + "count": 1350, + "max": [ + 0.34608399868011475, + -1.7228800058364868, + -2.0362699031829834 + ], + "min": [ + 0.12279699742794037, + -2.348720073699951, + -2.662100076675415 + ], + "type": "VEC3" + }, + { + "bufferView": 77, + "componentType": 5126, + "count": 1350, + "type": "VEC3" + }, + { + "bufferView": 78, + "componentType": 5126, + "count": 1350, + "type": "VEC2" + }, + { + "bufferView": 79, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 80, + "componentType": 5126, + "count": 82, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 81, + "componentType": 5126, + "count": 82, + "type": "VEC3" + }, + { + "bufferView": 82, + "componentType": 5126, + "count": 82, + "type": "VEC2" + }, + { + "bufferView": 83, + "componentType": 5125, + "count": 192, + "type": "SCALAR" + }, + { + "bufferView": 84, + "componentType": 5126, + "count": 1251, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -0.022411100566387177, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 85, + "componentType": 5126, + "count": 1251, + "type": "VEC3" + }, + { + "bufferView": 86, + "componentType": 5126, + "count": 1251, + "type": "VEC2" + }, + { + "bufferView": 87, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 88, + "componentType": 5126, + "count": 1350, + "max": [ + -0.11738599836826324, + -1.7228800058364868, + -2.0362699031829834 + ], + "min": [ + -0.3406729996204376, + -2.348720073699951, + -2.662100076675415 + ], + "type": "VEC3" + }, + { + "bufferView": 89, + "componentType": 5126, + "count": 1350, + "type": "VEC3" + }, + { + "bufferView": 90, + "componentType": 5126, + "count": 1350, + "type": "VEC2" + }, + { + "bufferView": 91, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 92, + "componentType": 5126, + "count": 8033, + "max": [ + -4.538300037384033, + 0.42005500197410583, + 0.42005500197410583 + ], + "min": [ + -5.461699962615967, + -0.42005500197410583, + -0.42005500197410583 + ], + "type": "VEC3" + }, + { + "bufferView": 93, + "componentType": 5126, + "count": 8033, + "type": "VEC3" + }, + { + "bufferView": 94, + "componentType": 5126, + "count": 8033, + "type": "VEC2" + }, + { + "bufferView": 95, + "componentType": 5125, + "count": 44544, + "type": "SCALAR" + }, + { + "bufferView": 96, + "componentType": 5126, + "count": 642, + "max": [ + 0.30000001192092896, + 0.5, + 0.30000001192092896 + ], + "min": [ + -0.30000001192092896, + -0.5, + -0.30000001192092896 + ], + "type": "VEC3" + }, + { + "bufferView": 97, + "componentType": 5126, + "count": 642, + "type": "VEC3" + }, + { + "bufferView": 98, + "componentType": 5126, + "count": 642, + "type": "VEC2" + }, + { + "bufferView": 99, + "componentType": 5125, + "count": 1536, + "type": "SCALAR" + }, + { + "bufferView": 100, + "componentType": 5126, + "count": 642, + "max": [ + 0.30000001192092896, + 0.5, + 0.30000001192092896 + ], + "min": [ + -0.30000001192092896, + -0.5, + -0.30000001192092896 + ], + "type": "VEC3" + }, + { + "bufferView": 101, + "componentType": 5126, + "count": 642, + "type": "VEC3" + }, + { + "bufferView": 102, + "componentType": 5126, + "count": 642, + "type": "VEC2" + }, + { + "bufferView": 103, + "componentType": 5125, + "count": 1536, + "type": "SCALAR" + }, + { + "bufferView": 104, + "componentType": 5126, + "count": 642, + "max": [ + 0.30000001192092896, + 0.5, + 0.30000001192092896 + ], + "min": [ + -0.30000001192092896, + -0.5, + -0.30000001192092896 + ], + "type": "VEC3" + }, + { + "bufferView": 105, + "componentType": 5126, + "count": 642, + "type": "VEC3" + }, + { + "bufferView": 106, + "componentType": 5126, + "count": 642, + "type": "VEC2" + }, + { + "bufferView": 107, + "componentType": 5125, + "count": 1536, + "type": "SCALAR" + }, + { + "bufferView": 108, + "componentType": 5126, + "count": 642, + "max": [ + 0.30000001192092896, + 0.5, + 0.30000001192092896 + ], + "min": [ + -0.30000001192092896, + -0.5, + -0.30000001192092896 + ], + "type": "VEC3" + }, + { + "bufferView": 109, + "componentType": 5126, + "count": 642, + "type": "VEC3" + }, + { + "bufferView": 110, + "componentType": 5126, + "count": 642, + "type": "VEC2" + }, + { + "bufferView": 111, + "componentType": 5125, + "count": 1536, + "type": "SCALAR" + }, + { + "bufferView": 112, + "componentType": 5126, + "count": 642, + "max": [ + 0.30000001192092896, + 0.5, + 0.30000001192092896 + ], + "min": [ + -0.30000001192092896, + -0.5, + -0.30000001192092896 + ], + "type": "VEC3" + }, + { + "bufferView": 113, + "componentType": 5126, + "count": 642, + "type": "VEC3" + }, + { + "bufferView": 114, + "componentType": 5126, + "count": 642, + "type": "VEC2" + }, + { + "bufferView": 115, + "componentType": 5125, + "count": 1536, + "type": "SCALAR" + }, + { + "bufferView": 116, + "componentType": 5126, + "count": 642, + "max": [ + 0.30000001192092896, + 0.5, + 0.30000001192092896 + ], + "min": [ + -0.30000001192092896, + -0.5, + -0.30000001192092896 + ], + "type": "VEC3" + }, + { + "bufferView": 117, + "componentType": 5126, + "count": 642, + "type": "VEC3" + }, + { + "bufferView": 118, + "componentType": 5126, + "count": 642, + "type": "VEC2" + }, + { + "bufferView": 119, + "componentType": 5125, + "count": 1536, + "type": "SCALAR" + }, + { + "bufferView": 120, + "componentType": 5126, + "count": 8042, + "max": [ + -4.033979892730713, + 1.5648599863052368, + -3.6442699432373047 + ], + "min": [ + -5.578390121459961, + 0.21132400631904602, + -4.997799873352051 + ], + "type": "VEC3" + }, + { + "bufferView": 121, + "componentType": 5126, + "count": 8042, + "type": "VEC3" + }, + { + "bufferView": 122, + "componentType": 5126, + "count": 8042, + "type": "VEC2" + }, + { + "bufferView": 123, + "componentType": 5125, + "count": 44544, + "type": "SCALAR" + } + ], + "asset": { + "copyright": "Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.", + "generator": "Iray glTF plugin", + "version": "2.0" + }, + "bufferViews": [ + { + "buffer": 0, + "byteLength": 16200, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 16200, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10800, + "byteOffset": 32400, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 43200 + }, + { + "buffer": 0, + "byteLength": 16704, + "byteOffset": 67776, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 16704, + "byteOffset": 84480, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 11136, + "byteOffset": 101184, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 112320 + }, + { + "buffer": 0, + "byteLength": 39888, + "byteOffset": 136896, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 39888, + "byteOffset": 176784, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 26592, + "byteOffset": 216672, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 58368, + "byteOffset": 243264 + }, + { + "buffer": 0, + "byteLength": 80580, + "byteOffset": 301632, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 80580, + "byteOffset": 382212, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 53720, + "byteOffset": 462792, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 150528, + "byteOffset": 516512 + }, + { + "buffer": 0, + "byteLength": 11940, + "byteOffset": 667040, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 11940, + "byteOffset": 678980, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7960, + "byteOffset": 690920, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 18432, + "byteOffset": 698880 + }, + { + "buffer": 0, + "byteLength": 27720, + "byteOffset": 717312, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 27720, + "byteOffset": 745032, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 18480, + "byteOffset": 772752, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 43008, + "byteOffset": 791232 + }, + { + "buffer": 0, + "byteLength": 43848, + "byteOffset": 834240, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 43848, + "byteOffset": 878088, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 29232, + "byteOffset": 921936, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 70656, + "byteOffset": 951168 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 1021824, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 1036836, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10008, + "byteOffset": 1051848, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 1061856 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 1086432, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 1102632, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10800, + "byteOffset": 1118832, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 1129632 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 1154208, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 1169220, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10008, + "byteOffset": 1184232, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 1194240 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 1218816, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 1235016, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10800, + "byteOffset": 1251216, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 1262016 + }, + { + "buffer": 0, + "byteLength": 113388, + "byteOffset": 1286592, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 113388, + "byteOffset": 1399980, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 75592, + "byteOffset": 1513368, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 184320, + "byteOffset": 1588960 + }, + { + "buffer": 0, + "byteLength": 113388, + "byteOffset": 1773280, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 113388, + "byteOffset": 1886668, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 75592, + "byteOffset": 2000056, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 184320, + "byteOffset": 2075648 + }, + { + "buffer": 0, + "byteLength": 43848, + "byteOffset": 2259968, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 43848, + "byteOffset": 2303816, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 29232, + "byteOffset": 2347664, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 70656, + "byteOffset": 2376896 + }, + { + "buffer": 0, + "byteLength": 102600, + "byteOffset": 2447552, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 102600, + "byteOffset": 2550152, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 68400, + "byteOffset": 2652752, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 165888, + "byteOffset": 2721152 + }, + { + "buffer": 0, + "byteLength": 22536, + "byteOffset": 2887040, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 22536, + "byteOffset": 2909576, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 15024, + "byteOffset": 2932112, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 33792, + "byteOffset": 2947136 + }, + { + "buffer": 0, + "byteLength": 22536, + "byteOffset": 2980928, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 22536, + "byteOffset": 3003464, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 15024, + "byteOffset": 3026000, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 33792, + "byteOffset": 3041024 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 3074816, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 3089828, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10008, + "byteOffset": 3104840, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 3114848 + }, + { + "buffer": 0, + "byteLength": 97800, + "byteOffset": 3139424, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 97800, + "byteOffset": 3237224, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 65200, + "byteOffset": 3335024, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 165888, + "byteOffset": 3400224 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 3566112, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 3582312, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10800, + "byteOffset": 3598512, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 3609312 + }, + { + "buffer": 0, + "byteLength": 984, + "byteOffset": 3633888, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 984, + "byteOffset": 3634872, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 656, + "byteOffset": 3635856, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 768, + "byteOffset": 3636512 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 3637280, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 3652292, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10008, + "byteOffset": 3667304, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 3677312 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 3701888, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 3718088, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10800, + "byteOffset": 3734288, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 3745088 + }, + { + "buffer": 0, + "byteLength": 96396, + "byteOffset": 3769664, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 96396, + "byteOffset": 3866060, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 64264, + "byteOffset": 3962456, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 178176, + "byteOffset": 4026720 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4204896, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4212600, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 5136, + "byteOffset": 4220304, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 6144, + "byteOffset": 4225440 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4231584, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4239288, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 5136, + "byteOffset": 4246992, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 6144, + "byteOffset": 4252128 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4258272, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4265976, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 5136, + "byteOffset": 4273680, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 6144, + "byteOffset": 4278816 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4284960, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4292664, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 5136, + "byteOffset": 4300368, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 6144, + "byteOffset": 4305504 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4311648, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4319352, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 5136, + "byteOffset": 4327056, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 6144, + "byteOffset": 4332192 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4338336, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4346040, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 5136, + "byteOffset": 4353744, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 6144, + "byteOffset": 4358880 + }, + { + "buffer": 0, + "byteLength": 96504, + "byteOffset": 4365024, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 96504, + "byteOffset": 4461528, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 64336, + "byteOffset": 4558032, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 178176, + "byteOffset": 4622368 + } + ], + "buffers": [ + { + "byteLength": 4800544, + "uri": "biplane.bin" + } + ], + "meshes": [ + { + "name": "plane_wheel_front_lShape", + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 0, + "TEXCOORD_0": 2 + }, + "indices": 3, + "mode": 4 + } + ] + }, + { + "name": "plane_pCylinderShape6", + "primitives": [ + { + "attributes": { + "NORMAL": 5, + "POSITION": 4, + "TEXCOORD_0": 6 + }, + "indices": 7, + "mode": 4 + } + ] + }, + { + "name": "plane_pSphereShape1", + "primitives": [ + { + "attributes": { + "NORMAL": 9, + "POSITION": 8, + "TEXCOORD_0": 10 + }, + "indices": 11, + "mode": 4 + } + ] + }, + { + "name": "plane_pCubeShape1", + "primitives": [ + { + "attributes": { + "NORMAL": 13, + "POSITION": 12, + "TEXCOORD_0": 14 + }, + "indices": 15, + "mode": 4 + } + ] + }, + { + "name": "plane_pCylinderShape7", + "primitives": [ + { + "attributes": { + "NORMAL": 17, + "POSITION": 16, + "TEXCOORD_0": 18 + }, + "indices": 19, + "mode": 4 + } + ] + }, + { + "name": "plane_back_wingShape", + "primitives": [ + { + "attributes": { + "NORMAL": 21, + "POSITION": 20, + "TEXCOORD_0": 22 + }, + "indices": 23, + "mode": 4 + } + ] + }, + { + "name": "plane_top_whing|top_whingShape", + "primitives": [ + { + "attributes": { + "NORMAL": 25, + "POSITION": 24, + "TEXCOORD_0": 26 + }, + "indices": 27, + "mode": 4 + } + ] + }, + { + "name": "plane_hubcap_front_rShape", + "primitives": [ + { + "attributes": { + "NORMAL": 29, + "POSITION": 28, + "TEXCOORD_0": 30 + }, + "indices": 31, + "mode": 4 + } + ] + }, + { + "name": "plane_wheel_front_rShape", + "primitives": [ + { + "attributes": { + "NORMAL": 33, + "POSITION": 32, + "TEXCOORD_0": 34 + }, + "indices": 35, + "mode": 4 + } + ] + }, + { + "name": "plane_hubcap_front_lShape", + "primitives": [ + { + "attributes": { + "NORMAL": 37, + "POSITION": 36, + "TEXCOORD_0": 38 + }, + "indices": 39, + "mode": 4 + } + ] + }, + { + "name": "plane_propeeler_capShape", + "primitives": [ + { + "attributes": { + "NORMAL": 41, + "POSITION": 40, + "TEXCOORD_0": 42 + }, + "indices": 43, + "mode": 4 + } + ] + }, + { + "name": "plane_wheel_holder_backShape", + "primitives": [ + { + "attributes": { + "NORMAL": 45, + "POSITION": 44, + "TEXCOORD_0": 46 + }, + "indices": 47, + "mode": 4 + } + ] + }, + { + "name": "plane_wheel_holder_front_rShape", + "primitives": [ + { + "attributes": { + "NORMAL": 49, + "POSITION": 48, + "TEXCOORD_0": 50 + }, + "indices": 51, + "mode": 4 + } + ] + }, + { + "name": "plane_top_whing|top_whingShape_106", + "primitives": [ + { + "attributes": { + "NORMAL": 53, + "POSITION": 52, + "TEXCOORD_0": 54 + }, + "indices": 55, + "mode": 4 + } + ] + }, + { + "name": "plane_wheel_holder_frontShape", + "primitives": [ + { + "attributes": { + "NORMAL": 57, + "POSITION": 56, + "TEXCOORD_0": 58 + }, + "indices": 59, + "mode": 4 + } + ] + }, + { + "name": "plane_pCylinderShape38", + "primitives": [ + { + "attributes": { + "NORMAL": 61, + "POSITION": 60, + "TEXCOORD_0": 62 + }, + "indices": 63, + "mode": 4 + } + ] + }, + { + "name": "plane_pCylinderShape39", + "primitives": [ + { + "attributes": { + "NORMAL": 65, + "POSITION": 64, + "TEXCOORD_0": 66 + }, + "indices": 67, + "mode": 4 + } + ] + }, + { + "name": "plane_hubcap_back_lShape", + "primitives": [ + { + "attributes": { + "NORMAL": 69, + "POSITION": 68, + "TEXCOORD_0": 70 + }, + "indices": 71, + "mode": 4 + } + ] + }, + { + "name": "plane_propellerShape", + "primitives": [ + { + "attributes": { + "NORMAL": 73, + "POSITION": 72, + "TEXCOORD_0": 74 + }, + "indices": 75, + "mode": 4 + } + ] + }, + { + "name": "plane_wheel_back_lShape", + "primitives": [ + { + "attributes": { + "NORMAL": 77, + "POSITION": 76, + "TEXCOORD_0": 78 + }, + "indices": 79, + "mode": 4 + } + ] + }, + { + "name": "plane_pCylinderShape12", + "primitives": [ + { + "attributes": { + "NORMAL": 81, + "POSITION": 80, + "TEXCOORD_0": 82 + }, + "indices": 83, + "mode": 4 + } + ] + }, + { + "name": "plane_hubcap_back_rShape", + "primitives": [ + { + "attributes": { + "NORMAL": 85, + "POSITION": 84, + "TEXCOORD_0": 86 + }, + "indices": 87, + "mode": 4 + } + ] + }, + { + "name": "plane_wheel_back_rShape", + "primitives": [ + { + "attributes": { + "NORMAL": 89, + "POSITION": 88, + "TEXCOORD_0": 90 + }, + "indices": 91, + "mode": 4 + } + ] + }, + { + "name": "plane_bearShape", + "primitives": [ + { + "attributes": { + "NORMAL": 93, + "POSITION": 92, + "TEXCOORD_0": 94 + }, + "indices": 95, + "mode": 4 + } + ] + }, + { + "name": "plane_pCylinderShape45", + "primitives": [ + { + "attributes": { + "NORMAL": 97, + "POSITION": 96, + "TEXCOORD_0": 98 + }, + "indices": 99, + "mode": 4 + } + ] + }, + { + "name": "plane_pCylinderShape44", + "primitives": [ + { + "attributes": { + "NORMAL": 101, + "POSITION": 100, + "TEXCOORD_0": 102 + }, + "indices": 103, + "mode": 4 + } + ] + }, + { + "name": "plane_pCylinderShape43", + "primitives": [ + { + "attributes": { + "NORMAL": 105, + "POSITION": 104, + "TEXCOORD_0": 106 + }, + "indices": 107, + "mode": 4 + } + ] + }, + { + "name": "plane_pCylinderShape42", + "primitives": [ + { + "attributes": { + "NORMAL": 109, + "POSITION": 108, + "TEXCOORD_0": 110 + }, + "indices": 111, + "mode": 4 + } + ] + }, + { + "name": "plane_pCylinderShape41", + "primitives": [ + { + "attributes": { + "NORMAL": 113, + "POSITION": 112, + "TEXCOORD_0": 114 + }, + "indices": 115, + "mode": 4 + } + ] + }, + { + "name": "plane_pCylinderShape40", + "primitives": [ + { + "attributes": { + "NORMAL": 117, + "POSITION": 116, + "TEXCOORD_0": 118 + }, + "indices": 119, + "mode": 4 + } + ] + }, + { + "name": "plane_catShape", + "primitives": [ + { + "attributes": { + "NORMAL": 121, + "POSITION": 120, + "TEXCOORD_0": 122 + }, + "indices": 123, + "mode": 4 + } + ] + } + ], + "nodes": [ + { + "children": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ], + "name": "plane_g_biplane" + }, + { + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + -0.1352120041847229, + 0.0, + 0.0, + 1.0 + ], + "mesh": 0, + "name": "plane_wheel_front_l" + }, + { + "matrix": [ + -4.503613928759906e-20, + 0.07913270502167596, + -1.2442439289369603e-17, + 0.0, + -0.6730969999044348, + -0.0, + -0.0, + -0.0, + -7.754210156927142e-19, + -0.0, + 0.07913270502167594, + -0.0, + 0.09438973631964107, + -2.7430085077528967, + 2.8324919410860656, + 1.0 + ], + "mesh": 1, + "name": "plane_pCylinder6" + }, + { + "matrix": [ + 1.5206442220523475, + 0.0, + 0.0, + 0.0, + 0.0, + 1.5206442220523475, + 0.0, + 0.0, + -0.0, + 1.8092239757909018e-17, + 1.520644222052347, + -3.6184479515818036e-17, + 0.0, + -0.4179323583522327, + 4.6656860902136374, + 0.9999999999999999 + ], + "mesh": 2, + "name": "plane_pSphere1" + }, + { + "mesh": 3, + "name": "plane_pCube1" + }, + { + "matrix": [ + 0.0, + 0.07913270502167596, + 0.0, + 0.0, + -0.446123864535383, + -0.0, + -0.0, + -0.0, + 0.0, + 0.0, + 0.07913270502167596, + 0.0, + -0.0, + -2.226889208281277, + 2.0091634841676256, + 1.0 + ], + "mesh": 4, + "name": "plane_pCylinder7" + }, + { + "mesh": 5, + "name": "plane_back_wing" + }, + { + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.8333333002196431, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.33126998618165715, + 0.0, + 1.0 + ], + "mesh": 6, + "name": "plane_top_whing" + }, + { + "matrix": [ + 0.0, + 0.3501731536676184, + 0.0, + 0.0, + -0.07286505404166049, + -0.0, + 7.896182383024819e-17, + -0.0, + 0.0, + 0.0, + 0.3501731536676184, + 0.0, + -0.8196007312244326, + -2.7430078979445307, + 2.832494448062249, + 1.0 + ], + "mesh": 7, + "name": "plane_hubcap_front_r" + }, + { + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + -0.04489929974079132, + 0.0, + 0.0, + 1.0 + ], + "mesh": 8, + "name": "plane_wheel_front_r" + }, + { + "matrix": [ + 0.0, + 0.3501731536676184, + 0.0, + 0.0, + -0.0728650540416605, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.35017315366761836, + 0.0, + 0.8682090053289439, + -2.7430078979445307, + 2.832494448062248, + 1.0 + ], + "mesh": 9, + "name": "plane_hubcap_front_l" + }, + { + "matrix": [ + 0.0, + 0.3501731536676184, + 9.921121515036299e-16, + 0.0, + -0.0, + -0.0, + 0.0728650540416605, + -0.0, + 0.3501731536676184, + 0.0, + 0.0, + 0.0, + 0.0, + -0.42511020387717274, + 6.379801561527037, + 1.0 + ], + "mesh": 10, + "name": "plane_propeeler_cap" + }, + { + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.20278400182724, + -0.033313699066638947, + 1.0 + ], + "mesh": 11, + "name": "plane_wheel_holder_back" + }, + { + "matrix": [ + -1.0, + -0.0, + -1.22465002895872e-16, + -0.0, + 0.0, + 1.0, + 0.0, + 0.0, + -1.22465002895872e-16, + 0.0, + 1.0, + 0.0, + -0.0017257200088351924, + 0.20278400182724, + -0.033313699066638947, + 1.0 + ], + "mesh": 12, + "name": "plane_wheel_holder_front_r" + }, + { + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.8222196498409736, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + -2.54551809560757, + 0.0, + 1.0 + ], + "mesh": 13, + "name": "plane_bottom_wing" + }, + { + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.20278400182724, + -0.033313699066638947, + 1.0 + ], + "mesh": 14, + "name": "plane_wheel_holder_front" + }, + { + "matrix": [ + 0.13911224430027733, + 0.0, + 0.0, + 0.0, + 0.0, + 0.28110655196867224, + 1.1430380751472984e-16, + 0.0, + -0.0, + -1.6867716740930364e-17, + 0.13911224430027733, + -0.0, + 0.0, + 0.590703272388658, + 0.9156284694695964, + 1.0 + ], + "mesh": 15, + "name": "plane_pCylinder38" + }, + { + "matrix": [ + 0.13911224430027733, + 0.0, + 0.0, + 0.0, + 0.0, + 0.28110655196867224, + 0.0, + 0.0, + 0.0, + 0.0, + 0.1391122443002773, + 0.0, + -0.0, + 0.5907032723886582, + -1.022210708133483, + 1.0 + ], + "mesh": 16, + "name": "plane_pCylinder39" + }, + { + "matrix": [ + 7.274302163986107e-18, + 0.2248029632821641, + 0.0, + 0.0, + -0.0728650540416605, + -0.0, + -0.0, + -0.0, + -3.990679555742759e-18, + -1.5962718222971035e-17, + 0.22480296328216412, + 0.0, + 0.41001237817008634, + -1.9592948537573518, + -3.1270542066032827, + 1.0 + ], + "mesh": 17, + "name": "plane_hubcap_back_l" + }, + { + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.07650289684534073, + -0.7778750061988831, + 1.0 + ], + "mesh": 19, + "name": "plane_wheel_back_l" + }, + { + "matrix": [ + 0.0, + 0.07913270502167596, + 0.0, + 0.0, + -0.3903581634877212, + -0.0, + -0.0, + -0.0, + 0.0, + -1.1238041539267617e-17, + 0.07913270502167596, + 0.0, + -0.00972214340471884, + -1.9592940983808211, + -3.127055574904412, + 1.0 + ], + "mesh": 20, + "name": "plane_pCylinder12" + }, + { + "matrix": [ + 0.0, + 0.2248029632821641, + 0.0, + 0.0, + -0.0728650540416605, + -0.0, + 1.2943418447916657e-16, + -0.0, + -4.652497303874334e-18, + 0.0, + 0.22480296328216412, + 0.0, + -0.3360215589878905, + -1.9592948537573516, + -3.1270542066032823, + 1.0 + ], + "mesh": 21, + "name": "plane_hubcap_back_r" + }, + { + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.07650289684534073, + -0.7778750061988831, + 1.0 + ], + "mesh": 22, + "name": "plane_wheel_back_r" + }, + { + "matrix": [ + 1.4016508987996061, + -4.7009451361841777e-17, + -0.7943663372417651, + -0.0, + 0.0, + 1.6111000357612164, + 0.0, + 0.0, + 0.7943663372417649, + 2.4306489030878798e-17, + 1.4016508987996064, + 0.0, + 6.999999910745812, + 1.1097000283093623, + -3.0825997979768607, + 1.0 + ], + "mesh": 23, + "name": "plane_bear" + }, + { + "matrix": [ + 0.28759763057024884, + -3.019025714380955e-17, + -4.2648001453077585e-16, + 0.0, + 0.0, + 3.0108601873916445, + 0.0, + 0.0, + 9.562068245202474e-18, + -9.562068245202474e-18, + 0.2875976305702489, + -0.0, + -0.4613986448509663, + 0.6127371546795375, + 3.3392097096455, + 1.0 + ], + "mesh": 24, + "name": "plane_pCylinder45" + }, + { + "matrix": [ + 0.28759763057024884, + -4.806804834439427e-17, + 0.0, + 0.0, + 0.0, + 3.0108601873916445, + 0.0, + 0.0, + -9.562068245202474e-18, + 9.562068245202474e-18, + 0.2875976305702489, + -0.0, + 0.424914002952976, + 0.6127371546795374, + 3.3392097096455, + 1.0 + ], + "mesh": 25, + "name": "plane_pCylinder44" + }, + { + "matrix": [ + 0.28759763057024884, + -7.993944753931852e-18, + 0.0, + 0.0, + 0.0, + 3.0108601873916445, + 0.0, + 0.0, + 0.0, + 0.0, + 0.28759763057024884, + 0.0, + -3.9942421559728993, + 0.6127371546795375, + 3.3392097096454996, + 1.0 + ], + "mesh": 26, + "name": "plane_pCylinder43" + }, + { + "matrix": [ + 0.28759763057024884, + -7.993944753931852e-18, + -4.796366852359111e-17, + 0.0, + 0.0, + 3.0108601873916445, + 0.0, + 0.0, + 0.0, + 0.0, + 0.28759763057024884, + 0.0, + -3.9942421559728993, + 0.6127371546795375, + 1.9396131262551914, + 1.0 + ], + "mesh": 27, + "name": "plane_pCylinder42" + }, + { + "matrix": [ + 0.28759763057024884, + -0.0, + -3.1836406970499295e-17, + -0.0, + 0.0, + 3.0108601873916445, + 0.0, + 0.0, + 0.0, + 0.0, + 0.28759763057024884, + 0.0, + 4.011727976496871, + 0.6127371546795374, + 1.9396131262551906, + 1.0 + ], + "mesh": 28, + "name": "plane_pCylinder41" + }, + { + "matrix": [ + 0.28759763057024884, + -0.0, + -3.1836406970499295e-17, + -0.0, + 0.0, + 3.0108601873916445, + 0.0, + 0.0, + 0.0, + 0.0, + 0.28759763057024884, + 0.0, + 4.011727976496871, + 0.6127371546795374, + 3.339209709645499, + 1.0 + ], + "mesh": 29, + "name": "plane_pCylinder40" + }, + { + "matrix": [ + 0.4484679048202015, + -9.764339807558352e-18, + -0.8937988178495266, + -0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.8937988178495264, + -6.5115753287798626e-18, + 0.44846790482020144, + 0.0, + 6.0581697143710125, + 0.2317830026149749, + -3.3208750382712675, + 1.0 + ], + "mesh": 30, + "name": "plane_cat" + } + ], + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ] +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Plane/biplane_propeller.gltf b/Extern/3rdParty/OptiX/Linux/SDK/data/Plane/biplane_propeller.gltf new file mode 100644 index 00000000..24ce9ffd --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/data/Plane/biplane_propeller.gltf @@ -0,0 +1,1855 @@ +{ + "accessors": [ + { + "bufferView": 0, + "componentType": 5126, + "count": 1350, + "max": [ + 0.9298949837684631, + -2.255579948425293, + 3.319920063018799 + ], + "min": [ + 0.70660799741745, + -3.2304298877716064, + 2.3450698852539063 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "componentType": 5126, + "count": 1350, + "type": "VEC3" + }, + { + "bufferView": 2, + "componentType": 5126, + "count": 1350, + "type": "VEC2" + }, + { + "bufferView": 3, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 4, + "componentType": 5126, + "count": 1392, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -1.0, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 5, + "componentType": 5126, + "count": 1392, + "type": "VEC3" + }, + { + "bufferView": 6, + "componentType": 5126, + "count": 1392, + "type": "VEC2" + }, + { + "bufferView": 7, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 8, + "componentType": 5126, + "count": 3324, + "max": [ + 0.9663580060005188, + 0.9663569927215576, + 0.9940149784088135 + ], + "min": [ + -0.9663580060005188, + -0.9663569927215576, + -0.006445410195738077 + ], + "type": "VEC3" + }, + { + "bufferView": 9, + "componentType": 5126, + "count": 3324, + "type": "VEC3" + }, + { + "bufferView": 10, + "componentType": 5126, + "count": 3324, + "type": "VEC2" + }, + { + "bufferView": 11, + "componentType": 5125, + "count": 14592, + "type": "SCALAR" + }, + { + "bufferView": 12, + "componentType": 5126, + "count": 6715, + "max": [ + 1.465649962425232, + 2.0121400356292725, + 4.9845499992370605 + ], + "min": [ + -1.465649962425232, + -1.8972899913787842, + -5.935830116271973 + ], + "type": "VEC3" + }, + { + "bufferView": 13, + "componentType": 5126, + "count": 6715, + "type": "VEC3" + }, + { + "bufferView": 14, + "componentType": 5126, + "count": 6715, + "type": "VEC2" + }, + { + "bufferView": 15, + "componentType": 5125, + "count": 37632, + "type": "SCALAR" + }, + { + "bufferView": 16, + "componentType": 5126, + "count": 995, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -1.0, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 17, + "componentType": 5126, + "count": 995, + "type": "VEC3" + }, + { + "bufferView": 18, + "componentType": 5126, + "count": 995, + "type": "VEC2" + }, + { + "bufferView": 19, + "componentType": 5125, + "count": 4608, + "type": "SCALAR" + }, + { + "bufferView": 20, + "componentType": 5126, + "count": 2310, + "max": [ + 2.8061699867248535, + 1.203879952430725, + -4.365079879760742 + ], + "min": [ + -2.8061699867248535, + 0.893314003944397, + -5.9963698387146 + ], + "type": "VEC3" + }, + { + "bufferView": 21, + "componentType": 5126, + "count": 2310, + "type": "VEC3" + }, + { + "bufferView": 22, + "componentType": 5126, + "count": 2310, + "type": "VEC2" + }, + { + "bufferView": 23, + "componentType": 5125, + "count": 10752, + "type": "SCALAR" + }, + { + "bufferView": 24, + "componentType": 5126, + "count": 3654, + "max": [ + 6.321770191192627, + 2.2598400115966797, + 4.0313801765441895 + ], + "min": [ + -6.321770191192627, + 1.9169800281524658, + 1.1481599807739258 + ], + "type": "VEC3" + }, + { + "bufferView": 25, + "componentType": 5126, + "count": 3654, + "type": "VEC3" + }, + { + "bufferView": 26, + "componentType": 5126, + "count": 3654, + "type": "VEC2" + }, + { + "bufferView": 27, + "componentType": 5125, + "count": 17664, + "type": "SCALAR" + }, + { + "bufferView": 28, + "componentType": 5126, + "count": 1251, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -0.022411100566387177, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 29, + "componentType": 5126, + "count": 1251, + "type": "VEC3" + }, + { + "bufferView": 30, + "componentType": 5126, + "count": 1251, + "type": "VEC2" + }, + { + "bufferView": 31, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 32, + "componentType": 5126, + "count": 1350, + "max": [ + -0.5491830110549927, + -2.255579948425293, + 3.319920063018799 + ], + "min": [ + -0.7724699974060059, + -3.2304298877716064, + 2.3450698852539063 + ], + "type": "VEC3" + }, + { + "bufferView": 33, + "componentType": 5126, + "count": 1350, + "type": "VEC3" + }, + { + "bufferView": 34, + "componentType": 5126, + "count": 1350, + "type": "VEC2" + }, + { + "bufferView": 35, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 36, + "componentType": 5126, + "count": 1251, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -0.022411100566387177, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 37, + "componentType": 5126, + "count": 1251, + "type": "VEC3" + }, + { + "bufferView": 38, + "componentType": 5126, + "count": 1251, + "type": "VEC2" + }, + { + "bufferView": 39, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 40, + "componentType": 5126, + "count": 1350, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -0.022411100566387177, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 41, + "componentType": 5126, + "count": 1350, + "type": "VEC3" + }, + { + "bufferView": 42, + "componentType": 5126, + "count": 1350, + "type": "VEC2" + }, + { + "bufferView": 43, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 44, + "componentType": 5126, + "count": 9449, + "max": [ + 0.5739319920539856, + -1.3657000064849854, + 3.06112003326416 + ], + "min": [ + 0.13625599443912506, + -3.1994800567626953, + 0.7208960056304932 + ], + "type": "VEC3" + }, + { + "bufferView": 45, + "componentType": 5126, + "count": 9449, + "type": "VEC3" + }, + { + "bufferView": 46, + "componentType": 5126, + "count": 9449, + "type": "VEC2" + }, + { + "bufferView": 47, + "componentType": 5125, + "count": 46080, + "type": "SCALAR" + }, + { + "bufferView": 48, + "componentType": 5126, + "count": 9449, + "max": [ + 0.5739319920539856, + -1.3657000064849854, + 3.06112003326416 + ], + "min": [ + 0.13625599443912506, + -3.1994800567626953, + 0.7208960056304932 + ], + "type": "VEC3" + }, + { + "bufferView": 49, + "componentType": 5126, + "count": 9449, + "type": "VEC3" + }, + { + "bufferView": 50, + "componentType": 5126, + "count": 9449, + "type": "VEC2" + }, + { + "bufferView": 51, + "componentType": 5125, + "count": 46080, + "type": "SCALAR" + }, + { + "bufferView": 52, + "componentType": 5126, + "count": 3654, + "max": [ + 6.321770191192627, + 2.2598400115966797, + 4.0313801765441895 + ], + "min": [ + -6.321770191192627, + 1.9169800281524658, + 1.1481599807739258 + ], + "type": "VEC3" + }, + { + "bufferView": 53, + "componentType": 5126, + "count": 3654, + "type": "VEC3" + }, + { + "bufferView": 54, + "componentType": 5126, + "count": 3654, + "type": "VEC2" + }, + { + "bufferView": 55, + "componentType": 5125, + "count": 17664, + "type": "SCALAR" + }, + { + "bufferView": 56, + "componentType": 5126, + "count": 8550, + "max": [ + 0.0804138034582138, + -0.7259989976882935, + -0.9384599924087524 + ], + "min": [ + -0.09670309722423553, + -2.265239953994751, + -3.284600019454956 + ], + "type": "VEC3" + }, + { + "bufferView": 57, + "componentType": 5126, + "count": 8550, + "type": "VEC3" + }, + { + "bufferView": 58, + "componentType": 5126, + "count": 8550, + "type": "VEC2" + }, + { + "bufferView": 59, + "componentType": 5125, + "count": 41472, + "type": "SCALAR" + }, + { + "bufferView": 60, + "componentType": 5126, + "count": 1878, + "max": [ + 0.9258729815483093, + 0.9477850198745728, + 0.9258729815483093 + ], + "min": [ + -0.9258729815483093, + -0.9124799966812134, + -0.9258729815483093 + ], + "type": "VEC3" + }, + { + "bufferView": 61, + "componentType": 5126, + "count": 1878, + "type": "VEC3" + }, + { + "bufferView": 62, + "componentType": 5126, + "count": 1878, + "type": "VEC2" + }, + { + "bufferView": 63, + "componentType": 5125, + "count": 8448, + "type": "SCALAR" + }, + { + "bufferView": 64, + "componentType": 5126, + "count": 1878, + "max": [ + 0.9258729815483093, + 0.9477850198745728, + 0.9258729815483093 + ], + "min": [ + -0.9258729815483093, + -0.9124799966812134, + -0.9258729815483093 + ], + "type": "VEC3" + }, + { + "bufferView": 65, + "componentType": 5126, + "count": 1878, + "type": "VEC3" + }, + { + "bufferView": 66, + "componentType": 5126, + "count": 1878, + "type": "VEC2" + }, + { + "bufferView": 67, + "componentType": 5125, + "count": 8448, + "type": "SCALAR" + }, + { + "bufferView": 68, + "componentType": 5126, + "count": 1251, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -0.022411100566387177, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 69, + "componentType": 5126, + "count": 1251, + "type": "VEC3" + }, + { + "bufferView": 70, + "componentType": 5126, + "count": 1251, + "type": "VEC2" + }, + { + "bufferView": 71, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 72, + "componentType": 5126, + "count": 8150, + "max": [ + 2.6431798934936523, + -0.1942950040102005, + 6.410470008850098 + ], + "min": [ + -2.6426498889923096, + -1.0471400022506714, + 6.1552300453186035 + ], + "type": "VEC3" + }, + { + "bufferView": 73, + "componentType": 5126, + "count": 8150, + "type": "VEC3" + }, + { + "bufferView": 74, + "componentType": 5126, + "count": 8150, + "type": "VEC2" + }, + { + "bufferView": 75, + "componentType": 5125, + "count": 41472, + "type": "SCALAR" + }, + { + "bufferView": 76, + "componentType": 5126, + "count": 1350, + "max": [ + 0.34608399868011475, + -1.7228800058364868, + -2.0362699031829834 + ], + "min": [ + 0.12279699742794037, + -2.348720073699951, + -2.662100076675415 + ], + "type": "VEC3" + }, + { + "bufferView": 77, + "componentType": 5126, + "count": 1350, + "type": "VEC3" + }, + { + "bufferView": 78, + "componentType": 5126, + "count": 1350, + "type": "VEC2" + }, + { + "bufferView": 79, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 80, + "componentType": 5126, + "count": 82, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 81, + "componentType": 5126, + "count": 82, + "type": "VEC3" + }, + { + "bufferView": 82, + "componentType": 5126, + "count": 82, + "type": "VEC2" + }, + { + "bufferView": 83, + "componentType": 5125, + "count": 192, + "type": "SCALAR" + }, + { + "bufferView": 84, + "componentType": 5126, + "count": 1251, + "max": [ + 0.9084709882736206, + 1.0, + 0.9084709882736206 + ], + "min": [ + -0.9084709882736206, + -0.022411100566387177, + -0.9084709882736206 + ], + "type": "VEC3" + }, + { + "bufferView": 85, + "componentType": 5126, + "count": 1251, + "type": "VEC3" + }, + { + "bufferView": 86, + "componentType": 5126, + "count": 1251, + "type": "VEC2" + }, + { + "bufferView": 87, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 88, + "componentType": 5126, + "count": 1350, + "max": [ + -0.11738599836826324, + -1.7228800058364868, + -2.0362699031829834 + ], + "min": [ + -0.3406729996204376, + -2.348720073699951, + -2.662100076675415 + ], + "type": "VEC3" + }, + { + "bufferView": 89, + "componentType": 5126, + "count": 1350, + "type": "VEC3" + }, + { + "bufferView": 90, + "componentType": 5126, + "count": 1350, + "type": "VEC2" + }, + { + "bufferView": 91, + "componentType": 5125, + "count": 6144, + "type": "SCALAR" + }, + { + "bufferView": 92, + "componentType": 5126, + "count": 8033, + "max": [ + -4.538300037384033, + 0.42005500197410583, + 0.42005500197410583 + ], + "min": [ + -5.461699962615967, + -0.42005500197410583, + -0.42005500197410583 + ], + "type": "VEC3" + }, + { + "bufferView": 93, + "componentType": 5126, + "count": 8033, + "type": "VEC3" + }, + { + "bufferView": 94, + "componentType": 5126, + "count": 8033, + "type": "VEC2" + }, + { + "bufferView": 95, + "componentType": 5125, + "count": 44544, + "type": "SCALAR" + }, + { + "bufferView": 96, + "componentType": 5126, + "count": 642, + "max": [ + 0.30000001192092896, + 0.5, + 0.30000001192092896 + ], + "min": [ + -0.30000001192092896, + -0.5, + -0.30000001192092896 + ], + "type": "VEC3" + }, + { + "bufferView": 97, + "componentType": 5126, + "count": 642, + "type": "VEC3" + }, + { + "bufferView": 98, + "componentType": 5126, + "count": 642, + "type": "VEC2" + }, + { + "bufferView": 99, + "componentType": 5125, + "count": 1536, + "type": "SCALAR" + }, + { + "bufferView": 100, + "componentType": 5126, + "count": 642, + "max": [ + 0.30000001192092896, + 0.5, + 0.30000001192092896 + ], + "min": [ + -0.30000001192092896, + -0.5, + -0.30000001192092896 + ], + "type": "VEC3" + }, + { + "bufferView": 101, + "componentType": 5126, + "count": 642, + "type": "VEC3" + }, + { + "bufferView": 102, + "componentType": 5126, + "count": 642, + "type": "VEC2" + }, + { + "bufferView": 103, + "componentType": 5125, + "count": 1536, + "type": "SCALAR" + }, + { + "bufferView": 104, + "componentType": 5126, + "count": 642, + "max": [ + 0.30000001192092896, + 0.5, + 0.30000001192092896 + ], + "min": [ + -0.30000001192092896, + -0.5, + -0.30000001192092896 + ], + "type": "VEC3" + }, + { + "bufferView": 105, + "componentType": 5126, + "count": 642, + "type": "VEC3" + }, + { + "bufferView": 106, + "componentType": 5126, + "count": 642, + "type": "VEC2" + }, + { + "bufferView": 107, + "componentType": 5125, + "count": 1536, + "type": "SCALAR" + }, + { + "bufferView": 108, + "componentType": 5126, + "count": 642, + "max": [ + 0.30000001192092896, + 0.5, + 0.30000001192092896 + ], + "min": [ + -0.30000001192092896, + -0.5, + -0.30000001192092896 + ], + "type": "VEC3" + }, + { + "bufferView": 109, + "componentType": 5126, + "count": 642, + "type": "VEC3" + }, + { + "bufferView": 110, + "componentType": 5126, + "count": 642, + "type": "VEC2" + }, + { + "bufferView": 111, + "componentType": 5125, + "count": 1536, + "type": "SCALAR" + }, + { + "bufferView": 112, + "componentType": 5126, + "count": 642, + "max": [ + 0.30000001192092896, + 0.5, + 0.30000001192092896 + ], + "min": [ + -0.30000001192092896, + -0.5, + -0.30000001192092896 + ], + "type": "VEC3" + }, + { + "bufferView": 113, + "componentType": 5126, + "count": 642, + "type": "VEC3" + }, + { + "bufferView": 114, + "componentType": 5126, + "count": 642, + "type": "VEC2" + }, + { + "bufferView": 115, + "componentType": 5125, + "count": 1536, + "type": "SCALAR" + }, + { + "bufferView": 116, + "componentType": 5126, + "count": 642, + "max": [ + 0.30000001192092896, + 0.5, + 0.30000001192092896 + ], + "min": [ + -0.30000001192092896, + -0.5, + -0.30000001192092896 + ], + "type": "VEC3" + }, + { + "bufferView": 117, + "componentType": 5126, + "count": 642, + "type": "VEC3" + }, + { + "bufferView": 118, + "componentType": 5126, + "count": 642, + "type": "VEC2" + }, + { + "bufferView": 119, + "componentType": 5125, + "count": 1536, + "type": "SCALAR" + }, + { + "bufferView": 120, + "componentType": 5126, + "count": 8042, + "max": [ + -4.033979892730713, + 1.5648599863052368, + -3.6442699432373047 + ], + "min": [ + -5.578390121459961, + 0.21132400631904602, + -4.997799873352051 + ], + "type": "VEC3" + }, + { + "bufferView": 121, + "componentType": 5126, + "count": 8042, + "type": "VEC3" + }, + { + "bufferView": 122, + "componentType": 5126, + "count": 8042, + "type": "VEC2" + }, + { + "bufferView": 123, + "componentType": 5125, + "count": 44544, + "type": "SCALAR" + } + ], + "asset": { + "copyright": "Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.", + "generator": "Iray glTF plugin", + "version": "2.0" + }, + "bufferViews": [ + { + "buffer": 0, + "byteLength": 16200, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 16200, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10800, + "byteOffset": 32400, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 43200 + }, + { + "buffer": 0, + "byteLength": 16704, + "byteOffset": 67776, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 16704, + "byteOffset": 84480, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 11136, + "byteOffset": 101184, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 112320 + }, + { + "buffer": 0, + "byteLength": 39888, + "byteOffset": 136896, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 39888, + "byteOffset": 176784, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 26592, + "byteOffset": 216672, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 58368, + "byteOffset": 243264 + }, + { + "buffer": 0, + "byteLength": 80580, + "byteOffset": 301632, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 80580, + "byteOffset": 382212, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 53720, + "byteOffset": 462792, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 150528, + "byteOffset": 516512 + }, + { + "buffer": 0, + "byteLength": 11940, + "byteOffset": 667040, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 11940, + "byteOffset": 678980, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7960, + "byteOffset": 690920, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 18432, + "byteOffset": 698880 + }, + { + "buffer": 0, + "byteLength": 27720, + "byteOffset": 717312, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 27720, + "byteOffset": 745032, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 18480, + "byteOffset": 772752, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 43008, + "byteOffset": 791232 + }, + { + "buffer": 0, + "byteLength": 43848, + "byteOffset": 834240, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 43848, + "byteOffset": 878088, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 29232, + "byteOffset": 921936, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 70656, + "byteOffset": 951168 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 1021824, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 1036836, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10008, + "byteOffset": 1051848, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 1061856 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 1086432, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 1102632, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10800, + "byteOffset": 1118832, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 1129632 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 1154208, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 1169220, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10008, + "byteOffset": 1184232, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 1194240 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 1218816, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 1235016, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10800, + "byteOffset": 1251216, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 1262016 + }, + { + "buffer": 0, + "byteLength": 113388, + "byteOffset": 1286592, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 113388, + "byteOffset": 1399980, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 75592, + "byteOffset": 1513368, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 184320, + "byteOffset": 1588960 + }, + { + "buffer": 0, + "byteLength": 113388, + "byteOffset": 1773280, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 113388, + "byteOffset": 1886668, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 75592, + "byteOffset": 2000056, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 184320, + "byteOffset": 2075648 + }, + { + "buffer": 0, + "byteLength": 43848, + "byteOffset": 2259968, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 43848, + "byteOffset": 2303816, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 29232, + "byteOffset": 2347664, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 70656, + "byteOffset": 2376896 + }, + { + "buffer": 0, + "byteLength": 102600, + "byteOffset": 2447552, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 102600, + "byteOffset": 2550152, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 68400, + "byteOffset": 2652752, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 165888, + "byteOffset": 2721152 + }, + { + "buffer": 0, + "byteLength": 22536, + "byteOffset": 2887040, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 22536, + "byteOffset": 2909576, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 15024, + "byteOffset": 2932112, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 33792, + "byteOffset": 2947136 + }, + { + "buffer": 0, + "byteLength": 22536, + "byteOffset": 2980928, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 22536, + "byteOffset": 3003464, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 15024, + "byteOffset": 3026000, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 33792, + "byteOffset": 3041024 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 3074816, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 3089828, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10008, + "byteOffset": 3104840, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 3114848 + }, + { + "buffer": 0, + "byteLength": 97800, + "byteOffset": 3139424, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 97800, + "byteOffset": 3237224, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 65200, + "byteOffset": 3335024, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 165888, + "byteOffset": 3400224 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 3566112, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 3582312, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10800, + "byteOffset": 3598512, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 3609312 + }, + { + "buffer": 0, + "byteLength": 984, + "byteOffset": 3633888, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 984, + "byteOffset": 3634872, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 656, + "byteOffset": 3635856, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 768, + "byteOffset": 3636512 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 3637280, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 15012, + "byteOffset": 3652292, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10008, + "byteOffset": 3667304, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 3677312 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 3701888, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 16200, + "byteOffset": 3718088, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 10800, + "byteOffset": 3734288, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 24576, + "byteOffset": 3745088 + }, + { + "buffer": 0, + "byteLength": 96396, + "byteOffset": 3769664, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 96396, + "byteOffset": 3866060, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 64264, + "byteOffset": 3962456, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 178176, + "byteOffset": 4026720 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4204896, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4212600, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 5136, + "byteOffset": 4220304, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 6144, + "byteOffset": 4225440 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4231584, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4239288, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 5136, + "byteOffset": 4246992, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 6144, + "byteOffset": 4252128 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4258272, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4265976, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 5136, + "byteOffset": 4273680, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 6144, + "byteOffset": 4278816 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4284960, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4292664, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 5136, + "byteOffset": 4300368, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 6144, + "byteOffset": 4305504 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4311648, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4319352, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 5136, + "byteOffset": 4327056, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 6144, + "byteOffset": 4332192 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4338336, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 7704, + "byteOffset": 4346040, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 5136, + "byteOffset": 4353744, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 6144, + "byteOffset": 4358880 + }, + { + "buffer": 0, + "byteLength": 96504, + "byteOffset": 4365024, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 96504, + "byteOffset": 4461528, + "byteStride": 12 + }, + { + "buffer": 0, + "byteLength": 64336, + "byteOffset": 4558032, + "byteStride": 8 + }, + { + "buffer": 0, + "byteLength": 178176, + "byteOffset": 4622368 + } + ], + "buffers": [ + { + "byteLength": 4800544, + "uri": "biplane.bin" + } + ], + "meshes": [ + { + "name": "plane_propellerShape", + "primitives": [ + { + "attributes": { + "NORMAL": 73, + "POSITION": 72, + "TEXCOORD_0": 74 + }, + "indices": 75, + "mode": 4 + } + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ], + "name": "plane_g_biplane" + }, + { + "matrix": [ + -0.33197730113727386, + -0.9432878556583003, + -0.0, + -0.0, + 0.9432878556583004, + -0.3319773011372738, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.585866329427519, + -0.6237477527458339, + -0.0333137, + 1.0 + ], + "mesh": 0, + "name": "plane_propeller" + } + ], + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ] +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/Bricks12_col.exr b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/Bricks12_col.exr new file mode 100644 index 00000000..10bca7ea Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/Bricks12_col.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/README b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/README new file mode 100644 index 00000000..0c773893 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/README @@ -0,0 +1,2 @@ +Bricks12 downloaded from CC0Textures.com (https://cc0textures.com/view.php?tex=Bricks12) +Licensed under the Creative Commons CC0 License. diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_r_half.exr b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_r_half.exr new file mode 100644 index 00000000..f2ad8314 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_r_half.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_rg_half.exr b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_rg_half.exr new file mode 100644 index 00000000..553e6339 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_rg_half.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_rgb_float.exr b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_rgb_float.exr new file mode 100644 index 00000000..500b429d Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_rgb_float.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_rgb_half.exr b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_rgb_half.exr new file mode 100644 index 00000000..73b4288d Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_rgb_half.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_rgba_half.exr b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_rgba_half.exr new file mode 100644 index 00000000..6fc7515f Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Textures/circleSquare_rgba_half.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Volumes/README.txt b/Extern/3rdParty/OptiX/Linux/SDK/data/Volumes/README.txt new file mode 100644 index 00000000..f9f1ae02 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/data/Volumes/README.txt @@ -0,0 +1,6 @@ + +monu*.vox from ephtracy: +/~https://github.com/ephtracy/voxel-model/tree/master/vox/monument + +scene_aliens.vox from mikelovesrobots: +/~https://github.com/mikelovesrobots/mmmm/tree/master/vox diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/Volumes/smoke.nvdb b/Extern/3rdParty/OptiX/Linux/SDK/data/Volumes/smoke.nvdb new file mode 100644 index 00000000..67bab066 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/Volumes/smoke.nvdb differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/LICENSE.txt b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/LICENSE.txt new file mode 100644 index 00000000..fa0335b8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/LICENSE.txt @@ -0,0 +1,11 @@ +CC0 1.0 Universal (CC0 1.0) +Public Domain Dedication + +No Copyright +The person who associated a work with this deed has dedicated the work to the +public domain by waiving all of his or her rights to the work worldwide under +copyright law, including all related and neighboring rights, to the extent +allowed by law. + +You can copy, modify, distribute and perform the work, even for commercial +purposes, all without asking permission. See Other Information below. diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle.bin b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle.bin new file mode 100644 index 00000000..b10cfd01 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle.bin differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle.gltf b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle.gltf new file mode 100644 index 00000000..9f23f3ad --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle.gltf @@ -0,0 +1,172 @@ +{ + "accessors": [ + { + "bufferView": 0, + "componentType": 5126, + "count": 2549, + "type": "VEC2" + }, + { + "bufferView": 1, + "componentType": 5126, + "count": 2549, + "type": "VEC3" + }, + { + "bufferView": 2, + "componentType": 5126, + "count": 2549, + "type": "VEC4" + }, + { + "bufferView": 3, + "componentType": 5126, + "count": 2549, + "type": "VEC3", + "max": [ + 0.05445001, + 0.130220339, + 0.0544500239 + ], + "min": [ + -0.05445001, + -0.130220339, + -0.0544500239 + ] + }, + { + "bufferView": 4, + "componentType": 5123, + "count": 13530, + "type": "SCALAR" + } + ], + "asset": { + "generator": "glTF Tools for Unity", + "version": "2.0" + }, + "bufferViews": [ + { + "buffer": 0, + "byteLength": 20392 + }, + { + "buffer": 0, + "byteOffset": 20392, + "byteLength": 30588 + }, + { + "buffer": 0, + "byteOffset": 50980, + "byteLength": 40784 + }, + { + "buffer": 0, + "byteOffset": 91764, + "byteLength": 30588 + }, + { + "buffer": 0, + "byteOffset": 122352, + "byteLength": 27060 + } + ], + "buffers": [ + { + "uri": "WaterBottle.bin", + "byteLength": 149412 + } + ], + "images": [ + { + "uri": "WaterBottle_baseColor.png" + }, + { + "uri": "WaterBottle_occlusionRoughnessMetallic.png" + }, + { + "uri": "WaterBottle_normal.png" + }, + { + "uri": "WaterBottle_emissive.png" + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "TEXCOORD_0": 0, + "NORMAL": 1, + "TANGENT": 2, + "POSITION": 3 + }, + "indices": 4, + "material": 0 + } + ], + "name": "WaterBottle" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicRoughnessTexture": { + "index": 1 + } + }, + "normalTexture": { + "index": 2 + }, + "occlusionTexture": { + "index": 1 + }, + "emissiveFactor": [ + 1.0, + 1.0, + 1.0 + ], + "emissiveTexture": { + "index": 3 + }, + "name": "BottleMat" + } + ], + "nodes": [ + { + "mesh": 0, + "rotation": [ + 0.0, + 1.0, + 0.0, + 0.0 + ], + "name": "WaterBottle" + } + ], + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "textures": [ + { + "source": 0 + }, + { + "source": 1 + }, + { + "source": 2 + }, + { + "source": 3 + } + ] +} \ No newline at end of file diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_baseColor.png b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_baseColor.png new file mode 100644 index 00000000..759b85c9 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_baseColor.png differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_baseColor.png.backup b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_baseColor.png.backup new file mode 100644 index 00000000..f28c3f27 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_baseColor.png.backup differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_emissive.png b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_emissive.png new file mode 100644 index 00000000..338905ff Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_emissive.png differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_normal.png b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_normal.png new file mode 100644 index 00000000..82c690ce Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_normal.png differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_occlusionRoughnessMetallic.png b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_occlusionRoughnessMetallic.png new file mode 100644 index 00000000..0999b4fd Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/data/WaterBottle/WaterBottle_occlusionRoughnessMetallic.png differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/lib/CompileWithTasks.h b/Extern/3rdParty/OptiX/Linux/SDK/lib/CompileWithTasks.h new file mode 100644 index 00000000..faef6be8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/lib/CompileWithTasks.h @@ -0,0 +1,184 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace optix { +namespace CompileWithTasks { + +inline void check( OptixResult res, const char* call, const char* file, unsigned int line ) +{ + if( res != OPTIX_SUCCESS ) + { + std::stringstream s; + s << "Optix call in " << file << ", line " << line << " (" << call << ") failed with code " << res; + throw std::runtime_error( s.str() ); + } +} +#define COMPILE_WITH_TASKS_CHECK( call ) check( call, #call, __FILE__, __LINE__ ) + + +// Using the specified number of threads, execute the functions added to the work +// queue. Work can be added asynchronously by any other thread. Call terminate() to exit +// all the threads. The thread pool can be started up again after being +// terminated. Threads are started, but suspended until there is work in the queue. +struct ThreadPool +{ + std::vector m_pool; + std::mutex m_queueMutex; + using FunctionType = std::function; + std::deque m_workQueue; + bool m_killPool = false; + std::condition_variable m_condition; + + void startPool( int numThreads ) + { + for( int i = 0; i < numThreads; ++i ) + m_pool.emplace_back( std::bind( &ThreadPool::workerExecute, this ) ); + } + + void addWork( FunctionType&& function ) + { + std::lock_guard lock( m_queueMutex ); + m_workQueue.push_back( function ); + // Wake up one thread to handle this new job if it's not already awake. + m_condition.notify_one(); + } + + void workerExecute() + { + while( true ) + { + FunctionType work; + { + std::unique_lock lock( m_queueMutex ); + + // Sit here and wait until there's some work to do or we are terminating the pool + m_condition.wait( lock, [this] { return !m_workQueue.empty() || m_killPool; } ); + if( m_killPool ) + break; + work = m_workQueue.front(); + m_workQueue.pop_front(); + } + work(); + } + } + + void terminate() + { + { + std::unique_lock lock( m_queueMutex ); + m_killPool = true; + // This bit of code is optional depending on whether you want to be able to + // terminate a non-empty queue. + if( !m_workQueue.empty() ) + throw std::runtime_error( "pool not empty" ); + } + // Wake all threads, so they can exit the work/wait loop. + m_condition.notify_all(); + for( size_t i = 0; i < m_pool.size(); ++i ) + m_pool[i].join(); + m_pool.clear(); + } +}; + +// Compiles one or more OptixModules using multiple threads contained in m_threadPool. As new +// tasks are generated from calling optixTaskExecute, add more work to the thread pool. +struct OptixTaskExecutePool +{ + ThreadPool m_threadPool; + unsigned int m_maxNumAdditionalTasks; + bool m_stop = false; + std::condition_variable m_cv; + + void executeTask( OptixTask task, std::condition_variable& cv ) + { + // When we execute the task, OptiX can generate upto the number of additional + // tasks that we provide. [0..m_maxNumAdditionalTasks] are valid values for + // numAdditionalTasksCreated. + std::vector additionalTasks( m_maxNumAdditionalTasks ); + unsigned int numAdditionalTasksCreated; + COMPILE_WITH_TASKS_CHECK( optixTaskExecute( task, additionalTasks.data(), m_maxNumAdditionalTasks, &numAdditionalTasksCreated ) ); + for( unsigned int i = 0; i < numAdditionalTasksCreated; ++i ) + { + // Capture additionalTasks[i] by value since it will go out of scope. + OptixTask task = additionalTasks[i]; + m_threadPool.addWork( [task, &cv, this]() { executeTask( task, cv ); } ); + } + // Notify the thread calling executeTaskAndWait that a task has finished + // executing. + cv.notify_all(); + } + + // Add a module compilation task to the work queue. + void addTaskAndExecute( OptixTask task ) + { + m_threadPool.addWork( [task, this]() { executeTask( task, m_cv ); } ); + } + + // Monitor the work queue and wait until the compile tasks for all of the + // OptixModules have completed. + OptixResult waitForModuleTasks( std::vector& modules ) + { + std::mutex mutex; + std::unique_lock lock( mutex ); + OptixResult result = OPTIX_SUCCESS; + for( OptixModule& module : modules ) + { + OptixModuleCompileState state; + m_cv.wait( lock, [&] { + COMPILE_WITH_TASKS_CHECK( optixModuleGetCompilationState( module, &state ) ); + return state == OPTIX_MODULE_COMPILE_STATE_FAILED || state == OPTIX_MODULE_COMPILE_STATE_COMPLETED || m_stop; + } ); + result = state == OPTIX_MODULE_COMPILE_STATE_FAILED || state == OPTIX_MODULE_COMPILE_STATE_IMPENDING_FAILURE ? + OPTIX_ERROR_UNKNOWN : + result; + } + return result; + } + + // Wait until the task for the OptiXModule has completed. + OptixResult waitForModuleTask( OptixModule module ) + { + std::vector modules( 1, module ); + return waitForModuleTasks( modules ); + } +}; + +} // end namespace CompileWithTasks +} // end namespace optix diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/CMakeLists.txt new file mode 100644 index 00000000..aa58cbfb --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/CMakeLists.txt @@ -0,0 +1,40 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixBoundValues target_name + optixBoundValues.cu + optixBoundValues_ch.cu + optixBoundValues.cpp + optixBoundValues.h + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/optixBoundValues.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/optixBoundValues.cpp new file mode 100644 index 00000000..e6de2bc1 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/optixBoundValues.cpp @@ -0,0 +1,1261 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This sample shows how to apply launch parameter specialization. +// That technique allows to replace loads from a given range of the launch parameters +// with a fixed value at compile time. Compiler optimization passes use those constant +// values which may result in improved optimization results. +// The sample demonstrates the usage of the OptixModuleCompileBoundValueEntry struct +// and the OptixModuleCompileOptions::boundValues field. + +#include // Needs to be included before gl_interop + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "optixBoundValues.h" + +#include +#include +#include +#include +#include +#include +#include + + + +bool resize_dirty = false; +bool minimized = false; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Mouse state +int32_t mouse_button = -1; + +int32_t samples_per_launch = 16; + +// The number of samples to calculate the light are specified in the launch parameters. +// That value can be specialized to a fixed value at compile time. +// Note than when changing the number of light samples at runtime by pressing the PLUS +// or MINUS keys with specialization enabled recompilation of the closest hit module +// is necessary or it needs to be loaded from the cache. +unsigned int light_samples = 1; +bool specialize = true; + +//------------------------------------------------------------------------------ +// +// Local types +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +template +struct Record +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef Record RayGenRecord; +typedef Record MissRecord; +typedef Record HitGroupRecord; + + +struct Vertex +{ + float x, y, z, pad; +}; + + +struct IndexedTriangle +{ + uint32_t v1, v2, v3, pad; +}; + + +struct Instance +{ + float transform[12]; +}; + + +struct PathTracerState +{ + OptixDeviceContext context = 0; + + OptixTraversableHandle gas_handle = 0; // Traversable handle for triangle AS + CUdeviceptr d_gas_output_buffer = 0; // Triangle AS memory + CUdeviceptr d_vertices = 0; + + OptixModule ptx_module = 0; + OptixModule ptx_module_radiance = 0; + OptixPipelineCompileOptions pipeline_compile_options = {}; + OptixPipeline pipeline = 0; + + OptixProgramGroup raygen_prog_group = 0; + OptixProgramGroup radiance_miss_group = 0; + OptixProgramGroup occlusion_miss_group = 0; + OptixProgramGroup radiance_hit_group = 0; + OptixProgramGroup occlusion_hit_group = 0; + + CUstream stream = 0; + Params params; + Params* d_params; + + OptixShaderBindingTable sbt = {}; +}; + + +//------------------------------------------------------------------------------ +// +// Scene data +// +//------------------------------------------------------------------------------ + +const int32_t TRIANGLE_COUNT = 32; +const int32_t MAT_COUNT = 4; + +const static std::array g_vertices = +{ { + // Floor -- white lambert + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 0.0f, 0.0f }, + + // Ceiling -- white lambert + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + + // Back wall -- white lambert + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + + // Right wall -- green lambert + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + { 0.0f, 0.0f, 559.2f, 0.0f }, + + // Left wall -- red lambert + { 556.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 556.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 0.0f, 0.0f }, + + // Short block -- white lambert + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 242.0f, 165.0f, 274.0f, 0.0f }, + + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 242.0f, 165.0f, 274.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + + { 290.0f, 0.0f, 114.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + + { 290.0f, 0.0f, 114.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + { 240.0f, 0.0f, 272.0f, 0.0f }, + + { 130.0f, 0.0f, 65.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + + { 130.0f, 0.0f, 65.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + { 290.0f, 0.0f, 114.0f, 0.0f }, + + { 82.0f, 0.0f, 225.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + + { 82.0f, 0.0f, 225.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 130.0f, 0.0f, 65.0f, 0.0f }, + + { 240.0f, 0.0f, 272.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + + { 240.0f, 0.0f, 272.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 82.0f, 0.0f, 225.0f, 0.0f }, + + // Tall block -- white lambert + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 314.0f, 330.0f, 455.0f, 0.0f }, + + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 314.0f, 330.0f, 455.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + + { 423.0f, 0.0f, 247.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + + { 423.0f, 0.0f, 247.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + { 472.0f, 0.0f, 406.0f, 0.0f }, + + { 472.0f, 0.0f, 406.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + + { 472.0f, 0.0f, 406.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + { 314.0f, 0.0f, 456.0f, 0.0f }, + + { 314.0f, 0.0f, 456.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + + { 314.0f, 0.0f, 456.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 265.0f, 0.0f, 296.0f, 0.0f }, + + { 265.0f, 0.0f, 296.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + + { 265.0f, 0.0f, 296.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 423.0f, 0.0f, 247.0f, 0.0f }, + + // Ceiling light -- emmissive + { 343.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 332.0f, 0.0f }, + + { 343.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 332.0f, 0.0f }, + { 343.0f, 548.6f, 332.0f, 0.0f } +} }; + +static std::array g_mat_indices = {{ + 0, 0, // Floor -- white lambert + 0, 0, // Ceiling -- white lambert + 0, 0, // Back wall -- white lambert + 1, 1, // Right wall -- green lambert + 2, 2, // Left wall -- red lambert + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Short block -- white lambert + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Tall block -- white lambert + 3, 3 // Ceiling light -- emmissive +}}; + + + +const std::array g_emission_colors = +{ { + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 15.0f, 15.0f, 5.0f } + +} }; + + +const std::array g_diffuse_colors = +{ { + { 0.80f, 0.80f, 0.80f }, + { 0.05f, 0.80f, 0.05f }, + { 0.80f, 0.05f, 0.05f }, + { 0.50f, 0.00f, 0.00f } +} }; + + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking( static_cast( xpos ), static_cast( ypos ) ); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + Params& params = static_cast(glfwGetWindowUserPointer( window ))->params; + + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params.width, params.height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params.width, params.height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + Params& params = static_cast(glfwGetWindowUserPointer( window ))->params; + params.width = res_x; + params.height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + +void updatePipeline( PathTracerState& state ); + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + } + else if( key == GLFW_KEY_G ) + { + // toggle UI draw + } + else if( key == GLFW_KEY_S ) + { + specialize = !specialize; + updatePipeline( *static_cast(glfwGetWindowUserPointer( window )) ); + } +} + + +static void charCallback( GLFWwindow* window, unsigned int codepoint ) +{ + if( codepoint == '+' ) + { + ++light_samples; + if( specialize ) + updatePipeline( *static_cast(glfwGetWindowUserPointer( window )) ); + } + else if( codepoint == '-' ) + { + if( light_samples > 1 ) + { + --light_samples; + if( specialize ) + updatePipeline( *static_cast(glfwGetWindowUserPointer( window )) ); + } + } +} + + +static void scrollCallback( GLFWwindow* window, double xscroll, double yscroll ) +{ + if( trackball.wheelEvent( (int)yscroll ) ) + camera_changed = true; +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --launch-samples | -s Number of samples per pixel per launch (default 16)\n"; + std::cerr << " --light-samples | -l Number of radiance samples (default 1)\n"; + std::cerr << " --no-specialize ...\n"; + std::cerr << " --no-gl-interop Disable GL interop for display\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 768x768\n"; + std::cerr << " --help | -h Print this usage message\n"; + exit( 0 ); +} + + +void initLaunchParams( PathTracerState& state ) +{ + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &state.params.accum_buffer ), + state.params.width * state.params.height * sizeof( float4 ) + ) ); + state.params.frame_buffer = nullptr; // Will be set when output buffer is mapped + + state.params.samples_per_launch = samples_per_launch; + state.params.light_samples = light_samples; + state.params.subframe_index = 0u; + + state.params.light.emission = make_float3( 15.0f, 15.0f, 5.0f ); + state.params.light.corner = make_float3( 343.0f, 548.5f, 227.0f ); + state.params.light.v1 = make_float3( 0.0f, 0.0f, 105.0f ); + state.params.light.v2 = make_float3( -130.0f, 0.0f, 0.0f ); + state.params.light.normal = normalize( cross( state.params.light.v1, state.params.light.v2 ) ); + state.params.handle = state.gas_handle; + + CUDA_CHECK( cudaStreamCreate( &state.stream ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_params ), sizeof( Params ) ) ); + +} + + +void handleCameraUpdate( Params& params ) +{ + if( !camera_changed ) + return; + camera_changed = false; + + camera.setAspectRatio( static_cast( params.width ) / static_cast( params.height ) ); + params.eye = camera.eye(); + camera.UVWFrame( params.U, params.V, params.W ); +} + + +void handleResize( sutil::CUDAOutputBuffer& output_buffer, Params& params ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + output_buffer.resize( params.width, params.height ); + + // Realloc accumulation buffer + CUDA_CHECK( cudaFree( reinterpret_cast( params.accum_buffer ) ) ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( ¶ms.accum_buffer ), + params.width * params.height * sizeof( float4 ) + ) ); +} + +void updateState( sutil::CUDAOutputBuffer& output_buffer, Params& params ) +{ + // Update params on device + if( camera_changed || resize_dirty ) + params.subframe_index = 0; + + params.light_samples = light_samples; + + handleCameraUpdate( params ); + handleResize( output_buffer, params ); +} + + +void launchSubframe( sutil::CUDAOutputBuffer& output_buffer, PathTracerState& state ) +{ + // Launch + uchar4* result_buffer_data = output_buffer.map(); + state.params.frame_buffer = result_buffer_data; + CUDA_CHECK( cudaMemcpyAsync( + reinterpret_cast( state.d_params ), + &state.params, sizeof( Params ), + cudaMemcpyHostToDevice, state.stream + ) ); + + OPTIX_CHECK( optixLaunch( + state.pipeline, + state.stream, + reinterpret_cast( state.d_params ), + sizeof( Params ), + &state.sbt, + state.params.width, // launch width + state.params.height, // launch height + 1 // launch depth + ) ); + output_buffer.unmap(); + CUDA_SYNC_CHECK(); +} + + +void displaySubframe( sutil::CUDAOutputBuffer& output_buffer, sutil::GLDisplay& gl_display, GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( + output_buffer.width(), + output_buffer.height(), + framebuf_res_x, + framebuf_res_y, + output_buffer.getPBO() + ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n"; +} + + +void initCameraState() +{ + camera.setEye( make_float3( 278.0f, 273.0f, -900.0f ) ); + camera.setLookat( make_float3( 278.0f, 273.0f, 330.0f ) ); + camera.setUp( make_float3( 0.0f, 1.0f, 0.0f ) ); + camera.setFovY( 35.0f ); + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( + make_float3( 1.0f, 0.0f, 0.0f ), + make_float3( 0.0f, 0.0f, 1.0f ), + make_float3( 0.0f, 1.0f, 0.0f ) + ); + trackball.setGimbalLock( true ); +} + + +void createContext( PathTracerState& state ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cu_ctx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; +#ifdef DEBUG + // This may incur significant performance cost and should only be done during development. + options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; +#endif + OPTIX_CHECK( optixDeviceContextCreate( cu_ctx, &options, &context ) ); + + state.context = context; +} + + +void buildMeshAccel( PathTracerState& state ) +{ + // + // copy mesh data to device + // + const size_t vertices_size_in_bytes = g_vertices.size() * sizeof( Vertex ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_vertices ), vertices_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( state.d_vertices ), + g_vertices.data(), vertices_size_in_bytes, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr d_mat_indices = 0; + const size_t mat_indices_size_in_bytes = g_mat_indices.size() * sizeof( uint32_t ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_mat_indices ), mat_indices_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_mat_indices ), + g_mat_indices.data(), + mat_indices_size_in_bytes, + cudaMemcpyHostToDevice + ) ); + + // + // Build triangle GAS + // + uint32_t triangle_input_flags[MAT_COUNT] = // One per SBT record for this build input + { + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT + }; + + OptixBuildInput triangle_input = {}; + triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangle_input.triangleArray.vertexStrideInBytes = sizeof( Vertex ); + triangle_input.triangleArray.numVertices = static_cast( g_vertices.size() ); + triangle_input.triangleArray.vertexBuffers = &state.d_vertices; + triangle_input.triangleArray.flags = triangle_input_flags; + triangle_input.triangleArray.numSbtRecords = MAT_COUNT; + triangle_input.triangleArray.sbtIndexOffsetBuffer = d_mat_indices; + triangle_input.triangleArray.sbtIndexOffsetSizeInBytes = sizeof( uint32_t ); + triangle_input.triangleArray.sbtIndexOffsetStrideInBytes = sizeof( uint32_t ); + + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( + state.context, + &accel_options, + &triangle_input, + 1, // num_build_inputs + &gas_buffer_sizes + ) ); + + CUdeviceptr d_temp_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 + ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( (char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( + state.context, + 0, // CUDA stream + &accel_options, + &triangle_input, + 1, // num build inputs + d_temp_buffer, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &state.gas_handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_mat_indices ) ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, (void*)emitProperty.result, sizeof(size_t), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, 0, state.gas_handle, state.d_gas_output_buffer, compacted_gas_size, &state.gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + state.d_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } +} + + +void createRadianceModule( PathTracerState& state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + OptixModuleCompileBoundValueEntry boundValue = {}; + if( specialize ) + { + boundValue.pipelineParamOffsetInBytes = offsetof( Params, light_samples ); + boundValue.sizeInBytes = sizeof( Params::light_samples ); + boundValue.boundValuePtr = &light_samples; + boundValue.annotation = "light_samples"; + module_compile_options.numBoundValues = 1; + module_compile_options.boundValues = &boundValue; + } + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixBoundValues_ch.cu", inputSize ); + + OPTIX_CHECK_LOG( optixModuleCreate( + state.context, + &module_compile_options, + &state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &state.ptx_module_radiance + ) ); +} + +void createModule( PathTracerState& state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + state.pipeline_compile_options.usesMotionBlur = false; + state.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + state.pipeline_compile_options.numPayloadValues = 2; + state.pipeline_compile_options.numAttributeValues = 2; + state.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + state.pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixBoundValues.cu", inputSize ); + + OPTIX_CHECK_LOG( optixModuleCreate( + state.context, + &module_compile_options, + &state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &state.ptx_module + ) ); + + createRadianceModule( state ); +} + +void createRadianceProgramGroup( PathTracerState& state ) +{ + OptixProgramGroupOptions program_group_options ={}; + OptixProgramGroupDesc hit_prog_group_desc ={}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = state.ptx_module_radiance; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__radiance"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.radiance_hit_group + ) ); +} + +void createProgramGroups( PathTracerState& state ) +{ + OptixProgramGroupOptions program_group_options = {}; + + { + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = state.ptx_module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.raygen_prog_group + ) ); + } + + { + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.ptx_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__radiance"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.radiance_miss_group + ) ); + + memset( &miss_prog_group_desc, 0, sizeof( OptixProgramGroupDesc ) ); + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = nullptr; // NULL miss program for occlusion rays + miss_prog_group_desc.miss.entryFunctionName = nullptr; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.occlusion_miss_group + ) ); + } + + { + OptixProgramGroupDesc hit_prog_group_desc = {}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = state.ptx_module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__occlusion"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.occlusion_hit_group + ) ); + } + createRadianceProgramGroup( state ); +} + +void createPipeline( PathTracerState& state ) +{ + OptixProgramGroup program_groups[] = + { + state.raygen_prog_group, + state.radiance_miss_group, + state.occlusion_miss_group, + state.radiance_hit_group, + state.occlusion_hit_group + }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = 2; + + OPTIX_CHECK_LOG( optixPipelineCreate( + state.context, + &state.pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &state.pipeline + ) ); + + // We need to specify the max traversal depth. Calculate the stack sizes, so we can specify all + // parameters to optixPipelineSetStackSize. + OptixStackSizes stack_sizes = {}; + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.raygen_prog_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.radiance_miss_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.occlusion_miss_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.radiance_hit_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.occlusion_hit_group, &stack_sizes, state.pipeline ) ); + + uint32_t max_trace_depth = 2; + uint32_t max_cc_depth = 0; + uint32_t max_dc_depth = 0; + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( + &stack_sizes, + max_trace_depth, + max_cc_depth, + max_dc_depth, + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, + &continuation_stack_size + ) ); + + const uint32_t max_traversal_depth = 1; + OPTIX_CHECK( optixPipelineSetStackSize( + state.pipeline, + direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, + continuation_stack_size, + max_traversal_depth + ) ); +} + +void allocateSBT( PathTracerState& state ) +{ + const size_t raygen_record_size = sizeof( RayGenRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast(&state.sbt.raygenRecord), raygen_record_size ) ); + + const size_t miss_record_size = sizeof( MissRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast(&state.sbt.missRecordBase), miss_record_size * RAY_TYPE_COUNT ) ); + state.sbt.missRecordStrideInBytes = static_cast(miss_record_size); + state.sbt.missRecordCount = RAY_TYPE_COUNT; + + const size_t hitgroup_record_size = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast(&state.sbt.hitgroupRecordBase), + hitgroup_record_size * RAY_TYPE_COUNT * MAT_COUNT + ) ); + state.sbt.hitgroupRecordStrideInBytes = static_cast(hitgroup_record_size); + state.sbt.hitgroupRecordCount = RAY_TYPE_COUNT * MAT_COUNT; +} + +void fillSBT( PathTracerState& state ) +{ + const size_t raygen_record_size = sizeof( RayGenRecord ); + RayGenRecord rg_sbt ={}; + OPTIX_CHECK( optixSbtRecordPackHeader( state.raygen_prog_group, &rg_sbt ) ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast(state.sbt.raygenRecord), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + + + const size_t miss_record_size = sizeof( MissRecord ); + MissRecord ms_sbt[2]; + OPTIX_CHECK( optixSbtRecordPackHeader( state.radiance_miss_group, &ms_sbt[0] ) ); + ms_sbt[0].data.bg_color = make_float4( 0.0f ); + OPTIX_CHECK( optixSbtRecordPackHeader( state.occlusion_miss_group, &ms_sbt[1] ) ); + ms_sbt[1].data.bg_color = make_float4( 0.0f ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast(state.sbt.missRecordBase), + ms_sbt, + miss_record_size*RAY_TYPE_COUNT, + cudaMemcpyHostToDevice + ) ); +} + +void fillHitGroupSBT( PathTracerState& state ) +{ + const size_t hitgroup_record_size = sizeof( HitGroupRecord ); + HitGroupRecord hitgroup_records[RAY_TYPE_COUNT * MAT_COUNT]; + for( int i = 0; i < MAT_COUNT; ++i ) + { + { + const int sbt_idx = i * RAY_TYPE_COUNT + 0; // SBT for radiance ray-type for ith material + + OPTIX_CHECK( optixSbtRecordPackHeader( state.radiance_hit_group, &hitgroup_records[sbt_idx] ) ); + hitgroup_records[sbt_idx].data.emission_color = g_emission_colors[i]; + hitgroup_records[sbt_idx].data.diffuse_color = g_diffuse_colors[i]; + hitgroup_records[sbt_idx].data.vertices = reinterpret_cast(state.d_vertices); + } + + { + const int sbt_idx = i * RAY_TYPE_COUNT + 1; // SBT for occlusion ray-type for ith material + memset( &hitgroup_records[sbt_idx], 0, hitgroup_record_size ); + + OPTIX_CHECK( optixSbtRecordPackHeader( state.occlusion_hit_group, &hitgroup_records[sbt_idx] ) ); + } + } + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast(state.sbt.hitgroupRecordBase), + hitgroup_records, + hitgroup_record_size*RAY_TYPE_COUNT*MAT_COUNT, + cudaMemcpyHostToDevice + ) ); +} + +void createSBT( PathTracerState& state ) +{ + allocateSBT( state ); + fillSBT( state ); + fillHitGroupSBT( state ); +} + +void updatePipeline( PathTracerState& state ) +{ + // destroy old stuff + OPTIX_CHECK( optixPipelineDestroy( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_hit_group ) ); + OPTIX_CHECK( optixModuleDestroy( state.ptx_module_radiance ) ); + + createRadianceModule( state ); + createRadianceProgramGroup( state ); + createPipeline( state ); + fillHitGroupSBT( state ); +} + +void cleanupState( PathTracerState& state ) +{ + OPTIX_CHECK( optixPipelineDestroy( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_miss_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_hit_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.occlusion_hit_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.occlusion_miss_group ) ); + OPTIX_CHECK( optixModuleDestroy( state.ptx_module ) ); + OPTIX_CHECK( optixModuleDestroy( state.ptx_module_radiance ) ); + OPTIX_CHECK( optixDeviceContextDestroy( state.context ) ); + + + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_vertices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.accum_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_params ) ) ); +} + + +//------------------------------------------------------------------------------ +// +// Main +// +//------------------------------------------------------------------------------ + +void displaySpecializationInfo( GLFWwindow* window ) +{ + static char display_text[256]; + + sutil::beginFrameImGui(); + sprintf( display_text, + "light samples [+/-]: %d\n" + "specialization [S] : %s\n", light_samples, (specialize ? "on" : "off") ); + Params& params = static_cast(glfwGetWindowUserPointer( window ))->params; + sutil::displayText( display_text, 10.0f, (float)params.height - 50.f ); + sutil::endFrameImGui(); +} + +int main( int argc, char* argv[] ) +{ + PathTracerState state; + state.params.width = 768; + state.params.height = 768; + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::GL_INTEROP; + + // + // Parse command line options + // + std::string outfile; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--no-gl-interop" ) + { + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + } + else if( arg == "--no-specialize" ) + { + specialize = false; + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outfile = argv[++i]; + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + int w, h; + sutil::parseDimensions( dims_arg.c_str(), w, h ); + state.params.width = w; + state.params.height = h; + } + else if( arg == "--launch-samples" || arg == "-s" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + samples_per_launch = atoi( argv[++i] ); + } + else if( arg == "--light-samples" || arg == "-l" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + light_samples = atoi( argv[++i] ); + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + initCameraState(); + + // + // Set up OptiX state + // + createContext( state ); + buildMeshAccel( state ); + createModule( state ); + createProgramGroups( state ); + createPipeline( state ); + createSBT( state ); + initLaunchParams( state ); + + + if( outfile.empty() ) + { + GLFWwindow* window = sutil::initUI( "optixBoundValues", state.params.width, state.params.height ); + glfwSetMouseButtonCallback( window, mouseButtonCallback ); + glfwSetCursorPosCallback( window, cursorPosCallback ); + glfwSetWindowSizeCallback( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback( window, keyCallback ); + glfwSetCharCallback( window, charCallback ); + glfwSetScrollCallback( window, scrollCallback ); + glfwSetWindowUserPointer( window, &state ); + + // + // Render loop + // + { + sutil::CUDAOutputBuffer output_buffer( + output_buffer_type, + state.params.width, + state.params.height + ); + + output_buffer.setStream( state.stream ); + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + updateState( output_buffer, state.params ); + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + launchSubframe( output_buffer, state ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1 - t0; + + sutil::displayStats( state_update_time, render_time, display_time ); + + displaySpecializationInfo( window ); + + glfwSwapBuffers( window ); + + ++state.params.subframe_index; + } while( !glfwWindowShouldClose( window ) ); + CUDA_SYNC_CHECK(); + } + + sutil::cleanupUI( window ); + } + else + { + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + sutil::initGLFW(); // For GL context + sutil::initGL(); + } + + { + // this scope is for output_buffer, to ensure the destructor is called bfore glfwTerminate() + + sutil::CUDAOutputBuffer output_buffer( + output_buffer_type, + state.params.width, + state.params.height + ); + + handleCameraUpdate( state.params ); + handleResize( output_buffer, state.params ); + launchSubframe( output_buffer, state ); + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + glfwTerminate(); + } + } + + cleanupState( state ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/optixBoundValues.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/optixBoundValues.cu new file mode 100644 index 00000000..ecda4ab9 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/optixBoundValues.cu @@ -0,0 +1,175 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include "optixBoundValues.h" +#include "random.h" + +extern "C" { +__constant__ Params params; +} + + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + + + +static __forceinline__ __device__ void setPayloadOcclusion( bool occluded ) +{ + optixSetPayload_0( static_cast( occluded ) ); +} + +static __forceinline__ __device__ void traceRadiance( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax, + RadiancePRD* prd + ) +{ + // TODO: deduce stride from num ray-types passed in params + + unsigned int u0, u1; + packPointer( prd, u0, u1 ); + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_NONE, + RAY_TYPE_RADIANCE, // SBT offset + RAY_TYPE_COUNT, // SBT stride + RAY_TYPE_RADIANCE, // missSBTIndex + u0, u1 ); +} + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +extern "C" __global__ void __raygen__rg() +{ + const int w = params.width; + const int h = params.height; + const float3 eye = params.eye; + const float3 U = params.U; + const float3 V = params.V; + const float3 W = params.W; + const uint3 idx = optixGetLaunchIndex(); + const int subframe_index = params.subframe_index; + + unsigned int seed = tea<4>( idx.y*w + idx.x, subframe_index ); + + float3 result = make_float3( 0.0f ); + int i = params.samples_per_launch; + do + { + const float2 subpixel_jitter = make_float2( rnd( seed )-0.5f, rnd( seed )-0.5f ); + + const float2 d = 2.0f * make_float2( + ( static_cast( idx.x ) + subpixel_jitter.x ) / static_cast( w ), + ( static_cast( idx.y ) + subpixel_jitter.y ) / static_cast( h ) + ) - 1.0f; + float3 ray_direction = normalize(d.x*U + d.y*V + W); + float3 ray_origin = eye; + + RadiancePRD prd; + prd.emitted = make_float3(0.f); + prd.radiance = make_float3(0.f); + prd.attenuation = make_float3(1.f); + prd.countEmitted = true; + prd.done = false; + prd.seed = seed; + + int depth = 0; + for( ;; ) + { + traceRadiance( + params.handle, + ray_origin, + ray_direction, + 0.01f, // tmin // TODO: smarter offset + 1e16f, // tmax + &prd ); + + result += prd.emitted; + result += prd.radiance * prd.attenuation; + + if( prd.done || depth >= 3 ) // TODO RR, variable for depth + break; + + ray_origin = prd.origin; + ray_direction = prd.direction; + + ++depth; + } + } + while( --i ); + + const uint3 launch_index = optixGetLaunchIndex(); + const unsigned int image_index = launch_index.y * params.width + launch_index.x; + float3 accum_color = result / static_cast( params.samples_per_launch ); + + if( subframe_index > 0 ) + { + const float a = 1.0f / static_cast( subframe_index+1 ); + const float3 accum_color_prev = make_float3( params.accum_buffer[ image_index ]); + accum_color = lerp( accum_color_prev, accum_color, a ); + } + params.accum_buffer[ image_index ] = make_float4( accum_color, 1.0f); + params.frame_buffer[ image_index ] = make_color ( accum_color ); +} + + +extern "C" __global__ void __miss__radiance() +{ + MissData* rt_data = reinterpret_cast( optixGetSbtDataPointer() ); + RadiancePRD* prd = getPRD(); + + prd->radiance = make_float3( rt_data->bg_color ); + prd->done = true; +} + + +extern "C" __global__ void __closesthit__occlusion() +{ + setPayloadOcclusion( true ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/optixBoundValues.h b/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/optixBoundValues.h new file mode 100644 index 00000000..89788e16 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/optixBoundValues.h @@ -0,0 +1,163 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +enum RayType +{ + RAY_TYPE_RADIANCE = 0, + RAY_TYPE_OCCLUSION = 1, + RAY_TYPE_COUNT +}; + + +struct ParallelogramLight +{ + float3 corner; + float3 v1, v2; + float3 normal; + float3 emission; +}; + + +struct Params +{ + unsigned int subframe_index; + float4* accum_buffer; + uchar4* frame_buffer; + unsigned int width; + unsigned int height; + unsigned int samples_per_launch; + unsigned int light_samples; + + float3 eye; + float3 U; + float3 V; + float3 W; + + ParallelogramLight light; // TODO: make light list + OptixTraversableHandle handle; +}; + + +struct RayGenData +{ +}; + + +struct MissData +{ + float4 bg_color; +}; + + +struct HitGroupData +{ + float3 emission_color; + float3 diffuse_color; + float4* vertices; +}; + +#if defined( __CUDACC__ ) + +#include +#include + +struct RadiancePRD +{ + // TODO: move some state directly into payload registers? + float3 emitted; + float3 radiance; + float3 attenuation; + float3 origin; + float3 direction; + unsigned int seed; + int countEmitted; + int done; + int pad; +}; + + +struct Onb +{ + __forceinline__ __device__ Onb( const float3& normal ) + { + m_normal = normal; + + if( fabs( m_normal.x ) > fabs( m_normal.z ) ) + { + m_binormal.x = -m_normal.y; + m_binormal.y = m_normal.x; + m_binormal.z = 0; + } + else + { + m_binormal.x = 0; + m_binormal.y = -m_normal.z; + m_binormal.z = m_normal.y; + } + + m_binormal = normalize( m_binormal ); + m_tangent = cross( m_binormal, m_normal ); + } + + __forceinline__ __device__ void inverse_transform( float3& p ) const + { + p = p.x*m_tangent + p.y*m_binormal + p.z*m_normal; + } + + float3 m_tangent; + float3 m_binormal; + float3 m_normal; +}; + + +static __forceinline__ __device__ void* unpackPointer( unsigned int i0, unsigned int i1 ) +{ + const unsigned long long uptr = static_cast(i0) << 32 | i1; + void* ptr = reinterpret_cast(uptr); + return ptr; +} + + +static __forceinline__ __device__ void packPointer( void* ptr, unsigned int& i0, unsigned int& i1 ) +{ + const unsigned long long uptr = reinterpret_cast(ptr); + i0 = uptr >> 32; + i1 = uptr & 0x00000000ffffffff; +} + +static __forceinline__ __device__ RadiancePRD* getPRD() +{ + const unsigned int u0 = optixGetPayload_0(); + const unsigned int u1 = optixGetPayload_1(); + return reinterpret_cast(unpackPointer( u0, u1 )); +} + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/optixBoundValues_ch.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/optixBoundValues_ch.cu new file mode 100644 index 00000000..120f0dad --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixBoundValues/optixBoundValues_ch.cu @@ -0,0 +1,164 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include "optixBoundValues.h" +#include "random.h" + +extern "C" { +__constant__ Params params; +} + + + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +static __forceinline__ __device__ void cosine_sample_hemisphere(const float u1, const float u2, float3& p) +{ + // Uniformly sample disk. + const float r = sqrtf( u1 ); + const float phi = 2.0f*M_PIf * u2; + p.x = r * cosf( phi ); + p.y = r * sinf( phi ); + + // Project up to hemisphere. + p.z = sqrtf( fmaxf( 0.0f, 1.0f - p.x*p.x - p.y*p.y ) ); +} + +static __forceinline__ __device__ bool traceOcclusion( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax + ) +{ + unsigned int occluded = 0u; + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT, + RAY_TYPE_OCCLUSION, // SBT offset + RAY_TYPE_COUNT, // SBT stride + RAY_TYPE_OCCLUSION, // missSBTIndex + occluded ); + return occluded; +} + +extern "C" __global__ void __closesthit__radiance() +{ + HitGroupData* rt_data = (HitGroupData*)optixGetSbtDataPointer(); + + const int prim_idx = optixGetPrimitiveIndex(); + const float3 ray_dir = optixGetWorldRayDirection(); + const int vert_idx_offset = prim_idx*3; + + const float3 v0 = make_float3( rt_data->vertices[ vert_idx_offset+0 ] ); + const float3 v1 = make_float3( rt_data->vertices[ vert_idx_offset+1 ] ); + const float3 v2 = make_float3( rt_data->vertices[ vert_idx_offset+2 ] ); + const float3 N_0 = normalize( cross( v1-v0, v2-v0 ) ); + + const float3 N = faceforward( N_0, -ray_dir, N_0 ); + const float3 P = optixGetWorldRayOrigin() + optixGetRayTmax()*ray_dir; + + RadiancePRD* prd = getPRD(); + + if( prd->countEmitted ) + prd->emitted = rt_data->emission_color; + else + prd->emitted = make_float3( 0.0f ); + + + unsigned int seed = prd->seed; + + { + const float z1 = rnd(seed); + const float z2 = rnd(seed); + + float3 w_in; + cosine_sample_hemisphere( z1, z2, w_in ); + Onb onb( N ); + onb.inverse_transform( w_in ); + prd->direction = w_in; + prd->origin = P; + + prd->attenuation *= rt_data->diffuse_color; + prd->countEmitted = false; + } + + float3 result = make_float3( 0.0f ); + + for( int i = 0; i < params.light_samples; ++i ) + { + const float z1 = rnd( seed ); + const float z2 = rnd( seed ); + prd->seed = seed; + + ParallelogramLight light = params.light; + const float3 light_pos = light.corner + light.v1 * z1 + light.v2 * z2; + + // Calculate properties of light sample (for area based pdf) + const float Ldist = length( light_pos - P ); + const float3 L = normalize( light_pos - P ); + const float nDl = dot( N, L ); + const float LnDl = -dot( light.normal, L ); + + float weight = 0.0f; + if( nDl > 0.0f && LnDl > 0.0f ) + { + const bool occluded = traceOcclusion( + params.handle, + P, + L, + 0.01f, // tmin + Ldist - 0.01f // tmax + ); + + if( !occluded ) + { + const float A = length( cross( light.v1, light.v2 ) ); + weight = nDl * LnDl * A / (M_PIf * Ldist * Ldist); + result += (light.emission * weight); + } + } + } + + prd->radiance += ( result / params.light_samples ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCallablePrograms/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixCallablePrograms/CMakeLists.txt new file mode 100644 index 00000000..e3dddf13 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCallablePrograms/CMakeLists.txt @@ -0,0 +1,40 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixCallablePrograms target_name + optixCallablePrograms.cpp + optixCallablePrograms.cu + optixCallablePrograms.h + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCallablePrograms/optixCallablePrograms.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixCallablePrograms/optixCallablePrograms.cpp new file mode 100644 index 00000000..d8f59adf --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCallablePrograms/optixCallablePrograms.cpp @@ -0,0 +1,889 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include // Needs to be included before gl_interop + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "optixCallablePrograms.h" + +//------------------------------------------------------------------------------ +// +// Globals +// +//------------------------------------------------------------------------------ + +bool resize_dirty = false; +bool minimized = false; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Shading state +bool shading_changed = false; +unsigned int dc_index = 0; + +// Mouse state +int32_t mouse_button = -1; + +//------------------------------------------------------------------------------ +// +// Local types +// +//------------------------------------------------------------------------------ + +template +struct Record +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef Record RayGenRecord; +typedef Record MissRecord; +typedef Record HitGroupRecord; +typedef Record CallablesRecord; + +struct CallableProgramsState +{ + OptixDeviceContext context = 0; + OptixTraversableHandle gas_handle = 0; + CUdeviceptr d_gas_output_buffer = 0; + + OptixModule camera_module = 0; + OptixModule geometry_module = 0; + OptixModule shading_module = 0; + + OptixProgramGroup raygen_prog_group = 0; + OptixProgramGroup miss_prog_group = 0; + OptixProgramGroup hitgroup_prog_group = 0; + OptixProgramGroup callable_prog_groups[3] = {}; + + OptixPipeline pipeline = 0; + OptixPipelineCompileOptions pipeline_compile_options = {}; + + CUstream stream = 0; + whitted::LaunchParams params = {}; + whitted::LaunchParams* d_params = 0; + OptixShaderBindingTable sbt = {}; +}; + +//------------------------------------------------------------------------------ +// +// Geometry data +// +//------------------------------------------------------------------------------ + +const GeometryData::Sphere g_sphere = { + {0.f, 0.f, 0.f}, // center + 1.0f // radius +}; + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking( static_cast( xpos ), static_cast( ypos ) ); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + whitted::LaunchParams* params = static_cast( glfwGetWindowUserPointer( window ) ); + + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params->width, params->height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params->width, params->height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + whitted::LaunchParams* params = static_cast( glfwGetWindowUserPointer( window ) ); + params->width = res_x; + params->height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + } + else if( key == GLFW_KEY_SPACE ) + { + shading_changed = true; + dc_index = ( dc_index + 1 ) % 3; + } +} + + +static void scrollCallback( GLFWwindow* window, double xscroll, double yscroll ) +{ + if( trackball.wheelEvent( (int)yscroll ) ) + camera_changed = true; +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// +//------------------------------------------------------------------------------ + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --no-gl-interop Disable GL interop for display\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 768x768\n"; + std::cerr << " --help | -h Print this usage message\n"; + exit( 0 ); +} + +void initLaunchParams( CallableProgramsState& state ) +{ + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.params.accum_buffer ), + state.params.width * state.params.height * sizeof( float4 ) ) ); + state.params.frame_buffer = nullptr; // Will be set when output buffer is mapped + + state.params.subframe_index = 0u; + + // Set ambient light color and point light position + std::vector lights( 2 ); + lights[0].type = Light::Type::AMBIENT; + lights[0].ambient.color = make_float3( 0.4f, 0.4f, 0.4f ); + lights[1].type = Light::Type::POINT; + lights[1].point.color = make_float3( 1.0f, 1.0f, 1.0f ); + lights[1].point.intensity = 1.0f; + lights[1].point.position = make_float3( 10.0f, 10.0f, -10.0f ); + lights[1].point.falloff = Light::Falloff::QUADRATIC; + + state.params.lights.count = static_cast( lights.size() ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.params.lights.data ), lights.size() * sizeof( Light ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( state.params.lights.data ), lights.data(), + lights.size() * sizeof( Light ), cudaMemcpyHostToDevice ) ); + + CUDA_CHECK( cudaStreamCreate( &state.stream ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_params ), sizeof( whitted::LaunchParams ) ) ); + + state.params.handle = state.gas_handle; +} + +inline OptixAabb sphere_bound( float3 center, float radius ) +{ + float3 m_min = center - radius; + float3 m_max = center + radius; + + return { + m_min.x, m_min.y, m_min.z, + m_max.x, m_max.y, m_max.z + }; +} + +static void buildGas( const CallableProgramsState& state, + const OptixAccelBuildOptions& accel_options, + const OptixBuildInput& build_input, + OptixTraversableHandle& gas_handle, + CUdeviceptr& d_gas_output_buffer ) +{ + OptixAccelBufferSizes gas_buffer_sizes; + CUdeviceptr d_temp_buffer_gas; + + OPTIX_CHECK( optixAccelComputeMemoryUsage( state.context, &accel_options, &build_input, 1, &gas_buffer_sizes ) ); + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer_gas ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output and size of compacted GAS + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), compactedSizeOffset + 8 ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( (char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( state.context, 0, &accel_options, &build_input, 1, d_temp_buffer_gas, + gas_buffer_sizes.tempSizeInBytes, d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, &gas_handle, &emitProperty, 1 ) ); + + CUDA_CHECK( cudaFree( (void*)d_temp_buffer_gas ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, (void*)emitProperty.result, sizeof( size_t ), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, 0, gas_handle, d_gas_output_buffer, compacted_gas_size, &gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + d_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } +} + +void createGeometry( CallableProgramsState& state ) +{ + // + // Build Custom Primitive for Sphere + // + + // Load AABB into device memory + OptixAabb aabb = sphere_bound( g_sphere.center, g_sphere.radius ); + CUdeviceptr d_aabb; + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_aabb ), sizeof( OptixAabb ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_aabb ), &aabb, sizeof( OptixAabb ), cudaMemcpyHostToDevice ) ); + + // Setup AABB build input + uint32_t aabb_input_flags[1] = {OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT}; + + const uint32_t sbt_index[1] = {0}; + CUdeviceptr d_sbt_index; + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_sbt_index ), sizeof( uint32_t ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_sbt_index ), sbt_index, sizeof( uint32_t ), cudaMemcpyHostToDevice ) ); + + OptixBuildInput aabb_input = {}; + aabb_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES; + aabb_input.customPrimitiveArray.aabbBuffers = &d_aabb; + aabb_input.customPrimitiveArray.flags = aabb_input_flags; + aabb_input.customPrimitiveArray.numSbtRecords = 1; + aabb_input.customPrimitiveArray.numPrimitives = 1; + aabb_input.customPrimitiveArray.sbtIndexOffsetBuffer = d_sbt_index; + aabb_input.customPrimitiveArray.sbtIndexOffsetSizeInBytes = sizeof( uint32_t ); + aabb_input.customPrimitiveArray.primitiveIndexOffset = 0; + + OptixAccelBuildOptions accel_options = { + OPTIX_BUILD_FLAG_ALLOW_COMPACTION, // buildFlags + OPTIX_BUILD_OPERATION_BUILD // operation + }; + + buildGas( state, accel_options, aabb_input, state.gas_handle, state.d_gas_output_buffer ); + + CUDA_CHECK( cudaFree( (void*)d_aabb ) ); + CUDA_CHECK( cudaFree( (void*)d_sbt_index ) ); +} + +void createModules( CallableProgramsState& state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + { + size_t inputSize = 0; + const char* input = sutil::getInputData( nullptr, nullptr, "whitted.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( state.context, &module_compile_options, &state.pipeline_compile_options, + input, inputSize, LOG, &LOG_SIZE, &state.camera_module ) ); + } + + { + size_t inputSize = 0; + const char* input = sutil::getInputData( nullptr, nullptr, "sphere.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( state.context, &module_compile_options, &state.pipeline_compile_options, + input, inputSize, LOG, &LOG_SIZE, &state.geometry_module ) ); + } + + { + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixCallablePrograms.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( state.context, &module_compile_options, &state.pipeline_compile_options, + input, inputSize, LOG, &LOG_SIZE, &state.shading_module ) ); + } +} + +static void createCameraProgram( CallableProgramsState& state, std::vector& program_groups ) +{ + OptixProgramGroup cam_prog_group; + OptixProgramGroupOptions cam_prog_group_options = {}; + OptixProgramGroupDesc cam_prog_group_desc = {}; + cam_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + cam_prog_group_desc.raygen.module = state.camera_module; + cam_prog_group_desc.raygen.entryFunctionName = "__raygen__pinhole"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &cam_prog_group_desc, 1, &cam_prog_group_options, LOG, + &LOG_SIZE, &cam_prog_group ) ); + + program_groups.push_back( cam_prog_group ); + state.raygen_prog_group = cam_prog_group; +} + +static void createSphereProgram( CallableProgramsState& state, std::vector& program_groups ) +{ + OptixProgramGroup hitgroup_prog_group; + OptixProgramGroupOptions hitgroup_prog_group_options = {}; + OptixProgramGroupDesc hitgroup_prog_group_desc = {}; + hitgroup_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP, + hitgroup_prog_group_desc.hitgroup.moduleIS = state.geometry_module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__sphere"; + hitgroup_prog_group_desc.hitgroup.moduleCH = state.shading_module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__radiance"; + hitgroup_prog_group_desc.hitgroup.moduleAH = nullptr; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &hitgroup_prog_group_desc, 1, &hitgroup_prog_group_options, + LOG, &LOG_SIZE, &hitgroup_prog_group ) ); + + program_groups.push_back( hitgroup_prog_group ); + state.hitgroup_prog_group = hitgroup_prog_group; + + // Callable programs + OptixProgramGroupOptions callable_prog_group_options = {}; + OptixProgramGroupDesc callable_prog_group_descs[3] = {}; + + callable_prog_group_descs[0].kind = OPTIX_PROGRAM_GROUP_KIND_CALLABLES; + callable_prog_group_descs[0].callables.moduleDC = state.shading_module; + callable_prog_group_descs[0].callables.entryFunctionNameDC = "__direct_callable__phong_shade"; + callable_prog_group_descs[0].callables.moduleCC = state.shading_module; + callable_prog_group_descs[0].callables.entryFunctionNameCC = "__continuation_callable__raydir_shade"; + + callable_prog_group_descs[1].kind = OPTIX_PROGRAM_GROUP_KIND_CALLABLES; + callable_prog_group_descs[1].callables.moduleDC = state.shading_module; + callable_prog_group_descs[1].callables.entryFunctionNameDC = "__direct_callable__checkered_shade"; + + callable_prog_group_descs[2].kind = OPTIX_PROGRAM_GROUP_KIND_CALLABLES; + callable_prog_group_descs[2].callables.moduleDC = state.shading_module; + callable_prog_group_descs[2].callables.entryFunctionNameDC = "__direct_callable__normal_shade"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, callable_prog_group_descs, 3, &callable_prog_group_options, + LOG, &LOG_SIZE, state.callable_prog_groups ) ); + + program_groups.push_back( state.callable_prog_groups[0] ); + program_groups.push_back( state.callable_prog_groups[1] ); + program_groups.push_back( state.callable_prog_groups[2] ); +} + +static void createMissProgram( CallableProgramsState& state, std::vector& program_groups ) +{ + OptixProgramGroupOptions miss_prog_group_options = {}; + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.shading_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__raydir_shade"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &miss_prog_group_desc, 1, &miss_prog_group_options, LOG, + &LOG_SIZE, &state.miss_prog_group ) ); + + program_groups.push_back( state.miss_prog_group ); +} + +void createPipeline( CallableProgramsState& state ) +{ + const uint32_t max_trace_depth = 1; + const uint32_t max_cc_depth = 1; + const uint32_t max_dc_depth = 1; + const uint32_t max_traversal_depth = 1; + + std::vector program_groups; + + state.pipeline_compile_options = { + false, // usesMotionBlur + OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS, // traversableGraphFlags + whitted::NUM_PAYLOAD_VALUES, // numPayloadValues + whitted::NUM_ATTRIBUTE_VALUES, // numAttributeValues + OPTIX_EXCEPTION_FLAG_NONE, // exceptionFlags + "params" // pipelineLaunchParamsVariableName + }; + + // Prepare program groups + createModules( state ); + createCameraProgram( state, program_groups ); + createSphereProgram( state, program_groups ); + createMissProgram( state, program_groups ); + + // Link program groups to pipeline + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + OPTIX_CHECK_LOG( optixPipelineCreate( state.context, &state.pipeline_compile_options, &pipeline_link_options, + program_groups.data(), static_cast( program_groups.size() ), + LOG, &LOG_SIZE, &state.pipeline ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, state.pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, max_cc_depth, max_dc_depth, &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( state.pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, max_traversal_depth ) ); +} + +void syncDCShaderIndexToSbt( CallableProgramsState& state ) +{ + // Update the dc_index in HitGroupData so that the closest hit program invokes the correct DC for shading + HitGroupRecord hitgroup_record; + OPTIX_CHECK( optixSbtRecordPackHeader( state.hitgroup_prog_group, &hitgroup_record ) ); + hitgroup_record.data.dc_index = dc_index; + + CUDA_CHECK( cudaMemcpy( reinterpret_cast( state.sbt.hitgroupRecordBase + + ( sizeof( hitgroup_record.header ) + sizeof( GeometryData::Sphere ) ) ), + &hitgroup_record.data.dc_index, sizeof( unsigned int ), cudaMemcpyHostToDevice ) ); +} + +void createSBT( CallableProgramsState& state ) +{ + // Raygen program record + { + RayGenRecord raygen_record; + OPTIX_CHECK( optixSbtRecordPackHeader( state.raygen_prog_group, &raygen_record ) ); + + CUdeviceptr d_raygen_record; + size_t sizeof_raygen_record = sizeof( RayGenRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_raygen_record ), sizeof_raygen_record ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_raygen_record ), &raygen_record, sizeof_raygen_record, cudaMemcpyHostToDevice ) ); + + state.sbt.raygenRecord = d_raygen_record; + } + + // Miss program record + { + MissRecord miss_record; + OPTIX_CHECK( optixSbtRecordPackHeader( state.miss_prog_group, &miss_record ) ); + + CUdeviceptr d_miss_record; + size_t sizeof_miss_record = sizeof( MissRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_miss_record ), sizeof_miss_record ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_miss_record ), &miss_record, sizeof_miss_record, cudaMemcpyHostToDevice ) ); + + state.sbt.missRecordBase = d_miss_record; + state.sbt.missRecordCount = 1; + state.sbt.missRecordStrideInBytes = static_cast( sizeof_miss_record ); + } + + // Hitgroup program record + { + HitGroupRecord hitgroup_record; + OPTIX_CHECK( optixSbtRecordPackHeader( state.hitgroup_prog_group, &hitgroup_record ) ); + hitgroup_record.data.geometry_data.setSphere( g_sphere ); + hitgroup_record.data.dc_index = dc_index; + + CUdeviceptr d_hitgroup_record; + size_t sizeof_hitgroup_record = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_hitgroup_record ), sizeof_hitgroup_record ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_hitgroup_record ), &hitgroup_record, sizeof_hitgroup_record, + cudaMemcpyHostToDevice ) ); + + state.sbt.hitgroupRecordBase = d_hitgroup_record; + state.sbt.hitgroupRecordCount = 1; + state.sbt.hitgroupRecordStrideInBytes = static_cast( sizeof_hitgroup_record ); + } + + // Callables program record + { + CallablesRecord callable_records[3]; + OPTIX_CHECK( optixSbtRecordPackHeader( state.callable_prog_groups[0], &callable_records[0] ) ); + OPTIX_CHECK( optixSbtRecordPackHeader( state.callable_prog_groups[1], &callable_records[1] ) ); + OPTIX_CHECK( optixSbtRecordPackHeader( state.callable_prog_groups[2], &callable_records[2] ) ); + + CUdeviceptr d_callable_records; + size_t sizeof_callable_record = sizeof( CallablesRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_callable_records ), sizeof_callable_record * 3 ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_callable_records ), callable_records, + sizeof_callable_record * 3, cudaMemcpyHostToDevice ) ); + + state.sbt.callablesRecordBase = d_callable_records; + state.sbt.callablesRecordCount = 3; + state.sbt.callablesRecordStrideInBytes = static_cast( sizeof_callable_record ); + } +} + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n"; +} + +void createContext( CallableProgramsState& state ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + + state.context = context; +} + +// +// Handle updates +// + +void initCameraState() +{ + camera.setEye( make_float3( 0.0f, 0.0f, -3.0f ) ); + camera.setLookat( make_float3( 0.0f, 0.0f, 0.0f ) ); + camera.setUp( make_float3( 0.0f, 1.0f, 0.0f ) ); + camera.setFovY( 60.0f ); + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( make_float3( 1.0f, 0.0f, 0.0f ), make_float3( 0.0f, 0.0f, 1.0f ), make_float3( 0.0f, 1.0f, 0.0f ) ); + trackball.setGimbalLock( true ); +} + +void handleCameraUpdate( CallableProgramsState& state ) +{ + if( !camera_changed ) + return; + camera_changed = false; + + camera.setAspectRatio( static_cast( state.params.width ) / static_cast( state.params.height ) ); + state.params.eye = camera.eye(); + camera.UVWFrame( state.params.U, state.params.V, state.params.W ); +} + +void handleResize( sutil::CUDAOutputBuffer& output_buffer, whitted::LaunchParams& params ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + output_buffer.resize( params.width, params.height ); + + // Realloc accumulation buffer + CUDA_CHECK( cudaFree( reinterpret_cast( params.accum_buffer ) ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( ¶ms.accum_buffer ), params.width * params.height * sizeof( float4 ) ) ); +} + +void handleShading( CallableProgramsState& state ) +{ + if( !shading_changed ) + return; + shading_changed = false; + + syncDCShaderIndexToSbt( state ); +} + +void updateState( sutil::CUDAOutputBuffer& output_buffer, CallableProgramsState& state ) +{ + // Update params on device + if( camera_changed || resize_dirty || shading_changed ) + state.params.subframe_index = 0; + + handleCameraUpdate( state ); + handleResize( output_buffer, state.params ); + handleShading( state ); +} + +void launchSubframe( sutil::CUDAOutputBuffer& output_buffer, CallableProgramsState& state ) +{ + + // Launch + uchar4* result_buffer_data = output_buffer.map(); + state.params.frame_buffer = result_buffer_data; + CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast( state.d_params ), &state.params, + sizeof( whitted::LaunchParams ), cudaMemcpyHostToDevice, state.stream ) ); + + OPTIX_CHECK( optixLaunch( state.pipeline, state.stream, reinterpret_cast( state.d_params ), + sizeof( whitted::LaunchParams ), &state.sbt, + state.params.width, // launch width + state.params.height, // launch height + 1 // launch depth + ) ); + output_buffer.unmap(); + CUDA_SYNC_CHECK(); +} + + +void displaySubframe( sutil::CUDAOutputBuffer& output_buffer, sutil::GLDisplay& gl_display, GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( output_buffer.width(), output_buffer.height(), framebuf_res_x, framebuf_res_y, output_buffer.getPBO() ); +} + + +void cleanupState( CallableProgramsState& state ) +{ + OPTIX_CHECK( optixPipelineDestroy( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.hitgroup_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.callable_prog_groups[0] ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.callable_prog_groups[1] ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.callable_prog_groups[2] ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.miss_prog_group ) ); + OPTIX_CHECK( optixModuleDestroy( state.shading_module ) ); + OPTIX_CHECK( optixModuleDestroy( state.geometry_module ) ); + OPTIX_CHECK( optixModuleDestroy( state.camera_module ) ); + OPTIX_CHECK( optixDeviceContextDestroy( state.context ) ); + + + CUDA_CHECK( cudaStreamDestroy( state.stream ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.callablesRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.accum_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.lights.data ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_params ) ) ); +} + +int main( int argc, char* argv[] ) +{ + CallableProgramsState state; + state.params.width = 768; + state.params.height = 768; + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::GL_INTEROP; + + // + // Parse command line options + // + std::string outfile; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--no-gl-interop" ) + { + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outfile = argv[++i]; + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + int w, h; + sutil::parseDimensions( dims_arg.c_str(), w, h ); + state.params.width = w; + state.params.height = h; + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + initCameraState(); + + // + // Set up OptiX state + // + createContext( state ); + createGeometry( state ); + createPipeline( state ); + createSBT( state ); + + initLaunchParams( state ); + + // + // Render loop + // + if( outfile.empty() ) + { + GLFWwindow* window = sutil::initUI( "optixCallablePrograms", state.params.width, state.params.height ); + glfwSetMouseButtonCallback( window, mouseButtonCallback ); + glfwSetCursorPosCallback( window, cursorPosCallback ); + glfwSetWindowSizeCallback( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback( window, keyCallback ); + glfwSetScrollCallback( window, scrollCallback ); + glfwSetWindowUserPointer( window, &state.params ); + + { + // output_buffer needs to be destroyed before cleanupUI is called + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, state.params.width, state.params.height ); + + output_buffer.setStream( state.stream ); + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + updateState( output_buffer, state ); + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + launchSubframe( output_buffer, state ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1 - t0; + + sutil::displayStats( state_update_time, render_time, display_time ); + + glfwSwapBuffers( window ); + + ++state.params.subframe_index; + } while( !glfwWindowShouldClose( window ) ); + } + sutil::cleanupUI( window ); + } + else + { + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + sutil::initGLFW(); // For GL context + sutil::initGL(); + } + + { + // this scope is for output_buffer, to ensure the destructor is called bfore glfwTerminate() + + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, state.params.width, state.params.height ); + + handleCameraUpdate( state ); + handleResize( output_buffer, state.params ); + handleShading( state ); + launchSubframe( output_buffer, state ); + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + glfwTerminate(); + } + } + + cleanupState( state ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCallablePrograms/optixCallablePrograms.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixCallablePrograms/optixCallablePrograms.cu new file mode 100644 index 00000000..9d553a26 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCallablePrograms/optixCallablePrograms.cu @@ -0,0 +1,143 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include + +#include "optixCallablePrograms.h" + +// Direct callables for shading +extern "C" __device__ float3 __direct_callable__phong_shade( float3 hit_point, float3 ray_dir, float3 normal ) +{ + float3 Ka = {0.2f, 0.5f, 0.5f}; + float3 Kd = {0.2f, 0.7f, 0.8f}; + float3 Ks = {0.9f, 0.9f, 0.9f}; + float phong_exp = 64.0f; + + float3 result = make_float3( 0.0f ); + + for( int i = 0; i < whitted::params.lights.count; ++i ) + { + Light light = whitted::params.lights[i]; + if( light.type == Light::Type::POINT ) + { + // compute direct lighting + float Ldist = length( light.point.position - hit_point ); + float3 L = normalize( light.point.position - hit_point ); + float nDl = dot( normal, L ); + + result += Kd * nDl * light.point.color; + + float3 H = normalize( L - ray_dir ); + float nDh = dot( normal, H ); + if( nDh > 0 ) + { + float power = pow( nDh, phong_exp ); + result += Ks * power * light.point.color; + } + } + else if( light.type == Light::Type::AMBIENT ) + { + // ambient contribution + result += Ka * light.ambient.color; + } + } + + return result; +} + +extern "C" __device__ float3 __direct_callable__checkered_shade( float3 hit_point, float3 ray_dir, float3 normal ) +{ + float3 result; + + float value = dot( normal, ray_dir ); + if( value < 0 ) + { + value *= -1; + } + + float3 sphere_normal = normalize( hit_point ); + float a = acos( sphere_normal.y ); + float b = atan2( sphere_normal.x, sphere_normal.z ) + M_PIf; + Light::Ambient light = whitted::params.lights[0].ambient; + if( ( fmod( a, M_PIf / 8 ) < M_PIf / 16 ) ^ ( fmod( b, M_PIf / 4 ) < M_PIf / 8 ) ) + { + result = light.color + ( value * make_float3( 0.0f ) ); + } + else + { + result = light.color + ( value * make_float3( 1.0f ) ); + } + + return clamp( result, 0.0f, 1.0f ); +} + +extern "C" __device__ float3 __direct_callable__normal_shade( float3 hit_point, float3 ray_dir, float3 normal ) +{ + return normalize( normal ) * 0.5f + 0.5f; +} + +// Closest hit +extern "C" __global__ void __closesthit__radiance() +{ + const CallableProgramsHitGroupData* hitgroup_data = + reinterpret_cast( optixGetSbtDataPointer() ); + + const float3 ray_orig = optixGetWorldRayOrigin(); + const float3 ray_dir = optixGetWorldRayDirection(); + const float ray_t = optixGetRayTmax(); + float3 hit_point = ray_orig + ray_t * ray_dir; + + float3 object_normal = make_float3( __uint_as_float( optixGetAttribute_0() ), __uint_as_float( optixGetAttribute_1() ), + __uint_as_float( optixGetAttribute_2() ) ); + float3 world_normal = normalize( optixTransformNormalFromObjectToWorldSpace( object_normal ) ); + float3 ffnormal = faceforward( world_normal, -ray_dir, world_normal ); + + // Use a direct callable to set the result + float3 result = optixDirectCall( hitgroup_data->dc_index, hit_point, ray_dir, ffnormal ); + whitted::setPayloadResult( result ); +} + +// Continuation callable for background +extern "C" __device__ float3 __continuation_callable__raydir_shade( float3 ray_dir ) +{ + return normalize( ray_dir ) * 0.5f + 0.5f; +} + +// Miss +extern "C" __global__ void __miss__raydir_shade() +{ + const float3 ray_dir = optixGetWorldRayDirection(); + + float3 result = optixContinuationCall( 0, ray_dir ); + whitted::setPayloadResult( result ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCallablePrograms/optixCallablePrograms.h b/Extern/3rdParty/OptiX/Linux/SDK/optixCallablePrograms/optixCallablePrograms.h new file mode 100644 index 00000000..caa45062 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCallablePrograms/optixCallablePrograms.h @@ -0,0 +1,44 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +struct EmptyData +{ +}; + +struct CallableProgramsHitGroupData : whitted::HitGroupData +{ + unsigned int dc_index; +}; + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCompileWithTasks/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixCompileWithTasks/CMakeLists.txt new file mode 100644 index 00000000..39add446 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCompileWithTasks/CMakeLists.txt @@ -0,0 +1,38 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixCompileWithTasks target_name + "${SAMPLES_DIR}/lib/CompileWithTasks.h" + optixCompileWithTasks.cpp + ) + +include_directories( "${SAMPLES_DIR}/lib" ) +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCompileWithTasks/optixCompileWithTasks.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixCompileWithTasks/optixCompileWithTasks.cpp new file mode 100644 index 00000000..0cbd0300 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCompileWithTasks/optixCompileWithTasks.cpp @@ -0,0 +1,337 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +using namespace optix::CompileWithTasks; + + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + +OptixDeviceContext s_context = 0; +OptixDeviceContextOptions s_options = {}; +OptixModuleCompileOptions s_moduleCompileOptions = {}; +OptixPipelineCompileOptions s_pipelineCompileOptions = {}; +unsigned int s_defaultLogLevel = 4; + +OptixTaskExecutePool g_pool; + + +static void SetUp() +{ + CUDA_CHECK( cudaFree( 0 ) ); + void* handle; + OPTIX_CHECK( optixInitWithHandle( &handle ) ); + + s_options.logCallbackFunction = &context_log_cb; + s_options.logCallbackLevel = s_defaultLogLevel; + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &s_options, &s_context ) ); +} + +static void SetLoggingLevel( unsigned int level ) +{ + OPTIX_CHECK( optixDeviceContextSetLogCallback( s_context, &context_log_cb, 0, level ) ); +} + +static void TearDown() +{ + OPTIX_CHECK( optixDeviceContextDestroy( s_context ) ); +} + +std::string readInputFile( const std::string& filename ) +{ + std::ifstream input( filename.c_str(), std::ios::binary ); + if( !input ) + { + std::cerr << "ERROR: Failed to open input file '" << filename << "'\n"; + exit( 1 ); + } + + std::vector buffer( std::istreambuf_iterator( input ), {} ); + return std::string( buffer.begin(), buffer.end() ); +} + +struct Timer +{ + Timer() { m_start = m_clock.now(); } + + double elapsed() const + { + std::chrono::duration e = m_clock.now() - m_start; + return e.count(); + } + + friend std::ostream& operator<<( std::ostream& out, const Timer& timer ) { return out << timer.elapsed(); } + std::chrono::high_resolution_clock m_clock; + std::chrono::high_resolution_clock::time_point m_start; +}; + +void compileModules( const std::vector& input, int numIters = 1 ) +{ + std::vector modules( input.size() ); + Timer overallTimer; + for( int i = 0; i < numIters; ++i ) + { + Timer iterTimer; + for( size_t idx = 0; idx < input.size(); ++idx ) + { + Timer iterTimer; + OPTIX_CHECK( optixModuleCreate( s_context, &s_moduleCompileOptions, &s_pipelineCompileOptions, + input[idx].c_str(), input[idx].size(), 0, 0, &modules[idx] ) ); + } + if( i == 0 ) + { + SetLoggingLevel( 0 ); + } + std::cout << "iter[" << i << "] duration = " << iterTimer << " seconds\n"; + } + double seconds = overallTimer.elapsed(); + SetLoggingLevel( s_defaultLogLevel ); + std::cout << "over all time " << seconds << " seconds, per iter average = " << seconds / numIters << "\n"; + std::cout << "Successfully compiled\n"; +} + +void compileModulesWithTasks( const std::vector& input, int numIters = 1 ) +{ + std::vector modules( input.size() ); + Timer overallTimer; + for( int i = 0; i < numIters; ++i ) + { + Timer iterTimer; + for( size_t idx = 0; idx < input.size(); ++idx ) + { + OptixTask initialTask; + OPTIX_CHECK( optixModuleCreateWithTasks( s_context, &s_moduleCompileOptions, &s_pipelineCompileOptions, + input[idx].c_str(), input[idx].size(), 0, 0, &modules[idx], &initialTask ) ); + g_pool.addTaskAndExecute( initialTask ); + } + OPTIX_CHECK( g_pool.waitForModuleTasks( modules ) ); + if( i == 0 ) + { + SetLoggingLevel( 0 ); + } + + std::cout << "iter[" << i << "] duration = " << iterTimer << " seconds\n"; + } + double seconds = overallTimer.elapsed(); + SetLoggingLevel( s_defaultLogLevel ); + std::cout << "over all time " << seconds << " seconds, per iter average = " << seconds / numIters << "\n"; + std::cout << "Successfully compiled\n"; +} + +void printUsageAndExit( const std::string& argv0, bool doExit = true ) +{ + // These provide a rudimentary set of options and are by no means exhaustive to the + // set of compile options available to optixModuleCreate. + std::cerr << "\nUsage : " << argv0 << " [options] \n" + << "App options:\n" + << " -h | --help Print this usage message\n" + << " -na | --num-attributes Number of attribute values (up to 8, default 2)\n" + << " -npv | --num-payload-values Number of payload values (up to " + << OPTIX_COMPILE_DEFAULT_MAX_PAYLOAD_VALUE_COUNT << ", default 2)\n" + << " -npt | --num-payload-types Number of payload types (up to " + << OPTIX_COMPILE_DEFAULT_MAX_PAYLOAD_TYPE_COUNT << ", default 1)\n" + << " -ni | --num-iters Number of iterations to compile. > 1 disables disk cache (default 1)\n" + << " -dt | --disable-tasks Disable compilation with tasks (default enabled)\n" + << " -dc | --disable-cache Disable caching of compiled ptx on disk (default enabled)\n" + << " -nt | --num-threads Number of threads (default 1)\n" + << " -mt | --max-num-tasks Maximum number of additional tasks (default 2)\n" + << " | --filenames A quote-enclosed, semicolon delimited list of PTX input files\n" + << " -g Enable debug support (implies -O0)\n" + << std::endl; + + if( doExit ) + exit( 1 ); +} + +int main( int argc, char** argv ) +{ + bool useTasks = true; + bool useCache = true; + int numThreads = 2; + int maxNumTasks = 2; + int numIters = 1; + std::vector filenames; + std::vector types; + std::vector defaultPayloadSemantics; + + if( argc < 2 ) + { + std::cerr << "\nERROR: No input file provided for compilation\n"; + printUsageAndExit( argv[0] ); + } + + for( int i = 1; i < argc; ++i ) + { + std::string arg( argv[i] ); + if( arg == "-h" || arg == "--help" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "-na" || arg == "--num-attributes" ) + { + if( i >= argc-1 ) + printUsageAndExit( argv[0] ); + s_pipelineCompileOptions.numAttributeValues = atoi( argv[++i] ); + } + else if( arg == "-npv" || arg == "--num-payload-values" ) + { + if( i >= argc-1 ) + printUsageAndExit( argv[0] ); + s_pipelineCompileOptions.numPayloadValues = atoi( argv[++i] ); + } + else if( arg == "-npt" || arg == "--num-payload-types" ) + { + if( i >= argc-1 ) + printUsageAndExit( argv[0] ); + int numTypes = atoi( argv[++i] ); + types.resize( numTypes, {} ); + defaultPayloadSemantics.resize( s_pipelineCompileOptions.numPayloadValues, 0 ); + for( unsigned int& payloadSemantic : defaultPayloadSemantics ) + { + payloadSemantic = OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ_WRITE + | OPTIX_PAYLOAD_SEMANTICS_CH_READ_WRITE | OPTIX_PAYLOAD_SEMANTICS_MS_READ_WRITE + | OPTIX_PAYLOAD_SEMANTICS_AH_READ_WRITE | OPTIX_PAYLOAD_SEMANTICS_IS_READ_WRITE; + } + for( OptixPayloadType& type : types ) + { + type.numPayloadValues = static_cast( defaultPayloadSemantics.size() ); + type.payloadSemantics = defaultPayloadSemantics.data(); + } + s_pipelineCompileOptions.numPayloadValues = 0; + s_moduleCompileOptions.numPayloadTypes = numTypes; + s_moduleCompileOptions.payloadTypes = types.data(); + } + else if( arg == "-ni" || arg == "--num-iters" ) + { + if( i >= argc-1 ) + printUsageAndExit( argv[0] ); + numIters = atoi( argv[++i] ); + } + else if( arg == "-dt" || arg == "--disable-tasks" ) + { + useTasks = false; + } + else if( arg == "-dc" || arg == "--disable-cache" ) + { + useCache = false; + } + else if( arg == "-nt" || arg == "--num-threads" ) + { + if( i >= argc-1 ) + printUsageAndExit( argv[0] ); + numThreads = atoi( argv[++i] ); + } + else if( arg == "-mt" || arg == "--max-num-tasks" ) + { + if( i >= argc-1 ) + printUsageAndExit( argv[0] ); + maxNumTasks = atoi( argv[++i] ); + } + else if( arg == "-g" ) + { + s_moduleCompileOptions.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + s_moduleCompileOptions.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; + } + else if( arg == "--filenames" ) + { + if( i >= argc-1 ) + printUsageAndExit( argv[0] ); + + // Tokenize the filename list into a vector of std::strings + std::string namesArg = argv[++i]; + std::stringstream namesStream( namesArg ); + std::string filename; + while( std::getline( namesStream, filename, ';' ) ) + filenames.push_back( filename ); + } + else + { + if( !filenames.empty() ) + { + std::cerr << "Only one filename is supported as a positional argument. "; + std::cerr << "Found additional filename: " << arg << ". "; + std::cerr << "Already found " << filenames.size() << " " << (filenames.size() > 1 ? "filenames" : "filename") << ".\n"; + printUsageAndExit( argv[0] ); + } + filenames.push_back( arg ); + } + } + + SetUp(); + if( numIters > 1 || !useCache ) + optixDeviceContextSetCacheEnabled( s_context, 0 ); + + std::vector input; + for( const std::string& filename : filenames ) + { + std::string ptx = readInputFile( filename ); + input.push_back( ptx ); + } + + if( useTasks ) + { + std::cout << "Running with " << numThreads << " threads and " << maxNumTasks << " maximum number of tasks\n"; + g_pool.m_threadPool.startPool( numThreads ); + g_pool.m_maxNumAdditionalTasks = maxNumTasks; + compileModulesWithTasks( input, numIters ); + g_pool.m_threadPool.terminate(); + } + else + { + compileModules( input, numIters ); + } + + TearDown(); + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/CMakeLists.txt new file mode 100644 index 00000000..8964b0fb --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/CMakeLists.txt @@ -0,0 +1,36 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2022 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixConsole target_name + optixConsole.cpp + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/optixConsole.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/optixConsole.cpp new file mode 100644 index 00000000..15809496 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/optixConsole.cpp @@ -0,0 +1,818 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2022 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#ifdef min +#undef min +#endif +#ifdef max +#undef max +#endif +#include + +#include + +#include +#include +#ifndef OPTIX_CONSOLE_PROJECT +#include +#endif + +#include +#include +#include + + +// Globals +const int max_trace = 12; + +// Local types +typedef sutil::Record HitGroupRecord; + +const uint32_t OBJ_COUNT = 3; + +struct OptixConsoleState +{ + OptixDeviceContext context = 0; + OptixTraversableHandle gas_handle = {}; + CUdeviceptr d_gas_output_buffer = {}; + + OptixModule geometry_module = 0; + OptixModule camera_module = 0; + OptixModule shading_module = 0; + OptixModule sphere_module = 0; + + OptixProgramGroup raygen_prog_group = 0; + OptixProgramGroup radiance_miss_prog_group = 0; + OptixProgramGroup occlusion_miss_prog_group = 0; + OptixProgramGroup radiance_glass_sphere_prog_group = 0; + OptixProgramGroup occlusion_glass_sphere_prog_group = 0; + OptixProgramGroup radiance_metal_sphere_prog_group = 0; + OptixProgramGroup occlusion_metal_sphere_prog_group = 0; + OptixProgramGroup radiance_floor_prog_group = 0; + OptixProgramGroup occlusion_floor_prog_group = 0; + + OptixPipeline pipeline = 0; + OptixPipelineCompileOptions pipeline_compile_options = {}; + + CUstream stream = 0; + whitted::LaunchParams params; + whitted::LaunchParams* d_params = nullptr; + + OptixShaderBindingTable sbt = {}; +}; + +// Metal sphere, glass sphere, floor +const GeometryData::Sphere g_sphere = { + { 2.0f, 1.5f, -2.5f }, // center + 1.0f // radius +}; +const GeometryData::SphereShell g_sphere_shell = { + { 4.0f, 2.3f, -4.0f }, // center + 0.96f, // radius1 + 1.0f // radius2 +}; +const GeometryData::Parallelogram g_floor( make_float3( 32.0f, 0.0f, 0.0f ), // v1 + make_float3( 0.0f, 0.0f, 16.0f ), // v2 + make_float3( -16.0f, 0.01f, -8.0f ) // anchor +); + +// Helper functions +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --help | -h Print this usage message\n"; + exit( 0 ); +} + +void initLaunchParams( OptixConsoleState& state ) +{ + state.params.width = 48u * 2u; + state.params.height = 32u * 2u; + + state.params.eye = make_float3( 8.0f, 2.0f, -4.0f ); + state.params.U = make_float3( 0.0f, 0.0f, -2.315887f ); + state.params.V = make_float3( 0.173205f, 2.309401f, 0.0f ); + state.params.W = make_float3( -4.0f, 0.3f, 0.0f ); + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.params.accum_buffer ), + state.params.width * state.params.height * sizeof( float4 ) ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.params.frame_buffer ), + state.params.width * state.params.height * sizeof( uchar4 ) ) ); + + state.params.subframe_index = 0u; + + // Set ambient light color and point light position + std::vector lights( 2 ); + lights[0].type = Light::Type::AMBIENT; + lights[0].ambient.color = make_float3( 0.4f, 0.4f, 0.4f ); + lights[1].type = Light::Type::POINT; + lights[1].point.color = make_float3( 1.0f, 1.0f, 1.0f ); + lights[1].point.intensity = 1.0f; + lights[1].point.position = make_float3( 60.0f, 40.0f, 0.0f ); + lights[1].point.falloff = Light::Falloff::QUADRATIC; + + state.params.lights.count = static_cast( lights.size() ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.params.lights.data ), lights.size() * sizeof( Light ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( state.params.lights.data ), lights.data(), + lights.size() * sizeof( Light ), cudaMemcpyHostToDevice ) ); + state.params.miss_color = { 0.34f, 0.55f, 0.85f }; + + state.params.max_depth = max_trace; + state.params.scene_epsilon = 1.e-4f; + + CUDA_CHECK( cudaStreamCreate( &state.stream ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_params ), sizeof( whitted::LaunchParams ) ) ); + + state.params.handle = state.gas_handle; +} + +inline OptixAabb sphere_bound( float3 center, float radius ) +{ + float3 m_min = center - radius; + float3 m_max = center + radius; + + return { m_min.x, m_min.y, m_min.z, m_max.x, m_max.y, m_max.z }; +} + +inline OptixAabb parallelogram_bound( float3 v1, float3 v2, float3 anchor ) +{ + // v1 and v2 are scaled by 1./length^2. Rescale back to normal for the bounds computation. + const float3 tv1 = v1 / dot( v1, v1 ); + const float3 tv2 = v2 / dot( v2, v2 ); + const float3 p00 = anchor; + const float3 p01 = anchor + tv1; + const float3 p10 = anchor + tv2; + const float3 p11 = anchor + tv1 + tv2; + + float3 m_min = fminf( fminf( p00, p01 ), fminf( p10, p11 ) ); + float3 m_max = fmaxf( fmaxf( p00, p01 ), fmaxf( p10, p11 ) ); + return { m_min.x, m_min.y, m_min.z, m_max.x, m_max.y, m_max.z }; +} + +static void buildGas( const OptixConsoleState& state, + const OptixAccelBuildOptions& accel_options, + const OptixBuildInput& build_input, + OptixTraversableHandle& gas_handle, + CUdeviceptr& d_gas_output_buffer ) +{ + OptixAccelBufferSizes gas_buffer_sizes; + CUdeviceptr d_temp_buffer_gas; + + OPTIX_CHECK( optixAccelComputeMemoryUsage( state.context, &accel_options, &build_input, 1, &gas_buffer_sizes ) ); + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer_gas ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output and size of compacted GAS + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = ( ( gas_buffer_sizes.outputSizeInBytes + 8ull - 1 ) / 8ull ) * 8ull; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), compactedSizeOffset + 8 ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = (CUdeviceptr)( (char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( state.context, 0, &accel_options, &build_input, 1, d_temp_buffer_gas, + gas_buffer_sizes.tempSizeInBytes, d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, &gas_handle, &emitProperty, 1 ) ); + + CUDA_CHECK( cudaFree( (void*)d_temp_buffer_gas ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, (void*)emitProperty.result, sizeof( size_t ), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, 0, gas_handle, d_gas_output_buffer, compacted_gas_size, &gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + d_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } +} + +void createGeometry( OptixConsoleState& state ) +{ + // Load AABB into device memory + OptixAabb aabb[OBJ_COUNT] = { sphere_bound( g_sphere.center, g_sphere.radius ), + sphere_bound( g_sphere_shell.center, g_sphere_shell.radius2 ), + parallelogram_bound( g_floor.v1, g_floor.v2, g_floor.anchor ) }; + CUdeviceptr d_aabb; + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_aabb ), OBJ_COUNT * sizeof( OptixAabb ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_aabb ), &aabb, OBJ_COUNT * sizeof( OptixAabb ), cudaMemcpyHostToDevice ) ); + + // Setup AABB build input + uint32_t aabb_input_flags[] = { + /* flags for metal sphere */ + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + /* flag for glass sphere */ + OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL, + /* flag for floor */ + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + }; + /* TODO: This API cannot control flags for different ray type */ + + const uint32_t sbt_index[] = { 0, 1, 2 }; + CUdeviceptr d_sbt_index; + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_sbt_index ), sizeof( sbt_index ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_sbt_index ), sbt_index, sizeof( sbt_index ), cudaMemcpyHostToDevice ) ); + + OptixBuildInput aabb_input = {}; + aabb_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES; + aabb_input.customPrimitiveArray.aabbBuffers = &d_aabb; + aabb_input.customPrimitiveArray.flags = aabb_input_flags; + aabb_input.customPrimitiveArray.numSbtRecords = OBJ_COUNT; + aabb_input.customPrimitiveArray.numPrimitives = OBJ_COUNT; + aabb_input.customPrimitiveArray.sbtIndexOffsetBuffer = d_sbt_index; + aabb_input.customPrimitiveArray.sbtIndexOffsetSizeInBytes = sizeof( uint32_t ); + aabb_input.customPrimitiveArray.primitiveIndexOffset = 0; + + OptixAccelBuildOptions accel_options = { + OPTIX_BUILD_FLAG_ALLOW_COMPACTION, // buildFlags + OPTIX_BUILD_OPERATION_BUILD // operation + }; + + buildGas( state, accel_options, aabb_input, state.gas_handle, state.d_gas_output_buffer ); + + CUDA_CHECK( cudaFree( (void*)d_aabb ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_sbt_index ) ) ); +} + +std::string readFile( const std::string& filename ) +{ + std::string contents; + std::ifstream file( filename, std::ios::binary ); + if( file.good() ) + { + std::vector buffer = std::vector( std::istreambuf_iterator( file ), {} ); + contents.assign( buffer.begin(), buffer.end() ); + } + else + { + std::cerr << "Error opening " << filename << ": " << strerror( errno ) << "\n"; + } + return contents; +} + +void createModules( OptixConsoleState& state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + +#ifdef OPTIX_CONSOLE_PROJECT + std::string geometry_ir = readFile( CUDA_INT_DIR "/geometry.cu.optixir" ); + const char* geometry_input = geometry_ir.c_str(); + size_t geometry_input_size = geometry_ir.size(); + + std::string camera_ir = readFile( CUDA_INT_DIR "/camera.cu.optixir" ); + const char* camera_input = camera_ir.c_str(); + size_t camera_input_size = camera_ir.size(); + + std::string shading_ir = readFile( CUDA_INT_DIR "/shading.cu.optixir" ); + const char* shading_input = shading_ir.c_str(); + size_t shading_input_size = shading_ir.size(); + + std::string sphere_ir = readFile( CUDA_INT_DIR "/sphere.cu.optixir" ); + const char* sphere_input = sphere_ir.c_str(); + size_t sphere_input_size = sphere_ir.size(); +#else + size_t geometry_input_size = 0; + const char* geometry_input = sutil::getInputData( nullptr, nullptr, "geometry.cu", geometry_input_size ); + + size_t camera_input_size = 0; + const char* camera_input = sutil::getInputData( nullptr, nullptr, "camera.cu", camera_input_size ); + + size_t shading_input_size = 0; + const char* shading_input = sutil::getInputData( nullptr, nullptr, "shading.cu", shading_input_size ); + + size_t sphere_input_size = 0; + const char* sphere_input = sutil::getInputData( nullptr, nullptr, "sphere.cu", sphere_input_size ); +#endif + + OPTIX_CHECK_LOG( optixModuleCreate( state.context, &module_compile_options, &state.pipeline_compile_options, + geometry_input, geometry_input_size, LOG, &LOG_SIZE, &state.geometry_module ) ); + OPTIX_CHECK_LOG( optixModuleCreate( state.context, &module_compile_options, &state.pipeline_compile_options, + camera_input, camera_input_size, LOG, &LOG_SIZE, &state.camera_module ) ); + OPTIX_CHECK_LOG( optixModuleCreate( state.context, &module_compile_options, &state.pipeline_compile_options, + shading_input, shading_input_size, LOG, &LOG_SIZE, &state.shading_module ) ); + OPTIX_CHECK_LOG( optixModuleCreate( state.context, &module_compile_options, &state.pipeline_compile_options, + sphere_input, sphere_input_size, LOG, &LOG_SIZE, &state.sphere_module ) ); +} + +static void createCameraProgram( OptixConsoleState& state, std::vector& program_groups ) +{ + OptixProgramGroup cam_prog_group; + OptixProgramGroupOptions cam_prog_group_options = {}; + OptixProgramGroupDesc cam_prog_group_desc = {}; + cam_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + cam_prog_group_desc.raygen.module = state.camera_module; + cam_prog_group_desc.raygen.entryFunctionName = "__raygen__pinhole_camera"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &cam_prog_group_desc, 1, &cam_prog_group_options, LOG, + &LOG_SIZE, &cam_prog_group ) ); + + program_groups.push_back( cam_prog_group ); + state.raygen_prog_group = cam_prog_group; +} + +static void createGlassSphereProgram( OptixConsoleState& state, std::vector& program_groups ) +{ + OptixProgramGroup radiance_sphere_prog_group; + OptixProgramGroupOptions radiance_sphere_prog_group_options = {}; + OptixProgramGroupDesc radiance_sphere_prog_group_desc = {}; + radiance_sphere_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + radiance_sphere_prog_group_desc.hitgroup.moduleIS = state.geometry_module; + radiance_sphere_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__sphere_shell"; + radiance_sphere_prog_group_desc.hitgroup.moduleCH = state.shading_module; + radiance_sphere_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__glass_radiance"; + radiance_sphere_prog_group_desc.hitgroup.moduleAH = nullptr; + radiance_sphere_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &radiance_sphere_prog_group_desc, 1, &radiance_sphere_prog_group_options, + LOG, &LOG_SIZE, &radiance_sphere_prog_group ) ); + + program_groups.push_back( radiance_sphere_prog_group ); + state.radiance_glass_sphere_prog_group = radiance_sphere_prog_group; + + OptixProgramGroup occlusion_sphere_prog_group; + OptixProgramGroupOptions occlusion_sphere_prog_group_options = {}; + OptixProgramGroupDesc occlusion_sphere_prog_group_desc = {}; + occlusion_sphere_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + occlusion_sphere_prog_group_desc.hitgroup.moduleIS = state.geometry_module; + occlusion_sphere_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__sphere_shell"; + occlusion_sphere_prog_group_desc.hitgroup.moduleCH = nullptr; + occlusion_sphere_prog_group_desc.hitgroup.entryFunctionNameCH = nullptr; + occlusion_sphere_prog_group_desc.hitgroup.moduleAH = state.shading_module; + occlusion_sphere_prog_group_desc.hitgroup.entryFunctionNameAH = "__anyhit__glass_occlusion"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &occlusion_sphere_prog_group_desc, 1, &occlusion_sphere_prog_group_options, + LOG, &LOG_SIZE, &occlusion_sphere_prog_group ) ); + + program_groups.push_back( occlusion_sphere_prog_group ); + state.occlusion_glass_sphere_prog_group = occlusion_sphere_prog_group; +} + +static void createMetalSphereProgram( OptixConsoleState& state, std::vector& program_groups ) +{ + OptixProgramGroup radiance_sphere_prog_group; + OptixProgramGroupOptions radiance_sphere_prog_group_options = {}; + OptixProgramGroupDesc radiance_sphere_prog_group_desc = {}; + radiance_sphere_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP, + radiance_sphere_prog_group_desc.hitgroup.moduleIS = state.sphere_module; + radiance_sphere_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__sphere"; + radiance_sphere_prog_group_desc.hitgroup.moduleCH = state.shading_module; + radiance_sphere_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__metal_radiance"; + radiance_sphere_prog_group_desc.hitgroup.moduleAH = nullptr; + radiance_sphere_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &radiance_sphere_prog_group_desc, 1, &radiance_sphere_prog_group_options, + LOG, &LOG_SIZE, &radiance_sphere_prog_group ) ); + + program_groups.push_back( radiance_sphere_prog_group ); + state.radiance_metal_sphere_prog_group = radiance_sphere_prog_group; + + OptixProgramGroup occlusion_sphere_prog_group; + OptixProgramGroupOptions occlusion_sphere_prog_group_options = {}; + OptixProgramGroupDesc occlusion_sphere_prog_group_desc = {}; + occlusion_sphere_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP, + occlusion_sphere_prog_group_desc.hitgroup.moduleIS = state.sphere_module; + occlusion_sphere_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__sphere"; + occlusion_sphere_prog_group_desc.hitgroup.moduleCH = state.shading_module; + occlusion_sphere_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__full_occlusion"; + occlusion_sphere_prog_group_desc.hitgroup.moduleAH = nullptr; + occlusion_sphere_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &occlusion_sphere_prog_group_desc, 1, &occlusion_sphere_prog_group_options, + LOG, &LOG_SIZE, &occlusion_sphere_prog_group ) ); + + program_groups.push_back( occlusion_sphere_prog_group ); + state.occlusion_metal_sphere_prog_group = occlusion_sphere_prog_group; +} + +static void createFloorProgram( OptixConsoleState& state, std::vector& program_groups ) +{ + OptixProgramGroup radiance_floor_prog_group; + OptixProgramGroupOptions radiance_floor_prog_group_options = {}; + OptixProgramGroupDesc radiance_floor_prog_group_desc = {}; + radiance_floor_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + radiance_floor_prog_group_desc.hitgroup.moduleIS = state.geometry_module; + radiance_floor_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__parallelogram"; + radiance_floor_prog_group_desc.hitgroup.moduleCH = state.shading_module; + radiance_floor_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__checker_radiance"; + radiance_floor_prog_group_desc.hitgroup.moduleAH = nullptr; + radiance_floor_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &radiance_floor_prog_group_desc, 1, &radiance_floor_prog_group_options, + LOG, &LOG_SIZE, &radiance_floor_prog_group ) ); + + program_groups.push_back( radiance_floor_prog_group ); + state.radiance_floor_prog_group = radiance_floor_prog_group; + + OptixProgramGroup occlusion_floor_prog_group; + OptixProgramGroupOptions occlusion_floor_prog_group_options = {}; + OptixProgramGroupDesc occlusion_floor_prog_group_desc = {}; + occlusion_floor_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + occlusion_floor_prog_group_desc.hitgroup.moduleIS = state.geometry_module; + occlusion_floor_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__parallelogram"; + occlusion_floor_prog_group_desc.hitgroup.moduleCH = state.shading_module; + occlusion_floor_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__full_occlusion"; + occlusion_floor_prog_group_desc.hitgroup.moduleAH = nullptr; + occlusion_floor_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &occlusion_floor_prog_group_desc, 1, &occlusion_floor_prog_group_options, + LOG, &LOG_SIZE, &occlusion_floor_prog_group ) ); + + program_groups.push_back( occlusion_floor_prog_group ); + state.occlusion_floor_prog_group = occlusion_floor_prog_group; +} + +static void createMissProgram( OptixConsoleState& state, std::vector& program_groups ) +{ + OptixProgramGroupOptions miss_prog_group_options = {}; + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.shading_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__constant_bg"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &miss_prog_group_desc, 1, &miss_prog_group_options, LOG, + &LOG_SIZE, &state.radiance_miss_prog_group ) ); + + program_groups.push_back( state.radiance_miss_prog_group ); + + miss_prog_group_desc.miss = { + nullptr, // module + nullptr // entryFunctionName + }; + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &miss_prog_group_desc, 1, &miss_prog_group_options, LOG, + &LOG_SIZE, &state.occlusion_miss_prog_group ) ); + + program_groups.push_back( state.occlusion_miss_prog_group ); +} + +void createPipeline( OptixConsoleState& state ) +{ + std::vector program_groups; + + state.pipeline_compile_options = { + false, // usesMotionBlur + OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS, // traversableGraphFlags + 5, + /* RadiancePRD uses 5 payloads */ // numPayloadValues + 5, + /* Parallelogram intersection uses 5 attrs */ // numAttributeValues + OPTIX_EXCEPTION_FLAG_NONE, // exceptionFlags + "params" // pipelineLaunchParamsVariableName + }; + + // Prepare program groups + createModules( state ); + createCameraProgram( state, program_groups ); + createGlassSphereProgram( state, program_groups ); + createMetalSphereProgram( state, program_groups ); + createFloorProgram( state, program_groups ); + createMissProgram( state, program_groups ); + + // Link program groups to pipeline + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace; + OPTIX_CHECK_LOG( optixPipelineCreate( state.context, &state.pipeline_compile_options, &pipeline_link_options, + program_groups.data(), static_cast( program_groups.size() ), + LOG, &LOG_SIZE, &state.pipeline ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, state.pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace, + 0, // maxCCDepth + 0, // maxDCDepth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( state.pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + ) ); +} + +void createSBT( OptixConsoleState& state ) +{ + // Raygen program record + { + CUdeviceptr d_raygen_record; + size_t sizeof_raygen_record = sizeof( sutil::EmptyRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_raygen_record ), sizeof_raygen_record ) ); + + sutil::EmptyRecord rg_sbt; + optixSbtRecordPackHeader( state.raygen_prog_group, &rg_sbt ); + + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_raygen_record ), &rg_sbt, sizeof_raygen_record, cudaMemcpyHostToDevice ) ); + + state.sbt.raygenRecord = d_raygen_record; + } + + // Miss program record + { + CUdeviceptr d_miss_record; + size_t sizeof_miss_record = sizeof( sutil::EmptyRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_miss_record ), sizeof_miss_record * whitted::RAY_TYPE_COUNT ) ); + + sutil::EmptyRecord ms_sbt[whitted::RAY_TYPE_COUNT]; + optixSbtRecordPackHeader( state.radiance_miss_prog_group, &ms_sbt[0] ); + optixSbtRecordPackHeader( state.occlusion_miss_prog_group, &ms_sbt[1] ); + + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_miss_record ), ms_sbt, + sizeof_miss_record * whitted::RAY_TYPE_COUNT, cudaMemcpyHostToDevice ) ); + + state.sbt.missRecordBase = d_miss_record; + state.sbt.missRecordCount = whitted::RAY_TYPE_COUNT; + state.sbt.missRecordStrideInBytes = static_cast( sizeof_miss_record ); + } + + // Hitgroup program record + { + const size_t count_records = whitted::RAY_TYPE_COUNT * OBJ_COUNT; + HitGroupRecord hitgroup_records[count_records]; + + // Note: Fill SBT record array the same order like AS is built. + int sbt_idx = 0; + + // Metal Sphere + OPTIX_CHECK( optixSbtRecordPackHeader( state.radiance_metal_sphere_prog_group, &hitgroup_records[sbt_idx] ) ); + hitgroup_records[sbt_idx].data.geometry_data.setSphere( g_sphere ); + hitgroup_records[sbt_idx].data.material_data.metal = { + { 0.2f, 0.5f, 0.5f }, // Ka + { 0.2f, 0.7f, 0.8f }, // Kd + { 0.9f, 0.9f, 0.9f }, // Ks + { 0.5f, 0.5f, 0.5f }, // Kr + 64, // phong_exp + }; + sbt_idx++; + + OPTIX_CHECK( optixSbtRecordPackHeader( state.occlusion_metal_sphere_prog_group, &hitgroup_records[sbt_idx] ) ); + hitgroup_records[sbt_idx].data.geometry_data.setSphere( g_sphere ); + sbt_idx++; + + // Glass Sphere + OPTIX_CHECK( optixSbtRecordPackHeader( state.radiance_glass_sphere_prog_group, &hitgroup_records[sbt_idx] ) ); + hitgroup_records[sbt_idx].data.geometry_data.setSphereShell( g_sphere_shell ); + hitgroup_records[sbt_idx].data.material_data.glass = { + 1e-2f, // importance_cutoff + { 0.034f, 0.055f, 0.085f }, // cutoff_color + 3.0f, // fresnel_exponent + 0.1f, // fresnel_minimum + 1.0f, // fresnel_maximum + 1.4f, // refraction_index + { 1.0f, 1.0f, 1.0f }, // refraction_color + { 1.0f, 1.0f, 1.0f }, // reflection_color + { logf( .83f ), logf( .83f ), logf( .83f ) }, // extinction_constant + { 0.6f, 0.6f, 0.6f }, // shadow_attenuation + 10, // refraction_maxdepth + 5 // reflection_maxdepth + }; + sbt_idx++; + + OPTIX_CHECK( optixSbtRecordPackHeader( state.occlusion_glass_sphere_prog_group, &hitgroup_records[sbt_idx] ) ); + hitgroup_records[sbt_idx].data.geometry_data.setSphereShell( g_sphere_shell ); + hitgroup_records[sbt_idx].data.material_data.glass.shadow_attenuation = { 0.6f, 0.6f, 0.6f }; + sbt_idx++; + + // Floor + OPTIX_CHECK( optixSbtRecordPackHeader( state.radiance_floor_prog_group, &hitgroup_records[sbt_idx] ) ); + hitgroup_records[sbt_idx].data.geometry_data.setParallelogram( g_floor ); + hitgroup_records[sbt_idx].data.material_data.checker = { + { 0.8f, 0.3f, 0.15f }, // Kd1 + { 0.9f, 0.85f, 0.05f }, // Kd2 + { 0.8f, 0.3f, 0.15f }, // Ka1 + { 0.9f, 0.85f, 0.05f }, // Ka2 + { 0.0f, 0.0f, 0.0f }, // Ks1 + { 0.0f, 0.0f, 0.0f }, // Ks2 + { 0.0f, 0.0f, 0.0f }, // Kr1 + { 0.0f, 0.0f, 0.0f }, // Kr2 + 0.0f, // phong_exp1 + 0.0f, // phong_exp2 + { 32.0f, 16.0f } // inv_checker_size + }; + sbt_idx++; + + OPTIX_CHECK( optixSbtRecordPackHeader( state.occlusion_floor_prog_group, &hitgroup_records[sbt_idx] ) ); + hitgroup_records[sbt_idx].data.geometry_data.setParallelogram( g_floor ); + + CUdeviceptr d_hitgroup_records; + size_t sizeof_hitgroup_record = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_hitgroup_records ), sizeof_hitgroup_record * count_records ) ); + + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_hitgroup_records ), hitgroup_records, + sizeof_hitgroup_record * count_records, cudaMemcpyHostToDevice ) ); + + state.sbt.hitgroupRecordBase = d_hitgroup_records; + state.sbt.hitgroupRecordCount = count_records; + state.sbt.hitgroupRecordStrideInBytes = static_cast( sizeof_hitgroup_record ); + } +} + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n"; +} + +void createContext( OptixConsoleState& state ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + + state.context = context; +} + +void launchSubframe( OptixConsoleState& state ) +{ + // Launch + CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast( state.d_params ), &state.params, + sizeof( whitted::LaunchParams ), cudaMemcpyHostToDevice, state.stream ) ); + + OPTIX_CHECK( optixLaunch( state.pipeline, state.stream, reinterpret_cast( state.d_params ), + sizeof( whitted::LaunchParams ), &state.sbt, + state.params.width, // launch width + state.params.height, // launch height + 1 // launch depth + ) ); + CUDA_SYNC_CHECK(); +} + +void displaySubframe( OptixConsoleState& state, std::ostream& output_stream ) +{ + unsigned int width = state.params.width; + unsigned int height = state.params.height; + + std::vector output_buffer( width * height ); + CUDA_CHECK( cudaMemcpy( output_buffer.data(), state.params.frame_buffer, width * height * sizeof( uchar4 ), cudaMemcpyDeviceToHost ) ); + + float minLum = std::numeric_limits::infinity(); + float maxLum = 0; + std::vector lums( width * height ); + for( unsigned int y = 0; y < height; ++y ) + { + uchar4* row = output_buffer.data() + ( ( height - y - 1 ) * width ); + for( unsigned int x = 0; x < width; ++x ) + { + uchar4 ucolor = row[x]; + float3 color = + make_float3( static_cast( ucolor.x ), static_cast( ucolor.y ), static_cast( ucolor.z ) ) + / make_float3( 256.0f ); + float lum = color.x * 0.3f + color.y * 0.6f + color.z * 0.1f; + minLum = std::min( minLum, lum ); + maxLum = std::max( maxLum, lum ); + + lums[y * width + x] = lum; + } + } + + std::ostringstream out; + char lumchar[] = { ' ', '.', ',', ';', '!', 'o', '&', '8', '#', '@' }; + for( unsigned int y = 0; y < height; ++y ) + { + for( unsigned int x = 0; x < width; ++x ) + { + float normalized = ( lums[y * width + x] - minLum ) / ( maxLum - minLum ); + out << lumchar[static_cast( normalized * 9 )]; + } + out << "\n"; + } + output_stream << out.str(); +} + +void cleanupState( OptixConsoleState& state ) +{ + OPTIX_CHECK( optixPipelineDestroy( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_metal_sphere_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.occlusion_metal_sphere_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_glass_sphere_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.occlusion_glass_sphere_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_miss_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_floor_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.occlusion_floor_prog_group ) ); + OPTIX_CHECK( optixModuleDestroy( state.shading_module ) ); + OPTIX_CHECK( optixModuleDestroy( state.geometry_module ) ); + OPTIX_CHECK( optixModuleDestroy( state.camera_module ) ); + OPTIX_CHECK( optixModuleDestroy( state.sphere_module ) ); + OPTIX_CHECK( optixDeviceContextDestroy( state.context ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.accum_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.frame_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.lights.data ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_params ) ) ); +} + +int main( int argc, char* argv[] ) +{ + OptixConsoleState state; + + // Parse command line options + std::ostream* out_stream = &std::cout; + std::ofstream file_stream; + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + file_stream.open( argv[++i], std::ofstream::out ); + out_stream = &file_stream; + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + // Set up OptiX state + createContext( state ); + createGeometry( state ); + createPipeline( state ); + createSBT( state ); + + // Render and display + initLaunchParams( state ); + launchSubframe( state ); + displaySubframe( state, *out_stream ); + + // Cleanup + cleanupState( state ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/optixConsole.sln b/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/optixConsole.sln new file mode 100644 index 00000000..fc3da4b8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/optixConsole.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31321.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "optixConsole", "optixConsole.vcxproj", "{175DC310-3361-4D66-96BB-71C0742E827E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {175DC310-3361-4D66-96BB-71C0742E827E}.Debug|x64.ActiveCfg = Debug|x64 + {175DC310-3361-4D66-96BB-71C0742E827E}.Debug|x64.Build.0 = Debug|x64 + {175DC310-3361-4D66-96BB-71C0742E827E}.Release|x64.ActiveCfg = Release|x64 + {175DC310-3361-4D66-96BB-71C0742E827E}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6BC1DECF-7A0D-48B2-B2E8-4ABFCBFB6926} + EndGlobalSection +EndGlobal diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/optixConsole.vcxproj b/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/optixConsole.vcxproj new file mode 100644 index 00000000..d4160f38 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/optixConsole.vcxproj @@ -0,0 +1,106 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {175DC310-3361-4D66-96BB-71C0742E827E} + optixConsole + + + + Application + true + MultiByte + v142 + + + Application + false + true + MultiByte + v142 + + + + + + + + + + + + + + true + + + + Level3 + Disabled + WIN32;WIN64;_DEBUG;_CONSOLE;OPTIX_OPTIONAL_FEATURE_EXTERNAL_BUILD=1;OPTIX_CONSOLE_PROJECT=1;CUDA_INT_DIR=R"($(CudaIntDirFullPath))";%(PreprocessorDefinitions) + %(ProjectDir)..\;%(ProjectDir)..\support\;%(ProjectDir)..\..\include\;%(AdditionalIncludeDirectories) + + + true + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + 64 + $(CudaIntDirFullPath)\%(Filename)%(Extension).optixir + optix-ir + %(ProjectDir)..\;%(ProjectDir)..\support\;%(ProjectDir)..\..\include\;%(Include) + true + + + false + + + + + Level3 + MaxSpeed + true + true + WIN32;WIN64;NDEBUG;_CONSOLE;OPTIX_OPTIONAL_FEATURE_EXTERNAL_BUILD=1;OPTIX_CONSOLE_PROJECT=1;CUDA_INT_DIR=R"($(CudaIntDirFullPath))";%(PreprocessorDefinitions) + %(ProjectDir)..\;%(ProjectDir)..\support\;%(ProjectDir)..\..\include\;%(AdditionalIncludeDirectories) + + + true + true + true + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + 64 + $(CudaIntDirFullPath)\%(Filename)%(Extension).optixir + %(ProjectDir)..\;%(ProjectDir)..\support\;%(ProjectDir)..\..\include\;%(Include) + optix-ir + true + + + false + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/sampleConfig.h b/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/sampleConfig.h new file mode 100644 index 00000000..61454efe --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixConsole/sampleConfig.h @@ -0,0 +1,54 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2022 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +// Include directories +#define SAMPLES_RELATIVE_INCLUDE_DIRS \ + "cuda", \ + "sutil", \ + ".", + +// Signal whether to use NVRTC or not +#define CUDA_NVRTC_ENABLED 0 + +// NVRTC compiler options +#define CUDA_NVRTC_OPTIONS \ + "-std=c++11", \ + "-arch", \ + "compute_50", \ + "-use_fast_math", \ + "-lineinfo", \ + "-default-device", \ + "-rdc", \ + "true", \ + "-D__x86_64", \ + "-DOPTIX_OPTIONAL_FEATURE_OPTIX7", diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCurves/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixCurves/CMakeLists.txt new file mode 100644 index 00000000..55c258b5 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCurves/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixCurves target_name + optixCurves.cpp + optixCurves.h + optixCurves.cu + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCurves/optixCurves.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixCurves/optixCurves.cpp new file mode 100644 index 00000000..0d73ec4a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCurves/optixCurves.cpp @@ -0,0 +1,699 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include "optixCurves.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + + +template +struct SbtRecord +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef SbtRecord RayGenSbtRecord; +typedef SbtRecord MissSbtRecord; +typedef SbtRecord HitGroupSbtRecord; + +enum BasisType +{ + BSPLINE, + BEZIER, + CATROM +}; + +void configureCamera( sutil::Camera& cam, const uint32_t width, const uint32_t height, int degree ) +{ + if( degree < 3) + { + cam.setEye( {0.0f, 0.0f, 2.0f} ); + cam.setLookat( {0.0f, 0.0f, 0.0f} ); + } + else + { + cam.setEye( {0.0f, 0.0f, 3.0f} ); + cam.setLookat( {0.0f, -0.3f, 0.0f} ); + } + cam.setUp( {0.0f, 1.0f, 3.0f} ); + cam.setFovY( 45.0f ); + cam.setAspectRatio( (float)width / (float)height ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n"; +} + + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f Specify file for image output\n"; + std::cerr << " --help | -h Print this usage message\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 512x384\n"; + std::cerr << " --ribbon Render quadratic Bsplines as oriented flat ribbons.\n"; + std::cerr << " Either deriving the orientation from the curve axis shape, or\n"; + std::cerr << " from specified normals by using option --normals.\n"; + std::cerr << " --normals Use given normals as ribbon orientations.\n"; + std::cerr << " --deg | -d Specify polynomial degree of b-spline curve (default 3)\n"; + std::cerr << " Valid options:\n"; + std::cerr << " 1 - Linear curve segments/round caps,\n"; + std::cerr << " 2 - Quadratic b-spline/no caps,\n"; + std::cerr << " 3 - Cubic b-spline/no caps\n"; + std::cerr << " For bezier and catmullrom the only option is 3.\n"; + std::cerr << " --basis | -b Set basis to bspline, bezier, catmullrom (default bspline);\n"; + std::cerr << " --rad | -r Specify radius of curve (default 0.4)\n"; + std::cerr << " --mot | -m Render with motion blur\n"; + exit( 1 ); +} + + +int main( int argc, char* argv[] ) +{ + // + // Command-line parameter parsing + // + + std::string outfile; + int width = 1024; + int height = 768; + BasisType basis = BSPLINE; + int degree = 3; + float radius = 0.4f; + bool motion_blur = false; + bool ribbon = false; + bool ribbon_normals = false; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg( argv[i] ); + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--file" || arg == "-f" ) + { + if( i < argc - 1 ) + { + outfile = argv[++i]; + } + else + { + printUsageAndExit( argv[0] ); + } + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + sutil::parseDimensions( dims_arg.c_str(), width, height ); + } + else if( arg == "--ribbon" ) + { + ribbon = true; + basis = BSPLINE; + degree = 2; + } + else if( arg == "--normals" ) + { + if( ribbon ) + ribbon_normals = true; + else + std::cerr << "Ignored normals, they can only be used as ribbon orientations.\n"; + } + else if( arg == "-b" || arg == "--basis" ) + { + if( i < argc - 1 ) + { + std::string basis_name = argv[++i]; + if( basis_name == "bezier" ) + basis = BEZIER; + else if( basis_name == "catmullrom" ) + basis = CATROM; + else + basis = BSPLINE; + if( ribbon && basis != BSPLINE ) + { + std::cerr << "Ribbons are based on quadratic Bsplines. Switched basis to Bspline.\n"; + basis = BSPLINE; + } + } + else + { + printUsageAndExit( argv[0] ); + } + } + else if( arg == "-d" || arg == "--deg" ) + { + if( i < argc - 1 ) + { + degree = atoi( argv[++i] ); + if( basis == BEZIER || basis == CATROM ) + { + std::cerr << "Switched degree to 3 for Catmull-Rom or Bezier curves.\n"; + degree = 3; + } + if( 0 >= degree || degree > 3 ) + { + std::cerr << "Curve degree must be in {1, 2, 3}.\n\n"; + printUsageAndExit( argv[0] ); + } + else if( ribbon && degree != 2 ) + { + std::cerr << "Ribbons are based on quadratic Bsplines. Switched degree to 2.\n"; + degree = 2; + } + } + else + { + printUsageAndExit( argv[0] ); + } + } + else if( arg == "-r" || arg == "--rad" ) + { + if( i < argc - 1 ) + { + radius = static_cast( atof( argv[++i] ) ); + } + else + { + printUsageAndExit( argv[0] ); + } + } + else if( arg == "-m" || arg == "--mot" ) + { + motion_blur = true; + } + else + { + std::cerr << "Unknown option '" << arg << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + // + // Initialize CUDA and create OptiX context + // + OptixDeviceContext context = nullptr; + { + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + // Initialize the OptiX API, loading all API entry points + OPTIX_CHECK( optixInit() ); + + // Specify context options + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; +#ifdef DEBUG + // This may incur significant performance cost and should only be done during development. + options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; +#endif + + // Associate a CUDA context (and therefore a specific GPU) with this + // device context + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + } + + const unsigned int buildFlags = OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS | OPTIX_BUILD_FLAG_PREFER_FAST_TRACE; + // + // accel handling + // + OptixTraversableHandle gas_handle; + CUdeviceptr d_gas_output_buffer; + { + // Number of motion keys + const int NUM_KEYS = 6; + // Use default options for simplicity. In a real use case we would want to + // enable compaction, etc + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = buildFlags; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + if( motion_blur ) { + accel_options.motionOptions.numKeys = NUM_KEYS; + accel_options.motionOptions.timeBegin = 0.0f; + accel_options.motionOptions.timeEnd = 1.0f; + accel_options.motionOptions.flags = OPTIX_MOTION_FLAG_NONE; + } + + // Curve build input: simple list of three/four vertices + std::vector vertices; + std::vector widths; + std::vector normals; + SUTIL_ASSERT( radius > 0.0 ); + for( int i = 0; i < NUM_KEYS; ++i ) { + // move the y-coordinates based on cosine + const float c = cosf(i / static_cast(NUM_KEYS) * 2.0f * static_cast(M_PI)); + switch( degree ) { + case 1: { + vertices.push_back( make_float3( -0.25f, -0.25f * c, 0.0f ) ); + widths.push_back( 0.3f ); + vertices.push_back( make_float3( 0.25f, 0.25f * c, 0.0f ) ); + widths.push_back( radius ); + } break; + case 2: { + vertices.push_back( make_float3( -1.5f, -2.0f * c, 0.0f ) ); + widths.push_back( .01f ); + vertices.push_back( make_float3( 0.0f, 1.0f * c, 0.0f ) ); + widths.push_back( radius ); + vertices.push_back( make_float3( 1.5f, -2.0f * c, 0.0f ) ); + widths.push_back( .01f ); + if( ribbon_normals ) + { + // For a ribbon segment two normals can be specified, the orientation along the + // ribbon segment is computed as a linear interpolation between these two normals. + // The two normals are stored inside the normal buffer at positions vert_idx and vert_idx+1, + // where vert_idx is the index of the first vertex of the segment. + normals.push_back( make_float3( -1.f, 0.f, 0.f ) ); + normals.push_back( make_float3( 0.0f, 0.0f, 1.f ) ); + normals.push_back( make_float3( 0.f, 0.f, 0.f ) ); // dummy + } + } break; + case 3: { + vertices.push_back( make_float3( -1.0f, -1.5f * c, 0.0f ) ); + widths.push_back( .01f ); + vertices.push_back( make_float3( -1.0f, 0.2f * c, 0.0f ) ); + widths.push_back( radius ); + vertices.push_back( make_float3( 1.0f, 0.2f * c, 0.0f ) ); + widths.push_back( radius ); + vertices.push_back( make_float3( 1.0f, -1.5f * c, 0.0f ) ); + widths.push_back( .01f ); + } break; + default: + SUTIL_ASSERT_FAIL_MSG( "Curve degree must be in {1, 2, 3}." ); + } + } + const size_t vertices_size = sizeof( float3 ) * vertices.size(); + CUdeviceptr d_vertices = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_vertices ), vertices_size ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_vertices ), vertices.data(), vertices_size, cudaMemcpyHostToDevice ) ); + + + const size_t widthsSize = sizeof( float ) * widths.size(); + CUdeviceptr d_widths = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_widths ), widthsSize ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_widths ), widths.data(), widthsSize, cudaMemcpyHostToDevice ) ); + + CUdeviceptr d_normals = 0; + if( ribbon_normals ) + { + const size_t normals_size = sizeof( float3 ) * normals.size(); + CUDA_CHECK( cudaMalloc( reinterpret_cast(&d_normals), normals_size ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast(d_normals), normals.data(), normals_size, cudaMemcpyHostToDevice ) ); + } + + CUdeviceptr vertexBufferPointers[NUM_KEYS]; + CUdeviceptr widthBufferPointers[NUM_KEYS]; + CUdeviceptr normalBufferPointers[NUM_KEYS]; + for( int i = 0; i < NUM_KEYS; ++i ) { + vertexBufferPointers[i] = d_vertices + i * (degree + 1) * sizeof(float3); + widthBufferPointers[i] = d_widths + i * (degree + 1) * sizeof(float); + if( ribbon_normals ) + normalBufferPointers[i] = d_normals + i * (degree + 1) * sizeof( float3 ); + } + + // Curve build intput: with a single segment the index array + // contains index of first vertex. + const std::array segmentIndices = {0}; + const size_t segmentIndicesSize = sizeof( int ) * segmentIndices.size(); + CUdeviceptr d_segmentIndices = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_segmentIndices ), segmentIndicesSize ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_segmentIndices ), segmentIndices.data(), + segmentIndicesSize, cudaMemcpyHostToDevice ) ); + + // Curve build input. + OptixBuildInput curve_input = {}; + + curve_input.type = OPTIX_BUILD_INPUT_TYPE_CURVES; + switch( degree ) { + case 1: + curve_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_LINEAR; + break; + case 2: + if( ribbon ) + curve_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_FLAT_QUADRATIC_BSPLINE; + else + curve_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_QUADRATIC_BSPLINE; + break; + case 3: + if( basis == BEZIER ) + curve_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BEZIER; + else if( basis == CATROM ) + curve_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CATMULLROM; + else + curve_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE; + break; + } + + curve_input.curveArray.numPrimitives = 1; + curve_input.curveArray.vertexBuffers = vertexBufferPointers; + curve_input.curveArray.numVertices = static_cast( vertices.size() ); + curve_input.curveArray.vertexStrideInBytes = sizeof( float3 ); + curve_input.curveArray.widthBuffers = widthBufferPointers; + curve_input.curveArray.widthStrideInBytes = sizeof( float ); + curve_input.curveArray.normalBuffers = ribbon_normals ? normalBufferPointers : 0; + curve_input.curveArray.normalStrideInBytes = ribbon_normals ? sizeof( float3 ) : 0; + curve_input.curveArray.indexBuffer = d_segmentIndices; + curve_input.curveArray.indexStrideInBytes = sizeof( int ); + curve_input.curveArray.flag = OPTIX_GEOMETRY_FLAG_NONE; + curve_input.curveArray.primitiveIndexOffset = 0; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( context, &accel_options, &curve_input, + 1, // Number of build inputs + &gas_buffer_sizes ) ); + + CUdeviceptr d_temp_buffer_gas; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer_gas ), gas_buffer_sizes.tempSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_gas_output_buffer ), gas_buffer_sizes.outputSizeInBytes ) ); + + OPTIX_CHECK( optixAccelBuild( context, 0, // CUDA stream + &accel_options, &curve_input, + 1, // num build inputs + d_temp_buffer_gas, gas_buffer_sizes.tempSizeInBytes, d_gas_output_buffer, + gas_buffer_sizes.outputSizeInBytes, &gas_handle, + nullptr, // emitted property list + 0 ) ); // num emitted properties + + // We can now free the scratch space buffer used during build and the vertex + // inputs, since they are not needed by our trivial shading method + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer_gas ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_vertices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_widths ) ) ); + if( ribbon_normals ) + CUDA_CHECK( cudaFree( reinterpret_cast( d_normals ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_segmentIndices ) ) ); + } + + // + // Create modules + // + OptixModule shading_module = nullptr; + OptixModule geometry_module = nullptr; + OptixPipelineCompileOptions pipeline_compile_options = {}; + { + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + pipeline_compile_options.usesMotionBlur = motion_blur; // enable motion-blur in pipeline + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + pipeline_compile_options.numPayloadValues = 3; + pipeline_compile_options.numAttributeValues = 1; + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + switch( degree ) + { + case 1: + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_LINEAR; + break; + case 2: + if( ribbon ) + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_FLAT_QUADRATIC_BSPLINE; + else + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_QUADRATIC_BSPLINE; + break; + case 3: + if( basis == BEZIER ) + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CUBIC_BEZIER; + else if( basis == CATROM ) + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CATMULLROM; + else + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CUBIC_BSPLINE; + break; + } + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixCurves.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( context, &module_compile_options, &pipeline_compile_options, input, + inputSize, LOG, &LOG_SIZE, &shading_module ) ); + + OptixBuiltinISOptions builtinISOptions = {}; + switch( degree ) + { + case 1: + builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_LINEAR; + break; + case 2: + if( ribbon ) + builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_FLAT_QUADRATIC_BSPLINE; + else + builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_QUADRATIC_BSPLINE; + break; + case 3: + if( basis == BEZIER ) + builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BEZIER; + else if( basis == CATROM ) + builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CATMULLROM; + else + builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE; + break; + } + builtinISOptions.usesMotionBlur = motion_blur; // enable motion-blur for built-in intersector + builtinISOptions.buildFlags = buildFlags; + OPTIX_CHECK( optixBuiltinISModuleGet( context, &module_compile_options, &pipeline_compile_options, + &builtinISOptions, &geometry_module ) ); + } + + // + // Create program groups + // + OptixProgramGroup raygen_prog_group = nullptr; + OptixProgramGroup miss_prog_group = nullptr; + OptixProgramGroup hitgroup_prog_group = nullptr; + { + OptixProgramGroupOptions program_group_options = {}; // Initialize to zeros + + OptixProgramGroupDesc raygen_prog_group_desc = {}; // + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = shading_module; + if( motion_blur ) + { + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__motion_blur"; + } + else + { + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__basic"; + } + OPTIX_CHECK_LOG( optixProgramGroupCreate( context, &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &raygen_prog_group ) ); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = shading_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__ms"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &miss_prog_group ) ); + + OptixProgramGroupDesc hitgroup_prog_group_desc = {}; + hitgroup_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hitgroup_prog_group_desc.hitgroup.moduleCH = shading_module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__ch"; + hitgroup_prog_group_desc.hitgroup.moduleIS = geometry_module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameIS = 0; // automatically supplied for built-in module + OPTIX_CHECK_LOG( optixProgramGroupCreate( context, &hitgroup_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &hitgroup_prog_group ) ); + } + + // + // Link pipeline + // + OptixPipeline pipeline = nullptr; + { + const uint32_t max_trace_depth = 1; + OptixProgramGroup program_groups[] = {raygen_prog_group, miss_prog_group, hitgroup_prog_group}; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + OPTIX_CHECK_LOG( optixPipelineCreate( context, &pipeline_compile_options, &pipeline_link_options, + program_groups, sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, &pipeline ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + ) ); + } + + // + // Set up shader binding table + // + OptixShaderBindingTable sbt = {}; + { + CUdeviceptr raygen_record; + const size_t raygen_record_size = sizeof( RayGenSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &raygen_record ), raygen_record_size ) ); + RayGenSbtRecord rg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( raygen_prog_group, &rg_sbt ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( raygen_record ), &rg_sbt, raygen_record_size, cudaMemcpyHostToDevice ) ); + + CUdeviceptr miss_record; + size_t miss_record_size = sizeof( MissSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &miss_record ), miss_record_size ) ); + MissSbtRecord ms_sbt; + ms_sbt.data = {0.0f, 0.2f, 0.6f}; // background color (blue) + OPTIX_CHECK( optixSbtRecordPackHeader( miss_prog_group, &ms_sbt ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( miss_record ), &ms_sbt, miss_record_size, cudaMemcpyHostToDevice ) ); + + CUdeviceptr hitgroup_record; + size_t hitgroup_record_size = sizeof( HitGroupSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &hitgroup_record ), hitgroup_record_size ) ); + HitGroupSbtRecord hg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( hitgroup_prog_group, &hg_sbt ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( hitgroup_record ), &hg_sbt, hitgroup_record_size, cudaMemcpyHostToDevice ) ); + + sbt.raygenRecord = raygen_record; + sbt.missRecordBase = miss_record; + sbt.missRecordStrideInBytes = sizeof( MissSbtRecord ); + sbt.missRecordCount = 1; + sbt.hitgroupRecordBase = hitgroup_record; + sbt.hitgroupRecordStrideInBytes = sizeof( HitGroupSbtRecord ); + sbt.hitgroupRecordCount = 1; + } + + sutil::CUDAOutputBuffer output_buffer( sutil::CUDAOutputBufferType::CUDA_DEVICE, width, height ); + + // + // launch + // + { + CUstream stream; + CUDA_CHECK( cudaStreamCreate( &stream ) ); + + sutil::Camera cam; + configureCamera( cam, width, height, degree ); + + Params params; + params.image = output_buffer.map(); + params.image_width = width; + params.image_height = height; + params.handle = gas_handle; + params.cam_eye = cam.eye(); + cam.UVWFrame( params.cam_u, params.cam_v, params.cam_w ); + + CUdeviceptr d_param; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_param ), sizeof( Params ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_param ), ¶ms, sizeof( params ), cudaMemcpyHostToDevice ) ); + + OPTIX_CHECK( optixLaunch( pipeline, stream, d_param, sizeof( Params ), &sbt, width, height, /*depth=*/1 ) ); + CUDA_SYNC_CHECK(); + + output_buffer.unmap(); + CUDA_CHECK( cudaFree( reinterpret_cast( d_param ) ) ); + } + + // + // Display results + // + { + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = width; + buffer.height = height; + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + if( outfile.empty() ) + sutil::displayBufferWindow( argv[0], buffer ); + else + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + // + // Cleanup + // + { + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_gas_output_buffer ) ) ); + + OPTIX_CHECK( optixPipelineDestroy( pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( hitgroup_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( miss_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( raygen_prog_group ) ); + OPTIX_CHECK( optixModuleDestroy( shading_module ) ); + OPTIX_CHECK( optixModuleDestroy( geometry_module ) ); + + OPTIX_CHECK( optixDeviceContextDestroy( context ) ); + } + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCurves/optixCurves.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixCurves/optixCurves.cu new file mode 100644 index 00000000..3c7d020e --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCurves/optixCurves.cu @@ -0,0 +1,159 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include "optixCurves.h" +#include +#include + +#include + + +extern "C" { +__constant__ Params params; +} + + +static __forceinline__ __device__ void setPayload( float3 p ) +{ + optixSetPayload_0( __float_as_uint( p.x ) ); + optixSetPayload_1( __float_as_uint( p.y ) ); + optixSetPayload_2( __float_as_uint( p.z ) ); +} + + +static __forceinline__ __device__ void computeRay( uint3 idx, uint3 dim, float3& origin, float3& direction ) +{ + const float3 U = params.cam_u; + const float3 V = params.cam_v; + const float3 W = params.cam_w; + const float2 d = 2.0f * make_float2( + static_cast( idx.x ) / static_cast( dim.x ), + static_cast( idx.y ) / static_cast( dim.y ) + ) - 1.0f; + + origin = params.cam_eye; + direction = normalize( d.x * U + d.y * V + W ); +} + + +extern "C" __global__ void __raygen__basic() +{ + // Lookup our location within the launch grid + const uint3 idx = optixGetLaunchIndex(); + const uint3 dim = optixGetLaunchDimensions(); + + // Map our launch idx to a screen location and create a ray from the camera + // location through the screen + float3 ray_origin, ray_direction; + computeRay( idx, dim, ray_origin, ray_direction ); + + // Trace the ray against our scene hierarchy + unsigned int p0, p1, p2; + optixTrace( + params.handle, + ray_origin, + ray_direction, + 0.0f, // Min intersection distance + 1e16f, // Max intersection distance + 0.0f, // rayTime -- used for motion blur + OptixVisibilityMask( 255 ), // Specify always visible + OPTIX_RAY_FLAG_NONE, + 0, // SBT offset -- See SBT discussion + 1, // SBT stride -- See SBT discussion + 0, // missSBTIndex -- See SBT discussion + p0, p1, p2 ); + float3 result; + result.x = __uint_as_float( p0 ); + result.y = __uint_as_float( p1 ); + result.z = __uint_as_float( p2 ); + + // Record results in our output raster + params.image[idx.y * params.image_width + idx.x] = make_color( result ); +} + + +extern "C" __global__ void __raygen__motion_blur() +{ + // Lookup our location within the launch grid + const uint3 idx = optixGetLaunchIndex(); + const uint3 dim = optixGetLaunchDimensions(); + + // Map our launch idx to a screen location and create a ray from the camera + // location through the screen + float3 ray_origin, ray_direction; + computeRay( idx, dim, ray_origin, ray_direction ); + + // Trace the ray against our scene hierarchy + unsigned int p0, p1, p2; + const int NUM_SAMPLES = 100; + float3 result = {}; + unsigned int seed = tea<4>(idx.y * dim.y + dim.x, idx.x); + for( int i = 0; i < NUM_SAMPLES; ++i ) + { + const float ray_time = rnd(seed); // compute next random ray time in [0, 1[ + optixTrace( params.handle, ray_origin, ray_direction, + 0.0f, // Min intersection distance + 1e16f, // Max intersection distance + ray_time, // rayTime -- used for motion blur + OptixVisibilityMask( 255 ), // Specify always visible + OPTIX_RAY_FLAG_NONE, + 0, // SBT offset -- See SBT discussion + 1, // SBT stride -- See SBT discussion + 0, // missSBTIndex -- See SBT discussion + p0, p1, p2 ); + result.x += __uint_as_float( p0 ); + result.y += __uint_as_float( p1 ); + result.z += __uint_as_float( p2 ); + } + + // Record results in our output raster + params.image[idx.y * params.image_width + idx.x] = make_color( result / NUM_SAMPLES ); +} + + +extern "C" __global__ void __miss__ms() +{ + MissData* miss_data = reinterpret_cast( optixGetSbtDataPointer() ); + setPayload( miss_data->bg_color ); +} + + +extern "C" __global__ void __closesthit__ch() +{ + // When built-in curve intersection is used, the curve parameter u is provided + // by the OptiX API. The parameter’s range is [0,1] over the curve segment, + // with u=0 or u=1 only on the end caps. + float u = optixGetCurveParameter(); + + // linearly interpolate from black to orange + setPayload( make_float3( u, u / 3.0f, 0.0f ) ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCurves/optixCurves.h b/Extern/3rdParty/OptiX/Linux/SDK/optixCurves/optixCurves.h new file mode 100644 index 00000000..44786e57 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCurves/optixCurves.h @@ -0,0 +1,58 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +struct Params +{ + uchar4* image; + unsigned int image_width; + unsigned int image_height; + float3 cam_eye; + float3 cam_u, cam_v, cam_w; + OptixTraversableHandle handle; +}; + + +struct RayGenData +{ + // No data needed +}; + + +struct MissData +{ + float3 bg_color; +}; + + +struct HitGroupData +{ + // No data needed +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCustomPrimitive/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixCustomPrimitive/CMakeLists.txt new file mode 100644 index 00000000..09e353da --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCustomPrimitive/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2022 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixCustomPrimitive target_name + optixCustomPrimitive.cu + optixCustomPrimitive.cpp + optixCustomPrimitive.h + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCustomPrimitive/optixCustomPrimitive.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixCustomPrimitive/optixCustomPrimitive.cpp new file mode 100644 index 00000000..ae24c061 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCustomPrimitive/optixCustomPrimitive.cpp @@ -0,0 +1,505 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2022 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include + +#include "optixCustomPrimitive.h" + +#include +#include +#include + +#include +#include + + + +template +struct SbtRecord +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef SbtRecord RayGenSbtRecord; +typedef SbtRecord MissSbtRecord; +typedef SbtRecord HitGroupSbtRecord; + + +void configureCamera( sutil::Camera& cam, const uint32_t width, const uint32_t height ) +{ + cam.setEye( {0.0f, 0.0f, 3.0f} ); + cam.setLookat( {0.0f, 0.0f, 0.0f} ); + cam.setUp( {0.0f, 1.0f, 3.0f} ); + cam.setFovY( 60.0f ); + cam.setAspectRatio( (float)width / (float)height ); +} + + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f Specify file for image output\n"; + std::cerr << " --help | -h Print this usage message\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 512x384\n"; + exit( 1 ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + + +int main( int argc, char* argv[] ) +{ + std::string outfile; + int width = 1024; + int height = 768; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg( argv[i] ); + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--file" || arg == "-f" ) + { + if( i < argc - 1 ) + { + outfile = argv[++i]; + } + else + { + printUsageAndExit( argv[0] ); + } + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + sutil::parseDimensions( dims_arg.c_str(), width, height ); + } + else + { + std::cerr << "Unknown option '" << arg << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + // + // Initialize CUDA and create OptiX context + // + OptixDeviceContext context = nullptr; + { + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + } + + + // + // accel handling + // + OptixTraversableHandle gas_handle; + CUdeviceptr d_gas_output_buffer; + { + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + // AABB build input + OptixAabb aabb = {-1.5f, -1.5f, -1.5f, 1.5f, 1.5f, 1.5f}; + CUdeviceptr d_aabb_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_aabb_buffer ), sizeof( OptixAabb ) ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_aabb_buffer ), + &aabb, + sizeof( OptixAabb ), + cudaMemcpyHostToDevice + ) ); + + OptixBuildInput aabb_input = {}; + + aabb_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES; + aabb_input.customPrimitiveArray.aabbBuffers = &d_aabb_buffer; + aabb_input.customPrimitiveArray.numPrimitives = 1; + + uint32_t aabb_input_flags[1] = {OPTIX_GEOMETRY_FLAG_NONE}; + aabb_input.customPrimitiveArray.flags = aabb_input_flags; + aabb_input.customPrimitiveArray.numSbtRecords = 1; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( context, &accel_options, &aabb_input, 1, &gas_buffer_sizes ) ); + CUdeviceptr d_temp_buffer_gas; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer_gas ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 + ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( (char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( context, + 0, // CUDA stream + &accel_options, + &aabb_input, + 1, // num build inputs + d_temp_buffer_gas, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &gas_handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + CUDA_CHECK( cudaFree( (void*)d_temp_buffer_gas ) ); + CUDA_CHECK( cudaFree( (void*)d_aabb_buffer ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, (void*)emitProperty.result, sizeof(size_t), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( context, 0, gas_handle, d_gas_output_buffer, compacted_gas_size, &gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + d_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } + } + + // + // Create module + // + OptixModule module = nullptr; + OptixModule sphere_module = nullptr; + OptixPipelineCompileOptions pipeline_compile_options = {}; + { + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + pipeline_compile_options.usesMotionBlur = false; + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + pipeline_compile_options.numPayloadValues = 3; + pipeline_compile_options.numAttributeValues = whitted::NUM_ATTRIBUTE_VALUES; + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; // TODO: should be OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW; + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixCustomPrimitive.cu", inputSize ); + + OPTIX_CHECK_LOG( optixModuleCreate( + context, + &module_compile_options, + &pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &module + ) ); + + input = sutil::getInputData( nullptr, nullptr, "sphere.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( + context, + &module_compile_options, + &pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &sphere_module + ) ); + } + + // + // Create program groups + // + OptixProgramGroup raygen_prog_group = nullptr; + OptixProgramGroup miss_prog_group = nullptr; + OptixProgramGroup hitgroup_prog_group = nullptr; + { + OptixProgramGroupOptions program_group_options = {}; // Initialize to zeros + + OptixProgramGroupDesc raygen_prog_group_desc = {}; // + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &raygen_prog_group + ) ); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__ms"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &miss_prog_group + ) ); + + OptixProgramGroupDesc hitgroup_prog_group_desc = {}; + hitgroup_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hitgroup_prog_group_desc.hitgroup.moduleCH = module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__ch"; + hitgroup_prog_group_desc.hitgroup.moduleAH = nullptr; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + hitgroup_prog_group_desc.hitgroup.moduleIS = sphere_module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__sphere"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &hitgroup_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &hitgroup_prog_group + ) ); + } + + // + // Link pipeline + // + OptixPipeline pipeline = nullptr; + { + const uint32_t max_trace_depth = 1; + OptixProgramGroup program_groups[] = { raygen_prog_group, miss_prog_group, hitgroup_prog_group }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + OPTIX_CHECK_LOG( optixPipelineCreate( + context, + &pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &pipeline + ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + ) ); + } + + // + // Set up shader binding table + // + OptixShaderBindingTable sbt = {}; + { + CUdeviceptr raygen_record; + const size_t raygen_record_size = sizeof( RayGenSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &raygen_record ), raygen_record_size ) ); + sutil::Camera cam; + configureCamera( cam, width, height ); + RayGenSbtRecord rg_sbt; + rg_sbt.data ={}; + rg_sbt.data.cam_eye = cam.eye(); + cam.UVWFrame( rg_sbt.data.camera_u, rg_sbt.data.camera_v, rg_sbt.data.camera_w ); + OPTIX_CHECK( optixSbtRecordPackHeader( raygen_prog_group, &rg_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( raygen_record ), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr miss_record; + size_t miss_record_size = sizeof( MissSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &miss_record ), miss_record_size ) ); + MissSbtRecord ms_sbt; + ms_sbt.data = { 0.3f, 0.1f, 0.2f }; + OPTIX_CHECK( optixSbtRecordPackHeader( miss_prog_group, &ms_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( miss_record ), + &ms_sbt, + miss_record_size, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr hitgroup_record; + size_t hitgroup_record_size = sizeof( HitGroupSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &hitgroup_record ), hitgroup_record_size ) ); + HitGroupSbtRecord hg_sbt; + GeometryData::Sphere sphere = {}; + sphere.center = { 0.0f, 0.0f, 0.0f }; + sphere.radius = 1.5f; + hg_sbt.data.geometry_data.setSphere( sphere ); + OPTIX_CHECK( optixSbtRecordPackHeader( hitgroup_prog_group, &hg_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( hitgroup_record ), + &hg_sbt, + hitgroup_record_size, + cudaMemcpyHostToDevice + ) ); + + sbt.raygenRecord = raygen_record; + sbt.missRecordBase = miss_record; + sbt.missRecordStrideInBytes = sizeof( MissSbtRecord ); + sbt.missRecordCount = 1; + sbt.hitgroupRecordBase = hitgroup_record; + sbt.hitgroupRecordStrideInBytes = sizeof( HitGroupSbtRecord ); + sbt.hitgroupRecordCount = 1; + } + + sutil::CUDAOutputBuffer output_buffer( sutil::CUDAOutputBufferType::CUDA_DEVICE, width, height ); + + // + // launch + // + { + CUstream stream; + CUDA_CHECK( cudaStreamCreate( &stream ) ); + + Params params; + params.image = output_buffer.map(); + params.image_width = width; + params.image_height = height; + params.origin_x = width / 2; + params.origin_y = height / 2; + params.handle = gas_handle; + + CUdeviceptr d_param; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_param ), sizeof( Params ) ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_param ), + ¶ms, sizeof( params ), + cudaMemcpyHostToDevice + ) ); + + OPTIX_CHECK( optixLaunch( pipeline, stream, d_param, sizeof( Params ), &sbt, width, height, /*depth=*/1 ) ); + CUDA_SYNC_CHECK(); + + output_buffer.unmap(); + CUDA_CHECK( cudaFree( reinterpret_cast( d_param ) ) ); + } + + // + // Display results + // + { + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = width; + buffer.height = height; + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + if( outfile.empty() ) + sutil::displayBufferWindow( argv[0], buffer ); + else + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + // + // Cleanup + // + { + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_gas_output_buffer ) ) ); + + OPTIX_CHECK( optixPipelineDestroy( pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( hitgroup_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( miss_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( raygen_prog_group ) ); + OPTIX_CHECK( optixModuleDestroy( module ) ); + OPTIX_CHECK( optixModuleDestroy( sphere_module ) ); + + OPTIX_CHECK( optixDeviceContextDestroy( context ) ); + } + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCustomPrimitive/optixCustomPrimitive.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixCustomPrimitive/optixCustomPrimitive.cu new file mode 100644 index 00000000..10b9e80e --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCustomPrimitive/optixCustomPrimitive.cu @@ -0,0 +1,139 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2022 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "optixCustomPrimitive.h" +#include + +#include + +extern "C" { +__constant__ Params params; +} + + +static __forceinline__ __device__ void trace( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax, + float3* prd + ) +{ + unsigned int p0, p1, p2; + p0 = __float_as_int( prd->x ); + p1 = __float_as_int( prd->y ); + p2 = __float_as_int( prd->z ); + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_NONE, + 0, // SBT offset + RAY_TYPE_COUNT, // SBT stride + 0, // missSBTIndex + p0, p1, p2 ); + prd->x = __int_as_float( p0 ); + prd->y = __int_as_float( p1 ); + prd->z = __int_as_float( p2 ); +} + + +static __forceinline__ __device__ void setPayload( float3 p ) +{ + optixSetPayload_0( __float_as_int( p.x ) ); + optixSetPayload_1( __float_as_int( p.y ) ); + optixSetPayload_2( __float_as_int( p.z ) ); +} + + +static __forceinline__ __device__ float3 getPayload() +{ + return make_float3( + __int_as_float( optixGetPayload_0() ), + __int_as_float( optixGetPayload_1() ), + __int_as_float( optixGetPayload_2() ) + ); +} + + +extern "C" __global__ void __raygen__rg() +{ + const uint3 idx = optixGetLaunchIndex(); + const uint3 dim = optixGetLaunchDimensions(); + + const RayGenData* rtData = (RayGenData*)optixGetSbtDataPointer(); + const float3 U = rtData->camera_u; + const float3 V = rtData->camera_v; + const float3 W = rtData->camera_w; + const float2 d = 2.0f * make_float2( + static_cast( idx.x ) / static_cast( dim.x ), + static_cast( idx.y ) / static_cast( dim.y ) + ) - 1.0f; + + const float3 origin = rtData->cam_eye; + const float3 direction = normalize( d.x * U + d.y * V + W ); + float3 payload_rgb = make_float3( 0.5f, 0.5f, 0.5f ); + trace( params.handle, + origin, + direction, + 0.00f, // tmin + 1e16f, // tmax + &payload_rgb ); + + params.image[idx.y * params.image_width + idx.x] = make_color( payload_rgb ); +} + + +extern "C" __global__ void __miss__ms() +{ + MissData* rt_data = reinterpret_cast( optixGetSbtDataPointer() ); + float3 payload = getPayload(); + setPayload( make_float3( rt_data->r, rt_data->g, rt_data->b ) ); +} + + +extern "C" __global__ void __closesthit__ch() +{ + const float3 shading_normal = + make_float3( + __int_as_float( optixGetAttribute_0() ), + __int_as_float( optixGetAttribute_1() ), + __int_as_float( optixGetAttribute_2() ) + ); + setPayload( normalize( optixTransformNormalFromObjectToWorldSpace( shading_normal ) ) * 0.5f + 0.5f ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCustomPrimitive/optixCustomPrimitive.h b/Extern/3rdParty/OptiX/Linux/SDK/optixCustomPrimitive/optixCustomPrimitive.h new file mode 100644 index 00000000..da465f22 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCustomPrimitive/optixCustomPrimitive.h @@ -0,0 +1,61 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2022 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +enum RayType +{ + RAY_TYPE_RADIANCE = 0, + RAY_TYPE_COUNT +}; + +struct Params +{ + uchar4* image; + unsigned int image_width; + unsigned int image_height; + int origin_x; + int origin_y; + OptixTraversableHandle handle; +}; + + +struct RayGenData +{ + float3 cam_eye; + float3 camera_u, camera_v, camera_w; +}; + + +struct MissData +{ + float r, g, b; +}; + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCutouts/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixCutouts/CMakeLists.txt new file mode 100644 index 00000000..9f14055e --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCutouts/CMakeLists.txt @@ -0,0 +1,40 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixCutouts target_name + ${SAMPLES_CUDA_DIR}/helpers.h + optixCutouts.cu + optixCutouts.cpp + optixCutouts.h + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCutouts/optixCutouts.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixCutouts/optixCutouts.cpp new file mode 100644 index 00000000..5da261bc --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCutouts/optixCutouts.cpp @@ -0,0 +1,1726 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include // Needs to be included before gl_interop + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "optixCutouts.h" + +#include +#include +#include +#include +#include +#include +#include + + +bool use_pbo = true; +bool resize_dirty = false; +bool minimized = false; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Mouse state +int2 mouse_prev_pos; +int32_t mouse_button = -1; + +int32_t samples_per_launch = 16; + +//------------------------------------------------------------------------------ +// +// Local types +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +template +struct Record +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef Record RayGenRecord; +typedef Record MissRecord; +typedef Record HitGroupRecord; + + +struct Vertex +{ + float x, y, z, pad; +}; + + +struct Instance +{ + float transform[12]; +}; + + +struct CutoutsState +{ + OptixDeviceContext context = 0; + + OptixTraversableHandle triangle_gas_handle = 0; // Traversable handle for triangle AS + CUdeviceptr d_triangle_gas_output_buffer = 0; // Triangle AS memory + CUdeviceptr d_vertices = 0; + CUdeviceptr d_tex_coords = 0; + CUdeviceptr d_omm_array = 0; // OMM array for triangles, memory needs to be persistent over GAS build + + OptixTraversableHandle sphere_gas_handle = 0; // Traversable handle for sphere AS + CUdeviceptr d_sphere_gas_output_buffer = 0; // Sphere AS memory + + OptixTraversableHandle ias_handle = 0; // Traversable handle for instance AS + CUdeviceptr d_ias_output_buffer = 0; // Instance AS memory + + OptixModule module = 0; + OptixModule sphere_module = 0; + + OptixPipelineCompileOptions pipeline_compile_options = {}; + OptixPipeline pipeline = 0; + + OptixProgramGroup raygen_prog_group = 0; + OptixProgramGroup radiance_miss_group = 0; + OptixProgramGroup occlusion_miss_group = 0; + OptixProgramGroup triangle_checkerboard_hit_group = 0; + OptixProgramGroup triangle_circle_hit_group = 0; + OptixProgramGroup sphere_checkerboard_hit_group = 0; + + + bool enableAH = true; + bool enableOMMs = true; + + CUstream stream = 0; + Params params = {}; + Params* d_params = nullptr; + + OptixShaderBindingTable sbt = {}; +}; + + +//------------------------------------------------------------------------------ +// +// Scene data +// +//------------------------------------------------------------------------------ + + +constexpr int32_t TRIANGLE_COUNT = 32; +constexpr int32_t TRIANGLE_MAT_COUNT = 6; +constexpr int32_t SPHERE_COUNT = 1; +constexpr int32_t SPHERE_MAT_COUNT = 1; + +// Size of the checkerboard pattern on the 'cutout' box, must be power of two for simplicity of the opacity micromap in this sample. +// The opacity micromap is generated to perfectly cover the checkerboard pattern. +constexpr int CHECKERBOARD_OMM_SUBDIV_LEVEL = 3; +constexpr int CHECKERBOARD_SIZE = 1 << CHECKERBOARD_OMM_SUBDIV_LEVEL; + +constexpr int CIRCLE_OMM_SUBDIV_LEVEL = 5; + +const static std::array g_vertices = +{ { + // Floor -- white lambert + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 0.0f, 0.0f }, + + // Ceiling -- white lambert + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + + // Back wall -- white lambert + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + + // Right wall -- green lambert + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + { 0.0f, 0.0f, 559.2f, 0.0f }, + + // Left wall -- red lambert + { 556.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 556.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 0.0f, 0.0f }, + + // Short block -- white lambert + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 242.0f, 165.0f, 274.0f, 0.0f }, + + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 242.0f, 165.0f, 274.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + + { 290.0f, 0.0f, 114.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + + { 290.0f, 0.0f, 114.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + { 240.0f, 0.0f, 272.0f, 0.0f }, + + { 130.0f, 0.0f, 65.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + + { 130.0f, 0.0f, 65.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + { 290.0f, 0.0f, 114.0f, 0.0f }, + + { 82.0f, 0.0f, 225.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + + { 82.0f, 0.0f, 225.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 130.0f, 0.0f, 65.0f, 0.0f }, + + { 240.0f, 0.0f, 272.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + + { 240.0f, 0.0f, 272.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 82.0f, 0.0f, 225.0f, 0.0f }, + + // Tall block -- white lambert + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 314.0f, 330.0f, 455.0f, 0.0f }, + + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 314.0f, 330.0f, 455.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + + { 423.0f, 0.0f, 247.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + + { 423.0f, 0.0f, 247.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + { 472.0f, 0.0f, 406.0f, 0.0f }, + + { 472.0f, 0.0f, 406.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + + { 472.0f, 0.0f, 406.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + { 314.0f, 0.0f, 456.0f, 0.0f }, + + { 314.0f, 0.0f, 456.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + + { 314.0f, 0.0f, 456.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 265.0f, 0.0f, 296.0f, 0.0f }, + + { 265.0f, 0.0f, 296.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + + { 265.0f, 0.0f, 296.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 423.0f, 0.0f, 247.0f, 0.0f }, + + // Ceiling light -- emmissive + { 343.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 332.0f, 0.0f }, + + { 343.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 332.0f, 0.0f }, + { 343.0f, 548.6f, 332.0f, 0.0f } +} }; + + +static std::array g_mat_indices = +{ { + 0, 0, // Floor -- white lambert + 0, 0, // Ceiling -- white lambert + 0, 0, // Back wall -- white lambert + 1, 1, // Right wall -- green lambert + 2, 2, // Left wall -- red lambert + 4, 4, 4, 4, 5, 5, 4, 4, 5, 5, // Short block -- cutout checkerboard and circle + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Tall block -- white lambert + 3, 3 // Ceiling light -- emmissive +} }; + + +const std::array g_emission_colors = +{ { + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 15.0f, 15.0f, 5.0f }, + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f } +} }; + + +const std::array g_diffuse_colors = +{ { + { 0.80f, 0.80f, 0.80f }, + { 0.05f, 0.80f, 0.05f }, + { 0.80f, 0.05f, 0.05f }, + { 0.50f, 0.00f, 0.00f }, + { 0.70f, 0.25f, 0.00f }, + { 0.70f, 0.25f, 0.00f } +} }; + +const std::array g_checkerboard_tex_coords = +{ { + { CHECKERBOARD_SIZE, 0.0f }, { 0.0f, 0.0f }, + { 0.0f, CHECKERBOARD_SIZE }, { CHECKERBOARD_SIZE, 0.0f }, + { 0.0f, CHECKERBOARD_SIZE }, { CHECKERBOARD_SIZE, CHECKERBOARD_SIZE } +} }; + +const std::array g_circle_tex_coords = +{ { + { 1.f, -1.0f }, { -1.0f, -1.0f }, + { -1.0f, 1.f }, { 1.f, -1.0f }, + { -1.0f, 1.f }, { 1.f, 1.f } +} }; + +// NB: Some UV scaling is baked into the coordinates for the short block, since +// the coordinates are used for the cutout texture. +const std::array g_tex_coords = +{ { + // Floor + { 1.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 1.0f }, + { 1.0f, 0.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f }, + + // Ceiling + { 1.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 1.0f }, + { 1.0f, 0.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f }, + + // Back wall + { 1.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 1.0f }, + { 1.0f, 0.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f }, + + // Right wall + { 1.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 1.0f }, + { 1.0f, 0.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f }, + + // Left wall + { 1.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 1.0f }, + { 1.0f, 0.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f }, + + // Short Block + g_checkerboard_tex_coords[0], g_checkerboard_tex_coords[1], g_checkerboard_tex_coords[2], + g_checkerboard_tex_coords[3], g_checkerboard_tex_coords[4], g_checkerboard_tex_coords[5], + g_checkerboard_tex_coords[0], g_checkerboard_tex_coords[1], g_checkerboard_tex_coords[2], + g_checkerboard_tex_coords[3], g_checkerboard_tex_coords[4], g_checkerboard_tex_coords[5], + g_circle_tex_coords[0], g_circle_tex_coords[1], g_circle_tex_coords[2], + g_circle_tex_coords[3], g_circle_tex_coords[4], g_circle_tex_coords[5], + g_checkerboard_tex_coords[0], g_checkerboard_tex_coords[1], g_checkerboard_tex_coords[2], + g_checkerboard_tex_coords[3], g_checkerboard_tex_coords[4], g_checkerboard_tex_coords[5], + g_circle_tex_coords[0], g_circle_tex_coords[1], g_circle_tex_coords[2], + g_circle_tex_coords[3], g_circle_tex_coords[4], g_circle_tex_coords[5], + + // Tall Block + { 1.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 1.0f }, + { 1.0f, 0.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f }, + { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f }, + { 0.0f, 1.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, + { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f }, + { 0.0f, 1.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, + { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f }, + { 0.0f, 1.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, + { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f }, + { 0.0f, 1.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, + + // Ceiling light + { 1.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 1.0f }, + { 1.0f, 0.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f } +} }; + + +const GeometryData::Sphere g_sphere = {410.0f, 90.0f, 110.0f, 90.0f}; +const float3 g_sphere_emission_color = {0.0f}; +const float3 g_sphere_diffuse_color = {0.1f, 0.2f, 0.8f}; + +// decl +void buildInstanceAccel( CutoutsState& state ); + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking(static_cast( xpos ), static_cast( ypos )); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + CutoutsState& state = *static_cast( glfwGetWindowUserPointer( window ) ); + Params& params = state.params; + + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params.width, params.height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params.width, params.height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + CutoutsState& state = *static_cast( glfwGetWindowUserPointer( window ) ); + Params& params = state.params; + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + params.width = res_x; + params.height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + CutoutsState& state = *static_cast( glfwGetWindowUserPointer( window ) ); + + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + } + else if( key == GLFW_KEY_O ) + { + // toggle enabling/disabling OMMs + // in this sample we always add OMMs to the triangles + // we can disable OMMs at the instance level (using instance flag OPTIX_INSTANCE_FLAG_DISABLE_OPACITY_MICROMAPS) + state.enableOMMs = !state.enableOMMs; + buildInstanceAccel( state ); + state.params.subframe_index = 0; + if( state.enableOMMs ) + std::cout << "Opacity micromaps (OMMs) on small block enabled.\n"; + else + std::cout << "Opacity micromaps (OMMs) on small block disabled.\n"; + + } + else if( key == GLFW_KEY_A ) + { + // toggle enabling/disabling AH program (entirely rely on OMMs) + // Like OMMs, AH can be disabled at the instance level (using instance flag OPTIX_INSTANCE_FLAG_DISABLE_ANYHIT) + state.enableAH = !state.enableAH; + buildInstanceAccel( state ); + state.params.subframe_index = 0; + if( state.enableAH ) + std::cout << "Anyhit program (AH) on small block enabled.\n"; + else + std::cout << "Anyhit program (AH) on small block disabled.\n"; + } +} + + +static void scrollCallback( GLFWwindow* window, double xscroll, double yscroll ) +{ + if(trackball.wheelEvent((int)yscroll)) + camera_changed = true; +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --launch-samples | -s Number of samples per pixel per launch (default 16)\n"; + std::cerr << " --launch-frames Number of frames accumulated when rendering to a file (option -f, default 16)\n"; + std::cerr << " --no-gl-interop Disable GL interop for display\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 768x768\n"; + std::cerr << " --help | -h Print this usage message\n"; + exit( 0 ); +} + + +void initLaunchParams( CutoutsState& state ) +{ + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.params.accum_buffer ), + state.params.width*state.params.height*sizeof(float4) ) ); + state.params.frame_buffer = nullptr; // Will be set when output buffer is mapped + + state.params.samples_per_launch = samples_per_launch; + state.params.subframe_index = 0u; + + state.params.light.emission = make_float3( 15.0f, 15.0f, 5.0f ); + state.params.light.corner = make_float3( 343.0f, 548.5f, 227.0f ); + state.params.light.v1 = make_float3( 0.0f, 0.0f, 105.0f ); + state.params.light.v2 = make_float3( -130.0f, 0.0f, 0.0f ); + state.params.light.normal = normalize ( cross( state.params.light.v1, state.params.light.v2) ); + + CUDA_CHECK( cudaStreamCreate( &state.stream ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_params ), sizeof( Params ) ) ); +} + + +void handleCameraUpdate( Params& params ) +{ + if( !camera_changed ) + return; + camera_changed = false; + + camera.setAspectRatio( static_cast( params.width ) / static_cast( params.height ) ); + params.eye = camera.eye(); + camera.UVWFrame( params.U, params.V, params.W ); +} + + +void handleResize( sutil::CUDAOutputBuffer& output_buffer, Params& params ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + output_buffer.resize( params.width, params.height ); + + // Realloc accumulation buffer + CUDA_CHECK( cudaFree( reinterpret_cast( params.accum_buffer ) ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( ¶ms.accum_buffer ), + params.width*params.height*sizeof(float4) ) ); +} + + +void updateState( sutil::CUDAOutputBuffer& output_buffer, Params& params ) +{ + // Update params on device + if( camera_changed || resize_dirty ) + params.subframe_index = 0; + + handleCameraUpdate( params ); + handleResize( output_buffer, params ); +} + + +void launchSubframe( sutil::CUDAOutputBuffer& output_buffer, CutoutsState& state ) +{ + // Launch + uchar4* result_buffer_data = output_buffer.map(); + state.params.frame_buffer = result_buffer_data; + CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast( state.d_params ), + &state.params, + sizeof( Params ), + cudaMemcpyHostToDevice, + state.stream + ) ); + + OPTIX_CHECK( optixLaunch( + state.pipeline, + state.stream, + reinterpret_cast( state.d_params ), + sizeof( Params ), + &state.sbt, + state.params.width, // launch width + state.params.height, // launch height + 1 // launch depth + ) ); + output_buffer.unmap(); +} + + +void displaySubframe( + sutil::CUDAOutputBuffer& output_buffer, + sutil::GLDisplay& gl_display, + GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( + output_buffer.width(), + output_buffer.height(), + framebuf_res_x, + framebuf_res_y, + output_buffer.getPBO() + ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + + +void initCameraState() +{ + camera.setEye( make_float3( 278.0f, 273.0f, -900.0f ) ); + camera.setLookat( make_float3( 278.0f, 273.0f, 330.0f ) ); + camera.setUp( make_float3( 0.0f, 1.0f, 0.0f ) ); + camera.setFovY( 35.0f ); + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( make_float3( 1.0f, 0.0f, 0.0f ), + make_float3( 0.0f, 0.0f, 1.0f ), + make_float3( 0.0f, 1.0f, 0.0f ) ); + trackball.setGimbalLock(true); +} + + +void createContext( CutoutsState& state ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + + state.context = context; +} + + +void buildGeomAccel( CutoutsState& state ) +{ + // + // Build triangle GAS + // + { + const size_t vertices_size_in_bytes = g_vertices.size() * sizeof( Vertex ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_vertices ), vertices_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( state.d_vertices ), g_vertices.data(), vertices_size_in_bytes, + cudaMemcpyHostToDevice ) ); + + CUdeviceptr d_mat_indices = 0; + const size_t mat_indices_size_in_bytes = g_mat_indices.size() * sizeof( uint32_t ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_mat_indices ), mat_indices_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_mat_indices ), g_mat_indices.data(), + mat_indices_size_in_bytes, cudaMemcpyHostToDevice ) ); + + // NOTE: the 'DISABLE_ANYHIT' flag will be overwritten by the explicit OMM predefined index below. + // With OMMs, the opacity state is explicitly defined per triangle. + uint32_t triangle_input_flags[TRIANGLE_MAT_COUNT] = { + // One flag per SBT record for this build input + // The following materials are known to be opaque, so normally, we would use OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT. + // However, the usage of OMMs in the AS build input overwrites flag OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT. + // Instead we use predefined OMM indices to mark the triangles opaque that make use of opaque materials. + OPTIX_GEOMETRY_FLAG_NONE, // opaque material + OPTIX_GEOMETRY_FLAG_NONE, // opaque material + OPTIX_GEOMETRY_FLAG_NONE, // opaque material + OPTIX_GEOMETRY_FLAG_NONE, // opaque material + OPTIX_GEOMETRY_FLAG_NONE // cutout material + }; + + std::array ommUsages ={}; + { + OptixOpacityMicromapUsageCount& ommUsageCheckerboard = ommUsages[0]; + ommUsageCheckerboard.count = 6; // 3 out of 5 sides of a box, 2 triangles per side reference an OMM in the OMM array + ommUsageCheckerboard.format = OPTIX_OPACITY_MICROMAP_FORMAT_2_STATE; // simple 2 state as the OMM perfectly matches the checkerboard pattern. 'unknown' states that are resolved in the anyhit program are not needed. + ommUsageCheckerboard.subdivisionLevel = CHECKERBOARD_OMM_SUBDIV_LEVEL; + } + { + OptixOpacityMicromapUsageCount& ommUsageCirle = ommUsages[1]; + ommUsageCirle.count = 4; // 2 out of 5 sides of a box, 2 triangles per side reference an OMM in the OMM array + ommUsageCirle.format = OPTIX_OPACITY_MICROMAP_FORMAT_4_STATE; // 4 state, some parts need to be resolved in the anyhit program. + ommUsageCirle.subdivisionLevel = CIRCLE_OMM_SUBDIV_LEVEL; + } + + OptixBuildInputOpacityMicromap ommInput ={}; + ommInput.opacityMicromapArray = state.d_omm_array; + ommInput.indexingMode = OPTIX_OPACITY_MICROMAP_ARRAY_INDEXING_MODE_INDEXED; + ommInput.indexSizeInBytes = 2; + ommInput.numMicromapUsageCounts = static_cast(ommUsages.size()); + ommInput.micromapUsageCounts = ommUsages.data(); + + // OMM indexing must be specified for all triangles in this build input. + // Since only the triangles of the small box actually reference OMMs, predefined indices must be used for the other triangles. + // Alternatively, a separate build input can be used for the geometry that uses OMMs (the small box) + // and only that build input references the OMM array. + constexpr unsigned int numTriangles = static_cast(g_vertices.size()) / 3; + constexpr unsigned short opaqueIndex = static_cast( OPTIX_OPACITY_MICROMAP_PREDEFINED_INDEX_FULLY_OPAQUE ); + std::array ommIndices ={ + opaqueIndex, opaqueIndex, // floor + opaqueIndex, opaqueIndex, // ceiling + opaqueIndex, opaqueIndex, // back wall + opaqueIndex, opaqueIndex, // right wall + opaqueIndex, opaqueIndex, // left wall + 0, 1, 0, 1, 2, 3, 0, 1, 2, 3, // small box, three sides use OMMs 0 and 1, two sides of the box (front/back) use OMMs 2 and 3 + opaqueIndex, opaqueIndex, // tall box ... + opaqueIndex, opaqueIndex, + opaqueIndex, opaqueIndex, + opaqueIndex, opaqueIndex, + opaqueIndex, opaqueIndex, + opaqueIndex, opaqueIndex // ceiling light + }; + const size_t omm_indices_size_in_bytes = ommIndices.size() * ommInput.indexSizeInBytes; + CUdeviceptr d_omm_indices = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_omm_indices ), omm_indices_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_omm_indices ), ommIndices.data(), + omm_indices_size_in_bytes, cudaMemcpyHostToDevice ) ); + ommInput.indexBuffer = d_omm_indices; + + OptixBuildInput triangle_input = {}; + triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangle_input.triangleArray.vertexStrideInBytes = sizeof( Vertex ); + triangle_input.triangleArray.numVertices = static_cast( g_vertices.size() ); + triangle_input.triangleArray.vertexBuffers = &state.d_vertices; + triangle_input.triangleArray.flags = triangle_input_flags; + triangle_input.triangleArray.numSbtRecords = TRIANGLE_MAT_COUNT; + triangle_input.triangleArray.sbtIndexOffsetBuffer = d_mat_indices; + triangle_input.triangleArray.sbtIndexOffsetSizeInBytes = sizeof( uint32_t ); + triangle_input.triangleArray.sbtIndexOffsetStrideInBytes = sizeof( uint32_t ); + + triangle_input.triangleArray.opacityMicromap = ommInput; + + OptixAccelBuildOptions accel_options = {}; + // Enable 'OPTIX_BUILD_FLAG_ALLOW_DISABLE_OPACITY_MICROMAPS' for demonstration purposes to allow for toggling between enabling/disabling OMMs at runtime quickly + // we toggle by disabling OMMs at the instance level (using instance flag OPTIX_INSTANCE_FLAG_DISABLE_OPACITY_MICROMAPS) + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION | OPTIX_BUILD_FLAG_ALLOW_DISABLE_OPACITY_MICROMAPS; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( state.context, &accel_options, &triangle_input, + 1, // num_build_inputs + &gas_buffer_sizes ) ); + + CUdeviceptr d_temp_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 + ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( (char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( + state.context, + 0, // CUDA stream + &accel_options, + &triangle_input, + 1, // num build inputs + d_temp_buffer, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &state.triangle_gas_handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_mat_indices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_omm_indices ) ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( + &compacted_gas_size, + (void*)emitProperty.result, + sizeof( size_t ), + cudaMemcpyDeviceToHost + ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_triangle_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, 0, state.triangle_gas_handle, state.d_triangle_gas_output_buffer, compacted_gas_size, &state.triangle_gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + state.d_triangle_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } + } + + // + // Build sphere GAS + // + { + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + // AABB build input + float3 m_min = g_sphere.center - g_sphere.radius; + float3 m_max = g_sphere.center + g_sphere.radius; + OptixAabb aabb = {m_min.x, m_min.y, m_min.z, m_max.x, m_max.y, m_max.z}; + + CUdeviceptr d_aabb_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_aabb_buffer ), sizeof( OptixAabb ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_aabb_buffer ), &aabb, sizeof( OptixAabb ), + cudaMemcpyHostToDevice ) ); + + uint32_t sphere_input_flag = OPTIX_GEOMETRY_FLAG_NONE; + OptixBuildInput sphere_input = {}; + sphere_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES; + sphere_input.customPrimitiveArray.aabbBuffers = &d_aabb_buffer; + sphere_input.customPrimitiveArray.numPrimitives = 1; + sphere_input.customPrimitiveArray.flags = &sphere_input_flag; + sphere_input.customPrimitiveArray.numSbtRecords = 1; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( state.context, + &accel_options, + &sphere_input, + 1, // num_build_inputs + &gas_buffer_sizes ) ); + + CUdeviceptr d_temp_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), compactedSizeOffset + 8 ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( (char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( state.context, + 0, // CUDA stream + &accel_options, + &sphere_input, + 1, // num build inputs + d_temp_buffer, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &state.sphere_gas_handle, + &emitProperty, // emitted property list + 1 ) ); // num emitted properties + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_aabb_buffer ) ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, (void*)emitProperty.result, sizeof( size_t ), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_sphere_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, 0, state.sphere_gas_handle, state.d_sphere_gas_output_buffer, compacted_gas_size, &state.sphere_gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + state.d_sphere_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } + } +} + +void buildCheckerboardOpacityMicromap( CutoutsState& state ) +{ + // Need two histogram entries, one for the checkerboard pattern (combination of OMM format and OMM subdivision level), + // and one for the circular pattern + std::array histogram; + + { + OptixOpacityMicromapHistogramEntry& entry = histogram[0]; + entry.count = 2; + entry.format = OptixOpacityMicromapFormat::OPTIX_OPACITY_MICROMAP_FORMAT_2_STATE; + entry.subdivisionLevel = CHECKERBOARD_OMM_SUBDIV_LEVEL; + } + { + OptixOpacityMicromapHistogramEntry& entry = histogram[1]; + entry.count = 2; + entry.format = OptixOpacityMicromapFormat::OPTIX_OPACITY_MICROMAP_FORMAT_4_STATE; + entry.subdivisionLevel = CIRCLE_OMM_SUBDIV_LEVEL; + } + + constexpr int numCheckerboardMicroTriangles = 1 << ( CHECKERBOARD_OMM_SUBDIV_LEVEL * 2 ); + std::array, 2> ommDataCheckerboard ={}; // 2 OMMs + + constexpr int numCircleMicroTriangles = 1 << ( CIRCLE_OMM_SUBDIV_LEVEL * 2 ); + std::array, 2> ommDataCircle = {}; // 2 OMMs with 2b per state + + CUdeviceptr d_omm_input_data = 0; + const size_t omm_data_checkerboard_size_in_bytes = numCheckerboardMicroTriangles / 8 * 2; // 2 OMMs, 1b per micro triangle + const size_t omm_data_circle_size_in_bytes = numCircleMicroTriangles / 8 * 2 * 2; // 2 OMMs, 2b per micro triangle + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_omm_input_data ), omm_data_checkerboard_size_in_bytes + omm_data_circle_size_in_bytes ) ); + + auto computeUV = []( const float2& bary, const float2* texcoord ) + { + return ( 1 - bary.x - bary.y ) * texcoord[0] + bary.x * texcoord[1] + bary.y * texcoord[2]; + }; + { + // OMMs are used for 'quads' with vertices a,b,c,d as: + // first triangle: a, b, c + // second triangle: a, c, d + +#if 0 + // Knowing the order of the micro triangles, it is possible to hard code the sequence for a checkerboard pattern + + // The simplified, 16 microtriangles example pictured below illustrates the space filling curve. + // + // w | + // / \ | + // v \ | + // x--- | + // \ / \ | + // \ / F \ | + // ---------- | + // \ / \ D / \ | + // \ / E \ / C \ | + // ---------------- | + // \ / \ 4 / \ 6 / \ | + // \ / 3 \ / 5 \ / B \ | + // ---------------------- | + // \ / \ 1 / \ 7 / \ 9 / \ ^ | + // \ / 0 \ / 2 \ / 8 \ / A \ \ | + // x-----------------------x--- v | + // / / / / / | + // u - > | + + unsigned short t00 = 0b1100100111001001; // 1100 1001 1100 1001 + unsigned short t01 = 0b1001110010011100; // 1001 1100 1001 1100 + unsigned short t10 = 0b0101010101010101; // 0101 0101 0101 0101 + for( size_t i = 0; i < ommData[0].size(); ++i ) + { + ommData[0][i] = i&1 ? t01 : t00; + } + for( size_t i = 0; i < ommData[1].size(); ++i ) + { + ommData[1][i] = t10; + } +#else + // Alternatively, one can use the uv values of the triangles to determine the position of the micro triangle and determine the state + // Note that the tex coords (uvs) are in range [0, CHECKERBOARD_SIZE] for the checkerboard in this sample. + ommDataCheckerboard[0].fill( 0 ); + ommDataCheckerboard[1].fill( 0 ); + const float2* tex_coords_t0 = &g_checkerboard_tex_coords[0]; + const float2* tex_coords_t1 = &g_checkerboard_tex_coords[3]; + for( uint32_t uTriI=0; uTriI( d_omm_input_data ), ommDataCheckerboard.data(), + omm_data_checkerboard_size_in_bytes, cudaMemcpyHostToDevice ) ); + } + + { + // Use the uv values of the triangles to determine the position of the micro triangle and determine the state + // Note that the tex coords (uvs) are in range [-1,1] for the circular cutout. + ommDataCircle[0].fill( 0 ); + ommDataCircle[1].fill( 0 ); + const float2* tex_coords_t0 = &g_circle_tex_coords[0]; + const float2* tex_coords_t1 = &g_circle_tex_coords[3]; + for( uint32_t uTriI = 0; uTriI < numCircleMicroTriangles; ++uTriI ) + { + // Opacity micromaps for a circular cutout. + // Note that this computation is assumed to align with the anyhit program (AH). + // While AH only needs to evaluate opacity of a single (intersection) point, in the following we must determine the + // opacity state of the micro triangles, i.e., an area, making the evaluation more involved: + // Check if the micro triangle overlaps the circle, if so, it needs to be marked as 'unknown'. + // If the micro triangle is fully within the circle, it is marked as 'transparent'. + // Otherwise it must be fully outside the circle and can be marked 'opaque'. + + // AH: + // texcoord = t0 * ( 1.0f - barycentrics.x - barycentrics.y ) + t1 * barycentrics.x + t2 * barycentrics.y; + // ignore = ( texcoord.x * texcoord.x + texcoord.y * texcoord.y ) < ( CIRCLE_RADIUS * CIRCLE_RADIUS ); + + auto inCircle = [&]( const float2& uv ) -> bool + { + // check if point uv is in circle with center at [0,0] and radius CIRCLE_RADIUS + return ( uv.x * uv.x + uv.y * uv.y ) < ( CIRCLE_RADIUS * CIRCLE_RADIUS ); + }; + auto edgeIntersectsCircle = [&]( const float2& uv0, const float2& uv1 ) -> bool + { + float2 d = uv1 - uv0; + float2 f = uv0; // circle center is at [0,0] + + float a = dot( d, d ); + float b = 2.f * dot( f, d ); + float c = dot(f, f) - CIRCLE_RADIUS * CIRCLE_RADIUS; + + float discriminant = b * b - 4 * a * c; + if( discriminant < 0 ) + { + // no intersection + return false; + } + else + { + // there is a solution to the equation. + discriminant = sqrtf( discriminant ); + + float t0 = ( -b - discriminant ) / ( 2.f * a ); + float t1 = ( -b + discriminant ) / ( 2.f * a ); + + // check for solutions of the quadratic equation, must be in range [0,1] to be 'within the edge' + if( (t0 >= 0 && t0 <= 1.f) || (t1 >= 0 && t1 <= 1)) + { + return true; + } + + // no intersection: fully in front of, behind, or inside the circe + return false; + } + }; + + float2 bary0, bary1, bary2; + optixMicromapIndexToBaseBarycentrics( uTriI, CIRCLE_OMM_SUBDIV_LEVEL, bary0, bary1, bary2 ); + + auto computeOMMData = [&]( int ommIdx, const float2* tex_coords ) + { + float2 uv0 = computeUV( bary0, tex_coords ); + float2 uv1 = computeUV( bary1, tex_coords ); + float2 uv2 = computeUV( bary2, tex_coords ); + bool isInCircle0 = inCircle( uv0 ); + bool isInCircle1 = inCircle( uv1 ); + bool isInCircle2 = inCircle( uv2 ); + if( isInCircle0 && isInCircle1 && isInCircle2 ) + // this is a nop since ommDataCircle is 0 initialized + ommDataCircle[ommIdx][uTriI / 8] |= OPTIX_OPACITY_MICROMAP_STATE_TRANSPARENT << ( ( uTriI % 8 ) * 2 ); + else if( !isInCircle0 && !isInCircle1 && !isInCircle2 && !edgeIntersectsCircle( uv0, uv1 ) + && !edgeIntersectsCircle( uv1, uv2 ) && !edgeIntersectsCircle( uv2, uv0 ) ) + // if all vertices are outside of the circle and no edge intersects the circle, mark it as opaque + // we do not need to check if the circle is fully contained by the micro triangle as the circle is already cut + // by the triangle that this OMM is applied to. + ommDataCircle[ommIdx][uTriI / 8] |= OPTIX_OPACITY_MICROMAP_STATE_OPAQUE << ( ( uTriI % 8 ) * 2 ); + else + // otherwise, let AH resolve it + ommDataCircle[ommIdx][uTriI / 8] |= OPTIX_OPACITY_MICROMAP_STATE_UNKNOWN_TRANSPARENT << ( ( uTriI % 8 ) * 2 ); + }; + + // first triangle (a,b,c) + computeOMMData( 0, tex_coords_t0 ); + // second triangle (a,c,d) + computeOMMData( 1, tex_coords_t1 ); + } + + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_omm_input_data ) + omm_data_checkerboard_size_in_bytes, ommDataCircle.data(), + omm_data_circle_size_in_bytes, cudaMemcpyHostToDevice ) ); + } + + + OptixOpacityMicromapArrayBuildInput bi = {}; + bi.flags = OPTIX_OPACITY_MICROMAP_FLAG_NONE; + bi.inputBuffer = d_omm_input_data; + bi.numMicromapHistogramEntries = (unsigned)histogram.size(); + bi.micromapHistogramEntries = histogram.data(); + + OptixMicromapBufferSizes bs = {}; + OPTIX_CHECK( optixOpacityMicromapArrayComputeMemoryUsage( state.context, &bi, &bs ) ); + + // this is fairly simple, two OMMs, both with the same layout + std::vector ommDescs = + { + { + 0, + CHECKERBOARD_OMM_SUBDIV_LEVEL, + OPTIX_OPACITY_MICROMAP_FORMAT_2_STATE + }, + { + static_cast(ommDataCheckerboard[0].size() * sizeof(unsigned short) ), + CHECKERBOARD_OMM_SUBDIV_LEVEL, + OPTIX_OPACITY_MICROMAP_FORMAT_2_STATE + }, + { + omm_data_checkerboard_size_in_bytes, + CIRCLE_OMM_SUBDIV_LEVEL, + OPTIX_OPACITY_MICROMAP_FORMAT_4_STATE + }, + { + static_cast(omm_data_checkerboard_size_in_bytes + ommDataCircle[0].size() * sizeof(unsigned short) ), + CIRCLE_OMM_SUBDIV_LEVEL, + OPTIX_OPACITY_MICROMAP_FORMAT_4_STATE + } + }; + + CUdeviceptr d_omm_desc = 0; + const size_t omm_desc_size_in_bytes = ommDescs.size() * sizeof(OptixOpacityMicromapDesc); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_omm_desc ), omm_desc_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_omm_desc ), ommDescs.data(), omm_desc_size_in_bytes, cudaMemcpyHostToDevice ) ); + + bi.perMicromapDescBuffer = d_omm_desc; + bi.perMicromapDescStrideInBytes = 0; + + CUdeviceptr d_temp_buffer = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer ), bs.tempSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_omm_array ), bs.outputSizeInBytes ) ); + + OptixMicromapBuffers uBuffers = {}; + uBuffers.output = state.d_omm_array; + uBuffers.outputSizeInBytes = bs.outputSizeInBytes; + uBuffers.temp = d_temp_buffer; + uBuffers.tempSizeInBytes = bs.tempSizeInBytes; + + OPTIX_CHECK( optixOpacityMicromapArrayBuild( state.context, 0, &bi, &uBuffers ) ); + + cudaFree( reinterpret_cast( d_omm_input_data ) ); + cudaFree( reinterpret_cast( d_omm_desc ) ); + cudaFree( reinterpret_cast( d_temp_buffer ) ); +} + + +void buildInstanceAccel( CutoutsState& state ) +{ + if( state.d_ias_output_buffer ) + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_ias_output_buffer ) ) ); + + CUdeviceptr d_instances; + size_t instance_size_in_bytes = sizeof( OptixInstance ) * 2; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_instances ), instance_size_in_bytes ) ); + + OptixBuildInput instance_input = {}; + + instance_input.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; + instance_input.instanceArray.instances = d_instances; + instance_input.instanceArray.numInstances = 2; + + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_NONE; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes ias_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( state.context, &accel_options, &instance_input, + 1, // num build inputs + &ias_buffer_sizes ) ); + + CUdeviceptr d_temp_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer ), ias_buffer_sizes.tempSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_ias_output_buffer ), ias_buffer_sizes.outputSizeInBytes ) ); + + // Use the identity matrix for the instance transform + Instance instance = { { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 } }; + + OptixInstance optix_instances[2]; + memset( optix_instances, 0, instance_size_in_bytes ); + + optix_instances[0].traversableHandle = state.triangle_gas_handle; + optix_instances[0].flags = ( state.enableOMMs ? OPTIX_INSTANCE_FLAG_NONE : OPTIX_INSTANCE_FLAG_DISABLE_OPACITY_MICROMAPS ) | + ( state.enableAH ? OPTIX_INSTANCE_FLAG_NONE : OPTIX_INSTANCE_FLAG_DISABLE_ANYHIT ); + optix_instances[0].instanceId = 0; + optix_instances[0].sbtOffset = 0; + optix_instances[0].visibilityMask = 1; + memcpy( optix_instances[0].transform, instance.transform, sizeof( float ) * 12 ); + + optix_instances[1].traversableHandle = state.sphere_gas_handle; + optix_instances[1].flags = OPTIX_INSTANCE_FLAG_NONE; + optix_instances[1].instanceId = 1; + optix_instances[1].sbtOffset = TRIANGLE_MAT_COUNT; + optix_instances[1].visibilityMask = 1; + memcpy( optix_instances[1].transform, instance.transform, sizeof( float ) * 12 ); + + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_instances ), &optix_instances, instance_size_in_bytes, + cudaMemcpyHostToDevice ) ); + + OPTIX_CHECK( optixAccelBuild( state.context, + 0, // CUDA stream + &accel_options, + &instance_input, + 1, // num build inputs + d_temp_buffer, + ias_buffer_sizes.tempSizeInBytes, + state.d_ias_output_buffer, + ias_buffer_sizes.outputSizeInBytes, + &state.ias_handle, + nullptr, // emitted property list + 0 // num emitted properties + ) ); + + state.params.handle = state.ias_handle; + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_instances ) ) ); +} + + +void createModule( CutoutsState& state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + state.pipeline_compile_options.usesMotionBlur = false; + state.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING; + state.pipeline_compile_options.numPayloadValues = 2; + state.pipeline_compile_options.numAttributeValues = whitted::NUM_ATTRIBUTE_VALUES; + state.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + state.pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + state.pipeline_compile_options.allowOpacityMicromaps = 1; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixCutouts.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( + state.context, + &module_compile_options, + &state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &state.module + ) ); + + input = sutil::getInputData( nullptr, nullptr, "sphere.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( + state.context, + &module_compile_options, + &state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &state.sphere_module + ) ); +} + + +void createProgramGroups( CutoutsState& state ) +{ + OptixProgramGroupOptions program_group_options = {}; + + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = state.module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.raygen_prog_group ) ); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__radiance"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.radiance_miss_group ) ); + + memset( &miss_prog_group_desc, 0, sizeof( OptixProgramGroupDesc ) ); + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__occlusion"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.occlusion_miss_group ) ); + + OptixProgramGroupDesc hit_prog_group_desc = {}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = state.module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__radiance"; + hit_prog_group_desc.hitgroup.moduleAH = state.module; + + { + hit_prog_group_desc.hitgroup.entryFunctionNameAH = "__anyhit__ah_checkerboard"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &hit_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.triangle_checkerboard_hit_group ) ); + } + { + hit_prog_group_desc.hitgroup.entryFunctionNameAH = "__anyhit__ah_circle"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &hit_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.triangle_circle_hit_group ) ); + } + { + hit_prog_group_desc.hitgroup.entryFunctionNameAH = "__anyhit__ah_checkerboard"; + hit_prog_group_desc.hitgroup.moduleIS = state.sphere_module; + hit_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__sphere"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &hit_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.sphere_checkerboard_hit_group ) ); + } + +} + + +void createPipeline( CutoutsState& state ) +{ + const uint32_t max_trace_depth = 2; + OptixProgramGroup program_groups[] = + { + state.raygen_prog_group, + state.radiance_miss_group, + state.occlusion_miss_group, + state.triangle_checkerboard_hit_group, + state.triangle_circle_hit_group, + state.sphere_checkerboard_hit_group + }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + + OPTIX_CHECK_LOG( optixPipelineCreate( state.context, + &state.pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &state.pipeline ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, state.pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( state.pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 2 // maxTraversableDepth + ) ); +} + + +void createSBT( CutoutsState& state ) +{ + // texture coordinates are custom application state, not part of any primitive data! + const size_t tex_coords_size_in_bytes = g_tex_coords.size() * sizeof( float2 ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_tex_coords ), tex_coords_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( state.d_tex_coords ), g_tex_coords.data(), + tex_coords_size_in_bytes, cudaMemcpyHostToDevice ) ); + + CUdeviceptr d_raygen_record; + const size_t raygen_record_size = sizeof( RayGenRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_raygen_record ), raygen_record_size ) ); + + RayGenRecord rg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( state.raygen_prog_group, &rg_sbt ) ); + rg_sbt.data = {1.0f, 0.f, 0.f}; + + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_raygen_record ), &rg_sbt, raygen_record_size, + cudaMemcpyHostToDevice ) ); + + // two miss programs: + // first for 'radiance' rays, return the 'background' color + // second for 'occlusion' rays, marking a ray as 'unoccluded' if miss is executed. + CUdeviceptr d_miss_records; + const size_t miss_record_size = sizeof( MissRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_miss_records ), miss_record_size * 2 ) ); + + MissRecord ms_sbt[2]; + OPTIX_CHECK( optixSbtRecordPackHeader( state.radiance_miss_group, &ms_sbt[0] ) ); + ms_sbt[0].data = {0.0f, 0.0f, 0.0f}; + OPTIX_CHECK( optixSbtRecordPackHeader( state.occlusion_miss_group, &ms_sbt[1] ) ); + ms_sbt[1].data = {}; // no data needed for occlusion miss program + + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_miss_records ), ms_sbt, miss_record_size * 2, + cudaMemcpyHostToDevice ) ); + + CUdeviceptr d_hitgroup_records; + const size_t hitgroup_record_size = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_hitgroup_records ), + hitgroup_record_size * ( TRIANGLE_MAT_COUNT + SPHERE_MAT_COUNT ) ) ); + + HitGroupRecord hitgroup_records[TRIANGLE_MAT_COUNT + SPHERE_MAT_COUNT]; + + // Set up the HitGroupRecords for the triangle materials + for( int sbt_idx = 0; sbt_idx < TRIANGLE_MAT_COUNT; ++sbt_idx ) + { + // Apply hitgroup with checkerboard cutout in AH as default. + // The last triangle material uses a different hitgroup for the circular cutout, + // this material / sbt is applied to two faces of the small box. + // Both hit groups only differ in the AH though, which is disabled for all triangles referencing materials [0,3]. + // These triangles use OMM predefined index 'opaque'. + OPTIX_CHECK( optixSbtRecordPackHeader( sbt_idx != TRIANGLE_MAT_COUNT - 1 ? state.triangle_checkerboard_hit_group : + state.triangle_circle_hit_group, + &hitgroup_records[sbt_idx] ) ); + hitgroup_records[sbt_idx].data.emission_color = g_emission_colors[sbt_idx]; + hitgroup_records[sbt_idx].data.diffuse_color = g_diffuse_colors[sbt_idx]; + hitgroup_records[sbt_idx].data.vertices = reinterpret_cast( state.d_vertices ); + hitgroup_records[sbt_idx].data.tex_coords = reinterpret_cast( state.d_tex_coords ); + } + + // Set up the HitGroupRecords for the sphere material + for( int sbt_idx = TRIANGLE_MAT_COUNT; sbt_idx < TRIANGLE_MAT_COUNT + SPHERE_MAT_COUNT; ++sbt_idx ) + { + OPTIX_CHECK( optixSbtRecordPackHeader( state.sphere_checkerboard_hit_group, &hitgroup_records[sbt_idx] ) ); + hitgroup_records[sbt_idx].data.emission_color = g_sphere_emission_color; + hitgroup_records[sbt_idx].data.diffuse_color = g_sphere_diffuse_color; + hitgroup_records[sbt_idx].data.geometry_data.setSphere( g_sphere ); + } + + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_hitgroup_records ), hitgroup_records, + hitgroup_record_size * ( TRIANGLE_MAT_COUNT + SPHERE_MAT_COUNT ), + cudaMemcpyHostToDevice ) ); + + state.sbt.raygenRecord = d_raygen_record; + state.sbt.missRecordBase = d_miss_records; + state.sbt.missRecordStrideInBytes = static_cast( miss_record_size ); + state.sbt.missRecordCount = 2; // one for 'radiance' rays and one for 'occlusion' rays + state.sbt.hitgroupRecordBase = d_hitgroup_records; + state.sbt.hitgroupRecordStrideInBytes = static_cast( hitgroup_record_size ); + state.sbt.hitgroupRecordCount = TRIANGLE_MAT_COUNT + SPHERE_MAT_COUNT; +} + + +void cleanupState( CutoutsState& state ) +{ + OPTIX_CHECK( optixPipelineDestroy( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_miss_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.triangle_checkerboard_hit_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.triangle_circle_hit_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.sphere_checkerboard_hit_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.occlusion_miss_group ) ); + OPTIX_CHECK( optixModuleDestroy( state.module ) ); + OPTIX_CHECK( optixModuleDestroy( state.sphere_module ) ); + OPTIX_CHECK( optixDeviceContextDestroy( state.context ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_vertices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_tex_coords ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_omm_array ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_triangle_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_sphere_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.accum_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_params ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_ias_output_buffer ) ) ); +} + + +//------------------------------------------------------------------------------ +// +// Main +// +//------------------------------------------------------------------------------ + +int main( int argc, char* argv[] ) +{ + CutoutsState state; // init with values as specified at definition + state.params.width = 768; + state.params.height = 768; + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::GL_INTEROP; + + // + // Parse command line options + // + std::string outfile; + int32_t file_launch_frames = 16; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--no-gl-interop" ) + { + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + use_pbo = false; + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outfile = argv[++i]; + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + int w, h; + sutil::parseDimensions( dims_arg.c_str(), w, h ); + state.params.width = w; + state.params.height = h; + } + else if( arg == "--launch-samples" || arg == "-s" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + samples_per_launch = atoi( argv[++i] ); + } + else if( arg == "--launch-frames" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + file_launch_frames = max( 1, atoi( argv[++i] ) ); + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + initCameraState(); + + // + // Set up OptiX state + // + createContext ( state ); + buildCheckerboardOpacityMicromap( state ); + buildGeomAccel ( state ); + buildInstanceAccel ( state ); + createModule ( state ); + createProgramGroups ( state ); + createPipeline ( state ); + createSBT ( state ); + initLaunchParams ( state ); + + + if( outfile.empty() ) + { + std::cout << "////////////////////////////////////////////////////////////////////////////////////////////////////////////\n"; + std::cout << "Keys:\n"; + std::cout << " Q Quit sample\n"; + std::cout << " A Toggle usage of anyhit program (AH) on small block (checkerboard and circle cutout)\n"; + std::cout << " O Toggle usage of opacity micromaps (OMM) on small block (checkerboard and circle cutout)\n"; + std::cout << "\n"; + std::cout << "Default: OMMs and AH are enabled.\n"; + std::cout << "Toggle behavior:\n"; + std::cout << "Having OMMs disabled, but AH enabled will cause all hits of the small block to be resolve by AH. This has no visual difference to OMMs and AH being enabled.\n"; + std::cout << "Having OMMs enabled, but AH disabled will turn all micro triangles with opacity states 'opaque' and 'unknown opaque' to opaque, causing a 'jaggy' circular cutout.\n"; + std::cout << "Having both, OMMs and AH disabled will cause all intersections on the small block to be accepted, i.e., fully opaque triangles.\n"; + std::cout << "////////////////////////////////////////////////////////////////////////////////////////////////////////////\n"; + + GLFWwindow* window = sutil::initUI( "optixCutouts", state.params.width, state.params.height ); + glfwSetMouseButtonCallback ( window, mouseButtonCallback ); + glfwSetCursorPosCallback ( window, cursorPosCallback ); + glfwSetWindowSizeCallback ( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback ( window, keyCallback ); + glfwSetScrollCallback ( window, scrollCallback ); + glfwSetWindowUserPointer ( window, &state ); + + // + // Render loop + // + { + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, state.params.width, state.params.height ); + output_buffer.setStream( state.stream ); + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + updateState( output_buffer, state.params ); + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + launchSubframe( output_buffer, state ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1 - t0; + + sutil::displayStats( state_update_time, render_time, display_time ); + + glfwSwapBuffers(window); + + ++state.params.subframe_index; + } + while( !glfwWindowShouldClose( window ) ); + CUDA_SYNC_CHECK(); + } + + sutil::cleanupUI( window ); + } + else + { + if( use_pbo) + { + sutil::initGLFW(); // For GL context + sutil::initGL(); + } + + { + // this scope is for output_buffer, to ensure the destructor is called bfore glfwTerminate() + + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, state.params.width, state.params.height ); + handleCameraUpdate( state.params ); + handleResize( output_buffer, state.params ); + for( int i = 0; i < file_launch_frames; ++i ) + { + updateState( output_buffer, state.params ); + launchSubframe( output_buffer, state ); + ++state.params.subframe_index; + } + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + if (use_pbo) + { + glfwTerminate(); + } + } + + cleanupState( state ); + + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCutouts/optixCutouts.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixCutouts/optixCutouts.cu new file mode 100644 index 00000000..50fce6f1 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCutouts/optixCutouts.cu @@ -0,0 +1,454 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "optixCutouts.h" + +#include +#include +#include + +extern "C" { +__constant__ Params params; +} + + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +struct RadiancePRD +{ + // TODO: move some state directly into payload registers? + float3 emitted; + float3 radiance; + float3 attenuation; + float3 origin; + float3 direction; + unsigned int seed; + int countEmitted; + int done; + int pad; +}; + + +struct Onb +{ + __forceinline__ __device__ Onb( const float3& normal ) + { + m_normal = normal; + + if( fabs( m_normal.x ) > fabs( m_normal.z ) ) + { + m_binormal.x = -m_normal.y; + m_binormal.y = m_normal.x; + m_binormal.z = 0; + } + else + { + m_binormal.x = 0; + m_binormal.y = -m_normal.z; + m_binormal.z = m_normal.y; + } + + m_binormal = normalize( m_binormal ); + m_tangent = cross( m_binormal, m_normal ); + } + + __forceinline__ __device__ void inverse_transform( float3& p ) const + { + p = p.x * m_tangent + p.y * m_binormal + p.z * m_normal; + } + + float3 m_tangent; + float3 m_binormal; + float3 m_normal; +}; + + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +static __forceinline__ __device__ void* unpackPointer( unsigned int i0, unsigned int i1 ) +{ + const unsigned long long uptr = static_cast( i0 ) << 32 | i1; + void* ptr = reinterpret_cast( uptr ); + return ptr; +} + + +static __forceinline__ __device__ void packPointer( void* ptr, unsigned int& i0, unsigned int& i1 ) +{ + const unsigned long long uptr = reinterpret_cast( ptr ); + i0 = uptr >> 32; + i1 = uptr & 0x00000000ffffffff; +} + + +static __forceinline__ __device__ RadiancePRD* getPRD() +{ + const unsigned int u0 = optixGetPayload_0(); + const unsigned int u1 = optixGetPayload_1(); + return reinterpret_cast( unpackPointer( u0, u1 ) ); +} + + +static __forceinline__ __device__ void setPayloadOcclusion( bool occluded ) +{ + optixSetPayload_0( static_cast( occluded ) ); +} + + +static __forceinline__ __device__ void cosine_sample_hemisphere( const float u1, const float u2, float3& p ) +{ + // Uniformly sample disk. + const float r = sqrtf( u1 ); + const float phi = 2.0f * M_PIf * u2; + p.x = r * cosf( phi ); + p.y = r * sinf( phi ); + + // Project up to hemisphere. + p.z = sqrtf( fmaxf( 0.0f, 1.0f - p.x * p.x - p.y * p.y ) ); +} + + +static __forceinline__ __device__ void traceRadiance( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax, + RadiancePRD* prd + ) +{ + unsigned int u0, u1; + packPointer( prd, u0, u1 ); + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_NONE, + 0, // SBT offset + RAY_TYPE_COUNT, // SBT stride + 0, // missSBTIndex + u0, u1 ); +} + + +static __forceinline__ __device__ bool traceOcclusion( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax + ) +{ + unsigned int occluded = 1u; + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT | OPTIX_RAY_FLAG_DISABLE_CLOSESTHIT, + 0, // SBT offset + RAY_TYPE_COUNT, // SBT stride + 1, // missSBTIndex + occluded ); + return occluded; +} + + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +extern "C" __global__ void __raygen__rg() +{ + const int w = params.width; + const int h = params.height; + const float3 eye = params.eye; + const float3 U = params.U; + const float3 V = params.V; + const float3 W = params.W; + const uint3 idx = optixGetLaunchIndex(); + const int subframe_index = params.subframe_index; + + unsigned int seed = tea<4>( idx.y*w + idx.x, subframe_index ); + + float3 result = make_float3( 0.0f ); + int i = params.samples_per_launch; + do + { + // The center of each pixel is at fraction (0.5,0.5) + const float2 subpixel_jitter = make_float2( rnd( seed ), rnd( seed ) ); + + const float2 d = 2.0f * make_float2( + ( static_cast( idx.x ) + subpixel_jitter.x ) / static_cast( w ), + ( static_cast( idx.y ) + subpixel_jitter.y ) / static_cast( h ) + ) - 1.0f; + float3 ray_direction = normalize(d.x*U + d.y*V + W); + float3 ray_origin = eye; + + RadiancePRD prd; + prd.emitted = make_float3(0.f); + prd.radiance = make_float3(0.f); + prd.attenuation = make_float3(1.f); + prd.countEmitted = true; + prd.done = false; + prd.seed = seed; + + int depth = 0; + for( ;; ) + { + traceRadiance( + params.handle, + ray_origin, + ray_direction, + 0.01f, // tmin // TODO: smarter offset + 1e16f, // tmax + &prd ); + + result += prd.emitted; + result += prd.radiance * prd.attenuation; + + if( prd.done || depth >= 10 ) + break; + + // russian roulette in linear color space + const float rr = rnd( prd.seed ); + float lumAttenuation = luminance( prd.attenuation ); + if( lumAttenuation > rr ) + prd.attenuation /= min(1.f, lumAttenuation); + else + break; + + ray_origin = prd.origin; + ray_direction = prd.direction; + + ++depth; + } + } + while( --i ); + + const uint3 launch_index = optixGetLaunchIndex(); + const unsigned int image_index = launch_index.y * params.width + launch_index.x; + float3 accum_color = result / static_cast( params.samples_per_launch ); + + if( subframe_index > 0 ) + { + const float a = 1.0f / static_cast( subframe_index+1 ); + const float3 accum_color_prev = make_float3( params.accum_buffer[ image_index ]); + accum_color = lerp( accum_color_prev, accum_color, a ); + } + params.accum_buffer[ image_index ] = make_float4( accum_color, 1.0f); + params.frame_buffer[ image_index ] = make_color ( accum_color ); +} + + +extern "C" __global__ void __miss__radiance() +{ + MissData* rt_data = reinterpret_cast( optixGetSbtDataPointer() ); + RadiancePRD* prd = getPRD(); + + prd->radiance = make_float3( rt_data->r, rt_data->g, rt_data->b ); + prd->done = true; +} + + +extern "C" __global__ void __anyhit__ah_checkerboard() +{ + const unsigned int hit_kind = optixGetHitKind(); + CutoutsHitGroupData* rt_data = (CutoutsHitGroupData*)optixGetSbtDataPointer(); + const int prim_idx = optixGetPrimitiveIndex(); + + // The texture coordinates are defined per-vertex for built-in triangles, + // and are derived from the surface normal for our custom sphere geometry. + float2 texcoord; + int ignore = 0; + if( optixIsTriangleHit() ) + { + const int vert_idx_offset = prim_idx*3; + const float2 barycentrics = optixGetTriangleBarycentrics(); + + const float2 t0 = rt_data->tex_coords[ vert_idx_offset+0 ]; + const float2 t1 = rt_data->tex_coords[ vert_idx_offset+1 ]; + const float2 t2 = rt_data->tex_coords[ vert_idx_offset+2 ]; + + texcoord = t0 * ( 1.0f - barycentrics.x - barycentrics.y ) + t1 * barycentrics.x + t2 * barycentrics.y; + } + else + { + // assume sphere, could use a custom hit kind to identify the sphere type + const float3 normal = make_float3( __uint_as_float( optixGetAttribute_0() ), + __uint_as_float( optixGetAttribute_1() ), + __uint_as_float( optixGetAttribute_2() ) ); + + // TODO: Pass UV scale in SBT? + const float uv_scale = 16.0f; + const float u = uv_scale * ( 0.5f + atan2f( normal.z, normal.x ) * 0.5f * M_1_PIf ); + const float v = uv_scale * ( 0.5f - asinf( normal.y ) * M_1_PIf ); + texcoord = make_float2( u, v ); + } + ignore = ( static_cast( texcoord.x ) + static_cast( texcoord.y ) ) & 1; + + if( ignore ) + { + optixIgnoreIntersection(); + } +} + +extern "C" __global__ void __anyhit__ah_circle() +{ + CutoutsHitGroupData* rt_data = (CutoutsHitGroupData*)optixGetSbtDataPointer(); + const int prim_idx = optixGetPrimitiveIndex(); + + // The texture coordinates are defined per-vertex for built-in triangles + float2 texcoord; + int ignore = 0; + + const int vert_idx_offset = prim_idx * 3; + const float2 barycentrics = optixGetTriangleBarycentrics(); + + const float2 t0 = rt_data->tex_coords[vert_idx_offset + 0]; + const float2 t1 = rt_data->tex_coords[vert_idx_offset + 1]; + const float2 t2 = rt_data->tex_coords[vert_idx_offset + 2]; + + texcoord = t0 * ( 1.0f - barycentrics.x - barycentrics.y ) + t1 * barycentrics.x + t2 * barycentrics.y; + // circular cutout + ignore = ( texcoord.x * texcoord.x + texcoord.y * texcoord.y ) < ( CIRCLE_RADIUS * CIRCLE_RADIUS ); + + if( ignore ) + { + optixIgnoreIntersection(); + } +} + + + +extern "C" __global__ void __miss__occlusion() +{ + setPayloadOcclusion( false ); +} + + +extern "C" __global__ void __closesthit__radiance() +{ + CutoutsHitGroupData* rt_data = (CutoutsHitGroupData*)optixGetSbtDataPointer(); + RadiancePRD* prd = getPRD(); + + const int prim_idx = optixGetPrimitiveIndex(); + const float3 ray_dir = optixGetWorldRayDirection(); + const int vert_idx_offset = prim_idx*3; + const unsigned int hit_kind = optixGetHitKind(); + + float3 N; + if( optixIsTriangleHit() ) + { + const float3 v0 = make_float3( rt_data->vertices[vert_idx_offset + 0] ); + const float3 v1 = make_float3( rt_data->vertices[vert_idx_offset + 1] ); + const float3 v2 = make_float3( rt_data->vertices[vert_idx_offset + 2] ); + const float3 N_0 = normalize( cross( v1 - v0, v2 - v0 ) ); + + N = faceforward( N_0, -ray_dir, N_0 ); + } + else + { + N = make_float3(__uint_as_float( optixGetAttribute_0() ), + __uint_as_float( optixGetAttribute_1() ), + __uint_as_float( optixGetAttribute_2() )); + } + + prd->emitted = ( prd->countEmitted ) ? rt_data->emission_color : make_float3( 0.0f ); + + const float3 P = optixGetWorldRayOrigin() + optixGetRayTmax() * ray_dir; + + unsigned int seed = prd->seed; + + { + const float z1 = rnd(seed); + const float z2 = rnd(seed); + + float3 w_in; + cosine_sample_hemisphere( z1, z2, w_in ); + Onb onb( N ); + onb.inverse_transform( w_in ); + prd->direction = w_in; + prd->origin = P; + + prd->attenuation *= rt_data->diffuse_color; + prd->countEmitted = false; + } + + const float z1 = rnd(seed); + const float z2 = rnd(seed); + prd->seed = seed; + + ParallelogramLight light = params.light; + const float3 light_pos = light.corner + light.v1 * z1 + light.v2 * z2; + + // Calculate properties of light sample (for area based pdf) + const float Ldist = length(light_pos - P ); + const float3 L = normalize(light_pos - P ); + const float nDl = dot( N, L ); + const float LnDl = -dot( light.normal, L ); + + float weight = 0.0f; + if( nDl > 0.0f && LnDl > 0.0f ) + { + const bool occluded = traceOcclusion( + params.handle, + P, + L, + 0.01f, // tmin + Ldist - 0.01f // tmax + ); + + if( !occluded ) + { + const float A = length(cross(light.v1, light.v2)); + weight = nDl * LnDl * A / (M_PIf * Ldist * Ldist); + } + } + + prd->radiance += light.emission * weight; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixCutouts/optixCutouts.h b/Extern/3rdParty/OptiX/Linux/SDK/optixCutouts/optixCutouts.h new file mode 100644 index 00000000..8bc5386f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixCutouts/optixCutouts.h @@ -0,0 +1,93 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#include + +#include + +#include + +constexpr float CIRCLE_RADIUS = 0.65f; + +enum RayType +{ + RAY_TYPE_RADIANCE = 0, + RAY_TYPE_COUNT +}; + +struct ParallelogramLight +{ + float3 corner; + float3 v1, v2; + float3 normal; + float3 emission; +}; + + +struct Params +{ + float4* accum_buffer; + uchar4* frame_buffer; + unsigned int width; + unsigned int height; + unsigned int samples_per_launch; + unsigned int subframe_index; + + float3 eye; + float3 U; + float3 V; + float3 W; + + ParallelogramLight light; // TODO: make light list + OptixTraversableHandle handle; +}; + + +struct RayGenData +{ + float r, g, b; +}; + + +struct MissData +{ + float r, g, b; +}; + + +struct CutoutsHitGroupData : whitted::HitGroupData +{ + float3 emission_color; + float3 diffuse_color; + float4* vertices; + float2* tex_coords; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/CMakeLists.txt new file mode 100644 index 00000000..ebf48e1e --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/CMakeLists.txt @@ -0,0 +1,37 @@ + +# +# Copyright (c) 2010 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA Corporation and its licensors retain all intellectual property and proprietary +# rights in and to this software, related documentation and any modifications thereto. +# Any use, reproduction, disclosure or distribution of this software and related +# documentation without an express license agreement from NVIDIA Corporation is strictly +# prohibited. +# +# TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* +# AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, +# INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY +# SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT +# LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF +# BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR +# INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGES +# + +# See top level CMakeLists.txt file for documentation of OPTIX_add_sample_executable. + + + +OPTIX_add_sample_executable( optixDenoiser target_name + OptiXDenoiser.h + optixDenoiser.cpp + ) + +set_target_properties( ${target_name} PROPERTIES CXX_STANDARD 14 ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) + + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/OptiXDenoiser.h b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/OptiXDenoiser.h new file mode 100644 index 00000000..d0520fc0 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/OptiXDenoiser.h @@ -0,0 +1,654 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + + +static void context_log_cb( uint32_t level, const char* tag, const char* message, void* /*cbdata*/ ) +{ + if( level < 4 ) + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + +// Create four channel float OptixImage2D with given dimension. Allocate memory on device and +// Copy data from host memory given in hmem to device if hmem is nonzero. +static OptixImage2D createOptixImage2D( unsigned int width, unsigned int height, const float * hmem = nullptr ) +{ + OptixImage2D oi; + + const uint64_t frame_byte_size = width * height * sizeof(float4); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &oi.data ), frame_byte_size ) ); + if( hmem ) + { + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( oi.data ), + hmem, + frame_byte_size, + cudaMemcpyHostToDevice + ) ); + } + oi.width = width; + oi.height = height; + oi.rowStrideInBytes = width*sizeof(float4); + oi.pixelStrideInBytes = sizeof(float4); + oi.format = OPTIX_PIXEL_FORMAT_FLOAT4; + return oi; +} + +// Copy OptixImage2D from src to dest. +static void copyOptixImage2D( OptixImage2D& dest, const OptixImage2D& src ) +{ + CUDA_CHECK( cudaMemcpy( (void*)dest.data, (void*)src.data, src.width * src.height * sizeof( float4 ), cudaMemcpyDeviceToDevice ) ); +} + +class OptiXDenoiser +{ +public: + struct Data + { + uint32_t width = 0; + uint32_t height = 0; + float* color = nullptr; + float* albedo = nullptr; + float* normal = nullptr; + float* flow = nullptr; + float* flowtrust = nullptr; + std::vector< float* > aovs; // input AOVs + std::vector< float* > outputs; // denoised beauty, followed by denoised AOVs + }; + + // Initialize the API and push all data to the GPU -- normaly done only once per session. + // tileWidth, tileHeight: If nonzero, enable tiling with given dimension. + // kpMode: If enabled, use kernel prediction model even if no AOVs are given. + // temporalMode: If enabled, use a model for denoising sequences of images. + // applyFlowMode: Apply flow vectors from current frame to previous image (no denoising). + void init( const Data& data, + unsigned int tileWidth = 0, + unsigned int tileHeight = 0, + bool kpMode = false, + bool temporalMode = false, + bool applyFlowMode = false, + bool upscale2xMode = false, + OptixDenoiserAlphaMode alphaMode = OPTIX_DENOISER_ALPHA_MODE_COPY, + bool specularMode = false ); + + // Execute the denoiser. In interactive sessions, this would be done once per frame/subframe. + void exec(); + + // Update denoiser input data on GPU from host memory. + void update( const Data& data ); + + // Copy results from GPU to host memory. + void getResults(); + + // Return internal guide layer data for temporal models, if available. Returned memory must be freed. + void getInternalGuideLayerData( unsigned char** data, size_t* sizeInBytes ); + + // Cleanup state, deallocate memory -- normally done only once per render session. + void finish(); + +private: + // --- Test flow vectors: Flow is applied to noisy input image and written back to result. + // --- No denoising. + void applyFlow(); + +private: + OptixDeviceContext m_context = nullptr; + OptixDenoiser m_denoiser = nullptr; + OptixDenoiserParams m_params = {}; + + bool m_temporalMode; + bool m_applyFlowMode; + + CUdeviceptr m_intensity = 0; + CUdeviceptr m_avgColor = 0; + CUdeviceptr m_scratch = 0; + uint32_t m_scratch_size = 0; + CUdeviceptr m_state = 0; + uint32_t m_state_size = 0; + + unsigned int m_tileWidth = 0; + unsigned int m_tileHeight = 0; + unsigned int m_overlap = 0; + + OptixDenoiserGuideLayer m_guideLayer = {}; + std::vector< OptixDenoiserLayer > m_layers; + std::vector< float* > m_host_outputs; +}; + +void OptiXDenoiser::init( const Data& data, + unsigned int tileWidth, + unsigned int tileHeight, + bool kpMode, + bool temporalMode, + bool applyFlowMode, + bool upscale2xMode, + OptixDenoiserAlphaMode alphaMode, + bool specularMode ) +{ + SUTIL_ASSERT( data.color ); + SUTIL_ASSERT( data.outputs.size() >= 1 ); + SUTIL_ASSERT( data.width ); + SUTIL_ASSERT( data.height ); + SUTIL_ASSERT_MSG( !data.normal || data.albedo, "Currently albedo is required if normal input is given" ); + SUTIL_ASSERT_MSG( ( tileWidth == 0 && tileHeight == 0 ) || ( tileWidth > 0 && tileHeight > 0 ), "tile size must be > 0 for width and height" ); + + unsigned int outScale = 1; + if( upscale2xMode ) + { + kpMode = true; + outScale = 2; + } + + m_host_outputs = data.outputs; + m_temporalMode = temporalMode; + m_applyFlowMode = applyFlowMode; + + m_tileWidth = tileWidth > 0 ? tileWidth : data.width; + m_tileHeight = tileHeight > 0 ? tileHeight : data.height; + + // + // Initialize CUDA and create OptiX context + // + { + // Initialize CUDA + CUDA_CHECK( cudaFree( nullptr ) ); + + CUcontext cu_ctx = nullptr; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cu_ctx, &options, &m_context ) ); + } + + // + // Create denoiser + // + { + /***** + // Load user provided model if model.bin is present in the currrent directory, + // configuration of filename not done here. + std::ifstream file( "model.bin" ); + if ( file.good() ) { + std::stringstream source_buffer; + source_buffer << file.rdbuf(); + OPTIX_CHECK( optixDenoiserCreateWithUserModel( m_context, (void*)source_buffer.str().c_str(), source_buffer.str().size(), &m_denoiser ) ); + } + else + *****/ + { + OptixDenoiserOptions options = {}; + options.guideAlbedo = data.albedo ? 1 : 0; + options.guideNormal = data.normal ? 1 : 0; + options.denoiseAlpha = alphaMode; + + OptixDenoiserModelKind modelKind; + if( upscale2xMode ) + modelKind = temporalMode ? OPTIX_DENOISER_MODEL_KIND_TEMPORAL_UPSCALE2X : OPTIX_DENOISER_MODEL_KIND_UPSCALE2X; + else if( kpMode || data.aovs.size() > 0 ) + modelKind = temporalMode ? OPTIX_DENOISER_MODEL_KIND_TEMPORAL_AOV : OPTIX_DENOISER_MODEL_KIND_AOV; + else + modelKind = temporalMode ? OPTIX_DENOISER_MODEL_KIND_TEMPORAL : OPTIX_DENOISER_MODEL_KIND_HDR; + OPTIX_CHECK( optixDenoiserCreate( m_context, modelKind, &options, &m_denoiser ) ); + } + } + + + // + // Allocate device memory for denoiser + // + { + OptixDenoiserSizes denoiser_sizes; + + OPTIX_CHECK( optixDenoiserComputeMemoryResources( + m_denoiser, + m_tileWidth, + m_tileHeight, + &denoiser_sizes + ) ); + + if( tileWidth == 0 ) + { + m_scratch_size = static_cast( denoiser_sizes.withoutOverlapScratchSizeInBytes ); + m_overlap = 0; + } + else + { + m_scratch_size = static_cast( denoiser_sizes.withOverlapScratchSizeInBytes ); + m_overlap = denoiser_sizes.overlapWindowSizeInPixels; + } + + if( data.aovs.size() == 0 && kpMode == false ) + { + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &m_intensity ), + sizeof( float ) + ) ); + } + else + { + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &m_avgColor ), + 3 * sizeof( float ) + ) ); + } + + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &m_scratch ), + m_scratch_size + ) ); + + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &m_state ), + denoiser_sizes.stateSizeInBytes + ) ); + + m_state_size = static_cast( denoiser_sizes.stateSizeInBytes ); + + OptixDenoiserLayer layer = {}; + layer.input = createOptixImage2D( data.width, data.height, data.color ); + layer.output = createOptixImage2D( outScale * data.width, outScale * data.height ); + + if( m_temporalMode ) + { + layer.previousOutput = createOptixImage2D( outScale * data.width, outScale * data.height ); + + // This is the first frame, create zero motion vector image. + void* flowmem; + CUDA_CHECK( cudaMalloc( &flowmem, data.width * data.height * sizeof( float4 ) ) ); + CUDA_CHECK( cudaMemset( flowmem, 0, data.width * data.height * sizeof(float4) ) ); + m_guideLayer.flow = {(CUdeviceptr)flowmem, data.width, data.height, (unsigned int)(data.width * sizeof( float4 )), (unsigned int)sizeof( float4 ), OPTIX_PIXEL_FORMAT_FLOAT4 }; + + // Set first frame previous output to noisy input image from first frame + if( !upscale2xMode ) + copyOptixImage2D( layer.previousOutput, layer.input ); + + // Internal guide layer memory set to zero for first frame. + void* internalMemIn = 0; + void* internalMemOut = 0; + size_t internalSize = outScale * data.width * outScale * data.height * denoiser_sizes.internalGuideLayerPixelSizeInBytes; + CUDA_CHECK( cudaMalloc( &internalMemIn, internalSize ) ); + CUDA_CHECK( cudaMalloc( &internalMemOut, internalSize ) ); + CUDA_CHECK( cudaMemset( internalMemIn, 0, internalSize ) ); + + m_guideLayer.previousOutputInternalGuideLayer.data = (CUdeviceptr)internalMemIn; + m_guideLayer.previousOutputInternalGuideLayer.width = outScale * data.width; + m_guideLayer.previousOutputInternalGuideLayer.height = outScale * data.height; + m_guideLayer.previousOutputInternalGuideLayer.pixelStrideInBytes = unsigned( denoiser_sizes.internalGuideLayerPixelSizeInBytes ); + m_guideLayer.previousOutputInternalGuideLayer.rowStrideInBytes = m_guideLayer.previousOutputInternalGuideLayer.width * m_guideLayer.previousOutputInternalGuideLayer.pixelStrideInBytes; + m_guideLayer.previousOutputInternalGuideLayer.format = OPTIX_PIXEL_FORMAT_INTERNAL_GUIDE_LAYER; + + m_guideLayer.outputInternalGuideLayer = m_guideLayer.previousOutputInternalGuideLayer; + m_guideLayer.outputInternalGuideLayer.data = (CUdeviceptr)internalMemOut; + + if( data.flowtrust ) + { + void* ftmem; + CUDA_CHECK( cudaMalloc( &ftmem, data.width * data.height * sizeof( float4 ) ) ); + CUDA_CHECK( cudaMemset( ftmem, 0, data.width * data.height * sizeof( float4 ) ) ); + m_guideLayer.flowTrustworthiness = {(CUdeviceptr)ftmem, data.width, data.height, (unsigned int)(data.width * sizeof( float4 )), (unsigned int)sizeof( float4 ), OPTIX_PIXEL_FORMAT_FLOAT4 }; + } + } + m_layers.push_back( layer ); + + if( data.albedo ) + m_guideLayer.albedo = createOptixImage2D( data.width, data.height, data.albedo ); + if( data.normal ) + m_guideLayer.normal = createOptixImage2D( data.width, data.height, data.normal ); + + for( size_t i=0; i < data.aovs.size(); i++ ) + { + layer = {}; + layer.input = createOptixImage2D( data.width, data.height, data.aovs[i] ); + layer.output = createOptixImage2D( outScale * data.width, outScale * data.height ); + if( m_temporalMode ) + { + // First frame initializaton. + layer.previousOutput = createOptixImage2D( outScale * data.width, outScale * data.height ); + if( !upscale2xMode ) + copyOptixImage2D( layer.previousOutput, layer.input ); + if( specularMode ) + layer.type = OPTIX_DENOISER_AOV_TYPE_SPECULAR; + } + m_layers.push_back( layer ); + } + } + + // + // Setup denoiser + // + { + OPTIX_CHECK( optixDenoiserSetup( + m_denoiser, + nullptr, // CUDA stream + m_tileWidth + 2 * m_overlap, + m_tileHeight + 2 * m_overlap, + m_state, + m_state_size, + m_scratch, + m_scratch_size + ) ); + + + m_params.hdrIntensity = m_intensity; + m_params.hdrAverageColor = m_avgColor; + m_params.blendFactor = 0.0f; + m_params.temporalModeUsePreviousLayers = 0; + } +} + +void OptiXDenoiser::update( const Data& data ) +{ + SUTIL_ASSERT( data.color ); + SUTIL_ASSERT( data.outputs.size() >= 1 ); + SUTIL_ASSERT( data.width ); + SUTIL_ASSERT( data.height ); + SUTIL_ASSERT_MSG( !data.normal || data.albedo, "Currently albedo is required if normal input is given" ); + + m_host_outputs = data.outputs; + + CUDA_CHECK( cudaMemcpy( (void*)m_layers[0].input.data, data.color, data.width * data.height * sizeof( float4 ), cudaMemcpyHostToDevice ) ); + + if( m_temporalMode ) + CUDA_CHECK( cudaMemcpy( (void*)m_guideLayer.flow.data, data.flow, data.width * data.height * sizeof( float4 ), cudaMemcpyHostToDevice ) ); + + if( data.albedo ) + CUDA_CHECK( cudaMemcpy( (void*)m_guideLayer.albedo.data, data.albedo, data.width * data.height * sizeof( float4 ), cudaMemcpyHostToDevice ) ); + + if( data.normal ) + CUDA_CHECK( cudaMemcpy( (void*)m_guideLayer.normal.data, data.normal, data.width * data.height * sizeof( float4 ), cudaMemcpyHostToDevice ) ); + + if( data.flowtrust ) + CUDA_CHECK( cudaMemcpy( (void*)m_guideLayer.flowTrustworthiness.data, data.flowtrust, data.width * data.height * sizeof( float4 ), cudaMemcpyHostToDevice ) ); + + for( size_t i=0; i < data.aovs.size(); i++ ) + CUDA_CHECK( cudaMemcpy( (void*)m_layers[1+i].input.data, data.aovs[i], data.width * data.height * sizeof( float4 ), cudaMemcpyHostToDevice ) ); + + if( m_temporalMode ) + { + OptixImage2D temp = m_guideLayer.previousOutputInternalGuideLayer; + m_guideLayer.previousOutputInternalGuideLayer = m_guideLayer.outputInternalGuideLayer; + m_guideLayer.outputInternalGuideLayer = temp; + + for( size_t i=0; i < m_layers.size(); i++ ) + { + temp = m_layers[i].previousOutput; + m_layers[i].previousOutput = m_layers[i].output; + m_layers[i].output = temp; + } + } + m_params.temporalModeUsePreviousLayers = 1; +} + +void OptiXDenoiser::exec() +{ + if( m_intensity ) + { + OPTIX_CHECK( optixDenoiserComputeIntensity( + m_denoiser, + nullptr, // CUDA stream + &m_layers[0].input, + m_intensity, + m_scratch, + m_scratch_size + ) ); + } + + if( m_avgColor ) + { + OPTIX_CHECK( optixDenoiserComputeAverageColor( + m_denoiser, + nullptr, // CUDA stream + &m_layers[0].input, + m_avgColor, + m_scratch, + m_scratch_size + ) ); + } + + if( m_applyFlowMode ) + { + applyFlow(); + } + else + { + // This sample is always using tiling mode. +#if 0 + OPTIX_CHECK( optixDenoiserInvoke( + m_denoiser, + nullptr, // CUDA stream + &m_params, + m_state, + m_state_size, + &m_guideLayer, + m_layers.data(), + static_cast( m_layers.size() ), + 0, // input offset X + 0, // input offset y + m_scratch, + m_scratch_size + ) ); +#else + OPTIX_CHECK( optixUtilDenoiserInvokeTiled( + m_denoiser, + nullptr, // CUDA stream + &m_params, + m_state, + m_state_size, + &m_guideLayer, + m_layers.data(), + static_cast( m_layers.size() ), + m_scratch, + m_scratch_size, + m_overlap, + m_tileWidth, + m_tileHeight + ) ); +#endif + } + CUDA_SYNC_CHECK(); +} + +inline float catmull_rom( + float p[4], + float t) +{ + return p[1] + 0.5f * t * ( p[2] - p[0] + t * ( 2.f * p[0] - 5.f * p[1] + 4.f * p[2] - p[3] + t * ( 3.f * ( p[1] - p[2]) + p[3] - p[0] ) ) ); +} + +// Apply flow to image at given pixel position (using bilinear interpolation), write back RGB result. +static void addFlow( + float4* result, + const float4* image, + const float4* flow, + unsigned int width, + unsigned int height, + unsigned int x, + unsigned int y ) +{ + float dst_x = float( x ) - flow[x + y * width].x; + float dst_y = float( y ) - flow[x + y * width].y; + + float x0 = dst_x - 1.f; + float y0 = dst_y - 1.f; + + float r[4][4], g[4][4], b[4][4]; + for (int j=0; j < 4; j++) + { + for (int k=0; k < 4; k++) + { + int tx = static_cast( x0 ) + k; + if( tx < 0 ) + tx = 0; + else if( tx >= (int)width ) + tx = width - 1; + + int ty = static_cast( y0 ) + j; + if( ty < 0 ) + ty = 0; + else if( ty >= (int)height ) + ty = height - 1; + + r[j][k] = image[tx + ty * width].x; + g[j][k] = image[tx + ty * width].y; + b[j][k] = image[tx + ty * width].z; + } + } + float tx = dst_x <= 0.f ? 0.f : dst_x - floorf( dst_x ); + + r[0][0] = catmull_rom( r[0], tx ); + r[0][1] = catmull_rom( r[1], tx ); + r[0][2] = catmull_rom( r[2], tx ); + r[0][3] = catmull_rom( r[3], tx ); + + g[0][0] = catmull_rom( g[0], tx ); + g[0][1] = catmull_rom( g[1], tx ); + g[0][2] = catmull_rom( g[2], tx ); + g[0][3] = catmull_rom( g[3], tx ); + + b[0][0] = catmull_rom( b[0], tx ); + b[0][1] = catmull_rom( b[1], tx ); + b[0][2] = catmull_rom( b[2], tx ); + b[0][3] = catmull_rom( b[3], tx ); + + float ty = dst_y <= 0.f ? 0.f : dst_y - floorf( dst_y ); + + result[y * width + x].x = catmull_rom( r[0], ty ); + result[y * width + x].y = catmull_rom( g[0], ty ); + result[y * width + x].z = catmull_rom( b[0], ty ); +} + +// Apply flow from current frame to the previous noisy image. +void OptiXDenoiser::applyFlow() +{ + if( m_layers.size() == 0 ) + return; + + const uint64_t frame_size = m_layers[0].output.width * m_layers[0].output.height; + const uint64_t frame_byte_size = frame_size * sizeof(float4); + + const float4* device_flow = (float4*)m_guideLayer.flow.data; + if( !device_flow ) + return; + float4* flow = new float4[ frame_size ]; + CUDA_CHECK( cudaMemcpy( flow, device_flow, frame_byte_size, cudaMemcpyDeviceToHost ) ); + + float4* image = new float4[ frame_size ]; + float4* result = new float4[frame_size]; + + for( size_t i=0; i < m_layers.size(); i++ ) + { + CUDA_CHECK( cudaMemcpy( image, (float4*)m_layers[i].previousOutput.data, frame_byte_size, cudaMemcpyDeviceToHost ) ); + for( unsigned int y=0; y < m_layers[i].previousOutput.height; y++ ) + for( unsigned int x=0; x < m_layers[i].previousOutput.width; x++ ) + addFlow( result, image, flow, m_layers[i].previousOutput.width, m_layers[i].previousOutput.height, x, y ); + + CUDA_CHECK( cudaMemcpy( (void*)m_layers[i].output.data, result, frame_byte_size, cudaMemcpyHostToDevice ) ); + } + delete[] result; + delete[] image; + delete[] flow; +} + +void OptiXDenoiser::getResults() +{ + const uint64_t frame_byte_size = m_layers[0].output.width*m_layers[0].output.height*sizeof(float4); + for( size_t i=0; i < m_layers.size(); i++ ) + { + CUDA_CHECK( cudaMemcpy( + m_host_outputs[i], + reinterpret_cast( m_layers[i].output.data ), + frame_byte_size, + cudaMemcpyDeviceToHost + ) ); + + // We start with a noisy image in this mode for each frame, otherwise the warped images would accumulate. + if( m_applyFlowMode ) + CUDA_CHECK( cudaMemcpy( (void*)m_layers[i].output.data, + reinterpret_cast( m_layers[i].input.data ), + frame_byte_size, cudaMemcpyDeviceToHost ) ); + } +} + +void OptiXDenoiser::getInternalGuideLayerData( unsigned char** data, size_t* sizeInBytes ) +{ + *data = 0; + *sizeInBytes = 0; + + if( m_guideLayer.outputInternalGuideLayer.data ) + { + *sizeInBytes = m_guideLayer.outputInternalGuideLayer.width * m_guideLayer.outputInternalGuideLayer.height * m_guideLayer.outputInternalGuideLayer.pixelStrideInBytes; + *data = new unsigned char[ *sizeInBytes ]; + CUDA_CHECK( cudaMemcpy( *data, (void*)m_guideLayer.outputInternalGuideLayer.data, *sizeInBytes, cudaMemcpyDeviceToHost ) ); + } +} + +void OptiXDenoiser::finish() +{ + // Cleanup resources + optixDenoiserDestroy( m_denoiser ); + optixDeviceContextDestroy( m_context ); + + CUDA_CHECK( cudaFree(reinterpret_cast(m_intensity)) ); + CUDA_CHECK( cudaFree(reinterpret_cast(m_avgColor)) ); + CUDA_CHECK( cudaFree(reinterpret_cast(m_scratch)) ); + CUDA_CHECK( cudaFree(reinterpret_cast(m_state)) ); + CUDA_CHECK( cudaFree(reinterpret_cast(m_guideLayer.albedo.data)) ); + CUDA_CHECK( cudaFree(reinterpret_cast(m_guideLayer.normal.data)) ); + CUDA_CHECK( cudaFree(reinterpret_cast(m_guideLayer.flow.data)) ); + CUDA_CHECK( cudaFree(reinterpret_cast(m_guideLayer.flowTrustworthiness.data)) ); + CUDA_CHECK( cudaFree(reinterpret_cast(m_guideLayer.previousOutputInternalGuideLayer.data)) ); + CUDA_CHECK( cudaFree(reinterpret_cast(m_guideLayer.outputInternalGuideLayer.data)) ); + for( size_t i=0; i < m_layers.size(); i++ ) + { + CUDA_CHECK( cudaFree(reinterpret_cast(m_layers[i].input.data) ) ); + CUDA_CHECK( cudaFree(reinterpret_cast(m_layers[i].output.data) ) ); + CUDA_CHECK( cudaFree(reinterpret_cast(m_layers[i].previousOutput.data) ) ); + } +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/README.TXT b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/README.TXT new file mode 100644 index 00000000..4155b319 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/README.TXT @@ -0,0 +1,37 @@ +Single frame denoising example. Denoise all AOVs (-A) for a single image: +optixDenoiser -a data/albedo.exr \ + -A data/diffuse.exr -A data/glossy.exr -A data/specular.exr \ + -o result.exr data/beauty.exr + +When adding (compositing) the RGB pixels in the output files + result_diffuse_denoised.exr, result_glossy_denoised.exr and result_specular_denoised.exr, +the resulting image should look very close to result.exr (the denoised beauty layer). + +optixDenoiser -k enables the inference model used for AOVs (so called kernel prediction), +even if no AOVs are given. The beauty layer is always denoised in this model, in addition to the AOVs. +This model preserves colors much better and might remove low frequency noise better compared to the +non-AOV inference model. + +--------------------------------------------------------------------------------------------------- +Temporal denoising using direct prediction: +optixDenoiser -F 1-20 -a motiondata/soane-BSDF-+++.exr \ + -n motiondata/soane-Normal-+++.exr \ + -f motiondata/soane-Flow-+++.exr \ + -o result-+++.exr motiondata/soane-Beauty-+++.exr + +Add -k for selecting the kernel prediction denoising mode instead of direct prediction. + +It is recommended to add -e -8.6 to the command line when creating a clip with ffmpeg (exposure +control). A clip can be created with ffmpeg -i result-%03d.exr soane.mp4 + +To get a clip from the noisy beauty images first multiply the images by pow(2, -8.6) for example +with oiiotool (part of the OpenImageIO library): +oiiotool --frames 1-20 --cmul 2.577163e-3 motiondata/soane-Beauty-%03d.exr -o noisy%03d.exr +ffmpeg -i noisy%03d.exr noisy.mp4 + +--------------------------------------------------------------------------------------------------- +Checking motion vectors: +Add -z to the temporal denoising command line above. With this option flow vectors from frame N +will be applied to the image in frame N-1 to get the frame N image. +Flow vectors are correct when the result image of frame N is almost congruent with the noisy frame N +image (i.e. no shifts). diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/albedo.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/albedo.exr new file mode 100644 index 00000000..982be5d2 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/albedo.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/beauty.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/beauty.exr new file mode 100644 index 00000000..9157a0f1 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/beauty.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/diffuse.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/diffuse.exr new file mode 100644 index 00000000..a17a0e34 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/diffuse.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/glossy.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/glossy.exr new file mode 100644 index 00000000..08edc4ba Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/glossy.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/normal.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/normal.exr new file mode 100644 index 00000000..e35c1a70 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/normal.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/specular.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/specular.exr new file mode 100644 index 00000000..6e85725a Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/data/specular.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-001.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-001.exr new file mode 100644 index 00000000..a59820c1 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-001.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-002.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-002.exr new file mode 100644 index 00000000..32788a27 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-002.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-003.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-003.exr new file mode 100644 index 00000000..4841b3a9 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-003.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-004.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-004.exr new file mode 100644 index 00000000..4ebeaca8 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-004.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-005.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-005.exr new file mode 100644 index 00000000..98139704 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-005.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-006.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-006.exr new file mode 100644 index 00000000..df40972c Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-006.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-007.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-007.exr new file mode 100644 index 00000000..5bfcc154 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-007.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-008.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-008.exr new file mode 100644 index 00000000..8bca35a4 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-008.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-009.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-009.exr new file mode 100644 index 00000000..b5ee17f0 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-009.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-010.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-010.exr new file mode 100644 index 00000000..8beaaf95 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-010.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-011.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-011.exr new file mode 100644 index 00000000..c001bcc3 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-011.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-012.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-012.exr new file mode 100644 index 00000000..cb57f017 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-012.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-013.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-013.exr new file mode 100644 index 00000000..c0039992 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-013.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-014.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-014.exr new file mode 100644 index 00000000..05881bc5 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-014.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-015.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-015.exr new file mode 100644 index 00000000..e54a807f Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-015.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-016.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-016.exr new file mode 100644 index 00000000..9a98ba65 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-016.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-017.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-017.exr new file mode 100644 index 00000000..9cf9aa94 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-017.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-018.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-018.exr new file mode 100644 index 00000000..b2cb4d28 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-018.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-019.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-019.exr new file mode 100644 index 00000000..d19f38c6 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-019.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-020.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-020.exr new file mode 100644 index 00000000..7ffa9319 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-BSDF-020.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-001.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-001.exr new file mode 100644 index 00000000..311163df Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-001.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-002.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-002.exr new file mode 100644 index 00000000..cf3f7d77 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-002.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-003.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-003.exr new file mode 100644 index 00000000..6f856eed Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-003.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-004.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-004.exr new file mode 100644 index 00000000..b5939f50 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-004.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-005.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-005.exr new file mode 100644 index 00000000..19de9aa8 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-005.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-006.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-006.exr new file mode 100644 index 00000000..292961e1 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-006.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-007.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-007.exr new file mode 100644 index 00000000..d018665a Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-007.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-008.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-008.exr new file mode 100644 index 00000000..b18bf7aa Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-008.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-009.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-009.exr new file mode 100644 index 00000000..daa0b519 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-009.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-010.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-010.exr new file mode 100644 index 00000000..4ab9ad01 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-010.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-011.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-011.exr new file mode 100644 index 00000000..cdf52f14 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-011.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-012.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-012.exr new file mode 100644 index 00000000..d0406701 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-012.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-013.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-013.exr new file mode 100644 index 00000000..58e97f6b Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-013.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-014.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-014.exr new file mode 100644 index 00000000..bdf11288 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-014.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-015.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-015.exr new file mode 100644 index 00000000..4b9879aa Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-015.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-016.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-016.exr new file mode 100644 index 00000000..d62657ff Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-016.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-017.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-017.exr new file mode 100644 index 00000000..00853698 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-017.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-018.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-018.exr new file mode 100644 index 00000000..f7079684 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-018.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-019.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-019.exr new file mode 100644 index 00000000..9f54e59b Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-019.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-020.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-020.exr new file mode 100644 index 00000000..95ac0627 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Beauty-020.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-001.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-001.exr new file mode 100644 index 00000000..1f24a2c5 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-001.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-002.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-002.exr new file mode 100644 index 00000000..c8cf720a Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-002.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-003.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-003.exr new file mode 100644 index 00000000..2a2f5b2a Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-003.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-004.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-004.exr new file mode 100644 index 00000000..3a68792f Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-004.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-005.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-005.exr new file mode 100644 index 00000000..3c17481a Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-005.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-006.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-006.exr new file mode 100644 index 00000000..745b2edb Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-006.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-007.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-007.exr new file mode 100644 index 00000000..e0283c91 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-007.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-008.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-008.exr new file mode 100644 index 00000000..ffaa12ef Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-008.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-009.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-009.exr new file mode 100644 index 00000000..d1a69ad1 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-009.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-010.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-010.exr new file mode 100644 index 00000000..050b4763 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-010.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-011.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-011.exr new file mode 100644 index 00000000..a9db756f Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-011.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-012.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-012.exr new file mode 100644 index 00000000..bc97e58f Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-012.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-013.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-013.exr new file mode 100644 index 00000000..8a047d23 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-013.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-014.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-014.exr new file mode 100644 index 00000000..3b5e912a Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-014.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-015.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-015.exr new file mode 100644 index 00000000..76d714f9 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-015.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-016.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-016.exr new file mode 100644 index 00000000..ef25a899 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-016.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-017.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-017.exr new file mode 100644 index 00000000..18136e8a Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-017.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-018.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-018.exr new file mode 100644 index 00000000..260faa7e Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-018.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-019.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-019.exr new file mode 100644 index 00000000..f21ac14f Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-019.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-020.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-020.exr new file mode 100644 index 00000000..ced386d3 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Flow-020.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-001.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-001.exr new file mode 100644 index 00000000..58a351d4 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-001.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-002.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-002.exr new file mode 100644 index 00000000..83d8b07f Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-002.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-003.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-003.exr new file mode 100644 index 00000000..24cdb04b Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-003.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-004.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-004.exr new file mode 100644 index 00000000..58059bdc Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-004.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-005.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-005.exr new file mode 100644 index 00000000..b924f628 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-005.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-006.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-006.exr new file mode 100644 index 00000000..853b1c24 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-006.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-007.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-007.exr new file mode 100644 index 00000000..55376c2e Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-007.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-008.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-008.exr new file mode 100644 index 00000000..c271d7a6 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-008.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-009.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-009.exr new file mode 100644 index 00000000..c9965aa4 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-009.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-010.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-010.exr new file mode 100644 index 00000000..3ec331b0 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-010.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-011.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-011.exr new file mode 100644 index 00000000..2403b762 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-011.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-012.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-012.exr new file mode 100644 index 00000000..a32c7df2 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-012.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-013.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-013.exr new file mode 100644 index 00000000..214ce390 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-013.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-014.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-014.exr new file mode 100644 index 00000000..52bbd648 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-014.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-015.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-015.exr new file mode 100644 index 00000000..38cd1660 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-015.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-016.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-016.exr new file mode 100644 index 00000000..3eb332e3 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-016.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-017.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-017.exr new file mode 100644 index 00000000..96f8d204 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-017.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-018.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-018.exr new file mode 100644 index 00000000..6def8bd0 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-018.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-019.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-019.exr new file mode 100644 index 00000000..2db48239 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-019.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-020.exr b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-020.exr new file mode 100644 index 00000000..e60e8ce2 Binary files /dev/null and b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/motiondata/soane-Normal-020.exr differ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/optixDenoiser.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/optixDenoiser.cpp new file mode 100644 index 00000000..b8f2d8f6 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDenoiser/optixDenoiser.cpp @@ -0,0 +1,449 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "OptiXDenoiser.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + + +//------------------------------------------------------------------------------ +// +// optixDenoiser -- Demonstration of the OptiX denoising API. +// +//------------------------------------------------------------------------------ + +void printUsageAndExit( const std::string& argv0 ) +{ + std::cout << "Usage : " << argv0 << " [options] {-A | --AOV aov.exr} color.exr\n" + << "Options: -n | --normal \n" + << " -a | --albedo \n" + << " -f | --flow \n" + << " -A | --AOV \n" + << " -S \n" + << " -T \n" + << " -o | --out Defaults to 'denoised.exr'\n" + << " -F | --Frames first-last frame number in sequence\n" + << " -e | --exposure apply exposure on output images\n" + << " -t | --tilesize use tiling to save GPU memory\n" + << " -alpha denoise alpha channel\n" + << " -up2 upscale image by factor of 2\n" + << " -z apply flow to input images (no denoising), write output\n" + << " -k use kernel prediction model even if there are no AOVs (default on)\n" + << " -d use direct prediction model\n" + << "in sequences, first occurrence of '+' characters substring in filenames is replaced by framenumber\n" + << std::endl; + exit( 0 ); +} + +// filename is copied to result and the first sequence of "+" characters is +// replaced (using leading zeros) with framename. +// true is returned if the framenumber is -1 or if the function was successful. + +static bool getFrameFilename( std::string& result, const std::string& filename, int frame ) +{ + result = filename; + if( frame == -1 ) + return true; + size_t nplus = 0; + size_t ppos = result.find( '+' ); + if( ppos == std::string::npos ) + return true; // static filename without "+" characters + size_t cpos = ppos; + while( result[cpos] != 0 && result[cpos] == '+' ) + { + nplus++; + cpos++; + } + std::string fn = std::to_string( frame ); + if( fn.length() > nplus ) + { + std::cout << "illegal temporal filename, framenumber requires " << fn.length() + << " digits, \"+\" placeholder length: " << nplus << "too small" << std::endl; + return false; + } + for( size_t i = 0; i < nplus; i++ ) + result[ppos + i] = '0'; + for( size_t i = 0; i < fn.length(); i++ ) + result[ppos + nplus - 1 - i] = fn[fn.length() - 1 - i]; + return true; +} + +int32_t main( int32_t argc, char** argv ) +{ + if( argc < 2 ) + printUsageAndExit( argv[0] ); + std::string color_filename = argv[argc - 1]; + + std::string normal_filename; + std::string albedo_filename; + std::string flow_filename; + std::string flowtrust_filename; + std::string output_filename = "denoised.exr"; + std::vector aov_filenames; + bool kpMode = true; + bool applyFlow = false; + float exposure = 0.f; + int firstFrame = -1, lastFrame = -1; + unsigned int tileWidth = 0, tileHeight = 0; + bool upscale2x = false; + OptixDenoiserAlphaMode alphaMode = OPTIX_DENOISER_ALPHA_MODE_COPY; + bool specularMode = 0; + + for( int32_t i = 1; i < argc - 1; ++i ) + { + std::string arg( argv[i] ); + + if( arg == "-n" || arg == "--normal" ) + { + if( i == argc - 2 ) + printUsageAndExit( argv[0] ); + normal_filename = argv[++i]; + } + else if( arg == "-a" || arg == "--albedo" ) + { + if( i == argc - 2 ) + printUsageAndExit( argv[0] ); + albedo_filename = argv[++i]; + } + else if( arg == "-e" || arg == "--exposure" ) + { + if( i == argc - 2 ) + printUsageAndExit( argv[0] ); + exposure = std::stof( argv[++i] ); + } + else if( arg == "-f" || arg == "--flow" ) + { + if( i == argc - 2 ) + printUsageAndExit( argv[0] ); + flow_filename = argv[++i]; + } + else if( arg == "-T" ) + { + if( i == argc - 2 ) + printUsageAndExit( argv[0] ); + flowtrust_filename = argv[++i]; + } + else if( arg == "-o" || arg == "--out" ) + { + if( i == argc - 2 ) + printUsageAndExit( argv[0] ); + output_filename = argv[++i]; + } + else if( arg == "-t" || arg == "--tilesize" ) + { + if( i == argc - 3 ) + printUsageAndExit( argv[0] ); + tileWidth = atoi( argv[++i] ); + tileHeight = atoi( argv[++i] ); + } + else if( arg == "-A" || arg == "--AOV" ) + { + if( i == argc - 2 ) + printUsageAndExit( argv[0] ); + aov_filenames.push_back( std::string( argv[++i] ) ); + } + else if( arg == "-S" ) + { + if( i == argc - 2 ) + printUsageAndExit( argv[0] ); + aov_filenames.push_back( std::string( argv[++i] ) ); + specularMode = true; + } + else if( arg == "-k" ) + { + kpMode = true; + } + else if( arg == "-d" ) + { + kpMode = false; + } + else if( arg == "-z" ) + { + applyFlow = true; + } + else if( arg == "-up2" ) + { + upscale2x = true; + } + else if( arg == "-alpha" ) + { + alphaMode = OPTIX_DENOISER_ALPHA_MODE_DENOISE; + } + else if( arg == "-F" || arg == "--Frames" ) + { + if( i == argc - 2 ) + printUsageAndExit( argv[0] ); + std::string s( argv[++i] ); + size_t cpos = s.find( '-' ); + if( cpos == 0 || cpos == s.length() - 1 || cpos == std::string::npos ) + printUsageAndExit( argv[0] ); + firstFrame = atoi( s.substr( 0, cpos ).c_str() ); + lastFrame = atoi( s.substr( cpos + 1 ).c_str() ); + if( firstFrame < 0 || lastFrame < 0 || firstFrame > lastFrame ) + { + std::cout << "illegal frame range, first frame must be <= last frame and >= 0" << std::endl; + exit( 0 ); + } + } + else + { + printUsageAndExit( argv[0] ); + } + } + + bool temporalMode = bool( firstFrame != -1 ); + + if( temporalMode && flow_filename.empty() ) + { + std::cout << "temporal mode enabled, flow filename not specified" << std::endl; + exit( 0 ); + } + + sutil::ImageBuffer color = {}; + sutil::ImageBuffer normal = {}; + sutil::ImageBuffer albedo = {}; + sutil::ImageBuffer flow = {}; + sutil::ImageBuffer flowtrust = {}; + + unsigned int outScale = upscale2x ? 2 : 1; + + try + { + OptiXDenoiser denoiser; + for( int frame = firstFrame; frame <= lastFrame; frame++ ) + { + std::vector aovs; + + const double t0 = sutil::currentTime(); + std::cout << "Loading inputs "; + if( frame != -1 ) + std::cout << "for frame " << frame; + std::cout << " ..." << std::endl; + + std::string frame_filename; + if( !getFrameFilename( frame_filename, color_filename, frame ) ) + { + std::cout << "cannot open color file" << std::endl; + exit( 0 ); + } + color = sutil::loadImage( frame_filename.c_str() ); + std::cout << "\tLoaded color image " << frame_filename << " (" << color.width << "x" << color.height << ")" + << std::endl; + + if( !normal_filename.empty() ) + { + if( !getFrameFilename( frame_filename, normal_filename, frame ) ) + { + std::cout << "cannot open normal file" << std::endl; + exit( 0 ); + } + // allocate four channels. only two/three channels used depending on model. + normal = sutil::loadImage( frame_filename.c_str() ); + std::cout << "\tLoaded normal image " << frame_filename << std::endl; + } + + if( !albedo_filename.empty() ) + { + if( !getFrameFilename( frame_filename, albedo_filename, frame ) ) + { + std::cout << "cannot open albedo file" << std::endl; + exit( 0 ); + } + // allocate four channels. only three channels used. + albedo = sutil::loadImage( frame_filename.c_str() ); + std::cout << "\tLoaded albedo image " << frame_filename << std::endl; + } + + if( frame > firstFrame && !flow_filename.empty() ) + { + if( !getFrameFilename( frame_filename, flow_filename, frame ) ) + { + std::cout << "cannot open flow file" << std::endl; + exit( 0 ); + } + // allocate four channels. only two channels used. + // sutil::loadImage handles only 3 and 4 channels. + flow = sutil::loadImage( frame_filename.c_str() ); + std::cout << "\tLoaded flow image " << frame_filename << std::endl; + } + + if( !flowtrust_filename.empty() ) + { + if( !getFrameFilename( frame_filename, flowtrust_filename, frame ) ) + { + std::cout << "cannot open flowTrustworthiness file" << std::endl; + exit( 0 ); + } + // allocate four channels. only three channels used. + flowtrust = sutil::loadImage( frame_filename.c_str() ); + std::cout << "\tLoaded flowTrustworthiness image " << frame_filename << std::endl; + } + + for( size_t i = 0; i < aov_filenames.size(); i++ ) + { + if( !getFrameFilename( frame_filename, aov_filenames[i], frame ) ) + { + std::cout << "cannot open aov file" << std::endl; + exit( 0 ); + } + aovs.push_back( sutil::loadImage( frame_filename.c_str() ) ); + std::cout << "\tLoaded aov image " << frame_filename << std::endl; + } + + const double t1 = sutil::currentTime(); + std::cout << "\tLoad inputs from disk :" << std::fixed << std::setw( 8 ) << std::setprecision( 2 ) + << ( t1 - t0 ) * 1000.0 << " ms" << std::endl; + + SUTIL_ASSERT( color.pixel_format == sutil::FLOAT4 ); + SUTIL_ASSERT( !albedo.data || albedo.pixel_format == sutil::FLOAT4 ); + SUTIL_ASSERT( !normal.data || normal.pixel_format == sutil::FLOAT4 ); + SUTIL_ASSERT( !flow.data || flow.pixel_format == sutil::FLOAT4 ); + for( size_t i = 0; i < aov_filenames.size(); i++ ) + SUTIL_ASSERT( aovs[i].pixel_format == sutil::FLOAT4 ); + + OptiXDenoiser::Data data; + data.width = color.width; + data.height = color.height; + data.color = reinterpret_cast( color.data ); + data.albedo = reinterpret_cast( albedo.data ); + data.normal = reinterpret_cast( normal.data ); + data.flow = reinterpret_cast( flow.data ); + data.flowtrust = reinterpret_cast( flowtrust.data ); + + // set AOVs + for( size_t i = 0; i < aovs.size(); i++ ) + data.aovs.push_back( reinterpret_cast( aovs[i].data ) ); + + // allocate outputs + for( size_t i = 0; i < 1 + aovs.size(); i++ ) + data.outputs.push_back( new float[outScale * color.width * outScale * color.height * 4] ); + + std::cout << "Denoising ..." << std::endl; + + if( frame == firstFrame ) + { + const double t0 = sutil::currentTime(); + denoiser.init( data, tileWidth, tileHeight, kpMode, temporalMode, applyFlow, upscale2x, alphaMode, specularMode ); + const double t1 = sutil::currentTime(); + std::cout << "\tAPI Initialization :" << std::fixed << std::setw( 8 ) << std::setprecision( 2 ) + << ( t1 - t0 ) * 1000.0 << " ms" << std::endl; + } + else + { + denoiser.update( data ); + } + + { + const double t0 = sutil::currentTime(); + denoiser.exec(); + const double t1 = sutil::currentTime(); + std::cout << "\tDenoise frame :" << std::fixed << std::setw( 8 ) << std::setprecision( 2 ) + << ( t1 - t0 ) * 1000.0 << " ms" << std::endl; + } + + { + const double t0 = sutil::currentTime(); + denoiser.getResults(); + const double t1 = sutil::currentTime(); + std::cout << "\tCleanup state/copy to host:" << std::fixed << std::setw( 8 ) << std::setprecision( 2 ) + << ( t1 - t0 ) * 1000.0 << " ms" << std::endl; + } + + // AOVs are not written when speclarMode is set. A single specular AOV is expected in this mode, + // to keep the sample code simple. + size_t numOut = specularMode ? 1 : 1 + aovs.size(); + + { + const double t0 = sutil::currentTime(); + + for( size_t i = 0; i < numOut; i++ ) + { + sutil::ImageBuffer output_image; + output_image.width = outScale * color.width; + output_image.height = outScale * color.height; + output_image.data = data.outputs[i]; + output_image.pixel_format = sutil::FLOAT4; + + frame_filename = output_filename; + getFrameFilename( frame_filename, output_filename, frame ); + if( i > 0 ) + { + std::string basename = aov_filenames[i - 1].substr( aov_filenames[i - 1].find_last_of( "/\\" ) + 1 ); + std::string::size_type const p( basename.find_last_of( '.' ) ); + std::string b = basename.substr( 0, p ); + frame_filename.insert( frame_filename.rfind( '.' ), "_" + b + "_denoised" ); + } + if( exposure != 0.f ) + { + for( unsigned int p = 0; p < output_image.width * output_image.height; p++ ) + { + float* f = &( (float*)output_image.data )[p * 4 + 0]; + f[0] *= std::pow( 2.f, exposure ); + f[1] *= std::pow( 2.f, exposure ); + f[2] *= std::pow( 2.f, exposure ); + } + } + std::cout << "Saving results to '" << frame_filename << "'..." << std::endl; + sutil::saveImage( frame_filename.c_str(), output_image, false ); + } + + const double t1 = sutil::currentTime(); + std::cout << "\tSave output to disk :" << std::fixed << std::setw( 8 ) << std::setprecision( 2 ) + << ( t1 - t0 ) * 1000.0 << " ms" << std::endl; + } + + color.destroy(); + albedo.destroy(); + normal.destroy(); + flow.destroy(); + flowtrust.destroy(); + for( size_t i = 0; i < aovs.size(); i++ ) + aovs[i].destroy(); + for( size_t i = 0; i < 1 + aovs.size(); i++ ) + delete[]( data.outputs[i] ); + } + + denoiser.finish(); + } + catch( std::exception& e ) + { + std::cerr << "ERROR: exception caught '" << e.what() << "'" << std::endl; + } +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDisplacedMicromesh/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixDisplacedMicromesh/CMakeLists.txt new file mode 100644 index 00000000..8d645350 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDisplacedMicromesh/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +OPTIX_add_sample_executable( optixDisplacedMicromesh target_name + ${SAMPLES_DIR}/sutil/CuBuffer.h + optixDisplacedMicromesh.cu + optixDisplacedMicromesh.cpp + optixDisplacedMicromesh.h + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} ${CUDA_LIBRARIES} ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDisplacedMicromesh/optixDisplacedMicromesh.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixDisplacedMicromesh/optixDisplacedMicromesh.cpp new file mode 100644 index 00000000..ed2838df --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDisplacedMicromesh/optixDisplacedMicromesh.cpp @@ -0,0 +1,1245 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include // Needs to be included before gl_interop + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "optixDisplacedMicromesh.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +//------------------------------------------------------------------------------ +// +// Local types +// +//------------------------------------------------------------------------------ + +#define MB( X ) X.byteSize() / 1024 / 1024.f + +template +struct Record +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef Record RayGenRecord; +typedef Record MissRecord; +typedef Record HitGroupRecord; + +struct AS +{ + CuBuffer<> d_data; + OptixTraversableHandle handle; +}; + +struct MeshData +{ + unsigned int numTriangles; + std::vector positions; + std::vector uvs; + AS gas; + AS ias; + + struct DmmArray + { + CuBuffer<> d_dmmArrayData; + OptixDisplacementMicromapUsageCount usage; + OptixDisplacementMicromapHistogramEntry histogram; + } dmmArray; +}; + +struct DisplacedMicromeshState +{ + OptixDeviceContext context = 0; + + CuBuffer accumBuffer; + + MeshData mesh; + + unsigned int geomFlags = OPTIX_GEOMETRY_FLAG_NONE; + unsigned int buildFlags = 0; + + OptixModule module = 0; + OptixModule builtinModule = 0; + OptixPipelineCompileOptions pipeline_compile_options = {}; + OptixPipeline pipeline = 0; + + OptixProgramGroup raygen_prog_group = 0; + OptixProgramGroup miss_group = 0; + OptixProgramGroup miss_group_occlusion = 0; + OptixProgramGroup hit_group = 0; + + CUstream stream = 0; + Globals params; + CuBuffer d_params; + + OptixShaderBindingTable sbt = {}; + CuBuffer d_sbtRg; + CuBuffer d_sbtMs; + CuBuffer d_sbtHit; + + bool enableDMMs = true; + int dmmSubdivisionLevel = 3; + float displacementScale = 1.0f; + + bool render = true; + bool renderAO = true; +}; + +bool resize_dirty = false; +bool minimized = false; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Mouse state +int32_t mouse_button = -1; + +void createBuiltinModule( DisplacedMicromeshState& state, OptixPrimitiveType type ); +void createModule( DisplacedMicromeshState& state ); +void createProgramGroups( DisplacedMicromeshState& state ); +void createPipeline( DisplacedMicromeshState& state ); +void buildMeshAccel( DisplacedMicromeshState& state ); +void createSBT( DisplacedMicromeshState& state ); +void update( DisplacedMicromeshState& state ); +void launch( DisplacedMicromeshState& state ); +void renderFrame( sutil::CUDAOutputBuffer& output_buffer, DisplacedMicromeshState& state ); + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + uint32_t ixpos = static_cast( xpos ); + uint32_t iypos = static_cast( ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking( ixpos, iypos ); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + DisplacedMicromeshState& state = *static_cast( glfwGetWindowUserPointer( window ) ); + Globals& params = state.params; + + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast< int >( xpos ), static_cast< int >( ypos ), params.width, params.height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast< int >( xpos ), static_cast< int >( ypos ), params.width, params.height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + Globals& params = static_cast< DisplacedMicromeshState* >( glfwGetWindowUserPointer( window ) )->params; + params.width = res_x; + params.height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t mods ) +{ + DisplacedMicromeshState& state = *static_cast( glfwGetWindowUserPointer( window ) ); + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + } + else if( key == GLFW_KEY_KP_1 ) + { + state.dmmSubdivisionLevel = max( 0, state.dmmSubdivisionLevel - 1 ); + std::cout << "DMM subdivision levels: " << state.dmmSubdivisionLevel << std::endl; + buildMeshAccel( state ); + update( state ); + } + else if( key == GLFW_KEY_KP_2 ) + { + state.dmmSubdivisionLevel = min( 5, state.dmmSubdivisionLevel + 1 ); + std::cout << "DMM subdivision levels: " << state.dmmSubdivisionLevel << std::endl; + buildMeshAccel( state ); + update( state ); + } + else if( key == GLFW_KEY_KP_4 ) + { + state.displacementScale /= 1.5f; + std::cout << "displacement Scale: " << state.displacementScale << std::endl; + buildMeshAccel( state ); + update( state ); + } + else if( key == GLFW_KEY_KP_5 ) + { + state.displacementScale *= 1.5f; + std::cout << "displacement Scale: " << state.displacementScale << std::endl; + buildMeshAccel( state ); + update( state ); + } + else if( key == GLFW_KEY_D ) + { + state.enableDMMs = !state.enableDMMs; + std::cout << "enable DMMs: " << state.enableDMMs << std::endl; + + buildMeshAccel( state ); + /// Note that getting a built-in IS for triangle and displaced micro-mesh triangle primitives is possible, but not required. + /// Skip overhead of getting the IS module, creating program groups and a pipeline as well as updating the SBT + //createBuiltinModule( state, state.enableDMMs ? OPTIX_PRIMITIVE_TYPE_DISPLACED_MICROMESH_TRIANGLE : OPTIX_PRIMITIVE_TYPE_TRIANGLE ); + //createProgramGroups( state ); + //createPipeline( state ); + //createSBT( state ); + + update( state ); + } + else if( key == GLFW_KEY_A ) + { + state.renderAO = !state.renderAO; + + createModule( state ); + createProgramGroups( state ); + createPipeline( state ); + createSBT( state ); + + state.params.ao = state.renderAO; + update( state ); + } + else if( key == GLFW_KEY_R ) + { + createModule( state ); + createProgramGroups( state ); + createPipeline( state ); + createSBT( state ); + + update( state ); + } +} + + +static void scrollCallback( GLFWwindow* window, double xscroll, double yscroll ) +{ + if( trackball.wheelEvent( ( int )yscroll ) ) + camera_changed = true; +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// +//------------------------------------------------------------------------------ + +float randf() +{ + return static_cast( rand() ) / static_cast( RAND_MAX ); +} + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --time | -t Animation time for image output (default 1)\n"; + std::cerr << " --frames | -n Number of animation frames for image output (default 16)\n"; + std::cerr << " --no-gl-interop Disable GL interop for display\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 1024x768\n"; + std::cerr << " --help | -h Print this usage message\n"; + exit( 0 ); +} + +void update( DisplacedMicromeshState& state ) +{ + state.accumBuffer.allocIfRequired( state.params.width * state.params.height ); + state.accumBuffer.memset( 0 ); + state.params.accum_buffer = state.accumBuffer.get(); + state.params.subframe_index = 0u; + +} + +void initLaunchGlobals( DisplacedMicromeshState& state ) +{ + state.params.frame_buffer = nullptr; // Will be set when output buffer is mapped + state.params.subframe_index = 0u; + state.params.spp = 1u; + state.params.ao = true; + + CUDA_CHECK( cudaStreamCreate( &state.stream ) ); + state.d_params.alloc( 1 ); + update( state ); +} + +void handleResize( DisplacedMicromeshState& state, sutil::CUDAOutputBuffer& output_buffer ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + output_buffer.resize( state.params.width, state.params.height ); + update( state ); +} + +void launch( DisplacedMicromeshState& state ) +{ + state.d_params.uploadAsync( state.params, state.stream ); + + OPTIX_CHECK( optixLaunch( + state.pipeline, + state.stream, + state.d_params.getCU(), + state.d_params.byteSize(), + &state.sbt, + state.params.width, + state.params.height, + 1 + ) ); +} + +void renderFrame( sutil::CUDAOutputBuffer& output_buffer, DisplacedMicromeshState& state ) +{ + uchar4* result_buffer_data = output_buffer.map(); + state.params.frame_buffer = result_buffer_data; + + launch( state ); + + output_buffer.unmap(); +} + +void displaySubframe( sutil::CUDAOutputBuffer& output_buffer, sutil::GLDisplay& gl_display, GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( + output_buffer.width(), + output_buffer.height(), + framebuf_res_x, + framebuf_res_y, + output_buffer.getPBO() + ); +} + + +void initCameraState() +{ + camera.setEye( make_float3( 50, 50, 0 ) + (make_float3( -1.f, -3.f, 2.f )*50) ); + camera.setLookat( make_float3( 50, 50, 0 ) ); + camera.setUp( make_float3( 0.0f, 0.0f, 1.0f ) ); + camera.setFovY( 35.0f ); + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( + make_float3( 0.0f, 1.0f, 0.0f ), + make_float3( 1.0f, 0.0f, 0.0f ), + make_float3( 0.0f, 0.0f, 1.0f ) + ); + trackball.setGimbalLock( true ); +} + +void handleCameraUpdate( DisplacedMicromeshState& state ) +{ + if( !camera_changed ) + return; + camera_changed = false; + + Globals& params = state.params; + camera.setAspectRatio( static_cast( params.width ) / static_cast( params.height ) ); + params.eye = camera.eye(); + camera.UVWFrame( params.U, params.V, params.W ); + update( state ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n"; +} + +void createContext( DisplacedMicromeshState& state ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cu_ctx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cu_ctx, &options, &context ) ); + + state.context = context; +} + +struct DisplacementBlock64MicroTris64B +{ + // 45 displacement values, implicit vertices + // 11 bits per displacement values, tightly packed + // -> 64 bytes per block + uint8_t data[64]; + + // packs the 11 lower bits of the displacement value into the displacement block + // vertexIdx must be in range [0,44] + inline void setDisplacement( unsigned vertexIdx, uint16_t displacement ) + { + constexpr unsigned bitWidth = 11; + + unsigned bitOfs = bitWidth * vertexIdx; + unsigned valueOfs = 0; + + while( valueOfs < bitWidth ) + { + unsigned num = ( ~bitOfs & 7 ) + 1; + if( bitWidth - valueOfs < num ) + num = bitWidth - valueOfs; + + unsigned mask = ( 1u << num ) - 1u; + int idx = bitOfs >> 3; + int shift = bitOfs & 7; + + unsigned bits = (unsigned)( displacement >> valueOfs ) & mask; // extract bits from the input value + data[idx] &= ~( mask << shift ); // clear bits in memory + data[idx] |= bits << shift; // insert bits into memory + + valueOfs += num; + bitOfs += num; + } + } + + // The displacement values of the block follow a hierarchical order: + // The first three values correspond to the vertices of the sub triangle this block is applied to. (subdivision level 0) + // The following three values correspond to the vertices when splitting the edges of the sub triangle. (subdivision level 1) + // Afterwards all the remaining values of the vertices for subdivision level 2 follow and so on. + + // The hierarchical subdivision is executed by splitting upright triangles. + // New vertices are introduced in the following order: + // 1. splitting edge u + // 2. splitting edge w + // 3. splitting edge v + // + // 2 2 | + // / \ / \ | + // / \ / \ | + // / \ / \ | + // / \ / \ | + // / \ / \ | + // u / \ w 3-----------4 | + // / \ / \ / \ | + // / \ / \ / \ | + // / \ / \ / \ | + // / \ / \ / \ | + // / \ / \ / \ | + // 0-----------------------1 0-----------5-----------1 | + // v | + + // Hierarchical splitting is done by looping over the triangles in a hierarchical space filling order, introducing new vertices as shown above for all upright triangles. + // First triangle A, then C, then D. + // B is skipped as an non-upright triangle. + // + // 2 2 2 2 2 | + // / \ / \ / \ / \ / \ | + // / \ / \ / \ / \ / \ | + // / \ / ^ \ / \ / \ 12----13 | + // / \ / / D \ / D \ / D \ / \ / \ | + // / \ / <---- \ / \ / \ / \ / \ | + // / \ 3-----------4 3-----------4 3-----------4 3-----14----4 | + // / \ / \ ----> / \ / \ / \ / \ / \ / \ / \ / \ | + // / \ / \ B / / \ / \ / \ / \ / \ / \ / \ / \ | + // / \ / ^ \ v / ^ \ 6-----7 / \ 6-----7-----9-----10 6-----7-----9-----10 | + // / \ / A \ \ / C \ \ / \ / \ / C \ / \ / \ / \ / \ / \ / \ / \ / \ | + // / \ / ----> \ / ----> \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ | + // 0-----------------------1 0-----------5-----------1 0-----8-----5-----------1 0-----8-----5-----11----1 0-----8-----5-----11----1 | + // + // Equally, values for subdivision level 3 are added by bisecting the edges of the upright triangles in the space filling order of triangles: + // A, C, D, F, I, K, L, M, O, P (10 * 3 new values) + // + // 2 2 2 | + // / \ / \ / \ | + // / \ xx--xx 42--43 | + // / P \ / \ / \ / \ / \ | + // 12------13 12--xx--13 12--44--13 | + // / \ N / \ / \ / \ / \ / \ / \ / \ | + // / \ / \ xx--xx--xx--xx 39--40--36--37 | + // / O \ / M \ / \ / \ / \ / \ / \ / \ / \ / \ | + // 3-------14------4 3---xx--14--xx--4 3---41--14--38--4 | + // / \ E / \ G / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ | + // / \ / \ / \ xx--xx--xx--xx--xx--xx 21--22--24--25--33--34 | + // / D \ / F \ / L \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ | + // 6-------7-------9-------10 6---xx--7---xx--9---xx--10 6---23--7---26--9---35--10 | + // / \ B / \ H / \ J / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ | + // / \ / \ / \ / \ 15--16--xx--xx--xx--xx--xx--xx 15--16--18--19--27--28--30--31 | + // / A \ / C \ / I \ / K \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ | + // 0-------8-------5-------11------1 0---17--8---xx--5---xx--11--xx--1 0---17--8---20--5---29--11--32--1 | + // | +}; + + +void buildDMMArray( OptixDeviceContext context, CUstream cuStream, CuBuffer<>& buildTemp, MeshData& mesh, unsigned int dmmSubdivisionLevel ) +{ + // Based on the subdivision level [0,5], we compute the number of sub triangles. + // In this sample, we fix the format to OPTIX_DISPLACEMENT_MICROMAP_FORMAT_64_MICRO_TRIS_64_BYTES, which corresponds to 1 sub triangle at subdivision levels 0-3. + // Level 4 requires 4 sub triangles, level 5 requires 16 sub triangles. + const unsigned int dmmSubdivisionLevelSubTriangles = max( 0, (int)dmmSubdivisionLevel - 3 ); + const unsigned int numSubTrianglesPerBaseTriangle = 1 << ( 2 * dmmSubdivisionLevelSubTriangles ); + constexpr int subTriSizeByteSize = 64; // 64B for format OPTIX_DISPLACEMENT_MICROMAP_FORMAT_64_MICRO_TRIS_64_BYTES + + const unsigned int numTriangles = mesh.numTriangles; + const unsigned int numSubTriangles = numTriangles * numSubTrianglesPerBaseTriangle; + + // For the sake of simplicity we fill in the following DMM data (directions, displacement values, descriptors) on host. + // If not read directly from file, one would otherwise compute/fill these in in a CUDA kernel. + + std::vector displacementValues( numSubTriangles ); // One displacement block per sub triangle! + + // mapping the max input value in float to the max value in 11b + constexpr float maxDisplacement = 1.f; + constexpr float maxOverMaxDisp = 0x7FF / maxDisplacement; + + auto proceduralSineDisplacement = [&maxOverMaxDisp]( const float2& uv ) -> uint16_t + { + // Compute procedural displacement for a simple sine wave + // 1. map uv [0,1] to [-1,1] range + float2 pos = 2 * uv - 1.f; + // 2. distance to center + float d = sqrtf( pos.x * pos.x + pos.y * pos.y ); + // 3. sine wave with output in range [0,1] + float h = sinf( d * M_PIf * 10 ) * 0.5f + 0.5f; + // Quantization from float to 11b values, note that the rounding is up to the application. + return uint16_t( h * maxOverMaxDisp ); + }; + + // Instead of filling a displacement block in the hierarchical order as specified above (memory layout of the block), a simple lookup table + // is used specify the displacement values in a u-major order (u edge connects vertices 0/2) + // + // Offset into vertex index LUT (u major to hierarchical order) for subdivision levels 0 to 3 + // 6 values for subdiv lvl 1 + // 15 values for subdiv lvl 2 + // 45 values for subdiv lvl 3 + static const uint16_t UMAJOR_TO_HIERARCHICAL_VTX_IDX_LUT_OFFSET[5] ={ 0, 3, 9, 24, 69 }; + // LUTs for levels [0,3] + static const uint16_t UMAJOR_TO_HIERARCHICAL_VTX_IDX_LUT[69] ={ + // level 0 + 0, 2, 1, + // level 1 + 0, 3, 2, 5, 4, 1, + // level 2 + 0, 6, 3, 12, 2, 8, 7, 14, 13, 5, 9, 4, 11, 10, 1, + // level 3 + 0, 15, 6, 21, 3, 39, 12, 42, 2, 17, 16, 23, 22, 41, 40, 44, 43, 8, 18, 7, 24, 14, 36, 13, 20, 19, 26, 25, + 38, 37, 5, 27, 9, 33, 4, 29, 28, 35, 34, 11, 30, 10, 32, 31, 1 }; + + for( unsigned int triIdx=0; triIdx descriptors( numTriangles ); + for( unsigned int i = 0; i < numTriangles; ++i ) + { + OptixDisplacementMicromapDesc& desc = descriptors[i]; + desc.byteOffset = i * subTriSizeByteSize * numSubTrianglesPerBaseTriangle; + desc.format = OPTIX_DISPLACEMENT_MICROMAP_FORMAT_64_MICRO_TRIS_64_BYTES; + desc.subdivisionLevel = dmmSubdivisionLevel; + } + + CuBuffer d_descriptors( descriptors ); + CuBuffer d_displacementsValues( displacementValues ); + bi.perDisplacementMicromapDescBuffer = d_descriptors.getCU(); + bi.displacementValuesBuffer = d_displacementsValues.getCU(); + + dmm.d_dmmArrayData.allocIfRequired( bs.outputSizeInBytes ); + buildTemp.allocIfRequired( bs.tempSizeInBytes ); + + OptixMicromapBuffers uBuffers ={}; + uBuffers.output = dmm.d_dmmArrayData.getCU(); + uBuffers.outputSizeInBytes = dmm.d_dmmArrayData.byteSize(); + uBuffers.temp = buildTemp.getCU(); + uBuffers.tempSizeInBytes = buildTemp.byteSize(); + + optixDisplacementMicromapArrayBuild( context, cuStream, &bi, &uBuffers ); +} + +void buildAndCompact( OptixDeviceContext context, + CUstream cuStream, + CuBuffer<>& temp, + CuBuffer<>& output, + OptixTraversableHandle& handle, + const OptixAccelBuildOptions& asOptions, + const std::vector& bi ) +{ + OptixAccelBufferSizes bufferSizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( context, &asOptions, bi.data(), (unsigned int)bi.size(), &bufferSizes ) ); + + if( asOptions.buildFlags & OPTIX_BUILD_FLAG_ALLOW_COMPACTION ) + { + size_t outputOffset; + size_t compactedSizeOffset; + temp.allocIfRequired( temp.pool( bufferSizes.tempSizeInBytes, bufferSizes.outputSizeInBytes, OPTIX_ACCEL_BUFFER_BYTE_ALIGNMENT, + outputOffset, sizeof( size_t ), sizeof( size_t ), compactedSizeOffset ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = temp.getCU( compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( context, cuStream, &asOptions, bi.data(), (unsigned int)bi.size(), temp.getCU(), + bufferSizes.tempSizeInBytes, temp.getCU( outputOffset ), + bufferSizes.outputSizeInBytes, &handle, &emitProperty, 1 ) ); + + size_t compactedASSize = 0; + CUDA_CHECK( cudaMemcpy( &compactedASSize, (void*)emitProperty.result, sizeof( size_t ), cudaMemcpyDeviceToHost ) ); + + output.alloc( compactedASSize ); + OPTIX_CHECK( optixAccelCompact( context, cuStream, handle, output.getCU(), output.byteSize(), &handle ) ); + } + else + { + temp.allocIfRequired( bufferSizes.tempSizeInBytes ); + output.allocIfRequired( bufferSizes.outputSizeInBytes ); + + OPTIX_CHECK( optixAccelBuild( context, cuStream, &asOptions, bi.data(), (unsigned int)bi.size(), temp.getCU(), + bufferSizes.tempSizeInBytes, output.getCU(), bufferSizes.outputSizeInBytes, &handle, 0, 0 ) ); + } +}; + +void buildMeshAccel( DisplacedMicromeshState& state ) +{ + CuBuffer<> buildTemp; + + unsigned int numQuadsPerAxis = 4; // number of quads per dimension (for a flat surface) + unsigned int numQuads = numQuadsPerAxis * numQuadsPerAxis; + state.mesh.numTriangles = numQuads * 2; + + if( state.mesh.positions.empty() ) + { + state.mesh.positions.resize( state.mesh.numTriangles * 3 ); + state.mesh.uvs.resize( state.mesh.numTriangles * 3 ); + + // vertex and uv generation for flat quads + for( unsigned quadU = 0; quadU < numQuadsPerAxis; ++quadU ) + { + for( unsigned quadV = 0; quadV < numQuadsPerAxis; ++quadV ) + { + // 2 triangles per quad, 3 positions per triangle + state.mesh.uvs[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 0] ={ (quadU+0) / (float)numQuadsPerAxis, (quadV+0) / (float)numQuadsPerAxis }; + state.mesh.uvs[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 1] ={ (quadU+1) / (float)numQuadsPerAxis, (quadV+0) / (float)numQuadsPerAxis }; + state.mesh.uvs[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 2] ={ (quadU+1) / (float)numQuadsPerAxis, (quadV+1) / (float)numQuadsPerAxis }; + state.mesh.uvs[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 3] ={ (quadU+0) / (float)numQuadsPerAxis, (quadV+0) / (float)numQuadsPerAxis }; + state.mesh.uvs[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 4] ={ (quadU+1) / (float)numQuadsPerAxis, (quadV+1) / (float)numQuadsPerAxis }; + state.mesh.uvs[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 5] ={ (quadU+0) / (float)numQuadsPerAxis, (quadV+1) / (float)numQuadsPerAxis }; + + // a simple tesselated quad, use UVs for position generation + state.mesh.positions[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 0] = make_float3( state.mesh.uvs[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 0] * 100, 0 ); + state.mesh.positions[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 1] = make_float3( state.mesh.uvs[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 1] * 100, 0 ); + state.mesh.positions[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 2] = make_float3( state.mesh.uvs[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 2] * 100, 0 ); + state.mesh.positions[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 3] = make_float3( state.mesh.uvs[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 3] * 100, 0 ); + state.mesh.positions[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 4] = make_float3( state.mesh.uvs[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 4] * 100, 0 ); + state.mesh.positions[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 5] = make_float3( state.mesh.uvs[(quadU*numQuadsPerAxis + quadV) * 2 * 3 + 5] * 100, 0 ); + } + } + } + + if( state.enableDMMs ) + buildDMMArray( state.context, state.stream, buildTemp, state.mesh, state.dmmSubdivisionLevel ); + + OptixBuildInput buildInput = {}; + std::vector flags; + + // only needed for GAS build + // this buffer needs to be alive over the GAS build + CuBuffer d_positions( state.mesh.positions ); + + unsigned int geomFlags = OPTIX_GEOMETRY_FLAG_NONE; + + { + // Build an AS over the triangles. + // These are the basic information for non-indexed static triangles + buildInput.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + buildInput.triangleArray.flags = &geomFlags; + buildInput.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + buildInput.triangleArray.vertexStrideInBytes = d_positions.stride(); + buildInput.triangleArray.numVertices = (unsigned int)d_positions.size(); + buildInput.triangleArray.vertexBuffers = d_positions.getCUAsArray(); + buildInput.triangleArray.numSbtRecords = 1; + } + + // this buffer needs to be alive over the GAS build + CuBuffer d_displacementDirections; + + // this value needs to be alive over the GAS build + OptixDisplacementMicromapUsageCount usage = {}; + + if( state.enableDMMs ) + { + // Applying the DMMs to triangles. + // DMMs in the DMM array need to be index. + // Also, per triangle data for the displacement is specified, such as the displacement directions. + MeshData::DmmArray& dmm = state.mesh.dmmArray; + OptixBuildInputDisplacementMicromap& disp = buildInput.triangleArray.displacementMicromap; + + disp.indexingMode = OPTIX_DISPLACEMENT_MICROMAP_ARRAY_INDEXING_MODE_LINEAR; + disp.displacementMicromapArray = dmm.d_dmmArrayData.getCU(); + + // Displacement directions, 3 vectors (these do not need to be normalized!) + // While the API accepts float values for convenience, OptiX uses the half format internally. Float inputs are converted to half. + // So it is usually best to input half values directly to control precision. + // Note that this is not an issue for this sample, using ~( 0, 0, 10 ) as directions everywhere. + std::vector directions( state.mesh.numTriangles * 3, make_float3( 0, 0, 10 ) * state.displacementScale ); + d_displacementDirections.allocAndUpload( directions ); + disp.vertexDirectionsBuffer = d_displacementDirections.getCU(); + disp.vertexDirectionFormat = OPTIX_DISPLACEMENT_MICROMAP_DIRECTION_FORMAT_FLOAT3; + + // Since we create exactly one displacement micromap per triangle and we apply a displacement micromap to every triangle, there + // is a one to one mapping between the DMM usage and the DMM histogram + // we could even do a reinterpret_cast from dmm histogram to dmm usage here + usage.count = dmm.histogram.count; + usage.format = dmm.histogram.format; + usage.subdivisionLevel = dmm.histogram.subdivisionLevel; + disp.numDisplacementMicromapUsageCounts = 1; + disp.displacementMicromapUsageCounts = &usage; + } + + + OptixAccelBuildOptions gas_accel_options = {}; + + state.buildFlags = OPTIX_BUILD_FLAG_NONE; + state.buildFlags |= OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS; + state.buildFlags |= OPTIX_BUILD_FLAG_ALLOW_COMPACTION; + state.buildFlags |= OPTIX_BUILD_FLAG_PREFER_FAST_TRACE; + gas_accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + gas_accel_options.buildFlags = state.buildFlags; + + std::vector buildInputs = { buildInput }; + buildAndCompact( state.context, state.stream, buildTemp, state.mesh.gas.d_data, state.mesh.gas.handle, gas_accel_options, buildInputs ); + + state.params.handle = state.mesh.gas.handle; +} + +void createModule( DisplacedMicromeshState& state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + state.pipeline_compile_options.usesMotionBlur = false; + state.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + state.pipeline_compile_options.numPayloadValues = 4; + state.pipeline_compile_options.numAttributeValues = 2; + state.pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + state.pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE | OPTIX_PRIMITIVE_TYPE_FLAGS_DISPLACED_MICROMESH_TRIANGLE; + + state.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixDisplacedMicromesh.cu", inputSize ); + + OPTIX_CHECK_LOG( optixModuleCreate( state.context, &module_compile_options, &state.pipeline_compile_options, input, + inputSize, LOG, &LOG_SIZE, &state.module ) ); // LOG, LOG_SIZE are part of OPTIX_CHECK_LOG +} + +void createBuiltinModule( DisplacedMicromeshState& state, OptixPrimitiveType type ) +{ + OptixModuleCompileOptions module_compile_options = {}; + OptixBuiltinISOptions builtin_is_options = {}; + builtin_is_options.builtinISModuleType = type; + builtin_is_options.buildFlags = state.buildFlags; + + // Note that getting a built-in IS for triangle and displaced micro-mesh triangle primitives is possible, but not required. + OPTIX_CHECK_LOG( optixBuiltinISModuleGet( state.context, &module_compile_options, &state.pipeline_compile_options, + &builtin_is_options, &state.builtinModule ) ); +} + + +void createProgramGroups( DisplacedMicromeshState& state ) +{ + OptixProgramGroupOptions program_group_options = {}; + + { + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = state.module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.raygen_prog_group ) ); // LOG, LOG_SIZE are part of OPTIX_CHECK_LOG + } + + { + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__ms"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.miss_group ) ); // LOG, LOG_SIZE are part of OPTIX_CHECK_LOG + } + + { + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__occlusion"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.miss_group_occlusion ) ); // LOG, LOG_SIZE are part of OPTIX_CHECK_LOG + } + + { + OptixProgramGroupDesc hit_prog_group_desc = {}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleIS = state.builtinModule; + hit_prog_group_desc.hitgroup.moduleCH = state.module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__ch_tri"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &hit_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.hit_group ) ); // LOG, LOG_SIZE are part of OPTIX_CHECK_LOG + } +} + + +void createPipeline( DisplacedMicromeshState& state ) +{ + OptixProgramGroup program_groups[] = + { + state.raygen_prog_group, + state.miss_group, + state.miss_group_occlusion, + state.hit_group, + }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = 2; + + OPTIX_CHECK_LOG( optixPipelineCreate( state.context, &state.pipeline_compile_options, &pipeline_link_options, + program_groups, sizeof( program_groups ) / sizeof( program_groups[0] ), LOG, + &LOG_SIZE, &state.pipeline ) ); // LOG, LOG_SIZE are part of OPTIX_CHECK_LOG + + // We need to specify the max traversal depth. Calculate the stack sizes, so we can specify all + // parameters to optixPipelineSetStackSize. + OptixStackSizes stack_sizes = {}; + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.raygen_prog_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.miss_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.miss_group_occlusion, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.hit_group, &stack_sizes, state.pipeline ) ); + + uint32_t max_trace_depth = pipeline_link_options.maxTraceDepth; + uint32_t max_cc_depth = 0, max_dc_depth = 0; + uint32_t direct_callable_stack_size_from_traversal, direct_callable_stack_size_from_state, continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, max_cc_depth, max_dc_depth, &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + + // GAS only traversal + const uint32_t max_traversable_graph_depth = 1; + OPTIX_CHECK( optixPipelineSetStackSize( state.pipeline, direct_callable_stack_size_from_traversal, direct_callable_stack_size_from_state, + continuation_stack_size, max_traversable_graph_depth ) ); +} + + +void createSBT( DisplacedMicromeshState& state ) +{ + { + RayGenRecord sbtRg[1] = {}; + OPTIX_CHECK( optixSbtRecordPackHeader( state.raygen_prog_group, &sbtRg[0] ) ); + + state.d_sbtRg.allocIfRequired( 1 ); + state.d_sbtRg.upload( sbtRg ); + + state.sbt.raygenRecord = state.d_sbtRg.getCU(); + } + + { + MissRecord sbtMs[2]; + OPTIX_CHECK( optixSbtRecordPackHeader( state.miss_group, &sbtMs[0] ) ); + OPTIX_CHECK( optixSbtRecordPackHeader( state.miss_group_occlusion, &sbtMs[1] ) ); + sbtMs[0].data.bg_color = make_float4( 0.0f ); + sbtMs[1].data.bg_color = make_float4( 0.0f ); // this is never read! + + state.d_sbtMs.allocIfRequired( 2 ); + state.d_sbtMs.upload( sbtMs ); + + state.sbt.missRecordBase = state.d_sbtMs.getCU(); + state.sbt.missRecordStrideInBytes = state.d_sbtMs.stride(); + state.sbt.missRecordCount = (unsigned int)state.d_sbtMs.size(); + } + + { + HitGroupRecord sbtHit[1]; + OPTIX_CHECK( optixSbtRecordPackHeader( state.hit_group, &sbtHit[0] ) ); + sbtHit[0].data.color = make_float3( 1 ); + + state.d_sbtHit.allocIfRequired( 1 ); + state.d_sbtHit.upload( sbtHit ); + + state.sbt.hitgroupRecordBase = state.d_sbtHit.getCU(); + state.sbt.hitgroupRecordStrideInBytes = state.d_sbtHit.stride(); + state.sbt.hitgroupRecordCount = (unsigned int)state.d_sbtHit.size(); + } +} + + +void cleanupState( DisplacedMicromeshState& state ) +{ + OPTIX_CHECK( optixPipelineDestroy( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.miss_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.miss_group_occlusion ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.hit_group ) ); + OPTIX_CHECK( optixModuleDestroy( state.module ) ); + OPTIX_CHECK( optixDeviceContextDestroy( state.context ) ); +} + + +//------------------------------------------------------------------------------ +// +// Main +// +//------------------------------------------------------------------------------ + +int main( int argc, char* argv[] ) +{ + DisplacedMicromeshState state = {}; + state.params.width = 512; + state.params.height = 512; + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::GL_INTEROP; + + // + // Parse command line options + // + std::string outfile; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--no-gl-interop" ) + { + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + } + else if( arg == "--subdivision-levels" || arg == "-s" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + + int subdivLevels = atoi( argv[++i] ); + if( subdivLevels >= 0 && subdivLevels <= 5 ) + state.dmmSubdivisionLevel = subdivLevels; + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outfile = argv[++i]; + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + int w, h; + sutil::parseDimensions( dims_arg.c_str(), w, h ); + state.params.width = w; + state.params.height = h; + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + initCameraState(); + + // + // Set up OptiX state + // + createContext( state ); + + unsigned int RTCoresVersion = 0; + OPTIX_CHECK( optixDeviceContextGetProperty( state.context, OPTIX_DEVICE_PROPERTY_RTCORE_VERSION, + &RTCoresVersion, sizeof( unsigned int ) ) ); + if( RTCoresVersion < 10 ) + { + std::cerr << "The optixDisplacedMicromesh sample requires a RTX-enabled graphics card to run on.\n"; + exit( 0 ); + } + + buildMeshAccel( state ); + createModule( state ); + createBuiltinModule( state, state.enableDMMs ? OPTIX_PRIMITIVE_TYPE_DISPLACED_MICROMESH_TRIANGLE : OPTIX_PRIMITIVE_TYPE_TRIANGLE ); + createProgramGroups( state ); + createPipeline( state ); + createSBT( state ); + initLaunchGlobals( state ); + + + const bool interactive = outfile.empty(); + + if( interactive ) + { + std::cout << "////////////////////////////////////////////////////////////////////////////////////////////////////////////\n"; + std::cout << "Keys:\n"; + std::cout << " KP_1/2 Decrease/increase DMM subdivision levels\n"; + std::cout << " KP_4/5 Decrease/increase displacement scale\n"; + std::cout << " D Toggle: DMM usage\n"; + std::cout << " A Toggle: AO rendering\n"; + std::cout << "////////////////////////////////////////////////////////////////////////////////////////////////////////////\n"; + GLFWwindow* window = sutil::initUI( "optixDisplacedMicromesh", state.params.width, state.params.height ); + glfwSetMouseButtonCallback( window, mouseButtonCallback ); + glfwSetCursorPosCallback( window, cursorPosCallback ); + glfwSetWindowSizeCallback( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback( window, keyCallback ); + glfwSetScrollCallback( window, scrollCallback ); + glfwSetWindowUserPointer( window, &state ); + + // + // Render loop + // + { + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, state.params.width, state.params.height ); + output_buffer.setStream( state.stream ); + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + handleCameraUpdate( state ); + handleResize( state, output_buffer ); + + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + renderFrame( output_buffer, state ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1 - t0; + + sutil::displayStats( state_update_time, render_time, display_time ); + + glfwSwapBuffers( window ); + + ++state.params.subframe_index; + } while( !glfwWindowShouldClose( window ) ); + + CUDA_SYNC_CHECK(); + } + + sutil::cleanupUI( window ); + } + else + { + handleCameraUpdate( state ); + + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + sutil::initGLFW(); // For GL context + sutil::initGL(); + } + + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, state.params.width, state.params.height ); + output_buffer.setStream( state.stream ); + handleResize( state, output_buffer ); + + state.params.spp = 4; + + renderFrame( output_buffer, state ); + CUDA_SYNC_CHECK(); + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + sutil::saveImage( outfile.c_str(), buffer, false ); + + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + glfwTerminate(); + } + } + + cleanupState( state ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDisplacedMicromesh/optixDisplacedMicromesh.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixDisplacedMicromesh/optixDisplacedMicromesh.cu new file mode 100644 index 00000000..3ac23cf9 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDisplacedMicromesh/optixDisplacedMicromesh.cu @@ -0,0 +1,307 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "optixDisplacedMicromesh.h" +#include "random.h" + +#include +#include + + +extern "C" { + __constant__ Globals params; +} + + +struct Onb +{ + __forceinline__ __device__ Onb( const float3& normal ) + { + m_normal = normal; + + if( fabs( m_normal.x ) > fabs( m_normal.z ) ) + { + m_binormal.x = -m_normal.y; + m_binormal.y = m_normal.x; + m_binormal.z = 0; + } + else + { + m_binormal.x = 0; + m_binormal.y = -m_normal.z; + m_binormal.z = m_normal.y; + } + + m_binormal = normalize( m_binormal ); + m_tangent = cross( m_binormal, m_normal ); + } + + __forceinline__ __device__ void inverse_transform( float3& p ) const + { + p = p.x * m_tangent + p.y * m_binormal + p.z * m_normal; + } + + float3 m_tangent; + float3 m_binormal; + float3 m_normal; +}; + +static __forceinline__ __device__ void cosine_sample_hemisphere( const float u1, const float u2, float3& p ) +{ + // Uniformly sample disk. + const float r = sqrtf( u1 ); + const float phi = 2.0f * M_PIf * u2; + p.x = r * cosf( phi ); + p.y = r * sinf( phi ); + + // Project up to hemisphere. + p.z = sqrtf( fmaxf( 0.0f, 1.0f - p.x * p.x - p.y * p.y ) ); +} + + +// Use named types for compatibility with nvrtc +// Otherwise these structs can be defined as unnamed structs directly in 'Payload' +// to avoid access via p0123.px and directly access px. +struct t_p0123 { + unsigned int p0, p1, p2, p3; +}; +struct t_cseed { + float3 color; + unsigned int seed; +}; + +struct Payload { + + union { + t_p0123 p0123; + t_cseed cseed; + }; + + __forceinline__ __device__ void setAll() + { + optixSetPayload_0( p0123.p0 ); + optixSetPayload_1( p0123.p1 ); + optixSetPayload_2( p0123.p2 ); + optixSetPayload_3( p0123.p3 ); + } + __forceinline__ __device__ void getAll() + { + p0123.p0 = optixGetPayload_0(); + p0123.p1 = optixGetPayload_1(); + p0123.p2 = optixGetPayload_2(); + p0123.p3 = optixGetPayload_3(); + } + __forceinline__ __device__ void setC() + { + optixSetPayload_0( p0123.p0 ); + optixSetPayload_1( p0123.p1 ); + optixSetPayload_2( p0123.p2 ); + } + __forceinline__ __device__ void getC() + { + p0123.p0 = optixGetPayload_0(); + p0123.p1 = optixGetPayload_1(); + p0123.p2 = optixGetPayload_2(); + } + __forceinline__ __device__ void getSeed() + { + p0123.p3 = optixGetPayload_3(); + } +}; + +constexpr unsigned int SBT_STRIDE_COLLAPSE = 0; + +extern "C" __global__ void __raygen__rg() +{ + const uint3 idx = optixGetLaunchIndex(); + const uint3 dim = optixGetLaunchDimensions(); + + const float3 eye = params.eye; + const float3 U = params.U; + const float3 V = params.V; + const float3 W = params.W; + + Payload payload; + payload.cseed.seed = tea<4>( idx.y * dim.x + idx.x, 12346789 + params.subframe_index ); + + float3 final_c = make_float3( 0 ); +#pragma unroll 1 + for( int x = 1; x <= params.spp; ++x ) + { + const float2 d = 2.0f * make_float2( + ( static_cast< float >( idx.x ) + rnd( payload.cseed.seed ) ) / static_cast< float >( dim.x ), + ( static_cast< float >( idx.y ) + rnd( payload.cseed.seed ) ) / static_cast< float >( dim.y ) + ) - 1.0f; + float3 direction = normalize( d.x * U + d.y * V + W ); + + float time = 0; + + payload.cseed.color = make_float3( 0.5f ); + optixTrace( params.handle, eye, direction, 0, 1e16f, time, OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_NONE, + 0, // SBT offset, first ray type (only one here) + SBT_STRIDE_COLLAPSE, // SBT stride, forcing a single HitGroup in combination with an sbt offset set to zero for every instance! + 0, // missSBTIndex, used for camera rays + payload.p0123.p0, payload.p0123.p1, payload.p0123.p2, payload.p0123.p3 ); + final_c += payload.cseed.color; + } + final_c /= params.spp; + + if( !params.accum_buffer || !params.frame_buffer ) + return; + + unsigned int image_index = idx.y * params.width + idx.x; + if( params.subframe_index > 0 ) + { + const float a = 1.0f / static_cast( params.subframe_index + 1 ); + const float3 accum_color_prev = make_float3( params.accum_buffer[image_index] ); + final_c = lerp( accum_color_prev, final_c, a ); + } + params.accum_buffer[image_index] = make_float4( final_c, 1.0f ); + params.frame_buffer[image_index] = make_color( final_c ); +} + + +extern "C" __global__ void __miss__ms() +{ + MissData* rt_data = reinterpret_cast< MissData* >( optixGetSbtDataPointer() ); + Payload p; + p.cseed.color = make_float3( rt_data->bg_color.x, rt_data->bg_color.y, rt_data->bg_color.z ); + p.setC(); +} + +extern "C" __global__ void __miss__occlusion() +{ + optixSetPayload_0( 0 ); +} + +static __forceinline__ __device__ void ch_impl( const float3& normal, const float3& hitpoint ) +{ + Payload p; + p.getSeed(); + + const float offset = 0.0001f; + float shade = 1.0f; + if( params.ao ) + { + const float z1 = rnd( p.cseed.seed ); + const float z2 = rnd( p.cseed.seed ); + + float3 w_in; + cosine_sample_hemisphere( z1, z2, w_in ); + float3 wn = normalize( optixTransformNormalFromObjectToWorldSpace( normal ) ); + wn = faceforward( wn, -optixGetWorldRayDirection(), wn ); + Onb onb( wn ); + onb.inverse_transform( w_in ); + + unsigned int occluded = 1; + optixTrace( params.handle, hitpoint + wn * offset, w_in, 0.0f, 1e16f, optixGetRayTime(), OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_DISABLE_CLOSESTHIT | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT, + 0, SBT_STRIDE_COLLAPSE, // no hit group will even be executed (assuming no IS), hence, set stride and offset to 0 + 1, // select MS program (__miss__occlusion) + occluded ); // this is inout here! If MS is called, it will override the payload + + if( occluded ) + shade = 0.f; + } + + HitGroupData* rt_data = reinterpret_cast( optixGetSbtDataPointer() ); + // convert normal to color and store in payload + p.cseed.color = shade * ( 0.5f * normal + make_float3( 0.5f ) ) * rt_data->color; + + p.setAll(); +} + +extern "C" __global__ void __closesthit__ch_tri() +{ + // fetch current triangle vertices + float3 vertices[3]; + float3 hitP; + + if( optixIsTriangleHit() ) + { + optixGetTriangleVertexData( optixGetGASTraversableHandle(), optixGetPrimitiveIndex(), optixGetSbtGASIndex(), + optixGetRayTime(), vertices ); + + float2 barycentrics = optixGetTriangleBarycentrics(); + + ////////////////////////////////////////////////////////////////////////// + // wire frame rendering for triangles + if( barycentrics.x < .01f || barycentrics.y < .01f || 1 - barycentrics.x - barycentrics.y < .01f ) + { + Payload p = {}; + p.cseed.color = make_float3( 1.f ); + p.setAll(); + return; + } + ////////////////////////////////////////////////////////////////////////// + + hitP = ( 1 - barycentrics.x - barycentrics.y ) * vertices[0] + barycentrics.x * vertices[1] + barycentrics.y * vertices[2]; + } + else if( optixIsDisplacedMicromeshTriangleHit() ) + { + // returns the vertices of the current DMM micro triangle hit + optixGetMicroTriangleVertexData( vertices ); + + float2 hitBaseBarycentrics = optixGetTriangleBarycentrics(); + + float2 microVertexBaseBarycentrics[3]; + optixGetMicroTriangleBarycentricsData( microVertexBaseBarycentrics ); + + float2 microBarycentrics = optixBaseBarycentricsToMicroBarycentrics( hitBaseBarycentrics, microVertexBaseBarycentrics ); + + ////////////////////////////////////////////////////////////////////////// + // wire frame rendering for micro triangles + if( microBarycentrics.x < .01f || microBarycentrics.y < .01f || 1 - microBarycentrics.x - microBarycentrics.y < .01f ) + { + Payload p ={}; + p.cseed.color = make_float3( 1.f ); + p.setAll(); + return; + } + ////////////////////////////////////////////////////////////////////////// + + hitP = (1 - microBarycentrics.x - microBarycentrics.y) * vertices[0] + microBarycentrics.x * vertices[1] + microBarycentrics.y * vertices[2]; + } + + // compute triangle normal + vertices[1] -= vertices[0]; + vertices[2] -= vertices[0]; + float3 normal = make_float3( + vertices[1].y*vertices[2].z - vertices[1].z*vertices[2].y, + vertices[1].z*vertices[2].x - vertices[1].x*vertices[2].z, + vertices[1].x*vertices[2].y - vertices[1].y*vertices[2].x ); + + ch_impl( normalize( normal ), hitP ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDisplacedMicromesh/optixDisplacedMicromesh.h b/Extern/3rdParty/OptiX/Linux/SDK/optixDisplacedMicromesh/optixDisplacedMicromesh.h new file mode 100644 index 00000000..3f43d197 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDisplacedMicromesh/optixDisplacedMicromesh.h @@ -0,0 +1,64 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +struct Globals +{ + float4* accum_buffer; + uchar4* frame_buffer; + unsigned int width; + unsigned int height; + unsigned int spp; + float3 eye, U, V, W; + OptixTraversableHandle handle; + int subframe_index; + bool ao; +}; + +struct RayGenData +{ + float3 cam_eye; + float3 camera_u, camera_v, camera_w; +}; + + +struct MissData +{ + float4 bg_color; +}; + +struct HitGroupData +{ + float3 color; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/CMakeLists.txt new file mode 100644 index 00000000..ddb232e5 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/CMakeLists.txt @@ -0,0 +1,45 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Tag the following kernel to be compiled to OBJ intead of PTX (which is the default for +# OPTIX_add_sample_executable). Must be called before OPTIX_add_sample_executable. +set_source_files_properties( + ${CMAKE_CURRENT_SOURCE_DIR}/vertices.cu + PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ +) + +OPTIX_add_sample_executable( optixDynamicGeometry target_name + optixDynamicGeometry.cu + optixDynamicGeometry.cpp + optixDynamicGeometry.h + vertices.cu + # OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} ${CUDA_LIBRARIES} ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/optixDynamicGeometry.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/optixDynamicGeometry.cpp new file mode 100644 index 00000000..f35fecdc --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/optixDynamicGeometry.cpp @@ -0,0 +1,1129 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include // Needs to be included before gl_interop + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "optixDynamicGeometry.h" +#include "vertices.h" + +#include +#include +#include +#include +#include +#include +#include + +bool resize_dirty = false; +bool minimized = false; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Mouse state +int32_t mouse_button = -1; + + +//------------------------------------------------------------------------------ +// +// Local types +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +template +struct Record +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef Record RayGenRecord; +typedef Record MissRecord; +typedef Record HitGroupRecord; + +struct DynamicGeometryState +{ + OptixDeviceContext context = 0; + + size_t temp_buffer_size = 0; + CUdeviceptr d_temp_buffer = 0; + CUdeviceptr d_temp_vertices = 0; + CUdeviceptr d_instances = 0; + + unsigned int triangle_flags = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT; + + OptixBuildInput ias_instance_input = {}; + OptixBuildInput triangle_input = {}; + + OptixTraversableHandle ias_handle; + OptixTraversableHandle static_gas_handle; + OptixTraversableHandle deforming_gas_handle; + OptixTraversableHandle exploding_gas_handle; + + CUdeviceptr d_ias_output_buffer = 0; + CUdeviceptr d_static_gas_output_buffer; + CUdeviceptr d_deforming_gas_output_buffer; + CUdeviceptr d_exploding_gas_output_buffer; + + size_t ias_output_buffer_size = 0; + size_t static_gas_output_buffer_size = 0; + size_t deforming_gas_output_buffer_size = 0; + size_t exploding_gas_output_buffer_size = 0; + + OptixModule ptx_module = 0; + OptixPipelineCompileOptions pipeline_compile_options = {}; + OptixPipeline pipeline = 0; + + OptixProgramGroup raygen_prog_group; + OptixProgramGroup miss_group = 0; + OptixProgramGroup hit_group = 0; + + CUstream stream = 0; + Params params; + Params* d_params; + + float time = 0.f; + float last_exploding_sphere_rebuild_time = 0.f; + + OptixShaderBindingTable sbt = {}; +}; + +//------------------------------------------------------------------------------ +// +// Scene data +// +//------------------------------------------------------------------------------ + +const int32_t g_tessellation_resolution = 128; + +const float g_exploding_gas_rebuild_frequency = 10.f; + +const int32_t INST_COUNT = 4; + +const std::array g_diffuse_colors = +{ { + { 0.70f, 0.70f, 0.70f }, + { 0.80f, 0.80f, 0.80f }, + { 0.90f, 0.90f, 0.90f }, + { 1.00f, 1.00f, 1.00f } +} }; + +struct Instance +{ + float m[12]; +}; + +const std::array g_instances = +{ { + {{1, 0, 0, -4.5f, 0, 1, 0, 0, 0, 0, 1, 0}}, + {{1, 0, 0, -1.5f, 0, 1, 0, 0, 0, 0, 1, 0}}, + {{1, 0, 0, 1.5f, 0, 1, 0, 0, 0, 0, 1, 0}}, + {{1, 0, 0, 4.5f, 0, 1, 0, 0, 0, 0, 1, 0}} +} }; + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking( static_cast< int >( xpos ), static_cast< int >( ypos ) ); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + Params* params = static_cast< Params* >( glfwGetWindowUserPointer( window ) ); + + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast< int >( xpos ), static_cast< int >( ypos ), params->width, params->height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast< int >( xpos ), static_cast< int >( ypos ), params->width, params->height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + Params* params = static_cast< Params* >( glfwGetWindowUserPointer( window ) ); + params->width = res_x; + params->height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + } + else if( key == GLFW_KEY_G ) + { + // toggle UI draw + } +} + + +static void scrollCallback( GLFWwindow* window, double xscroll, double yscroll ) +{ + if( trackball.wheelEvent( ( int )yscroll ) ) + camera_changed = true; +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --time | -t Animation time for image output (default 1)\n"; + std::cerr << " --frames | -n Number of animation frames for image output (default 16)\n"; + std::cerr << " --no-gl-interop Disable GL interop for display\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 1024x768\n"; + std::cerr << " --help | -h Print this usage message\n"; + exit( 0 ); +} + + +void initLaunchParams( DynamicGeometryState& state ) +{ + state.params.frame_buffer = nullptr; // Will be set when output buffer is mapped + state.params.subframe_index = 0u; + + CUDA_CHECK( cudaStreamCreate( &state.stream ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &state.d_params ), sizeof( Params ) ) ); +} + + +void handleCameraUpdate( Params& params ) +{ + if( !camera_changed ) + return; + camera_changed = false; + + camera.setAspectRatio( static_cast< float >( params.width ) / static_cast< float >( params.height ) ); + params.eye = camera.eye(); + camera.UVWFrame( params.U, params.V, params.W ); +} + + +void handleResize( sutil::CUDAOutputBuffer& output_buffer, Params& params ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + output_buffer.resize( params.width, params.height ); +} + + +void updateState( sutil::CUDAOutputBuffer& output_buffer, Params& params ) +{ + handleCameraUpdate( params ); + handleResize( output_buffer, params ); +} + + +void launchSubframe( sutil::CUDAOutputBuffer& output_buffer, DynamicGeometryState& state ) +{ + // Launch + uchar4* result_buffer_data = output_buffer.map(); + state.params.frame_buffer = result_buffer_data; + CUDA_CHECK( cudaMemcpyAsync( + reinterpret_cast< void* >( state.d_params ), + &state.params, sizeof( Params ), + cudaMemcpyHostToDevice, state.stream + ) ); + + OPTIX_CHECK( optixLaunch( + state.pipeline, + state.stream, + reinterpret_cast< CUdeviceptr >( state.d_params ), + sizeof( Params ), + &state.sbt, + state.params.width, // launch width + state.params.height, // launch height + 1 // launch depth + ) ); + output_buffer.unmap(); + CUDA_SYNC_CHECK(); +} + + +void displaySubframe( sutil::CUDAOutputBuffer& output_buffer, sutil::GLDisplay& gl_display, GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( + output_buffer.width(), + output_buffer.height(), + framebuf_res_x, + framebuf_res_y, + output_buffer.getPBO() + ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n"; +} + + +void initCameraState() +{ + camera.setEye( make_float3( 0.f, 1.f, -20.f ) ); + camera.setLookat( make_float3( 0, 0, 0 ) ); + camera.setUp( make_float3( 0.0f, 1.0f, 0.0f ) ); + camera.setFovY( 35.0f ); + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( + make_float3( 1.0f, 0.0f, 0.0f ), + make_float3( 0.0f, 0.0f, 1.0f ), + make_float3( 0.0f, 1.0f, 0.0f ) + ); + trackball.setGimbalLock( true ); +} + + +void createContext( DynamicGeometryState& state ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cu_ctx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; +#ifdef DEBUG + // This may incur significant performance cost and should only be done during development. + options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; +#endif + OPTIX_CHECK( optixDeviceContextCreate( cu_ctx, &options, &context ) ); + + state.context = context; +} + +void launchGenerateAnimatedVertices( DynamicGeometryState& state, AnimationMode animation_mode ) +{ + generateAnimatedVetrices( (float3*)state.d_temp_vertices, animation_mode, state.time, g_tessellation_resolution, g_tessellation_resolution ); +} + +void updateMeshAccel( DynamicGeometryState& state ) +{ + // Generate deformed sphere vertices + launchGenerateAnimatedVertices( state, AnimationMode_Deform ); + + // Update deforming GAS + + OptixAccelBuildOptions gas_accel_options = {}; + gas_accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION | OPTIX_BUILD_FLAG_ALLOW_UPDATE | OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS; + gas_accel_options.operation = OPTIX_BUILD_OPERATION_UPDATE; + + OPTIX_CHECK( optixAccelBuild( + state.context, + state.stream, // CUDA stream + &gas_accel_options, + &state.triangle_input, + 1, // num build inputs + state.d_temp_buffer, + state.temp_buffer_size, + state.d_deforming_gas_output_buffer, + state.deforming_gas_output_buffer_size, + &state.deforming_gas_handle, + nullptr, // emitted property list + 0 // num emitted properties + ) ); + + // Generate exploding sphere vertices + launchGenerateAnimatedVertices( state, AnimationMode_Explode ); + + // Update exploding GAS + + // Occasionally rebuild to maintain AS quality + if( state.time - state.last_exploding_sphere_rebuild_time > 1 / g_exploding_gas_rebuild_frequency ) + { + gas_accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + state.last_exploding_sphere_rebuild_time = state.time; + + // We don't compress the AS so the size of the GAS won't change and we can rebuild the GAS in-place. + } + + OPTIX_CHECK( optixAccelBuild( + state.context, + state.stream, // CUDA stream + &gas_accel_options, + &state.triangle_input, + 1, // num build inputs + state.d_temp_buffer, + state.temp_buffer_size, + state.d_exploding_gas_output_buffer, + state.exploding_gas_output_buffer_size, + &state.exploding_gas_handle, + nullptr, // emitted property list + 0 // num emitted properties + ) ); + + // Update the IAS + // We refit the IAS as the relative positions of the spheres don't change much so AS quality after update is fine. + + OptixAccelBuildOptions ias_accel_options = {}; + ias_accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION | OPTIX_BUILD_FLAG_ALLOW_UPDATE; + ias_accel_options.motionOptions.numKeys = 1; + ias_accel_options.operation = OPTIX_BUILD_OPERATION_UPDATE; + + if( g_instances.size() > 1 ) + { + float t = sinf( state.time * 4.f ); + CUDA_CHECK( cudaMemcpy( ( ( OptixInstance* )state.d_instances )[1].transform + 7, &t, sizeof( float ), cudaMemcpyHostToDevice ) ); + } + + OPTIX_CHECK( optixAccelBuild( state.context, state.stream, &ias_accel_options, &state.ias_instance_input, 1, state.d_temp_buffer, state.temp_buffer_size, + state.d_ias_output_buffer, state.ias_output_buffer_size, &state.ias_handle, nullptr, 0 ) ); + + CUDA_SYNC_CHECK(); +} + +void buildMeshAccel( DynamicGeometryState& state ) +{ + // Allocate temporary space for vertex generation. + // The same memory space is reused for generating the deformed and exploding vertices before updates. + uint32_t numVertices = g_tessellation_resolution * g_tessellation_resolution * 6; + const size_t vertices_size_in_bytes = numVertices * sizeof( float3 ); + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &state.d_temp_vertices ), vertices_size_in_bytes ) ); + + // Build static triangulated sphere. + launchGenerateAnimatedVertices( state, AnimationMode_None ); + + // Build an AS over the triangles. + // We use un-indexed triangles so we can explode the sphere per triangle. + state.triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + state.triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + state.triangle_input.triangleArray.vertexStrideInBytes = sizeof( float3 ); + state.triangle_input.triangleArray.numVertices = static_cast< uint32_t >( numVertices ); + state.triangle_input.triangleArray.vertexBuffers = &state.d_temp_vertices; + state.triangle_input.triangleArray.flags = &state.triangle_flags; + state.triangle_input.triangleArray.numSbtRecords = 1; + state.triangle_input.triangleArray.sbtIndexOffsetBuffer = 0; + state.triangle_input.triangleArray.sbtIndexOffsetSizeInBytes = 0; + state.triangle_input.triangleArray.sbtIndexOffsetStrideInBytes = 0; + + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION | OPTIX_BUILD_FLAG_ALLOW_UPDATE | OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( + state.context, + &accel_options, + &state.triangle_input, + 1, // num_build_inputs + &gas_buffer_sizes + ) ); + + state.temp_buffer_size = gas_buffer_sizes.tempSizeInBytes; + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &state.d_temp_buffer ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast< void** >( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 + ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( ( char* )d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( + state.context, + 0, // CUDA stream + &accel_options, + &state.triangle_input, + 1, // num build inputs + state.d_temp_buffer, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &state.static_gas_handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + // Replicate the uncompressed GAS for the exploding sphere. + // The exploding sphere is occasionally rebuild. We don't want to compress the GAS after every rebuild so we use the uncompressed GAS for the exploding sphere. + // The memory requirements for the uncompressed exploding GAS won't change so we can rebuild in-place. + state.exploding_gas_output_buffer_size = gas_buffer_sizes.outputSizeInBytes; + + OptixRelocationInfo relocationInfo; + OPTIX_CHECK( optixAccelGetRelocationInfo( state.context, state.static_gas_handle, &relocationInfo ) ); + + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &state.d_exploding_gas_output_buffer ), state.exploding_gas_output_buffer_size ) ); + CUDA_CHECK( cudaMemcpy( ( void* )state.d_exploding_gas_output_buffer, ( const void* )d_buffer_temp_output_gas_and_compacted_size, state.exploding_gas_output_buffer_size, cudaMemcpyDeviceToDevice ) ); + OPTIX_CHECK( optixAccelRelocate( state.context, 0, &relocationInfo, 0, 0, state.d_exploding_gas_output_buffer, state.exploding_gas_output_buffer_size, &state.exploding_gas_handle ) ); + + // Compress GAS + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, ( void* )emitProperty.result, sizeof( size_t ), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &state.d_static_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, 0, state.static_gas_handle, state.d_static_gas_output_buffer, compacted_gas_size, &state.static_gas_handle ) ); + + CUDA_CHECK( cudaFree( ( void* )d_buffer_temp_output_gas_and_compacted_size ) ); + + state.static_gas_output_buffer_size = compacted_gas_size; + } + else + { + state.d_static_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + + state.static_gas_output_buffer_size = gas_buffer_sizes.outputSizeInBytes; + } + + // Replicate the compressed GAS for the deforming sphere. + // The deforming sphere is never rebuild so we refit the compressed GAS without requiring recompression. + state.deforming_gas_output_buffer_size = state.static_gas_output_buffer_size; + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &state.d_deforming_gas_output_buffer ), state.deforming_gas_output_buffer_size ) ); + CUDA_CHECK( cudaMemcpy( ( void* )state.d_deforming_gas_output_buffer, ( const void* )state.d_static_gas_output_buffer, state.deforming_gas_output_buffer_size, cudaMemcpyDeviceToDevice ) ); + OPTIX_CHECK( optixAccelRelocate( state.context, 0, &relocationInfo, 0, 0, state.d_deforming_gas_output_buffer, state.deforming_gas_output_buffer_size, &state.deforming_gas_handle ) ); + + // Build the IAS + + std::vector instances( g_instances.size() ); + + for( size_t i = 0; i < g_instances.size(); ++i ) + { + memcpy( instances[i].transform, g_instances[i].m, sizeof( float ) * 12 ); + instances[i].sbtOffset = static_cast< unsigned int >( i ); + instances[i].visibilityMask = 255; + } + + instances[0].traversableHandle = state.static_gas_handle; + instances[1].traversableHandle = state.static_gas_handle; + instances[2].traversableHandle = state.deforming_gas_handle; + instances[3].traversableHandle = state.exploding_gas_handle; + + size_t instances_size_in_bytes = sizeof( OptixInstance ) * instances.size(); + CUDA_CHECK( cudaMalloc( ( void** )&state.d_instances, instances_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( ( void* )state.d_instances, instances.data(), instances_size_in_bytes, cudaMemcpyHostToDevice ) ); + + state.ias_instance_input.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; + state.ias_instance_input.instanceArray.instances = state.d_instances; + state.ias_instance_input.instanceArray.numInstances = static_cast( instances.size() ); + + OptixAccelBuildOptions ias_accel_options = {}; + ias_accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION | OPTIX_BUILD_FLAG_ALLOW_UPDATE; + ias_accel_options.motionOptions.numKeys = 1; + ias_accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes ias_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( state.context, &ias_accel_options, &state.ias_instance_input, 1, &ias_buffer_sizes ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_ias_and_compacted_size; + compactedSizeOffset = roundUp( ias_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_buffer_temp_output_ias_and_compacted_size ), compactedSizeOffset + 8 ) ); + + CUdeviceptr d_ias_temp_buffer; + bool needIASTempBuffer = ias_buffer_sizes.tempSizeInBytes > state.temp_buffer_size; + if( needIASTempBuffer ) + { + CUDA_CHECK( cudaMalloc( (void**)&d_ias_temp_buffer, ias_buffer_sizes.tempSizeInBytes ) ); + } + else + { + d_ias_temp_buffer = state.d_temp_buffer; + } + + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( (char*)d_buffer_temp_output_ias_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( state.context, 0, &ias_accel_options, &state.ias_instance_input, 1, d_ias_temp_buffer, + ias_buffer_sizes.tempSizeInBytes, d_buffer_temp_output_ias_and_compacted_size, + ias_buffer_sizes.outputSizeInBytes, &state.ias_handle, &emitProperty, 1 ) ); + + if( needIASTempBuffer ) + { + CUDA_CHECK( cudaFree( (void*)d_ias_temp_buffer ) ); + } + + // Compress the IAS + + size_t compacted_ias_size; + CUDA_CHECK( cudaMemcpy( &compacted_ias_size, (void*)emitProperty.result, sizeof( size_t ), cudaMemcpyDeviceToHost ) ); + + if( compacted_ias_size < ias_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_ias_output_buffer ), compacted_ias_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, 0, state.ias_handle, state.d_ias_output_buffer, + compacted_ias_size, &state.ias_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_ias_and_compacted_size ) ); + + state.ias_output_buffer_size = compacted_ias_size; + } + else + { + state.d_ias_output_buffer = d_buffer_temp_output_ias_and_compacted_size; + + state.ias_output_buffer_size = ias_buffer_sizes.outputSizeInBytes; + } + + // allocate enough temporary update space for updating the deforming GAS, exploding GAS and IAS. + size_t maxUpdateTempSize = std::max( ias_buffer_sizes.tempUpdateSizeInBytes, gas_buffer_sizes.tempUpdateSizeInBytes ); + if( state.temp_buffer_size < maxUpdateTempSize ) + { + CUDA_CHECK( cudaFree( (void*)state.d_temp_buffer ) ); + state.temp_buffer_size = maxUpdateTempSize; + CUDA_CHECK( cudaMalloc( (void**)&state.d_temp_buffer, state.temp_buffer_size ) ); + } + + state.params.handle = state.ias_handle; +} + + +void createModule( DynamicGeometryState& state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + state.pipeline_compile_options.usesMotionBlur = false; + state.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING; + state.pipeline_compile_options.numPayloadValues = 3; + state.pipeline_compile_options.numAttributeValues = 2; + state.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + state.pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + state.pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixDynamicGeometry.cu", inputSize ); + + OPTIX_CHECK_LOG( optixModuleCreate( + state.context, + &module_compile_options, + &state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &state.ptx_module + ) ); +} + + +void createProgramGroups( DynamicGeometryState& state ) +{ + OptixProgramGroupOptions program_group_options = {}; + + { + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = state.ptx_module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.raygen_prog_group + ) ); + } + + { + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.ptx_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__ms"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.miss_group + ) ); + } + + { + OptixProgramGroupDesc hit_prog_group_desc = {}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = state.ptx_module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__ch"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.hit_group + ) ); + } +} + + +void createPipeline( DynamicGeometryState& state ) +{ + OptixProgramGroup program_groups[] = + { + state.raygen_prog_group, + state.miss_group, + state.hit_group + }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = 1; + + OPTIX_CHECK_LOG( optixPipelineCreate( + state.context, + &state.pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &state.pipeline + ) ); + + // We need to specify the max traversal depth. Calculate the stack sizes, so we can specify all + // parameters to optixPipelineSetStackSize. + OptixStackSizes stack_sizes = {}; + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.raygen_prog_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.miss_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.hit_group, &stack_sizes, state.pipeline ) ); + + uint32_t max_trace_depth = 1; + uint32_t max_cc_depth = 0; + uint32_t max_dc_depth = 0; + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( + &stack_sizes, + max_trace_depth, + max_cc_depth, + max_dc_depth, + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, + &continuation_stack_size + ) ); + + // This is 2 since the largest depth is IAS->GAS + const uint32_t max_traversable_graph_depth = 2; + + OPTIX_CHECK( optixPipelineSetStackSize( + state.pipeline, + direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, + continuation_stack_size, + max_traversable_graph_depth + ) ); +} + + +void createSBT( DynamicGeometryState& state ) +{ + CUdeviceptr d_raygen_record; + const size_t raygen_record_size = sizeof( RayGenRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &d_raygen_record ), raygen_record_size ) ); + + RayGenRecord rg_sbt = {}; + OPTIX_CHECK( optixSbtRecordPackHeader( state.raygen_prog_group, &rg_sbt ) ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast< void* >( d_raygen_record ), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr d_miss_records; + const size_t miss_record_size = sizeof( MissRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &d_miss_records ), miss_record_size ) ); + + MissRecord ms_sbt[1]; + OPTIX_CHECK( optixSbtRecordPackHeader( state.miss_group, &ms_sbt[0] ) ); + ms_sbt[0].data.bg_color = make_float4( 0.0f ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast< void* >( d_miss_records ), + ms_sbt, + miss_record_size, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr d_hitgroup_records; + const size_t hitgroup_record_size = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast< void** >( &d_hitgroup_records ), + hitgroup_record_size * g_instances.size() + ) ); + + std::vector hitgroup_records( g_instances.size() ); + for( int i = 0; i < static_cast( g_instances.size() ); ++i ) + { + const int sbt_idx = i; + + OPTIX_CHECK( optixSbtRecordPackHeader( state.hit_group, &hitgroup_records[sbt_idx] ) ); + hitgroup_records[sbt_idx].data.color = g_diffuse_colors[i]; + } + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast< void* >( d_hitgroup_records ), + hitgroup_records.data(), + hitgroup_record_size*hitgroup_records.size(), + cudaMemcpyHostToDevice + ) ); + + state.sbt.raygenRecord = d_raygen_record; + state.sbt.missRecordBase = d_miss_records; + state.sbt.missRecordStrideInBytes = static_cast< uint32_t >( miss_record_size ); + state.sbt.missRecordCount = 1; + state.sbt.hitgroupRecordBase = d_hitgroup_records; + state.sbt.hitgroupRecordStrideInBytes = static_cast< uint32_t >( hitgroup_record_size ); + state.sbt.hitgroupRecordCount = static_cast< uint32_t >( hitgroup_records.size() ); +} + + +void cleanupState( DynamicGeometryState& state ) +{ + OPTIX_CHECK( optixPipelineDestroy( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.miss_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.hit_group ) ); + OPTIX_CHECK( optixModuleDestroy( state.ptx_module ) ); + OPTIX_CHECK( optixDeviceContextDestroy( state.context ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_temp_vertices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_static_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_deforming_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_exploding_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_instances ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_ias_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_temp_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_params ) ) ); +} + + +//------------------------------------------------------------------------------ +// +// Main +// +//------------------------------------------------------------------------------ + +int main( int argc, char* argv[] ) +{ + DynamicGeometryState state; + state.params.width = 1024; + state.params.height = 768; + state.time = 0.f; + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::GL_INTEROP; + + int num_frames = 16; + float animation_time = 1.f; + + // + // Parse command line options + // + std::string outfile; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--no-gl-interop" ) + { + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outfile = argv[++i]; + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + int w, h; + sutil::parseDimensions( dims_arg.c_str(), w, h ); + state.params.width = w; + state.params.height = h; + } + else if( arg == "--time" || arg == "-t" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + + animation_time = (float)atof( argv[++i] ); + } + else if( arg == "--frames" || arg == "-n" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + + num_frames = atoi( argv[++i] ); + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + initCameraState(); + + // + // Set up OptiX state + // + createContext( state ); + + createModule( state ); + createProgramGroups( state ); + createPipeline( state ); + createSBT( state ); + initLaunchParams( state ); + + buildMeshAccel( state ); + + if( outfile.empty() ) + { + GLFWwindow* window = sutil::initUI( "optixDynamicGeometry", state.params.width, state.params.height ); + glfwSetMouseButtonCallback( window, mouseButtonCallback ); + glfwSetCursorPosCallback( window, cursorPosCallback ); + glfwSetWindowSizeCallback( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback( window, keyCallback ); + glfwSetScrollCallback( window, scrollCallback ); + glfwSetWindowUserPointer( window, &state.params ); + + // + // Render loop + // + { + sutil::CUDAOutputBuffer output_buffer( + output_buffer_type, + state.params.width, + state.params.height + ); + + output_buffer.setStream( state.stream ); + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + auto tstart = std::chrono::system_clock::now(); + + state.last_exploding_sphere_rebuild_time = 0.f; + + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + auto tnow = std::chrono::system_clock::now(); + std::chrono::duration time = tnow - tstart; + state.time = (float)time.count(); + + updateMeshAccel( state ); + + updateState( output_buffer, state.params ); + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + launchSubframe( output_buffer, state ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1 - t0; + + sutil::displayStats( state_update_time, render_time, display_time ); + + glfwSwapBuffers( window ); + + ++state.params.subframe_index; + } while( !glfwWindowShouldClose( window ) ); + CUDA_SYNC_CHECK(); + } + + sutil::cleanupUI( window ); + } + else + { + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + sutil::initGLFW(); // For GL context + sutil::initGL(); + } + + state.last_exploding_sphere_rebuild_time = 0.f; + + { + // this scope is for output_buffer, to ensure the destructor is called bfore glfwTerminate() + + sutil::CUDAOutputBuffer output_buffer( + output_buffer_type, + state.params.width, + state.params.height + ); + + handleCameraUpdate( state.params ); + handleResize( output_buffer, state.params ); + + // run animation frames + for( unsigned int i = 0; i < static_cast( num_frames ); ++i ) + { + state.time = i * ( animation_time / ( num_frames - 1 ) ); + updateMeshAccel( state ); + launchSubframe( output_buffer, state ); + } + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + glfwTerminate(); + } + } + + cleanupState( state ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/optixDynamicGeometry.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/optixDynamicGeometry.cu new file mode 100644 index 00000000..b0833ea6 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/optixDynamicGeometry.cu @@ -0,0 +1,151 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "optixDynamicGeometry.h" + +#include +#include + +extern "C" { + __constant__ Params params; +} + +constexpr unsigned int SBT_STRIDE_COLLAPSE = 0; + +static __forceinline__ __device__ void trace( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax, + float3* prd +) +{ + unsigned int p0, p1, p2; + p0 = __float_as_uint( prd->x ); + p1 = __float_as_uint( prd->y ); + p2 = __float_as_uint( prd->z ); + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_NONE, + 0, // SBT offset + SBT_STRIDE_COLLAPSE, // SBT stride + 0, // missSBTIndex + p0, p1, p2 ); + prd->x = __uint_as_float( p0 ); + prd->y = __uint_as_float( p1 ); + prd->z = __uint_as_float( p2 ); +} + + +static __forceinline__ __device__ void setPayload( float3 p ) +{ + optixSetPayload_0( __float_as_uint( p.x ) ); + optixSetPayload_1( __float_as_uint( p.y ) ); + optixSetPayload_2( __float_as_uint( p.z ) ); +} + + +static __forceinline__ __device__ float3 getPayload() +{ + return make_float3( + __uint_as_float( optixGetPayload_0() ), + __uint_as_float( optixGetPayload_1() ), + __uint_as_float( optixGetPayload_2() ) + ); +} + + +extern "C" __global__ void __raygen__rg() +{ + const uint3 idx = optixGetLaunchIndex(); + const uint3 dim = optixGetLaunchDimensions(); + + const float3 eye = params.eye; + const float3 U = params.U; + const float3 V = params.V; + const float3 W = params.W; + const float2 d = 2.0f * make_float2( + static_cast< float >( idx.x ) / static_cast< float >( dim.x ), + static_cast< float >( idx.y ) / static_cast< float >( dim.y ) + ) - 1.0f; + + const float3 direction = normalize( d.x * U + d.y * V + W ); + float3 payload_rgb = make_float3( 0.5f, 0.5f, 0.5f ); + + trace( params.handle, + eye, + direction, + 0.00f, // tmin + 1e16f, // tmax + &payload_rgb ); + + params.frame_buffer[idx.y * params.width + idx.x] = make_color( payload_rgb ); +} + + +extern "C" __global__ void __miss__ms() +{ + MissData* rt_data = reinterpret_cast< MissData* >( optixGetSbtDataPointer() ); + float3 payload = getPayload(); + setPayload( make_float3( rt_data->bg_color.x, rt_data->bg_color.y, rt_data->bg_color.z ) ); +} + + +extern "C" __global__ void __closesthit__ch() +{ + HitGroupData* rt_data = reinterpret_cast< HitGroupData* >( optixGetSbtDataPointer() ); + + // fetch current triangle vertices + float3 data[3]; + optixGetTriangleVertexData( optixGetGASTraversableHandle(), optixGetPrimitiveIndex(), optixGetSbtGASIndex(), + optixGetRayTime(), data ); + + // compute triangle normal + data[1] -= data[0]; + data[2] -= data[0]; + float3 normal = make_float3( + data[1].y*data[2].z - data[1].z*data[2].y, + data[1].z*data[2].x - data[1].x*data[2].z, + data[1].x*data[2].y - data[1].y*data[2].x ); + const float s = 0.5f / sqrtf( normal.x*normal.x + normal.y*normal.y + normal.z*normal.z ); + + // convert normal to color and store in payload + setPayload( (normal*s + make_float3( 0.5 )) * rt_data->color ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/optixDynamicGeometry.h b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/optixDynamicGeometry.h new file mode 100644 index 00000000..2dc98872 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/optixDynamicGeometry.h @@ -0,0 +1,58 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +struct Params +{ + uchar4* frame_buffer; + unsigned int width; + unsigned int height; + float3 eye, U, V, W; + OptixTraversableHandle handle; + int subframe_index; +}; + +struct RayGenData +{ + float3 cam_eye; + float3 camera_u, camera_v, camera_w; +}; + + +struct MissData +{ + float4 bg_color; +}; + + +struct HitGroupData +{ + float3 color; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/vertices.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/vertices.cu new file mode 100644 index 00000000..acd4cbb0 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/vertices.cu @@ -0,0 +1,110 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "vertices.h" + +__forceinline__ __device__ float triangle_wave( float x, float shift = 0.f, float period = 2.f * M_PI, float amplitude = 1.f ) +{ + return fabsf( fmodf( ( 4.f / period ) * ( x - shift ), 4.f * amplitude ) - 2.f * amplitude ) - amplitude; +} + +__forceinline__ __device__ void write_animated_triangle( float3* out_vertices, int tidx, float3 v0, float3 v1, float3 v2, AnimationMode mode, float time ) +{ + float3 v = make_float3( 0 ); + + if( mode == AnimationMode_Explode ) + { + // Generate displacement vector from triangle index + const float theta = ( ( float )M_PI * ( tidx * ( 13 / M_PI ) ) ); + const float phi = ( ( float )( 2.0 * M_PI ) * ( tidx * ( 97 / M_PI ) ) ); + + // Apply displacement to the sphere triangles + v = make_float3( triangle_wave( phi ) * triangle_wave( theta, M_PI / 2.f ), + triangle_wave( phi, M_PI / 2.f ) * triangle_wave( theta, M_PI / 2.f ), triangle_wave( theta ) ) + * triangle_wave( time, M_PI / 2.f ) * 2.f; + } + + out_vertices[tidx * 3 + 0] = v0 + v; + out_vertices[tidx * 3 + 1] = v1 + v; + out_vertices[tidx * 3 + 2] = v2 + v; +} + +__forceinline__ __device__ float3 deform_vertex( const float3& c, AnimationMode mode, float time ) +{ + // Apply sine wave to the y coordinate of the sphere vertices + if( mode == AnimationMode_Deform ) + return make_float3( c.x, c.y * ( 0.5f + 0.4f * cosf( 4 * ( c.x + time ) ) ), c.z ); + return c; +} + +extern "C" __global__ void generate_vertices(float3* out_vertices, AnimationMode mode, float time, int width, int height) +{ + int idx = blockIdx.x * blockDim.x + threadIdx.x; + + if( idx < width * height ) + { + // generate a single patch (two unindexed triangles) of a tessellated sphere + + int x = idx % width; + int y = idx / width; + + const float theta0 = ( ( float )M_PI * ( y + 0 ) ) / height; + const float theta1 = ( ( float )M_PI * ( y + 1 ) ) / height; + const float phi0 = ( ( float )( 2.0 * M_PI ) * ( x + 0 ) ) / width; + const float phi1 = ( ( float )( 2.0 * M_PI ) * ( x + 1 ) ) / width; + + const float ct0 = cosf( theta0 ); + const float st0 = sinf( theta0 ); + const float ct1 = cosf( theta1 ); + const float st1 = sinf( theta1 ); + + const float cp0 = cosf( phi0 ); + const float sp0 = sinf( phi0 ); + const float cp1 = cosf( phi1 ); + const float sp1 = sinf( phi1 ); + + const float3 v00 = deform_vertex( make_float3( cp0 * st0, sp0 * st0, ct0 ), mode, time ); + const float3 v10 = deform_vertex( make_float3( cp0 * st1, sp0 * st1, ct1 ), mode, time ); + const float3 v01 = deform_vertex( make_float3( cp1 * st0, sp1 * st0, ct0 ), mode, time ); + const float3 v11 = deform_vertex( make_float3( cp1 * st1, sp1 * st1, ct1 ), mode, time ); + + write_animated_triangle( out_vertices, idx * 2 + 0, v00, v10, v11, mode, time ); + write_animated_triangle( out_vertices, idx * 2 + 1, v00, v11, v01, mode, time ); + } +} + +extern "C" __host__ void +generateAnimatedVetrices( float3* out_vertices, AnimationMode animation_mode, float time, int width, int height ) +{ + dim3 threadsPerBlock( 128, 1 ); + int numBlocks = ( width * height ) / threadsPerBlock.x; + generate_vertices <<< numBlocks, threadsPerBlock >>> ( out_vertices, animation_mode, time, width, height ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/vertices.h b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/vertices.h new file mode 100644 index 00000000..59002a58 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicGeometry/vertices.h @@ -0,0 +1,44 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +enum AnimationMode +{ + AnimationMode_None, + AnimationMode_Deform, + AnimationMode_Explode +}; + +extern "C" __host__ void generateAnimatedVetrices( float3* out_vertices, AnimationMode animation_mode, float time, int width, int height ); diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicMaterials/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicMaterials/CMakeLists.txt new file mode 100644 index 00000000..f85c61d6 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicMaterials/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixDynamicMaterials target_name + optixDynamicMaterials.cu + optixDynamicMaterials.cpp + optixDynamicMaterials.h + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicMaterials/optixDynamicMaterials.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicMaterials/optixDynamicMaterials.cpp new file mode 100644 index 00000000..3357f1a5 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicMaterials/optixDynamicMaterials.cpp @@ -0,0 +1,875 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include // Needs to be included before gl_interop + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "optixDynamicMaterials.h" + +#include +#include +#include +#include +#include +#include + + +template +struct SbtRecord +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef SbtRecord RayGenSbtRecord; +typedef SbtRecord MissSbtRecord; +typedef SbtRecord HitGroupSbtRecord; + +struct SampleState +{ + SampleState( uint32_t width, uint32_t height ) + { + params.image_width = width; + params.image_height = height; + } + + Params params; + CUdeviceptr d_param; + + OptixDeviceContext context = nullptr; + OptixTraversableHandle gas_handle; + OptixTraversableHandle ias_handle; + CUdeviceptr d_gas_output_buffer = 0; + CUdeviceptr d_ias_output_buffer = 0; + OptixModule module = nullptr; + OptixPipelineCompileOptions pipeline_compile_options = {}; + OptixProgramGroup raygen_prog_group = nullptr; + OptixProgramGroup miss_prog_group = nullptr; + std::vector hitgroup_prog_groups; + OptixPipeline pipeline = nullptr; + OptixShaderBindingTable sbt = {}; + CUstream stream = 0; + size_t hitgroupSbtRecordStride = 0; +}; + + +struct Matrix +{ + float m[12]; +}; + + +//------------------------------------------------------------------------------ +// +// Scene data +// +//------------------------------------------------------------------------------ + +// Transforms for instances - one on the left (sphere 0), one in the centre and one on the right (sphere 2). +std::vector transforms = { + { 1, 0, 0, -6, 0, 1, 0, 0, 0, 0, 1, -10 }, + { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -10 }, + { 1, 0, 0, 6, 0, 1, 0, 0, 0, 0, 1, -10 }, +}; + + +// Offsets into SBT for each instance. Hence this needs to be in sync with transforms! +// The middle sphere has two SBT records, the two other instances have one each. +unsigned int sbtOffsets[] = { 0, 1, 3 }; + + +const static std::array g_colors = +{ { { 1.f, 0.f, 0.f }, { 0.f, 1.f, 0.f }, { 0.f, 0.f, 1.f } } }; + + +// A cycling index (offset), used here as an offset onto hitgroup records. +template +struct MaterialIndex +{ + MaterialIndex() + : mIndex( 0 ) + { + } + unsigned int getVal() const { return mIndex; } + void nextVal() + { + if( ++mIndex == MAXINDEX ) + mIndex = 0; + } + + private: + unsigned int mIndex; +}; + +// Left sphere +MaterialIndex<3> g_materialIndex_0; +bool g_hasDataChanged = false; + +// Middle sphere +MaterialIndex<2> g_materialIndex_1; +bool g_hasOffsetChanged = false; + +// Right sphere +MaterialIndex<3> g_materialIndex_2; +bool g_hasSbtChanged = false; + + +//------------------------------------------------------------------------------ +// +// Helper Functions +// +//------------------------------------------------------------------------------ + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f Specify file for image output\n"; + std::cerr << " --help | -h Print this usage message\n"; + std::cerr << " --no-gl-interop Disable GL interop for display\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 512x384\n"; + exit( 1 ); +} + + +void initCamera( SampleState& state ) +{ + sutil::Camera camera; + camera.setEye( make_float3( 0.0f, 0.0f, 3.0f ) ); + camera.setLookat( make_float3( 0.0f, 0.0f, 0.0f ) ); + camera.setUp( make_float3( 0.0f, 1.0f, 0.0f ) ); + camera.setFovY( 60.0f ); + camera.setAspectRatio( static_cast( state.params.image_width ) / static_cast( state.params.image_height ) ); + camera.UVWFrame( state.params.camera_u, state.params.camera_v, state.params.camera_w ); + state.params.cam_eye = camera.eye(); +} + + +void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n"; +} + + +void createContext( SampleState& state ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; +#ifdef DEBUG + // This may incur significant performance cost and should only be done during development. + options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; +#endif + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &state.context ) ); +} + + +void buildGAS( SampleState& state ) +{ + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + // AABB build input + OptixAabb aabb = { -1.5f, -1.5f, -1.5f, 1.5f, 1.5f, 1.5f }; + CUdeviceptr d_aabb_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_aabb_buffer ), sizeof( OptixAabb ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_aabb_buffer ), &aabb, sizeof( OptixAabb ), cudaMemcpyHostToDevice ) ); + + OptixBuildInput aabb_input = {}; + + aabb_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES; + aabb_input.customPrimitiveArray.aabbBuffers = &d_aabb_buffer; + aabb_input.customPrimitiveArray.numPrimitives = 1; + + uint32_t aabb_input_flags[1] = {OPTIX_GEOMETRY_FLAG_NONE}; + aabb_input.customPrimitiveArray.flags = aabb_input_flags; + aabb_input.customPrimitiveArray.numSbtRecords = 1; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( state.context, &accel_options, &aabb_input, 1, &gas_buffer_sizes ) ); + CUdeviceptr d_temp_buffer_gas; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer_gas ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 + ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = reinterpret_cast( + reinterpret_cast( d_buffer_temp_output_gas_and_compacted_size ) + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( + state.context, + 0, // CUDA stream + &accel_options, + &aabb_input, + 1, // num build inputs + d_temp_buffer_gas, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &state.gas_handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + state.params.radius = 1.5f; + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer_gas ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_aabb_buffer ) ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, reinterpret_cast( emitProperty.result ), + sizeof( size_t ), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( + state.context, + 0, // CUDA stream + state.gas_handle, + state.d_gas_output_buffer, + compacted_gas_size, + &state.gas_handle + ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( d_buffer_temp_output_gas_and_compacted_size ) ) ); + } + else + { + state.d_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } +} + + +void buildIAS( SampleState& state ) +{ + std::vector instances; + for( size_t i = 0; i < transforms.size(); ++i ) + { + OptixInstance inst; + memcpy( inst.transform, &transforms[i], sizeof( float ) * 12 ); + inst.instanceId = 0; + inst.visibilityMask = 1; + inst.sbtOffset = sbtOffsets[i]; + inst.flags = OPTIX_INSTANCE_FLAG_NONE; + inst.traversableHandle = state.gas_handle; + instances.push_back( inst ); + } + + CUdeviceptr d_inst; + size_t instancesSizeInBytes = instances.size() * sizeof( OptixInstance ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_inst ), instancesSizeInBytes ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_inst ), &instances[0], instancesSizeInBytes, cudaMemcpyHostToDevice ) ); + + OptixBuildInput instanceInput = {}; + instanceInput.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; + instanceInput.instanceArray.instances = d_inst; + instanceInput.instanceArray.numInstances = static_cast( instances.size() ); + + OptixAccelBuildOptions iasAccelOptions = {}; + iasAccelOptions.buildFlags = OPTIX_BUILD_FLAG_NONE; + iasAccelOptions.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes ias_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( state.context, &iasAccelOptions, &instanceInput, 1, &ias_buffer_sizes ) ); + CUdeviceptr d_temp_buffer_ias; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer_ias ), ias_buffer_sizes.tempSizeInBytes ) ); + + // We need to free the output buffer if we are rebuilding the IAS. + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_ias_output_buffer ) ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_ias_output_buffer ), ias_buffer_sizes.outputSizeInBytes ) ); + + OPTIX_CHECK( optixAccelBuild( + state.context, + 0, // CUDA stream + &iasAccelOptions, + &instanceInput, + 1, // num build inputs + d_temp_buffer_ias, + ias_buffer_sizes.tempSizeInBytes, + state.d_ias_output_buffer, + ias_buffer_sizes.outputSizeInBytes, + &state.ias_handle, + nullptr, + 0 + ) ); + CUDA_SYNC_CHECK(); + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer_ias ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_inst ) ) ); +} + + +void createModule( SampleState& state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + state.pipeline_compile_options.usesMotionBlur = false; + state.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_ANY; + state.pipeline_compile_options.numPayloadValues = 3; // memory size of payload (in trace()) + state.pipeline_compile_options.numAttributeValues = 3; // memory size of attributes (from is()) + state.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + state.pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixDynamicMaterials.cu", inputSize ); + + OPTIX_CHECK_LOG( optixModuleCreate( state.context, &module_compile_options, &state.pipeline_compile_options, input, + inputSize, LOG, &LOG_SIZE, &state.module ) ); +} + + +void createProgramGroups( SampleState& state ) +{ + OptixProgramGroupOptions program_group_options = {}; // Initialize to zeros + + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = state.module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.raygen_prog_group ) ); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__ms"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.miss_prog_group ) ); + + // hard-coded list of different CH programs for different OptixInstances + std::vector chNames = {// The left sphere has a single CH program + "__closesthit__ch", + // The middle sphere toggles between two CH programs + "__closesthit__ch", "__closesthit__normal", + // The right sphere uses the g_materialIndex_2.getVal()'th of these CH programs + "__closesthit__blue", "__closesthit__green", "__closesthit__red"}; + + std::vector hitgroup_prog_group_descs; + for( auto chName : chNames ) + { + OptixProgramGroupDesc hitgroup_prog_group_desc = {}; + hitgroup_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hitgroup_prog_group_desc.hitgroup.moduleCH = state.module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameCH = chName; + hitgroup_prog_group_desc.hitgroup.moduleAH = nullptr; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + hitgroup_prog_group_desc.hitgroup.moduleIS = state.module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__is"; + hitgroup_prog_group_descs.push_back( hitgroup_prog_group_desc ); + } + state.hitgroup_prog_groups.resize( hitgroup_prog_group_descs.size() ); + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &hitgroup_prog_group_descs[0], + static_cast( hitgroup_prog_group_descs.size() ), + &program_group_options, LOG, &LOG_SIZE, &state.hitgroup_prog_groups[0] ) ); +} + + +void createPipeline( SampleState& state ) +{ + const uint32_t max_trace_depth = 1; + + std::vector program_groups; + program_groups.push_back( state.raygen_prog_group ); + program_groups.push_back( state.miss_prog_group ); + for( auto g : state.hitgroup_prog_groups ) + program_groups.push_back( g ); + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + + OPTIX_CHECK_LOG( optixPipelineCreate( state.context, &state.pipeline_compile_options, &pipeline_link_options, + &program_groups[0], static_cast( program_groups.size() ), LOG, + &LOG_SIZE, &state.pipeline ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, state.pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( state.pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + ) ); +} + + +void createSbt( SampleState& state ) +{ + CUdeviceptr raygen_record; + const size_t raygen_record_size = sizeof( RayGenSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &raygen_record ), raygen_record_size ) ); + RayGenSbtRecord rg_sbt; + rg_sbt.data = {}; + OPTIX_CHECK( optixSbtRecordPackHeader( state.raygen_prog_group, &rg_sbt ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( raygen_record ), &rg_sbt, raygen_record_size, cudaMemcpyHostToDevice ) ); + state.sbt.raygenRecord = raygen_record; + + CUdeviceptr miss_record; + size_t miss_record_size = sizeof( MissSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &miss_record ), miss_record_size ) ); + + MissSbtRecord ms_sbt; + ms_sbt.data = { 0.3f, 0.1f, 0.2f }; // Background color + OPTIX_CHECK( optixSbtRecordPackHeader( state.miss_prog_group, &ms_sbt ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( miss_record ), &ms_sbt, miss_record_size, cudaMemcpyHostToDevice ) ); + state.sbt.missRecordBase = miss_record; + state.sbt.missRecordStrideInBytes = sizeof( MissSbtRecord ); + state.sbt.missRecordCount = 1; + + const size_t hitGroupSbtRecordCount = 4; + std::vector hg_sbt( hitGroupSbtRecordCount ); + size_t hg_sbt_size = hg_sbt.size(); + + // The left sphere cycles through three colors by updating the data field of the SBT record. + hg_sbt[0].data = { g_colors[0], 0u }; + OPTIX_CHECK( optixSbtRecordPackHeader( state.hitgroup_prog_groups[0], &hg_sbt[0] ) ); + + // The middle sphere toggles between two SBT records by adjusting the SBT + // offset field of the sphere instance. The IAS needs to be rebuilt for the + // update to take effect. + hg_sbt[1].data = { g_colors[1], 1u }; + OPTIX_CHECK( optixSbtRecordPackHeader( state.hitgroup_prog_groups[1], &hg_sbt[1] ) ); + + hg_sbt[2].data = { g_colors[1], 1u }; + OPTIX_CHECK( optixSbtRecordPackHeader( state.hitgroup_prog_groups[2], &hg_sbt[2] ) ); + + // The right sphere cycles through colors by modifying the SBT. On update, a + // different pre-built CH program is packed into the corresponding SBT + // record. + hg_sbt[3].data = { { 0.f, 0.f, 0.f }, 2u }; + OPTIX_CHECK( optixSbtRecordPackHeader( state.hitgroup_prog_groups[g_materialIndex_2.getVal() + 3], &hg_sbt[3] ) ); + + CUdeviceptr hitgroup_record; + state.hitgroupSbtRecordStride = sizeof( HitGroupSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &hitgroup_record ), state.hitgroupSbtRecordStride * hg_sbt_size ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( hitgroup_record ), &hg_sbt[0], + state.hitgroupSbtRecordStride * hg_sbt_size, cudaMemcpyHostToDevice ) ); + state.sbt.hitgroupRecordBase = hitgroup_record; + state.sbt.hitgroupRecordStrideInBytes = static_cast( state.hitgroupSbtRecordStride ); + state.sbt.hitgroupRecordCount = static_cast( hg_sbt_size ); +} + + +void updateHitGroupData( SampleState& state ) +{ + // Method 1: + // Change the material parameters for the left sphere by directly modifying + // the HitGroupData for the first SBT record. + + // Cycle through three base colors. + g_materialIndex_0.nextVal(); + HitGroupData hg_data = HitGroupData { g_colors[g_materialIndex_0.getVal()], 0u }; + + // Update the data field of the SBT record for the left sphere with the new base color. + HitGroupSbtRecord* hg_sbt_0_ptr = &reinterpret_cast( state.sbt.hitgroupRecordBase )[0]; + CUDA_CHECK( cudaMemcpy( reinterpret_cast( &hg_sbt_0_ptr->data ), + &hg_data, sizeof( HitGroupData ), cudaMemcpyHostToDevice ) ); + + g_hasDataChanged = false; +} + + +void updateInstanceOffset( SampleState& state ) +{ + // Method 2: + // Update the SBT offset of the middle sphere. The offset is used to select + // an SBT record during traversal, which dertermines the CH & AH programs + // that will be invoked for shading. + + g_materialIndex_1.nextVal(); + sbtOffsets[1] = g_materialIndex_1.getVal() + 1; + + // It's necessary to rebuild the IAS for the updated offset to take effect. + buildIAS( state ); + + g_hasOffsetChanged = false; +} + + +void updateSbtHeader( SampleState& state ) +{ + // Method 3: + // Select a new material by re-packing the SBT header for the right sphere + // with a different CH program. + + // The right sphere will use the next compiled program group. + g_materialIndex_2.nextVal(); + + HitGroupSbtRecord hg_sbt_2; + hg_sbt_2.data = { { 0.f, 0.f, 0.f }, 2u }; // The color is hard-coded in the CH program. + OPTIX_CHECK( optixSbtRecordPackHeader( state.hitgroup_prog_groups[g_materialIndex_2.getVal() + 3], &hg_sbt_2 ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( state.sbt.hitgroupRecordBase + sizeof( HitGroupSbtRecord ) * sbtOffsets[2] ), + &hg_sbt_2, sizeof( HitGroupSbtRecord ), cudaMemcpyHostToDevice ) ); + + g_hasSbtChanged = false; +} + + +void updateState( sutil::CUDAOutputBuffer& output_buffer, SampleState& state ) +{ + // Change the material properties using one of three different approaches. + if( g_hasDataChanged ) + updateHitGroupData( state ); + if( g_hasOffsetChanged ) + updateInstanceOffset( state ); + if( g_hasSbtChanged ) + updateSbtHeader( state ); +} + + +void initLaunch( SampleState& state ) +{ + CUDA_CHECK( cudaStreamCreate( &state.stream ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_param ), sizeof( Params ) ) ); +} + + +void launch( SampleState& state, sutil::CUDAOutputBuffer& output_buffer ) +{ + state.params.image = output_buffer.map(); + state.params.handle = state.ias_handle; + + CUDA_CHECK( cudaMemcpy( reinterpret_cast( state.d_param ), &state.params, sizeof( Params ), cudaMemcpyHostToDevice ) ); + + assert( state.sbt.hitgroupRecordStrideInBytes % OPTIX_SBT_RECORD_ALIGNMENT == 0 ); + assert( state.sbt.hitgroupRecordBase % OPTIX_SBT_RECORD_ALIGNMENT == 0 ); + + OPTIX_CHECK( optixLaunch( state.pipeline, state.stream, state.d_param, sizeof( Params ), &state.sbt, + state.params.image_width, state.params.image_height, /*depth=*/1 ) ); + CUDA_SYNC_CHECK(); + + output_buffer.unmap(); +} + + +void displayUsage() +{ + static char display_text[256]; + sutil::beginFrameImGui(); + { + sprintf( display_text, + "Use the arrow keys to modify the materials:\n" + " [LEFT] left sphere\n" + " [UP] middle sphere\n" + " [RIGHT] right sphere\n" ); + } + sutil::displayText( display_text, 20.0f, 20.0f ); + sutil::endFrameImGui(); +} + + +void display( sutil::CUDAOutputBuffer& output_buffer, sutil::GLDisplay& gl_display, GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( static_cast( output_buffer.width() ), static_cast( output_buffer.height() ), + framebuf_res_x, framebuf_res_y, output_buffer.getPBO() ); +} + + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + else if( key == GLFW_KEY_LEFT ) + { + g_hasDataChanged = true; + } + else if( key == GLFW_KEY_RIGHT ) + { + g_hasSbtChanged = true; + } + else if( key == GLFW_KEY_UP ) + { + g_hasOffsetChanged = true; + } + } + else if( key == GLFW_KEY_G ) + { + // toggle UI draw + } +} + + +std::string getIndexedFilename( const std::string& name ) +{ + static unsigned int counter = 0; + size_t pos = name.find_last_of( '.' ); + if( pos == std::string::npos ) + { + std::cerr << "Cannot find image format suffix" << std::endl; + return name; + } + std::string suffix = name.substr( pos ); + std::string root = name.substr( 0, pos ); + std::stringstream s; + s << '_' << counter++ << suffix; + return root + s.str(); +} + + +void printBuffer( sutil::CUDAOutputBuffer& output_buffer, const std::string& outfile ) +{ + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = static_cast( output_buffer.width() ); + buffer.height = static_cast( output_buffer.height() ); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + sutil::saveImage( outfile.c_str(), buffer, false ); +} + + +int main( int argc, char* argv[] ) +{ + SampleState state( 1024, 768 ); + std::string outfile; + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::GL_INTEROP; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg( argv[i] ); + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--no-gl-interop" ) + { + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + } + else if( arg == "--file" || arg == "-f" ) + { + if( i < argc - 1 ) + { + outfile = argv[++i]; + } + else + { + printUsageAndExit( argv[0] ); + } + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + int width, height; + sutil::parseDimensions( dims_arg.c_str(), width, height ); + state.params.image_width = width; + state.params.image_height = height; + } + else + { + std::cerr << "Unknown option '" << arg << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + initCamera( state ); + createContext( state ); + buildGAS( state ); + buildIAS( state ); + createModule( state ); + createProgramGroups( state ); + createPipeline( state ); + createSbt( state ); + + initLaunch( state ); + if( outfile.empty() ) + { + GLFWwindow* window = sutil::initUI( "optixDynamicMaterials", state.params.image_width, state.params.image_height ); + glfwSetKeyCallback( window, keyCallback ); + { + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, state.params.image_width, + state.params.image_height ); + output_buffer.setStream( state.stream ); + sutil::GLDisplay gl_display; + + while( !glfwWindowShouldClose( window ) ) + { + glfwPollEvents(); + updateState( output_buffer, state ); + launch( state, output_buffer ); + display( output_buffer, gl_display, window ); + displayUsage(); + glfwSwapBuffers( window ); + } + } + sutil::cleanupUI( window ); + } + else + { + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + sutil::initGLFW(); // For GL context + sutil::initGL(); + } + + { + // this scope is for output_buffer, to ensure the destructor is called bfore glfwTerminate() + + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, state.params.image_width, + state.params.image_height ); + updateState( output_buffer, state ); + launch( state, output_buffer ); + + // Original setup - R, G, B spheres from left to right. + printBuffer( output_buffer, getIndexedFilename( outfile ) ); + + // Now add "dynamism" - first cycle through three colors of sphere 0 + g_hasDataChanged = true; + updateState( output_buffer, state ); + launch( state, output_buffer ); + printBuffer( output_buffer, getIndexedFilename( outfile ) ); + + g_hasDataChanged = true; + updateState( output_buffer, state ); + launch( state, output_buffer ); + printBuffer( output_buffer, getIndexedFilename( outfile ) ); + + g_hasDataChanged = true; + updateState( output_buffer, state ); + launch( state, output_buffer ); + printBuffer( output_buffer, getIndexedFilename( outfile ) ); + + // Now cycle through three SBT entries for sphere 2 + g_hasSbtChanged = true; + updateState( output_buffer, state ); + launch( state, output_buffer ); + printBuffer( output_buffer, getIndexedFilename( outfile ) ); + + g_hasSbtChanged = true; + updateState( output_buffer, state ); + launch( state, output_buffer ); + printBuffer( output_buffer, getIndexedFilename( outfile ) ); + + // This should give us an image identical to the original one + g_hasSbtChanged = true; + updateState( output_buffer, state ); + launch( state, output_buffer ); + printBuffer( output_buffer, getIndexedFilename( outfile ) ); + + // Toggle the material on the middle sphere + g_hasOffsetChanged = true; + updateState( output_buffer, state ); + launch( state, output_buffer ); + printBuffer( output_buffer, getIndexedFilename( outfile ) ); + } + + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + glfwTerminate(); + } + } + + // + // Cleanup + // + { + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_ias_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_param ) ) ); + + + OPTIX_CHECK( optixPipelineDestroy( state.pipeline ) ); + for( auto grp : state.hitgroup_prog_groups ) + OPTIX_CHECK( optixProgramGroupDestroy( grp ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.miss_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.raygen_prog_group ) ); + OPTIX_CHECK( optixModuleDestroy( state.module ) ); + + OPTIX_CHECK( optixDeviceContextDestroy( state.context ) ); + } + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicMaterials/optixDynamicMaterials.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicMaterials/optixDynamicMaterials.cu new file mode 100644 index 00000000..fe8309a9 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicMaterials/optixDynamicMaterials.cu @@ -0,0 +1,184 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "optixDynamicMaterials.h" +#include + +#include + +extern "C" __constant__ Params params; + +constexpr unsigned int SBT_STRIDE_COLLAPSE = 0; + +static __forceinline__ __device__ void trace( OptixTraversableHandle handle, float3 ray_origin, float3 ray_direction, float tmin, float tmax, float3* prd ) +{ + unsigned int p0, p1, p2; + p0 = __float_as_uint( prd->x ); + p1 = __float_as_uint( prd->y ); + p2 = __float_as_uint( prd->z ); + optixTrace( handle, ray_origin, ray_direction, tmin, tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), OPTIX_RAY_FLAG_NONE, + 0, // SBT offset + SBT_STRIDE_COLLAPSE, // SBT stride + 0, // missSBTIndex + p0, p1, p2 ); + prd->x = __uint_as_float( p0 ); + prd->y = __uint_as_float( p1 ); + prd->z = __uint_as_float( p2 ); +} + + +static __forceinline__ __device__ void setPayload( float3 p ) +{ + optixSetPayload_0( __float_as_uint( p.x ) ); + optixSetPayload_1( __float_as_uint( p.y ) ); + optixSetPayload_2( __float_as_uint( p.z ) ); +} + + +static __forceinline__ __device__ float3 getPayload() +{ + return make_float3( __uint_as_float( optixGetPayload_0() ), + __uint_as_float( optixGetPayload_1() ), + __uint_as_float( optixGetPayload_2() ) ); +} + + +static __forceinline__ __device__ float3 getShadingNormal() +{ + return make_float3( __uint_as_float( optixGetAttribute_0() ), + __uint_as_float( optixGetAttribute_1() ), + __uint_as_float( optixGetAttribute_2() ) ); +} + + +extern "C" __global__ void __raygen__rg() +{ + const uint3 idx = optixGetLaunchIndex(); + const uint3 dim = optixGetLaunchDimensions(); + + const float3 U = params.camera_u; + const float3 V = params.camera_v; + const float3 W = params.camera_w; + const float2 d = 2.0f * make_float2( static_cast( idx.x ) / static_cast( dim.x ), + static_cast( idx.y ) / static_cast( dim.y ) ) - 1.0f; + + const float3 origin = params.cam_eye; + const float3 direction = normalize( d.x * U + d.y * V + W ); + float3 payload_rgb = make_float3( 0.5f, 0.5f, 0.5f ); + trace( params.handle, origin, direction, + 0.00f, // tmin + 1e16f, // tmax + &payload_rgb ); + + params.image[idx.y * params.image_width + idx.x] = make_color( payload_rgb ); +} + + +extern "C" __global__ void __miss__ms() +{ + MissData* missData = reinterpret_cast( optixGetSbtDataPointer() ); + float3 payload = getPayload(); + setPayload( missData->color ); +} + + +extern "C" __global__ void __intersection__is() +{ + HitGroupData* hgData = reinterpret_cast( optixGetSbtDataPointer() ); + const float3 orig = optixGetObjectRayOrigin(); + const float3 dir = optixGetObjectRayDirection(); + + const float3 center = {0.f, 0.f, 0.f}; + const float3 O = orig - center; + const float l = 1 / length( dir ); + const float3 D = dir * l; + + const float b = dot( O, D ); + const float c = dot( O, O ) - params.radius * params.radius; + const float disc = b * b - c; + if( disc > 0.0f ) + { + const float sdisc = sqrtf( disc ); + const float root1 = ( -b - sdisc ); + + const float root11 = 0.0f; + const float3 shading_normal = ( O + ( root1 + root11 ) * D ) / params.radius; + unsigned int p0, p1, p2; + p0 = __float_as_uint( shading_normal.x ); + p1 = __float_as_uint( shading_normal.y ); + p2 = __float_as_uint( shading_normal.z ); + + optixReportIntersection( root1, // t hit + 0, // user hit kind + p0, p1, p2 ); + } +} + + +__forceinline__ __device__ void closesthit_impl( float3 baseColor ) +{ + float3 normals = normalize( optixTransformNormalFromObjectToWorldSpace( getShadingNormal() ) ) * 0.5f + 0.5f; + + // add material effects + normals *= baseColor; + setPayload( normals ); +} + +extern "C" __global__ void __closesthit__ch() +{ + HitGroupData* hgData = reinterpret_cast( optixGetSbtDataPointer() ); + closesthit_impl( hgData->color ); +} + +extern "C" __global__ void __closesthit__normal() +{ + float3 normals = normalize( optixTransformNormalFromObjectToWorldSpace( getShadingNormal() ) ) * 0.5f + 0.5f; + setPayload( normals ); +} + +extern "C" __global__ void __closesthit__red() +{ + closesthit_impl( make_float3( 1.f, 0.f, 0.f ) ); +} + +extern "C" __global__ void __closesthit__green() +{ + closesthit_impl( make_float3( 0.f, 1.f, 0.f ) ); +} + +extern "C" __global__ void __closesthit__blue() +{ + closesthit_impl( make_float3( 0.f, 0.f, 1.f ) ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicMaterials/optixDynamicMaterials.h b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicMaterials/optixDynamicMaterials.h new file mode 100644 index 00000000..08dab6f8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixDynamicMaterials/optixDynamicMaterials.h @@ -0,0 +1,63 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +struct Params +{ + uchar4* image; + unsigned int image_width; + unsigned int image_height; + float radius; + OptixTraversableHandle handle; + float3 cam_eye; + float3 camera_u, camera_v, camera_w; + unsigned int hitgroupRecordIdx_0; + unsigned int hitgroupRecordStride; +}; + + +struct RayGenData +{ + float3 cam_eye; + float3 camera_u, camera_v, camera_w; +}; + + +struct MissData +{ + float3 color; +}; + + +struct HitGroupData +{ + float3 color; + unsigned int geometryIndex; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/CMakeLists.txt new file mode 100644 index 00000000..7581cd63 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/CMakeLists.txt @@ -0,0 +1,48 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixHair target_name + optixHair.cpp + optixHair.h + optixHair.cu + Renderers.h + Renderers.cpp + Hair.h + Hair.cpp + Head.h + Head.cpp + ProgramGroups.h + ProgramGroups.cpp + Util.h + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Hair.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Hair.cpp new file mode 100644 index 00000000..00373b72 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Hair.cpp @@ -0,0 +1,463 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "Hair.h" + +#include + +#include +#include +#include +#include +#include + +#include "ProgramGroups.h" +#include "Util.h" + + +Hair::Hair( const OptixDeviceContext context, const std::string& fileName ) + : m_context( context ) +{ + std::ifstream input( fileName.c_str(), std::ios::binary ); + SUTIL_ASSERT_MSG( input.is_open(), "Unable to open " + fileName + "." ); + + input.read( reinterpret_cast( &m_header ), sizeof( FileHeader ) ); + SUTIL_ASSERT( input ); + SUTIL_ASSERT_MSG( strncmp( m_header.magic, "HAIR", 4 ) == 0, "Hair-file error: Invalid file format." + fileName ); + m_header.fileInfo[87] = 0; + + // Segments array(unsigned short) + // The segements array contains the number of linear segments per strand; + // thus there are segments + 1 control-points/vertices per strand. + auto strandSegments = std::vector( numberOfStrands() ); + if( hasSegments() ) + { + input.read( reinterpret_cast( strandSegments.data() ), numberOfStrands() * sizeof( unsigned short ) ); + SUTIL_ASSERT_MSG( input, "Hair-file error: Cannot read segments." ); + } + else + { + std::fill( strandSegments.begin(), strandSegments.end(), defaultNumberOfSegments() ); + } + + // Compute strands vector. Each element is the index to the + // first point of the first segment of the strand. The last entry is the + // index "one beyond the last vertex". + m_strands = std::vector( strandSegments.size() + 1 ); + auto strand = m_strands.begin(); + *strand++ = 0; + for( auto segments : strandSegments ) + { + *strand = *( strand - 1 ) + 1 + segments; + strand++; + } + + // Points array(float) + SUTIL_ASSERT_MSG( hasPoints(), "Hair-file error: File contains no points." ); + m_points = std::vector( numberOfPoints() ); + input.read( reinterpret_cast( m_points.data() ), numberOfPoints() * sizeof( float3 ) ); + SUTIL_ASSERT_MSG( input, "Hair-file error: Cannot read points." ); + + // Thickness array(float) + m_thickness = std::vector( numberOfPoints() ); + if( hasThickness() ) + { + input.read( reinterpret_cast( m_thickness.data() ), numberOfPoints() * sizeof( float ) ); + SUTIL_ASSERT_MSG( input, "Hair-file error: Cannot read thickness." ); + } + else + { + std::fill( m_thickness.begin(), m_thickness.end(), defaultThickness() ); + } + + // + // Compute the axis-aligned bounding box for this hair geometry. + // + for( auto point : m_points ) + { + m_aabb.include( point ); + } + // expand the aabb by the maximum hair radius + float max_width = defaultThickness(); + if( hasThickness() ) + { + max_width = *std::max_element( m_thickness.begin(), m_thickness.end() ); + } + m_aabb.m_min = m_aabb.m_min - make_float3( max_width ); + m_aabb.m_max = m_aabb.m_max + make_float3( max_width ); +} + +Hair::~Hair() {} + +void Hair::gatherProgramGroups( HairProgramGroups* pProgramGroups ) const +{ + OptixProgramGroupDesc programGroupDesc = {}; + // + // Shader blending red and green via segment u. + // + programGroupDesc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + programGroupDesc.hitgroup.moduleCH = pProgramGroups->m_shadingModule; + programGroupDesc.hitgroup.entryFunctionNameCH = "__closesthit__curve_segment_u"; + if( QUADRATIC_BSPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_quadraticCurveModule; + else if( CUBIC_BSPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_cubicCurveModule; + else if( LINEAR_BSPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_linearCurveModule; + else if( CATROM_SPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_catromCurveModule; + programGroupDesc.hitgroup.entryFunctionNameIS = 0; // automatically supplied for built-in moduleq + pProgramGroups->add( programGroupDesc, programName() + "SegmentU" ); + + // + // Shader blending red and green via with root-to-tip (strand) u. + // + memset( &programGroupDesc, 0, sizeof( OptixProgramGroupDesc ) ); + programGroupDesc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + programGroupDesc.hitgroup.moduleCH = pProgramGroups->m_shadingModule; + programGroupDesc.hitgroup.entryFunctionNameCH = "__closesthit__curve_strand_u"; + if( QUADRATIC_BSPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_quadraticCurveModule; + else if( CUBIC_BSPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_cubicCurveModule; + else if( LINEAR_BSPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_linearCurveModule; + else if( CATROM_SPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_catromCurveModule; + programGroupDesc.hitgroup.entryFunctionNameIS = 0; // automatically supplied for built-in moduleq + pProgramGroups->add( programGroupDesc, programName() + "StrandU" ); + + // + // Shader switching color based on strand index.. + // + memset( &programGroupDesc, 0, sizeof( OptixProgramGroupDesc ) ); + programGroupDesc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + programGroupDesc.hitgroup.moduleCH = pProgramGroups->m_shadingModule; + programGroupDesc.hitgroup.entryFunctionNameCH = "__closesthit__curve_strand_idx"; + if( QUADRATIC_BSPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_quadraticCurveModule; + else if( CUBIC_BSPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_cubicCurveModule; + else if( LINEAR_BSPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_linearCurveModule; + else if( CATROM_SPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_catromCurveModule; + programGroupDesc.hitgroup.entryFunctionNameIS = 0; // automatically supplied for built-in moduleq + pProgramGroups->add( programGroupDesc, programName() + "StrandIndex" ); + + // Occlusion shader for shadow rays + memset( &programGroupDesc, 0, sizeof( OptixProgramGroupDesc ) ); + programGroupDesc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + if( QUADRATIC_BSPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_quadraticCurveModule; + else if( CUBIC_BSPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_cubicCurveModule; + else if( LINEAR_BSPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_linearCurveModule; + else if( CATROM_SPLINE == m_splineMode ) + programGroupDesc.hitgroup.moduleIS = pProgramGroups->m_catromCurveModule; + programGroupDesc.hitgroup.entryFunctionNameIS = 0; // automatically supplied for built-in modul + pProgramGroups->add( programGroupDesc, "occludeCurve" ); +} + +std::string Hair::programName() const +{ + switch( m_splineMode ) { + case LINEAR_BSPLINE: + return "hitLinearCurve"; + case QUADRATIC_BSPLINE: + return "hitQuadraticCurve"; + case CUBIC_BSPLINE: + return "hitCubicCurve"; + case CATROM_SPLINE: + return "hitCatromCurve"; + } + + SUTIL_ASSERT_FAIL_MSG( "Invalid b-spline mode" ); +} + +std::string Hair::programSuffix() const +{ + switch( m_shadeMode ) { + case SEGMENT_U: + return "SegmentU"; + case STRAND_U: + return "StrandU"; + case STRAND_IDX: + return "StrandIndex"; + } + + SUTIL_ASSERT_FAIL_MSG( "Invalid hair-shading mode" ); +} + +uint32_t Hair::numberOfStrands() const +{ + return m_header.numStrands; +} + +uint32_t Hair::numberOfPoints() const +{ + return m_header.numPoints; +} + +uint32_t Hair::defaultNumberOfSegments() const +{ + return m_header.defaultNumSegments; +} + +float Hair::defaultThickness() const +{ + return m_header.defaultThickness; +} + +float Hair::defaultAlpha() const +{ + return m_header.defaultAlpha; +} + +float3 Hair::defaultColor() const +{ + return make_float3( m_header.defaultColor.x, m_header.defaultColor.y, m_header.defaultColor.z ); +} + +std::string Hair::fileInfo() const +{ + return std::string( m_header.fileInfo ); +} + +bool Hair::hasSegments() const +{ + return ( m_header.flags & ( 0x1 << 0 ) ) > 0; +} + +bool Hair::hasPoints() const +{ + return ( m_header.flags & ( 0x1 << 1 ) ) > 0; +} + +bool Hair::hasThickness() const +{ + return ( m_header.flags & ( 0x1 << 2 ) ) > 0; +} + +bool Hair::hasAlpha() const +{ + return ( m_header.flags & ( 0x1 << 3 ) ) > 0; +} + +bool Hair::hasColor() const +{ + return ( m_header.flags & ( 0x1 << 4 ) ) > 0; +} + +std::vector Hair::points() const +{ + return m_points; +} + +std::vector Hair::widths() const +{ + return m_thickness; +} + +int Hair::numberOfSegments() const +{ + return numberOfPoints() - numberOfStrands() * curveDegree(); +} + +// Compute a list of all segment indices making up the curves array. +// +// The structure of the list is as follows: +// * For each strand all segments are listed in order from root to tip. +// * Segment indices are identical to the index of the first control-point +// of a segment. +// * The number of segments per strand is dependent on the curve degree; e.g. +// a cubic segment requires four control points, thus a cubic strand with n +// control points will have (n - 3) segments. +// +std::vector Hair::segments() const +{ + std::vector segments; + // loop to one before end, as last strand value is the "past last valid vertex" + // index + for( auto strand = m_strands.begin(); strand != m_strands.end() - 1; ++strand ) + { + const int start = *( strand ); // first vertex in first segment + const int end = *( strand + 1 ) - curveDegree(); // second vertex of last segment + for( int i = start; i < end; ++i ) + { + segments.push_back( i ); + } + } + + return segments; +} + +std::vector Hair::strandU() const +{ + std::vector strand_u; + for( auto strand = m_strands.begin(); strand != m_strands.end() - 1; ++strand ) + { + const int start = *( strand ); + const int end = *( strand + 1 ) - curveDegree(); + const int segments = end - start; // number of strand's segments + const float scale = 1.0f / segments; + for( int i = 0; i < segments; ++i ) + { + strand_u.push_back( make_float2( i * scale, scale ) ); + } + } + + return strand_u; +} + +std::vector Hair::strandIndices() const +{ + std::vector strandIndices; + int strandIndex = 0; + for( auto strand = m_strands.begin(); strand != m_strands.end() - 1; ++strand ) + { + const int start = *( strand ); + const int end = *( strand + 1 ) - curveDegree(); + for( auto segment = start; segment != end; ++segment ) + { + strandIndices.push_back( strandIndex ); + } + ++strandIndex; + } + + return strandIndices; +} + +std::vector Hair::strandInfo() const +{ + std::vector strandInfo; + unsigned int firstPrimitiveIndex = 0; + for( auto strand = m_strands.begin(); strand != m_strands.end() - 1; ++strand ) + { + uint2 info; + info.x = firstPrimitiveIndex; // strand's start index + info.y = *( strand + 1 ) - *(strand)-curveDegree(); // number of segments in strand + firstPrimitiveIndex += info.y; // increment with number of primitives/segments in strand + strandInfo.push_back( info ); + } + return strandInfo; +} + +void Hair::setRadiusMode( Radius radiusMode ) +{ + if( m_radiusMode != radiusMode ) + { + m_radiusMode = radiusMode; + if( CONSTANT_R == m_radiusMode ) + { + // assign all radii the root radius + const float r = m_thickness[0]; + for( auto ir = m_thickness.begin(); ir != m_thickness.end(); ++ir ) + *ir = r; + } + else if( TAPERED_R == m_radiusMode ) + { + const float r = m_thickness[0]; + for( auto strand = m_strands.begin(); strand != m_strands.end() - 1; ++strand ) + { + const int rootVertex = *( strand ); + const int vertices = *( strand + 1 ) - rootVertex; // vertices in strand + for( int i = 0; i < vertices; ++i ) + { + m_thickness[rootVertex + i] = r * ( vertices - 1 - i ) / static_cast( vertices - 1 ); + } + } + } + } +} + +std::string toString( bool b ) +{ + std::string result; + if( b ) + result = "true"; + else + result = "false"; + return result; +} + +std::ostream& operator<<( std::ostream& o, Hair::SplineMode splineMode ) +{ + switch( splineMode ) + { + case Hair::LINEAR_BSPLINE: + o << "LINEAR_BSPLINE"; + break; + case Hair::QUADRATIC_BSPLINE: + o << "QUADRATIC_BSPLINE"; + break; + case Hair::CUBIC_BSPLINE: + o << "CUBIC_BSPLINE"; + break; + case Hair::CATROM_SPLINE: + o << "CATROM_SPLINE"; + break; + default: + SUTIL_ASSERT_FAIL_MSG( "Invalid spline mode." ); + } + + return o; +} + +std::ostream& operator<<( std::ostream& o, const Hair& hair ) +{ + o << "Hair: " << std::endl; + o << "Number of strands: " << hair.numberOfStrands() << std::endl; + o << "Number of points: " << hair.numberOfPoints() << std::endl; + o << "Spline mode: " << hair.m_splineMode << std::endl; + o << "Contains segments: " << toString( hair.hasSegments() ) << std::endl; + o << "Contains points: " << toString( hair.hasPoints() ) << std::endl; + o << "Contains alpha: " << toString( hair.hasAlpha() ) << std::endl; + o << "Contains color: " << toString( hair.hasColor() ) << std::endl; + o << "Default number of segments: " << hair.defaultNumberOfSegments() << std::endl; + o << "Default thickness: " << hair.defaultThickness() << std::endl; + o << "Default alpha: " << hair.defaultAlpha() << std::endl; + float3 color = hair.defaultColor(); + o << "Default color: (" << color.x << ", " << color.y << ", " << color.z << ")" << std::endl; + std::string fileInfo = hair.fileInfo(); + o << "File info: "; + if( fileInfo.empty() ) + o << "n/a" << std::endl; + else + o << fileInfo << std::endl; + + o << "Strands: [" << hair.m_strands[0] << "..." << hair.m_strands[hair.m_strands.size() - 1] << "]" << std::endl; + o << "Points: [" << hair.m_points[0] << "..." << hair.m_points[hair.m_points.size() - 1] << "]" << std::endl; + o << "Thickness: [" << hair.m_thickness[0] << "..." << hair.m_thickness[hair.m_thickness.size() - 1] << "]" << std::endl; + o << "Bounding box: [" << hair.m_aabb.m_min << ", " << hair.m_aabb.m_max << "]" << std::endl; + + return o; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Hair.h b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Hair.h new file mode 100644 index 00000000..b38b6738 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Hair.h @@ -0,0 +1,213 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#include +#include + +#include +#include +#include + +#include +#include +#include + + +// forwrad declarations +class Context; +class HairProgramGroups; + + +class Hair +{ + public: + enum SplineMode + { + LINEAR_BSPLINE, + QUADRATIC_BSPLINE, + CUBIC_BSPLINE, + CATROM_SPLINE + }; + enum Shade + { + SEGMENT_U, + STRAND_U, + STRAND_IDX + }; + enum Radius + { + CONSTANT_R, + TAPERED_R + }; + + Hair( const OptixDeviceContext context, const std::string& fileName ); + virtual ~Hair(); + + // Factory method for loading Hair from file. + static Hair Load( const std::string& fileName, const OptixDeviceContext context ); + + void setSplineMode( SplineMode splineMode ) { m_splineMode = splineMode; }; + SplineMode splineMode() const { return m_splineMode; }; + + void setShadeMode( Shade shadeMode ) { m_shadeMode = shadeMode; }; + Shade shadeMode() const { return m_shadeMode; }; + + void setRadiusMode( Radius radiusMode ); + Radius radiusMode() const { return m_radiusMode; }; + + uint32_t numberOfStrands() const; + uint32_t numberOfPoints() const; + std::string fileInfo() const; + + std::vector points() const; + std::vector widths() const; + + int numberOfSegments() const; + + // Compute a vector containing vertex indices for all segments + // making up the hair geometry. E.g. + // [h0s0, h0s1, ..., h0sn0, h1s0, h1s1, ..., h1sn1, h2s0, ...] + // + std::vector segments() const; + + std::vector strandU() const; + std::vector strandIndices() const; + std::vector strandInfo() const; + + virtual void gatherProgramGroups( HairProgramGroups* pProgramGroups ) const; + + std::string programName() const; + std::string programSuffix() const; + + sutil::Aabb aabb() const { return m_aabb; } + unsigned int usesPrimitiveTypes() const + { + switch( m_splineMode ) { + case LINEAR_BSPLINE: + return OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_LINEAR; + case QUADRATIC_BSPLINE: + return OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_QUADRATIC_BSPLINE; + case CUBIC_BSPLINE: + return OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CUBIC_BSPLINE; + case CATROM_SPLINE: + return OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CATMULLROM; + } + SUTIL_ASSERT_FAIL_MSG( "Invalid b-spline mode." ); + } + + protected: + bool hasSegments() const; + bool hasPoints() const; + bool hasThickness() const; + bool hasAlpha() const; + bool hasColor() const; + + OptixTraversableHandle gas() const; + + uint32_t defaultNumberOfSegments() const; + float defaultThickness() const; + float defaultAlpha() const; + float3 defaultColor() const; + + void makeOptix() const; + void clearOptix(); + + + private: + + // .hair format spec here: http://www.cemyuksel.com/research/hairmodels/ + struct FileHeader + { + // Bytes 0 - 3 Must be "HAIR" in ascii code(48 41 49 52) + char magic[4]; + + // Bytes 4 - 7 Number of hair strands as unsigned int + uint32_t numStrands; + + // Bytes 8 - 11 Total number of points of all strands as unsigned int + uint32_t numPoints; + + // Bytes 12 - 15 Bit array of data in the file + // Bit - 5 to Bit - 31 are reserved for future extension(must be 0). + uint32_t flags; + + // Bytes 16 - 19 Default number of segments of hair strands as unsigned int + // If the file does not have a segments array, this default value is used. + uint32_t defaultNumSegments; + + // Bytes 20 - 23 Default thickness hair strands as float + // If the file does not have a thickness array, this default value is used. + float defaultThickness; + + // Bytes 24 - 27 Default transparency hair strands as float + // If the file does not have a transparency array, this default value is used. + float defaultAlpha; + + // Bytes 28 - 39 Default color hair strands as float array of size 3 + // If the file does not have a color array, this default value is used. + float3 defaultColor; + + // Bytes 40 - 127 File information as char array of size 88 in ascii + char fileInfo[88]; + }; + + FileHeader m_header; + std::vector m_strands; + std::vector m_points; + std::vector m_thickness; + + SplineMode m_splineMode = CUBIC_BSPLINE; + unsigned int curveDegree() const + { + switch( m_splineMode ) { + case LINEAR_BSPLINE: + return 1; + case QUADRATIC_BSPLINE: + return 2; + case CUBIC_BSPLINE: + case CATROM_SPLINE: + return 3; + } + SUTIL_ASSERT_FAIL_MSG( "Invalid spline mode." ); + } + Shade m_shadeMode = SEGMENT_U; + Radius m_radiusMode = CONSTANT_R; + + mutable sutil::Aabb m_aabb; + + OptixDeviceContext m_context = 0; + + friend std::ostream& operator<<( std::ostream& o, const Hair& hair ); +}; + +// Output operator for Hair +std::ostream& operator<<( std::ostream& o, const Hair& hair ); diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Head.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Head.cpp new file mode 100644 index 00000000..c6055364 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Head.cpp @@ -0,0 +1,250 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "Head.h" + +#include +#include +#include + +#define TINYGLTF_IMPLEMENTATION +#if defined( WIN32 ) +#pragma warning( push ) +#pragma warning( disable : 4267 ) +#endif +#include +#define STB_IMAGE_IMPLEMENTATION +#include +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include +#if defined( WIN32 ) +#pragma warning( pop ) +#endif + +#include +#include +#include +#include +#include +#include + +#include "ProgramGroups.h" +#include "Util.h" +#include "optixHair.h" + + +Head::Head( const OptixDeviceContext context, const std::string& fileName ) + +{ + tinygltf::Model model; + tinygltf::TinyGLTF loader; + + std::string err; + std::string warn; + + bool ret = loader.LoadASCIIFromFile( &model, &err, &warn, fileName ); + if( !warn.empty() ) + std::cout << "glTF WARNING: " << warn << std::endl; + if( !ret ) + { + std::cout << "Failed to load GLTF scene '" << fileName << "': " << err << std::endl; + throw sutil::Exception( err.c_str() ); + } + // + // Process buffer data first -- buffer views will reference this list + // + SUTIL_ASSERT( 1 == model.buffers.size() ); + createOnDevice( model.buffers[0].data, &m_buffer ); + + SUTIL_ASSERT( model.nodes.size() == 1 ); + SUTIL_ASSERT( model.nodes[0].mesh != -1 ); + const auto& gltfMesh = model.meshes[model.nodes[0].mesh]; + std::cout << "Processing glTF mesh: '" << gltfMesh.name << "'\n"; + std::cout << "\tNum mesh primitive groups: " << gltfMesh.primitives.size() << std::endl; + SUTIL_ASSERT( gltfMesh.primitives.size() == 1 ); + + auto primitive = gltfMesh.primitives[0]; + SUTIL_ASSERT( primitive.mode == TINYGLTF_MODE_TRIANGLES ); + + // Indices + + std::cout << "Processing index buffer" << std::endl; + SUTIL_ASSERT( primitive.indices != -1 ); + auto& accessor = model.accessors[primitive.indices]; + auto& bufferView = model.bufferViews[accessor.bufferView]; + OptixBuildInput buildInput = {}; + + m_triangleMesh.indices.data = m_buffer + bufferView.byteOffset + accessor.byteOffset; + SUTIL_ASSERT( accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT ); + m_triangleMesh.indices.elmt_byte_size = accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT ? + 2 : + accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT ? + 4 : + accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT ? 4 : 0; + SUTIL_ASSERT_MSG( m_triangleMesh.indices.elmt_byte_size != 0, "gltf accessor component type not supported" ); + m_triangleMesh.indices.byte_stride = static_cast( bufferView.byteStride ? bufferView.byteStride : m_triangleMesh.indices.elmt_byte_size ); + SUTIL_ASSERT( accessor.count % 3 == 0 ); + m_triangleMesh.indices.count = static_cast( accessor.count ); + + // index buffer build input + buildInput.triangleArray.indexFormat = + m_triangleMesh.indices.elmt_byte_size == 2 ? OPTIX_INDICES_FORMAT_UNSIGNED_SHORT3 : OPTIX_INDICES_FORMAT_UNSIGNED_INT3; + buildInput.triangleArray.indexStrideInBytes = m_triangleMesh.indices.byte_stride * 3; + buildInput.triangleArray.numIndexTriplets = m_triangleMesh.indices.count / 3; + buildInput.triangleArray.indexBuffer = m_triangleMesh.indices.data; + const unsigned int triangleFlags = OPTIX_GEOMETRY_FLAG_NONE; + buildInput.triangleArray.flags = &triangleFlags; + buildInput.triangleArray.numSbtRecords = 1; + m_triangles = m_triangleMesh.indices.count; + + // Vertex array + SUTIL_ASSERT( primitive.attributes.find( "POSITION" ) != primitive.attributes.end() ); + const int32_t positionIndex = primitive.attributes.at( "POSITION" ); + std::cout << "Processing position array" << positionIndex << std::endl; + SUTIL_ASSERT( positionIndex != -1 ); + accessor = model.accessors[positionIndex]; + bufferView = model.bufferViews[accessor.bufferView]; + SUTIL_ASSERT( accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT ); + m_triangleMesh.positions.data = m_buffer + bufferView.byteOffset + accessor.byteOffset; + m_triangleMesh.positions.elmt_byte_size = accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT ? + 2 : + accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT ? + 4 : + accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT ? 4 : 0; + m_triangleMesh.positions.elmt_byte_size *= 3; + SUTIL_ASSERT_MSG( m_triangleMesh.indices.elmt_byte_size != 0, "gltf accessor component type not supported" ); + m_triangleMesh.positions.byte_stride = static_cast( bufferView.byteStride ? bufferView.byteStride : m_triangleMesh.positions.elmt_byte_size ); + m_triangleMesh.positions.count = static_cast( accessor.count ); + // bounding box + sutil::Aabb bb = sutil::Aabb( make_float3( (float) accessor.minValues[0], (float) accessor.minValues[1], (float) accessor.minValues[2] ), + make_float3( (float) accessor.maxValues[0], (float) accessor.maxValues[1], (float) accessor.maxValues[2] ) ); + m_aabb.include( bb ); + m_vertices = m_triangleMesh.positions.count; + + // vertex buffer build input + buildInput.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + buildInput.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + SUTIL_ASSERT( m_triangleMesh.positions.byte_stride == sizeof( float3 ) ); + buildInput.triangleArray.vertexStrideInBytes = m_triangleMesh.positions.byte_stride; + buildInput.triangleArray.numVertices = m_triangleMesh.positions.count; + buildInput.triangleArray.vertexBuffers = &m_triangleMesh.positions.data; + + // Normal array + auto normalAccessorIter = primitive.attributes.find( "NORMAL" ); + SUTIL_ASSERT( normalAccessorIter != primitive.attributes.end() ); + const int32_t normalIndex = normalAccessorIter->second; + std::cout << "Processing normal array" << std::endl; + accessor = model.accessors[normalIndex]; + bufferView = model.bufferViews[accessor.bufferView]; + m_triangleMesh.normals.data = m_buffer + bufferView.byteOffset + accessor.byteOffset; + m_triangleMesh.normals.byte_stride = static_cast( bufferView.byteStride ? bufferView.byteStride : sizeof( float3 ) ); + m_triangleMesh.normals.count = static_cast( accessor.count ); + m_triangleMesh.positions.elmt_byte_size = accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT ? + 2 : + accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT ? + 4 : + accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT ? 4 : 0; + m_triangleMesh.positions.elmt_byte_size *= 3; + SUTIL_ASSERT_MSG( m_triangleMesh.indices.elmt_byte_size != 0, "gltf accessor component type not supported" ); + std::cout << "Build input type: " << buildInput.type << std::endl; + + OptixAccelBufferSizes bufferSizes; + OptixAccelBuildOptions accelBuildOptions = {}; + accelBuildOptions.buildFlags = OPTIX_BUILD_FLAG_NONE; + accelBuildOptions.operation = OPTIX_BUILD_OPERATION_BUILD; + OPTIX_CHECK( optixAccelComputeMemoryUsage( context, &accelBuildOptions, &buildInput, 1, &bufferSizes ) ); + + CUdeviceptr deviceTempBuffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &deviceTempBuffer ), bufferSizes.tempSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &m_deviceBufferGAS ), bufferSizes.outputSizeInBytes ) ); + + OPTIX_CHECK( optixAccelBuild( context, 0, // CUDA stream + &accelBuildOptions, &buildInput, 1, deviceTempBuffer, bufferSizes.tempSizeInBytes, + m_deviceBufferGAS, bufferSizes.outputSizeInBytes, &m_hGAS, + nullptr, // emitted property list + 0 ) ); // num emitted properties + + CUDA_CHECK( cudaFree( reinterpret_cast( deviceTempBuffer ) ) ); +} + +Head::~Head() +{ + + CUDA_CHECK_NOTHROW( cudaFree( reinterpret_cast( m_buffer ) ) ); + CUDA_CHECK_NOTHROW( cudaFree( reinterpret_cast( m_deviceBufferGAS ) ) ); +} + +void Head::gatherProgramGroups( HairProgramGroups* pProgramGroups ) const +{ + OptixProgramGroupDesc programGroupDesc = {}; + programGroupDesc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + programGroupDesc.hitgroup.moduleCH = pProgramGroups->m_whittedModule; + programGroupDesc.hitgroup.entryFunctionNameCH = "__closesthit__radiance"; + pProgramGroups->add( programGroupDesc, "hitTriangle" ); + + memset( &programGroupDesc, 0, sizeof( OptixProgramGroupDesc ) ); + programGroupDesc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + pProgramGroups->add( programGroupDesc, "occludeTriangle" ); +} + +std::vector Head::sbtHitRecords( const ProgramGroups& programs, size_t rayTypes ) const +{ + SUTIL_ASSERT_MSG( 2 == rayTypes, "Head requires two ray types." ); + std::vector records; + + HitRecord hitGroupRecord = {}; + + hitGroupRecord.data.geometry_data.setTriangleMesh( m_triangleMesh ); + hitGroupRecord.data.material_data.pbr.base_color = {0.5f, 0.5f, 0.5f}; + hitGroupRecord.data.material_data.pbr.metallic = 0.2f; + hitGroupRecord.data.material_data.pbr.roughness = 1.0f; + OPTIX_CHECK( optixSbtRecordPackHeader( programs["hitTriangle"], &hitGroupRecord ) ); + records.push_back( hitGroupRecord ); + + OPTIX_CHECK( optixSbtRecordPackHeader( programs["occludeTriangle"], &hitGroupRecord ) ); + records.push_back( hitGroupRecord ); + + return records; +} + +OptixTraversableHandle Head::traversable() const +{ + return m_hGAS; +} + +std::ostream& operator<<( std::ostream& o, const Head& head ) +{ + o << "Head: " << std::endl; + o << "Number of vertices: " << head.numberOfVertices() << std::endl; + o << "Number of triangles: " << head.numberOfTriangles() << std::endl; + o << "Bounding box: [" << head.m_aabb.m_min << ", " << head.m_aabb.m_max << "]" << std::endl; + + return o; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Head.h b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Head.h new file mode 100644 index 00000000..98079348 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Head.h @@ -0,0 +1,80 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#include + +#include "optixHair.h" + +#include +#include + + +// forward declarations +class Context; +class ProgramGroups; + + +class Head +{ + public: + Head( const OptixDeviceContext context, const std::string& fileName ); + ~Head(); + + virtual OptixTraversableHandle traversable() const; + + virtual void gatherProgramGroups( HairProgramGroups* pProgramGroups ) const; + + virtual std::vector sbtHitRecords( const ProgramGroups& programs, size_t rayTypes ) const; + + size_t numberOfVertices() const { return m_vertices; } + + size_t numberOfTriangles() const { return m_triangles; } + + virtual sutil::Aabb aabb() const { return m_aabb; } + + virtual unsigned int usesPrimitiveTypes() const { return OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE; } + + private: + + size_t m_vertices = 0; + size_t m_triangles = 0; + CUdeviceptr m_buffer = 0; + sutil::Aabb m_aabb; + mutable OptixTraversableHandle m_hGAS = 0; + mutable CUdeviceptr m_deviceBufferGAS = 0; + GeometryData::TriangleMesh m_triangleMesh; + + friend std::ostream& operator<<( std::ostream& o, const Head& head ); +}; + +// Ouput operator for Head +std::ostream& operator<<( std::ostream& o, const Head& head ); diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/ProgramGroups.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/ProgramGroups.cpp new file mode 100644 index 00000000..2d97f0db --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/ProgramGroups.cpp @@ -0,0 +1,136 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "ProgramGroups.h" + +#include +#include + +#include +#include + +#include + + +ProgramGroups::ProgramGroups( const OptixDeviceContext context, + OptixPipelineCompileOptions pipeOptions, + OptixProgramGroupOptions programGroupOptions = {} ) + : m_context( context ) + , m_pipeOptions( pipeOptions ) + , m_programGroupOptions( programGroupOptions ) +{ + ; +} + +void ProgramGroups::add( const OptixProgramGroupDesc& programGroupDescriptor, const std::string& name ) +{ + // Only add a new program group, if one with `name` doesn't yet exist. + if( m_nameToIndex.find( name ) == m_nameToIndex.end() ) + { + size_t last = m_programGroups.size(); + m_nameToIndex[name] = static_cast( last ); + m_programGroups.resize( last + 1 ); + OPTIX_CHECK_LOG( optixProgramGroupCreate( m_context, &programGroupDescriptor, + 1, // num program groups + &m_programGroupOptions, LOG, &LOG_SIZE, &m_programGroups[last] ) ); + } +} + +const OptixProgramGroup& ProgramGroups::operator[]( const std::string& name ) const +{ + auto iter = m_nameToIndex.find( name ); + SUTIL_ASSERT( iter != m_nameToIndex.end() ); + size_t index = iter->second; + return m_programGroups[index]; +} + +const OptixProgramGroup* ProgramGroups::data() const +{ + return &( m_programGroups[0] ); +} + +unsigned int ProgramGroups::size() const +{ + return static_cast( m_programGroups.size() ); +} + +// +// HairProgramGroups +// +HairProgramGroups::HairProgramGroups( const OptixDeviceContext context, OptixPipelineCompileOptions pipeOptions, unsigned int buildFlags ) + : ProgramGroups( context, pipeOptions ) +{ + // + // Create modules + // + OptixModuleCompileOptions defaultOptions = {}; +#if !defined( NDEBUG ) + defaultOptions.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + defaultOptions.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixHair.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( context, + &defaultOptions, + &pipeOptions, + input, + inputSize, + LOG, &LOG_SIZE, + &m_shadingModule ) ); + + input = sutil::getInputData( nullptr, nullptr, "whitted.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( context, + &defaultOptions, + &pipeOptions, + input, + inputSize, + LOG, &LOG_SIZE, + &m_whittedModule ) ); + + OptixBuiltinISOptions builtinISOptions = {}; + builtinISOptions.buildFlags = buildFlags; + if( pipeOptions.usesPrimitiveTypeFlags & OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_QUADRATIC_BSPLINE ) { + builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_QUADRATIC_BSPLINE; + OPTIX_CHECK( optixBuiltinISModuleGet( context, &defaultOptions, &pipeOptions, &builtinISOptions, &m_quadraticCurveModule ) ); + } + if( pipeOptions.usesPrimitiveTypeFlags & OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CUBIC_BSPLINE ) { + builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE; + OPTIX_CHECK( optixBuiltinISModuleGet( context, &defaultOptions, &pipeOptions, &builtinISOptions, &m_cubicCurveModule ) ); + } + if( pipeOptions.usesPrimitiveTypeFlags & OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_LINEAR ) { + builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_LINEAR; + OPTIX_CHECK( optixBuiltinISModuleGet( context, &defaultOptions, &pipeOptions, &builtinISOptions, &m_linearCurveModule ) ); + } + if( pipeOptions.usesPrimitiveTypeFlags & OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CATMULLROM ) { + builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CATMULLROM; + OPTIX_CHECK( optixBuiltinISModuleGet( context, &defaultOptions, &pipeOptions, &builtinISOptions, &m_catromCurveModule ) ); + } +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/ProgramGroups.h b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/ProgramGroups.h new file mode 100644 index 00000000..620f154d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/ProgramGroups.h @@ -0,0 +1,73 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#include + +#include +#include +#include + + +class ProgramGroups +{ + public: + const OptixProgramGroup* data() const; + unsigned int size() const; + const OptixProgramGroup& operator[]( const std::string& name ) const; + + void add( const OptixProgramGroupDesc& programGroupDescriptor, const std::string& name ); + + protected: + ProgramGroups( const OptixDeviceContext context, OptixPipelineCompileOptions pipeOptions, OptixProgramGroupOptions programGroupOptions ); + + private: + const OptixDeviceContext m_context; + OptixPipelineCompileOptions m_pipeOptions; + OptixProgramGroupOptions m_programGroupOptions; + + std::vector m_programGroups; + std::map m_nameToIndex; +}; + +class HairProgramGroups : public ProgramGroups +{ + public: + HairProgramGroups( const OptixDeviceContext context, OptixPipelineCompileOptions pipeOptions, + unsigned int buildFlags ); + + OptixModule m_shadingModule; + OptixModule m_whittedModule; + OptixModule m_quadraticCurveModule; + OptixModule m_cubicCurveModule; + OptixModule m_linearCurveModule; + OptixModule m_catromCurveModule; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/README.TXT b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/README.TXT new file mode 100644 index 00000000..793aaa6a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/README.TXT @@ -0,0 +1,25 @@ + +Keyboard commands: +* 'q' or 'ESC': Quit the application. +* '1' linear (segments) interpretation of the geometry. +* '2' quadratic b-spline interpretation of the geometry. +* '3' cubic b-spline interpretation of the geometry. +* 's' "segment u": modulate base color with segment u, i.e. each segment starts + black and ends with full luminance of the base color. +* 'r' "root-to-tip u": modulate base color with root-to-tip u, i.e. start hair + at root black and full luminance of base color at hair's tip. +* 'i' "index color": assign one of six solid colors (red, green, blue, magenta, + cyan, and yellow) based on a hair's index. The shader in this mode + demonstrates how to compute a hair index from the primitive index. + It also does root to tip shading but uses index based math to compute a + contiguous u along the hair. +* 'c' "constant radius" hair geometry. +* 't' "tapered radius" hair geometry. + +The hair model file for this SDK sample are from Cem Yuksel's web page: + + www.cemyuksel.com/research/hairmodels + +You can download three additional .hair definitions from there to be used +by the sample code. Other hair files than the default can be passed to +the executable via its "--hair" command-line parameter. diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Renderers.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Renderers.cpp new file mode 100644 index 00000000..bca4502a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Renderers.cpp @@ -0,0 +1,348 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "Renderers.h" + +#include "Hair.h" + +#include +#include + +// +// Renderer base class +// +Renderer::Renderer( HairState* pState ) + : m_pState( pState ) +{} + +void Renderer::render() const +{ + renderFrame( m_pState ); +} + +// +// FileRenderer +// +FileRenderer::FileRenderer( HairState* pState ) + : Renderer( pState ) +{ +} + +void FileRenderer::renderFile( const std::string& fileName ) const +{ + render(); + + // save result image + sutil::ImageBuffer buffer; + buffer.data = m_pState->outputBuffer.getHostPointer(); + buffer.width = m_pState->width; + buffer.height = m_pState->height; + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + sutil::saveImage( fileName.c_str(), buffer, false ); +} + +//void FileRenderer::update( HairState::Event event ){}; + +// +// WindowRenderer +// +WindowRenderer::WindowRenderer( HairState* pState ) + : Renderer( pState ) +{ + // Initialize the trackball + m_trackball.setCamera( &pState->camera ); + m_trackball.setMoveSpeed( 10.0f ); + m_trackball.setReferenceFrame( make_float3( 1.0f, 0.0f, 0.0f ), make_float3( 0.0f, 0.0f, 1.0f ), make_float3( 0.0f, 1.0f, 0.0f ) ); + m_trackball.setGimbalLock(true); + + m_window = sutil::initUI( "optixHair", pState->width, pState->height ); + glfwSetMouseButtonCallback( m_window, mouseButtonCallback ); + glfwSetCursorPosCallback( m_window, cursorPosCallback ); + glfwSetWindowSizeCallback( m_window, windowSizeCallback ); + glfwSetWindowIconifyCallback( m_window, windowIconifyCallback ); + glfwSetKeyCallback( m_window, keyCallback ); + glfwSetScrollCallback( m_window, scrollCallback ); + glfwSetWindowUserPointer( m_window, this ); +} + +WindowRenderer::~WindowRenderer() +{ + m_pState->outputBuffer.deletePBO(); + sutil::cleanupUI( m_window ); +} + +void WindowRenderer::run() const +{ + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + updateParams( m_pState ); + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + render(); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( m_window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( m_pState->width, m_pState->height, framebuf_res_x, framebuf_res_y, + m_pState->outputBuffer.getPBO() ); + t1 = std::chrono::steady_clock::now(); + display_time += t1 - t0; + + sutil::displayStats( state_update_time, render_time, display_time ); + + glfwSwapBuffers( m_window ); + } while( !glfwWindowShouldClose( m_window ) ); + CUDA_SYNC_CHECK(); +} + +// +// StaticMethods +// +WindowRenderer* WindowRenderer::GetRenderer( GLFWwindow* window ) +{ + return static_cast( glfwGetWindowUserPointer( window ) ); +} + +void WindowRenderer::mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + WindowRenderer* pRenderer = GetRenderer( window ); + HairState* pState = pRenderer->m_pState; + + if( action == GLFW_PRESS ) + { + pRenderer->m_mouseButton = button; + pRenderer->m_trackball.startTracking( static_cast( xpos ), static_cast( ypos ) ); + + pState->params.subframe_index = 0u; + } + else + { + pRenderer->m_mouseButton = -1; + } +} + + +void WindowRenderer::cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + WindowRenderer* pRenderer = GetRenderer( window ); + HairState* pState = pRenderer->m_pState; + + if( pRenderer->m_mouseButton == GLFW_MOUSE_BUTTON_LEFT ) + { + pRenderer->m_trackball.setViewMode( sutil::Trackball::LookAtFixed ); + pRenderer->m_trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), + pRenderer->m_pState->width, pRenderer->m_pState->height ); + pState->params.subframe_index = 0u; + } + else if( pRenderer->m_mouseButton == GLFW_MOUSE_BUTTON_RIGHT ) + { + pRenderer->m_trackball.setViewMode( sutil::Trackball::EyeFixed ); + pRenderer->m_trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), + pRenderer->m_pState->width, pRenderer->m_pState->height ); + pState->params.subframe_index = 0u; + } +} + + +void WindowRenderer::windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + WindowRenderer* pRenderer = GetRenderer( window ); + HairState* pState = pRenderer->m_pState; + + // Keep rendering at the current resolution when the window is minimized. + if( pRenderer->m_minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + updateSize( pState, res_x, res_y ); + pState->params.subframe_index = 0u; +} + + +void WindowRenderer::windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + WindowRenderer* pRenderer = GetRenderer( window ); + HairState* pState = pRenderer->m_pState; + pRenderer->m_minimized = ( iconified > 0 ); + pState->params.subframe_index = 0u; +} + + +void WindowRenderer::keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + WindowRenderer* pRenderer = GetRenderer( window ); + HairState* pState = pRenderer->m_pState; + if( action == GLFW_PRESS ) + { + switch( key ) + { + case GLFW_KEY_Q: + case GLFW_KEY_ESCAPE: + { + glfwSetWindowShouldClose( window, true ); + } + break; + case GLFW_KEY_1: + { + pState->pHair->setSplineMode( Hair::LINEAR_BSPLINE ); + makeHairGAS( pState ); + makeInstanceAccelerationStructure( pState ); + pState->params.handle = pState->hIAS; + makeProgramGroups( pState ); + makePipeline( pState ); + makeSBT( pState ); + pState->params.subframe_index = 0u; + + std::cout << "Switched to linear b-spline geometry." << std::endl; + } + break; + case GLFW_KEY_2: + { + pState->pHair->setSplineMode( Hair::QUADRATIC_BSPLINE ); + makeHairGAS( pState ); + makeInstanceAccelerationStructure( pState ); + pState->params.handle = pState->hIAS; + makeProgramGroups( pState ); + makePipeline( pState ); + makeSBT( pState ); + pState->params.subframe_index = 0u; + + std::cout << "Switched to quadratic b-spline geometry." << std::endl; + } + break; + case GLFW_KEY_3: + { + pState->pHair->setSplineMode( Hair::CUBIC_BSPLINE ); + makeHairGAS( pState ); + makeInstanceAccelerationStructure( pState ); + pState->params.handle = pState->hIAS; + makeProgramGroups( pState ); + makePipeline( pState ); + makeSBT( pState ); + pState->params.subframe_index = 0u; + std::cout << "Switched to cubic b-spline geometry." << std::endl; + } + break; + case GLFW_KEY_4: + { + pState->pHair->setSplineMode( Hair::CATROM_SPLINE ); + makeHairGAS( pState ); + makeInstanceAccelerationStructure( pState ); + pState->params.handle = pState->hIAS; + makeProgramGroups( pState ); + makePipeline( pState ); + makeSBT( pState ); + pState->params.subframe_index = 0u; + std::cout << "Switched to Catmull-Rom geometry." << std::endl; + } + break; + case GLFW_KEY_S: + { + pState->pHair->setShadeMode( Hair::SEGMENT_U ); + makeSBT( pState ); + pState->params.subframe_index = 0u; + std::cout << "Switched to per-segment u shading." << std::endl; + } + break; + case GLFW_KEY_R: + { + pState->pHair->setShadeMode( Hair::STRAND_U ); + makeSBT( pState ); + pState->params.subframe_index = 0u; + std::cout << "Switched to root-to-tip u shading." << std::endl; + } + break; + case GLFW_KEY_I: + { + pState->pHair->setShadeMode( Hair::STRAND_IDX ); + makeSBT( pState ); + pState->params.subframe_index = 0u; + std::cout << "Switched to per-hair color shading." << std::endl; + } + break; + case GLFW_KEY_C: + { + pState->pHair->setRadiusMode( Hair::CONSTANT_R ); + makeHairGAS( pState ); + makeInstanceAccelerationStructure( pState ); + pState->params.handle = pState->hIAS; + makeProgramGroups( pState ); + makePipeline( pState ); + makeSBT( pState ); + pState->params.subframe_index = 0u; + std::cout << "Switched to constant radius hair geometry." << std::endl; + } + break; + case GLFW_KEY_T: + { + pState->pHair->setRadiusMode( Hair::TAPERED_R ); + makeHairGAS( pState ); + makeInstanceAccelerationStructure( pState ); + pState->params.handle = pState->hIAS; + makeProgramGroups( pState ); + makePipeline( pState ); + makeSBT( pState ); + pState->params.subframe_index = 0u; + std::cout << "Switched to tapered radius hair geometry." << std::endl; + } + break; + } // switch + } // if "press" +} + + +void WindowRenderer::scrollCallback( GLFWwindow* window, double xscroll, double yscroll ) +{ + WindowRenderer* pRenderer = GetRenderer( window ); + + HairState* pState = pRenderer->m_pState; + if( pRenderer->m_trackball.wheelEvent( (int)yscroll ) ) { + pState->params.subframe_index = 0u; + } +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Renderers.h b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Renderers.h new file mode 100644 index 00000000..d30d4abc --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Renderers.h @@ -0,0 +1,92 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#include +#include + +#include "optixHair.h" + +#include + +#include + + +// forward declarations +struct GLFWwindow; + +class Renderer +{ + public: + Renderer( HairState* pState ); + + Camera defaultCamera() const; + + protected: + void render() const; + HairState* const m_pState; +}; + +class FileRenderer : public Renderer +{ + public: + FileRenderer( HairState* pState ); + + void renderFile( const std::string& fileName ) const; +}; + +class WindowRenderer : public Renderer +{ + public: + WindowRenderer( HairState* pState ); + + ~WindowRenderer(); + + void run() const; + + protected: + // + // GLFW callbacks + // + static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ); + static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ); + static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ); + static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ); + static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ); + static void scrollCallback( GLFWwindow* window, double xscroll, double yscroll ); + + private: + static WindowRenderer* GetRenderer( GLFWwindow* window ); + GLFWwindow* m_window = nullptr; + sutil::Trackball m_trackball = {}; + int32_t m_mouseButton = -1; + bool m_minimized = false; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Util.h b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Util.h new file mode 100644 index 00000000..cb15bb3d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/Util.h @@ -0,0 +1,71 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +// includes CUDA Runtime +#include +#include + +#include + + +template +void copyToDevice( const T& source, CUdeviceptr destination ) +{ + CUDA_CHECK( cudaMemcpy( reinterpret_cast( destination ), &source, sizeof( T ), cudaMemcpyHostToDevice ) ); +} + +template +void createOnDevice( const T& source, CUdeviceptr* destination ) +{ + CUDA_CHECK( cudaMalloc( reinterpret_cast( destination ), sizeof( T ) ) ); + copyToDevice( source, *destination ); +} + +template +void copyToDevice( const std::vector& source, CUdeviceptr destination ) +{ + CUDA_CHECK( cudaMemcpy( reinterpret_cast( destination ), source.data(), source.size() * sizeof( T ), cudaMemcpyHostToDevice ) ); +} + +template +void createOnDevice( const std::vector& source, CUdeviceptr* destination ) +{ + CUDA_CHECK( cudaMalloc( reinterpret_cast( destination ), source.size() * sizeof( T ) ) ); + copyToDevice( source, *destination ); +} + + +inline std::ostream& operator<<( std::ostream& o, float3 v ) +{ + o << "(" << v.x << ", " << v.y << ", " << v.z << ")"; + return o; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/optixHair.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/optixHair.cpp new file mode 100644 index 00000000..7c6864a8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/optixHair.cpp @@ -0,0 +1,768 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include "Hair.h" +#include "Head.h" +#include "ProgramGroups.h" +#include "Renderers.h" +#include "Util.h" +#include "optixHair.h" + + +void makeHairGAS( HairState* pState ) +{ + Hair* const pHair = pState->pHair; + // Free any HairGAS related memory previously allocated. + cudaFree( reinterpret_cast( pState->deviceBufferHairGAS ) ); + pState->deviceBufferHairGAS = 0; + pState->hHairGAS = 0; + + // Use default options for simplicity. In a real use case we would want to + // enable compaction, etc + OptixAccelBuildOptions accelBuildOptions = {}; + accelBuildOptions.buildFlags = pState->buildFlags; + accelBuildOptions.operation = OPTIX_BUILD_OPERATION_BUILD; + CUdeviceptr devicePoints = 0; + CUdeviceptr deviceWidths = 0; + CUdeviceptr deviceStrands = 0; + + auto tempPoints = pState->pHair->points(); + createOnDevice( tempPoints, &devicePoints ); + createOnDevice( pHair->widths(), &deviceWidths ); + auto segments = pHair->segments(); + createOnDevice( segments, &deviceStrands ); + unsigned int numberOfHairSegments = static_cast( segments.size() ); + + // Curve build input. + OptixBuildInput buildInput = {}; + + buildInput.type = OPTIX_BUILD_INPUT_TYPE_CURVES; + switch( pHair->splineMode() ) + { + case Hair::LINEAR_BSPLINE: + buildInput.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_LINEAR; + break; + case Hair::QUADRATIC_BSPLINE: + buildInput.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_QUADRATIC_BSPLINE; + break; + case Hair::CUBIC_BSPLINE: + buildInput.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE; + break; + case Hair::CATROM_SPLINE: + buildInput.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CATMULLROM; + break; + default: + SUTIL_ASSERT_FAIL_MSG( "Invalid spline mode" ); + } + buildInput.curveArray.numPrimitives = numberOfHairSegments; + buildInput.curveArray.vertexBuffers = &devicePoints; + buildInput.curveArray.numVertices = static_cast( tempPoints.size() ); + buildInput.curveArray.vertexStrideInBytes = sizeof( float3 ); + buildInput.curveArray.widthBuffers = &deviceWidths; + buildInput.curveArray.widthStrideInBytes = sizeof( float ); + buildInput.curveArray.normalBuffers = 0; + buildInput.curveArray.normalStrideInBytes = 0; + buildInput.curveArray.indexBuffer = deviceStrands; + buildInput.curveArray.indexStrideInBytes = sizeof( int ); + buildInput.curveArray.flag = OPTIX_GEOMETRY_FLAG_NONE; + buildInput.curveArray.primitiveIndexOffset = 0; + + OptixAccelBufferSizes bufferSizesGAS; + OPTIX_CHECK( optixAccelComputeMemoryUsage( pState->context, + &accelBuildOptions, + &buildInput, + 1, // Number of build inputs + &bufferSizesGAS ) ); + + CUdeviceptr deviceTempBufferGAS; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &deviceTempBufferGAS ), + bufferSizesGAS.tempSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &pState->deviceBufferHairGAS ), + bufferSizesGAS.outputSizeInBytes ) ); + + CUdeviceptr deviceCompactedSize; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &deviceCompactedSize ), + sizeof(size_t) ) ); + OptixAccelEmitDesc emitDesc = {}; + emitDesc.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitDesc.result = deviceCompactedSize; + + OPTIX_CHECK( optixAccelBuild( pState->context, + 0, // CUDA stream + &accelBuildOptions, + &buildInput, + 1, // num build inputs + deviceTempBufferGAS, + bufferSizesGAS.tempSizeInBytes, + pState->deviceBufferHairGAS, + bufferSizesGAS.outputSizeInBytes, + &pState->hHairGAS, + &emitDesc, // emitted property list + 1 ) ); // num emitted properties + + size_t compactedSize; + CUDA_CHECK( cudaMemcpy(&compactedSize, (void*)deviceCompactedSize, sizeof(size_t), cudaMemcpyDeviceToHost) ); + + printf("bufferSizesGAS.outputSizeInBytes: %zd compacted size: %zd\n", + bufferSizesGAS.outputSizeInBytes, compactedSize); + + CUdeviceptr deviceCompactedGAS; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &deviceCompactedGAS), compactedSize ) ); + + OPTIX_CHECK( optixAccelCompact( pState->context, + 0, + pState->hHairGAS, + deviceCompactedGAS, + compactedSize, + &pState->hHairGAS ) ); + + CUDA_CHECK( cudaFree( (void*)pState->deviceBufferHairGAS ) ); + CUDA_CHECK( cudaFree( (void*)deviceCompactedSize ) ); + + pState->deviceBufferHairGAS = deviceCompactedGAS; + + + + // We can now free the scratch space buffers used during build. + CUDA_CHECK( cudaFree( reinterpret_cast( deviceTempBufferGAS ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( devicePoints ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( deviceWidths ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( deviceStrands ) ) ); +} + +void makeInstanceAccelerationStructure( HairState* pState ) +{ + // Free any memory that has been previously allocated. + cudaFree( reinterpret_cast( pState->deviceBufferIAS ) ); + pState->deviceBufferIAS = 0; + pState->hIAS = 0; + + std::vector instances; + unsigned int sbtOffset = 0; + + OptixInstance instance = {}; + // Common instance settings + instance.instanceId = 0; + instance.visibilityMask = 0xFF; + instance.flags = OPTIX_INSTANCE_FLAG_NONE; + sutil::Matrix3x4 yUpTransform = { + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + }; + // Head first + if( pState->pHead ) + { + memcpy( instance.transform, yUpTransform.getData(), sizeof( float ) * 12 ); + instance.sbtOffset = sbtOffset; + instance.traversableHandle = pState->pHead->traversable(); + sbtOffset += whitted::RAY_TYPE_COUNT; + instances.push_back( instance ); + sutil::Aabb bb = pState->pHead->aabb(); + bb.transform( yUpTransform ); + pState->aabb.include( bb ); + } + // Hair second + if( pState->pHair ) + { + memcpy( instance.transform, yUpTransform.getData(), sizeof( float ) * 12 ); + instance.sbtOffset = sbtOffset; + instance.traversableHandle = pState->hHairGAS; + sbtOffset += whitted::RAY_TYPE_COUNT; + instances.push_back( instance ); + sutil::Aabb bb = pState->pHair->aabb(); + bb.transform( yUpTransform ); + pState->aabb.include( bb ); + } + + CUdeviceptr deviceInstances = 0; + createOnDevice( instances, &deviceInstances ); + + // Instance build input. + OptixBuildInput buildInput = {}; + + buildInput.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; + buildInput.instanceArray.instances = deviceInstances; + buildInput.instanceArray.numInstances = static_cast( instances.size() ); + + OptixAccelBuildOptions accelBuildOptions = {}; + accelBuildOptions.buildFlags = OPTIX_BUILD_FLAG_NONE; + accelBuildOptions.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes bufferSizesIAS; + OPTIX_CHECK( optixAccelComputeMemoryUsage( pState->context, &accelBuildOptions, &buildInput, + 1, // Number of build inputs + &bufferSizesIAS ) ); + + CUdeviceptr deviceTempBufferIAS; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &deviceTempBufferIAS ), + bufferSizesIAS.tempSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &pState->deviceBufferIAS ), + bufferSizesIAS.outputSizeInBytes ) ); + + OPTIX_CHECK( optixAccelBuild( pState->context, + 0, // CUDA stream + &accelBuildOptions, + &buildInput, + 1, // num build inputs + deviceTempBufferIAS, + bufferSizesIAS.tempSizeInBytes, + pState->deviceBufferIAS, + bufferSizesIAS.outputSizeInBytes, + &pState->hIAS, + nullptr, // emitted property list + 0 ) ); // num emitted properties + + CUDA_CHECK( cudaFree( reinterpret_cast( deviceInstances ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( deviceTempBufferIAS ) ) ); +} + +void initializeCamera( HairState* pState ) +{ + const float aspectRatio = pState->width / static_cast( pState->height ); + const float fovAngle = 30.0f; + pState->camera.setFovY( fovAngle ); + const float r = length( pState->aabb.m_max - pState->aabb.center() ); + float distance = r / sin( (float)M_PI / 180.0f * fovAngle ); + if( aspectRatio > 1.0f ) + distance *= aspectRatio; + pState->camera.setLookat( pState->aabb.center() ); + pState->camera.setEye( pState->aabb.center() + make_float3( 0.0f, 0.0f, distance ) ); + pState->camera.setUp( {0.0f, 1.0f, 0.0f} ); + pState->camera.setAspectRatio( aspectRatio ); +} + +void updateSize( HairState* pState, int width, int height ) +{ + pState->width = width; + pState->height = height; + const float aspectRatio = pState->width / static_cast( pState->height ); + pState->camera.setAspectRatio( aspectRatio ); + pState->outputBuffer.resize( pState->width, pState->height ); + pState->accumBuffer.resize( pState->width, pState->height ); +} + +OptixPipelineCompileOptions defaultPipelineCompileOptions( HairState* pState ) +{ + OptixPipelineCompileOptions pipeOptions = {}; + pipeOptions.usesMotionBlur = false; + pipeOptions.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING; + pipeOptions.numPayloadValues = 4; + pipeOptions.numAttributeValues = 1; + pipeOptions.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + pipeOptions.pipelineLaunchParamsVariableName = "params"; + + unsigned int primitiveTypes = 0; + if( pState->pHead ) + primitiveTypes |= pState->pHead->usesPrimitiveTypes(); + if( pState->pHair ) + primitiveTypes |= pState->pHair->usesPrimitiveTypes(); + pipeOptions.usesPrimitiveTypeFlags = primitiveTypes; + + return pipeOptions; +} + +void makeProgramGroups( HairState* pState ) +{ + delete( pState->pProgramGroups ); + pState->pProgramGroups = new HairProgramGroups( pState->context, defaultPipelineCompileOptions( pState ), + pState->buildFlags ); + // Miss program groups + OptixProgramGroupDesc programGroupDesc = {}; + programGroupDesc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + programGroupDesc.miss.module = pState->pProgramGroups->m_whittedModule; + programGroupDesc.miss.entryFunctionName = "__miss__constant_radiance"; + pState->pProgramGroups->add( programGroupDesc, "miss" ); + + memset( &programGroupDesc, 0, sizeof( OptixProgramGroupDesc ) ); + programGroupDesc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + programGroupDesc.miss.module = pState->pProgramGroups->m_whittedModule; + programGroupDesc.miss.entryFunctionName = "__miss__occlusion"; + pState->pProgramGroups->add( programGroupDesc, "missOcclude" ); + + // add raygen group + { + OptixProgramGroupDesc raygenProgramGroupDesc = {}; + raygenProgramGroupDesc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygenProgramGroupDesc.raygen.module = pState->pProgramGroups->m_whittedModule; + raygenProgramGroupDesc.raygen.entryFunctionName = "__raygen__pinhole"; + pState->pProgramGroups->add( raygenProgramGroupDesc, "raygen" ); + } + if( pState->pHair ) + pState->pHair->gatherProgramGroups( pState->pProgramGroups ); + if( pState->pHead ) + pState->pHead->gatherProgramGroups( pState->pProgramGroups ); +} + +std::vector hairSbtHitRecords( HairState* pState, const ProgramGroups& programs ) +{ + // clear curves_ data + cudaFree( reinterpret_cast( pState->curves.strand_u.data ) ); + pState->curves.strand_u.data = 0; + cudaFree( reinterpret_cast( pState->curves.strand_i.data ) ); + pState->curves.strand_i.data = 0; + cudaFree( reinterpret_cast( pState->curves.strand_info.data ) ); + pState->curves.strand_info.data = 0; + + std::vector records; + HitRecord hitGroupRecord = {}; + + CUdeviceptr strandUs = 0; + createOnDevice( pState->pHair->strandU(), &strandUs ); + pState->curves.strand_u.data = strandUs; + pState->curves.strand_u.byte_stride = static_cast( sizeof( float2 ) ); + SUTIL_ASSERT( pState->pHair->numberOfSegments() == static_cast( pState->pHair->strandU().size() ) ); + pState->curves.strand_u.count = static_cast( pState->pHair->numberOfSegments() ); + pState->curves.strand_u.elmt_byte_size = static_cast( sizeof( float2 ) ); + CUdeviceptr strandIs = 0; + createOnDevice( pState->pHair->strandIndices(), &strandIs ); + pState->curves.strand_i.data = strandIs; + pState->curves.strand_i.byte_stride = static_cast( sizeof( unsigned int ) ); + pState->curves.strand_i.count = static_cast( pState->pHair->numberOfSegments() ); + pState->curves.strand_i.elmt_byte_size = static_cast( sizeof( unsigned int ) ); + CUdeviceptr strandInfos = 0; + createOnDevice( pState->pHair->strandInfo(), &strandInfos ); + pState->curves.strand_info.data = strandInfos; + pState->curves.strand_info.byte_stride = static_cast( sizeof( uint2 ) ); + pState->curves.strand_info.count = static_cast( pState->pHair->numberOfStrands() ); + pState->curves.strand_info.elmt_byte_size = static_cast( sizeof( uint2 ) ); + + switch( pState->pHair->splineMode() ) + { + case Hair::LINEAR_BSPLINE: + hitGroupRecord.data.geometry_data.setLinearCurveArray( pState->curves ); + break; + case Hair::QUADRATIC_BSPLINE: + hitGroupRecord.data.geometry_data.setQuadraticCurveArray( pState->curves ); + break; + case Hair::CUBIC_BSPLINE: + hitGroupRecord.data.geometry_data.setCubicCurveArray( pState->curves ); + break; + case Hair::CATROM_SPLINE: + hitGroupRecord.data.geometry_data.setCatromCurveArray( pState->curves ); + break; + default: + SUTIL_ASSERT_FAIL_MSG( "Invalid spline mode." ); + } + + hitGroupRecord.data.material_data.pbr.base_color = {0.8f, 0.1f, 0.1f}; + hitGroupRecord.data.material_data.pbr.metallic = 0.0f; + hitGroupRecord.data.material_data.pbr.roughness = 0.6f; + + std::string name = pState->pHair->programName() + pState->pHair->programSuffix(); + OPTIX_CHECK( optixSbtRecordPackHeader( programs[name], &hitGroupRecord ) ); + records.push_back( hitGroupRecord ); + + OPTIX_CHECK( optixSbtRecordPackHeader( programs["occludeCurve"], &hitGroupRecord ) ); + records.push_back( hitGroupRecord ); + + return records; +} + + +void makeSBT( HairState* pState ) +{ + std::vector missRecords; + MissRecord missRecord; + OPTIX_CHECK( optixSbtRecordPackHeader( ( *pState->pProgramGroups )["miss"], &missRecord ) ); + missRecords.push_back( missRecord ); + OPTIX_CHECK( optixSbtRecordPackHeader( ( *pState->pProgramGroups )["missOcclude"], &missRecord ) ); + missRecords.push_back( missRecord ); + + std::vector hitRecords; + // Head first + if( pState->pHead ) + { + std::vector headRecords = pState->pHead->sbtHitRecords( *pState->pProgramGroups, whitted::RAY_TYPE_COUNT ); + std::copy( headRecords.begin(), headRecords.end(), std::back_inserter( hitRecords ) ); + } + // Hair second + if( pState->pHair ) + { + std::vector hairRecords = hairSbtHitRecords( pState, *pState->pProgramGroups ); + std::copy( hairRecords.begin(), hairRecords.end(), std::back_inserter( hitRecords ) ); + } + + // raygen record + RayGenRecord raygenRecord; + OPTIX_CHECK( optixSbtRecordPackHeader( ( *pState->pProgramGroups )["raygen"], &raygenRecord ) ); + + cudaFree( reinterpret_cast( pState->SBT.raygenRecord ) ); + cudaFree( reinterpret_cast( pState->SBT.missRecordBase ) ); + cudaFree( reinterpret_cast( pState->SBT.hitgroupRecordBase ) ); + + CUdeviceptr deviceRayGenRecord; + createOnDevice( raygenRecord, &deviceRayGenRecord ); + CUdeviceptr deviceMissRecords; + createOnDevice( missRecords, &deviceMissRecords ); + CUdeviceptr deviceHitGroupRecords; + createOnDevice( hitRecords, &deviceHitGroupRecords ); + + pState->SBT.raygenRecord = deviceRayGenRecord; + pState->SBT.missRecordBase = deviceMissRecords; + pState->SBT.missRecordStrideInBytes = sizeof( MissRecord ); + pState->SBT.missRecordCount = static_cast( missRecords.size() ); + pState->SBT.hitgroupRecordBase = deviceHitGroupRecords; + pState->SBT.hitgroupRecordStrideInBytes = sizeof( HitRecord ); + pState->SBT.hitgroupRecordCount = static_cast( hitRecords.size() ); +} + +void makePipeline( HairState* pState ) +{ + const uint32_t max_trace_depth = 2; + + if( pState->pipeline ) + OPTIX_CHECK( optixPipelineDestroy( pState->pipeline ) ); + OptixPipelineCompileOptions pipelineCompileOptions = defaultPipelineCompileOptions( pState ); + OptixPipelineLinkOptions pipelineLinkOptions = {}; + pipelineLinkOptions.maxTraceDepth = max_trace_depth; + OPTIX_CHECK_LOG( optixPipelineCreate( pState->context, + &pipelineCompileOptions, + &pipelineLinkOptions, + pState->pProgramGroups->data(), + pState->pProgramGroups->size(), + LOG, + &LOG_SIZE, + &pState->pipeline ) ); + + OptixStackSizes stack_sizes = {}; + for( unsigned int i = 0; i < pState->pProgramGroups->size(); ++i ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( pState->pProgramGroups->data()[i], &stack_sizes, pState->pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( pState->pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 2 // maxTraversableDepth + ) ); +} + +void printLogMessage( unsigned int level, const char* tag, const char* message, void* /* cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << std::endl; +} + +void initializeOptix( HairState* pState ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( nullptr ) ); + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &printLogMessage; + options.logCallbackLevel = 4; +#ifdef DEBUG + // This may incur significant performance cost and should only be done during development. + options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; +#endif + OPTIX_CHECK( optixDeviceContextCreate( 0 /* default cuda context */, &options, &pState->context ) ); +} + +void initializeParams( HairState* pState ) +{ + pState->params.accum_buffer = nullptr; // Unused for the moment + pState->params.frame_buffer = nullptr; // Will be set when output buffer is mapped + + pState->params.subframe_index = 0u; + + const float loffset = 2.0f * pState->aabb.maxExtent(); + + pState->params.miss_color = make_float3( 0.1f, 0.1f, 0.4f ); + pState->params.eye = pState->camera.eye(); + pState->camera.UVWFrame( pState->params.U, pState->params.V, pState->params.W ); + + pState->lights[0].type = Light::Type::POINT; + pState->lights[0].point.color = {1.0f, 1.0f, 1.0f}; + pState->lights[0].point.intensity = 2.0f; + pState->lights[0].point.position = pState->aabb.center() + make_float3( loffset ); + pState->lights[0].point.falloff = Light::Falloff::QUADRATIC; + + pState->lights[1].type = Light::Type::POINT; + pState->lights[1].point.color = {1.0f, 1.0f, 1.0f}; + pState->lights[1].point.intensity = 2.0f; + // headlight...slightly offset to the side of eye. + pState->lights[1].point.position = pState->camera.eye() + pState->params.U; + pState->lights[1].point.falloff = Light::Falloff::QUADRATIC; + + pState->params.lights.count = 2; + createOnDevice( pState->lights, &pState->params.lights.data ); + + pState->params.handle = pState->hIAS; + createOnDevice( pState->params, reinterpret_cast( &pState->deviceParams ) ); +} + +void updateParams( HairState* pState ) +{ + pState->params.eye = pState->camera.eye(); + pState->camera.UVWFrame( pState->params.U, pState->params.V, pState->params.W ); + pState->lights[1].point.position = pState->camera.eye() + pState->params.U; + CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast( pState->params.lights.data ), + &pState->lights, + sizeof( pState->lights ), + cudaMemcpyHostToDevice, + 0 // stream + ) ); +} + +void renderFrame( HairState* pState ) +{ + // Launch + pState->params.frame_buffer = pState->outputBuffer.map(); + pState->params.accum_buffer = pState->accumBuffer.map(); + CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast( pState->deviceParams ), + &pState->params, + sizeof( whitted::LaunchParams ), + cudaMemcpyHostToDevice, + 0 // stream + ) ); + + OPTIX_CHECK( optixLaunch( pState->pipeline, + 0, // stream + reinterpret_cast( pState->deviceParams ), + sizeof( whitted::LaunchParams ), + &( pState->SBT ), + pState->width, // launch width + pState->height, // launch height + 1 // launch depth + ) ); + pState->outputBuffer.unmap(); + pState->accumBuffer.unmap(); + + pState->params.subframe_index++; + + CUDA_SYNC_CHECK(); +} + +void printKeyboardCommands() +{ + std::cerr << "\n\nKeyboard commands:\n\n" + " 'q' (or 'ESC'): Quit the application.\n" + " '1' linear b-spline interpretation of the geometry.\n" + " '2' quadratic b-spline interpretation of the geometry.\n" + " '3' cubic b-spline interpretation of the geometry.\n" + " '4' Catmull-Rom spline interpretation of the geometry.\n" + " 's' \"segment u\": lerp from red to green via segment u,\n" + " i.e. each segment starts green and ends red.\n" + " 'r' \"root-to-tip u\": lerp red to green with root-to-tip u,\n" + " i.e. hair roots are red and tips are green.\n" + " 'i' \"index color\": assign one of five solid colors (green,\n" + " blue, magenta, cyan, and yellow) based on a hair's index;\n" + " tips lerp to red. The shader in this mode demonstrates\n" + " how to compute a hair index from the primitive index.\n" + " It also does root to tip shading but uses index based math\n" + " to compute a contiguous u along the hair.\n" + " 'c' \"constant radius\" hair geometry.\n" + " 't' \"tapered radius\" hair geometry.\n"; +} + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 1024x768\n"; + std::cerr << " --hair Specify the hair model; defaults to \"Hair/wStraight.hair\"\n"; + std::cerr << " --deg=<1|2|3> Specify the curve degree; defaults to 3\n"; + std::cerr << " --catrom Catmul-Rom spline for curve specification (forces deg = 3)\n"; + std::cerr << " --help | -h Print this usage message\n\n\n"; + printKeyboardCommands(); + exit( 0 ); +} + +void cleanupState( HairState* pState ) +{ + CUDA_CHECK( cudaFree( reinterpret_cast( pState->deviceBufferHairGAS ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pState->SBT.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pState->SBT.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pState->SBT.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pState->params.lights.data ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pState->deviceParams ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pState->curves.strand_u.data ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pState->curves.strand_i.data ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pState->curves.strand_info.data ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pState->deviceBufferIAS ) ) ); + OPTIX_CHECK( optixDeviceContextDestroy( pState->context ) ); +} + +// +// Main program +// +int main( int argc, char* argv[] ) +{ + // + // Command-line parameter parsing + // + std::string hairFile( "Hair/wStraight.hair" ); + std::vector image_size( 2 ); + image_size[0] = 1024; + image_size[1] = 786; + int curveDegree = 3; + bool catrom = false; + std::string outputFile; + + // + // Parse command line options + // + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--hair" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + hairFile = argv[++i]; + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outputFile = argv[++i]; + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + sutil::parseDimensions( dims_arg.c_str(), image_size[0], image_size[1] ); + } + else if( arg.substr( 0, 6 ) == "--deg=" ) + { + const std::string deg_arg = arg.substr( 6 ); + curveDegree = atoi( deg_arg.c_str() ); + if (catrom && curveDegree != 3) { + std::cerr << "Warning: --deg=" << curveDegree << " incompatible with --catrom mode. Forcing degree = 3." << std::endl; + curveDegree = 3; + } + } + else if( arg == "--catrom" ) + { + catrom = true; + if (curveDegree != 3) { + std::cerr << "Warning: --deg=" << curveDegree << " incompatible with --catrom mode. Forcing degree = 3." << std::endl; + curveDegree = 3; + } + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + printKeyboardCommands(); + std::cerr << "\n\n" << std::endl; + HairState state = {}; + initializeOptix( &state ); + + state.outputBuffer.setStream( 0 ); // CUDA stream + state.accumBuffer.setStream( 0 ); // CUDA stream + + std::string hairFileName = sutil::sampleDataFilePath( hairFile.c_str() ); + Hair hair( state.context, hairFileName ); + + state.width = image_size[0]; + state.height = image_size[1]; + state.outputBuffer.resize( state.width, state.height ); + state.accumBuffer.resize( state.width, state.height ); + + if( catrom ) + hair.setSplineMode( Hair::CATROM_SPLINE ); + else if( 1 == curveDegree ) + hair.setSplineMode( Hair::LINEAR_BSPLINE ); + else if( 2 == curveDegree ) + hair.setSplineMode( Hair::QUADRATIC_BSPLINE ); + else if( 3 == curveDegree ) + hair.setSplineMode( Hair::CUBIC_BSPLINE ); + else + SUTIL_ASSERT_FAIL_MSG( "Curve type unspecified" ); + std::cout << hair << std::endl; + state.pHair = &hair; + + std::string headFileName = sutil::sampleDataFilePath( "Hair/woman.gltf" ); + const Head head( state.context, headFileName ); + std::cout << head << std::endl; + state.pHead = &head; + + // with head and hair set put them into an IAS... + makeHairGAS( &state ); + makeInstanceAccelerationStructure( &state ); + initializeCamera( &state ); + makeProgramGroups( &state ); + makePipeline( &state ); + makeSBT( &state ); + + initializeParams( &state ); + + if( !outputFile.empty() ) // render single frame to file + { + const FileRenderer renderer( &state ); + renderer.renderFile( outputFile.c_str() ); + } + else + { + WindowRenderer renderer( &state ); + renderer.run(); + } + + cleanupState( &state ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/optixHair.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/optixHair.cu new file mode 100644 index 00000000..69fcd52a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/optixHair.cu @@ -0,0 +1,274 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include +#include +#include +#include +#include +#include + + +// Get curve hit-point in world coordinates. +static __forceinline__ __device__ float3 getHitPoint() +{ + const float t = optixGetRayTmax(); + const float3 rayOrigin = optixGetWorldRayOrigin(); + const float3 rayDirection = optixGetWorldRayDirection(); + + return rayOrigin + t * rayDirection; +} + +// Compute surface normal of quadratic pimitive in world space. +static __forceinline__ __device__ float3 normalLinear( const int primitiveIndex ) +{ + const OptixTraversableHandle gas = optixGetGASTraversableHandle(); + const unsigned int gasSbtIndex = optixGetSbtGASIndex(); + float4 controlPoints[2]; + + optixGetLinearCurveVertexData( gas, primitiveIndex, gasSbtIndex, 0.0f, controlPoints ); + + LinearInterpolator interpolator; + interpolator.initialize(controlPoints); + + float3 hitPoint = getHitPoint(); + // interpolators work in object space + hitPoint = optixTransformPointFromWorldToObjectSpace( hitPoint ); + const float3 normal = surfaceNormal( interpolator, optixGetCurveParameter(), hitPoint ); + return optixTransformNormalFromObjectToWorldSpace( normal ); +} + +// Compute surface normal of quadratic pimitive in world space. +static __forceinline__ __device__ float3 normalQuadratic( const int primitiveIndex ) +{ + const OptixTraversableHandle gas = optixGetGASTraversableHandle(); + const unsigned int gasSbtIndex = optixGetSbtGASIndex(); + float4 controlPoints[3]; + + optixGetQuadraticBSplineVertexData( gas, primitiveIndex, gasSbtIndex, 0.0f, controlPoints ); + + QuadraticInterpolator interpolator; + interpolator.initializeFromBSpline(controlPoints); + + float3 hitPoint = getHitPoint(); + // interpolators work in object space + hitPoint = optixTransformPointFromWorldToObjectSpace( hitPoint ); + const float3 normal = surfaceNormal( interpolator, optixGetCurveParameter(), hitPoint ); + return optixTransformNormalFromObjectToWorldSpace( normal ); +} + +// Compute surface normal of cubic b-spline pimitive in world space. +static __forceinline__ __device__ float3 normalCubic( const int primitiveIndex ) +{ + const OptixTraversableHandle gas = optixGetGASTraversableHandle(); + const unsigned int gasSbtIndex = optixGetSbtGASIndex(); + float4 controlPoints[4]; + + optixGetCubicBSplineVertexData( gas, primitiveIndex, gasSbtIndex, 0.0f, controlPoints ); + + CubicInterpolator interpolator; + interpolator.initializeFromBSpline(controlPoints); + + float3 hitPoint = getHitPoint(); + // interpolators work in object space + hitPoint = optixTransformPointFromWorldToObjectSpace( hitPoint ); + const float3 normal = surfaceNormal( interpolator, optixGetCurveParameter(), hitPoint ); + return optixTransformNormalFromObjectToWorldSpace( normal ); +} + +// Compute surface normal of Catmull-Rom pimitive in world space. +static __forceinline__ __device__ float3 normalCatrom( const int primitiveIndex ) +{ + const OptixTraversableHandle gas = optixGetGASTraversableHandle(); + const unsigned int gasSbtIndex = optixGetSbtGASIndex(); + float4 controlPoints[4]; + + optixGetCatmullRomVertexData( gas, primitiveIndex, gasSbtIndex, 0.0f, controlPoints ); + + CubicInterpolator interpolator; + interpolator.initializeFromCatrom(controlPoints); + + float3 hitPoint = getHitPoint(); + // interpolators work in object space + hitPoint = optixTransformPointFromWorldToObjectSpace( hitPoint ); + const float3 normal = surfaceNormal( interpolator, optixGetCurveParameter(), hitPoint ); + return optixTransformNormalFromObjectToWorldSpace( normal ); +} + +static __forceinline__ __device__ float3 shade( const whitted::HitGroupData* hitGroupData, const float3 hitPoint, const float3 normal, const float3 base_color ) +{ + // + // Retrieve material data + // + float metallic = hitGroupData->material_data.pbr.metallic; + float roughness = hitGroupData->material_data.pbr.roughness; + + // + // Convert to material params + // + const float F0 = 0.04f; + const float3 diff_color = base_color * ( 1.0f - F0 ) * ( 1.0f - metallic ); + const float3 spec_color = lerp( make_float3( F0 ), base_color, metallic ); + const float alpha = roughness * roughness; + + float3 result = make_float3( 0.0f ); + + for( int i = 0; i < whitted::params.lights.count; ++i ) + { + Light light = whitted::params.lights[i]; + + if( light.type == Light::Type::POINT ) + { + const float L_dist = length( light.point.position - hitPoint ); + const float3 L = ( light.point.position - hitPoint ) / L_dist; + const float3 V = -normalize( optixGetWorldRayDirection() ); + const float3 H = normalize( L + V ); + const float N_dot_L = dot( normal, L ); + const float N_dot_V = dot( normal, V ); + const float N_dot_H = dot( normal, H ); + const float V_dot_H = dot( V, H ); + + if( N_dot_L > 0.0f && N_dot_V > 0.0f ) + { + const float tmin = 0.001f; // TODO + const float tmax = L_dist - 0.001f; // TODO + const float attenuation = whitted::traceOcclusion( whitted::params.handle, hitPoint, L, tmin, tmax ); + if( attenuation > 0.f ) + { + const float3 F = whitted::schlick( spec_color, V_dot_H ); + const float G_vis = whitted::vis( N_dot_L, N_dot_V, alpha ); + const float D = whitted::ggxNormal( N_dot_H, alpha ); + + const float3 diff = ( 1.0f - F ) * diff_color / M_PIf; + const float3 spec = F * G_vis * D; + + result += light.point.color * attenuation * light.point.intensity * N_dot_L * ( diff + spec ); + } + } + } + } + + return result; +} + +// Get u-parameter for full strand. +// +// Parameters: +// geo - the GeometricData from the SBT. +// primitiveIndex - the primitive index +// +static __forceinline__ __device__ float getStrandU( const GeometryData& geo, const int primitiveIndex ) +{ + float segmentU = optixGetCurveParameter(); + float2 strandInfo = geo.getCurveArray().strand_u[primitiveIndex]; + // strandInfo.x ~ strand u at segment start + // strandInfo.y ~ scale factor (i.e. 1/numberOfSegments) + return strandInfo.x + segmentU * strandInfo.y; +} + +// Compute normal +// +static __forceinline__ __device__ float3 computeNormal( OptixPrimitiveType type, const int primitiveIndex ) +{ + switch( type ) { + case OPTIX_PRIMITIVE_TYPE_ROUND_LINEAR: + return normalLinear( primitiveIndex ); + case OPTIX_PRIMITIVE_TYPE_ROUND_QUADRATIC_BSPLINE: + return normalQuadratic( primitiveIndex ); + case OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE: + return normalCubic( primitiveIndex ); + case OPTIX_PRIMITIVE_TYPE_ROUND_CATMULLROM: + return normalCatrom( primitiveIndex ); + } + return make_float3(0.0f); +} + +extern "C" __global__ void __closesthit__curve_strand_u() +{ + const unsigned int primitiveIndex = optixGetPrimitiveIndex(); + + const whitted::HitGroupData* hitGroupData = reinterpret_cast( optixGetSbtDataPointer() ); + const GeometryData& geometryData = reinterpret_cast( hitGroupData->geometry_data ); + + const float3 normal = computeNormal( optixGetPrimitiveType(), primitiveIndex ); + const float3 colors[2] = {make_float3( 1, 0, 0 ), make_float3( 0, 1, 0 )}; + const float u = getStrandU( geometryData, primitiveIndex ); + const float3 base_color = colors[0] * u + colors[1] * ( 1 - u ); + + const float3 hitPoint = getHitPoint(); + const float3 result = shade( hitGroupData, hitPoint, normal, base_color ); + + whitted::setPayloadResult( result ); +} + +extern "C" __global__ void __closesthit__curve_segment_u() +{ + const unsigned int primitiveIndex = optixGetPrimitiveIndex(); + + const whitted::HitGroupData* hitGroupData = reinterpret_cast( optixGetSbtDataPointer() ); + + const float3 normal = computeNormal( optixGetPrimitiveType(), primitiveIndex ); + const float3 colors[3] = {make_float3( 1, 0, 0 ), make_float3( 0, 1, 0 ), + make_float3( 0, 0, 1 ) }; + const float u = optixGetCurveParameter(); + float3 base_color; + if( u == 0.0f || u == 1.0f ) // on end-cap + base_color = colors[2]; + else + base_color = colors[0] * u + colors[1] * ( 1 - u ); + + const float3 hitPoint = getHitPoint(); + const float3 result = shade( hitGroupData, hitPoint, normal, base_color ); + + whitted::setPayloadResult( result ); +} + +extern "C" __global__ void __closesthit__curve_strand_idx() +{ + unsigned int primitiveIndex = optixGetPrimitiveIndex(); + + const whitted::HitGroupData* hitGroupData = reinterpret_cast( optixGetSbtDataPointer() ); + const GeometryData& geometryData = reinterpret_cast( hitGroupData->geometry_data ); + + float3 normal = computeNormal( optixGetPrimitiveType(), primitiveIndex ); + float3 colors[6] = {make_float3( 1, 0, 0 ), make_float3( 0, 1, 0 ), make_float3( 0, 0, 1 ), + make_float3( 1, 1, 0 ), make_float3( 1, 0, 1 ), make_float3( 0, 1, 1 )}; + unsigned int strandIndex = geometryData.getCurveArray().strand_i[primitiveIndex]; + uint2 strandInfo = geometryData.getCurveArray().strand_info[strandIndex]; + float u = ( primitiveIndex - strandInfo.x ) / (float)strandInfo.y; + float3 base_color = colors[0] * u + colors[strandIndex % 5 + 1] * ( 1.0f - u ); + + float3 hitPoint = getHitPoint(); + float3 result = shade( hitGroupData, hitPoint, normal, base_color ); + + whitted::setPayloadResult( result ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHair/optixHair.h b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/optixHair.h new file mode 100644 index 00000000..1cc2918b --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHair/optixHair.h @@ -0,0 +1,103 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#include "whitted.h" +#include +#include +#include +#include +#include +#include + +typedef sutil::EmptyRecord RayGenRecord; +typedef sutil::EmptyRecord MissRecord; +typedef sutil::Record HitRecord; + +// +// forward declarations +// + +class Hair; +class Head; +class Camera; +class ShaderBindingTable; +class HairProgramGroups; + +struct HairState +{ + unsigned int buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION | OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS | OPTIX_BUILD_FLAG_PREFER_FAST_TRACE; + + OptixDeviceContext context = 0; + + Hair* pHair; + const Head* pHead; + sutil::Camera camera = {}; + + unsigned int width = 0; + unsigned int height = 0; + + sutil::CUDAOutputBuffer outputBuffer = sutil::CUDAOutputBuffer(sutil::CUDAOutputBufferType::CUDA_DEVICE, 1, 1); + sutil::CUDAOutputBuffer accumBuffer = sutil::CUDAOutputBuffer(sutil::CUDAOutputBufferType::CUDA_DEVICE, 1, 1); + + sutil::Aabb aabb; + + whitted::LaunchParams params = {}; + whitted::LaunchParams* deviceParams = nullptr; + + Light lights[2] = {}; + + OptixTraversableHandle hHairGAS = 0; + CUdeviceptr deviceBufferHairGAS = 0; + + OptixTraversableHandle hIAS = 0; + CUdeviceptr deviceBufferIAS = 0; + + // for curves SBT record + GeometryData::Curves curves = {}; + + //ShaderBindingTable* pSBT = nullptr; + HairProgramGroups* pProgramGroups = nullptr; + OptixPipeline pipeline = 0; + OptixShaderBindingTable SBT = {}; + +}; + +void makeHairGAS( HairState* pState ); +void makeInstanceAccelerationStructure( HairState* pState ); +void makePipeline( HairState* pState ); +void makeProgramGroups( HairState* pState ); +void makeSBT( HairState* pState ); +void renderFrame( HairState* pState ); + +void initializeParams( HairState* pState ); +void updateParams( HairState* pState ); +void updateSize( HairState* pState, int width, int height ); diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHello/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixHello/CMakeLists.txt new file mode 100644 index 00000000..b86efce7 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHello/CMakeLists.txt @@ -0,0 +1,41 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixHello target_name + ${SAMPLES_CUDA_DIR}/helpers.h + draw_solid_color.cu + optixHello.cpp + optixHello.h + + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHello/draw_solid_color.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixHello/draw_solid_color.cu new file mode 100644 index 00000000..13ec000a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHello/draw_solid_color.cu @@ -0,0 +1,48 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "optixHello.h" +#include + +extern "C" { +__constant__ Params params; +} + +extern "C" +__global__ void __raygen__draw_solid_color() +{ + uint3 launch_index = optixGetLaunchIndex(); + RayGenData* rtData = (RayGenData*)optixGetSbtDataPointer(); + params.image[launch_index.y * params.image_width + launch_index.x] = + make_color( make_float3( rtData->r, rtData->g, rtData->b ) ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHello/optixHello.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixHello/optixHello.cpp new file mode 100644 index 00000000..8554d43b --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHello/optixHello.cpp @@ -0,0 +1,338 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "optixHello.h" + +#include +#include +#include + + +template +struct SbtRecord +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef SbtRecord RayGenSbtRecord; +typedef SbtRecord MissSbtRecord; + + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f Specify file for image output\n"; + std::cerr << " --help | -h Print this usage message\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 512x384\n"; + exit( 1 ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + +int main( int argc, char* argv[] ) +{ + std::string outfile; + int width = 512; + int height = 384; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg( argv[i] ); + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--file" || arg == "-f" ) + { + if( i < argc - 1 ) + { + outfile = argv[++i]; + } + else + { + printUsageAndExit( argv[0] ); + } + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + sutil::parseDimensions( dims_arg.c_str(), width, height ); + } + else + { + std::cerr << "Unknown option '" << arg << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + // + // Initialize CUDA and create OptiX context + // + OptixDeviceContext context = nullptr; + { + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + } + + // + // Create module + // + OptixModule module = nullptr; + OptixPipelineCompileOptions pipeline_compile_options = {}; + { + OptixModuleCompileOptions module_compile_options = {}; +#if !defined(NDEBUG) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + pipeline_compile_options.usesMotionBlur = false; + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING; + pipeline_compile_options.numPayloadValues = 2; + pipeline_compile_options.numAttributeValues = 2; + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; // TODO: should be OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW; + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "draw_solid_color.cu", inputSize ); + + OPTIX_CHECK_LOG( optixModuleCreate( + context, + &module_compile_options, + &pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &module + ) ); + } + + // + // Create program groups, including NULL miss and hitgroups + // + OptixProgramGroup raygen_prog_group = nullptr; + OptixProgramGroup miss_prog_group = nullptr; + { + OptixProgramGroupOptions program_group_options = {}; // Initialize to zeros + + OptixProgramGroupDesc raygen_prog_group_desc = {}; // + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__draw_solid_color"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &raygen_prog_group + ) ); + + // Leave miss group's module and entryfunc name null + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &miss_prog_group + ) ); + } + + // + // Link pipeline + // + OptixPipeline pipeline = nullptr; + { + const uint32_t max_trace_depth = 0; + OptixProgramGroup program_groups[] = { raygen_prog_group }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + OPTIX_CHECK_LOG( optixPipelineCreate( + context, + &pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &pipeline + ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 2 // maxTraversableDepth + ) ); + } + + // + // Set up shader binding table + // + OptixShaderBindingTable sbt = {}; + { + CUdeviceptr raygen_record; + const size_t raygen_record_size = sizeof( RayGenSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &raygen_record ), raygen_record_size ) ); + RayGenSbtRecord rg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( raygen_prog_group, &rg_sbt ) ); + rg_sbt.data = {0.462f, 0.725f, 0.f}; + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( raygen_record ), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr miss_record; + size_t miss_record_size = sizeof( MissSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &miss_record ), miss_record_size ) ); + MissSbtRecord ms_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( miss_prog_group, &ms_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( miss_record ), + &ms_sbt, + miss_record_size, + cudaMemcpyHostToDevice + ) ); + + sbt.raygenRecord = raygen_record; + sbt.missRecordBase = miss_record; + sbt.missRecordStrideInBytes = sizeof( MissSbtRecord ); + sbt.missRecordCount = 1; + } + + sutil::CUDAOutputBuffer output_buffer( sutil::CUDAOutputBufferType::CUDA_DEVICE, width, height ); + + // + // launch + // + { + CUstream stream; + CUDA_CHECK( cudaStreamCreate( &stream ) ); + + Params params; + params.image = output_buffer.map(); + params.image_width = width; + + CUdeviceptr d_param; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_param ), sizeof( Params ) ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_param ), + ¶ms, sizeof( params ), + cudaMemcpyHostToDevice + ) ); + + OPTIX_CHECK( optixLaunch( pipeline, stream, d_param, sizeof( Params ), &sbt, width, height, /*depth=*/1 ) ); + CUDA_SYNC_CHECK(); + + output_buffer.unmap(); + CUDA_CHECK( cudaFree( reinterpret_cast( d_param ) ) ); + } + + // + // Display results + // + { + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = width; + buffer.height = height; + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + if( outfile.empty() ) + sutil::displayBufferWindow( argv[0], buffer ); + else + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + // + // Cleanup + // + { + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.missRecordBase ) ) ); + + OPTIX_CHECK( optixPipelineDestroy( pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( miss_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( raygen_prog_group ) ); + OPTIX_CHECK( optixModuleDestroy( module ) ); + + OPTIX_CHECK( optixDeviceContextDestroy( context ) ); + } + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixHello/optixHello.h b/Extern/3rdParty/OptiX/Linux/SDK/optixHello/optixHello.h new file mode 100644 index 00000000..e07e8099 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixHello/optixHello.h @@ -0,0 +1,41 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +struct Params +{ + uchar4* image; + unsigned int image_width; +}; + +struct RayGenData +{ + float r,g,b; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMeshViewer/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixMeshViewer/CMakeLists.txt new file mode 100644 index 00000000..21ef01cc --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMeshViewer/CMakeLists.txt @@ -0,0 +1,38 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixMeshViewer target_name + optixMeshViewer.cpp + + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMeshViewer/optixMeshViewer.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixMeshViewer/optixMeshViewer.cpp new file mode 100644 index 00000000..c258efba --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMeshViewer/optixMeshViewer.cpp @@ -0,0 +1,522 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include // Needs to be included before gl_interop + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + + +//#define USE_IAS // WAR for broken direct intersection of GAS on non-RTX cards + +bool resize_dirty = false; +bool minimized = false; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Mouse state +int32_t mouse_button = -1; + +int32_t samples_per_launch = 16; + +whitted::LaunchParams* d_params = nullptr; +whitted::LaunchParams g_params = {}; +int32_t width = 768; +int32_t height = 768; + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking(static_cast( xpos ), static_cast( ypos )); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), width, height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), width, height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + width = res_x; + height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || + key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + } + else if( key == GLFW_KEY_G ) + { + // toggle UI draw + } +} + + +static void scrollCallback( GLFWwindow* window, double xscroll, double yscroll ) +{ + if(trackball.wheelEvent((int)yscroll)) + camera_changed = true; +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 768x768\n"; + std::cerr << " --launch-samples | -s Number of samples per pixel per launch (default 16)\n"; + std::cerr << " --no-gl-interop Disable GL interop for display\n"; + std::cerr << " --model Specify model to render (required)\n"; + std::cerr << " --help | -h Print this usage message\n"; + exit( 0 ); +} + + +void initLaunchParams( const sutil::Scene& scene ) { + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &g_params.accum_buffer ), + width*height*sizeof(float4) + ) ); + g_params.frame_buffer = nullptr; // Will be set when output buffer is mapped + + g_params.subframe_index = 0u; + + const float loffset = scene.aabb().maxExtent(); + + // TODO: add light support to sutil::Scene + std::vector lights( 2 ); + lights[0].type = Light::Type::POINT; + lights[0].point.color = {1.0f, 1.0f, 0.8f}; + lights[0].point.intensity = 5.0f; + lights[0].point.position = scene.aabb().center() + make_float3( loffset ); + lights[0].point.falloff = Light::Falloff::QUADRATIC; + lights[1].type = Light::Type::POINT; + lights[1].point.color = {0.8f, 0.8f, 1.0f}; + lights[1].point.intensity = 3.0f; + lights[1].point.position = scene.aabb().center() + make_float3( -loffset, 0.5f * loffset, -0.5f * loffset ); + lights[1].point.falloff = Light::Falloff::QUADRATIC; + + g_params.lights.count = static_cast( lights.size() ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &g_params.lights.data ), + lights.size() * sizeof( Light ) + ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( g_params.lights.data ), + lights.data(), + lights.size() * sizeof( Light ), + cudaMemcpyHostToDevice + ) ); + + g_params.miss_color = make_float3( 0.1f ); + + //CUDA_CHECK( cudaStreamCreate( &stream ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_params ), sizeof( whitted::LaunchParams ) ) ); + + g_params.handle = scene.traversableHandle(); +} + + +void handleCameraUpdate( whitted::LaunchParams& params ) +{ + if( !camera_changed ) + return; + camera_changed = false; + + camera.setAspectRatio( static_cast( width ) / static_cast( height ) ); + params.eye = camera.eye(); + camera.UVWFrame( params.U, params.V, params.W ); + /* + std::cerr + << "Updating camera:\n" + << "\tU: " << params.U.x << ", " << params.U.y << ", " << params.U.z << std::endl + << "\tV: " << params.V.x << ", " << params.V.y << ", " << params.V.z << std::endl + << "\tW: " << params.W.x << ", " << params.W.y << ", " << params.W.z << std::endl; + */ + +} + + +void handleResize( sutil::CUDAOutputBuffer& output_buffer ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + output_buffer.resize( width, height ); + + // Realloc accumulation buffer + CUDA_CHECK( cudaFree( reinterpret_cast( g_params.accum_buffer ) ) ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &g_params.accum_buffer ), + width*height*sizeof(float4) + ) ); +} + + +void updateState( sutil::CUDAOutputBuffer& output_buffer, whitted::LaunchParams& params ) +{ + // Update params on device + if( camera_changed || resize_dirty ) + params.subframe_index = 0; + + handleCameraUpdate( params ); + handleResize( output_buffer ); +} + + +void launchSubframe( sutil::CUDAOutputBuffer& output_buffer, const sutil::Scene& scene ) +{ + + // Launch + uchar4* result_buffer_data = output_buffer.map(); + g_params.frame_buffer = result_buffer_data; + CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast( d_params ), + &g_params, + sizeof( whitted::LaunchParams ), + cudaMemcpyHostToDevice, + 0 // stream + ) ); + + OPTIX_CHECK( optixLaunch( + scene.pipeline(), + 0, // stream + reinterpret_cast( d_params ), + sizeof( whitted::LaunchParams ), + scene.sbt(), + width, // launch width + height, // launch height + 1 // launch depth + ) ); + output_buffer.unmap(); + CUDA_SYNC_CHECK(); +} + + +void displaySubframe( + sutil::CUDAOutputBuffer& output_buffer, + sutil::GLDisplay& gl_display, + GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( + output_buffer.width(), + output_buffer.height(), + framebuf_res_x, + framebuf_res_y, + output_buffer.getPBO() + ); +} + + +void initCameraState( const sutil::Scene& scene ) +{ + camera = scene.camera(); + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( make_float3( 1.0f, 0.0f, 0.0f ), make_float3( 0.0f, 0.0f, 1.0f ), make_float3( 0.0f, 1.0f, 0.0f ) ); + trackball.setGimbalLock(true); +} + + +void cleanup() +{ + CUDA_CHECK( cudaFree( reinterpret_cast( g_params.accum_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( g_params.lights.data ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_params ) ) ); +} + + +//------------------------------------------------------------------------------ +// +// Main +// +//------------------------------------------------------------------------------ + +int main( int argc, char* argv[] ) +{ + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::GL_INTEROP; + + // + // Parse command line options + // + std::string outfile; + std::string infile = sutil::sampleDataFilePath( "WaterBottle/WaterBottle.gltf" ); + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--no-gl-interop" ) + { + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + } + else if( arg == "--model" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + infile = argv[++i]; + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outfile = argv[++i]; + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + sutil::parseDimensions( dims_arg.c_str(), width, height ); + } + else if( arg == "--launch-samples" || arg == "-s" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + samples_per_launch = atoi( argv[++i] ); + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + if( infile.empty() ) + { + std::cerr << "--model argument required" << std::endl; + printUsageAndExit( argv[0] ); + } + + + try + { + sutil::Scene scene; + sutil::loadScene( infile, scene ); + scene.finalize(); + + OPTIX_CHECK( optixInit() ); // Need to initialize function table + initCameraState( scene ); + initLaunchParams( scene ); + + + if( outfile.empty() ) + { + GLFWwindow* window = sutil::initUI( "optixMeshViewer", width, height ); + glfwSetMouseButtonCallback ( window, mouseButtonCallback ); + glfwSetCursorPosCallback ( window, cursorPosCallback ); + glfwSetWindowSizeCallback ( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback ( window, keyCallback ); + glfwSetScrollCallback ( window, scrollCallback ); + glfwSetWindowUserPointer ( window, &g_params ); + + // + // Render loop + // + { + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, width, height ); + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + updateState( output_buffer, g_params ); + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + launchSubframe( output_buffer, scene ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1 - t0; + + sutil::displayStats( state_update_time, render_time, display_time ); + + glfwSwapBuffers(window); + + ++g_params.subframe_index; + } + while( !glfwWindowShouldClose( window ) ); + CUDA_SYNC_CHECK(); + } + + sutil::cleanupUI( window ); + } + else + { + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + sutil::initGLFW(); // For GL context + sutil::initGL(); + } + + { + // this scope is for output_buffer, to ensure the destructor is called bfore glfwTerminate() + + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, width, height ); + handleCameraUpdate( g_params ); + handleResize( output_buffer ); + launchSubframe( output_buffer, scene ); + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + glfwTerminate(); + } + } + + cleanup(); + + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/CMakeLists.txt new file mode 100644 index 00000000..c1c737f1 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixMixSDKs target_name + optixMixSDKs.cpp + optixSDK750.cpp + optixSDKCurrent.cpp + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/internal/optix_7_device_impl.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/internal/optix_7_device_impl.h new file mode 100644 index 00000000..4da9e9e1 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/internal/optix_7_device_impl.h @@ -0,0 +1,1525 @@ +/* +* SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* SPDX-License-Identifier: LicenseRef-NvidiaProprietary +* +* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +* property and proprietary rights in and to this material, related +* documentation and any modifications thereto. Any use, reproduction, +* disclosure or distribution of this material and related documentation +* without an express license agreement from NVIDIA CORPORATION or +* its affiliates is strictly prohibited. +*/ +/** +* @file optix_7_device_impl.h +* @author NVIDIA Corporation +* @brief OptiX public API +* +* OptiX public API Reference - Device side implementation +*/ + +#if !defined( __OPTIX_INCLUDE_INTERNAL_HEADERS__ ) +#error("optix_7_device_impl.h is an internal header file and must not be used directly. Please use optix_device.h or optix.h instead.") +#endif + +#ifndef __optix_optix_7_device_impl_h__ +#define __optix_optix_7_device_impl_h__ + +#include "internal/optix_7_device_impl_exception.h" +#include "internal/optix_7_device_impl_transformations.h" + +#ifndef __CUDACC_RTC__ +#include +#include +#endif + +namespace optix_internal { +template +struct TypePack{}; +} // namespace optix_internal + +template +static __forceinline__ __device__ void optixTrace( OptixTraversableHandle handle, + float3 rayOrigin, + float3 rayDirection, + float tmin, + float tmax, + float rayTime, + OptixVisibilityMask visibilityMask, + unsigned int rayFlags, + unsigned int SBToffset, + unsigned int SBTstride, + unsigned int missSBTIndex, + Payload&... payload ) +{ + static_assert( sizeof...( Payload ) <= 32, "Only up to 32 payload values are allowed." ); + // std::is_same compares each type in the two TypePacks to make sure that all types are unsigned int. + // TypePack 1 unsigned int T0 T1 T2 ... Tn-1 Tn + // TypePack 2 T0 T1 T2 T3 ... Tn unsigned int +#ifndef __CUDACC_RTC__ + static_assert( std::is_same, optix_internal::TypePack>::value, + "All payload parameters need to be unsigned int." ); +#endif + + float ox = rayOrigin.x, oy = rayOrigin.y, oz = rayOrigin.z; + float dx = rayDirection.x, dy = rayDirection.y, dz = rayDirection.z; + unsigned int p[33] = { 0, payload... }; + int payloadSize = (int)sizeof...( Payload ); + asm volatile( + "call" + "(%0,%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15,%16,%17,%18,%19,%20,%21,%22,%23,%24,%25,%26,%27,%28,%" + "29,%30,%31)," + "_optix_trace_typed_32," + "(%32,%33,%34,%35,%36,%37,%38,%39,%40,%41,%42,%43,%44,%45,%46,%47,%48,%49,%50,%51,%52,%53,%54,%55,%56,%57,%58,%" + "59,%60,%61,%62,%63,%64,%65,%66,%67,%68,%69,%70,%71,%72,%73,%74,%75,%76,%77,%78,%79,%80);" + : "=r"( p[1] ), "=r"( p[2] ), "=r"( p[3] ), "=r"( p[4] ), "=r"( p[5] ), "=r"( p[6] ), "=r"( p[7] ), + "=r"( p[8] ), "=r"( p[9] ), "=r"( p[10] ), "=r"( p[11] ), "=r"( p[12] ), "=r"( p[13] ), "=r"( p[14] ), + "=r"( p[15] ), "=r"( p[16] ), "=r"( p[17] ), "=r"( p[18] ), "=r"( p[19] ), "=r"( p[20] ), "=r"( p[21] ), + "=r"( p[22] ), "=r"( p[23] ), "=r"( p[24] ), "=r"( p[25] ), "=r"( p[26] ), "=r"( p[27] ), "=r"( p[28] ), + "=r"( p[29] ), "=r"( p[30] ), "=r"( p[31] ), "=r"( p[32] ) + : "r"( 0 ), "l"( handle ), "f"( ox ), "f"( oy ), "f"( oz ), "f"( dx ), "f"( dy ), "f"( dz ), "f"( tmin ), + "f"( tmax ), "f"( rayTime ), "r"( visibilityMask ), "r"( rayFlags ), "r"( SBToffset ), "r"( SBTstride ), + "r"( missSBTIndex ), "r"( payloadSize ), "r"( p[1] ), "r"( p[2] ), "r"( p[3] ), "r"( p[4] ), "r"( p[5] ), + "r"( p[6] ), "r"( p[7] ), "r"( p[8] ), "r"( p[9] ), "r"( p[10] ), "r"( p[11] ), "r"( p[12] ), "r"( p[13] ), + "r"( p[14] ), "r"( p[15] ), "r"( p[16] ), "r"( p[17] ), "r"( p[18] ), "r"( p[19] ), "r"( p[20] ), + "r"( p[21] ), "r"( p[22] ), "r"( p[23] ), "r"( p[24] ), "r"( p[25] ), "r"( p[26] ), "r"( p[27] ), + "r"( p[28] ), "r"( p[29] ), "r"( p[30] ), "r"( p[31] ), "r"( p[32] ) + : ); + unsigned int index = 1; + (void)std::initializer_list{ index, ( payload = p[index++] )... }; +} + +template +static __forceinline__ __device__ void optixTrace( OptixPayloadTypeID type, + OptixTraversableHandle handle, + float3 rayOrigin, + float3 rayDirection, + float tmin, + float tmax, + float rayTime, + OptixVisibilityMask visibilityMask, + unsigned int rayFlags, + unsigned int SBToffset, + unsigned int SBTstride, + unsigned int missSBTIndex, + Payload&... payload ) +{ + // std::is_same compares each type in the two TypePacks to make sure that all types are unsigned int. + // TypePack 1 unsigned int T0 T1 T2 ... Tn-1 Tn + // TypePack 2 T0 T1 T2 T3 ... Tn unsigned int + static_assert( sizeof...( Payload ) <= 32, "Only up to 32 payload values are allowed." ); + static_assert( std::is_same, optix_internal::TypePack>::value, + "All payload parameters need to be unsigned int." ); + + float ox = rayOrigin.x, oy = rayOrigin.y, oz = rayOrigin.z; + float dx = rayDirection.x, dy = rayDirection.y, dz = rayDirection.z; + unsigned int p[33] = { 0, payload... }; + int payloadSize = (int)sizeof...( Payload ); + + asm volatile( + "call" + "(%0,%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15,%16,%17,%18,%19,%20,%21,%22,%23,%24,%25,%26,%27,%28,%" + "29,%30,%31)," + "_optix_trace_typed_32," + "(%32,%33,%34,%35,%36,%37,%38,%39,%40,%41,%42,%43,%44,%45,%46,%47,%48,%49,%50,%51,%52,%53,%54,%55,%56,%57,%58,%" + "59,%60,%61,%62,%63,%64,%65,%66,%67,%68,%69,%70,%71,%72,%73,%74,%75,%76,%77,%78,%79,%80);" + : "=r"( p[1] ), "=r"( p[2] ), "=r"( p[3] ), "=r"( p[4] ), "=r"( p[5] ), "=r"( p[6] ), "=r"( p[7] ), + "=r"( p[8] ), "=r"( p[9] ), "=r"( p[10] ), "=r"( p[11] ), "=r"( p[12] ), "=r"( p[13] ), "=r"( p[14] ), + "=r"( p[15] ), "=r"( p[16] ), "=r"( p[17] ), "=r"( p[18] ), "=r"( p[19] ), "=r"( p[20] ), "=r"( p[21] ), + "=r"( p[22] ), "=r"( p[23] ), "=r"( p[24] ), "=r"( p[25] ), "=r"( p[26] ), "=r"( p[27] ), "=r"( p[28] ), + "=r"( p[29] ), "=r"( p[30] ), "=r"( p[31] ), "=r"( p[32] ) + : "r"( type ), "l"( handle ), "f"( ox ), "f"( oy ), "f"( oz ), "f"( dx ), "f"( dy ), "f"( dz ), "f"( tmin ), + "f"( tmax ), "f"( rayTime ), "r"( visibilityMask ), "r"( rayFlags ), "r"( SBToffset ), "r"( SBTstride ), + "r"( missSBTIndex ), "r"( payloadSize ), "r"( p[1] ), "r"( p[2] ), "r"( p[3] ), "r"( p[4] ), "r"( p[5] ), + "r"( p[6] ), "r"( p[7] ), "r"( p[8] ), "r"( p[9] ), "r"( p[10] ), "r"( p[11] ), "r"( p[12] ), "r"( p[13] ), + "r"( p[14] ), "r"( p[15] ), "r"( p[16] ), "r"( p[17] ), "r"( p[18] ), "r"( p[19] ), "r"( p[20] ), + "r"( p[21] ), "r"( p[22] ), "r"( p[23] ), "r"( p[24] ), "r"( p[25] ), "r"( p[26] ), "r"( p[27] ), + "r"( p[28] ), "r"( p[29] ), "r"( p[30] ), "r"( p[31] ), "r"( p[32] ) + : ); + unsigned int index = 1; + (void)std::initializer_list{ index, ( payload = p[index++] )... }; +} + +static __forceinline__ __device__ void optixSetPayload_0( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 0 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_1( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 1 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_2( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 2 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_3( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 3 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_4( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 4 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_5( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 5 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_6( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 6 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_7( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 7 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_8( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 8 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_9( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 9 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_10( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 10 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_11( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 11 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_12( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 12 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_13( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 13 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_14( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 14 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_15( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 15 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_16( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 16 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_17( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 17 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_18( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 18 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_19( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 19 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_20( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 20 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_21( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 21 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_22( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 22 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_23( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 23 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_24( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 24 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_25( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 25 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_26( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 26 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_27( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 27 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_28( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 28 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_29( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 29 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_30( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 30 ), "r"( p ) : ); +} + +static __forceinline__ __device__ void optixSetPayload_31( unsigned int p ) +{ + asm volatile( "call _optix_set_payload, (%0, %1);" : : "r"( 31 ), "r"( p ) : ); +} + +static __forceinline__ __device__ unsigned int optixGetPayload_0() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 0 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_1() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 1 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_2() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 2 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_3() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 3 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_4() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 4 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_5() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 5 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_6() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 6 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_7() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 7 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_8() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 8 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_9() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 9 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_10() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 10 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_11() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 11 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_12() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 12 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_13() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 13 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_14() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 14 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_15() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 15 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_16() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 16 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_17() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 17 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_18() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 18 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_19() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 19 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_20() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 20 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_21() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 21 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_22() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 22 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_23() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 23 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_24() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 24 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_25() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 25 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_26() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 26 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_27() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 27 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_28() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 28 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_29() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 29 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_30() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 30 ) : ); + return result; +} + +static __forceinline__ __device__ unsigned int optixGetPayload_31() +{ + unsigned int result; + asm volatile( "call (%0), _optix_get_payload, (%1);" : "=r"( result ) : "r"( 31 ) : ); + return result; +} + +static __forceinline__ __device__ void optixSetPayloadTypes( unsigned int types ) +{ + asm volatile( "call _optix_set_payload_types, (%0);" : : "r"( types ) : ); +} + +static __forceinline__ __device__ unsigned int optixUndefinedValue() +{ + unsigned int u0; + asm( "call (%0), _optix_undef_value, ();" : "=r"( u0 ) : ); + return u0; +} + +static __forceinline__ __device__ float3 optixGetWorldRayOrigin() +{ + float f0, f1, f2; + asm( "call (%0), _optix_get_world_ray_origin_x, ();" : "=f"( f0 ) : ); + asm( "call (%0), _optix_get_world_ray_origin_y, ();" : "=f"( f1 ) : ); + asm( "call (%0), _optix_get_world_ray_origin_z, ();" : "=f"( f2 ) : ); + return make_float3( f0, f1, f2 ); +} + +static __forceinline__ __device__ float3 optixGetWorldRayDirection() +{ + float f0, f1, f2; + asm( "call (%0), _optix_get_world_ray_direction_x, ();" : "=f"( f0 ) : ); + asm( "call (%0), _optix_get_world_ray_direction_y, ();" : "=f"( f1 ) : ); + asm( "call (%0), _optix_get_world_ray_direction_z, ();" : "=f"( f2 ) : ); + return make_float3( f0, f1, f2 ); +} + +static __forceinline__ __device__ float3 optixGetObjectRayOrigin() +{ + float f0, f1, f2; + asm( "call (%0), _optix_get_object_ray_origin_x, ();" : "=f"( f0 ) : ); + asm( "call (%0), _optix_get_object_ray_origin_y, ();" : "=f"( f1 ) : ); + asm( "call (%0), _optix_get_object_ray_origin_z, ();" : "=f"( f2 ) : ); + return make_float3( f0, f1, f2 ); +} + +static __forceinline__ __device__ float3 optixGetObjectRayDirection() +{ + float f0, f1, f2; + asm( "call (%0), _optix_get_object_ray_direction_x, ();" : "=f"( f0 ) : ); + asm( "call (%0), _optix_get_object_ray_direction_y, ();" : "=f"( f1 ) : ); + asm( "call (%0), _optix_get_object_ray_direction_z, ();" : "=f"( f2 ) : ); + return make_float3( f0, f1, f2 ); +} + +static __forceinline__ __device__ float optixGetRayTmin() +{ + float f0; + asm( "call (%0), _optix_get_ray_tmin, ();" : "=f"( f0 ) : ); + return f0; +} + +static __forceinline__ __device__ float optixGetRayTmax() +{ + float f0; + asm( "call (%0), _optix_get_ray_tmax, ();" : "=f"( f0 ) : ); + return f0; +} + +static __forceinline__ __device__ float optixGetRayTime() +{ + float f0; + asm( "call (%0), _optix_get_ray_time, ();" : "=f"( f0 ) : ); + return f0; +} + +static __forceinline__ __device__ unsigned int optixGetRayFlags() +{ + unsigned int u0; + asm( "call (%0), _optix_get_ray_flags, ();" : "=r"( u0 ) : ); + return u0; +} + +static __forceinline__ __device__ unsigned int optixGetRayVisibilityMask() +{ + unsigned int u0; + asm( "call (%0), _optix_get_ray_visibility_mask, ();" : "=r"( u0 ) : ); + return u0; +} + +static __forceinline__ __device__ OptixTraversableHandle optixGetInstanceTraversableFromIAS( OptixTraversableHandle ias, + unsigned int instIdx ) +{ + unsigned long long handle; + asm( "call (%0), _optix_get_instance_traversable_from_ias, (%1, %2);" + : "=l"( handle ) : "l"( ias ), "r"( instIdx ) ); + return (OptixTraversableHandle)handle; +} + + +static __forceinline__ __device__ void optixGetTriangleVertexData( OptixTraversableHandle gas, + unsigned int primIdx, + unsigned int sbtGASIndex, + float time, + float3 data[3] ) +{ + asm( "call (%0, %1, %2, %3, %4, %5, %6, %7, %8), _optix_get_triangle_vertex_data, " + "(%9, %10, %11, %12);" + : "=f"( data[0].x ), "=f"( data[0].y ), "=f"( data[0].z ), "=f"( data[1].x ), "=f"( data[1].y ), + "=f"( data[1].z ), "=f"( data[2].x ), "=f"( data[2].y ), "=f"( data[2].z ) + : "l"( gas ), "r"( primIdx ), "r"( sbtGASIndex ), "f"( time ) + : ); +} + +static __forceinline__ __device__ void optixGetLinearCurveVertexData( OptixTraversableHandle gas, + unsigned int primIdx, + unsigned int sbtGASIndex, + float time, + float4 data[2] ) +{ + asm( "call (%0, %1, %2, %3, %4, %5, %6, %7), _optix_get_linear_curve_vertex_data, " + "(%8, %9, %10, %11);" + : "=f"( data[0].x ), "=f"( data[0].y ), "=f"( data[0].z ), "=f"( data[0].w ), + "=f"( data[1].x ), "=f"( data[1].y ), "=f"( data[1].z ), "=f"( data[1].w ) + : "l"( gas ), "r"( primIdx ), "r"( sbtGASIndex ), "f"( time ) + : ); +} + +static __forceinline__ __device__ void optixGetQuadraticBSplineVertexData( OptixTraversableHandle gas, + unsigned int primIdx, + unsigned int sbtGASIndex, + float time, + float4 data[3] ) +{ + asm( "call (%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11), _optix_get_quadratic_bspline_vertex_data, " + "(%12, %13, %14, %15);" + : "=f"( data[0].x ), "=f"( data[0].y ), "=f"( data[0].z ), "=f"( data[0].w ), + "=f"( data[1].x ), "=f"( data[1].y ), "=f"( data[1].z ), "=f"( data[1].w ), + "=f"( data[2].x ), "=f"( data[2].y ), "=f"( data[2].z ), "=f"( data[2].w ) + : "l"( gas ), "r"( primIdx ), "r"( sbtGASIndex ), "f"( time ) + : ); +} + +static __forceinline__ __device__ void optixGetCubicBSplineVertexData( OptixTraversableHandle gas, + unsigned int primIdx, + unsigned int sbtGASIndex, + float time, + float4 data[4] ) +{ + asm( "call (%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15), " + "_optix_get_cubic_bspline_vertex_data, " + "(%16, %17, %18, %19);" + : "=f"( data[0].x ), "=f"( data[0].y ), "=f"( data[0].z ), "=f"( data[0].w ), + "=f"( data[1].x ), "=f"( data[1].y ), "=f"( data[1].z ), "=f"( data[1].w ), + "=f"( data[2].x ), "=f"( data[2].y ), "=f"( data[2].z ), "=f"( data[2].w ), + "=f"( data[3].x ), "=f"( data[3].y ), "=f"( data[3].z ), "=f"( data[3].w ) + : "l"( gas ), "r"( primIdx ), "r"( sbtGASIndex ), "f"( time ) + : ); +} + +static __forceinline__ __device__ void optixGetCatmullRomVertexData( OptixTraversableHandle gas, + unsigned int primIdx, + unsigned int sbtGASIndex, + float time, + float4 data[4] ) +{ + asm( "call (%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15), " + "_optix_get_catmullrom_vertex_data, " + "(%16, %17, %18, %19);" + : "=f"( data[0].x ), "=f"( data[0].y ), "=f"( data[0].z ), "=f"( data[0].w ), "=f"( data[1].x ), + "=f"( data[1].y ), "=f"( data[1].z ), "=f"( data[1].w ), "=f"( data[2].x ), "=f"( data[2].y ), + "=f"( data[2].z ), "=f"( data[2].w ), "=f"( data[3].x ), "=f"( data[3].y ), "=f"( data[3].z ), "=f"( data[3].w ) + : "l"( gas ), "r"( primIdx ), "r"( sbtGASIndex ), "f"( time ) + : ); +} + +static __forceinline__ __device__ void optixGetSphereData( OptixTraversableHandle gas, + unsigned int primIdx, + unsigned int sbtGASIndex, + float time, + float4 data[1] ) +{ + asm( "call (%0, %1, %2, %3), " + "_optix_get_sphere_data, " + "(%4, %5, %6, %7);" + : "=f"( data[0].x ), "=f"( data[0].y ), "=f"( data[0].z ), "=f"( data[0].w ) + : "l"( gas ), "r"( primIdx ), "r"( sbtGASIndex ), "f"( time ) + : ); +} + +static __forceinline__ __device__ OptixTraversableHandle optixGetGASTraversableHandle() +{ + unsigned long long handle; + asm( "call (%0), _optix_get_gas_traversable_handle, ();" : "=l"( handle ) : ); + return (OptixTraversableHandle)handle; +} + +static __forceinline__ __device__ float optixGetGASMotionTimeBegin( OptixTraversableHandle handle ) +{ + float f0; + asm( "call (%0), _optix_get_gas_motion_time_begin, (%1);" : "=f"( f0 ) : "l"( handle ) : ); + return f0; +} + +static __forceinline__ __device__ float optixGetGASMotionTimeEnd( OptixTraversableHandle handle ) +{ + float f0; + asm( "call (%0), _optix_get_gas_motion_time_end, (%1);" : "=f"( f0 ) : "l"( handle ) : ); + return f0; +} + +static __forceinline__ __device__ unsigned int optixGetGASMotionStepCount( OptixTraversableHandle handle ) +{ + unsigned int u0; + asm( "call (%0), _optix_get_gas_motion_step_count, (%1);" : "=r"( u0 ) : "l"( handle ) : ); + return u0; +} + +static __forceinline__ __device__ void optixGetWorldToObjectTransformMatrix( float m[12] ) +{ + if( optixGetTransformListSize() == 0 ) + { + m[0] = 1.0f; + m[1] = 0.0f; + m[2] = 0.0f; + m[3] = 0.0f; + m[4] = 0.0f; + m[5] = 1.0f; + m[6] = 0.0f; + m[7] = 0.0f; + m[8] = 0.0f; + m[9] = 0.0f; + m[10] = 1.0f; + m[11] = 0.0f; + return; + } + + float4 m0, m1, m2; + optix_impl::optixGetWorldToObjectTransformMatrix( m0, m1, m2 ); + m[0] = m0.x; + m[1] = m0.y; + m[2] = m0.z; + m[3] = m0.w; + m[4] = m1.x; + m[5] = m1.y; + m[6] = m1.z; + m[7] = m1.w; + m[8] = m2.x; + m[9] = m2.y; + m[10] = m2.z; + m[11] = m2.w; +} + +static __forceinline__ __device__ void optixGetObjectToWorldTransformMatrix( float m[12] ) +{ + if( optixGetTransformListSize() == 0 ) + { + m[0] = 1.0f; + m[1] = 0.0f; + m[2] = 0.0f; + m[3] = 0.0f; + m[4] = 0.0f; + m[5] = 1.0f; + m[6] = 0.0f; + m[7] = 0.0f; + m[8] = 0.0f; + m[9] = 0.0f; + m[10] = 1.0f; + m[11] = 0.0f; + return; + } + + float4 m0, m1, m2; + optix_impl::optixGetObjectToWorldTransformMatrix( m0, m1, m2 ); + m[0] = m0.x; + m[1] = m0.y; + m[2] = m0.z; + m[3] = m0.w; + m[4] = m1.x; + m[5] = m1.y; + m[6] = m1.z; + m[7] = m1.w; + m[8] = m2.x; + m[9] = m2.y; + m[10] = m2.z; + m[11] = m2.w; +} + +static __forceinline__ __device__ float3 optixTransformPointFromWorldToObjectSpace( float3 point ) +{ + if( optixGetTransformListSize() == 0 ) + return point; + + float4 m0, m1, m2; + optix_impl::optixGetWorldToObjectTransformMatrix( m0, m1, m2 ); + return optix_impl::optixTransformPoint( m0, m1, m2, point ); +} + +static __forceinline__ __device__ float3 optixTransformVectorFromWorldToObjectSpace( float3 vec ) +{ + if( optixGetTransformListSize() == 0 ) + return vec; + + float4 m0, m1, m2; + optix_impl::optixGetWorldToObjectTransformMatrix( m0, m1, m2 ); + return optix_impl::optixTransformVector( m0, m1, m2, vec ); +} + +static __forceinline__ __device__ float3 optixTransformNormalFromWorldToObjectSpace( float3 normal ) +{ + if( optixGetTransformListSize() == 0 ) + return normal; + + float4 m0, m1, m2; + optix_impl::optixGetObjectToWorldTransformMatrix( m0, m1, m2 ); // inverse of optixGetWorldToObjectTransformMatrix() + return optix_impl::optixTransformNormal( m0, m1, m2, normal ); +} + +static __forceinline__ __device__ float3 optixTransformPointFromObjectToWorldSpace( float3 point ) +{ + if( optixGetTransformListSize() == 0 ) + return point; + + float4 m0, m1, m2; + optix_impl::optixGetObjectToWorldTransformMatrix( m0, m1, m2 ); + return optix_impl::optixTransformPoint( m0, m1, m2, point ); +} + +static __forceinline__ __device__ float3 optixTransformVectorFromObjectToWorldSpace( float3 vec ) +{ + if( optixGetTransformListSize() == 0 ) + return vec; + + float4 m0, m1, m2; + optix_impl::optixGetObjectToWorldTransformMatrix( m0, m1, m2 ); + return optix_impl::optixTransformVector( m0, m1, m2, vec ); +} + +static __forceinline__ __device__ float3 optixTransformNormalFromObjectToWorldSpace( float3 normal ) +{ + if( optixGetTransformListSize() == 0 ) + return normal; + + float4 m0, m1, m2; + optix_impl::optixGetWorldToObjectTransformMatrix( m0, m1, m2 ); // inverse of optixGetObjectToWorldTransformMatrix() + return optix_impl::optixTransformNormal( m0, m1, m2, normal ); +} + +static __forceinline__ __device__ unsigned int optixGetTransformListSize() +{ + unsigned int u0; + asm( "call (%0), _optix_get_transform_list_size, ();" : "=r"( u0 ) : ); + return u0; +} + +static __forceinline__ __device__ OptixTraversableHandle optixGetTransformListHandle( unsigned int index ) +{ + unsigned long long u0; + asm( "call (%0), _optix_get_transform_list_handle, (%1);" : "=l"( u0 ) : "r"( index ) : ); + return u0; +} + +static __forceinline__ __device__ OptixTransformType optixGetTransformTypeFromHandle( OptixTraversableHandle handle ) +{ + int i0; + asm( "call (%0), _optix_get_transform_type_from_handle, (%1);" : "=r"( i0 ) : "l"( handle ) : ); + return (OptixTransformType)i0; +} + +static __forceinline__ __device__ const OptixStaticTransform* optixGetStaticTransformFromHandle( OptixTraversableHandle handle ) +{ + unsigned long long ptr; + asm( "call (%0), _optix_get_static_transform_from_handle, (%1);" : "=l"( ptr ) : "l"( handle ) : ); + return (const OptixStaticTransform*)ptr; +} + +static __forceinline__ __device__ const OptixSRTMotionTransform* optixGetSRTMotionTransformFromHandle( OptixTraversableHandle handle ) +{ + unsigned long long ptr; + asm( "call (%0), _optix_get_srt_motion_transform_from_handle, (%1);" : "=l"( ptr ) : "l"( handle ) : ); + return (const OptixSRTMotionTransform*)ptr; +} + +static __forceinline__ __device__ const OptixMatrixMotionTransform* optixGetMatrixMotionTransformFromHandle( OptixTraversableHandle handle ) +{ + unsigned long long ptr; + asm( "call (%0), _optix_get_matrix_motion_transform_from_handle, (%1);" : "=l"( ptr ) : "l"( handle ) : ); + return (const OptixMatrixMotionTransform*)ptr; +} + +static __forceinline__ __device__ unsigned int optixGetInstanceIdFromHandle( OptixTraversableHandle handle ) +{ + int i0; + asm( "call (%0), _optix_get_instance_id_from_handle, (%1);" : "=r"( i0 ) : "l"( handle ) : ); + return i0; +} + +static __forceinline__ __device__ OptixTraversableHandle optixGetInstanceChildFromHandle( OptixTraversableHandle handle ) +{ + unsigned long long i0; + asm( "call (%0), _optix_get_instance_child_from_handle, (%1);" : "=l"( i0 ) : "l"( handle ) : ); + return (OptixTraversableHandle)i0; +} + +static __forceinline__ __device__ const float4* optixGetInstanceTransformFromHandle( OptixTraversableHandle handle ) +{ + unsigned long long ptr; + asm( "call (%0), _optix_get_instance_transform_from_handle, (%1);" : "=l"( ptr ) : "l"( handle ) : ); + return (const float4*)ptr; +} + +static __forceinline__ __device__ const float4* optixGetInstanceInverseTransformFromHandle( OptixTraversableHandle handle ) +{ + unsigned long long ptr; + asm( "call (%0), _optix_get_instance_inverse_transform_from_handle, (%1);" : "=l"( ptr ) : "l"( handle ) : ); + return (const float4*)ptr; +} + +static __forceinline__ __device__ bool optixReportIntersection( float hitT, unsigned int hitKind ) +{ + int ret; + asm volatile( + "call (%0), _optix_report_intersection_0" + ", (%1, %2);" + : "=r"( ret ) + : "f"( hitT ), "r"( hitKind ) + : ); + return ret; +} + +static __forceinline__ __device__ bool optixReportIntersection( float hitT, unsigned int hitKind, unsigned int a0 ) +{ + int ret; + asm volatile( + "call (%0), _optix_report_intersection_1" + ", (%1, %2, %3);" + : "=r"( ret ) + : "f"( hitT ), "r"( hitKind ), "r"( a0 ) + : ); + return ret; +} + +static __forceinline__ __device__ bool optixReportIntersection( float hitT, unsigned int hitKind, unsigned int a0, unsigned int a1 ) +{ + int ret; + asm volatile( + "call (%0), _optix_report_intersection_2" + ", (%1, %2, %3, %4);" + : "=r"( ret ) + : "f"( hitT ), "r"( hitKind ), "r"( a0 ), "r"( a1 ) + : ); + return ret; +} + +static __forceinline__ __device__ bool optixReportIntersection( float hitT, unsigned int hitKind, unsigned int a0, unsigned int a1, unsigned int a2 ) +{ + int ret; + asm volatile( + "call (%0), _optix_report_intersection_3" + ", (%1, %2, %3, %4, %5);" + : "=r"( ret ) + : "f"( hitT ), "r"( hitKind ), "r"( a0 ), "r"( a1 ), "r"( a2 ) + : ); + return ret; +} + +static __forceinline__ __device__ bool optixReportIntersection( float hitT, + unsigned int hitKind, + unsigned int a0, + unsigned int a1, + unsigned int a2, + unsigned int a3 ) +{ + int ret; + asm volatile( + "call (%0), _optix_report_intersection_4" + ", (%1, %2, %3, %4, %5, %6);" + : "=r"( ret ) + : "f"( hitT ), "r"( hitKind ), "r"( a0 ), "r"( a1 ), "r"( a2 ), "r"( a3 ) + : ); + return ret; +} + +static __forceinline__ __device__ bool optixReportIntersection( float hitT, + unsigned int hitKind, + unsigned int a0, + unsigned int a1, + unsigned int a2, + unsigned int a3, + unsigned int a4 ) +{ + int ret; + asm volatile( + "call (%0), _optix_report_intersection_5" + ", (%1, %2, %3, %4, %5, %6, %7);" + : "=r"( ret ) + : "f"( hitT ), "r"( hitKind ), "r"( a0 ), "r"( a1 ), "r"( a2 ), "r"( a3 ), "r"( a4 ) + : ); + return ret; +} + +static __forceinline__ __device__ bool optixReportIntersection( float hitT, + unsigned int hitKind, + unsigned int a0, + unsigned int a1, + unsigned int a2, + unsigned int a3, + unsigned int a4, + unsigned int a5 ) +{ + int ret; + asm volatile( + "call (%0), _optix_report_intersection_6" + ", (%1, %2, %3, %4, %5, %6, %7, %8);" + : "=r"( ret ) + : "f"( hitT ), "r"( hitKind ), "r"( a0 ), "r"( a1 ), "r"( a2 ), "r"( a3 ), "r"( a4 ), "r"( a5 ) + : ); + return ret; +} + +static __forceinline__ __device__ bool optixReportIntersection( float hitT, + unsigned int hitKind, + unsigned int a0, + unsigned int a1, + unsigned int a2, + unsigned int a3, + unsigned int a4, + unsigned int a5, + unsigned int a6 ) +{ + int ret; + asm volatile( + "call (%0), _optix_report_intersection_7" + ", (%1, %2, %3, %4, %5, %6, %7, %8, %9);" + : "=r"( ret ) + : "f"( hitT ), "r"( hitKind ), "r"( a0 ), "r"( a1 ), "r"( a2 ), "r"( a3 ), "r"( a4 ), "r"( a5 ), "r"( a6 ) + : ); + return ret; +} + +static __forceinline__ __device__ bool optixReportIntersection( float hitT, + unsigned int hitKind, + unsigned int a0, + unsigned int a1, + unsigned int a2, + unsigned int a3, + unsigned int a4, + unsigned int a5, + unsigned int a6, + unsigned int a7 ) +{ + int ret; + asm volatile( + "call (%0), _optix_report_intersection_8" + ", (%1, %2, %3, %4, %5, %6, %7, %8, %9, %10);" + : "=r"( ret ) + : "f"( hitT ), "r"( hitKind ), "r"( a0 ), "r"( a1 ), "r"( a2 ), "r"( a3 ), "r"( a4 ), "r"( a5 ), "r"( a6 ), "r"( a7 ) + : ); + return ret; +} + +#define OPTIX_DEFINE_optixGetAttribute_BODY( which ) \ + unsigned int ret; \ + asm( "call (%0), _optix_get_attribute_" #which ", ();" : "=r"( ret ) : ); \ + return ret; + +static __forceinline__ __device__ unsigned int optixGetAttribute_0() +{ + OPTIX_DEFINE_optixGetAttribute_BODY( 0 ); +} + +static __forceinline__ __device__ unsigned int optixGetAttribute_1() +{ + OPTIX_DEFINE_optixGetAttribute_BODY( 1 ); +} + +static __forceinline__ __device__ unsigned int optixGetAttribute_2() +{ + OPTIX_DEFINE_optixGetAttribute_BODY( 2 ); +} + +static __forceinline__ __device__ unsigned int optixGetAttribute_3() +{ + OPTIX_DEFINE_optixGetAttribute_BODY( 3 ); +} + +static __forceinline__ __device__ unsigned int optixGetAttribute_4() +{ + OPTIX_DEFINE_optixGetAttribute_BODY( 4 ); +} + +static __forceinline__ __device__ unsigned int optixGetAttribute_5() +{ + OPTIX_DEFINE_optixGetAttribute_BODY( 5 ); +} + +static __forceinline__ __device__ unsigned int optixGetAttribute_6() +{ + OPTIX_DEFINE_optixGetAttribute_BODY( 6 ); +} + +static __forceinline__ __device__ unsigned int optixGetAttribute_7() +{ + OPTIX_DEFINE_optixGetAttribute_BODY( 7 ); +} + +#undef OPTIX_DEFINE_optixGetAttribute_BODY + +static __forceinline__ __device__ void optixTerminateRay() +{ + asm volatile( "call _optix_terminate_ray, ();" ); +} + +static __forceinline__ __device__ void optixIgnoreIntersection() +{ + asm volatile( "call _optix_ignore_intersection, ();" ); +} + +static __forceinline__ __device__ unsigned int optixGetPrimitiveIndex() +{ + unsigned int u0; + asm( "call (%0), _optix_read_primitive_idx, ();" : "=r"( u0 ) : ); + return u0; +} + +static __forceinline__ __device__ unsigned int optixGetSbtGASIndex() +{ + unsigned int u0; + asm( "call (%0), _optix_read_sbt_gas_idx, ();" : "=r"( u0 ) : ); + return u0; +} + +static __forceinline__ __device__ unsigned int optixGetInstanceId() +{ + unsigned int u0; + asm( "call (%0), _optix_read_instance_id, ();" : "=r"( u0 ) : ); + return u0; +} + +static __forceinline__ __device__ unsigned int optixGetInstanceIndex() +{ + unsigned int u0; + asm( "call (%0), _optix_read_instance_idx, ();" : "=r"( u0 ) : ); + return u0; +} + +static __forceinline__ __device__ unsigned int optixGetHitKind() +{ + unsigned int u0; + asm( "call (%0), _optix_get_hit_kind, ();" : "=r"( u0 ) : ); + return u0; +} + +static __forceinline__ __device__ OptixPrimitiveType optixGetPrimitiveType(unsigned int hitKind) +{ + unsigned int u0; + asm( "call (%0), _optix_get_primitive_type_from_hit_kind, (%1);" : "=r"( u0 ) : "r"( hitKind ) ); + return (OptixPrimitiveType)u0; +} + +static __forceinline__ __device__ bool optixIsBackFaceHit( unsigned int hitKind ) +{ + unsigned int u0; + asm( "call (%0), _optix_get_backface_from_hit_kind, (%1);" : "=r"( u0 ) : "r"( hitKind ) ); + return (u0 == 0x1); +} + +static __forceinline__ __device__ bool optixIsFrontFaceHit( unsigned int hitKind ) +{ + return !optixIsBackFaceHit( hitKind ); +} + + +static __forceinline__ __device__ OptixPrimitiveType optixGetPrimitiveType() +{ + return optixGetPrimitiveType( optixGetHitKind() ); +} + +static __forceinline__ __device__ bool optixIsBackFaceHit() +{ + return optixIsBackFaceHit( optixGetHitKind() ); +} + +static __forceinline__ __device__ bool optixIsFrontFaceHit() +{ + return optixIsFrontFaceHit( optixGetHitKind() ); +} + +static __forceinline__ __device__ bool optixIsTriangleHit() +{ + return optixIsTriangleFrontFaceHit() || optixIsTriangleBackFaceHit(); +} + +static __forceinline__ __device__ bool optixIsTriangleFrontFaceHit() +{ + return optixGetHitKind() == OPTIX_HIT_KIND_TRIANGLE_FRONT_FACE; +} + +static __forceinline__ __device__ bool optixIsTriangleBackFaceHit() +{ + return optixGetHitKind() == OPTIX_HIT_KIND_TRIANGLE_BACK_FACE; +} + +static __forceinline__ __device__ float optixGetCurveParameter() +{ + return __int_as_float( optixGetAttribute_0() ); +} + +static __forceinline__ __device__ float2 optixGetTriangleBarycentrics() +{ + float f0, f1; + asm( "call (%0, %1), _optix_get_triangle_barycentrics, ();" : "=f"( f0 ), "=f"( f1 ) : ); + return make_float2( f0, f1 ); +} + +static __forceinline__ __device__ uint3 optixGetLaunchIndex() +{ + unsigned int u0, u1, u2; + asm( "call (%0), _optix_get_launch_index_x, ();" : "=r"( u0 ) : ); + asm( "call (%0), _optix_get_launch_index_y, ();" : "=r"( u1 ) : ); + asm( "call (%0), _optix_get_launch_index_z, ();" : "=r"( u2 ) : ); + return make_uint3( u0, u1, u2 ); +} + +static __forceinline__ __device__ uint3 optixGetLaunchDimensions() +{ + unsigned int u0, u1, u2; + asm( "call (%0), _optix_get_launch_dimension_x, ();" : "=r"( u0 ) : ); + asm( "call (%0), _optix_get_launch_dimension_y, ();" : "=r"( u1 ) : ); + asm( "call (%0), _optix_get_launch_dimension_z, ();" : "=r"( u2 ) : ); + return make_uint3( u0, u1, u2 ); +} + +static __forceinline__ __device__ CUdeviceptr optixGetSbtDataPointer() +{ + unsigned long long ptr; + asm( "call (%0), _optix_get_sbt_data_ptr_64, ();" : "=l"( ptr ) : ); + return (CUdeviceptr)ptr; +} + +static __forceinline__ __device__ void optixThrowException( int exceptionCode ) +{ + asm volatile( + "call _optix_throw_exception_0, (%0);" + : /* no return value */ + : "r"( exceptionCode ) + : ); +} + +static __forceinline__ __device__ void optixThrowException( int exceptionCode, unsigned int exceptionDetail0 ) +{ + asm volatile( + "call _optix_throw_exception_1, (%0, %1);" + : /* no return value */ + : "r"( exceptionCode ), "r"( exceptionDetail0 ) + : ); +} + +static __forceinline__ __device__ void optixThrowException( int exceptionCode, unsigned int exceptionDetail0, unsigned int exceptionDetail1 ) +{ + asm volatile( + "call _optix_throw_exception_2, (%0, %1, %2);" + : /* no return value */ + : "r"( exceptionCode ), "r"( exceptionDetail0 ), "r"( exceptionDetail1 ) + : ); +} + +static __forceinline__ __device__ void optixThrowException( int exceptionCode, unsigned int exceptionDetail0, unsigned int exceptionDetail1, unsigned int exceptionDetail2 ) +{ + asm volatile( + "call _optix_throw_exception_3, (%0, %1, %2, %3);" + : /* no return value */ + : "r"( exceptionCode ), "r"( exceptionDetail0 ), "r"( exceptionDetail1 ), "r"( exceptionDetail2 ) + : ); +} + +static __forceinline__ __device__ void optixThrowException( int exceptionCode, unsigned int exceptionDetail0, unsigned int exceptionDetail1, unsigned int exceptionDetail2, unsigned int exceptionDetail3 ) +{ + asm volatile( + "call _optix_throw_exception_4, (%0, %1, %2, %3, %4);" + : /* no return value */ + : "r"( exceptionCode ), "r"( exceptionDetail0 ), "r"( exceptionDetail1 ), "r"( exceptionDetail2 ), "r"( exceptionDetail3 ) + : ); +} + +static __forceinline__ __device__ void optixThrowException( int exceptionCode, unsigned int exceptionDetail0, unsigned int exceptionDetail1, unsigned int exceptionDetail2, unsigned int exceptionDetail3, unsigned int exceptionDetail4 ) +{ + asm volatile( + "call _optix_throw_exception_5, (%0, %1, %2, %3, %4, %5);" + : /* no return value */ + : "r"( exceptionCode ), "r"( exceptionDetail0 ), "r"( exceptionDetail1 ), "r"( exceptionDetail2 ), "r"( exceptionDetail3 ), "r"( exceptionDetail4 ) + : ); +} + +static __forceinline__ __device__ void optixThrowException( int exceptionCode, unsigned int exceptionDetail0, unsigned int exceptionDetail1, unsigned int exceptionDetail2, unsigned int exceptionDetail3, unsigned int exceptionDetail4, unsigned int exceptionDetail5 ) +{ + asm volatile( + "call _optix_throw_exception_6, (%0, %1, %2, %3, %4, %5, %6);" + : /* no return value */ + : "r"( exceptionCode ), "r"( exceptionDetail0 ), "r"( exceptionDetail1 ), "r"( exceptionDetail2 ), "r"( exceptionDetail3 ), "r"( exceptionDetail4 ), "r"( exceptionDetail5 ) + : ); +} + +static __forceinline__ __device__ void optixThrowException( int exceptionCode, unsigned int exceptionDetail0, unsigned int exceptionDetail1, unsigned int exceptionDetail2, unsigned int exceptionDetail3, unsigned int exceptionDetail4, unsigned int exceptionDetail5, unsigned int exceptionDetail6 ) +{ + asm volatile( + "call _optix_throw_exception_7, (%0, %1, %2, %3, %4, %5, %6, %7);" + : /* no return value */ + : "r"( exceptionCode ), "r"( exceptionDetail0 ), "r"( exceptionDetail1 ), "r"( exceptionDetail2 ), "r"( exceptionDetail3 ), "r"( exceptionDetail4 ), "r"( exceptionDetail5 ), "r"( exceptionDetail6 ) + : ); +} + +static __forceinline__ __device__ void optixThrowException( int exceptionCode, unsigned int exceptionDetail0, unsigned int exceptionDetail1, unsigned int exceptionDetail2, unsigned int exceptionDetail3, unsigned int exceptionDetail4, unsigned int exceptionDetail5, unsigned int exceptionDetail6, unsigned int exceptionDetail7 ) +{ + asm volatile( + "call _optix_throw_exception_8, (%0, %1, %2, %3, %4, %5, %6, %7, %8);" + : /* no return value */ + : "r"( exceptionCode ), "r"( exceptionDetail0 ), "r"( exceptionDetail1 ), "r"( exceptionDetail2 ), "r"( exceptionDetail3 ), "r"( exceptionDetail4 ), "r"( exceptionDetail5 ), "r"( exceptionDetail6 ), "r"( exceptionDetail7 ) + : ); +} + +static __forceinline__ __device__ int optixGetExceptionCode() +{ + int s0; + asm( "call (%0), _optix_get_exception_code, ();" : "=r"( s0 ) : ); + return s0; +} + +#define OPTIX_DEFINE_optixGetExceptionDetail_BODY( which ) \ + unsigned int ret; \ + asm( "call (%0), _optix_get_exception_detail_" #which ", ();" : "=r"( ret ) : ); \ + return ret; + +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_0() +{ + OPTIX_DEFINE_optixGetExceptionDetail_BODY( 0 ); +} + +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_1() +{ + OPTIX_DEFINE_optixGetExceptionDetail_BODY( 1 ); +} + +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_2() +{ + OPTIX_DEFINE_optixGetExceptionDetail_BODY( 2 ); +} + +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_3() +{ + OPTIX_DEFINE_optixGetExceptionDetail_BODY( 3 ); +} + +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_4() +{ + OPTIX_DEFINE_optixGetExceptionDetail_BODY( 4 ); +} + +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_5() +{ + OPTIX_DEFINE_optixGetExceptionDetail_BODY( 5 ); +} + +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_6() +{ + OPTIX_DEFINE_optixGetExceptionDetail_BODY( 6 ); +} + +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_7() +{ + OPTIX_DEFINE_optixGetExceptionDetail_BODY( 7 ); +} + +#undef OPTIX_DEFINE_optixGetExceptionDetail_BODY + +static __forceinline__ __device__ OptixTraversableHandle optixGetExceptionInvalidTraversable() +{ + unsigned long long handle; + asm( "call (%0), _optix_get_exception_invalid_traversable, ();" : "=l"( handle ) : ); + return (OptixTraversableHandle)handle; +} + +static __forceinline__ __device__ int optixGetExceptionInvalidSbtOffset() +{ + int s0; + asm( "call (%0), _optix_get_exception_invalid_sbt_offset, ();" : "=r"( s0 ) : ); + return s0; +} + +static __forceinline__ __device__ OptixInvalidRayExceptionDetails optixGetExceptionInvalidRay() +{ + float rayOriginX, rayOriginY, rayOriginZ, rayDirectionX, rayDirectionY, rayDirectionZ, tmin, tmax, rayTime; + asm( "call (%0, %1, %2, %3, %4, %5, %6, %7, %8), _optix_get_exception_invalid_ray, ();" + : "=f"( rayOriginX ), "=f"( rayOriginY ), "=f"( rayOriginZ ), "=f"( rayDirectionX ), "=f"( rayDirectionY ), + "=f"( rayDirectionZ ), "=f"( tmin ), "=f"( tmax ), "=f"( rayTime ) + : ); + OptixInvalidRayExceptionDetails ray; + ray.origin = make_float3( rayOriginX, rayOriginY, rayOriginZ ); + ray.direction = make_float3( rayDirectionX, rayDirectionY, rayDirectionZ ); + ray.tmin = tmin; + ray.tmax = tmax; + ray.time = rayTime; + return ray; +} + +static __forceinline__ __device__ OptixParameterMismatchExceptionDetails optixGetExceptionParameterMismatch() +{ + unsigned int expected, actual, sbtIdx; + unsigned long long calleeName; + asm( + "call (%0, %1, %2, %3), _optix_get_exception_parameter_mismatch, ();" + : "=r"(expected), "=r"(actual), "=r"(sbtIdx), "=l"(calleeName) : ); + OptixParameterMismatchExceptionDetails details; + details.expectedParameterCount = expected; + details.passedArgumentCount = actual; + details.sbtIndex = sbtIdx; + details.callableName = (char*)calleeName; + return details; +} + +static __forceinline__ __device__ char* optixGetExceptionLineInfo() +{ + unsigned long long ptr; + asm( "call (%0), _optix_get_exception_line_info, ();" : "=l"(ptr) : ); + return (char*)ptr; +} + +template +static __forceinline__ __device__ ReturnT optixDirectCall( unsigned int sbtIndex, ArgTypes... args ) +{ + unsigned long long func; + asm( "call (%0), _optix_call_direct_callable,(%1);" : "=l"( func ) : "r"( sbtIndex ) : ); + using funcT = ReturnT ( * )( ArgTypes... ); + funcT call = ( funcT )( func ); + return call( args... ); +} + +template +static __forceinline__ __device__ ReturnT optixContinuationCall( unsigned int sbtIndex, ArgTypes... args ) +{ + unsigned long long func; + asm( "call (%0), _optix_call_continuation_callable,(%1);" : "=l"( func ) : "r"( sbtIndex ) : ); + using funcT = ReturnT ( * )( ArgTypes... ); + funcT call = ( funcT )( func ); + return call( args... ); +} +#endif + +static __forceinline__ __device__ uint4 optixTexFootprint2D( unsigned long long tex, unsigned int texInfo, float x, float y, unsigned int* singleMipLevel ) +{ + uint4 result; + unsigned long long resultPtr = reinterpret_cast( &result ); + unsigned long long singleMipLevelPtr = reinterpret_cast( singleMipLevel ); + // Cast float args to integers, because the intrinics take .b32 arguments when compiled to PTX. + asm volatile( + "call _optix_tex_footprint_2d_v2" + ", (%0, %1, %2, %3, %4, %5);" + : + : "l"( tex ), "r"( texInfo ), "r"( __float_as_uint( x ) ), "r"( __float_as_uint( y ) ), + "l"( singleMipLevelPtr ), "l"( resultPtr ) + : ); + return result; +} + +static __forceinline__ __device__ uint4 optixTexFootprint2DGrad( unsigned long long tex, + unsigned int texInfo, + float x, + float y, + float dPdx_x, + float dPdx_y, + float dPdy_x, + float dPdy_y, + bool coarse, + unsigned int* singleMipLevel ) +{ + uint4 result; + unsigned long long resultPtr = reinterpret_cast( &result ); + unsigned long long singleMipLevelPtr = reinterpret_cast( singleMipLevel ); + // Cast float args to integers, because the intrinics take .b32 arguments when compiled to PTX. + asm volatile( + "call _optix_tex_footprint_2d_grad_v2" + ", (%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10);" + : + : "l"( tex ), "r"( texInfo ), "r"( __float_as_uint( x ) ), "r"( __float_as_uint( y ) ), + "r"( __float_as_uint( dPdx_x ) ), "r"( __float_as_uint( dPdx_y ) ), "r"( __float_as_uint( dPdy_x ) ), + "r"( __float_as_uint( dPdy_y ) ), "r"( static_cast( coarse ) ), "l"( singleMipLevelPtr ), "l"( resultPtr ) + : ); + + return result; +} + +static __forceinline__ __device__ uint4 +optixTexFootprint2DLod( unsigned long long tex, unsigned int texInfo, float x, float y, float level, bool coarse, unsigned int* singleMipLevel ) +{ + uint4 result; + unsigned long long resultPtr = reinterpret_cast( &result ); + unsigned long long singleMipLevelPtr = reinterpret_cast( singleMipLevel ); + // Cast float args to integers, because the intrinics take .b32 arguments when compiled to PTX. + asm volatile( + "call _optix_tex_footprint_2d_lod_v2" + ", (%0, %1, %2, %3, %4, %5, %6, %7);" + : + : "l"( tex ), "r"( texInfo ), "r"( __float_as_uint( x ) ), "r"( __float_as_uint( y ) ), + "r"( __float_as_uint( level ) ), "r"( static_cast( coarse ) ), "l"( singleMipLevelPtr ), "l"( resultPtr ) + : ); + return result; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/internal/optix_7_device_impl_exception.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/internal/optix_7_device_impl_exception.h new file mode 100644 index 00000000..abca3eba --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/internal/optix_7_device_impl_exception.h @@ -0,0 +1,286 @@ +/* +* SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* SPDX-License-Identifier: LicenseRef-NvidiaProprietary +* +* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +* property and proprietary rights in and to this material, related +* documentation and any modifications thereto. Any use, reproduction, +* disclosure or distribution of this material and related documentation +* without an express license agreement from NVIDIA CORPORATION or +* its affiliates is strictly prohibited. +*/ +/** +* @file optix_7_device_impl_exception.h +* @author NVIDIA Corporation +* @brief OptiX public API +* +* OptiX public API Reference - Device side implementation for exception helper function. +*/ + +#if !defined( __OPTIX_INCLUDE_INTERNAL_HEADERS__ ) +#error("optix_7_device_impl_exception.h is an internal header file and must not be used directly. Please use optix_device.h or optix.h instead.") +#endif + +#ifndef __optix_optix_7_device_impl_exception_h__ +#define __optix_optix_7_device_impl_exception_h__ + +#if !defined(__CUDACC_RTC__) +#include /* for printf */ +#endif + +namespace optix_impl { + + static __forceinline__ __device__ void optixDumpStaticTransformFromHandle( OptixTraversableHandle handle ) + { + const OptixStaticTransform* traversable = optixGetStaticTransformFromHandle( handle ); + if( traversable ) + { + const uint3 index = optixGetLaunchIndex(); + printf( "(%4i,%4i,%4i) OptixStaticTransform@%p = {\n" + " child = %p,\n" + " transform = { %f,%f,%f,%f,\n" + " %f,%f,%f,%f,\n" + " %f,%f,%f,%f } }\n", + index.x,index.y,index.z, + traversable, + (void*)traversable->child, + traversable->transform[0], traversable->transform[1], traversable->transform[2], traversable->transform[3], + traversable->transform[4], traversable->transform[5], traversable->transform[6], traversable->transform[7], + traversable->transform[8], traversable->transform[9], traversable->transform[10], traversable->transform[11] ); + } + } + + static __forceinline__ __device__ void optixDumpMotionMatrixTransformFromHandle( OptixTraversableHandle handle ) + { + const OptixMatrixMotionTransform* traversable = optixGetMatrixMotionTransformFromHandle( handle ); + if( traversable ) + { + const uint3 index = optixGetLaunchIndex(); + printf( "(%4i,%4i,%4i) OptixMatrixMotionTransform@%p = {\n" + " child = %p,\n" + " motionOptions = { numKeys = %i, flags = %i, timeBegin = %f, timeEnd = %f },\n" + " transform = { { %f,%f,%f,%f,\n" + " %f,%f,%f,%f,\n" + " %f,%f,%f,%f }, ... }\n", + index.x,index.y,index.z, + traversable, + (void*)traversable->child, + (int)traversable->motionOptions.numKeys, (int)traversable->motionOptions.flags, traversable->motionOptions.timeBegin, traversable->motionOptions.timeEnd, + traversable->transform[0][0], traversable->transform[0][1], traversable->transform[0][2], traversable->transform[0][3], + traversable->transform[0][4], traversable->transform[0][5], traversable->transform[0][6], traversable->transform[0][7], + traversable->transform[0][8], traversable->transform[0][9], traversable->transform[0][10], traversable->transform[0][11] ); + } + } + + static __forceinline__ __device__ void optixDumpSrtMatrixTransformFromHandle( OptixTraversableHandle handle ) + { + const OptixSRTMotionTransform* traversable = optixGetSRTMotionTransformFromHandle( handle ); + if( traversable ) + { + const uint3 index = optixGetLaunchIndex(); + printf( "(%4i,%4i,%4i) OptixSRTMotionTransform@%p = {\n" + " child = %p,\n" + " motionOptions = { numKeys = %i, flags = %i, timeBegin = %f, timeEnd = %f },\n" + " srtData = { { sx = %f, a = %f, b = %f, pvx = %f,\n" + " sy = %f, c = %f, pvy = %f, sz = %f,\n" + " pvz = %f, qx = %f, qy = %f, qz = %f,\n" + " qw = %f, tx = %f, ty = %f, tz = %f }, ... }\n", + index.x,index.y,index.z, + traversable, + (void*)traversable->child, + (int)traversable->motionOptions.numKeys, (int)traversable->motionOptions.flags, traversable->motionOptions.timeBegin, traversable->motionOptions.timeEnd, + traversable->srtData[0].sx, traversable->srtData[0].a, traversable->srtData[0].b, traversable->srtData[0].pvx, + traversable->srtData[0].sy, traversable->srtData[0].c, traversable->srtData[0].pvy,traversable->srtData[0].sz, + traversable->srtData[0].pvz,traversable->srtData[0].qx,traversable->srtData[0].qy, traversable->srtData[0].qz, + traversable->srtData[0].qw, traversable->srtData[0].tx,traversable->srtData[0].ty, traversable->srtData[0].tz ); + } + } + + static __forceinline__ __device__ void optixDumpInstanceFromHandle( OptixTraversableHandle handle ) + { + if( optixGetTransformTypeFromHandle( handle ) == OPTIX_TRANSFORM_TYPE_INSTANCE ) + { + unsigned int instanceId = optixGetInstanceIdFromHandle( handle ); + const float4* transform = optixGetInstanceTransformFromHandle( handle ); + + const uint3 index = optixGetLaunchIndex(); + printf( "(%4i,%4i,%4i) OptixInstance = {\n" + " instanceId = %i,\n" + " transform = { %f,%f,%f,%f,\n" + " %f,%f,%f,%f,\n" + " %f,%f,%f,%f } }\n", + index.x,index.y,index.z, + instanceId, + transform[0].x, transform[0].y, transform[0].z, transform[0].w, + transform[1].x, transform[1].y, transform[1].z, transform[1].w, + transform[2].x, transform[2].y, transform[2].z, transform[2].w ); + } + } + + static __forceinline__ __device__ void optixDumpTransform( OptixTraversableHandle handle ) + { + const OptixTransformType type = optixGetTransformTypeFromHandle( handle ); + const uint3 index = optixGetLaunchIndex(); + + switch( type ) + { + case OPTIX_TRANSFORM_TYPE_NONE: + break; + case OPTIX_TRANSFORM_TYPE_STATIC_TRANSFORM: + optixDumpStaticTransformFromHandle( handle ); + break; + case OPTIX_TRANSFORM_TYPE_MATRIX_MOTION_TRANSFORM: + optixDumpMotionMatrixTransformFromHandle( handle ); + break; + case OPTIX_TRANSFORM_TYPE_SRT_MOTION_TRANSFORM: + optixDumpSrtMatrixTransformFromHandle( handle ); + break; + case OPTIX_TRANSFORM_TYPE_INSTANCE: + optixDumpInstanceFromHandle( handle ); + break; + default: + break; + } + } + + static __forceinline__ __device__ void optixDumpTransformList() + { + const int tlistSize = optixGetTransformListSize(); + const uint3 index = optixGetLaunchIndex(); + + printf("(%4i,%4i,%4i) transform list of size %i:\n", index.x,index.y,index.z, tlistSize); + + for( unsigned int i = 0 ; i < tlistSize ; ++i ) + { + OptixTraversableHandle handle = optixGetTransformListHandle( i ); + printf("(%4i,%4i,%4i) transform[%i] = %p\n", index.x, index.y, index.z, i, (void*)handle); + optixDumpTransform(handle); + } + } + + static __forceinline__ __device__ void optixDumpExceptionDetails() + { + bool dumpTlist = false; + const int exceptionCode = optixGetExceptionCode(); + const uint3 index = optixGetLaunchIndex(); + + if( exceptionCode == OPTIX_EXCEPTION_CODE_STACK_OVERFLOW ) + { + printf("(%4i,%4i,%4i) error: stack overflow\n", index.x,index.y,index.z); + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_TRACE_DEPTH_EXCEEDED ) + { + printf("(%4i,%4i,%4i) error: trace depth exceeded\n", index.x,index.y,index.z); + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_TRAVERSAL_DEPTH_EXCEEDED ) + { + printf("(%4i,%4i,%4i) error: traversal depth exceeded\n", index.x,index.y,index.z); + dumpTlist = true; + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_TRAVERSAL_INVALID_TRAVERSABLE ) + { + OptixTraversableHandle handle = optixGetExceptionInvalidTraversable(); + printf("(%4i,%4i,%4i) error: invalid traversable %p\n", index.x,index.y,index.z, (void*)handle); + dumpTlist = true; + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_TRAVERSAL_INVALID_MISS_SBT ) + { + int sbtOffset = optixGetExceptionInvalidSbtOffset(); + printf("(%4i,%4i,%4i) error: invalid miss sbt of %i\n", index.x,index.y,index.z, sbtOffset); + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_TRAVERSAL_INVALID_HIT_SBT ) + { + int sbtOffset = optixGetExceptionInvalidSbtOffset(); + printf("(%4i,%4i,%4i) error: invalid hit sbt of %i at primitive with gas sbt index %i\n", index.x,index.y,index.z, sbtOffset, optixGetSbtGASIndex() ); + dumpTlist = true; + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_UNSUPPORTED_PRIMITIVE_TYPE ) + { + dumpTlist = true; + printf( "(%4i,%4i,%4i) error: shader encountered unsupported builtin type\n" + " call location: %s\n", index.x, index.y, index.z, optixGetExceptionLineInfo() ); + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_INVALID_RAY ) + { + OptixInvalidRayExceptionDetails ray = optixGetExceptionInvalidRay(); + printf( "(%4i,%4i,%4i) error: encountered an invalid ray:\n", index.x, index.y, index.z ); + printf( + " origin: [%f, %f, %f]\n" + " direction: [%f, %f, %f]\n" + " tmin: %f\n" + " tmax: %f\n" + " rayTime: %f\n" + " call location: %s\n", + ray.origin.x, ray.origin.y, ray.origin.z, ray.direction.x, ray.direction.y, + ray.direction.z, ray.tmin, ray.tmax, ray.time, optixGetExceptionLineInfo() ); + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_CALLABLE_PARAMETER_MISMATCH ) + { + OptixParameterMismatchExceptionDetails details = optixGetExceptionParameterMismatch(); + printf( "(%4i,%4i,%4i) error: parameter mismatch in callable call.\n", index.x, index.y, index.z ); + printf( + " passed packed arguments: %u 32 Bit values\n" + " expected packed parameters: %u 32 Bit values\n" + " SBT index: %u\n" + " called function: %s\n" + " call location: %s\n", + details.passedArgumentCount, details.expectedParameterCount, details.sbtIndex, + details.callableName, optixGetExceptionLineInfo() ); + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_BUILTIN_IS_MISMATCH ) + { + dumpTlist = true; + printf("(%4i,%4i,%4i) error: mismatch between builtin IS shader and build input\n" + " call location: %s\n", index.x,index.y,index.z, optixGetExceptionLineInfo() ); + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_CALLABLE_INVALID_SBT ) + { + int sbtOffset = optixGetExceptionInvalidSbtOffset(); + printf( "(%4i,%4i,%4i) error: invalid sbt offset of %i for callable program\n", index.x, index.y, index.z, sbtOffset ); + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_CALLABLE_NO_DC_SBT_RECORD ) + { + int sbtOffset = optixGetExceptionInvalidSbtOffset(); + printf( "(%4i,%4i,%4i) error: invalid sbt offset of %i for direct callable program\n", index.x, index.y, index.z, sbtOffset ); + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_CALLABLE_NO_CC_SBT_RECORD ) + { + int sbtOffset = optixGetExceptionInvalidSbtOffset(); + printf( "(%4i,%4i,%4i) error: invalid sbt offset of %i for continuation callable program\n", index.x, index.y, index.z, sbtOffset ); + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_UNSUPPORTED_SINGLE_LEVEL_GAS ) + { + OptixTraversableHandle handle = optixGetExceptionInvalidTraversable(); + printf("(%4i,%4i,%4i) error: unsupported single GAS traversable graph %p\n", index.x,index.y,index.z, (void*)handle); + dumpTlist = true; + } + else if( ( exceptionCode <= OPTIX_EXCEPTION_CODE_INVALID_VALUE_ARGUMENT_0 ) && ( exceptionCode >= OPTIX_EXCEPTION_CODE_INVALID_VALUE_ARGUMENT_2 ) ) + { + printf("(%4i,%4i,%4i) error: invalid value for argument %i\n", index.x,index.y,index.z, -(exceptionCode - OPTIX_EXCEPTION_CODE_INVALID_VALUE_ARGUMENT_0) ); + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_UNSUPPORTED_DATA_ACCESS ) + { + printf("(%4i,%4i,%4i) error: unsupported random data access\n", index.x,index.y,index.z); + } + else if( exceptionCode == OPTIX_EXCEPTION_CODE_PAYLOAD_TYPE_MISMATCH ) + { + printf("(%4i,%4i,%4i) error: payload type mismatch between program and optixTrace call\n", index.x,index.y,index.z); + } + else if( exceptionCode >= 0 ) + { + dumpTlist = true; + printf( "(%4i,%4i,%4i) error: user exception with error code %i\n" + " call location: %s\n", index.x, index.y, index.z, exceptionCode, optixGetExceptionLineInfo() ); + } + else + { + printf("(%4i,%4i,%4i) error: unknown exception with error code %i\n", index.x,index.y,index.z, exceptionCode); + } + + if( dumpTlist ) + optixDumpTransformList(); + } + +} // namespace optix_impl + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/internal/optix_7_device_impl_transformations.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/internal/optix_7_device_impl_transformations.h new file mode 100644 index 00000000..30f58c55 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/internal/optix_7_device_impl_transformations.h @@ -0,0 +1,415 @@ +/* +* SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* SPDX-License-Identifier: LicenseRef-NvidiaProprietary +* +* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +* property and proprietary rights in and to this material, related +* documentation and any modifications thereto. Any use, reproduction, +* disclosure or distribution of this material and related documentation +* without an express license agreement from NVIDIA CORPORATION or +* its affiliates is strictly prohibited. +*/ +/** +* @file optix_7_device_impl_transformations.h +* @author NVIDIA Corporation +* @brief OptiX public API +* +* OptiX public API Reference - Device side implementation for transformation helper functions. +*/ + +#if !defined( __OPTIX_INCLUDE_INTERNAL_HEADERS__ ) +#error("optix_7_device_impl_transformations.h is an internal header file and must not be used directly. Please use optix_device.h or optix.h instead.") +#endif + +#ifndef __optix_optix_7_device_impl_transformations_h__ +#define __optix_optix_7_device_impl_transformations_h__ + +namespace optix_impl { + +static __forceinline__ __device__ float4 optixAddFloat4( const float4& a, const float4& b ) +{ + return make_float4( a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w ); +} + +static __forceinline__ __device__ float4 optixMulFloat4( const float4& a, float b ) +{ + return make_float4( a.x * b, a.y * b, a.z * b, a.w * b ); +} + +static __forceinline__ __device__ uint4 optixLdg( unsigned long long addr ) +{ + const uint4* ptr; + asm volatile( "cvta.to.global.u64 %0, %1;" : "=l"( ptr ) : "l"( addr ) ); + uint4 ret; + asm volatile( "ld.global.v4.u32 {%0,%1,%2,%3}, [%4];" + : "=r"( ret.x ), "=r"( ret.y ), "=r"( ret.z ), "=r"( ret.w ) + : "l"( ptr ) ); + return ret; +} + +template +static __forceinline__ __device__ T optixLoadReadOnlyAlign16( const T* ptr ) +{ + T v; + for( int ofs = 0; ofs < sizeof( T ); ofs += 16 ) + *(uint4*)( (char*)&v + ofs ) = optixLdg( (unsigned long long)( (char*)ptr + ofs ) ); + return v; +} + +// Multiplies the row vector vec with the 3x4 matrix with rows m0, m1, and m2 +static __forceinline__ __device__ float4 optixMultiplyRowMatrix( const float4 vec, const float4 m0, const float4 m1, const float4 m2 ) +{ + float4 result; + + result.x = vec.x * m0.x + vec.y * m1.x + vec.z * m2.x; + result.y = vec.x * m0.y + vec.y * m1.y + vec.z * m2.y; + result.z = vec.x * m0.z + vec.y * m1.z + vec.z * m2.z; + result.w = vec.x * m0.w + vec.y * m1.w + vec.z * m2.w + vec.w; + + return result; +} + +// Converts the SRT transformation srt into a 3x4 matrix with rows m0, m1, and m2 +static __forceinline__ __device__ void optixGetMatrixFromSrt( float4& m0, float4& m1, float4& m2, const OptixSRTData& srt ) +{ + const float4 q = {srt.qx, srt.qy, srt.qz, srt.qw}; + + // normalize + const float inv_sql = 1.f / ( srt.qx * srt.qx + srt.qy * srt.qy + srt.qz * srt.qz + srt.qw * srt.qw ); + const float4 nq = optixMulFloat4( q, inv_sql ); + + const float sqw = q.w * nq.w; + const float sqx = q.x * nq.x; + const float sqy = q.y * nq.y; + const float sqz = q.z * nq.z; + + const float xy = q.x * nq.y; + const float zw = q.z * nq.w; + const float xz = q.x * nq.z; + const float yw = q.y * nq.w; + const float yz = q.y * nq.z; + const float xw = q.x * nq.w; + + m0.x = ( sqx - sqy - sqz + sqw ); + m0.y = 2.0f * ( xy - zw ); + m0.z = 2.0f * ( xz + yw ); + + m1.x = 2.0f * ( xy + zw ); + m1.y = ( -sqx + sqy - sqz + sqw ); + m1.z = 2.0f * ( yz - xw ); + + m2.x = 2.0f * ( xz - yw ); + m2.y = 2.0f * ( yz + xw ); + m2.z = ( -sqx - sqy + sqz + sqw ); + + m0.w = m0.x * srt.pvx + m0.y * srt.pvy + m0.z * srt.pvz + srt.tx; + m1.w = m1.x * srt.pvx + m1.y * srt.pvy + m1.z * srt.pvz + srt.ty; + m2.w = m2.x * srt.pvx + m2.y * srt.pvy + m2.z * srt.pvz + srt.tz; + + m0.z = m0.x * srt.b + m0.y * srt.c + m0.z * srt.sz; + m1.z = m1.x * srt.b + m1.y * srt.c + m1.z * srt.sz; + m2.z = m2.x * srt.b + m2.y * srt.c + m2.z * srt.sz; + + m0.y = m0.x * srt.a + m0.y * srt.sy; + m1.y = m1.x * srt.a + m1.y * srt.sy; + m2.y = m2.x * srt.a + m2.y * srt.sy; + + m0.x = m0.x * srt.sx; + m1.x = m1.x * srt.sx; + m2.x = m2.x * srt.sx; +} + +// Inverts a 3x4 matrix in place +static __forceinline__ __device__ void optixInvertMatrix( float4& m0, float4& m1, float4& m2 ) +{ + const float det3 = + m0.x * ( m1.y * m2.z - m1.z * m2.y ) - m0.y * ( m1.x * m2.z - m1.z * m2.x ) + m0.z * ( m1.x * m2.y - m1.y * m2.x ); + + const float inv_det3 = 1.0f / det3; + + float inv3[3][3]; + inv3[0][0] = inv_det3 * ( m1.y * m2.z - m2.y * m1.z ); + inv3[0][1] = inv_det3 * ( m0.z * m2.y - m2.z * m0.y ); + inv3[0][2] = inv_det3 * ( m0.y * m1.z - m1.y * m0.z ); + + inv3[1][0] = inv_det3 * ( m1.z * m2.x - m2.z * m1.x ); + inv3[1][1] = inv_det3 * ( m0.x * m2.z - m2.x * m0.z ); + inv3[1][2] = inv_det3 * ( m0.z * m1.x - m1.z * m0.x ); + + inv3[2][0] = inv_det3 * ( m1.x * m2.y - m2.x * m1.y ); + inv3[2][1] = inv_det3 * ( m0.y * m2.x - m2.y * m0.x ); + inv3[2][2] = inv_det3 * ( m0.x * m1.y - m1.x * m0.y ); + + const float b[3] = {m0.w, m1.w, m2.w}; + + m0.x = inv3[0][0]; + m0.y = inv3[0][1]; + m0.z = inv3[0][2]; + m0.w = -inv3[0][0] * b[0] - inv3[0][1] * b[1] - inv3[0][2] * b[2]; + + m1.x = inv3[1][0]; + m1.y = inv3[1][1]; + m1.z = inv3[1][2]; + m1.w = -inv3[1][0] * b[0] - inv3[1][1] * b[1] - inv3[1][2] * b[2]; + + m2.x = inv3[2][0]; + m2.y = inv3[2][1]; + m2.z = inv3[2][2]; + m2.w = -inv3[2][0] * b[0] - inv3[2][1] * b[1] - inv3[2][2] * b[2]; +} + +static __forceinline__ __device__ void optixLoadInterpolatedMatrixKey( float4& m0, float4& m1, float4& m2, const float4* matrix, const float t1 ) +{ + m0 = optixLoadReadOnlyAlign16( &matrix[0] ); + m1 = optixLoadReadOnlyAlign16( &matrix[1] ); + m2 = optixLoadReadOnlyAlign16( &matrix[2] ); + + // The conditional prevents concurrent loads leading to spills + if( t1 > 0.0f ) + { + const float t0 = 1.0f - t1; + m0 = optixAddFloat4( optixMulFloat4( m0, t0 ), optixMulFloat4( optixLoadReadOnlyAlign16( &matrix[3] ), t1 ) ); + m1 = optixAddFloat4( optixMulFloat4( m1, t0 ), optixMulFloat4( optixLoadReadOnlyAlign16( &matrix[4] ), t1 ) ); + m2 = optixAddFloat4( optixMulFloat4( m2, t0 ), optixMulFloat4( optixLoadReadOnlyAlign16( &matrix[5] ), t1 ) ); + } +} + +static __forceinline__ __device__ void optixLoadInterpolatedSrtKey( float4& srt0, + float4& srt1, + float4& srt2, + float4& srt3, + const float4* srt, + const float t1 ) +{ + srt0 = optixLoadReadOnlyAlign16( &srt[0] ); + srt1 = optixLoadReadOnlyAlign16( &srt[1] ); + srt2 = optixLoadReadOnlyAlign16( &srt[2] ); + srt3 = optixLoadReadOnlyAlign16( &srt[3] ); + + // The conditional prevents concurrent loads leading to spills + if( t1 > 0.0f ) + { + const float t0 = 1.0f - t1; + srt0 = optixAddFloat4( optixMulFloat4( srt0, t0 ), optixMulFloat4( optixLoadReadOnlyAlign16( &srt[4] ), t1 ) ); + srt1 = optixAddFloat4( optixMulFloat4( srt1, t0 ), optixMulFloat4( optixLoadReadOnlyAlign16( &srt[5] ), t1 ) ); + srt2 = optixAddFloat4( optixMulFloat4( srt2, t0 ), optixMulFloat4( optixLoadReadOnlyAlign16( &srt[6] ), t1 ) ); + srt3 = optixAddFloat4( optixMulFloat4( srt3, t0 ), optixMulFloat4( optixLoadReadOnlyAlign16( &srt[7] ), t1 ) ); + + float inv_length = 1.f / sqrt( srt2.y * srt2.y + srt2.z * srt2.z + srt2.w * srt2.w + srt3.x * srt3.x ); + srt2.y *= inv_length; + srt2.z *= inv_length; + srt2.w *= inv_length; + srt3.x *= inv_length; + } +} + +static __forceinline__ __device__ void optixResolveMotionKey( float& localt, int& key, const OptixMotionOptions& options, const float globalt ) +{ + const float timeBegin = options.timeBegin; + const float timeEnd = options.timeEnd; + const float numIntervals = (float)( options.numKeys - 1 ); + + // No need to check the motion flags. If data originates from a valid transform list handle, then globalt is in + // range, or vanish flags are not set. + + const float time = max( 0.f, min( numIntervals, ( globalt - timeBegin ) * numIntervals / ( timeEnd - timeBegin ) ) ); + const float fltKey = floorf( time ); + + localt = time - fltKey; + key = (int)fltKey; +} + +// Returns the interpolated transformation matrix for a particular matrix motion transformation and point in time. +static __forceinline__ __device__ void optixGetInterpolatedTransformation( float4& trf0, + float4& trf1, + float4& trf2, + const OptixMatrixMotionTransform* transformData, + const float time ) +{ + // Compute key and intra key time + float keyTime; + int key; + optixResolveMotionKey( keyTime, key, optixLoadReadOnlyAlign16( transformData ).motionOptions, time ); + + // Get pointer to left key + const float4* transform = (const float4*)( &transformData->transform[key][0] ); + + // Load and interpolate matrix keys + optixLoadInterpolatedMatrixKey( trf0, trf1, trf2, transform, keyTime ); +} + +// Returns the interpolated transformation matrix for a particular SRT motion transformation and point in time. +static __forceinline__ __device__ void optixGetInterpolatedTransformation( float4& trf0, + float4& trf1, + float4& trf2, + const OptixSRTMotionTransform* transformData, + const float time ) +{ + // Compute key and intra key time + float keyTime; + int key; + optixResolveMotionKey( keyTime, key, optixLoadReadOnlyAlign16( transformData ).motionOptions, time ); + + // Get pointer to left key + const float4* dataPtr = reinterpret_cast( &transformData->srtData[key] ); + + // Load and interpolated SRT keys + float4 data[4]; + optixLoadInterpolatedSrtKey( data[0], data[1], data[2], data[3], dataPtr, keyTime ); + + OptixSRTData srt = {data[0].x, data[0].y, data[0].z, data[0].w, data[1].x, data[1].y, data[1].z, data[1].w, + data[2].x, data[2].y, data[2].z, data[2].w, data[3].x, data[3].y, data[3].z, data[3].w}; + + // Convert SRT into a matrix + optixGetMatrixFromSrt( trf0, trf1, trf2, srt ); +} + +// Returns the interpolated transformation matrix for a particular traversable handle and point in time. +static __forceinline__ __device__ void optixGetInterpolatedTransformationFromHandle( float4& trf0, + float4& trf1, + float4& trf2, + const OptixTraversableHandle handle, + const float time, + const bool objectToWorld ) +{ + const OptixTransformType type = optixGetTransformTypeFromHandle( handle ); + + if( type == OPTIX_TRANSFORM_TYPE_MATRIX_MOTION_TRANSFORM || type == OPTIX_TRANSFORM_TYPE_SRT_MOTION_TRANSFORM ) + { + if( type == OPTIX_TRANSFORM_TYPE_MATRIX_MOTION_TRANSFORM ) + { + const OptixMatrixMotionTransform* transformData = optixGetMatrixMotionTransformFromHandle( handle ); + optixGetInterpolatedTransformation( trf0, trf1, trf2, transformData, time ); + } + else + { + const OptixSRTMotionTransform* transformData = optixGetSRTMotionTransformFromHandle( handle ); + optixGetInterpolatedTransformation( trf0, trf1, trf2, transformData, time ); + } + + if( !objectToWorld ) + optixInvertMatrix( trf0, trf1, trf2 ); + } + else if( type == OPTIX_TRANSFORM_TYPE_INSTANCE || type == OPTIX_TRANSFORM_TYPE_STATIC_TRANSFORM ) + { + const float4* transform; + + if( type == OPTIX_TRANSFORM_TYPE_INSTANCE ) + { + transform = ( objectToWorld ) ? optixGetInstanceTransformFromHandle( handle ) : + optixGetInstanceInverseTransformFromHandle( handle ); + } + else + { + const OptixStaticTransform* traversable = optixGetStaticTransformFromHandle( handle ); + transform = (const float4*)( ( objectToWorld ) ? traversable->transform : traversable->invTransform ); + } + + trf0 = optixLoadReadOnlyAlign16( &transform[0] ); + trf1 = optixLoadReadOnlyAlign16( &transform[1] ); + trf2 = optixLoadReadOnlyAlign16( &transform[2] ); + } + else + { + trf0 = {1.0f, 0.0f, 0.0f, 0.0f}; + trf1 = {0.0f, 1.0f, 0.0f, 0.0f}; + trf2 = {0.0f, 0.0f, 1.0f, 0.0f}; + } +} + +// Returns the world-to-object transformation matrix resulting from the current transform stack and current ray time. +static __forceinline__ __device__ void optixGetWorldToObjectTransformMatrix( float4& m0, float4& m1, float4& m2 ) +{ + const unsigned int size = optixGetTransformListSize(); + const float time = optixGetRayTime(); + +#pragma unroll 1 + for( unsigned int i = 0; i < size; ++i ) + { + OptixTraversableHandle handle = optixGetTransformListHandle( i ); + + float4 trf0, trf1, trf2; + optixGetInterpolatedTransformationFromHandle( trf0, trf1, trf2, handle, time, /*objectToWorld*/ false ); + + if( i == 0 ) + { + m0 = trf0; + m1 = trf1; + m2 = trf2; + } + else + { + // m := trf * m + float4 tmp0 = m0, tmp1 = m1, tmp2 = m2; + m0 = optixMultiplyRowMatrix( trf0, tmp0, tmp1, tmp2 ); + m1 = optixMultiplyRowMatrix( trf1, tmp0, tmp1, tmp2 ); + m2 = optixMultiplyRowMatrix( trf2, tmp0, tmp1, tmp2 ); + } + } +} + +// Returns the object-to-world transformation matrix resulting from the current transform stack and current ray time. +static __forceinline__ __device__ void optixGetObjectToWorldTransformMatrix( float4& m0, float4& m1, float4& m2 ) +{ + const int size = optixGetTransformListSize(); + const float time = optixGetRayTime(); + +#pragma unroll 1 + for( int i = size - 1; i >= 0; --i ) + { + OptixTraversableHandle handle = optixGetTransformListHandle( i ); + + float4 trf0, trf1, trf2; + optixGetInterpolatedTransformationFromHandle( trf0, trf1, trf2, handle, time, /*objectToWorld*/ true ); + + if( i == size - 1 ) + { + m0 = trf0; + m1 = trf1; + m2 = trf2; + } + else + { + // m := trf * m + float4 tmp0 = m0, tmp1 = m1, tmp2 = m2; + m0 = optixMultiplyRowMatrix( trf0, tmp0, tmp1, tmp2 ); + m1 = optixMultiplyRowMatrix( trf1, tmp0, tmp1, tmp2 ); + m2 = optixMultiplyRowMatrix( trf2, tmp0, tmp1, tmp2 ); + } + } +} + +// Multiplies the 3x4 matrix with rows m0, m1, m2 with the point p. +static __forceinline__ __device__ float3 optixTransformPoint( const float4& m0, const float4& m1, const float4& m2, const float3& p ) +{ + float3 result; + result.x = m0.x * p.x + m0.y * p.y + m0.z * p.z + m0.w; + result.y = m1.x * p.x + m1.y * p.y + m1.z * p.z + m1.w; + result.z = m2.x * p.x + m2.y * p.y + m2.z * p.z + m2.w; + return result; +} + +// Multiplies the 3x3 linear submatrix of the 3x4 matrix with rows m0, m1, m2 with the vector v. +static __forceinline__ __device__ float3 optixTransformVector( const float4& m0, const float4& m1, const float4& m2, const float3& v ) +{ + float3 result; + result.x = m0.x * v.x + m0.y * v.y + m0.z * v.z; + result.y = m1.x * v.x + m1.y * v.y + m1.z * v.z; + result.z = m2.x * v.x + m2.y * v.y + m2.z * v.z; + return result; +} + +// Multiplies the transpose of the 3x3 linear submatrix of the 3x4 matrix with rows m0, m1, m2 with the normal n. +// Note that the given matrix is supposed to be the inverse of the actual transformation matrix. +static __forceinline__ __device__ float3 optixTransformNormal( const float4& m0, const float4& m1, const float4& m2, const float3& n ) +{ + float3 result; + result.x = m0.x * n.x + m1.x * n.y + m2.x * n.z; + result.y = m0.y * n.x + m1.y * n.y + m2.y * n.z; + result.z = m0.z * n.x + m1.z * n.y + m2.z * n.z; + return result; +} + +} // namespace optix_impl + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix.h new file mode 100644 index 00000000..68ff6fa2 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix.h @@ -0,0 +1,38 @@ + +/* +* SPDX-FileCopyrightText: Copyright (c) 2009 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* SPDX-License-Identifier: LicenseRef-NvidiaProprietary +* +* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +* property and proprietary rights in and to this material, related +* documentation and any modifications thereto. Any use, reproduction, +* disclosure or distribution of this material and related documentation +* without an express license agreement from NVIDIA CORPORATION or +* its affiliates is strictly prohibited. +*/ +/// @file +/// @author NVIDIA Corporation +/// @brief OptiX public API header +/// +/// Includes the host api if compiling host code, includes the cuda api if compiling device code. +/// For the math library routines include optix_math.h + +#ifndef __optix_optix_h__ +#define __optix_optix_h__ + +/// The OptiX version. +/// +/// - major = OPTIX_VERSION/10000 +/// - minor = (OPTIX_VERSION%10000)/100 +/// - micro = OPTIX_VERSION%100 +#define OPTIX_VERSION 70500 + + +#ifdef __CUDACC__ +#include "optix_device.h" +#else +#include "optix_host.h" +#endif + + +#endif // __optix_optix_h__ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_7_device.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_7_device.h new file mode 100644 index 00000000..061f3c53 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_7_device.h @@ -0,0 +1,999 @@ +/* +* SPDX-FileCopyrightText: Copyright (c) 2010 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* SPDX-License-Identifier: LicenseRef-NvidiaProprietary +* +* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +* property and proprietary rights in and to this material, related +* documentation and any modifications thereto. Any use, reproduction, +* disclosure or distribution of this material and related documentation +* without an express license agreement from NVIDIA CORPORATION or +* its affiliates is strictly prohibited. +*/ +/// @file +/// @author NVIDIA Corporation +/// @brief OptiX public API header +/// +/// OptiX public API Reference - Device API declarations + +#if !defined( __OPTIX_INCLUDE_INTERNAL_HEADERS__ ) +#error("optix_7_device.h is an internal header file and must not be used directly. Please use optix_device.h or optix.h instead.") +#endif + + +#ifndef __optix_optix_7_device_h__ +#define __optix_optix_7_device_h__ + +#if defined( __cplusplus ) && ( __cplusplus < 201103L ) && !defined( _WIN32 ) +#error Device code for OptiX requires at least C++11. Consider adding "--std c++11" to the nvcc command-line. +#endif + +#include "optix_7_types.h" + +/// \defgroup optix_device_api Device API +/// \brief OptiX Device API + +/** \addtogroup optix_device_api +@{ +*/ + +/// Initiates a ray tracing query starting with the given traversable. +/// +/// \param[in] handle +/// \param[in] rayOrigin +/// \param[in] rayDirection +/// \param[in] tmin +/// \param[in] tmax +/// \param[in] rayTime +/// \param[in] visibilityMask really only 8 bits +/// \param[in] rayFlags really only 8 bits, combination of OptixRayFlags +/// \param[in] SBToffset really only 8 bits +/// \param[in] SBTstride really only 8 bits +/// \param[in] missSBTIndex specifies the miss program invoked on a miss +/// \param[out] payload up to 32 unsigned int values that hold the payload +template +static __forceinline__ __device__ void optixTrace( OptixTraversableHandle handle, + float3 rayOrigin, + float3 rayDirection, + float tmin, + float tmax, + float rayTime, + OptixVisibilityMask visibilityMask, + unsigned int rayFlags, + unsigned int SBToffset, + unsigned int SBTstride, + unsigned int missSBTIndex, + Payload&... payload ); + +/// Initiates a ray tracing query starting with the given traversable. +/// +/// \param[in] type +/// \param[in] handle +/// \param[in] rayOrigin +/// \param[in] rayDirection +/// \param[in] tmin +/// \param[in] tmax +/// \param[in] rayTime +/// \param[in] visibilityMask really only 8 bits +/// \param[in] rayFlags really only 8 bits, combination of OptixRayFlags +/// \param[in] SBToffset really only 8 bits +/// \param[in] SBTstride really only 8 bits +/// \param[in] missSBTIndex specifies the miss program invoked on a miss +/// \param[out] payload up to 32 unsigned int values that hold the payload +template +static __forceinline__ __device__ void optixTrace( OptixPayloadTypeID type, + OptixTraversableHandle handle, + float3 rayOrigin, + float3 rayDirection, + float tmin, + float tmax, + float rayTime, + OptixVisibilityMask visibilityMask, + unsigned int rayFlags, + unsigned int SBToffset, + unsigned int SBTstride, + unsigned int missSBTIndex, + Payload&... payload ); + +/// Writes the 32-bit payload value at slot 0. +static __forceinline__ __device__ void optixSetPayload_0( unsigned int p ); +/// Writes the 32-bit payload value at slot 1. +static __forceinline__ __device__ void optixSetPayload_1( unsigned int p ); +/// Writes the 32-bit payload value at slot 2. +static __forceinline__ __device__ void optixSetPayload_2( unsigned int p ); +/// Writes the 32-bit payload value at slot 3. +static __forceinline__ __device__ void optixSetPayload_3( unsigned int p ); +/// Writes the 32-bit payload value at slot 4. +static __forceinline__ __device__ void optixSetPayload_4( unsigned int p ); +/// Writes the 32-bit payload value at slot 5. +static __forceinline__ __device__ void optixSetPayload_5( unsigned int p ); +/// Writes the 32-bit payload value at slot 6. +static __forceinline__ __device__ void optixSetPayload_6( unsigned int p ); +/// Writes the 32-bit payload value at slot 7. +static __forceinline__ __device__ void optixSetPayload_7( unsigned int p ); + +/// Writes the 32-bit payload value at slot 8. +static __forceinline__ __device__ void optixSetPayload_8( unsigned int p ); +/// Writes the 32-bit payload value at slot 9. +static __forceinline__ __device__ void optixSetPayload_9( unsigned int p ); +/// Writes the 32-bit payload value at slot 10. +static __forceinline__ __device__ void optixSetPayload_10( unsigned int p ); +/// Writes the 32-bit payload value at slot 11. +static __forceinline__ __device__ void optixSetPayload_11( unsigned int p ); +/// Writes the 32-bit payload value at slot 12. +static __forceinline__ __device__ void optixSetPayload_12( unsigned int p ); +/// Writes the 32-bit payload value at slot 13. +static __forceinline__ __device__ void optixSetPayload_13( unsigned int p ); +/// Writes the 32-bit payload value at slot 14. +static __forceinline__ __device__ void optixSetPayload_14( unsigned int p ); +/// Writes the 32-bit payload value at slot 15. +static __forceinline__ __device__ void optixSetPayload_15( unsigned int p ); +/// Writes the 32-bit payload value at slot 16. +static __forceinline__ __device__ void optixSetPayload_16( unsigned int p ); +/// Writes the 32-bit payload value at slot 17. +static __forceinline__ __device__ void optixSetPayload_17( unsigned int p ); +/// Writes the 32-bit payload value at slot 18. +static __forceinline__ __device__ void optixSetPayload_18( unsigned int p ); +/// Writes the 32-bit payload value at slot 19. +static __forceinline__ __device__ void optixSetPayload_19( unsigned int p ); +/// Writes the 32-bit payload value at slot 20. +static __forceinline__ __device__ void optixSetPayload_20( unsigned int p ); +/// Writes the 32-bit payload value at slot 21. +static __forceinline__ __device__ void optixSetPayload_21( unsigned int p ); +/// Writes the 32-bit payload value at slot 22. +static __forceinline__ __device__ void optixSetPayload_22( unsigned int p ); +/// Writes the 32-bit payload value at slot 23. +static __forceinline__ __device__ void optixSetPayload_23( unsigned int p ); +/// Writes the 32-bit payload value at slot 24. +static __forceinline__ __device__ void optixSetPayload_24( unsigned int p ); +/// Writes the 32-bit payload value at slot 25. +static __forceinline__ __device__ void optixSetPayload_25( unsigned int p ); +/// Writes the 32-bit payload value at slot 26. +static __forceinline__ __device__ void optixSetPayload_26( unsigned int p ); +/// Writes the 32-bit payload value at slot 27. +static __forceinline__ __device__ void optixSetPayload_27( unsigned int p ); +/// Writes the 32-bit payload value at slot 28. +static __forceinline__ __device__ void optixSetPayload_28( unsigned int p ); +/// Writes the 32-bit payload value at slot 29. +static __forceinline__ __device__ void optixSetPayload_29( unsigned int p ); +/// Writes the 32-bit payload value at slot 30. +static __forceinline__ __device__ void optixSetPayload_30( unsigned int p ); +/// Writes the 32-bit payload value at slot 31. +static __forceinline__ __device__ void optixSetPayload_31( unsigned int p ); + +/// Reads the 32-bit payload value at slot 0. +static __forceinline__ __device__ unsigned int optixGetPayload_0(); +/// Reads the 32-bit payload value at slot 1. +static __forceinline__ __device__ unsigned int optixGetPayload_1(); +/// Reads the 32-bit payload value at slot 2. +static __forceinline__ __device__ unsigned int optixGetPayload_2(); +/// Reads the 32-bit payload value at slot 3. +static __forceinline__ __device__ unsigned int optixGetPayload_3(); +/// Reads the 32-bit payload value at slot 4. +static __forceinline__ __device__ unsigned int optixGetPayload_4(); +/// Reads the 32-bit payload value at slot 5. +static __forceinline__ __device__ unsigned int optixGetPayload_5(); +/// Reads the 32-bit payload value at slot 6. +static __forceinline__ __device__ unsigned int optixGetPayload_6(); +/// Reads the 32-bit payload value at slot 7. +static __forceinline__ __device__ unsigned int optixGetPayload_7(); + +/// Reads the 32-bit payload value at slot 8. +static __forceinline__ __device__ unsigned int optixGetPayload_8(); +/// Reads the 32-bit payload value at slot 9. +static __forceinline__ __device__ unsigned int optixGetPayload_9(); +/// Reads the 32-bit payload value at slot 10. +static __forceinline__ __device__ unsigned int optixGetPayload_10(); +/// Reads the 32-bit payload value at slot 11. +static __forceinline__ __device__ unsigned int optixGetPayload_11(); +/// Reads the 32-bit payload value at slot 12. +static __forceinline__ __device__ unsigned int optixGetPayload_12(); +/// Reads the 32-bit payload value at slot 13. +static __forceinline__ __device__ unsigned int optixGetPayload_13(); +/// Reads the 32-bit payload value at slot 14. +static __forceinline__ __device__ unsigned int optixGetPayload_14(); +/// Reads the 32-bit payload value at slot 15. +static __forceinline__ __device__ unsigned int optixGetPayload_15(); +/// Reads the 32-bit payload value at slot 16. +static __forceinline__ __device__ unsigned int optixGetPayload_16(); +/// Reads the 32-bit payload value at slot 17. +static __forceinline__ __device__ unsigned int optixGetPayload_17(); +/// Reads the 32-bit payload value at slot 18. +static __forceinline__ __device__ unsigned int optixGetPayload_18(); +/// Reads the 32-bit payload value at slot 19. +static __forceinline__ __device__ unsigned int optixGetPayload_19(); +/// Reads the 32-bit payload value at slot 20. +static __forceinline__ __device__ unsigned int optixGetPayload_20(); +/// Reads the 32-bit payload value at slot 21. +static __forceinline__ __device__ unsigned int optixGetPayload_21(); +/// Reads the 32-bit payload value at slot 22. +static __forceinline__ __device__ unsigned int optixGetPayload_22(); +/// Reads the 32-bit payload value at slot 23. +static __forceinline__ __device__ unsigned int optixGetPayload_23(); +/// Reads the 32-bit payload value at slot 24. +static __forceinline__ __device__ unsigned int optixGetPayload_24(); +/// Reads the 32-bit payload value at slot 25. +static __forceinline__ __device__ unsigned int optixGetPayload_25(); +/// Reads the 32-bit payload value at slot 26. +static __forceinline__ __device__ unsigned int optixGetPayload_26(); +/// Reads the 32-bit payload value at slot 27. +static __forceinline__ __device__ unsigned int optixGetPayload_27(); +/// Reads the 32-bit payload value at slot 28. +static __forceinline__ __device__ unsigned int optixGetPayload_28(); +/// Reads the 32-bit payload value at slot 29. +static __forceinline__ __device__ unsigned int optixGetPayload_29(); +/// Reads the 32-bit payload value at slot 30. +static __forceinline__ __device__ unsigned int optixGetPayload_30(); +/// Reads the 32-bit payload value at slot 31. +static __forceinline__ __device__ unsigned int optixGetPayload_31(); + +/// Specify the supported payload types for a program. +/// +/// The supported types are specified as a bitwise combination of payload types. (See OptixPayloadTypeID) +/// May only be called once per program. +/// Must be called at the top of the program. +/// Only available in IS, AH, CH, MS +static __forceinline__ __device__ void optixSetPayloadTypes( unsigned int typeMask ); + +/// Returns an undefined value. +static __forceinline__ __device__ unsigned int optixUndefinedValue(); + +/// Returns the rayOrigin passed into optixTrace. +/// +/// May be more expensive to call in IS and AH than their object space counterparts, +/// so effort should be made to use the object space ray in those programs. +/// Only available in IS, AH, CH, MS +static __forceinline__ __device__ float3 optixGetWorldRayOrigin(); + +/// Returns the rayDirection passed into optixTrace. +/// +/// May be more expensive to call in IS and AH than their object space counterparts, +/// so effort should be made to use the object space ray in those programs. +/// Only available in IS, AH, CH, MS +static __forceinline__ __device__ float3 optixGetWorldRayDirection(); + +/// Returns the current object space ray origin based on the current transform stack. +/// +/// Only available in IS and AH. +static __forceinline__ __device__ float3 optixGetObjectRayOrigin(); + +/// Returns the current object space ray direction based on the current transform stack. +/// +/// Only available in IS and AH. +static __forceinline__ __device__ float3 optixGetObjectRayDirection(); + +/// Returns the tmin passed into optixTrace. +/// +/// Only available in IS, AH, CH, MS +static __forceinline__ __device__ float optixGetRayTmin(); + +/// In IS and CH returns the current smallest reported hitT or the tmax passed into optixTrace if no hit has been reported +/// In AH returns the hitT value as passed in to optixReportIntersection +/// In MS returns the tmax passed into optixTrace +/// Only available in IS, AH, CH, MS +static __forceinline__ __device__ float optixGetRayTmax(); + +/// Returns the rayTime passed into optixTrace. +/// +/// Will return 0 if motion is disabled. +/// Only available in IS, AH, CH, MS +static __forceinline__ __device__ float optixGetRayTime(); + +/// Returns the rayFlags passed into optixTrace +/// +/// Only available in IS, AH, CH, MS +static __forceinline__ __device__ unsigned int optixGetRayFlags(); + +/// Returns the visibilityMask passed into optixTrace +/// +/// Only available in IS, AH, CH, MS +static __forceinline__ __device__ unsigned int optixGetRayVisibilityMask(); + +/// Return the traversable handle of a given instance in an Instance +/// Acceleration Structure (IAS) +static __forceinline__ __device__ OptixTraversableHandle optixGetInstanceTraversableFromIAS( OptixTraversableHandle ias, unsigned int instIdx ); + +/// Return the object space triangle vertex positions of a given triangle in a Geometry +/// Acceleration Structure (GAS) at a given motion time. +/// To access vertex data, the GAS must be built using the flag OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS. +/// +/// If motion is disabled via OptixPipelineCompileOptions::usesMotionBlur, or the GAS does not contain motion, the +/// time parameter is ignored. +static __forceinline__ __device__ void optixGetTriangleVertexData( OptixTraversableHandle gas, unsigned int primIdx, unsigned int sbtGASIndex, float time, float3 data[3]); + +/// Return the object space curve control vertex data of a linear curve in a Geometry +/// Acceleration Structure (GAS) at a given motion time. +/// To access vertex data, the GAS must be built using the flag OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS. +/// +/// data[i] = {x,y,z,w} with {x,y,z} the position and w the radius of control vertex i. +/// If motion is disabled via OptixPipelineCompileOptions::usesMotionBlur, or the GAS does not contain motion, the +/// time parameter is ignored. +static __forceinline__ __device__ void optixGetLinearCurveVertexData( OptixTraversableHandle gas, unsigned int primIdx, unsigned int sbtGASIndex, float time, float4 data[2] ); + +/// Return the object space curve control vertex data of a quadratic BSpline curve in a Geometry +/// Acceleration Structure (GAS) at a given motion time. +/// To access vertex data, the GAS must be built using the flag OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS. +/// +/// data[i] = {x,y,z,w} with {x,y,z} the position and w the radius of control vertex i. +/// If motion is disabled via OptixPipelineCompileOptions::usesMotionBlur, or the GAS does not contain motion, the +/// time parameter is ignored. +static __forceinline__ __device__ void optixGetQuadraticBSplineVertexData( OptixTraversableHandle gas, unsigned int primIdx, unsigned int sbtGASIndex, float time, float4 data[3] ); + +/// Return the object space curve control vertex data of a cubic BSpline curve in a Geometry +/// Acceleration Structure (GAS) at a given motion time. +/// To access vertex data, the GAS must be built using the flag OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS. +/// +/// data[i] = {x,y,z,w} with {x,y,z} the position and w the radius of control vertex i. +/// If motion is disabled via OptixPipelineCompileOptions::usesMotionBlur, or the GAS does not contain motion, the +/// time parameter is ignored. +static __forceinline__ __device__ void optixGetCubicBSplineVertexData( OptixTraversableHandle gas, unsigned int primIdx, unsigned int sbtGASIndex, float time, float4 data[4] ); + +/// Return the object space curve control vertex data of a CatmullRom spline curve in a Geometry +/// Acceleration Structure (GAS) at a given motion time. +/// To access vertex data, the GAS must be built using the flag OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS. +/// +/// data[i] = {x,y,z,w} with {x,y,z} the position and w the radius of control vertex i. +/// If motion is disabled via OptixPipelineCompileOptions::usesMotionBlur, or the GAS does not contain motion, the +/// time parameter is ignored. +static __forceinline__ __device__ void optixGetCatmullRomVertexData( OptixTraversableHandle gas, unsigned int primIdx, unsigned int sbtGASIndex, float time, float4 data[4] ); + +/// Return the object space sphere data, center point and radius, in a Geometry Acceleration Structure (GAS) at a given motion time. +/// To access sphere data, the GAS must be built using the flag OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS. +/// +/// data[0] = {x,y,z,w} with {x,y,z} the position of the sphere center and w the radius. +/// If motion is disabled via OptixPipelineCompileOptions::usesMotionBlur, or the GAS does not contain motion, the +/// time parameter is ignored. +static __forceinline__ __device__ void optixGetSphereData( OptixTraversableHandle gas, unsigned int primIdx, unsigned int sbtGASIndex, float time, float4 data[1] ); + +/// Returns the traversable handle for the Geometry Acceleration Structure (GAS) containing +/// the current hit. May be called from IS, AH and CH. +static __forceinline__ __device__ OptixTraversableHandle optixGetGASTraversableHandle(); + +/// Returns the motion begin time of a GAS (see OptixMotionOptions) +static __forceinline__ __device__ float optixGetGASMotionTimeBegin( OptixTraversableHandle gas ); + +/// Returns the motion end time of a GAS (see OptixMotionOptions) +static __forceinline__ __device__ float optixGetGASMotionTimeEnd( OptixTraversableHandle gas ); + +/// Returns the number of motion steps of a GAS (see OptixMotionOptions) +static __forceinline__ __device__ unsigned int optixGetGASMotionStepCount( OptixTraversableHandle gas ); + +/// Returns the world-to-object transformation matrix resulting from the current active transformation list. +/// +/// The cost of this function may be proportional to the size of the transformation list. +static __forceinline__ __device__ void optixGetWorldToObjectTransformMatrix( float m[12] ); + +/// Returns the object-to-world transformation matrix resulting from the current active transformation list. +/// +/// The cost of this function may be proportional to the size of the transformation list. +static __forceinline__ __device__ void optixGetObjectToWorldTransformMatrix( float m[12] ); + +/// Transforms the point using world-to-object transformation matrix resulting from the current active transformation +/// list. +/// +/// The cost of this function may be proportional to the size of the transformation list. +static __forceinline__ __device__ float3 optixTransformPointFromWorldToObjectSpace( float3 point ); + +/// Transforms the vector using world-to-object transformation matrix resulting from the current active transformation +/// list. +/// +/// The cost of this function may be proportional to the size of the transformation list. +static __forceinline__ __device__ float3 optixTransformVectorFromWorldToObjectSpace( float3 vec ); + +/// Transforms the normal using world-to-object transformation matrix resulting from the current active transformation +/// list. +/// +/// The cost of this function may be proportional to the size of the transformation list. +static __forceinline__ __device__ float3 optixTransformNormalFromWorldToObjectSpace( float3 normal ); + +/// Transforms the point using object-to-world transformation matrix resulting from the current active transformation +/// list. +/// +/// The cost of this function may be proportional to the size of the transformation list. +static __forceinline__ __device__ float3 optixTransformPointFromObjectToWorldSpace( float3 point ); + +/// Transforms the vector using object-to-world transformation matrix resulting from the current active transformation +/// list. +/// +/// The cost of this function may be proportional to the size of the transformation list. +static __forceinline__ __device__ float3 optixTransformVectorFromObjectToWorldSpace( float3 vec ); + +/// Transforms the normal using object-to-world transformation matrix resulting from the current active transformation +/// list. +/// +/// The cost of this function may be proportional to the size of the transformation list. +static __forceinline__ __device__ float3 optixTransformNormalFromObjectToWorldSpace( float3 normal ); + +/// Returns the number of transforms on the current transform list. +/// +/// Only available in IS, AH, CH, EX +static __forceinline__ __device__ unsigned int optixGetTransformListSize(); + +/// Returns the traversable handle for a transform on the current transform list. +/// +/// Only available in IS, AH, CH, EX +static __forceinline__ __device__ OptixTraversableHandle optixGetTransformListHandle( unsigned int index ); + + +/// Returns the transform type of a traversable handle from a transform list. +static __forceinline__ __device__ OptixTransformType optixGetTransformTypeFromHandle( OptixTraversableHandle handle ); + +/// Returns a pointer to a OptixStaticTransform from its traversable handle. +/// +/// Returns 0 if the traversable is not of type OPTIX_TRANSFORM_TYPE_STATIC_TRANSFORM. +static __forceinline__ __device__ const OptixStaticTransform* optixGetStaticTransformFromHandle( OptixTraversableHandle handle ); + +/// Returns a pointer to a OptixSRTMotionTransform from its traversable handle. +/// +/// Returns 0 if the traversable is not of type OPTIX_TRANSFORM_TYPE_SRT_MOTION_TRANSFORM. +static __forceinline__ __device__ const OptixSRTMotionTransform* optixGetSRTMotionTransformFromHandle( OptixTraversableHandle handle ); + +/// Returns a pointer to a OptixMatrixMotionTransform from its traversable handle. +/// +/// Returns 0 if the traversable is not of type OPTIX_TRANSFORM_TYPE_MATRIX_MOTION_TRANSFORM. +static __forceinline__ __device__ const OptixMatrixMotionTransform* optixGetMatrixMotionTransformFromHandle( OptixTraversableHandle handle ); + +/// Returns instanceId from an OptixInstance traversable. +/// +/// Returns 0 if the traversable handle does not reference an OptixInstance. +static __forceinline__ __device__ unsigned int optixGetInstanceIdFromHandle( OptixTraversableHandle handle ); + +/// Returns child traversable handle from an OptixInstance traversable. +/// +/// Returns 0 if the traversable handle does not reference an OptixInstance. +static __forceinline__ __device__ OptixTraversableHandle optixGetInstanceChildFromHandle( OptixTraversableHandle handle ); + +/// Returns object-to-world transform from an OptixInstance traversable. +/// +/// Returns 0 if the traversable handle does not reference an OptixInstance. +static __forceinline__ __device__ const float4* optixGetInstanceTransformFromHandle( OptixTraversableHandle handle ); + +/// Returns world-to-object transform from an OptixInstance traversable. +/// +/// Returns 0 if the traversable handle does not reference an OptixInstance. +static __forceinline__ __device__ const float4* optixGetInstanceInverseTransformFromHandle( OptixTraversableHandle handle ); + +/// Reports an intersections (overload without attributes). +/// +/// If optixGetRayTmin() <= hitT <= optixGetRayTmax(), the any hit program associated with this intersection program (via the SBT entry) is called. +/// The AH program can do one of three things: +/// 1. call optixIgnoreIntersection - no hit is recorded, optixReportIntersection returns false +/// 2. call optixTerminateRay - hit is recorded, optixReportIntersection does not return, no further traversal occurs, +/// and the associated closest hit program is called +/// 3. neither - hit is recorded, optixReportIntersection returns true +/// hitKind - Only the 7 least significant bits should be written [0..127]. Any values above 127 are reserved for built in intersection. The value can be queried with optixGetHitKind() in AH and CH. +/// +/// The attributes specified with a0..a7 are available in the AH and CH programs. +/// Note that the attributes available in the CH program correspond to the closest recorded intersection. +/// The number of attributes in registers and memory can be configured in the pipeline. +/// +/// \param[in] hitT +/// \param[in] hitKind +static __forceinline__ __device__ bool optixReportIntersection( float hitT, unsigned int hitKind ); + +/// Reports an intersection (overload with 1 attribute register). +/// +/// \see #optixReportIntersection(float,unsigned int) +static __forceinline__ __device__ bool optixReportIntersection( float hitT, unsigned int hitKind, unsigned int a0 ); + +/// Reports an intersection (overload with 2 attribute registers). +/// +/// \see #optixReportIntersection(float,unsigned int) +static __forceinline__ __device__ bool optixReportIntersection( float hitT, unsigned int hitKind, unsigned int a0, unsigned int a1 ); + +/// Reports an intersection (overload with 3 attribute registers). +/// +/// \see #optixReportIntersection(float,unsigned int) +static __forceinline__ __device__ bool optixReportIntersection( float hitT, unsigned int hitKind, unsigned int a0, unsigned int a1, unsigned int a2 ); + +/// Reports an intersection (overload with 4 attribute registers). +/// +/// \see #optixReportIntersection(float,unsigned int) +static __forceinline__ __device__ bool optixReportIntersection( float hitT, + unsigned int hitKind, + unsigned int a0, + unsigned int a1, + unsigned int a2, + unsigned int a3 ); + +/// Reports an intersection (overload with 5 attribute registers). +/// +/// \see #optixReportIntersection(float,unsigned int) +static __forceinline__ __device__ bool optixReportIntersection( float hitT, + unsigned int hitKind, + unsigned int a0, + unsigned int a1, + unsigned int a2, + unsigned int a3, + unsigned int a4 ); + +/// Reports an intersection (overload with 6 attribute registers). +/// +/// \see #optixReportIntersection(float,unsigned int) +static __forceinline__ __device__ bool optixReportIntersection( float hitT, + unsigned int hitKind, + unsigned int a0, + unsigned int a1, + unsigned int a2, + unsigned int a3, + unsigned int a4, + unsigned int a5 ); + +/// Reports an intersection (overload with 7 attribute registers). +/// +/// \see #optixReportIntersection(float,unsigned int) +static __forceinline__ __device__ bool optixReportIntersection( float hitT, + unsigned int hitKind, + unsigned int a0, + unsigned int a1, + unsigned int a2, + unsigned int a3, + unsigned int a4, + unsigned int a5, + unsigned int a6 ); + +/// Reports an intersection (overload with 8 attribute registers). +/// +/// \see #optixReportIntersection(float,unsigned int) +static __forceinline__ __device__ bool optixReportIntersection( float hitT, + unsigned int hitKind, + unsigned int a0, + unsigned int a1, + unsigned int a2, + unsigned int a3, + unsigned int a4, + unsigned int a5, + unsigned int a6, + unsigned int a7 ); + +/// Returns the attribute at slot 0. +static __forceinline__ __device__ unsigned int optixGetAttribute_0(); +/// Returns the attribute at slot 1. +static __forceinline__ __device__ unsigned int optixGetAttribute_1(); +/// Returns the attribute at slot 2. +static __forceinline__ __device__ unsigned int optixGetAttribute_2(); +/// Returns the attribute at slot 3. +static __forceinline__ __device__ unsigned int optixGetAttribute_3(); +/// Returns the attribute at slot 4. +static __forceinline__ __device__ unsigned int optixGetAttribute_4(); +/// Returns the attribute at slot 5. +static __forceinline__ __device__ unsigned int optixGetAttribute_5(); +/// Returns the attribute at slot 6. +static __forceinline__ __device__ unsigned int optixGetAttribute_6(); +/// Returns the attribute at slot 7. +static __forceinline__ __device__ unsigned int optixGetAttribute_7(); + +/// Record the hit, stops traversal, and proceeds to CH. +/// +/// Available only in AH. +static __forceinline__ __device__ void optixTerminateRay(); + +/// Discards the hit, and returns control to the calling optixReportIntersection or built-in intersection routine. +/// +/// Available only in AH. +static __forceinline__ __device__ void optixIgnoreIntersection(); + + +/// For a given OptixBuildInputTriangleArray the number of primitives is defined as +/// "(OptixBuildInputTriangleArray::indexBuffer == 0) ? OptixBuildInputTriangleArray::numVertices/3 : +/// OptixBuildInputTriangleArray::numIndexTriplets;". +/// For a given OptixBuildInputCustomPrimitiveArray the number of primitives is defined as +/// numAabbs. +/// +/// The primitive index returns the index into the array of primitives +/// plus the primitiveIndexOffset. +/// +/// In IS and AH this corresponds to the currently intersected primitive. +/// In CH this corresponds to the primitive index of the closest intersected primitive. +static __forceinline__ __device__ unsigned int optixGetPrimitiveIndex(); + +/// Returns the Sbt GAS index of the primitive associated with the current intersection. +/// +/// In IS and AH this corresponds to the currently intersected primitive. +/// In CH this corresponds to the Sbt GAS index of the closest intersected primitive. +/// In EX with exception code OPTIX_EXCEPTION_CODE_TRAVERSAL_INVALID_HIT_SBT corresponds to the sbt index within the hit GAS. Returns zero for all other exceptions. +static __forceinline__ __device__ unsigned int optixGetSbtGASIndex(); + + +/// Returns the OptixInstance::instanceId of the instance within the top level acceleration structure associated with the current intersection. +/// +/// When building an acceleration structure using OptixBuildInputInstanceArray each OptixInstance has a user supplied instanceId. +/// OptixInstance objects reference another acceleration structure. During traversal the acceleration structures are visited top down. +/// In the IS and AH programs the OptixInstance::instanceId corresponding to the most recently visited OptixInstance is returned when calling optixGetInstanceId(). +/// In CH optixGetInstanceId() returns the OptixInstance::instanceId when the hit was recorded with optixReportIntersection. +/// In the case where there is no OptixInstance visited, optixGetInstanceId returns ~0u +static __forceinline__ __device__ unsigned int optixGetInstanceId(); + +/// Returns the zero-based index of the instance within its instance acceleration structure associated with the current intersection. +/// +/// In the IS and AH programs the index corresponding to the most recently visited OptixInstance is returned when calling optixGetInstanceIndex(). +/// In CH optixGetInstanceIndex() returns the index when the hit was recorded with optixReportIntersection. +/// In the case where there is no OptixInstance visited, optixGetInstanceIndex returns 0 +static __forceinline__ __device__ unsigned int optixGetInstanceIndex(); + +/// Returns the 8 bit hit kind associated with the current hit. +/// +/// Use optixGetPrimitiveType() to interpret the hit kind. +/// For custom intersections (primitive type OPTIX_PRIMITIVE_TYPE_CUSTOM), +/// this is the 7-bit hitKind passed to optixReportIntersection(). +/// Hit kinds greater than 127 are reserved for built-in primitives. +/// +/// Available only in AH and CH. +static __forceinline__ __device__ unsigned int optixGetHitKind(); + +/// Function interpreting the result of #optixGetHitKind(). +static __forceinline__ __device__ OptixPrimitiveType optixGetPrimitiveType( unsigned int hitKind ); + +/// Function interpreting the result of #optixGetHitKind(). +static __forceinline__ __device__ bool optixIsFrontFaceHit( unsigned int hitKind ); + +/// Function interpreting the result of #optixGetHitKind(). +static __forceinline__ __device__ bool optixIsBackFaceHit( unsigned int hitKind ); + +/// Function interpreting the hit kind associated with the current optixReportIntersection. +static __forceinline__ __device__ OptixPrimitiveType optixGetPrimitiveType(); + +/// Function interpreting the hit kind associated with the current optixReportIntersection. +static __forceinline__ __device__ bool optixIsFrontFaceHit(); + +/// Function interpreting the hit kind associated with the current optixReportIntersection. +static __forceinline__ __device__ bool optixIsBackFaceHit(); + +/// Convenience function interpreting the result of #optixGetHitKind(). +static __forceinline__ __device__ bool optixIsTriangleHit(); + +/// Convenience function interpreting the result of #optixGetHitKind(). +static __forceinline__ __device__ bool optixIsTriangleFrontFaceHit(); + +/// Convenience function interpreting the result of #optixGetHitKind(). +static __forceinline__ __device__ bool optixIsTriangleBackFaceHit(); + +/// Convenience function that returns the first two attributes as floats. +/// +/// When using OptixBuildInputTriangleArray objects, during intersection the barycentric +/// coordinates are stored into the first two attribute registers. +static __forceinline__ __device__ float2 optixGetTriangleBarycentrics(); + +/// Convenience function that returns the curve parameter. +/// +/// When using OptixBuildInputCurveArray objects, during intersection the curve parameter +/// is stored into the first attribute register. +static __forceinline__ __device__ float optixGetCurveParameter(); + +/// Available in any program, it returns the current launch index within the launch dimensions specified by optixLaunch on the host. +/// +/// The raygen program is typically only launched once per launch index. +static __forceinline__ __device__ uint3 optixGetLaunchIndex(); + +/// Available in any program, it returns the dimensions of the current launch specified by optixLaunch on the host. +static __forceinline__ __device__ uint3 optixGetLaunchDimensions(); + +/// Returns the generic memory space pointer to the data region (past the header) of the currently active SBT record corresponding to the current program. +static __forceinline__ __device__ CUdeviceptr optixGetSbtDataPointer(); + +/// Throws a user exception with the given exception code (overload without exception details). +/// +/// The exception code must be in the range from 0 to 2^30 - 1. Up to 8 optional exception details can be passed. They +/// can be queried in the EX program using optixGetExceptionDetail_0() to ..._8(). +/// +/// The exception details must not be used to encode pointers to the stack since the current stack is not preserved in +/// the EX program. +/// +/// Not available in EX. +/// +/// \param[in] exceptionCode The exception code to be thrown. +static __forceinline__ __device__ void optixThrowException( int exceptionCode ); + +/// Throws a user exception with the given exception code (overload with 1 exception detail). +/// +/// \see #optixThrowException(int) +static __forceinline__ __device__ void optixThrowException( int exceptionCode, unsigned int exceptionDetail0 ); + +/// Throws a user exception with the given exception code (overload with 2 exception details). +/// +/// \see #optixThrowException(int) +static __forceinline__ __device__ void optixThrowException( int exceptionCode, + unsigned int exceptionDetail0, + unsigned int exceptionDetail1 ); + +/// Throws a user exception with the given exception code (overload with 3 exception details). +/// +/// \see #optixThrowException(int) +static __forceinline__ __device__ void optixThrowException( int exceptionCode, + unsigned int exceptionDetail0, + unsigned int exceptionDetail1, + unsigned int exceptionDetail2 ); + +/// Throws a user exception with the given exception code (overload with 4 exception details). +/// +/// \see #optixThrowException(int) +static __forceinline__ __device__ void optixThrowException( int exceptionCode, + unsigned int exceptionDetail0, + unsigned int exceptionDetail1, + unsigned int exceptionDetail2, + unsigned int exceptionDetail3 ); + +/// Throws a user exception with the given exception code (overload with 5 exception details). +/// +/// \see #optixThrowException(int) +static __forceinline__ __device__ void optixThrowException( int exceptionCode, + unsigned int exceptionDetail0, + unsigned int exceptionDetail1, + unsigned int exceptionDetail2, + unsigned int exceptionDetail3, + unsigned int exceptionDetail4 ); + +/// Throws a user exception with the given exception code (overload with 6 exception details). +/// +/// \see #optixThrowException(int) +static __forceinline__ __device__ void optixThrowException( int exceptionCode, + unsigned int exceptionDetail0, + unsigned int exceptionDetail1, + unsigned int exceptionDetail2, + unsigned int exceptionDetail3, + unsigned int exceptionDetail4, + unsigned int exceptionDetail5 ); + +/// Throws a user exception with the given exception code (overload with 7 exception details). +/// +/// \see #optixThrowException(int) +static __forceinline__ __device__ void optixThrowException( int exceptionCode, + unsigned int exceptionDetail0, + unsigned int exceptionDetail1, + unsigned int exceptionDetail2, + unsigned int exceptionDetail3, + unsigned int exceptionDetail4, + unsigned int exceptionDetail5, + unsigned int exceptionDetail6 ); + +/// Throws a user exception with the given exception code (overload with 8 exception details). +/// +/// \see #optixThrowException(int) +static __forceinline__ __device__ void optixThrowException( int exceptionCode, + unsigned int exceptionDetail0, + unsigned int exceptionDetail1, + unsigned int exceptionDetail2, + unsigned int exceptionDetail3, + unsigned int exceptionDetail4, + unsigned int exceptionDetail5, + unsigned int exceptionDetail6, + unsigned int exceptionDetail7 ); + +/// Returns the exception code. +/// +/// Only available in EX. +static __forceinline__ __device__ int optixGetExceptionCode(); + +/// Returns the 32-bit exception detail at slot 0. +/// +/// The behavior is undefined if the exception is not a user exception, or the used overload #optixThrowException() did +/// not provide the queried exception detail. +/// +/// Only available in EX. +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_0(); + +/// Returns the 32-bit exception detail at slot 1. +/// +/// \see #optixGetExceptionDetail_0() +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_1(); + +/// Returns the 32-bit exception detail at slot 2. +/// +/// \see #optixGetExceptionDetail_0() +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_2(); + +/// Returns the 32-bit exception detail at slot 3. +/// +/// \see #optixGetExceptionDetail_0() +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_3(); + +/// Returns the 32-bit exception detail at slot 4. +/// +/// \see #optixGetExceptionDetail_0() +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_4(); + +/// Returns the 32-bit exception detail at slot 5. +/// +/// \see #optixGetExceptionDetail_0() +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_5(); + +/// Returns the 32-bit exception detail at slot 6. +/// +/// \see #optixGetExceptionDetail_0() +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_6(); + +/// Returns the 32-bit exception detail at slot 7. +/// +/// \see #optixGetExceptionDetail_0() +static __forceinline__ __device__ unsigned int optixGetExceptionDetail_7(); + +/// Returns the invalid traversable handle for exceptions with exception code OPTIX_EXCEPTION_CODE_TRAVERSAL_INVALID_TRAVERSABLE. +/// +/// Returns zero for all other exception codes. +/// +/// Only available in EX. +static __forceinline__ __device__ OptixTraversableHandle optixGetExceptionInvalidTraversable(); + +/// Returns the invalid sbt offset for exceptions with exception code OPTIX_EXCEPTION_CODE_TRAVERSAL_INVALID_MISS_SBT and OPTIX_EXCEPTION_CODE_TRAVERSAL_INVALID_HIT_SBT. +/// +/// Returns zero for all other exception codes. +/// +/// Only available in EX. +static __forceinline__ __device__ int optixGetExceptionInvalidSbtOffset(); + +/// Returns the invalid ray for exceptions with exception code OPTIX_EXCEPTION_CODE_INVALID_RAY. +/// Exceptions of type OPTIX_EXCEPTION_CODE_INVALID_RAY are thrown when one or more values that were +/// passed into optixTrace are either inf or nan. +/// +/// OptixInvalidRayExceptionDetails::rayTime will always be 0 if OptixPipelineCompileOptions::usesMotionBlur is 0. +/// Values in the returned struct are all zero for all other exception codes. +/// +/// Only available in EX. +static __forceinline__ __device__ OptixInvalidRayExceptionDetails optixGetExceptionInvalidRay(); + +/// Returns information about an exception with code OPTIX_EXCEPTION_CODE_CALLABLE_PARAMETER_MISMATCH. +/// +/// Exceptions of type OPTIX_EXCEPTION_CODE_CALLABLE_PARAMETER_MISMATCH are called when the number of +/// arguments that were passed into a call to optixDirectCall or optixContinuationCall does not match +/// the number of parameters of the callable that is called. +/// Note that the parameters are packed by OptiX into individual 32 bit values, so the number of +/// expected and passed values may not correspond to the number of arguments passed into optixDirectCall +/// or optixContinuationCall. +/// +/// Values in the returned struct are all zero for all other exception codes. +/// +/// Only available in EX. +static __forceinline__ __device__ OptixParameterMismatchExceptionDetails optixGetExceptionParameterMismatch(); + +/// Returns a string that includes information about the source location that caused the current exception. +/// +/// The source location is only available for exceptions of type OPTIX_EXCEPTION_CODE_CALLABLE_PARAMETER_MISMATCH, +/// OPTIX_EXCEPTION_CODE_UNSUPPORTED_PRIMITIVE_TYPE, OPTIX_EXCEPTION_CODE_INVALID_RAY, and for user exceptions. +/// Line information needs to be present in the input PTX and OptixModuleCompileOptions::debugLevel +/// may not be set to OPTIX_COMPILE_DEBUG_LEVEL_NONE. +/// +/// Returns a NULL pointer if no line information is available. +/// +/// Only available in EX. +static __forceinline__ __device__ char* optixGetExceptionLineInfo(); + +/// Creates a call to the direct callable program at the specified SBT entry. +/// +/// This will call the program that was specified in the OptixProgramGroupCallables::entryFunctionNameDC in the +/// module specified by OptixProgramGroupCallables::moduleDC. +/// The address of the SBT entry is calculated by OptixShaderBindingTable::callablesRecordBase + ( OptixShaderBindingTable::callablesRecordStrideInBytes * sbtIndex ). +/// +/// Behavior is undefined if there is no direct callable program at the specified SBT entry. +/// +/// Behavior is undefined if the number of arguments that are being passed in does not match the number of +/// parameters expected by the program that is called. In that case an exception of type OPTIX_EXCEPTION_CODE_CALLABLE_PARAMETER_MISMATCH +/// will be thrown if OPTIX_EXCEPTION_FLAG_DEBUG was specified for the OptixPipelineCompileOptions::exceptionFlags. +/// +/// \param[in] sbtIndex The offset of the SBT entry of the direct callable program to call relative to OptixShaderBindingTable::callablesRecordBase. +/// \param[in] args The arguments to pass to the direct callable program. +template +static __forceinline__ __device__ ReturnT optixDirectCall( unsigned int sbtIndex, ArgTypes... args ); + + +/// Creates a call to the continuation callable program at the specified SBT entry. +/// +/// This will call the program that was specified in the OptixProgramGroupCallables::entryFunctionNameCC in the +/// module specified by OptixProgramGroupCallables::moduleCC. +/// The address of the SBT entry is calculated by OptixShaderBindingTable::callablesRecordBase + ( OptixShaderBindingTable::callablesRecordStrideInBytes * sbtIndex ). +/// As opposed to direct callable programs, continuation callable programs are allowed to call optixTrace recursively. +/// +/// Behavior is undefined if there is no continuation callable program at the specified SBT entry. +/// +/// Behavior is undefined if the number of arguments that are being passed in does not match the number of +/// parameters expected by the program that is called. In that case an exception of type OPTIX_EXCEPTION_CODE_CALLABLE_PARAMETER_MISMATCH +/// will be thrown if OPTIX_EXCEPTION_FLAG_DEBUG was specified for the OptixPipelineCompileOptions::exceptionFlags. +/// +/// \param[in] sbtIndex The offset of the SBT entry of the continuation callable program to call relative to OptixShaderBindingTable::callablesRecordBase. +/// \param[in] args The arguments to pass to the continuation callable program. +template +static __forceinline__ __device__ ReturnT optixContinuationCall( unsigned int sbtIndex, ArgTypes... args ); + + +/// optixTexFootprint2D calculates the footprint of a corresponding 2D texture fetch (non-mipmapped). +/// +/// On Turing and subsequent architectures, a texture footprint instruction allows user programs to +/// determine the set of texels that would be accessed by an equivalent filtered texture lookup. +/// +/// \param[in] tex CUDA texture object (cast to 64-bit integer) +/// \param[in] texInfo Texture info packed into 32-bit integer, described below. +/// \param[in] x Texture coordinate +/// \param[in] y Texture coordinate +/// \param[out] singleMipLevel Result indicating whether the footprint spans only a single miplevel. +/// +/// The texture info argument is a packed 32-bit integer with the following layout: +/// +/// texInfo[31:29] = reserved (3 bits) +/// texInfo[28:24] = miplevel count (5 bits) +/// texInfo[23:20] = log2 of tile width (4 bits) +/// texInfo[19:16] = log2 of tile height (4 bits) +/// texInfo[15:10] = reserved (6 bits) +/// texInfo[9:8] = horizontal wrap mode (2 bits) (CUaddress_mode) +/// texInfo[7:6] = vertical wrap mode (2 bits) (CUaddress_mode) +/// texInfo[5] = mipmap filter mode (1 bit) (CUfilter_mode) +/// texInfo[4:0] = maximum anisotropy (5 bits) +/// +/// Returns a 16-byte structure (as a uint4) that stores the footprint of a texture request at a +/// particular "granularity", which has the following layout: +/// +/// struct Texture2DFootprint +/// { +/// unsigned long long mask; +/// unsigned int tileY : 12; +/// unsigned int reserved1 : 4; +/// unsigned int dx : 3; +/// unsigned int dy : 3; +/// unsigned int reserved2 : 2; +/// unsigned int granularity : 4; +/// unsigned int reserved3 : 4; +/// unsigned int tileX : 12; +/// unsigned int level : 4; +/// unsigned int reserved4 : 16; +/// }; +/// +/// The granularity indicates the size of texel groups that are represented by an 8x8 bitmask. For +/// example, a granularity of 12 indicates texel groups that are 128x64 texels in size. In a +/// footprint call, The returned granularity will either be the actual granularity of the result, or +/// 0 if the footprint call was able to honor the requested granularity (the usual case). +/// +/// level is the mip level of the returned footprint. Two footprint calls are needed to get the +/// complete footprint when a texture call spans multiple mip levels. +/// +/// mask is an 8x8 bitmask of texel groups that are covered, or partially covered, by the footprint. +/// tileX and tileY give the starting position of the mask in 8x8 texel-group blocks. For example, +/// suppose a granularity of 12 (128x64 texels), and tileX=3 and tileY=4. In this case, bit 0 of the +/// mask (the low order bit) corresponds to texel group coordinates (3*8, 4*8), and texel +/// coordinates (3*8*128, 4*8*64), within the specified mip level. +/// +/// If nonzero, dx and dy specify a "toroidal rotation" of the bitmask. Toroidal rotation of a +/// coordinate in the mask simply means that its value is reduced by 8. Continuing the example from +/// above, if dx=0 and dy=0 the mask covers texel groups (3*8, 4*8) to (3*8+7, 4*8+7) inclusive. +/// If, on the other hand, dx=2, the rightmost 2 columns in the mask have their x coordinates +/// reduced by 8, and similarly for dy. +/// +/// See the OptiX SDK for sample code that illustrates how to unpack the result. +static __forceinline__ __device__ uint4 optixTexFootprint2D( unsigned long long tex, unsigned int texInfo, float x, float y, unsigned int* singleMipLevel ); + +/// optixTexFootprint2DLod calculates the footprint of a corresponding 2D texture fetch (tex2DLod) +/// \param[in] tex CUDA texture object (cast to 64-bit integer) +/// \param[in] texInfo Texture info packed into 32-bit integer, described below. +/// \param[in] x Texture coordinate +/// \param[in] y Texture coordinate +/// \param[in] level Level of detail (lod) +/// \param[in] coarse Requests footprint from coarse miplevel, when the footprint spans two levels. +/// \param[out] singleMipLevel Result indicating whether the footprint spans only a single miplevel. +/// \see #optixTexFootprint2D(unsigned long long,unsigned int,float,float,unsigned int*) +static __forceinline__ __device__ uint4 +optixTexFootprint2DLod( unsigned long long tex, unsigned int texInfo, float x, float y, float level, bool coarse, unsigned int* singleMipLevel ); + +/// optixTexFootprint2DGrad calculates the footprint of a corresponding 2D texture fetch (tex2DGrad) +/// \param[in] tex CUDA texture object (cast to 64-bit integer) +/// \param[in] texInfo Texture info packed into 32-bit integer, described below. +/// \param[in] x Texture coordinate +/// \param[in] y Texture coordinate +/// \param[in] dPdx_x Derivative of x coordinte, which determines level of detail. +/// \param[in] dPdx_y Derivative of x coordinte, which determines level of detail. +/// \param[in] dPdy_x Derivative of y coordinte, which determines level of detail. +/// \param[in] dPdy_y Derivative of y coordinte, which determines level of detail. +/// \param[in] coarse Requests footprint from coarse miplevel, when the footprint spans two levels. +/// \param[out] singleMipLevel Result indicating whether the footprint spans only a single miplevel. +/// \see #optixTexFootprint2D(unsigned long long,unsigned int,float,float,unsigned int*) +static __forceinline__ __device__ uint4 optixTexFootprint2DGrad( unsigned long long tex, + unsigned int texInfo, + float x, + float y, + float dPdx_x, + float dPdx_y, + float dPdy_x, + float dPdy_y, + bool coarse, + unsigned int* singleMipLevel ); + +/*@}*/ // end group optix_device_api + +#include "internal/optix_7_device_impl.h" + +#endif // __optix_optix_7_device_h__ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_7_host.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_7_host.h new file mode 100644 index 00000000..a621ddf5 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_7_host.h @@ -0,0 +1,893 @@ +/* +* SPDX-FileCopyrightText: Copyright (c) 2010 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* SPDX-License-Identifier: LicenseRef-NvidiaProprietary +* +* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +* property and proprietary rights in and to this material, related +* documentation and any modifications thereto. Any use, reproduction, +* disclosure or distribution of this material and related documentation +* without an express license agreement from NVIDIA CORPORATION or +* its affiliates is strictly prohibited. +*/ +/// @file +/// @author NVIDIA Corporation +/// @brief OptiX public API header +/// +/// OptiX host include file -- includes the host api if compiling host code. +/// For the math library routines include optix_math.h + +#if !defined( __OPTIX_INCLUDE_INTERNAL_HEADERS__ ) +#error("optix_7_host.h is an internal header file and must not be used directly. Please use optix_host.h or optix.h instead.") +#endif + +#ifndef __optix_optix_7_host_h__ +#define __optix_optix_7_host_h__ + +#include "optix_7_types.h" +#if !defined( OPTIX_DONT_INCLUDE_CUDA ) +// If OPTIX_DONT_INCLUDE_CUDA is defined, cuda driver types must be defined through other +// means before including optix headers. +#include +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + +/// \defgroup optix_host_api Host API +/// \brief OptiX Host API + +/// \defgroup optix_host_api_error_handling Error handling +/// \ingroup optix_host_api +//@{ + +/// Returns a string containing the name of an error code in the enum. +/// +/// Output is a string representation of the enum. For example "OPTIX_SUCCESS" for +/// OPTIX_SUCCESS and "OPTIX_ERROR_INVALID_VALUE" for OPTIX_ERROR_INVALID_VALUE. +/// +/// If the error code is not recognized, "Unrecognized OptixResult code" is returned. +/// +/// \param[in] result OptixResult enum to generate string name for +/// +/// \see #optixGetErrorString +const char* optixGetErrorName( OptixResult result ); + +/// Returns the description string for an error code. +/// +/// Output is a string description of the enum. For example "Success" for +/// OPTIX_SUCCESS and "Invalid value" for OPTIX_ERROR_INVALID_VALUE. +/// +/// If the error code is not recognized, "Unrecognized OptixResult code" is returned. +/// +/// \param[in] result OptixResult enum to generate string description for +/// +/// \see #optixGetErrorName +const char* optixGetErrorString( OptixResult result ); + +//@} +/// \defgroup optix_host_api_device_context Device context +/// \ingroup optix_host_api +//@{ + +/// Create a device context associated with the CUDA context specified with 'fromContext'. +/// +/// If zero is specified for 'fromContext', OptiX will use the current CUDA context. The +/// CUDA context should be initialized before calling optixDeviceContextCreate. +/// +/// \param[in] fromContext +/// \param[in] options +/// \param[out] context +/// \return +/// - OPTIX_ERROR_CUDA_NOT_INITIALIZED +/// If using zero for 'fromContext' and CUDA has not been initialized yet on the calling +/// thread. +/// - OPTIX_ERROR_CUDA_ERROR +/// CUDA operation failed. +/// - OPTIX_ERROR_HOST_OUT_OF_MEMORY +/// Heap allocation failed. +/// - OPTIX_ERROR_INTERNAL_ERROR +/// Internal error +OptixResult optixDeviceContextCreate( CUcontext fromContext, const OptixDeviceContextOptions* options, OptixDeviceContext* context ); + +/// Destroys all CPU and GPU state associated with the device. +/// +/// It will attempt to block on CUDA streams that have launch work outstanding. +/// +/// Any API objects, such as OptixModule and OptixPipeline, not already destroyed will be +/// destroyed. +/// +/// Thread safety: A device context must not be destroyed while it is still in use by concurrent API calls in other threads. +OptixResult optixDeviceContextDestroy( OptixDeviceContext context ); + +/// Query properties of a device context. +/// +/// \param[in] context the device context to query the property for +/// \param[in] property the property to query +/// \param[out] value pointer to the returned +/// \param[in] sizeInBytes size of output +OptixResult optixDeviceContextGetProperty( OptixDeviceContext context, OptixDeviceProperty property, void* value, size_t sizeInBytes ); + +/// Sets the current log callback method. +/// +/// See #OptixLogCallback for more details. +/// +/// Thread safety: It is guaranteed that the callback itself (callbackFunction and callbackData) are updated atomically. +/// It is not guaranteed that the callback itself (callbackFunction and callbackData) and the callbackLevel are updated +/// atomically. It is unspecified when concurrent API calls using the same context start to make use of the new +/// callback method. +/// +/// \param[in] context the device context +/// \param[in] callbackFunction the callback function to call +/// \param[in] callbackData pointer to data passed to callback function while invoking it +/// \param[in] callbackLevel callback level +OptixResult optixDeviceContextSetLogCallback( OptixDeviceContext context, + OptixLogCallback callbackFunction, + void* callbackData, + unsigned int callbackLevel ); + +/// Enables or disables the disk cache. +/// +/// If caching was previously disabled, enabling it will attempt to initialize +/// the disk cache database using the currently configured cache location. An +/// error will be returned if initialization fails. +/// +/// Note that no in-memory cache is used, so no caching behavior will be observed if the disk cache +/// is disabled. +/// +/// The cache can be disabled by setting the environment variable OPTIX_CACHE_MAXSIZE=0. +/// The environment variable takes precedence over this setting. +/// See #optixDeviceContextSetCacheDatabaseSizes for additional information. +/// +/// Note that the disk cache can be disabled by the environment variable, but it cannot be enabled +/// via the environment if it is disabled via the API. +/// +/// \param[in] context the device context +/// \param[in] enabled 1 to enabled, 0 to disable +OptixResult optixDeviceContextSetCacheEnabled( OptixDeviceContext context, + int enabled ); + +/// Sets the location of the disk cache. +/// +/// The location is specified by a directory. This directory should not be used for other purposes +/// and will be created if it does not exist. An error will be returned if is not possible to +/// create the disk cache at the specified location for any reason (e.g., the path is invalid or +/// the directory is not writable). Caching will be disabled if the disk cache cannot be +/// initialized in the new location. If caching is disabled, no error will be returned until caching +/// is enabled. If the disk cache is located on a network file share, behavior is undefined. +/// +/// The location of the disk cache can be overridden with the environment variable OPTIX_CACHE_PATH. +/// The environment variable takes precedence over this setting. +/// +/// The default location depends on the operating system: +/// - Windows: %LOCALAPPDATA%\\NVIDIA\\OptixCache +/// - Linux: /var/tmp/OptixCache_\ (or /tmp/OptixCache_\ if the first choice is not usable), +/// the underscore and username suffix are omitted if the username cannot be obtained +/// - MacOS X: /Library/Application Support/NVIDIA/OptixCache +/// +/// \param[in] context the device context +/// \param[in] location directory of disk cache +OptixResult optixDeviceContextSetCacheLocation( OptixDeviceContext context, const char* location ); + +/// Sets the low and high water marks for disk cache garbage collection. +/// +/// Garbage collection is triggered when a new entry is written to the cache and +/// the current cache data size plus the size of the cache entry that is about +/// to be inserted exceeds the high water mark. Garbage collection proceeds until +/// the size reaches the low water mark. Garbage collection will always free enough +/// space to insert the new entry without exceeding the low water mark. Setting +/// either limit to zero will disable garbage collection. An error will be returned +/// if both limits are non-zero and the high water mark is smaller than the low water mark. +/// +/// Note that garbage collection is performed only on writes to the disk cache. No garbage +/// collection is triggered on disk cache initialization or immediately when calling this function, +/// but on subsequent inserting of data into the database. +/// +/// If the size of a compiled module exceeds the value configured for the high water +/// mark and garbage collection is enabled, the module will not be added to the cache +/// and a warning will be added to the log. +/// +/// The high water mark can be overridden with the environment variable OPTIX_CACHE_MAXSIZE. +/// The environment variable takes precedence over the function parameters. The low water mark +/// will be set to half the value of OPTIX_CACHE_MAXSIZE. Setting OPTIX_CACHE_MAXSIZE to 0 will +/// disable the disk cache, but will not alter the contents of the cache. Negative and non-integer +/// values will be ignored. +/// +/// \param[in] context the device context +/// \param[in] lowWaterMark the low water mark +/// \param[in] highWaterMark the high water mark +OptixResult optixDeviceContextSetCacheDatabaseSizes( OptixDeviceContext context, size_t lowWaterMark, size_t highWaterMark ); + +/// Indicates whether the disk cache is enabled or disabled. +/// +/// \param[in] context the device context +/// \param[out] enabled 1 if enabled, 0 if disabled +OptixResult optixDeviceContextGetCacheEnabled( OptixDeviceContext context, int* enabled ); +/// Returns the location of the disk cache. If the cache has been disabled by setting the environment +/// variable OPTIX_CACHE_MAXSIZE=0, this function will return an empy string. +/// +/// \param[in] context the device context +/// \param[out] location directory of disk cache, null terminated if locationSize > 0 +/// \param[in] locationSize locationSize +OptixResult optixDeviceContextGetCacheLocation( OptixDeviceContext context, char* location, size_t locationSize ); + +/// Returns the low and high water marks for disk cache garbage collection. If the cache has been disabled by +/// setting the environment variable OPTIX_CACHE_MAXSIZE=0, this function will return 0 for the low and high +/// water marks. +/// +/// \param[in] context the device context +/// \param[out] lowWaterMark the low water mark +/// \param[out] highWaterMark the high water mark +OptixResult optixDeviceContextGetCacheDatabaseSizes( OptixDeviceContext context, size_t* lowWaterMark, size_t* highWaterMark ); + +//@} +/// \defgroup optix_host_api_pipelines Pipelines +/// \ingroup optix_host_api +//@{ + +/// logString is an optional buffer that contains compiler feedback and errors. This +/// information is also passed to the context logger (if enabled), however it may be +/// difficult to correlate output to the logger to specific API invocations when using +/// multiple threads. The output to logString will only contain feedback for this specific +/// invocation of this API call. +/// +/// logStringSize as input should be a pointer to the number of bytes backing logString. +/// Upon return it contains the length of the log message (including the null terminator) +/// which may be greater than the input value. In this case, the log message will be +/// truncated to fit into logString. +/// +/// If logString or logStringSize are NULL, no output is written to logString. If +/// logStringSize points to a value that is zero, no output is written. This does not +/// affect output to the context logger if enabled. +/// +/// \param[in] context +/// \param[in] pipelineCompileOptions +/// \param[in] pipelineLinkOptions +/// \param[in] programGroups array of ProgramGroup objects +/// \param[in] numProgramGroups number of ProgramGroup objects +/// \param[out] logString Information will be written to this string. If logStringSize > 0 logString will be null terminated. +/// \param[in,out] logStringSize +/// \param[out] pipeline +OptixResult optixPipelineCreate( OptixDeviceContext context, + const OptixPipelineCompileOptions* pipelineCompileOptions, + const OptixPipelineLinkOptions* pipelineLinkOptions, + const OptixProgramGroup* programGroups, + unsigned int numProgramGroups, + char* logString, + size_t* logStringSize, + OptixPipeline* pipeline ); + +/// Thread safety: A pipeline must not be destroyed while it is still in use by concurrent API calls in other threads. +OptixResult optixPipelineDestroy( OptixPipeline pipeline ); + +/// Sets the stack sizes for a pipeline. +/// +/// Users are encouraged to see the programming guide and the implementations of the helper functions +/// to understand how to construct the stack sizes based on their particular needs. +/// +/// If this method is not used, an internal default implementation is used. The default implementation is correct (but +/// not necessarily optimal) as long as the maximum depth of call trees of CC and DC programs is at most 2 and no motion transforms are used. +/// +/// The maxTraversableGraphDepth responds to the maximal number of traversables visited when calling trace. +/// Every acceleration structure and motion transform count as one level of traversal. +/// E.g., for a simple IAS (instance acceleration structure) -> GAS (geometry acceleration structure) +/// traversal graph, the maxTraversableGraphDepth is two. +/// For IAS -> MT (motion transform) -> GAS, the maxTraversableGraphDepth is three. +/// Note that it does not matter whether a IAS or GAS has motion or not, it always counts as one. +/// Launching optix with exceptions turned on (see #OPTIX_EXCEPTION_FLAG_TRACE_DEPTH) will throw an exception +/// if the specified maxTraversableGraphDepth is too small. +/// +/// \param[in] pipeline The pipeline to configure the stack size for. +/// \param[in] directCallableStackSizeFromTraversal The direct stack size requirement for direct callables invoked from IS or AH. +/// \param[in] directCallableStackSizeFromState The direct stack size requirement for direct callables invoked from RG, MS, or CH. +/// \param[in] continuationStackSize The continuation stack requirement. +/// \param[in] maxTraversableGraphDepth The maximum depth of a traversable graph passed to trace. +OptixResult optixPipelineSetStackSize( OptixPipeline pipeline, + unsigned int directCallableStackSizeFromTraversal, + unsigned int directCallableStackSizeFromState, + unsigned int continuationStackSize, + unsigned int maxTraversableGraphDepth ); + +//@} +/// \defgroup optix_host_api_modules Modules +/// \ingroup optix_host_api +//@{ + +/// logString is an optional buffer that contains compiler feedback and errors. This +/// information is also passed to the context logger (if enabled), however it may be +/// difficult to correlate output to the logger to specific API invocations when using +/// multiple threads. The output to logString will only contain feedback for this specific +/// invocation of this API call. +/// +/// logStringSize as input should be a pointer to the number of bytes backing logString. +/// Upon return it contains the length of the log message (including the null terminator) +/// which may be greater than the input value. In this case, the log message will be +/// truncated to fit into logString. +/// +/// If logString or logStringSize are NULL, no output is written to logString. If +/// logStringSize points to a value that is zero, no output is written. This does not +/// affect output to the context logger if enabled. +/// +/// \param[in] context +/// \param[in] moduleCompileOptions +/// \param[in] pipelineCompileOptions All modules in a pipeline need to use the same values for the pipeline compile options. +/// \param[in] PTX Pointer to the PTX input string. +/// \param[in] PTXsize Parsing proceeds up to PTXsize characters, or the first NUL byte, whichever occurs first. +/// \param[out] logString Information will be written to this string. If logStringSize > 0 logString will be null terminated. +/// \param[in,out] logStringSize +/// \param[out] module +/// +/// \return OPTIX_ERROR_INVALID_VALUE - context is 0, moduleCompileOptions is 0, pipelineCompileOptions is 0, PTX is 0, module is 0. +OptixResult optixModuleCreateFromPTX( OptixDeviceContext context, + const OptixModuleCompileOptions* moduleCompileOptions, + const OptixPipelineCompileOptions* pipelineCompileOptions, + const char* PTX, + size_t PTXsize, + char* logString, + size_t* logStringSize, + OptixModule* module ); + +/// This function is designed to do just enough work to create the OptixTask return +/// parameter and is expected to be fast enough run without needing parallel execution. A +/// single thread could generate all the OptixTask objects for further processing in a +/// work pool. +/// +/// Options are similar to #optixModuleCreateFromPTX(), aside from the return parameter, +/// firstTask. +/// +/// The memory used to hold the PTX should be live until all tasks are finished. +/// +/// It is illegal to call #optixModuleDestroy() if any OptixTask objects are currently +/// being executed. In that case OPTIX_ERROR_ILLEGAL_DURING_TASK_EXECUTE will be returned. +/// +/// If an invocation of optixTaskExecute fails, the OptixModule will be marked as +/// OPTIX_MODULE_COMPILE_STATE_IMPENDING_FAILURE if there are outstanding tasks or +/// OPTIX_MODULE_COMPILE_STATE_FAILURE if there are no outstanding tasks. Subsequent calls +/// to #optixTaskExecute() may execute additional work to collect compilation errors +/// generated from the input. Currently executing tasks will not necessarily be terminated +/// immediately but at the next opportunity. + +/// Logging will continue to be directed to the logger installed with the +/// OptixDeviceContext. If logString is provided to #optixModuleCreateFromPTXWithTasks(), +/// it will contain all the compiler feedback from all executed tasks. The lifetime of the +/// memory pointed to by logString should extend from calling +/// #optixModuleCreateFromPTXWithTasks() to when the compilation state is either +/// OPTIX_MODULE_COMPILE_STATE_FAILURE or OPTIX_MODULE_COMPILE_STATE_COMPLETED. OptiX will +/// not write to the logString outside of execution of +/// #optixModuleCreateFromPTXWithTasks() or #optixTaskExecute(). If the compilation state +/// is OPTIX_MODULE_COMPILE_STATE_IMPENDING_FAILURE and no further execution of +/// #optixTaskExecute() is performed the logString may be reclaimed by the application +/// before calling #optixModuleDestroy(). The contents of logString will contain output +/// from currently completed tasks. + +/// All OptixTask objects associated with a given OptixModule will be cleaned up when +/// #optixModuleDestroy() is called regardless of whether the compilation was successful +/// or not. If the compilation state is OPTIX_MODULE_COMPILE_STATE_IMPENDIND_FAILURE, any +/// unstarted OptixTask objects do not need to be executed though there is no harm doing +/// so. +/// +/// \see #optixModuleCreateFromPTX +OptixResult optixModuleCreateFromPTXWithTasks( OptixDeviceContext context, + const OptixModuleCompileOptions* moduleCompileOptions, + const OptixPipelineCompileOptions* pipelineCompileOptions, + const char* PTX, + size_t PTXsize, + char* logString, + size_t* logStringSize, + OptixModule* module, + OptixTask* firstTask ); + +/// When creating a module with tasks, the current state of the module can be queried +/// using this function. +/// +/// Thread safety: Safe to call from any thread until optixModuleDestroy is called. +/// +/// \see #optixModuleCreateFromPTXWithTasks +OptixResult optixModuleGetCompilationState( OptixModule module, OptixModuleCompileState* state ); + +/// Call for OptixModule objects created with optixModuleCreateFromPTX and optixModuleDeserialize. +/// +/// Modules must not be destroyed while they are still used by any program group. +/// +/// Thread safety: A module must not be destroyed while it is still in use by concurrent API calls in other threads. +OptixResult optixModuleDestroy( OptixModule module ); + +/// Returns a module containing the intersection program for the built-in primitive type specified +/// by the builtinISOptions. This module must be used as the moduleIS for the OptixProgramGroupHitgroup +/// in any SBT record for that primitive type. (The entryFunctionNameIS should be null.) +OptixResult optixBuiltinISModuleGet( OptixDeviceContext context, + const OptixModuleCompileOptions* moduleCompileOptions, + const OptixPipelineCompileOptions* pipelineCompileOptions, + const OptixBuiltinISOptions* builtinISOptions, + OptixModule* builtinModule ); + +//@} +/// \defgroup optix_host_api_tasks Tasks +/// \ingroup optix_host_api +//@{ + +/// Each OptixTask should be executed with #optixTaskExecute(). If additional parallel +/// work is found, new OptixTask objects will be returned in additionalTasks along with +/// the number of additional tasks in numAdditionalTasksCreated. The parameter +/// additionalTasks should point to a user allocated array of minimum size +/// maxNumAdditionalTasks. OptiX can generate upto maxNumAdditionalTasks additional tasks. +/// +/// Each task can be executed in parallel and in any order. +/// +/// Thread safety: Safe to call from any thread until #optixModuleDestroy() is called for +/// any associated task. +/// +/// \see #optixModuleCreateFromPTXWithTasks +/// +/// \param[in] task the OptixTask to execute +/// \param[in] additionalTasks pointer to array of OptixTask objects to be filled in +/// \param[in] maxNumAdditionalTasks maximum number of additional OptixTask objects +/// \param[out] numAdditionalTasksCreated number of OptixTask objects created by OptiX and written into #additionalTasks +OptixResult optixTaskExecute( OptixTask task, OptixTask* additionalTasks, unsigned int maxNumAdditionalTasks, unsigned int* numAdditionalTasksCreated ); + +//@} +/// \defgroup optix_host_api_program_groups Program groups +/// \ingroup optix_host_api +//@{ + +/// Returns the stack sizes for the given program group. +/// +/// \param[in] programGroup the program group +/// \param[out] stackSizes the corresponding stack sizes +OptixResult optixProgramGroupGetStackSize( OptixProgramGroup programGroup, OptixStackSizes* stackSizes ); + +/// logString is an optional buffer that contains compiler feedback and errors. This +/// information is also passed to the context logger (if enabled), however it may be +/// difficult to correlate output to the logger to specific API invocations when using +/// multiple threads. The output to logString will only contain feedback for this specific +/// invocation of this API call. +/// +/// logStringSize as input should be a pointer to the number of bytes backing logString. +/// Upon return it contains the length of the log message (including the null terminator) +/// which may be greater than the input value. In this case, the log message will be +/// truncated to fit into logString. +/// +/// If logString or logStringSize are NULL, no output is written to logString. If +/// logStringSize points to a value that is zero, no output is written. This does not +/// affect output to the context logger if enabled. +/// +/// Creates numProgramGroups OptiXProgramGroup objects from the specified +/// OptixProgramGroupDesc array. The size of the arrays must match. +/// +/// \param[in] context +/// \param[in] programDescriptions N * OptixProgramGroupDesc +/// \param[in] numProgramGroups N +/// \param[in] options +/// \param[out] logString Information will be written to this string. If logStringSize > 0 logString will be null terminated. +/// \param[in,out] logStringSize +/// \param[out] programGroups +OptixResult optixProgramGroupCreate( OptixDeviceContext context, + const OptixProgramGroupDesc* programDescriptions, + unsigned int numProgramGroups, + const OptixProgramGroupOptions* options, + char* logString, + size_t* logStringSize, + OptixProgramGroup* programGroups ); + +/// Thread safety: A program group must not be destroyed while it is still in use by concurrent API calls in other threads. +OptixResult optixProgramGroupDestroy( OptixProgramGroup programGroup ); + +//@} +/// \defgroup optix_host_api_launches Launches +/// \ingroup optix_host_api +//@{ + +/// Where the magic happens. +/// +/// The stream and pipeline must belong to the same device context. Multiple launches +/// may be issues in parallel from multiple threads to different streams. +/// +/// pipelineParamsSize number of bytes are copied from the device memory pointed to by +/// pipelineParams before launch. It is an error if pipelineParamsSize is greater than the +/// size of the variable declared in modules and identified by +/// OptixPipelineCompileOptions::pipelineLaunchParamsVariableName. If the launch params +/// variable was optimized out or not found in the modules linked to the pipeline then +/// the pipelineParams and pipelineParamsSize parameters are ignored. +/// +/// sbt points to the shader binding table, which defines shader +/// groupings and their resources. See the SBT spec. +/// +/// \param[in] pipeline +/// \param[in] stream +/// \param[in] pipelineParams +/// \param[in] pipelineParamsSize +/// \param[in] sbt +/// \param[in] width number of elements to compute +/// \param[in] height number of elements to compute +/// \param[in] depth number of elements to compute +/// +/// Thread safety: In the current implementation concurrent launches to the same pipeline are not +/// supported. Concurrent launches require separate OptixPipeline objects. +OptixResult optixLaunch( OptixPipeline pipeline, + CUstream stream, + CUdeviceptr pipelineParams, + size_t pipelineParamsSize, + const OptixShaderBindingTable* sbt, + unsigned int width, + unsigned int height, + unsigned int depth ); + +/// \param[in] programGroup the program group containing the program(s) +/// \param[out] sbtRecordHeaderHostPointer the result sbt record header +OptixResult optixSbtRecordPackHeader( OptixProgramGroup programGroup, void* sbtRecordHeaderHostPointer ); + +//@} +/// \defgroup optix_host_api_acceleration_structures Acceleration structures +/// \ingroup optix_host_api +//@{ + +/// \param[in] context +/// \param[in] accelOptions options for the accel build +/// \param[in] buildInputs an array of OptixBuildInput objects +/// \param[in] numBuildInputs number of elements in buildInputs (must be at least 1) +/// \param[out] bufferSizes fills in buffer sizes +OptixResult optixAccelComputeMemoryUsage( OptixDeviceContext context, + const OptixAccelBuildOptions* accelOptions, + const OptixBuildInput* buildInputs, + unsigned int numBuildInputs, + OptixAccelBufferSizes* bufferSizes ); + +/// \param[in] context +/// \param[in] stream +/// \param[in] accelOptions accel options +/// \param[in] buildInputs an array of OptixBuildInput objects +/// \param[in] numBuildInputs must be >= 1 for GAS, and == 1 for IAS +/// \param[in] tempBuffer must be a multiple of OPTIX_ACCEL_BUFFER_BYTE_ALIGNMENT +/// \param[in] tempBufferSizeInBytes +/// \param[in] outputBuffer must be a multiple of OPTIX_ACCEL_BUFFER_BYTE_ALIGNMENT +/// \param[in] outputBufferSizeInBytes +/// \param[out] outputHandle +/// \param[out] emittedProperties types of requested properties and output buffers +/// \param[in] numEmittedProperties number of post-build properties to populate (may be zero) +OptixResult optixAccelBuild( OptixDeviceContext context, + CUstream stream, + const OptixAccelBuildOptions* accelOptions, + const OptixBuildInput* buildInputs, + unsigned int numBuildInputs, + CUdeviceptr tempBuffer, + size_t tempBufferSizeInBytes, + CUdeviceptr outputBuffer, + size_t outputBufferSizeInBytes, + OptixTraversableHandle* outputHandle, + const OptixAccelEmitDesc* emittedProperties, + unsigned int numEmittedProperties ); + +/// Obtain relocation information, stored in OptixAccelRelocationInfo, for a given context +/// and acceleration structure's traversable handle. +/// +/// The relocation information can be passed to optixAccelCheckRelocationCompatibility to +/// determine if an acceleration structure, referenced by 'handle', can be relocated to a +/// different device's memory space (see #optixAccelCheckRelocationCompatibility). +/// +/// When used with optixAccelRelocate, it provides data necessary for doing the relocation. +/// +/// If the acceleration structure data associated with 'handle' is copied multiple times, +/// the same OptixAccelRelocationInfo can also be used on all copies. +/// +/// \param[in] context +/// \param[in] handle +/// \param[out] info +/// \return OPTIX_ERROR_INVALID_VALUE will be returned for traversable handles that are not from +/// acceleration structure builds. +OptixResult optixAccelGetRelocationInfo( OptixDeviceContext context, OptixTraversableHandle handle, OptixAccelRelocationInfo* info ); + +/// Checks if an acceleration structure built using another OptixDeviceContext (that was +/// used to fill in 'info') is compatible with the OptixDeviceContext specified in the +/// 'context' parameter. +/// +/// Any device is always compatible with itself. +/// +/// \param[in] context +/// \param[in] info +/// \param[out] compatible If OPTIX_SUCCESS is returned 'compatible' will have the value of either: +/// - 0: This context is not compatible with acceleration structure data associated with 'info'. +/// - 1: This context is compatible. +OptixResult optixAccelCheckRelocationCompatibility( OptixDeviceContext context, const OptixAccelRelocationInfo* info, int* compatible ); + +/// optixAccelRelocate is called to update the acceleration structure after it has been +/// relocated. Relocation is necessary when the acceleration structure's location in device +/// memory has changed. optixAccelRelocate does not copy the memory. This function only +/// operates on the relocated memory who's new location is specified by 'targetAccel'. +/// optixAccelRelocate also returns the new OptixTraversableHandle associated with +/// 'targetAccel'. The original memory (source) is not required to be valid, only the +/// OptixAccelRelocationInfo. +/// +/// Before copying the data and calling optixAccelRelocate, +/// optixAccelCheckRelocationCompatibility should be called to ensure the copy will be +/// compatible with the destination device context. +/// +/// The memory pointed to by 'targetAccel' should be allocated with the same size as the +/// source acceleration. Similar to the 'outputBuffer' used in optixAccelBuild, this +/// pointer must be a multiple of OPTIX_ACCEL_BUFFER_BYTE_ALIGNMENT. +/// +/// The memory in 'targetAccel' must be allocated as long as the accel is in use. +/// +/// When relocating an accel that contains instances, 'instanceTraversableHandles' and +/// 'numInstanceTraversableHandles' should be supplied. These are the traversable handles +/// of the instances. These can be used when also relocating the instances. No updates to +/// the bounds are performed. Use optixAccelBuild to update the bounds. +/// 'instanceTraversableHandles' and 'numInstanceTraversableHandles' may be zero when +/// relocating bottom level accel (i.e. an accel with no instances). +/// +/// \param[in] context +/// \param[in] stream +/// \param[in] info +/// \param[in] instanceTraversableHandles +/// \param[in] numInstanceTraversableHandles +/// \param[in] targetAccel +/// \param[in] targetAccelSizeInBytes +/// \param[out] targetHandle +OptixResult optixAccelRelocate( OptixDeviceContext context, + CUstream stream, + const OptixAccelRelocationInfo* info, + CUdeviceptr instanceTraversableHandles, + size_t numInstanceTraversableHandles, + CUdeviceptr targetAccel, + size_t targetAccelSizeInBytes, + OptixTraversableHandle* targetHandle ); + +/// After building an acceleration structure, it can be copied in a compacted form to reduce +/// memory. In order to be compacted, OPTIX_BUILD_FLAG_ALLOW_COMPACTION must be supplied in +/// OptixAccelBuildOptions::buildFlags passed to optixAccelBuild. +/// +/// 'outputBuffer' is the pointer to where the compacted acceleration structure will be +/// written. This pointer must be a multiple of OPTIX_ACCEL_BUFFER_BYTE_ALIGNMENT. +/// +/// The size of the memory specified in 'outputBufferSizeInBytes' should be at least the +/// value computed using the OPTIX_PROPERTY_TYPE_COMPACTED_SIZE that was reported during +/// optixAccelBuild. +/// +/// \param[in] context +/// \param[in] stream +/// \param[in] inputHandle +/// \param[in] outputBuffer +/// \param[in] outputBufferSizeInBytes +/// \param[out] outputHandle +OptixResult optixAccelCompact( OptixDeviceContext context, + CUstream stream, + OptixTraversableHandle inputHandle, + CUdeviceptr outputBuffer, + size_t outputBufferSizeInBytes, + OptixTraversableHandle* outputHandle ); + +/// \param[in] onDevice +/// \param[in] pointer pointer to traversable allocated in OptixDeviceContext. This pointer must be a multiple of OPTIX_TRANSFORM_BYTE_ALIGNMENT +/// \param[in] traversableType Type of OptixTraversableHandle to create +/// \param[out] traversableHandle traversable handle. traversableHandle must be in host memory +OptixResult optixConvertPointerToTraversableHandle( OptixDeviceContext onDevice, + CUdeviceptr pointer, + OptixTraversableType traversableType, + OptixTraversableHandle* traversableHandle ); + + + + +//@} +/// \defgroup optix_host_api_denoiser Denoiser +/// \ingroup optix_host_api +//@{ + +/// Creates a denoiser object with the given options, using built-in inference models +/// +/// 'modelKind' selects the model used for inference. +/// Inference for the built-in models can be guided (giving hints to improve image quality) with +/// albedo and normal vector images in the guide layer (see 'optixDenoiserInvoke'). +/// Use of these images must be enabled in 'OptixDenoiserOptions'. +/// +/// \param[in] context +/// \param[in] modelKind +/// \param[in] options +/// \param[out] denoiser +OptixResult optixDenoiserCreate( OptixDeviceContext context, + OptixDenoiserModelKind modelKind, + const OptixDenoiserOptions* options, + OptixDenoiser* denoiser ); + +/// Creates a denoiser object with the given options, using a provided inference model +/// +/// 'userData' and 'userDataSizeInBytes' provide a user model for inference. +/// The memory passed in userData will be accessed only during the invocation of this function and +/// can be freed after it returns. +/// The user model must export only one weight set which determines both the model kind and the +/// required set of guide images. +/// +/// \param[in] context +/// \param[in] userData +/// \param[in] userDataSizeInBytes +/// \param[out] denoiser +OptixResult optixDenoiserCreateWithUserModel( OptixDeviceContext context, + const void* userData, size_t userDataSizeInBytes, OptixDenoiser* denoiser ); + +/// Destroys the denoiser object and any associated host resources. +OptixResult optixDenoiserDestroy( OptixDenoiser denoiser ); + +/// Computes the GPU memory resources required to execute the denoiser. +/// +/// Memory for state and scratch buffers must be allocated with the sizes in 'returnSizes' and scratch memory +/// passed to optixDenoiserSetup, optixDenoiserInvoke, +/// optixDenoiserComputeIntensity and optixDenoiserComputeAverageColor. +/// For tiled denoising an overlap area ('overlapWindowSizeInPixels') must be added to each tile on all sides +/// which increases the amount of +/// memory needed to denoise a tile. In case of tiling use withOverlapScratchSizeInBytes for scratch memory size. +/// If only full resolution images are denoised, withoutOverlapScratchSizeInBytes can be used which is always +/// smaller than withOverlapScratchSizeInBytes. +/// +/// 'outputWidth' and 'outputHeight' is the dimension of the image to be denoised (without overlap in case tiling +/// is being used). +/// 'outputWidth' and 'outputHeight' must be greater than or equal to the dimensions passed to optixDenoiserSetup. +/// +/// \param[in] denoiser +/// \param[in] outputWidth +/// \param[in] outputHeight +/// \param[out] returnSizes +OptixResult optixDenoiserComputeMemoryResources( const OptixDenoiser denoiser, + unsigned int outputWidth, + unsigned int outputHeight, + OptixDenoiserSizes* returnSizes ); + +/// Initializes the state required by the denoiser. +/// +/// 'inputWidth' and 'inputHeight' must include overlap on both sides of the image if tiling is being used. The overlap is +/// returned by #optixDenoiserComputeMemoryResources. +/// For subsequent calls to #optixDenoiserInvoke 'inputWidth' and 'inputHeight' are the maximum dimensions +/// of the input layers. Dimensions of the input layers passed to #optixDenoiserInvoke may be different in each +/// invocation however they always must be smaller than 'inputWidth' and 'inputHeight' passed to #optixDenoiserSetup. +/// +/// \param[in] denoiser +/// \param[in] stream +/// \param[in] inputWidth +/// \param[in] inputHeight +/// \param[in] denoiserState +/// \param[in] denoiserStateSizeInBytes +/// \param[in] scratch +/// \param[in] scratchSizeInBytes +OptixResult optixDenoiserSetup( OptixDenoiser denoiser, + CUstream stream, + unsigned int inputWidth, + unsigned int inputHeight, + CUdeviceptr denoiserState, + size_t denoiserStateSizeInBytes, + CUdeviceptr scratch, + size_t scratchSizeInBytes ); + +/// Invokes denoiser on a set of input data and produces at least one output image. +/// State memory must be available during the execution of the +/// denoiser (or until optixDenoiserSetup is called with a new state memory pointer). +/// Scratch memory passed is used only for the duration of this function. +/// Scratch and state memory sizes must have a size greater than or equal to the sizes as returned by +/// optixDenoiserComputeMemoryResources. +/// +/// 'inputOffsetX' and 'inputOffsetY' are pixel offsets in the 'inputLayers' image +/// specifying the beginning of the image without overlap. When denoising an entire image without tiling +/// there is no overlap and 'inputOffsetX' and 'inputOffsetY' must be zero. When denoising a tile which is +/// adjacent to one of the four sides of the entire image the corresponding offsets must also be zero since +/// there is no overlap at the side adjacent to the image border. +/// +/// 'guideLayer' provides additional information to the denoiser. When providing albedo and normal vector +/// guide images, the corresponding fields in the 'OptixDenoiserOptions' must be +/// enabled, see #optixDenoiserCreate. +/// 'guideLayer' must not be null. If a guide image in 'OptixDenoiserOptions' is not enabled, the +/// corresponding image in 'OptixDenoiserGuideLayer' is ignored. +/// +/// If OPTIX_DENOISER_MODEL_KIND_TEMPORAL or OPTIX_DENOISER_MODEL_KIND_TEMPORAL_AOV is selected, a 2d flow +/// image must be given in 'OptixDenoiserGuideLayer'. +/// It describes for each pixel the flow from the previous to the current frame (a 2d vector in pixel space). +/// The denoised beauty/AOV of the previous frame must be given in 'previousOutput'. +/// If this image is not available in the first frame of a sequence, the noisy beauty/AOV from the first frame +/// and zero flow vectors could be given as a substitute. +/// For non-temporal model kinds the flow image in 'OptixDenoiserGuideLayer' is ignored. +/// 'previousOutput' and +/// 'output' may refer to the same buffer, i.e. 'previousOutput' is first read by this function and later +/// overwritten with the denoised result. 'output' can be passed as 'previousOutput' to the next frame. +/// In other model kinds (not temporal) 'previousOutput' is ignored. +/// +/// The beauty layer must be given as the first entry in 'layers'. +/// In AOV type model kinds (OPTIX_DENOISER_MODEL_KIND_AOV or in user defined models implementing +/// kernel-prediction) additional layers for the AOV images can be given. +/// In each layer the noisy input image is given in 'input', the denoised output is written into the +/// 'output' image. input and output images may refer to the same buffer, with the restriction that +/// the pixel formats must be identical for input and output when the blend mode is selected (see +/// #OptixDenoiserParams). +/// +/// If OPTIX_DENOISER_MODEL_KIND_TEMPORAL or OPTIX_DENOISER_MODEL_KIND_TEMPORAL_AOV is selected, the denoised +/// image from the previous frame must be given in 'previousOutput' in the layer. 'previousOutput' and +/// 'output' may refer to the same buffer, i.e. 'previousOutput' is first read by this function and later +/// overwritten with the denoised result. 'output' can be passed as 'previousOutput' to the next frame. +/// In other model kinds (not temporal) 'previousOutput' is ignored. +/// +/// If OPTIX_DENOISER_MODEL_KIND_TEMPORAL or OPTIX_DENOISER_MODEL_KIND_TEMPORAL_AOV is selected, the +/// normal vector guide image must be given as 3d vectors in camera space. In the other models only +/// the x and y channels are used and other channels are ignored. +/// +/// \param[in] denoiser +/// \param[in] stream +/// \param[in] params +/// \param[in] denoiserState +/// \param[in] denoiserStateSizeInBytes +/// \param[in] guideLayer +/// \param[in] layers +/// \param[in] numLayers +/// \param[in] inputOffsetX +/// \param[in] inputOffsetY +/// \param[in] scratch +/// \param[in] scratchSizeInBytes +OptixResult optixDenoiserInvoke( OptixDenoiser denoiser, + CUstream stream, + const OptixDenoiserParams* params, + CUdeviceptr denoiserState, + size_t denoiserStateSizeInBytes, + const OptixDenoiserGuideLayer* guideLayer, + const OptixDenoiserLayer* layers, + unsigned int numLayers, + unsigned int inputOffsetX, + unsigned int inputOffsetY, + CUdeviceptr scratch, + size_t scratchSizeInBytes ); + +/// Computes the logarithmic average intensity of the given image. The returned value 'outputIntensity' +/// is multiplied with the RGB values of the input image/tile in optixDenoiserInvoke if given in the parameter +/// OptixDenoiserParams::hdrIntensity (otherwise 'hdrIntensity' must be a null pointer). This is useful for +/// denoising HDR images which are very dark or bright. +/// When denoising tiles the intensity of the entire image should be computed, i.e. not per tile to get +/// consistent results. +/// +/// For each RGB pixel in the inputImage the intensity is calculated and summed if it is greater than 1e-8f: +/// intensity = log(r * 0.212586f + g * 0.715170f + b * 0.072200f). +/// The function returns 0.18 / exp(sum of intensities / number of summed pixels). +/// More details could be found in the Reinhard tonemapping paper: +/// http://www.cmap.polytechnique.fr/~peyre/cours/x2005signal/hdr_photographic.pdf +/// +/// The size of scratch memory required can be queried with #optixDenoiserComputeMemoryResources. +/// +/// data type unsigned char is not supported for 'inputImage', it must be 3 or 4 component half/float. +/// +/// \param[in] denoiser +/// \param[in] stream +/// \param[in] inputImage +/// \param[out] outputIntensity single float +/// \param[in] scratch +/// \param[in] scratchSizeInBytes +OptixResult optixDenoiserComputeIntensity( OptixDenoiser denoiser, + CUstream stream, + const OptixImage2D* inputImage, + CUdeviceptr outputIntensity, + CUdeviceptr scratch, + size_t scratchSizeInBytes ); + +/// Compute average logarithmic for each of the first three channels for the given image. +/// When denoising tiles the intensity of the entire image should be computed, i.e. not per tile to get +/// consistent results. +/// +/// The size of scratch memory required can be queried with #optixDenoiserComputeMemoryResources. +/// +/// data type unsigned char is not supported for 'inputImage', it must be 3 or 4 component half/float. +/// +/// \param[in] denoiser +/// \param[in] stream +/// \param[in] inputImage +/// \param[out] outputAverageColor three floats +/// \param[in] scratch +/// \param[in] scratchSizeInBytes +OptixResult optixDenoiserComputeAverageColor( OptixDenoiser denoiser, + CUstream stream, + const OptixImage2D* inputImage, + CUdeviceptr outputAverageColor, + CUdeviceptr scratch, + size_t scratchSizeInBytes ); + +//@} + +#ifdef __cplusplus +} +#endif + +#include "optix_function_table.h" + +#endif // __optix_optix_7_host_h__ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_7_types.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_7_types.h new file mode 100644 index 00000000..394bf0b6 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_7_types.h @@ -0,0 +1,1977 @@ + +/* +* SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* SPDX-License-Identifier: LicenseRef-NvidiaProprietary +* +* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +* property and proprietary rights in and to this material, related +* documentation and any modifications thereto. Any use, reproduction, +* disclosure or distribution of this material and related documentation +* without an express license agreement from NVIDIA CORPORATION or +* its affiliates is strictly prohibited. +*/ +/// @file +/// @author NVIDIA Corporation +/// @brief OptiX public API header +/// +/// OptiX types include file -- defines types and enums used by the API. +/// For the math library routines include optix_math.h + +#if !defined( __OPTIX_INCLUDE_INTERNAL_HEADERS__ ) +#error("optix_7_types.h is an internal header file and must not be used directly. Please use optix_types.h, optix_host.h, optix_device.h or optix.h instead.") +#endif + +#ifndef __optix_optix_7_types_h__ +#define __optix_optix_7_types_h__ + +#if !defined(__CUDACC_RTC__) +#include /* for size_t */ +#endif + + + +/// \defgroup optix_types Types +/// \brief OptiX Types + +/** \addtogroup optix_types +@{ +*/ + +// This typedef should match the one in cuda.h in order to avoid compilation errors. +#if defined(_WIN64) || defined(__LP64__) +/// CUDA device pointer +typedef unsigned long long CUdeviceptr; +#else +/// CUDA device pointer +typedef unsigned int CUdeviceptr; +#endif + +/// Opaque type representing a device context +typedef struct OptixDeviceContext_t* OptixDeviceContext; + +/// Opaque type representing a module +typedef struct OptixModule_t* OptixModule; + +/// Opaque type representing a program group +typedef struct OptixProgramGroup_t* OptixProgramGroup; + +/// Opaque type representing a pipeline +typedef struct OptixPipeline_t* OptixPipeline; + +/// Opaque type representing a denoiser instance +typedef struct OptixDenoiser_t* OptixDenoiser; + +/// Opaque type representing a work task +typedef struct OptixTask_t* OptixTask; + +/// Traversable handle +typedef unsigned long long OptixTraversableHandle; + +/// Visibility mask +typedef unsigned int OptixVisibilityMask; + +/// Size of the SBT record headers. +#define OPTIX_SBT_RECORD_HEADER_SIZE ( (size_t)32 ) + +/// Alignment requirement for device pointers in OptixShaderBindingTable. +#define OPTIX_SBT_RECORD_ALIGNMENT 16ull + +/// Alignment requirement for output and temporay buffers for acceleration structures. +#define OPTIX_ACCEL_BUFFER_BYTE_ALIGNMENT 128ull + +/// Alignment requirement for OptixBuildInputInstanceArray::instances. +#define OPTIX_INSTANCE_BYTE_ALIGNMENT 16ull + +/// Alignment requirement for OptixBuildInputCustomPrimitiveArray::aabbBuffers +#define OPTIX_AABB_BUFFER_BYTE_ALIGNMENT 8ull + +/// Alignment requirement for OptixBuildInputTriangleArray::preTransform +#define OPTIX_GEOMETRY_TRANSFORM_BYTE_ALIGNMENT 16ull + +/// Alignment requirement for OptixStaticTransform, OptixMatrixMotionTransform, OptixSRTMotionTransform. +#define OPTIX_TRANSFORM_BYTE_ALIGNMENT 64ull + +/// Maximum number of registers allowed. Defaults to no explicit limit. +#define OPTIX_COMPILE_DEFAULT_MAX_REGISTER_COUNT 0 + +/// Maximum number of payload types allowed. +#define OPTIX_COMPILE_DEFAULT_MAX_PAYLOAD_TYPE_COUNT 8 + +/// Maximum number of payload values allowed. +#define OPTIX_COMPILE_DEFAULT_MAX_PAYLOAD_VALUE_COUNT 32 + + +/// Result codes returned from API functions +/// +/// All host side API functions return OptixResult with the exception of optixGetErrorName +/// and optixGetErrorString. When successful OPTIX_SUCCESS is returned. All return codes +/// except for OPTIX_SUCCESS should be assumed to be errors as opposed to a warning. +/// +/// \see #optixGetErrorName(), #optixGetErrorString() +typedef enum OptixResult +{ + OPTIX_SUCCESS = 0, + OPTIX_ERROR_INVALID_VALUE = 7001, + OPTIX_ERROR_HOST_OUT_OF_MEMORY = 7002, + OPTIX_ERROR_INVALID_OPERATION = 7003, + OPTIX_ERROR_FILE_IO_ERROR = 7004, + OPTIX_ERROR_INVALID_FILE_FORMAT = 7005, + OPTIX_ERROR_DISK_CACHE_INVALID_PATH = 7010, + OPTIX_ERROR_DISK_CACHE_PERMISSION_ERROR = 7011, + OPTIX_ERROR_DISK_CACHE_DATABASE_ERROR = 7012, + OPTIX_ERROR_DISK_CACHE_INVALID_DATA = 7013, + OPTIX_ERROR_LAUNCH_FAILURE = 7050, + OPTIX_ERROR_INVALID_DEVICE_CONTEXT = 7051, + OPTIX_ERROR_CUDA_NOT_INITIALIZED = 7052, + OPTIX_ERROR_VALIDATION_FAILURE = 7053, + OPTIX_ERROR_INVALID_PTX = 7200, + OPTIX_ERROR_INVALID_LAUNCH_PARAMETER = 7201, + OPTIX_ERROR_INVALID_PAYLOAD_ACCESS = 7202, + OPTIX_ERROR_INVALID_ATTRIBUTE_ACCESS = 7203, + OPTIX_ERROR_INVALID_FUNCTION_USE = 7204, + OPTIX_ERROR_INVALID_FUNCTION_ARGUMENTS = 7205, + OPTIX_ERROR_PIPELINE_OUT_OF_CONSTANT_MEMORY = 7250, + OPTIX_ERROR_PIPELINE_LINK_ERROR = 7251, + OPTIX_ERROR_ILLEGAL_DURING_TASK_EXECUTE = 7270, + OPTIX_ERROR_INTERNAL_COMPILER_ERROR = 7299, + OPTIX_ERROR_DENOISER_MODEL_NOT_SET = 7300, + OPTIX_ERROR_DENOISER_NOT_INITIALIZED = 7301, + OPTIX_ERROR_ACCEL_NOT_COMPATIBLE = 7400, + OPTIX_ERROR_PAYLOAD_TYPE_MISMATCH = 7500, + OPTIX_ERROR_PAYLOAD_TYPE_RESOLUTION_FAILED = 7501, + OPTIX_ERROR_PAYLOAD_TYPE_ID_INVALID = 7502, + OPTIX_ERROR_NOT_SUPPORTED = 7800, + OPTIX_ERROR_UNSUPPORTED_ABI_VERSION = 7801, + OPTIX_ERROR_FUNCTION_TABLE_SIZE_MISMATCH = 7802, + OPTIX_ERROR_INVALID_ENTRY_FUNCTION_OPTIONS = 7803, + OPTIX_ERROR_LIBRARY_NOT_FOUND = 7804, + OPTIX_ERROR_ENTRY_SYMBOL_NOT_FOUND = 7805, + OPTIX_ERROR_LIBRARY_UNLOAD_FAILURE = 7806, + OPTIX_ERROR_DEVICE_OUT_OF_MEMORY = 7807, + OPTIX_ERROR_CUDA_ERROR = 7900, + OPTIX_ERROR_INTERNAL_ERROR = 7990, + OPTIX_ERROR_UNKNOWN = 7999, +} OptixResult; + +/// Parameters used for #optixDeviceContextGetProperty() +/// +/// \see #optixDeviceContextGetProperty() +typedef enum OptixDeviceProperty +{ + /// Maximum value for OptixPipelineLinkOptions::maxTraceDepth. sizeof( unsigned int ) + OPTIX_DEVICE_PROPERTY_LIMIT_MAX_TRACE_DEPTH = 0x2001, + + /// Maximum value to pass into optixPipelineSetStackSize for parameter + /// maxTraversableGraphDepth.v sizeof( unsigned int ) + OPTIX_DEVICE_PROPERTY_LIMIT_MAX_TRAVERSABLE_GRAPH_DEPTH = 0x2002, + + /// The maximum number of primitives (over all build inputs) as input to a single + /// Geometry Acceleration Structure (GAS). sizeof( unsigned int ) + OPTIX_DEVICE_PROPERTY_LIMIT_MAX_PRIMITIVES_PER_GAS = 0x2003, + + /// The maximum number of instances (over all build inputs) as input to a single + /// Instance Acceleration Structure (IAS). sizeof( unsigned int ) + OPTIX_DEVICE_PROPERTY_LIMIT_MAX_INSTANCES_PER_IAS = 0x2004, + + /// The RT core version supported by the device (0 for no support, 10 for version + /// 1.0). sizeof( unsigned int ) + OPTIX_DEVICE_PROPERTY_RTCORE_VERSION = 0x2005, + + /// The maximum value for #OptixInstance::instanceId. sizeof( unsigned int ) + OPTIX_DEVICE_PROPERTY_LIMIT_MAX_INSTANCE_ID = 0x2006, + + /// The number of bits available for the #OptixInstance::visibilityMask. + /// Higher bits must be set to zero. sizeof( unsigned int ) + OPTIX_DEVICE_PROPERTY_LIMIT_NUM_BITS_INSTANCE_VISIBILITY_MASK = 0x2007, + + /// The maximum number of instances that can be added to a single Instance + /// Acceleration Structure (IAS). sizeof( unsigned int ) + OPTIX_DEVICE_PROPERTY_LIMIT_MAX_SBT_RECORDS_PER_GAS = 0x2008, + + /// The maximum value for #OptixInstance::sbtOffset. sizeof( unsigned int ) + OPTIX_DEVICE_PROPERTY_LIMIT_MAX_SBT_OFFSET = 0x2009, +} OptixDeviceProperty; + +/// Type of the callback function used for log messages. +/// +/// \param[in] level The log level indicates the severity of the message. See below for +/// possible values. +/// \param[in] tag A terse message category description (e.g., 'SCENE STAT'). +/// \param[in] message Null terminated log message (without newline at the end). +/// \param[in] cbdata Callback data that was provided with the callback pointer. +/// +/// It is the users responsibility to ensure thread safety within this function. +/// +/// The following log levels are defined. +/// +/// 0 disable Setting the callback level will disable all messages. The callback +/// function will not be called in this case. +/// 1 fatal A non-recoverable error. The context and/or OptiX itself might no longer +/// be in a usable state. +/// 2 error A recoverable error, e.g., when passing invalid call parameters. +/// 3 warning Hints that OptiX might not behave exactly as requested by the user or +/// may perform slower than expected. +/// 4 print Status or progress messages. +/// +/// Higher levels might occur. +/// +/// \see #optixDeviceContextSetLogCallback(), #OptixDeviceContextOptions +typedef void ( *OptixLogCallback )( unsigned int level, const char* tag, const char* message, void* cbdata ); + +/// Validation mode settings. +/// +/// When enabled, certain device code utilities will be enabled to provide as good debug and +/// error checking facilities as possible. +/// +/// +/// \see #optixDeviceContextCreate() +typedef enum OptixDeviceContextValidationMode +{ + OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_OFF = 0, + OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL = 0xFFFFFFFF +} OptixDeviceContextValidationMode; + +/// Parameters used for #optixDeviceContextCreate() +/// +/// \see #optixDeviceContextCreate() +typedef struct OptixDeviceContextOptions +{ + /// Function pointer used when OptiX wishes to generate messages + OptixLogCallback logCallbackFunction; + /// Pointer stored and passed to logCallbackFunction when a message is generated + void* logCallbackData; + /// Maximum callback level to generate message for (see #OptixLogCallback) + int logCallbackLevel; + /// Validation mode of context. + OptixDeviceContextValidationMode validationMode; +} OptixDeviceContextOptions; + +/// Flags used by #OptixBuildInputTriangleArray::flags +/// and #OptixBuildInput::flag +/// and #OptixBuildInputCustomPrimitiveArray::flags +typedef enum OptixGeometryFlags +{ + /// No flags set + OPTIX_GEOMETRY_FLAG_NONE = 0, + + /// Disables the invocation of the anyhit program. + /// Can be overridden by OPTIX_INSTANCE_FLAG_ENFORCE_ANYHIT and OPTIX_RAY_FLAG_ENFORCE_ANYHIT. + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT = 1u << 0, + + /// If set, an intersection with the primitive will trigger one and only one + /// invocation of the anyhit program. Otherwise, the anyhit program may be invoked + /// more than once. + OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL = 1u << 1, + + /// Prevent triangles from getting culled due to their orientation. + /// Effectively ignores ray flags + /// OPTIX_RAY_FLAG_CULL_BACK_FACING_TRIANGLES and OPTIX_RAY_FLAG_CULL_FRONT_FACING_TRIANGLES. + OPTIX_GEOMETRY_FLAG_DISABLE_TRIANGLE_FACE_CULLING = 1u << 2, + +} OptixGeometryFlags; + +/// Legacy type: A subset of the hit kinds for built-in primitive intersections. +/// It is preferred to use optixGetPrimitiveType(), together with +/// optixIsFrontFaceHit() or optixIsBackFaceHit(). +/// +/// \see #optixGetHitKind() +typedef enum OptixHitKind +{ + /// Ray hit the triangle on the front face + OPTIX_HIT_KIND_TRIANGLE_FRONT_FACE = 0xFE, + /// Ray hit the triangle on the back face + OPTIX_HIT_KIND_TRIANGLE_BACK_FACE = 0xFF +} OptixHitKind; + +/// Format of indices used int #OptixBuildInputTriangleArray::indexFormat. +typedef enum OptixIndicesFormat +{ + /// No indices, this format must only be used in combination with triangle soups, i.e., numIndexTriplets must be zero + OPTIX_INDICES_FORMAT_NONE = 0, + /// Three shorts + OPTIX_INDICES_FORMAT_UNSIGNED_SHORT3 = 0x2102, + /// Three ints + OPTIX_INDICES_FORMAT_UNSIGNED_INT3 = 0x2103 +} OptixIndicesFormat; + +/// Format of vertices used in #OptixBuildInputTriangleArray::vertexFormat. +typedef enum OptixVertexFormat +{ + OPTIX_VERTEX_FORMAT_NONE = 0, ///< No vertices + OPTIX_VERTEX_FORMAT_FLOAT3 = 0x2121, ///< Vertices are represented by three floats + OPTIX_VERTEX_FORMAT_FLOAT2 = 0x2122, ///< Vertices are represented by two floats + OPTIX_VERTEX_FORMAT_HALF3 = 0x2123, ///< Vertices are represented by three halfs + OPTIX_VERTEX_FORMAT_HALF2 = 0x2124, ///< Vertices are represented by two halfs + OPTIX_VERTEX_FORMAT_SNORM16_3 = 0x2125, + OPTIX_VERTEX_FORMAT_SNORM16_2 = 0x2126 +} OptixVertexFormat; + +/// Format of transform used in #OptixBuildInputTriangleArray::transformFormat. +typedef enum OptixTransformFormat +{ + OPTIX_TRANSFORM_FORMAT_NONE = 0, ///< no transform, default for zero initialization + OPTIX_TRANSFORM_FORMAT_MATRIX_FLOAT12 = 0x21E1, ///< 3x4 row major affine matrix +} OptixTransformFormat; + + +/// Triangle inputs +/// +/// \see #OptixBuildInput::triangleArray +typedef struct OptixBuildInputTriangleArray +{ + /// Points to host array of device pointers, one per motion step. Host array size must match the number of + /// motion keys as set in #OptixMotionOptions (or an array of size 1 if OptixMotionOptions::numKeys is set + /// to 0 or 1). Each per motion key device pointer must point to an array of vertices of the + /// triangles in the format as described by vertexFormat. The minimum alignment must match the natural + /// alignment of the type as specified in the vertexFormat, i.e., for OPTIX_VERTEX_FORMAT_FLOATX 4-byte, + /// for all others a 2-byte alignment. However, an 16-byte stride (and buffer alignment) is recommended for + /// vertices of format OPTIX_VERTEX_FORMAT_FLOAT3 for GAS build performance. + const CUdeviceptr* vertexBuffers; + + /// Number of vertices in each of buffer in OptixBuildInputTriangleArray::vertexBuffers. + unsigned int numVertices; + + /// \see #OptixVertexFormat + OptixVertexFormat vertexFormat; + + /// Stride between vertices. If set to zero, vertices are assumed to be tightly + /// packed and stride is inferred from vertexFormat. + unsigned int vertexStrideInBytes; + + /// Optional pointer to array of 16 or 32-bit int triplets, one triplet per triangle. + /// The minimum alignment must match the natural alignment of the type as specified in the indexFormat, i.e., + /// for OPTIX_INDICES_FORMAT_UNSIGNED_INT3 4-byte and for OPTIX_INDICES_FORMAT_UNSIGNED_SHORT3 a 2-byte alignment. + CUdeviceptr indexBuffer; + + /// Size of array in OptixBuildInputTriangleArray::indexBuffer. For build, needs to be zero if indexBuffer is \c nullptr. + unsigned int numIndexTriplets; + + /// \see #OptixIndicesFormat + OptixIndicesFormat indexFormat; + + /// Stride between triplets of indices. If set to zero, indices are assumed to be tightly + /// packed and stride is inferred from indexFormat. + unsigned int indexStrideInBytes; + + /// Optional pointer to array of floats + /// representing a 3x4 row major affine + /// transformation matrix. This pointer must be a multiple of OPTIX_GEOMETRY_TRANSFORM_BYTE_ALIGNMENT + CUdeviceptr preTransform; + + /// Array of flags, to specify flags per sbt record, + /// combinations of OptixGeometryFlags describing the + /// primitive behavior, size must match numSbtRecords + const unsigned int* flags; + + /// Number of sbt records available to the sbt index offset override. + unsigned int numSbtRecords; + + /// Device pointer to per-primitive local sbt index offset buffer. May be NULL. + /// Every entry must be in range [0,numSbtRecords-1]. + /// Size needs to be the number of primitives. + CUdeviceptr sbtIndexOffsetBuffer; + + /// Size of type of the sbt index offset. Needs to be 0, 1, 2 or 4 (8, 16 or 32 bit). + unsigned int sbtIndexOffsetSizeInBytes; + + /// Stride between the index offsets. If set to zero, the offsets are assumed to be tightly + /// packed and the stride matches the size of the type (sbtIndexOffsetSizeInBytes). + unsigned int sbtIndexOffsetStrideInBytes; + + /// Primitive index bias, applied in optixGetPrimitiveIndex(). + /// Sum of primitiveIndexOffset and number of triangles must not overflow 32bits. + unsigned int primitiveIndexOffset; + + /// \see #OptixTransformFormat + OptixTransformFormat transformFormat; + + +} OptixBuildInputTriangleArray; + +/// Builtin primitive types +/// +typedef enum OptixPrimitiveType +{ + /// Custom primitive. + OPTIX_PRIMITIVE_TYPE_CUSTOM = 0x2500, + /// B-spline curve of degree 2 with circular cross-section. + OPTIX_PRIMITIVE_TYPE_ROUND_QUADRATIC_BSPLINE = 0x2501, + /// B-spline curve of degree 3 with circular cross-section. + OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE = 0x2502, + /// Piecewise linear curve with circular cross-section. + OPTIX_PRIMITIVE_TYPE_ROUND_LINEAR = 0x2503, + /// CatmullRom curve with circular cross-section. + OPTIX_PRIMITIVE_TYPE_ROUND_CATMULLROM = 0x2504, + OPTIX_PRIMITIVE_TYPE_SPHERE = 0x2506, + /// Triangle. + OPTIX_PRIMITIVE_TYPE_TRIANGLE = 0x2531, +} OptixPrimitiveType; + +/// Builtin flags may be bitwise combined. +/// +/// \see #OptixPipelineCompileOptions::usesPrimitiveTypeFlags +typedef enum OptixPrimitiveTypeFlags +{ + /// Custom primitive. + OPTIX_PRIMITIVE_TYPE_FLAGS_CUSTOM = 1 << 0, + /// B-spline curve of degree 2 with circular cross-section. + OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_QUADRATIC_BSPLINE = 1 << 1, + /// B-spline curve of degree 3 with circular cross-section. + OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CUBIC_BSPLINE = 1 << 2, + /// Piecewise linear curve with circular cross-section. + OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_LINEAR = 1 << 3, + /// CatmullRom curve with circular cross-section. + OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CATMULLROM = 1 << 4, + OPTIX_PRIMITIVE_TYPE_FLAGS_SPHERE = 1 << 6, + /// Triangle. + OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE = 1 << 31, +} OptixPrimitiveTypeFlags; + +/// Curve end cap types, for non-linear curves +/// +typedef enum OptixCurveEndcapFlags +{ + /// Default end caps. Round end caps for linear, no end caps for quadratic/cubic. + OPTIX_CURVE_ENDCAP_DEFAULT = 0, + /// Flat end caps at both ends of quadratic/cubic curve segments. Not valid for linear. + OPTIX_CURVE_ENDCAP_ON = 1 << 0, +} OptixCurveEndcapFlags; + +/// Curve inputs +/// +/// A curve is a swept surface defined by a 3D spline curve and a varying width (radius). A curve (or "strand") of +/// degree d (3=cubic, 2=quadratic, 1=linear) is represented by N > d vertices and N width values, and comprises N - d segments. +/// Each segment is defined by d+1 consecutive vertices. Each curve may have a different number of vertices. +/// +/// OptiX describes the curve array as a list of curve segments. The primitive id is the segment number. +/// It is the user's responsibility to maintain a mapping between curves and curve segments. +/// Each index buffer entry i = indexBuffer[primid] specifies the start of a curve segment, +/// represented by d+1 consecutive vertices in the vertex buffer, +/// and d+1 consecutive widths in the width buffer. Width is interpolated the same +/// way vertices are interpolated, that is, using the curve basis. +/// +/// Each curves build input has only one SBT record. +/// To create curves with different materials in the same BVH, use multiple build inputs. +/// +/// \see #OptixBuildInput::curveArray +typedef struct OptixBuildInputCurveArray +{ + /// Curve degree and basis + /// \see #OptixPrimitiveType + OptixPrimitiveType curveType; + /// Number of primitives. Each primitive is a polynomial curve segment. + unsigned int numPrimitives; + + /// Pointer to host array of device pointers, one per motion step. Host array size must match number of + /// motion keys as set in #OptixMotionOptions (or an array of size 1 if OptixMotionOptions::numKeys is set + /// to 1). Each per-motion-key device pointer must point to an array of floats (the vertices of the + /// curves). + const CUdeviceptr* vertexBuffers; + /// Number of vertices in each buffer in vertexBuffers. + unsigned int numVertices; + /// Stride between vertices. If set to zero, vertices are assumed to be tightly + /// packed and stride is sizeof( float3 ). + unsigned int vertexStrideInBytes; + + /// Parallel to vertexBuffers: a device pointer per motion step, each with numVertices float values, + /// specifying the curve width (radius) corresponding to each vertex. + const CUdeviceptr* widthBuffers; + /// Stride between widths. If set to zero, widths are assumed to be tightly + /// packed and stride is sizeof( float ). + unsigned int widthStrideInBytes; + + /// Reserved for future use. + const CUdeviceptr* normalBuffers; + /// Reserved for future use. + unsigned int normalStrideInBytes; + + /// Device pointer to array of unsigned ints, one per curve segment. + /// This buffer is required (unlike for OptixBuildInputTriangleArray). + /// Each index is the start of degree+1 consecutive vertices in vertexBuffers, + /// and corresponding widths in widthBuffers and normals in normalBuffers. + /// These define a single segment. Size of array is numPrimitives. + CUdeviceptr indexBuffer; + /// Stride between indices. If set to zero, indices are assumed to be tightly + /// packed and stride is sizeof( unsigned int ). + unsigned int indexStrideInBytes; + + /// Combination of OptixGeometryFlags describing the + /// primitive behavior. + unsigned int flag; + + /// Primitive index bias, applied in optixGetPrimitiveIndex(). + /// Sum of primitiveIndexOffset and number of primitives must not overflow 32bits. + unsigned int primitiveIndexOffset; + + /// End cap flags, see OptixCurveEndcapFlags + unsigned int endcapFlags; +} OptixBuildInputCurveArray; + +/// Sphere inputs +/// +/// A sphere is defined by a center point and a radius. +/// Each center point is represented by a vertex in the vertex buffer. +/// There is either a single radius for all spheres, or the radii are represented by entries in the radius buffer. +/// +/// The vertex buffers and radius buffers point to a host array of device pointers, one per motion step. +/// Host array size must match the number of motion keys as set in #OptixMotionOptions (or an array of size 1 if OptixMotionOptions::numKeys is set +/// to 0 or 1). Each per motion key device pointer must point to an array of vertices corresponding to the center points of the spheres, or +/// an array of 1 or N radii. Format OPTIX_VERTEX_FORMAT_FLOAT3 is used for vertices, OPTIX_VERTEX_FORMAT_FLOAT for radii. +/// +/// \see #OptixBuildInput::sphereArray +typedef struct OptixBuildInputSphereArray +{ + /// Pointer to host array of device pointers, one per motion step. Host array size must match number of + /// motion keys as set in #OptixMotionOptions (or an array of size 1 if OptixMotionOptions::numKeys is set + /// to 1). Each per-motion-key device pointer must point to an array of floats (the center points of + /// the spheres). + const CUdeviceptr* vertexBuffers; + + /// Stride between vertices. If set to zero, vertices are assumed to be tightly + /// packed and stride is sizeof( float3 ). + unsigned int vertexStrideInBytes; + /// Number of vertices in each buffer in vertexBuffers. + unsigned int numVertices; + + /// Parallel to vertexBuffers: a device pointer per motion step, each with numRadii float values, + /// specifying the sphere radius corresponding to each vertex. + const CUdeviceptr* radiusBuffers; + /// Stride between radii. If set to zero, widths are assumed to be tightly + /// packed and stride is sizeof( float ). + unsigned int radiusStrideInBytes; + /// Boolean value indicating whether a single radius per radius buffer is used, + /// or the number of radii in radiusBuffers equals numVertices. + int singleRadius; + + /// Array of flags, to specify flags per sbt record, + /// combinations of OptixGeometryFlags describing the + /// primitive behavior, size must match numSbtRecords + const unsigned int* flags; + + /// Number of sbt records available to the sbt index offset override. + unsigned int numSbtRecords; + /// Device pointer to per-primitive local sbt index offset buffer. May be NULL. + /// Every entry must be in range [0,numSbtRecords-1]. + /// Size needs to be the number of primitives. + CUdeviceptr sbtIndexOffsetBuffer; + /// Size of type of the sbt index offset. Needs to be 0, 1, 2 or 4 (8, 16 or 32 bit). + unsigned int sbtIndexOffsetSizeInBytes; + /// Stride between the sbt index offsets. If set to zero, the offsets are assumed to be tightly + /// packed and the stride matches the size of the type (sbtIndexOffsetSizeInBytes). + unsigned int sbtIndexOffsetStrideInBytes; + + /// Primitive index bias, applied in optixGetPrimitiveIndex(). + /// Sum of primitiveIndexOffset and number of primitives must not overflow 32bits. + unsigned int primitiveIndexOffset; +} OptixBuildInputSphereArray; + +/// AABB inputs +typedef struct OptixAabb +{ + float minX; ///< Lower extent in X direction. + float minY; ///< Lower extent in Y direction. + float minZ; ///< Lower extent in Z direction. + float maxX; ///< Upper extent in X direction. + float maxY; ///< Upper extent in Y direction. + float maxZ; ///< Upper extent in Z direction. +} OptixAabb; + +/// Custom primitive inputs +/// +/// \see #OptixBuildInput::customPrimitiveArray +typedef struct OptixBuildInputCustomPrimitiveArray +{ + /// Points to host array of device pointers to AABBs (type OptixAabb), one per motion step. + /// Host array size must match number of motion keys as set in OptixMotionOptions (or an array of size 1 + /// if OptixMotionOptions::numKeys is set to 1). + /// Each device pointer must be a multiple of OPTIX_AABB_BUFFER_BYTE_ALIGNMENT. + const CUdeviceptr* aabbBuffers; + + /// Number of primitives in each buffer (i.e., per motion step) in + /// #OptixBuildInputCustomPrimitiveArray::aabbBuffers. + unsigned int numPrimitives; + + /// Stride between AABBs (per motion key). If set to zero, the aabbs are assumed to be tightly + /// packed and the stride is assumed to be sizeof( OptixAabb ). + /// If non-zero, the value must be a multiple of OPTIX_AABB_BUFFER_BYTE_ALIGNMENT. + unsigned int strideInBytes; + + /// Array of flags, to specify flags per sbt record, + /// combinations of OptixGeometryFlags describing the + /// primitive behavior, size must match numSbtRecords + const unsigned int* flags; + + /// Number of sbt records available to the sbt index offset override. + unsigned int numSbtRecords; + + /// Device pointer to per-primitive local sbt index offset buffer. May be NULL. + /// Every entry must be in range [0,numSbtRecords-1]. + /// Size needs to be the number of primitives. + CUdeviceptr sbtIndexOffsetBuffer; + + /// Size of type of the sbt index offset. Needs to be 0, 1, 2 or 4 (8, 16 or 32 bit). + unsigned int sbtIndexOffsetSizeInBytes; + + /// Stride between the index offsets. If set to zero, the offsets are assumed to be tightly + /// packed and the stride matches the size of the type (sbtIndexOffsetSizeInBytes). + unsigned int sbtIndexOffsetStrideInBytes; + + /// Primitive index bias, applied in optixGetPrimitiveIndex(). + /// Sum of primitiveIndexOffset and number of primitive must not overflow 32bits. + unsigned int primitiveIndexOffset; +} OptixBuildInputCustomPrimitiveArray; + +/// Instance and instance pointer inputs +/// +/// \see #OptixBuildInput::instanceArray +typedef struct OptixBuildInputInstanceArray +{ + /// If OptixBuildInput::type is OPTIX_BUILD_INPUT_TYPE_INSTANCE_POINTERS instances and + /// aabbs should be interpreted as arrays of pointers instead of arrays of structs. + /// + /// This pointer must be a multiple of OPTIX_INSTANCE_BYTE_ALIGNMENT if + /// OptixBuildInput::type is OPTIX_BUILD_INPUT_TYPE_INSTANCES. The array elements must + /// be a multiple of OPTIX_INSTANCE_BYTE_ALIGNMENT if OptixBuildInput::type is + /// OPTIX_BUILD_INPUT_TYPE_INSTANCE_POINTERS. + CUdeviceptr instances; + + /// Number of elements in #OptixBuildInputInstanceArray::instances. + unsigned int numInstances; + +} OptixBuildInputInstanceArray; + +/// Enum to distinguish the different build input types. +/// +/// \see #OptixBuildInput::type +typedef enum OptixBuildInputType +{ + /// Triangle inputs. \see #OptixBuildInputTriangleArray + OPTIX_BUILD_INPUT_TYPE_TRIANGLES = 0x2141, + /// Custom primitive inputs. \see #OptixBuildInputCustomPrimitiveArray + OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES = 0x2142, + /// Instance inputs. \see #OptixBuildInputInstanceArray + OPTIX_BUILD_INPUT_TYPE_INSTANCES = 0x2143, + /// Instance pointer inputs. \see #OptixBuildInputInstanceArray + OPTIX_BUILD_INPUT_TYPE_INSTANCE_POINTERS = 0x2144, + /// Curve inputs. \see #OptixBuildInputCurveArray + OPTIX_BUILD_INPUT_TYPE_CURVES = 0x2145, + /// Sphere inputs. \see #OptixBuildInputSphereArray + OPTIX_BUILD_INPUT_TYPE_SPHERES = 0x2146 +} OptixBuildInputType; + +/// Build inputs. +/// +/// All of them support motion and the size of the data arrays needs to match the number of motion steps +/// +/// \see #optixAccelComputeMemoryUsage(), #optixAccelBuild() +typedef struct OptixBuildInput +{ + /// The type of the build input. + OptixBuildInputType type; + + union + { + /// Triangle inputs. + OptixBuildInputTriangleArray triangleArray; + /// Curve inputs. + OptixBuildInputCurveArray curveArray; + /// Sphere inputs. + OptixBuildInputSphereArray sphereArray; + /// Custom primitive inputs. + OptixBuildInputCustomPrimitiveArray customPrimitiveArray; + /// Instance and instance pointer inputs. + OptixBuildInputInstanceArray instanceArray; + char pad[1024]; + }; +} OptixBuildInput; + +// Some 32-bit tools use this header. This static_assert fails for them because +// the default enum size is 4 bytes, rather than 8, under 32-bit compilers. +// This #ifndef allows them to disable the static assert. + +// TODO Define a static assert for C/pre-C++-11 +#if defined( __cplusplus ) && __cplusplus >= 201103L +static_assert( sizeof( OptixBuildInput ) == 8 + 1024, "OptixBuildInput has wrong size" ); +#endif + +/// Flags set on the #OptixInstance::flags. +/// +/// These can be or'ed together to combine multiple flags. +typedef enum OptixInstanceFlags +{ + /// No special flag set + OPTIX_INSTANCE_FLAG_NONE = 0, + + /// Prevent triangles from getting culled due to their orientation. + /// Effectively ignores ray flags + /// OPTIX_RAY_FLAG_CULL_BACK_FACING_TRIANGLES and OPTIX_RAY_FLAG_CULL_FRONT_FACING_TRIANGLES. + OPTIX_INSTANCE_FLAG_DISABLE_TRIANGLE_FACE_CULLING = 1u << 0, + + /// Flip triangle orientation. + /// This affects front/backface culling as well as the reported face in case of a hit. + OPTIX_INSTANCE_FLAG_FLIP_TRIANGLE_FACING = 1u << 1, + + /// Disable anyhit programs for all geometries of the instance. + /// Can be overridden by OPTIX_RAY_FLAG_ENFORCE_ANYHIT. + /// This flag is mutually exclusive with OPTIX_INSTANCE_FLAG_ENFORCE_ANYHIT. + OPTIX_INSTANCE_FLAG_DISABLE_ANYHIT = 1u << 2, + + /// Enables anyhit programs for all geometries of the instance. + /// Overrides OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT + /// Can be overridden by OPTIX_RAY_FLAG_DISABLE_ANYHIT. + /// This flag is mutually exclusive with OPTIX_INSTANCE_FLAG_DISABLE_ANYHIT. + OPTIX_INSTANCE_FLAG_ENFORCE_ANYHIT = 1u << 3, + + + +} OptixInstanceFlags; + +/// Instances +/// +/// \see #OptixBuildInputInstanceArray::instances +typedef struct OptixInstance +{ + /// affine object-to-world transformation as 3x4 matrix in row-major layout + float transform[12]; + + /// Application supplied ID. The maximal ID can be queried using OPTIX_DEVICE_PROPERTY_LIMIT_MAX_INSTANCE_ID. + unsigned int instanceId; + + /// SBT record offset. Will only be used for instances of geometry acceleration structure (GAS) objects. + /// Needs to be set to 0 for instances of instance acceleration structure (IAS) objects. The maximal SBT offset + /// can be queried using OPTIX_DEVICE_PROPERTY_LIMIT_MAX_INSTANCE_SBT_OFFSET. + unsigned int sbtOffset; + + /// Visibility mask. If rayMask & instanceMask == 0 the instance is culled. The number of available bits can be + /// queried using OPTIX_DEVICE_PROPERTY_LIMIT_NUM_BITS_INSTANCE_VISIBILITY_MASK. + unsigned int visibilityMask; + + /// Any combination of OptixInstanceFlags is allowed. + unsigned int flags; + + /// Set with an OptixTraversableHandle. + OptixTraversableHandle traversableHandle; + + /// round up to 80-byte, to ensure 16-byte alignment + unsigned int pad[2]; +} OptixInstance; + +/// Builder Options +/// +/// Used for #OptixAccelBuildOptions::buildFlags. Can be or'ed together. +typedef enum OptixBuildFlags +{ + /// No special flags set. + OPTIX_BUILD_FLAG_NONE = 0, + + /// Allow updating the build with new vertex positions with subsequent calls to + /// optixAccelBuild. + OPTIX_BUILD_FLAG_ALLOW_UPDATE = 1u << 0, + + OPTIX_BUILD_FLAG_ALLOW_COMPACTION = 1u << 1, + + OPTIX_BUILD_FLAG_PREFER_FAST_TRACE = 1u << 2, + + OPTIX_BUILD_FLAG_PREFER_FAST_BUILD = 1u << 3, + + /// Allow random access to build input vertices + /// See optixGetTriangleVertexData + /// optixGetLinearCurveVertexData + /// optixGetQuadraticBSplineVertexData + /// optixGetCubicBSplineVertexData + /// optixGetCatmullRomVertexData + /// optixGetSphereData + OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS = 1u << 4, + + /// Allow random access to instances + /// See optixGetInstanceTraversableFromIAS + OPTIX_BUILD_FLAG_ALLOW_RANDOM_INSTANCE_ACCESS = 1u << 5, + +} OptixBuildFlags; + + + + +/// Enum to specify the acceleration build operation. +/// +/// Used in OptixAccelBuildOptions, which is then passed to optixAccelBuild and +/// optixAccelComputeMemoryUsage, this enum indicates whether to do a build or an update +/// of the acceleration structure. +/// +/// Acceleration structure updates utilize the same acceleration structure, but with +/// updated bounds. Updates are typically much faster than builds, however, large +/// perturbations can degrade the quality of the acceleration structure. +/// +/// \see #optixAccelComputeMemoryUsage(), #optixAccelBuild(), #OptixAccelBuildOptions +typedef enum OptixBuildOperation +{ + /// Perform a full build operation + OPTIX_BUILD_OPERATION_BUILD = 0x2161, + /// Perform an update using new bounds + OPTIX_BUILD_OPERATION_UPDATE = 0x2162, +} OptixBuildOperation; + +/// Enum to specify motion flags. +/// +/// \see #OptixMotionOptions::flags. +typedef enum OptixMotionFlags +{ + OPTIX_MOTION_FLAG_NONE = 0, + OPTIX_MOTION_FLAG_START_VANISH = 1u << 0, + OPTIX_MOTION_FLAG_END_VANISH = 1u << 1 +} OptixMotionFlags; + +/// Motion options +/// +/// \see #OptixAccelBuildOptions::motionOptions, #OptixMatrixMotionTransform::motionOptions, +/// #OptixSRTMotionTransform::motionOptions +typedef struct OptixMotionOptions +{ + /// If numKeys > 1, motion is enabled. timeBegin, + /// timeEnd and flags are all ignored when motion is disabled. + unsigned short numKeys; + + /// Combinations of #OptixMotionFlags + unsigned short flags; + + /// Point in time where motion starts. + float timeBegin; + + /// Point in time where motion ends. + float timeEnd; +} OptixMotionOptions; + +/// Build options for acceleration structures. +/// +/// \see #optixAccelComputeMemoryUsage(), #optixAccelBuild() +typedef struct OptixAccelBuildOptions +{ + /// Combinations of OptixBuildFlags + unsigned int buildFlags; + + /// If OPTIX_BUILD_OPERATION_UPDATE the output buffer is assumed to contain the result + /// of a full build with OPTIX_BUILD_FLAG_ALLOW_UPDATE set and using the same number of + /// primitives. It is updated incrementally to reflect the current position of the + /// primitives. + OptixBuildOperation operation; + + /// Options for motion. + OptixMotionOptions motionOptions; +} OptixAccelBuildOptions; + +/// Struct for querying builder allocation requirements. +/// +/// Once queried the sizes should be used to allocate device memory of at least these sizes. +/// +/// \see #optixAccelComputeMemoryUsage() +typedef struct OptixAccelBufferSizes +{ + /// The size in bytes required for the outputBuffer parameter to optixAccelBuild when + /// doing a build (OPTIX_BUILD_OPERATION_BUILD). + size_t outputSizeInBytes; + + /// The size in bytes required for the tempBuffer paramter to optixAccelBuild when + /// doing a build (OPTIX_BUILD_OPERATION_BUILD). + size_t tempSizeInBytes; + + /// The size in bytes required for the tempBuffer parameter to optixAccelBuild + /// when doing an update (OPTIX_BUILD_OPERATION_UPDATE). This value can be different + /// than tempSizeInBytes used for a full build. Only non-zero if + /// OPTIX_BUILD_FLAG_ALLOW_UPDATE flag is set in OptixAccelBuildOptions. + size_t tempUpdateSizeInBytes; +} OptixAccelBufferSizes; + +/// Properties which can be emitted during acceleration structure build. +/// +/// \see #OptixAccelEmitDesc::type. +typedef enum OptixAccelPropertyType +{ + /// Size of a compacted acceleration structure. The device pointer points to a uint64. + OPTIX_PROPERTY_TYPE_COMPACTED_SIZE = 0x2181, + + /// OptixAabb * numMotionSteps + OPTIX_PROPERTY_TYPE_AABBS = 0x2182, +} OptixAccelPropertyType; + +/// Specifies a type and output destination for emitted post-build properties. +/// +/// \see #optixAccelBuild() +typedef struct OptixAccelEmitDesc +{ + /// Output buffer for the properties + CUdeviceptr result; + + /// Requested property + OptixAccelPropertyType type; +} OptixAccelEmitDesc; + +/// Used to store information related to relocation of acceleration structures. +/// +/// \see #optixAccelGetRelocationInfo(), #optixAccelCheckRelocationCompatibility(), #optixAccelRelocate() +typedef struct OptixAccelRelocationInfo +{ + /// Opaque data, used internally, should not be modified + unsigned long long info[4]; +} OptixAccelRelocationInfo; + +/// Static transform +/// +/// The device address of instances of this type must be a multiple of OPTIX_TRANSFORM_BYTE_ALIGNMENT. +/// +/// \see #optixConvertPointerToTraversableHandle() +typedef struct OptixStaticTransform +{ + /// The traversable transformed by this transformation + OptixTraversableHandle child; + + /// Padding to make the transformations 16 byte aligned + unsigned int pad[2]; + + /// Affine object-to-world transformation as 3x4 matrix in row-major layout + float transform[12]; + + /// Affine world-to-object transformation as 3x4 matrix in row-major layout + /// Must be the inverse of the transform matrix + float invTransform[12]; +} OptixStaticTransform; + +/// Represents a matrix motion transformation. +/// +/// The device address of instances of this type must be a multiple of OPTIX_TRANSFORM_BYTE_ALIGNMENT. +/// +/// This struct, as defined here, handles only N=2 motion keys due to the fixed array length of its transform member. +/// The following example shows how to create instances for an arbitrary number N of motion keys: +/// +/// \code +/// float matrixData[N][12]; +/// ... // setup matrixData +/// +/// size_t transformSizeInBytes = sizeof( OptixMatrixMotionTransform ) + ( N-2 ) * 12 * sizeof( float ); +/// OptixMatrixMotionTransform* matrixMoptionTransform = (OptixMatrixMotionTransform*) malloc( transformSizeInBytes ); +/// memset( matrixMoptionTransform, 0, transformSizeInBytes ); +/// +/// ... // setup other members of matrixMoptionTransform +/// matrixMoptionTransform->motionOptions.numKeys/// = N; +/// memcpy( matrixMoptionTransform->transform, matrixData, N * 12 * sizeof( float ) ); +/// +/// ... // copy matrixMoptionTransform to device memory +/// free( matrixMoptionTransform ) +/// \endcode +/// +/// \see #optixConvertPointerToTraversableHandle() +typedef struct OptixMatrixMotionTransform +{ + /// The traversable that is transformed by this transformation + OptixTraversableHandle child; + + /// The motion options for this transformation + OptixMotionOptions motionOptions; + + /// Padding to make the transformation 16 byte aligned + unsigned int pad[3]; + + /// Affine object-to-world transformation as 3x4 matrix in row-major layout + float transform[2][12]; +} OptixMatrixMotionTransform; + +/// Represents an SRT transformation. +/// +/// An SRT transformation can represent a smooth rotation with fewer motion keys than a matrix transformation. Each +/// motion key is constructed from elements taken from a matrix S, a quaternion R, and a translation T. +/// +/// The scaling matrix +/// \f$S = \begin{bmatrix} sx & a & b & pvx \\ 0 & sy & c & pvy \\ 0 & 0 & sz & pvz \end{bmatrix}\f$ +// [ sx a b pvx ] +// S = [ 0 sy c pvy ] +// [ 0 0 sz pvz ] +/// defines an affine transformation that can include scale, shear, and a translation. +/// The translation allows to define the pivot point for the subsequent rotation. +/// +/// The quaternion R = [ qx, qy, qz, qw ] describes a rotation with angular component qw = cos(theta/2) and other +/// components [ qx, qy, qz ] = sin(theta/2) * [ ax, ay, az ] where the axis [ ax, ay, az ] is normalized. +/// +/// The translation matrix +/// \f$T = \begin{bmatrix} 1 & 0 & 0 & tx \\ 0 & 1 & 0 & ty \\ 0 & 0 & 1 & tz \end{bmatrix}\f$ +// [ 1 0 0 tx ] +// T = [ 0 1 0 ty ] +// [ 0 0 1 tz ] +/// defines another translation that is applied after the rotation. Typically, this translation includes +/// the inverse translation from the matrix S to reverse the translation for the pivot point for R. +/// +/// To obtain the effective transformation at time t, the elements of the components of S, R, and T will be interpolated +/// linearly. The components are then multiplied to obtain the combined transformation C = T * R * S. The transformation +/// C is the effective object-to-world transformations at time t, and C^(-1) is the effective world-to-object +/// transformation at time t. +/// +/// \see #OptixSRTMotionTransform::srtData, #optixConvertPointerToTraversableHandle() +typedef struct OptixSRTData +{ + /// \name Parameters describing the SRT transformation + /// @{ + float sx, a, b, pvx, sy, c, pvy, sz, pvz, qx, qy, qz, qw, tx, ty, tz; + /// @} +} OptixSRTData; + +// TODO Define a static assert for C/pre-C++-11 +#if defined( __cplusplus ) && __cplusplus >= 201103L +static_assert( sizeof( OptixSRTData ) == 16 * 4, "OptixSRTData has wrong size" ); +#endif + +/// Represents an SRT motion transformation. +/// +/// The device address of instances of this type must be a multiple of OPTIX_TRANSFORM_BYTE_ALIGNMENT. +/// +/// This struct, as defined here, handles only N=2 motion keys due to the fixed array length of its srtData member. +/// The following example shows how to create instances for an arbitrary number N of motion keys: +/// +/// \code +/// OptixSRTData srtData[N]; +/// ... // setup srtData +/// +/// size_t transformSizeInBytes = sizeof( OptixSRTMotionTransform ) + ( N-2 ) * sizeof( OptixSRTData ); +/// OptixSRTMotionTransform* srtMotionTransform = (OptixSRTMotionTransform*) malloc( transformSizeInBytes ); +/// memset( srtMotionTransform, 0, transformSizeInBytes ); +/// +/// ... // setup other members of srtMotionTransform +/// srtMotionTransform->motionOptions.numKeys = N; +/// memcpy( srtMotionTransform->srtData, srtData, N * sizeof( OptixSRTData ) ); +/// +/// ... // copy srtMotionTransform to device memory +/// free( srtMotionTransform ) +/// \endcode +/// +/// \see #optixConvertPointerToTraversableHandle() +typedef struct OptixSRTMotionTransform +{ + /// The traversable transformed by this transformation + OptixTraversableHandle child; + + /// The motion options for this transformation + OptixMotionOptions motionOptions; + + /// Padding to make the SRT data 16 byte aligned + unsigned int pad[3]; + + /// The actual SRT data describing the transformation + OptixSRTData srtData[2]; +} OptixSRTMotionTransform; + +// TODO Define a static assert for C/pre-C++-11 +#if defined( __cplusplus ) && __cplusplus >= 201103L +static_assert( sizeof( OptixSRTMotionTransform ) == 8 + 12 + 12 + 2 * 16 * 4, "OptixSRTMotionTransform has wrong size" ); +#endif + +/// Traversable Handles +/// +/// \see #optixConvertPointerToTraversableHandle() +typedef enum OptixTraversableType +{ + /// Static transforms. \see #OptixStaticTransform + OPTIX_TRAVERSABLE_TYPE_STATIC_TRANSFORM = 0x21C1, + /// Matrix motion transform. \see #OptixMatrixMotionTransform + OPTIX_TRAVERSABLE_TYPE_MATRIX_MOTION_TRANSFORM = 0x21C2, + /// SRT motion transform. \see #OptixSRTMotionTransform + OPTIX_TRAVERSABLE_TYPE_SRT_MOTION_TRANSFORM = 0x21C3, +} OptixTraversableType; + +/// Pixel formats used by the denoiser. +/// +/// \see #OptixImage2D::format +typedef enum OptixPixelFormat +{ + OPTIX_PIXEL_FORMAT_HALF2 = 0x2207, ///< two halfs, XY + OPTIX_PIXEL_FORMAT_HALF3 = 0x2201, ///< three halfs, RGB + OPTIX_PIXEL_FORMAT_HALF4 = 0x2202, ///< four halfs, RGBA + OPTIX_PIXEL_FORMAT_FLOAT2 = 0x2208, ///< two floats, XY + OPTIX_PIXEL_FORMAT_FLOAT3 = 0x2203, ///< three floats, RGB + OPTIX_PIXEL_FORMAT_FLOAT4 = 0x2204, ///< four floats, RGBA + OPTIX_PIXEL_FORMAT_UCHAR3 = 0x2205, ///< three unsigned chars, RGB + OPTIX_PIXEL_FORMAT_UCHAR4 = 0x2206, ///< four unsigned chars, RGBA + OPTIX_PIXEL_FORMAT_INTERNAL_GUIDE_LAYER = 0x2209, ///< internal format +} OptixPixelFormat; + +/// Image descriptor used by the denoiser. +/// +/// \see #optixDenoiserInvoke(), #optixDenoiserComputeIntensity() +typedef struct OptixImage2D +{ + /// Pointer to the actual pixel data. + CUdeviceptr data; + /// Width of the image (in pixels) + unsigned int width; + /// Height of the image (in pixels) + unsigned int height; + /// Stride between subsequent rows of the image (in bytes). + unsigned int rowStrideInBytes; + /// Stride between subsequent pixels of the image (in bytes). + /// If set to 0, dense packing (no gaps) is assumed. + /// For pixel format OPTIX_PIXEL_FORMAT_INTERNAL_GUIDE_LAYER it must be set to + /// at least OptixDenoiserSizes::internalGuideLayerSizeInBytes. + unsigned int pixelStrideInBytes; + /// Pixel format. + OptixPixelFormat format; +} OptixImage2D; + +/// Model kind used by the denoiser. +/// +/// \see #optixDenoiserCreate +typedef enum OptixDenoiserModelKind +{ + /// Use the built-in model appropriate for low dynamic range input. + OPTIX_DENOISER_MODEL_KIND_LDR = 0x2322, + + /// Use the built-in model appropriate for high dynamic range input. + OPTIX_DENOISER_MODEL_KIND_HDR = 0x2323, + + /// Use the built-in model appropriate for high dynamic range input and support for AOVs + OPTIX_DENOISER_MODEL_KIND_AOV = 0x2324, + + /// Use the built-in model appropriate for high dynamic range input, temporally stable + OPTIX_DENOISER_MODEL_KIND_TEMPORAL = 0x2325, + + /// Use the built-in model appropriate for high dynamic range input and support for AOVs, temporally stable + OPTIX_DENOISER_MODEL_KIND_TEMPORAL_AOV = 0x2326, + + /// Use the built-in model appropriate for high dynamic range input and support for AOVs, upscaling 2x + OPTIX_DENOISER_MODEL_KIND_UPSCALE2X = 0x2327, + + /// Use the built-in model appropriate for high dynamic range input and support for AOVs, upscaling 2x, + /// temporally stable + OPTIX_DENOISER_MODEL_KIND_TEMPORAL_UPSCALE2X = 0x2328, +} OptixDenoiserModelKind; + +/// Options used by the denoiser +/// +/// \see #optixDenoiserCreate() +typedef struct OptixDenoiserOptions +{ + // if nonzero, albedo image must be given in OptixDenoiserGuideLayer + unsigned int guideAlbedo; + + // if nonzero, normal image must be given in OptixDenoiserGuideLayer + unsigned int guideNormal; +} OptixDenoiserOptions; + +/// Guide layer for the denoiser +/// +/// \see #optixDenoiserInvoke() +typedef struct OptixDenoiserGuideLayer +{ + // albedo/bsdf image + OptixImage2D albedo; + + // normal vector image (2d or 3d pixel format) + OptixImage2D normal; + + // 2d flow image, pixel flow from previous to current frame for each pixel + OptixImage2D flow; + + OptixImage2D previousOutputInternalGuideLayer; + OptixImage2D outputInternalGuideLayer; +} OptixDenoiserGuideLayer; + +/// Input/Output layers for the denoiser +/// +/// \see #optixDenoiserInvoke() +typedef struct OptixDenoiserLayer +{ + // input image (beauty or AOV) + OptixImage2D input; + + // denoised output image from previous frame if temporal model kind selected + OptixImage2D previousOutput; + + // denoised output for given input + OptixImage2D output; +} OptixDenoiserLayer; + +/// Various parameters used by the denoiser +/// +/// \see #optixDenoiserInvoke() +/// \see #optixDenoiserComputeIntensity() +/// \see #optixDenoiserComputeAverageColor() +typedef enum OptixDenoiserAlphaMode +{ + /// Copy alpha (if present) from input layer, no denoising. + OPTIX_DENOISER_ALPHA_MODE_COPY = 0, + + /// Denoise alpha separately. With AOV model kinds, treat alpha like an AOV. + OPTIX_DENOISER_ALPHA_MODE_ALPHA_AS_AOV = 1, + + /// With AOV model kinds, full denoise pass with alpha. + /// This is slower than OPTIX_DENOISER_ALPHA_MODE_ALPHA_AS_AOV. + OPTIX_DENOISER_ALPHA_MODE_FULL_DENOISE_PASS = 2 +} OptixDenoiserAlphaMode; +typedef struct OptixDenoiserParams +{ + /// alpha denoise mode + OptixDenoiserAlphaMode denoiseAlpha; + + /// average log intensity of input image (default null pointer). points to a single float. + /// with the default (null pointer) denoised results will not be optimal for very dark or + /// bright input images. + CUdeviceptr hdrIntensity; + + /// blend factor. + /// If set to 0 the output is 100% of the denoised input. If set to 1, the output is 100% of + /// the unmodified input. Values between 0 and 1 will linearly interpolate between the denoised + /// and unmodified input. + float blendFactor; + + /// this parameter is used when the OPTIX_DENOISER_MODEL_KIND_AOV model kind is set. + /// average log color of input image, separate for RGB channels (default null pointer). + /// points to three floats. with the default (null pointer) denoised results will not be + /// optimal. + CUdeviceptr hdrAverageColor; + + /// In temporal modes this parameter must be set to 1 if previous layers (e.g. + /// previousOutputInternalGuideLayer) contain valid data. This is the case in the + /// second and subsequent frames of a sequence (for example after a change of camera + /// angle). In the first frame of such a sequence this parameter must be set to 0. + unsigned int temporalModeUsePreviousLayers; +} OptixDenoiserParams; + +/// Various sizes related to the denoiser. +/// +/// \see #optixDenoiserComputeMemoryResources() +typedef struct OptixDenoiserSizes +{ + /// Size of state memory passed to #optixDenoiserSetup, #optixDenoiserInvoke. + size_t stateSizeInBytes; + + /// Size of scratch memory passed to #optixDenoiserSetup, #optixDenoiserInvoke. + /// Overlap added to dimensions passed to #optixDenoiserComputeMemoryResources. + size_t withOverlapScratchSizeInBytes; + + /// Size of scratch memory passed to #optixDenoiserSetup, #optixDenoiserInvoke. + /// No overlap added. + size_t withoutOverlapScratchSizeInBytes; + + /// Overlap on all four tile sides. + unsigned int overlapWindowSizeInPixels; + + /// Size of scratch memory passed to #optixDenoiserComputeAverageColor. + /// The size is independent of the tile/image resolution. + size_t computeAverageColorSizeInBytes; + + /// Size of scratch memory passed to #optixDenoiserComputeIntensity. + /// The size is independent of the tile/image resolution. + size_t computeIntensitySizeInBytes; + + /// Number of bytes for each pixel in internal guide layers. + size_t internalGuideLayerPixelSizeInBytes; +} OptixDenoiserSizes; + +/// Ray flags passed to the device function #optixTrace(). These affect the behavior of +/// traversal per invocation. +/// +/// \see #optixTrace() +typedef enum OptixRayFlags +{ + /// No change from the behavior configured for the individual AS. + OPTIX_RAY_FLAG_NONE = 0u, + + /// Disables anyhit programs for the ray. + /// Overrides OPTIX_INSTANCE_FLAG_ENFORCE_ANYHIT. + /// This flag is mutually exclusive with OPTIX_RAY_FLAG_ENFORCE_ANYHIT, + /// OPTIX_RAY_FLAG_CULL_DISABLED_ANYHIT, OPTIX_RAY_FLAG_CULL_ENFORCED_ANYHIT. + OPTIX_RAY_FLAG_DISABLE_ANYHIT = 1u << 0, + + /// Forces anyhit program execution for the ray. + /// Overrides OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT as well as OPTIX_INSTANCE_FLAG_DISABLE_ANYHIT. + /// This flag is mutually exclusive with OPTIX_RAY_FLAG_DISABLE_ANYHIT, + /// OPTIX_RAY_FLAG_CULL_DISABLED_ANYHIT, OPTIX_RAY_FLAG_CULL_ENFORCED_ANYHIT. + OPTIX_RAY_FLAG_ENFORCE_ANYHIT = 1u << 1, + + /// Terminates the ray after the first hit and executes + /// the closesthit program of that hit. + OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT = 1u << 2, + + /// Disables closesthit programs for the ray, but still executes miss program in case of a miss. + OPTIX_RAY_FLAG_DISABLE_CLOSESTHIT = 1u << 3, + + /// Do not intersect triangle back faces + /// (respects a possible face change due to instance flag + /// OPTIX_INSTANCE_FLAG_FLIP_TRIANGLE_FACING). + /// This flag is mutually exclusive with OPTIX_RAY_FLAG_CULL_FRONT_FACING_TRIANGLES. + OPTIX_RAY_FLAG_CULL_BACK_FACING_TRIANGLES = 1u << 4, + + /// Do not intersect triangle front faces + /// (respects a possible face change due to instance flag + /// OPTIX_INSTANCE_FLAG_FLIP_TRIANGLE_FACING). + /// This flag is mutually exclusive with OPTIX_RAY_FLAG_CULL_BACK_FACING_TRIANGLES. + OPTIX_RAY_FLAG_CULL_FRONT_FACING_TRIANGLES = 1u << 5, + + /// Do not intersect geometry which disables anyhit programs + /// (due to setting geometry flag OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT or + /// instance flag OPTIX_INSTANCE_FLAG_DISABLE_ANYHIT). + /// This flag is mutually exclusive with OPTIX_RAY_FLAG_CULL_ENFORCED_ANYHIT, + /// OPTIX_RAY_FLAG_ENFORCE_ANYHIT, OPTIX_RAY_FLAG_DISABLE_ANYHIT. + OPTIX_RAY_FLAG_CULL_DISABLED_ANYHIT = 1u << 6, + + /// Do not intersect geometry which have an enabled anyhit program + /// (due to not setting geometry flag OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT or + /// setting instance flag OPTIX_INSTANCE_FLAG_ENFORCE_ANYHIT). + /// This flag is mutually exclusive with OPTIX_RAY_FLAG_CULL_DISABLED_ANYHIT, + /// OPTIX_RAY_FLAG_ENFORCE_ANYHIT, OPTIX_RAY_FLAG_DISABLE_ANYHIT. + OPTIX_RAY_FLAG_CULL_ENFORCED_ANYHIT = 1u << 7, + +} OptixRayFlags; + +/// Transform +/// +/// OptixTransformType is used by the device function #optixGetTransformTypeFromHandle() to +/// determine the type of the OptixTraversableHandle returned from +/// optixGetTransformListHandle(). +typedef enum OptixTransformType +{ + OPTIX_TRANSFORM_TYPE_NONE = 0, ///< Not a transformation + OPTIX_TRANSFORM_TYPE_STATIC_TRANSFORM = 1, ///< \see #OptixStaticTransform + OPTIX_TRANSFORM_TYPE_MATRIX_MOTION_TRANSFORM = 2, ///< \see #OptixMatrixMotionTransform + OPTIX_TRANSFORM_TYPE_SRT_MOTION_TRANSFORM = 3, ///< \see #OptixSRTMotionTransform + OPTIX_TRANSFORM_TYPE_INSTANCE = 4, ///< \see #OptixInstance +} OptixTransformType; + +/// Specifies the set of valid traversable graphs that may be +/// passed to invocation of #optixTrace(). Flags may be bitwise combined. +typedef enum OptixTraversableGraphFlags +{ + /// Used to signal that any traversable graphs is valid. + /// This flag is mutually exclusive with all other flags. + OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_ANY = 0, + + /// Used to signal that a traversable graph of a single Geometry Acceleration + /// Structure (GAS) without any transforms is valid. This flag may be combined with + /// other flags except for OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_ANY. + OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS = 1u << 0, + + /// Used to signal that a traversable graph of a single Instance Acceleration + /// Structure (IAS) directly connected to Geometry Acceleration Structure (GAS) + /// traversables without transform traversables in between is valid. This flag may + /// be combined with other flags except for OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_ANY. + OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING = 1u << 1, +} OptixTraversableGraphFlags; + +/// Optimization levels +/// +/// \see #OptixModuleCompileOptions::optLevel +typedef enum OptixCompileOptimizationLevel +{ + /// Default is to run all optimizations + OPTIX_COMPILE_OPTIMIZATION_DEFAULT = 0, + /// No optimizations + OPTIX_COMPILE_OPTIMIZATION_LEVEL_0 = 0x2340, + /// Some optimizations + OPTIX_COMPILE_OPTIMIZATION_LEVEL_1 = 0x2341, + /// Most optimizations + OPTIX_COMPILE_OPTIMIZATION_LEVEL_2 = 0x2342, + /// All optimizations + OPTIX_COMPILE_OPTIMIZATION_LEVEL_3 = 0x2343, +} OptixCompileOptimizationLevel; + +/// Debug levels +/// +/// \see #OptixModuleCompileOptions::debugLevel +typedef enum OptixCompileDebugLevel +{ + /// Default currently is minimal + OPTIX_COMPILE_DEBUG_LEVEL_DEFAULT = 0, + /// No debug information + OPTIX_COMPILE_DEBUG_LEVEL_NONE = 0x2350, + /// Generate information that does not impact performance. + /// Note this replaces OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO. + OPTIX_COMPILE_DEBUG_LEVEL_MINIMAL = 0x2351, + /// Generate some debug information with slight performance cost + OPTIX_COMPILE_DEBUG_LEVEL_MODERATE = 0x2353, + /// Generate full debug information + OPTIX_COMPILE_DEBUG_LEVEL_FULL = 0x2352, +} OptixCompileDebugLevel; + +/// Module compilation state. +/// +/// \see #optixModuleGetCompilationState(), #optixModuleCreateFromPTXWithTasks() +typedef enum OptixModuleCompileState +{ + /// No OptixTask objects have started + OPTIX_MODULE_COMPILE_STATE_NOT_STARTED = 0x2360, + + /// Started, but not all OptixTask objects have completed. No detected failures. + OPTIX_MODULE_COMPILE_STATE_STARTED = 0x2361, + + /// Not all OptixTask objects have completed, but at least one has failed. + OPTIX_MODULE_COMPILE_STATE_IMPENDING_FAILURE = 0x2362, + + /// All OptixTask objects have completed, and at least one has failed + OPTIX_MODULE_COMPILE_STATE_FAILED = 0x2363, + + /// All OptixTask objects have completed. The OptixModule is ready to be used. + OPTIX_MODULE_COMPILE_STATE_COMPLETED = 0x2364, +} OptixModuleCompileState; + + + +/// Struct for specifying specializations for pipelineParams as specified in +/// OptixPipelineCompileOptions::pipelineLaunchParamsVariableName. +/// +/// The bound values are supposed to represent a constant value in the +/// pipelineParams. OptiX will attempt to locate all loads from the pipelineParams and +/// correlate them to the appropriate bound value, but there are cases where OptiX cannot +/// safely or reliably do this. For example if the pointer to the pipelineParams is passed +/// as an argument to a non-inline function or the offset of the load to the +/// pipelineParams cannot be statically determined (e.g. accessed in a loop). No module +/// should rely on the value being specialized in order to work correctly. The values in +/// the pipelineParams specified on optixLaunch should match the bound value. If +/// validation mode is enabled on the context, OptiX will verify that the bound values +/// specified matches the values in pipelineParams specified to optixLaunch. +/// +/// These values are compiled in to the module as constants. Once the constants are +/// inserted into the code, an optimization pass will be run that will attempt to +/// propagate the consants and remove unreachable code. +/// +/// If caching is enabled, changes in these values will result in newly compiled modules. +/// +/// The pipelineParamOffset and sizeInBytes must be within the bounds of the +/// pipelineParams variable. OPTIX_ERROR_INVALID_VALUE will be returned from +/// optixModuleCreateFromPTX otherwise. +/// +/// If more than one bound value overlaps or the size of a bound value is equal to 0, +/// an OPTIX_ERROR_INVALID_VALUE will be returned from optixModuleCreateFromPTX. +/// +/// The same set of bound values do not need to be used for all modules in a pipeline, but +/// overlapping values between modules must have the same value. +/// OPTIX_ERROR_INVALID_VALUE will be returned from optixPipelineCreate otherwise. +/// +/// \see #OptixModuleCompileOptions +typedef struct OptixModuleCompileBoundValueEntry { + size_t pipelineParamOffsetInBytes; + size_t sizeInBytes; + const void* boundValuePtr; + const char* annotation; // optional string to display, set to 0 if unused. If unused, + // OptiX will report the annotation as "No annotation" +} OptixModuleCompileBoundValueEntry; + +/// Payload type identifiers. +typedef enum OptixPayloadTypeID { + OPTIX_PAYLOAD_TYPE_DEFAULT = 0, + OPTIX_PAYLOAD_TYPE_ID_0 = (1 << 0u), + OPTIX_PAYLOAD_TYPE_ID_1 = (1 << 1u), + OPTIX_PAYLOAD_TYPE_ID_2 = (1 << 2u), + OPTIX_PAYLOAD_TYPE_ID_3 = (1 << 3u), + OPTIX_PAYLOAD_TYPE_ID_4 = (1 << 4u), + OPTIX_PAYLOAD_TYPE_ID_5 = (1 << 5u), + OPTIX_PAYLOAD_TYPE_ID_6 = (1 << 6u), + OPTIX_PAYLOAD_TYPE_ID_7 = (1 << 7u) +} OptixPayloadTypeID; + +/// Semantic flags for a single payload word. +/// +/// Used to specify the semantics of a payload word per shader type. +/// "read": Shader of this type may read the payload word. +/// "write": Shader of this type may write the payload word. +/// +/// "trace_caller_write": Shaders may consume the value of the payload word passed to optixTrace by the caller. +/// "trace_caller_read": The caller to optixTrace may read the payload word after the call to optixTrace. +/// +/// Semantics can be bitwise combined. +/// Combining "read" and "write" is equivalent to specifying "read_write". +/// A payload needs to be writable by the caller or at least one shader type. +/// A payload needs to be readable by the caller or at least one shader type after a being writable. +typedef enum OptixPayloadSemantics +{ + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_NONE = 0, + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ = 1u << 0, + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_WRITE = 2u << 0, + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ_WRITE = 3u << 0, + + OPTIX_PAYLOAD_SEMANTICS_CH_NONE = 0, + OPTIX_PAYLOAD_SEMANTICS_CH_READ = 1u << 2, + OPTIX_PAYLOAD_SEMANTICS_CH_WRITE = 2u << 2, + OPTIX_PAYLOAD_SEMANTICS_CH_READ_WRITE = 3u << 2, + + OPTIX_PAYLOAD_SEMANTICS_MS_NONE = 0, + OPTIX_PAYLOAD_SEMANTICS_MS_READ = 1u << 4, + OPTIX_PAYLOAD_SEMANTICS_MS_WRITE = 2u << 4, + OPTIX_PAYLOAD_SEMANTICS_MS_READ_WRITE = 3u << 4, + + OPTIX_PAYLOAD_SEMANTICS_AH_NONE = 0, + OPTIX_PAYLOAD_SEMANTICS_AH_READ = 1u << 6, + OPTIX_PAYLOAD_SEMANTICS_AH_WRITE = 2u << 6, + OPTIX_PAYLOAD_SEMANTICS_AH_READ_WRITE = 3u << 6, + + OPTIX_PAYLOAD_SEMANTICS_IS_NONE = 0, + OPTIX_PAYLOAD_SEMANTICS_IS_READ = 1u << 8, + OPTIX_PAYLOAD_SEMANTICS_IS_WRITE = 2u << 8, + OPTIX_PAYLOAD_SEMANTICS_IS_READ_WRITE = 3u << 8, +} OptixPayloadSemantics; + +/// Specifies a single payload type +typedef struct OptixPayloadType +{ + /// The number of 32b words the payload of this type holds + unsigned int numPayloadValues; + + /// Points to host array of payload word semantics, size must match numPayloadValues + const unsigned int *payloadSemantics; +} OptixPayloadType; + +/// Compilation options for module +/// +/// \see #optixModuleCreateFromPTX() +typedef struct OptixModuleCompileOptions +{ + /// Maximum number of registers allowed when compiling to SASS. + /// Set to 0 for no explicit limit. May vary within a pipeline. + int maxRegisterCount; + + /// Optimization level. May vary within a pipeline. + OptixCompileOptimizationLevel optLevel; + + /// Generate debug information. + OptixCompileDebugLevel debugLevel; + + /// Ingored if numBoundValues is set to 0 + const OptixModuleCompileBoundValueEntry* boundValues; + + /// set to 0 if unused + unsigned int numBoundValues; + + /// The number of different payload types available for compilation. + /// Must be zero if OptixPipelineCompileOptions::numPayloadValues is not zero. + unsigned int numPayloadTypes; + + /// Points to host array of payload type definitions, size must match numPayloadTypes + OptixPayloadType *payloadTypes; + +} OptixModuleCompileOptions; + +/// Distinguishes different kinds of program groups. +typedef enum OptixProgramGroupKind +{ + /// Program group containing a raygen (RG) program + /// \see #OptixProgramGroupSingleModule, #OptixProgramGroupDesc::raygen + OPTIX_PROGRAM_GROUP_KIND_RAYGEN = 0x2421, + + /// Program group containing a miss (MS) program + /// \see #OptixProgramGroupSingleModule, #OptixProgramGroupDesc::miss + OPTIX_PROGRAM_GROUP_KIND_MISS = 0x2422, + + /// Program group containing an exception (EX) program + /// \see OptixProgramGroupHitgroup, #OptixProgramGroupDesc::exception + OPTIX_PROGRAM_GROUP_KIND_EXCEPTION = 0x2423, + + /// Program group containing an intersection (IS), any hit (AH), and/or closest hit (CH) program + /// \see #OptixProgramGroupSingleModule, #OptixProgramGroupDesc::hitgroup + OPTIX_PROGRAM_GROUP_KIND_HITGROUP = 0x2424, + + /// Program group containing a direct (DC) or continuation (CC) callable program + /// \see OptixProgramGroupCallables, #OptixProgramGroupDesc::callables + OPTIX_PROGRAM_GROUP_KIND_CALLABLES = 0x2425 +} OptixProgramGroupKind; + +/// Flags for program groups +typedef enum OptixProgramGroupFlags +{ + /// Currently there are no flags + OPTIX_PROGRAM_GROUP_FLAGS_NONE = 0 +} OptixProgramGroupFlags; + +/// Program group representing a single module. +/// +/// Used for raygen, miss, and exception programs. In case of raygen and exception programs, module and entry +/// function name need to be valid. For miss programs, module and entry function name might both be \c nullptr. +/// +/// \see #OptixProgramGroupDesc::raygen, #OptixProgramGroupDesc::miss, #OptixProgramGroupDesc::exception +typedef struct OptixProgramGroupSingleModule +{ + /// Module holding single program. + OptixModule module; + /// Entry function name of the single program. + const char* entryFunctionName; +} OptixProgramGroupSingleModule; + +/// Program group representing the hitgroup. +/// +/// For each of the three program types, module and entry function name might both be \c nullptr. +/// +/// \see #OptixProgramGroupDesc::hitgroup +typedef struct OptixProgramGroupHitgroup +{ + /// Module holding the closest hit (CH) program. + OptixModule moduleCH; + /// Entry function name of the closest hit (CH) program. + const char* entryFunctionNameCH; + /// Module holding the any hit (AH) program. + OptixModule moduleAH; + /// Entry function name of the any hit (AH) program. + const char* entryFunctionNameAH; + /// Module holding the intersection (Is) program. + OptixModule moduleIS; + /// Entry function name of the intersection (IS) program. + const char* entryFunctionNameIS; +} OptixProgramGroupHitgroup; + +/// Program group representing callables. +/// +/// Module and entry function name need to be valid for at least one of the two callables. +/// +/// \see ##OptixProgramGroupDesc::callables +typedef struct OptixProgramGroupCallables +{ + /// Module holding the direct callable (DC) program. + OptixModule moduleDC; + /// Entry function name of the direct callable (DC) program. + const char* entryFunctionNameDC; + /// Module holding the continuation callable (CC) program. + OptixModule moduleCC; + /// Entry function name of the continuation callable (CC) program. + const char* entryFunctionNameCC; +} OptixProgramGroupCallables; + +/// Descriptor for program groups. +typedef struct OptixProgramGroupDesc +{ + /// The kind of program group. + OptixProgramGroupKind kind; + + /// See #OptixProgramGroupFlags + unsigned int flags; + + union + { + /// \see #OPTIX_PROGRAM_GROUP_KIND_RAYGEN + OptixProgramGroupSingleModule raygen; + /// \see #OPTIX_PROGRAM_GROUP_KIND_MISS + OptixProgramGroupSingleModule miss; + /// \see #OPTIX_PROGRAM_GROUP_KIND_EXCEPTION + OptixProgramGroupSingleModule exception; + /// \see #OPTIX_PROGRAM_GROUP_KIND_CALLABLES + OptixProgramGroupCallables callables; + /// \see #OPTIX_PROGRAM_GROUP_KIND_HITGROUP + OptixProgramGroupHitgroup hitgroup; + }; +} OptixProgramGroupDesc; + +/// Program group options +/// +/// \see #optixProgramGroupCreate() +typedef struct OptixProgramGroupOptions +{ + /// Specifies the payload type of this program group. + /// All programs in the group must support the payload type + /// (Program support for a type is specified by calling + /// \see #optixSetPayloadTypes or otherwise all types specified in + /// \see #OptixModuleCompileOptions are supported). + /// If a program is not available for the requested payload type, + /// optixProgramGroupCreate returns OPTIX_ERROR_PAYLOAD_TYPE_MISMATCH. + /// If the payloadType is left zero, a unique type is deduced. + /// The payload type can be uniquely deduced if there is exactly one payload type + /// for which all programs in the group are available. + /// If the payload type could not be deduced uniquely + /// optixProgramGroupCreate returns OPTIX_ERROR_PAYLOAD_TYPE_RESOLUTION_FAILED. + OptixPayloadType* payloadType; +} OptixProgramGroupOptions; + +/// The following values are used to indicate which exception was thrown. +typedef enum OptixExceptionCodes +{ + /// Stack overflow of the continuation stack. + /// no exception details. + OPTIX_EXCEPTION_CODE_STACK_OVERFLOW = -1, + + /// The trace depth is exceeded. + /// no exception details. + OPTIX_EXCEPTION_CODE_TRACE_DEPTH_EXCEEDED = -2, + + /// The traversal depth is exceeded. + /// Exception details: + /// optixGetTransformListSize() + /// optixGetTransformListHandle() + OPTIX_EXCEPTION_CODE_TRAVERSAL_DEPTH_EXCEEDED = -3, + + /// Traversal encountered an invalid traversable type. + /// Exception details: + /// optixGetTransformListSize() + /// optixGetTransformListHandle() + /// optixGetExceptionInvalidTraversable() + OPTIX_EXCEPTION_CODE_TRAVERSAL_INVALID_TRAVERSABLE = -5, + + /// The miss SBT record index is out of bounds + /// A miss SBT record index is valid within the range [0, OptixShaderBindingTable::missRecordCount) (See optixLaunch) + /// Exception details: + /// optixGetExceptionInvalidSbtOffset() + OPTIX_EXCEPTION_CODE_TRAVERSAL_INVALID_MISS_SBT = -6, + + /// The traversal hit SBT record index out of bounds. + /// + /// A traversal hit SBT record index is valid within the range [0, OptixShaderBindingTable::hitgroupRecordCount) (See optixLaunch) + /// The following formula relates the + // sbt-index (See optixGetExceptionInvalidSbtOffset), + // sbt-instance-offset (See OptixInstance::sbtOffset), + /// sbt-geometry-acceleration-structure-index (See optixGetSbtGASIndex), + /// sbt-stride-from-trace-call and sbt-offset-from-trace-call (See optixTrace) + /// + /// sbt-index = sbt-instance-offset + (sbt-geometry-acceleration-structure-index * sbt-stride-from-trace-call) + sbt-offset-from-trace-call + /// + /// Exception details: + /// optixGetTransformListSize() + /// optixGetTransformListHandle() + /// optixGetExceptionInvalidSbtOffset() + /// optixGetSbtGASIndex() + OPTIX_EXCEPTION_CODE_TRAVERSAL_INVALID_HIT_SBT = -7, + + /// The shader encountered an unsupported primitive type (See OptixPipelineCompileOptions::usesPrimitiveTypeFlags). + /// no exception details. + OPTIX_EXCEPTION_CODE_UNSUPPORTED_PRIMITIVE_TYPE = -8, + + /// The shader encountered a call to optixTrace with at least + /// one of the float arguments being inf or nan, or the tmin argument is negative. + /// Exception details: + /// optixGetExceptionInvalidRay() + OPTIX_EXCEPTION_CODE_INVALID_RAY = -9, + + /// The shader encountered a call to either optixDirectCall or optixCallableCall + /// where the argument count does not match the parameter count of the callable + /// program which is called. + /// Exception details: + /// optixGetExceptionParameterMismatch + OPTIX_EXCEPTION_CODE_CALLABLE_PARAMETER_MISMATCH = -10, + + /// The invoked builtin IS does not match the current GAS + OPTIX_EXCEPTION_CODE_BUILTIN_IS_MISMATCH = -11, + + /// Tried to call a callable program using an SBT offset that is larger + /// than the number of passed in callable SBT records. + /// Exception details: + /// optixGetExceptionInvalidSbtOffset() + OPTIX_EXCEPTION_CODE_CALLABLE_INVALID_SBT = -12, + + /// Tried to call a direct callable using an SBT offset of a record that + /// was built from a program group that did not include a direct callable. + OPTIX_EXCEPTION_CODE_CALLABLE_NO_DC_SBT_RECORD = -13, + + /// Tried to call a continuation callable using an SBT offset of a record + /// that was built from a program group that did not include a continuation callable. + OPTIX_EXCEPTION_CODE_CALLABLE_NO_CC_SBT_RECORD = -14, + + /// Tried to directly traverse a single gas while single gas traversable graphs are not enabled + /// (see OptixTraversableGraphFlags::OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS). + /// Exception details: + /// optixGetTransformListSize() + /// optixGetTransformListHandle() + /// optixGetExceptionInvalidTraversable() + OPTIX_EXCEPTION_CODE_UNSUPPORTED_SINGLE_LEVEL_GAS = -15, + + /// argument passed to an optix call is + /// not within an acceptable range of values. + OPTIX_EXCEPTION_CODE_INVALID_VALUE_ARGUMENT_0 = -16, + OPTIX_EXCEPTION_CODE_INVALID_VALUE_ARGUMENT_1 = -17, + OPTIX_EXCEPTION_CODE_INVALID_VALUE_ARGUMENT_2 = -18, + + /// Tried to access data on an AS without random data access support (See OptixBuildFlags). + OPTIX_EXCEPTION_CODE_UNSUPPORTED_DATA_ACCESS = -32, + + /// The program payload type doesn't match the trace payload type. + OPTIX_EXCEPTION_CODE_PAYLOAD_TYPE_MISMATCH = -33, +} OptixExceptionCodes; + +/// Exception flags. +/// +/// \see #OptixPipelineCompileOptions::exceptionFlags, #OptixExceptionCodes +typedef enum OptixExceptionFlags +{ + /// No exception are enabled. + OPTIX_EXCEPTION_FLAG_NONE = 0, + + /// Enables exceptions check related to the continuation stack. + OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW = 1u << 0, + + /// Enables exceptions check related to trace depth. + OPTIX_EXCEPTION_FLAG_TRACE_DEPTH = 1u << 1, + + /// Enables user exceptions via optixThrowException(). This flag must be specified for all modules in a pipeline + /// if any module calls optixThrowException(). + OPTIX_EXCEPTION_FLAG_USER = 1u << 2, + + /// Enables various exceptions check related to traversal. + OPTIX_EXCEPTION_FLAG_DEBUG = 1u << 3 +} OptixExceptionFlags; + +/// Compilation options for all modules of a pipeline. +/// +/// Similar to #OptixModuleCompileOptions, but these options here need to be equal for all modules of a pipeline. +/// +/// \see #optixModuleCreateFromPTX(), #optixPipelineCreate() +typedef struct OptixPipelineCompileOptions +{ + /// Boolean value indicating whether motion blur could be used + int usesMotionBlur; + + /// Traversable graph bitfield. See OptixTraversableGraphFlags + unsigned int traversableGraphFlags; + + /// How much storage, in 32b words, to make available for the payload, [0..32] + /// Must be zero if numPayloadTypes is not zero. + int numPayloadValues; + + /// How much storage, in 32b words, to make available for the attributes. The + /// minimum number is 2. Values below that will automatically be changed to 2. [2..8] + int numAttributeValues; + + /// A bitmask of OptixExceptionFlags indicating which exceptions are enabled. + unsigned int exceptionFlags; + + /// The name of the pipeline parameter variable. If 0, no pipeline parameter + /// will be available. This will be ignored if the launch param variable was + /// optimized out or was not found in the modules linked to the pipeline. + const char* pipelineLaunchParamsVariableName; + + /// Bit field enabling primitive types. See OptixPrimitiveTypeFlags. + /// Setting to zero corresponds to enabling OPTIX_PRIMITIVE_TYPE_FLAGS_CUSTOM and OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE. + unsigned int usesPrimitiveTypeFlags; + +} OptixPipelineCompileOptions; + +/// Link options for a pipeline +/// +/// \see #optixPipelineCreate() +typedef struct OptixPipelineLinkOptions +{ + /// Maximum trace recursion depth. 0 means a ray generation program can be + /// launched, but can't trace any rays. The maximum allowed value is 31. + unsigned int maxTraceDepth; + + /// Generate debug information. + OptixCompileDebugLevel debugLevel; + +} OptixPipelineLinkOptions; + +/// Describes the shader binding table (SBT) +/// +/// \see #optixLaunch() +typedef struct OptixShaderBindingTable +{ + /// Device address of the SBT record of the ray gen program to start launch at. The address must be a multiple of + /// OPTIX_SBT_RECORD_ALIGNMENT. + CUdeviceptr raygenRecord; + + /// Device address of the SBT record of the exception program. The address must be a multiple of + /// OPTIX_SBT_RECORD_ALIGNMENT. + CUdeviceptr exceptionRecord; + + /// Arrays of SBT records for miss programs. The base address and the stride must be a multiple of + /// OPTIX_SBT_RECORD_ALIGNMENT. + /// @{ + CUdeviceptr missRecordBase; + unsigned int missRecordStrideInBytes; + unsigned int missRecordCount; + /// @} + + /// Arrays of SBT records for hit groups. The base address and the stride must be a multiple of + /// OPTIX_SBT_RECORD_ALIGNMENT. + /// @{ + CUdeviceptr hitgroupRecordBase; + unsigned int hitgroupRecordStrideInBytes; + unsigned int hitgroupRecordCount; + /// @} + + /// Arrays of SBT records for callable programs. If the base address is not null, the stride and count must not be + /// zero. If the base address is null, then the count needs to zero. The base address and the stride must be a + /// multiple of OPTIX_SBT_RECORD_ALIGNMENT. + /// @{ + CUdeviceptr callablesRecordBase; + unsigned int callablesRecordStrideInBytes; + unsigned int callablesRecordCount; + /// @} + +} OptixShaderBindingTable; + +/// Describes the stack size requirements of a program group. +/// +/// \see optixProgramGroupGetStackSize() +typedef struct OptixStackSizes +{ + /// Continuation stack size of RG programs in bytes + unsigned int cssRG; + /// Continuation stack size of MS programs in bytes + unsigned int cssMS; + /// Continuation stack size of CH programs in bytes + unsigned int cssCH; + /// Continuation stack size of AH programs in bytes + unsigned int cssAH; + /// Continuation stack size of IS programs in bytes + unsigned int cssIS; + /// Continuation stack size of CC programs in bytes + unsigned int cssCC; + /// Direct stack size of DC programs in bytes + unsigned int dssDC; + +} OptixStackSizes; + +/// Options that can be passed to \c optixQueryFunctionTable() +typedef enum OptixQueryFunctionTableOptions +{ + /// Placeholder (there are no options yet) + OPTIX_QUERY_FUNCTION_TABLE_OPTION_DUMMY = 0 + +} OptixQueryFunctionTableOptions; + +/// Type of the function \c optixQueryFunctionTable() +typedef OptixResult( OptixQueryFunctionTable_t )( int abiId, + unsigned int numOptions, + OptixQueryFunctionTableOptions* /*optionKeys*/, + const void** /*optionValues*/, + void* functionTable, + size_t sizeOfTable ); + +/// Specifies the options for retrieving an intersection program for a built-in primitive type. +/// The primitive type must not be OPTIX_PRIMITIVE_TYPE_CUSTOM. +/// +/// \see #optixBuiltinISModuleGet() +typedef struct OptixBuiltinISOptions +{ + OptixPrimitiveType builtinISModuleType; + /// Boolean value indicating whether vertex motion blur is used (but not motion transform blur). + int usesMotionBlur; + /// Build flags, see OptixBuildFlags. + unsigned int buildFlags; + /// End cap properties of curves, see OptixCurveEndcapFlags, 0 for non-curve types. + unsigned int curveEndcapFlags; +} OptixBuiltinISOptions; + +#if defined( __CUDACC__ ) +/// Describes the ray that was passed into \c optixTrace() which caused an exception with +/// exception code OPTIX_EXCEPTION_CODE_INVALID_RAY. +/// +/// \see #optixGetExceptionInvalidRay() +typedef struct OptixInvalidRayExceptionDetails +{ + float3 origin; + float3 direction; + float tmin; + float tmax; + float time; +} OptixInvalidRayExceptionDetails; + +/// Describes the details of a call to a callable program which caused an exception with +/// exception code OPTIX_EXCEPTION_CODE_CALLABLE_PARAMETER_MISMATCH, +/// Note that OptiX packs the parameters into individual 32 bit values, so the number of +/// expected and passed values may not correspond to the number of arguments passed into +/// optixDirectCall or optixContinuationCall, or the number parameters in the definition +/// of the function that is called. +typedef struct OptixParameterMismatchExceptionDetails +{ + /// Number of 32 bit values expected by the callable program + unsigned int expectedParameterCount; + /// Number of 32 bit values that were passed to the callable program + unsigned int passedArgumentCount; + /// The offset of the SBT entry of the callable program relative to OptixShaderBindingTable::callablesRecordBase + unsigned int sbtIndex; + /// Pointer to a string that holds the name of the callable program that was called + char* callableName; +} OptixParameterMismatchExceptionDetails; +#endif + + +/*@}*/ // end group optix_types + +#endif // __optix_optix_7_types_h__ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_denoiser_tiling.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_denoiser_tiling.h new file mode 100644 index 00000000..ed44e449 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_denoiser_tiling.h @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of NVIDIA CORPORATION nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/// @file +/// @author NVIDIA Corporation +/// @brief OptiX public API header + +#ifndef optix_denoiser_tiling_h +#define optix_denoiser_tiling_h + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \addtogroup optix_utilities +@{ +*/ + +/// Tile definition +/// +/// see #optixUtilDenoiserSplitImage +/// +struct OptixUtilDenoiserImageTile +{ + // input tile image + OptixImage2D input; + + // output tile image + OptixImage2D output; + + // overlap offsets, parameters for #optixUtilDenoiserInvoke + unsigned int inputOffsetX; + unsigned int inputOffsetY; +}; + +/// Return pixel stride in bytes for the given pixel format +/// if the pixelStrideInBytes member of the image is zero. +/// Otherwise return pixelStrideInBytes from the image. +/// +/// \param[in] image Image containing the pixel stride +/// +inline OptixResult optixUtilGetPixelStride( const OptixImage2D& image, unsigned int& pixelStrideInBytes ) +{ + pixelStrideInBytes = image.pixelStrideInBytes; + if( pixelStrideInBytes == 0 ) + { + switch( image.format ) + { + case OPTIX_PIXEL_FORMAT_HALF2: + pixelStrideInBytes = 2 * sizeof( short ); + break; + case OPTIX_PIXEL_FORMAT_HALF3: + pixelStrideInBytes = 3 * sizeof( short ); + break; + case OPTIX_PIXEL_FORMAT_HALF4: + pixelStrideInBytes = 4 * sizeof( short ); + break; + case OPTIX_PIXEL_FORMAT_FLOAT2: + pixelStrideInBytes = 2 * sizeof( float ); + break; + case OPTIX_PIXEL_FORMAT_FLOAT3: + pixelStrideInBytes = 3 * sizeof( float ); + break; + case OPTIX_PIXEL_FORMAT_FLOAT4: + pixelStrideInBytes = 4 * sizeof( float ); + break; + case OPTIX_PIXEL_FORMAT_UCHAR3: + pixelStrideInBytes = 3 * sizeof( char ); + break; + case OPTIX_PIXEL_FORMAT_UCHAR4: + pixelStrideInBytes = 4 * sizeof( char ); + break; + case OPTIX_PIXEL_FORMAT_INTERNAL_GUIDE_LAYER: + return OPTIX_ERROR_INVALID_VALUE; + break; + } + } + return OPTIX_SUCCESS; +} + +/// Split image into 2D tiles given horizontal and vertical tile size +/// +/// \param[in] input full resolution input image to be split +/// \param[in] output full resolution output image +/// \param[in] overlapWindowSizeInPixels see #OptixDenoiserSizes, #optixDenoiserComputeMemoryResources +/// \param[in] tileWidth maximum width of tiles +/// \param[in] tileHeight maximum height of tiles +/// \param[out] tiles list of tiles covering the input image +/// +inline OptixResult optixUtilDenoiserSplitImage( + const OptixImage2D& input, + const OptixImage2D& output, + unsigned int overlapWindowSizeInPixels, + unsigned int tileWidth, + unsigned int tileHeight, + std::vector& tiles ) +{ + if( tileWidth == 0 || tileHeight == 0 ) + return OPTIX_ERROR_INVALID_VALUE; + + unsigned int inPixelStride, outPixelStride; + if( const OptixResult res = optixUtilGetPixelStride( input, inPixelStride ) ) + return res; + if( const OptixResult res = optixUtilGetPixelStride( output, outPixelStride ) ) + return res; + + int inp_w = std::min( tileWidth + 2 * overlapWindowSizeInPixels, input.width ); + int inp_h = std::min( tileHeight + 2 * overlapWindowSizeInPixels, input.height ); + int inp_y = 0, copied_y = 0; + + int upscaleX = output.width / input.width; + int upscaleY = output.height / input.height; + + do + { + int inputOffsetY = inp_y == 0 ? 0 : std::max( (int)overlapWindowSizeInPixels, inp_h - ( (int)input.height - inp_y ) ); + int copy_y = inp_y == 0 ? std::min( input.height, tileHeight + overlapWindowSizeInPixels ) : + std::min( tileHeight, input.height - copied_y ); + + int inp_x = 0, copied_x = 0; + do + { + int inputOffsetX = inp_x == 0 ? 0 : std::max( (int)overlapWindowSizeInPixels, inp_w - ( (int)input.width - inp_x ) ); + int copy_x = inp_x == 0 ? std::min( input.width, tileWidth + overlapWindowSizeInPixels ) : + std::min( tileWidth, input.width - copied_x ); + + OptixUtilDenoiserImageTile tile; + tile.input.data = input.data + (size_t)( inp_y - inputOffsetY ) * input.rowStrideInBytes + + (size_t)( inp_x - inputOffsetX ) * inPixelStride; + tile.input.width = inp_w; + tile.input.height = inp_h; + tile.input.rowStrideInBytes = input.rowStrideInBytes; + tile.input.pixelStrideInBytes = input.pixelStrideInBytes; + tile.input.format = input.format; + + tile.output.data = output.data + (size_t)( upscaleY * inp_y ) * output.rowStrideInBytes + + (size_t)( upscaleX * inp_x ) * outPixelStride; + tile.output.width = upscaleX * copy_x; + tile.output.height = upscaleY * copy_y; + tile.output.rowStrideInBytes = output.rowStrideInBytes; + tile.output.pixelStrideInBytes = output.pixelStrideInBytes; + tile.output.format = output.format; + + tile.inputOffsetX = inputOffsetX; + tile.inputOffsetY = inputOffsetY; + + tiles.push_back( tile ); + + inp_x += inp_x == 0 ? tileWidth + overlapWindowSizeInPixels : tileWidth; + copied_x += copy_x; + } while( inp_x < static_cast( input.width ) ); + + inp_y += inp_y == 0 ? tileHeight + overlapWindowSizeInPixels : tileHeight; + copied_y += copy_y; + } while( inp_y < static_cast( input.height ) ); + + return OPTIX_SUCCESS; +} + +/// Run denoiser on input layers +/// see #optixDenoiserInvoke +/// additional parameters: + +/// Runs the denoiser on the input layers on a single GPU and stream using #optixDenoiserInvoke. +/// If the input layers' dimensions are larger than the specified tile size, the image is divided into +/// tiles using #optixUtilDenoiserSplitImage, and multiple back-to-back invocations are performed in +/// order to reuse the scratch space. Multiple tiles can be invoked concurrently if +/// #optixUtilDenoiserSplitImage is used directly and multiple scratch allocations for each concurrent +/// invocation are used. + +/// The input parameters are the same as #optixDenoiserInvoke except for the addition of the maximum tile size. +/// +/// \param[in] denoiser +/// \param[in] stream +/// \param[in] params +/// \param[in] denoiserState +/// \param[in] denoiserStateSizeInBytes +/// \param[in] guideLayer +/// \param[in] layers +/// \param[in] numLayers +/// \param[in] scratch +/// \param[in] scratchSizeInBytes +/// \param[in] overlapWindowSizeInPixels +/// \param[in] tileWidth +/// \param[in] tileHeight +inline OptixResult optixUtilDenoiserInvokeTiled( + OptixDenoiser denoiser, + CUstream stream, + const OptixDenoiserParams* params, + CUdeviceptr denoiserState, + size_t denoiserStateSizeInBytes, + const OptixDenoiserGuideLayer* guideLayer, + const OptixDenoiserLayer* layers, + unsigned int numLayers, + CUdeviceptr scratch, + size_t scratchSizeInBytes, + unsigned int overlapWindowSizeInPixels, + unsigned int tileWidth, + unsigned int tileHeight ) +{ + if( !guideLayer || !layers ) + return OPTIX_ERROR_INVALID_VALUE; + + const unsigned int upscale = numLayers > 0 && layers[0].previousOutput.width == 2 * layers[0].input.width ? 2 : 1; + + std::vector> tiles( numLayers ); + std::vector> prevTiles( numLayers ); + for( unsigned int l = 0; l < numLayers; l++ ) + { + if( const OptixResult res = optixUtilDenoiserSplitImage( layers[l].input, layers[l].output, + overlapWindowSizeInPixels, + tileWidth, tileHeight, tiles[l] ) ) + return res; + + if( layers[l].previousOutput.data ) + { + OptixImage2D dummyOutput = layers[l].previousOutput; + if( const OptixResult res = optixUtilDenoiserSplitImage( layers[l].previousOutput, dummyOutput, + upscale * overlapWindowSizeInPixels, + upscale * tileWidth, upscale * tileHeight, prevTiles[l] ) ) + return res; + } + } + + std::vector albedoTiles; + if( guideLayer->albedo.data ) + { + OptixImage2D dummyOutput = guideLayer->albedo; + if( const OptixResult res = optixUtilDenoiserSplitImage( guideLayer->albedo, dummyOutput, + overlapWindowSizeInPixels, + tileWidth, tileHeight, albedoTiles ) ) + return res; + } + + std::vector normalTiles; + if( guideLayer->normal.data ) + { + OptixImage2D dummyOutput = guideLayer->normal; + if( const OptixResult res = optixUtilDenoiserSplitImage( guideLayer->normal, dummyOutput, + overlapWindowSizeInPixels, + tileWidth, tileHeight, normalTiles ) ) + return res; + } + std::vector flowTiles; + if( guideLayer->flow.data ) + { + OptixImage2D dummyOutput = guideLayer->flow; + if( const OptixResult res = optixUtilDenoiserSplitImage( guideLayer->flow, dummyOutput, + overlapWindowSizeInPixels, + tileWidth, tileHeight, flowTiles ) ) + return res; + } + + std::vector internalGuideLayerTiles; + if( guideLayer->previousOutputInternalGuideLayer.data && guideLayer->outputInternalGuideLayer.data ) + { + if( const OptixResult res = optixUtilDenoiserSplitImage( guideLayer->previousOutputInternalGuideLayer, + guideLayer->outputInternalGuideLayer, + upscale * overlapWindowSizeInPixels, + upscale * tileWidth, upscale * tileHeight, internalGuideLayerTiles ) ) + return res; + } + + for( size_t t = 0; t < tiles[0].size(); t++ ) + { + std::vector tlayers; + for( unsigned int l = 0; l < numLayers; l++ ) + { + OptixDenoiserLayer layer = {}; + layer.input = ( tiles[l] )[t].input; + layer.output = ( tiles[l] )[t].output; + if( layers[l].previousOutput.data ) + layer.previousOutput = ( prevTiles[l] )[t].input; + tlayers.push_back( layer ); + } + + OptixDenoiserGuideLayer gl = {}; + if( guideLayer->albedo.data ) + gl.albedo = albedoTiles[t].input; + + if( guideLayer->normal.data ) + gl.normal = normalTiles[t].input; + + if( guideLayer->flow.data ) + gl.flow = flowTiles[t].input; + + if( guideLayer->previousOutputInternalGuideLayer.data ) + gl.previousOutputInternalGuideLayer = internalGuideLayerTiles[t].input; + + if( guideLayer->outputInternalGuideLayer.data ) + gl.outputInternalGuideLayer = internalGuideLayerTiles[t].output; + + if( const OptixResult res = + optixDenoiserInvoke( denoiser, stream, params, denoiserState, denoiserStateSizeInBytes, + &gl, &tlayers[0], numLayers, + ( tiles[0] )[t].inputOffsetX, ( tiles[0] )[t].inputOffsetY, + scratch, scratchSizeInBytes ) ) + return res; + } + return OPTIX_SUCCESS; +} + +/*@}*/ // end group optix_utilities + +#ifdef __cplusplus +} +#endif + +#endif // __optix_optix_stack_size_h__ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_device.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_device.h new file mode 100644 index 00000000..cfaafd12 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_device.h @@ -0,0 +1,38 @@ + +/* +* SPDX-FileCopyrightText: Copyright (c) 2010 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* SPDX-License-Identifier: LicenseRef-NvidiaProprietary +* +* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +* property and proprietary rights in and to this material, related +* documentation and any modifications thereto. Any use, reproduction, +* disclosure or distribution of this material and related documentation +* without an express license agreement from NVIDIA CORPORATION or +* its affiliates is strictly prohibited. +*/ + /** + * @file optix_device.h + * @author NVIDIA Corporation + * @brief OptiX public API + * + * OptiX public API Reference - Host/Device side + */ + +/******************************************************************************\ + * optix_cuda.h + * + * This file provides the nvcc interface for generating PTX that the OptiX is + * capable of parsing and weaving into the final kernel. This is included by + * optix.h automatically if compiling device code. It can be included explicitly + * in host code if desired. + * +\******************************************************************************/ +#if !defined(__OPTIX_INCLUDE_INTERNAL_HEADERS__) +# define __OPTIX_INCLUDE_INTERNAL_HEADERS__ +# define __UNDEF_OPTIX_INCLUDE_INTERNAL_HEADERS_OPTIX_DEVICE_H__ +#endif +#include "optix_7_device.h" +#if defined( __UNDEF_OPTIX_INCLUDE_INTERNAL_HEADERS_OPTIX_DEVICE_H__ ) +# undef __OPTIX_INCLUDE_INTERNAL_HEADERS__ +# undef __UNDEF_OPTIX_INCLUDE_INTERNAL_HEADERS_OPTIX_DEVICE_H__ +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_function_table.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_function_table.h new file mode 100644 index 00000000..b3ca4c2c --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_function_table.h @@ -0,0 +1,333 @@ +/* +* SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* SPDX-License-Identifier: LicenseRef-NvidiaProprietary +* +* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +* property and proprietary rights in and to this material, related +* documentation and any modifications thereto. Any use, reproduction, +* disclosure or distribution of this material and related documentation +* without an express license agreement from NVIDIA CORPORATION or +* its affiliates is strictly prohibited. +*/ +/// @file +/// @author NVIDIA Corporation +/// @brief OptiX public API header + +#ifndef __optix_optix_function_table_h__ +#define __optix_optix_function_table_h__ + +/// The OptiX ABI version. +#define OPTIX_ABI_VERSION 60 + +#ifndef OPTIX_DEFINE_ABI_VERSION_ONLY + +#include "optix_types.h" + +#if !defined( OPTIX_DONT_INCLUDE_CUDA ) +// If OPTIX_DONT_INCLUDE_CUDA is defined, cuda driver types must be defined through other +// means before including optix headers. +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/// \defgroup optix_function_table Function Table +/// \brief OptiX Function Table + +/** \addtogroup optix_function_table +@{ +*/ + +/// The function table containing all API functions. +/// +/// See #optixInit() and #optixInitWithHandle(). +typedef struct OptixFunctionTable +{ + /// \name Error handling + //@ { + + /// See ::optixGetErrorName(). + const char* ( *optixGetErrorName )( OptixResult result ); + + /// See ::optixGetErrorString(). + const char* ( *optixGetErrorString )( OptixResult result ); + + //@ } + /// \name Device context + //@ { + + /// See ::optixDeviceContextCreate(). + OptixResult ( *optixDeviceContextCreate )( CUcontext fromContext, const OptixDeviceContextOptions* options, OptixDeviceContext* context ); + + /// See ::optixDeviceContextDestroy(). + OptixResult ( *optixDeviceContextDestroy )( OptixDeviceContext context ); + + /// See ::optixDeviceContextGetProperty(). + OptixResult ( *optixDeviceContextGetProperty )( OptixDeviceContext context, OptixDeviceProperty property, void* value, size_t sizeInBytes ); + + /// See ::optixDeviceContextSetLogCallback(). + OptixResult ( *optixDeviceContextSetLogCallback )( OptixDeviceContext context, + OptixLogCallback callbackFunction, + void* callbackData, + unsigned int callbackLevel ); + + /// See ::optixDeviceContextSetCacheEnabled(). + OptixResult ( *optixDeviceContextSetCacheEnabled )( OptixDeviceContext context, int enabled ); + + /// See ::optixDeviceContextSetCacheLocation(). + OptixResult ( *optixDeviceContextSetCacheLocation )( OptixDeviceContext context, const char* location ); + + /// See ::optixDeviceContextSetCacheDatabaseSizes(). + OptixResult ( *optixDeviceContextSetCacheDatabaseSizes )( OptixDeviceContext context, size_t lowWaterMark, size_t highWaterMark ); + + /// See ::optixDeviceContextGetCacheEnabled(). + OptixResult ( *optixDeviceContextGetCacheEnabled )( OptixDeviceContext context, int* enabled ); + + /// See ::optixDeviceContextGetCacheLocation(). + OptixResult ( *optixDeviceContextGetCacheLocation )( OptixDeviceContext context, char* location, size_t locationSize ); + + /// See ::optixDeviceContextGetCacheDatabaseSizes(). + OptixResult ( *optixDeviceContextGetCacheDatabaseSizes )( OptixDeviceContext context, size_t* lowWaterMark, size_t* highWaterMark ); + + //@ } + /// \name Modules + //@ { + + /// See ::optixModuleCreateFromPTX(). + OptixResult ( *optixModuleCreateFromPTX )( OptixDeviceContext context, + const OptixModuleCompileOptions* moduleCompileOptions, + const OptixPipelineCompileOptions* pipelineCompileOptions, + const char* PTX, + size_t PTXsize, + char* logString, + size_t* logStringSize, + OptixModule* module ); + + /// See ::optixModuleCreateFromPTXWithTasks(). + OptixResult ( *optixModuleCreateFromPTXWithTasks )( OptixDeviceContext context, + const OptixModuleCompileOptions* moduleCompileOptions, + const OptixPipelineCompileOptions* pipelineCompileOptions, + const char* PTX, + size_t PTXsize, + char* logString, + size_t* logStringSize, + OptixModule* module, + OptixTask* firstTask ); + + /// See ::optixModuleGetCompilationState(). + OptixResult ( *optixModuleGetCompilationState )( OptixModule module, OptixModuleCompileState* state ); + + /// See ::optixModuleDestroy(). + OptixResult ( *optixModuleDestroy )( OptixModule module ); + + /// See ::optixBuiltinISModuleGet(). + OptixResult( *optixBuiltinISModuleGet )( OptixDeviceContext context, + const OptixModuleCompileOptions* moduleCompileOptions, + const OptixPipelineCompileOptions* pipelineCompileOptions, + const OptixBuiltinISOptions* builtinISOptions, + OptixModule* builtinModule); + + //@ } + /// \name Tasks + //@ { + + /// See ::optixTaskExecute(). + OptixResult ( *optixTaskExecute )( OptixTask task, + OptixTask* additionalTasks, + unsigned int maxNumAdditionalTasks, + unsigned int* numAdditionalTasksCreated ); + //@ } + /// \name Program groups + //@ { + + /// See ::optixProgramGroupCreate(). + OptixResult ( *optixProgramGroupCreate )( OptixDeviceContext context, + const OptixProgramGroupDesc* programDescriptions, + unsigned int numProgramGroups, + const OptixProgramGroupOptions* options, + char* logString, + size_t* logStringSize, + OptixProgramGroup* programGroups ); + + /// See ::optixProgramGroupDestroy(). + OptixResult ( *optixProgramGroupDestroy )( OptixProgramGroup programGroup ); + + /// See ::optixProgramGroupGetStackSize(). + OptixResult ( *optixProgramGroupGetStackSize )( OptixProgramGroup programGroup, OptixStackSizes* stackSizes ); + + //@ } + /// \name Pipeline + //@ { + + /// See ::optixPipelineCreate(). + OptixResult ( *optixPipelineCreate )( OptixDeviceContext context, + const OptixPipelineCompileOptions* pipelineCompileOptions, + const OptixPipelineLinkOptions* pipelineLinkOptions, + const OptixProgramGroup* programGroups, + unsigned int numProgramGroups, + char* logString, + size_t* logStringSize, + OptixPipeline* pipeline ); + + /// See ::optixPipelineDestroy(). + OptixResult ( *optixPipelineDestroy )( OptixPipeline pipeline ); + + /// See ::optixPipelineSetStackSize(). + OptixResult ( *optixPipelineSetStackSize )( OptixPipeline pipeline, + unsigned int directCallableStackSizeFromTraversal, + unsigned int directCallableStackSizeFromState, + unsigned int continuationStackSize, + unsigned int maxTraversableGraphDepth ); + + //@ } + /// \name Acceleration structures + //@ { + + /// See ::optixAccelComputeMemoryUsage(). + OptixResult ( *optixAccelComputeMemoryUsage )( OptixDeviceContext context, + const OptixAccelBuildOptions* accelOptions, + const OptixBuildInput* buildInputs, + unsigned int numBuildInputs, + OptixAccelBufferSizes* bufferSizes ); + + /// See ::optixAccelBuild(). + OptixResult ( *optixAccelBuild )( OptixDeviceContext context, + CUstream stream, + const OptixAccelBuildOptions* accelOptions, + const OptixBuildInput* buildInputs, + unsigned int numBuildInputs, + CUdeviceptr tempBuffer, + size_t tempBufferSizeInBytes, + CUdeviceptr outputBuffer, + size_t outputBufferSizeInBytes, + OptixTraversableHandle* outputHandle, + const OptixAccelEmitDesc* emittedProperties, + unsigned int numEmittedProperties ); + + /// See ::optixAccelGetRelocationInfo(). + OptixResult ( *optixAccelGetRelocationInfo )( OptixDeviceContext context, OptixTraversableHandle handle, OptixAccelRelocationInfo* info ); + + + /// See ::optixAccelCheckRelocationCompatibility(). + OptixResult ( *optixAccelCheckRelocationCompatibility )( OptixDeviceContext context, + const OptixAccelRelocationInfo* info, + int* compatible ); + + /// See ::optixAccelRelocate(). + OptixResult ( *optixAccelRelocate )( OptixDeviceContext context, + CUstream stream, + const OptixAccelRelocationInfo* info, + CUdeviceptr instanceTraversableHandles, + size_t numInstanceTraversableHandles, + CUdeviceptr targetAccel, + size_t targetAccelSizeInBytes, + OptixTraversableHandle* targetHandle ); + + + /// See ::optixAccelCompact(). + OptixResult ( *optixAccelCompact )( OptixDeviceContext context, + CUstream stream, + OptixTraversableHandle inputHandle, + CUdeviceptr outputBuffer, + size_t outputBufferSizeInBytes, + OptixTraversableHandle* outputHandle ); + + /// See ::optixConvertPointerToTraversableHandle(). + OptixResult ( *optixConvertPointerToTraversableHandle )( OptixDeviceContext onDevice, + CUdeviceptr pointer, + OptixTraversableType traversableType, + OptixTraversableHandle* traversableHandle ); + + void ( *reserved1 )( void ); + void ( *reserved2 )( void ); + + //@ } + /// \name Launch + //@ { + + /// See ::optixConvertPointerToTraversableHandle(). + OptixResult ( *optixSbtRecordPackHeader )( OptixProgramGroup programGroup, void* sbtRecordHeaderHostPointer ); + + /// See ::optixConvertPointerToTraversableHandle(). + OptixResult ( *optixLaunch )( OptixPipeline pipeline, + CUstream stream, + CUdeviceptr pipelineParams, + size_t pipelineParamsSize, + const OptixShaderBindingTable* sbt, + unsigned int width, + unsigned int height, + unsigned int depth ); + + //@ } + /// \name Denoiser + //@ { + + /// See ::optixDenoiserCreate(). + OptixResult ( *optixDenoiserCreate )( OptixDeviceContext context, OptixDenoiserModelKind modelKind, const OptixDenoiserOptions* options, OptixDenoiser* returnHandle ); + + /// See ::optixDenoiserDestroy(). + OptixResult ( *optixDenoiserDestroy )( OptixDenoiser handle ); + + /// See ::optixDenoiserComputeMemoryResources(). + OptixResult ( *optixDenoiserComputeMemoryResources )( const OptixDenoiser handle, + unsigned int maximumInputWidth, + unsigned int maximumInputHeight, + OptixDenoiserSizes* returnSizes ); + + /// See ::optixDenoiserSetup(). + OptixResult ( *optixDenoiserSetup )( OptixDenoiser denoiser, + CUstream stream, + unsigned int inputWidth, + unsigned int inputHeight, + CUdeviceptr state, + size_t stateSizeInBytes, + CUdeviceptr scratch, + size_t scratchSizeInBytes ); + + /// See ::optixDenoiserInvoke(). + OptixResult ( *optixDenoiserInvoke )( OptixDenoiser denoiser, + CUstream stream, + const OptixDenoiserParams* params, + CUdeviceptr denoiserState, + size_t denoiserStateSizeInBytes, + const OptixDenoiserGuideLayer * guideLayer, + const OptixDenoiserLayer * layers, + unsigned int numLayers, + unsigned int inputOffsetX, + unsigned int inputOffsetY, + CUdeviceptr scratch, + size_t scratchSizeInBytes ); + + /// See ::optixDenoiserComputeIntensity(). + OptixResult ( *optixDenoiserComputeIntensity )( OptixDenoiser handle, + CUstream stream, + const OptixImage2D* inputImage, + CUdeviceptr outputIntensity, + CUdeviceptr scratch, + size_t scratchSizeInBytes ); + + /// See ::optixDenoiserComputeAverageColor(). + OptixResult ( *optixDenoiserComputeAverageColor )( OptixDenoiser handle, + CUstream stream, + const OptixImage2D* inputImage, + CUdeviceptr outputAverageColor, + CUdeviceptr scratch, + size_t scratchSizeInBytes ); + + /// See ::optixDenoiserCreateWithUserModel(). + OptixResult ( *optixDenoiserCreateWithUserModel )( OptixDeviceContext context, const void * data, size_t dataSizeInBytes, OptixDenoiser* returnHandle ); + //@ } + +} OptixFunctionTable; + +/*@}*/ // end group optix_function_table + +#ifdef __cplusplus +} +#endif + +#endif /* OPTIX_DEFINE_ABI_VERSION_ONLY */ + +#endif /* __optix_optix_function_table_h__ */ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_function_table_definition.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_function_table_definition.h new file mode 100644 index 00000000..87ca3ec3 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_function_table_definition.h @@ -0,0 +1,40 @@ +/* +* SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* SPDX-License-Identifier: LicenseRef-NvidiaProprietary +* +* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +* property and proprietary rights in and to this material, related +* documentation and any modifications thereto. Any use, reproduction, +* disclosure or distribution of this material and related documentation +* without an express license agreement from NVIDIA CORPORATION or +* its affiliates is strictly prohibited. +*/ +/// @file +/// @author NVIDIA Corporation +/// @brief OptiX public API header + +#ifndef __optix_optix_function_table_definition_h__ +#define __optix_optix_function_table_definition_h__ + +#include "optix_function_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \addtogroup optix_function_table +@{ +*/ + +/// If the stubs in optix_stubs.h are used, then the function table needs to be defined in exactly +/// one translation unit. This can be achieved by including this header file in that translation +/// unit. +OptixFunctionTable g_optixFunctionTable; + +/*@}*/ // end group optix_function_table + +#ifdef __cplusplus +} +#endif + +#endif // __optix_optix_function_table_definition_h__ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_host.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_host.h new file mode 100644 index 00000000..e85bc491 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_host.h @@ -0,0 +1,29 @@ + +/* +* SPDX-FileCopyrightText: Copyright (c) 2010 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* SPDX-License-Identifier: LicenseRef-NvidiaProprietary +* +* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +* property and proprietary rights in and to this material, related +* documentation and any modifications thereto. Any use, reproduction, +* disclosure or distribution of this material and related documentation +* without an express license agreement from NVIDIA CORPORATION or +* its affiliates is strictly prohibited. +*/ +/** + * @file optix_host.h + * @author NVIDIA Corporation + * @brief OptiX public API + * + * OptiX public API Reference - Host side + */ + +#if !defined(__OPTIX_INCLUDE_INTERNAL_HEADERS__) +# define __OPTIX_INCLUDE_INTERNAL_HEADERS__ +# define __UNDEF_OPTIX_INCLUDE_INTERNAL_HEADERS_OPTIX_HOST_H__ +#endif +#include "optix_7_host.h" +#if defined( __UNDEF_OPTIX_INCLUDE_INTERNAL_HEADERS_OPTIX_HOST_H__ ) +# undef __OPTIX_INCLUDE_INTERNAL_HEADERS__ +# undef __UNDEF_OPTIX_INCLUDE_INTERNAL_HEADERS_OPTIX_HOST_H__ +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_stack_size.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_stack_size.h new file mode 100644 index 00000000..be7c77e8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_stack_size.h @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of NVIDIA CORPORATION nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/// @file +/// @author NVIDIA Corporation +/// @brief OptiX public API header + +#ifndef __optix_optix_stack_size_h__ +#define __optix_optix_stack_size_h__ + +#include "optix.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \addtogroup optix_utilities +@{ +*/ + +/// Retrieves direct and continuation stack sizes for each program in the program group and accumulates the upper bounds +/// in the correponding output variables based on the semantic type of the program. Before the first invocation of this +/// function with a given instance of #OptixStackSizes, the members of that instance should be set to 0. +inline OptixResult optixUtilAccumulateStackSizes( OptixProgramGroup programGroup, OptixStackSizes* stackSizes ) +{ + if( !stackSizes ) + return OPTIX_ERROR_INVALID_VALUE; + + OptixStackSizes localStackSizes; + OptixResult result = optixProgramGroupGetStackSize( programGroup, &localStackSizes ); + if( result != OPTIX_SUCCESS ) + return result; + + stackSizes->cssRG = std::max( stackSizes->cssRG, localStackSizes.cssRG ); + stackSizes->cssMS = std::max( stackSizes->cssMS, localStackSizes.cssMS ); + stackSizes->cssCH = std::max( stackSizes->cssCH, localStackSizes.cssCH ); + stackSizes->cssAH = std::max( stackSizes->cssAH, localStackSizes.cssAH ); + stackSizes->cssIS = std::max( stackSizes->cssIS, localStackSizes.cssIS ); + stackSizes->cssCC = std::max( stackSizes->cssCC, localStackSizes.cssCC ); + stackSizes->dssDC = std::max( stackSizes->dssDC, localStackSizes.dssDC ); + + return OPTIX_SUCCESS; +} + +/// Computes the stack size values needed to configure a pipeline. +/// +/// See the programming guide for an explanation of the formula. +/// +/// \param[in] stackSizes Accumulated stack sizes of all programs in the call graph. +/// \param[in] maxTraceDepth Maximum depth of #optixTrace() calls. +/// \param[in] maxCCDepth Maximum depth of calls trees of continuation callables. +/// \param[in] maxDCDepth Maximum depth of calls trees of direct callables. +/// \param[out] directCallableStackSizeFromTraversal Direct stack size requirement for direct callables invoked from +/// IS or AH. +/// \param[out] directCallableStackSizeFromState Direct stack size requirement for direct callables invoked from +/// RG, MS, or CH. +/// \param[out] continuationStackSize Continuation stack requirement. +inline OptixResult optixUtilComputeStackSizes( const OptixStackSizes* stackSizes, + unsigned int maxTraceDepth, + unsigned int maxCCDepth, + unsigned int maxDCDepth, + unsigned int* directCallableStackSizeFromTraversal, + unsigned int* directCallableStackSizeFromState, + unsigned int* continuationStackSize ) +{ + if( !stackSizes ) + return OPTIX_ERROR_INVALID_VALUE; + + const unsigned int cssRG = stackSizes->cssRG; + const unsigned int cssMS = stackSizes->cssMS; + const unsigned int cssCH = stackSizes->cssCH; + const unsigned int cssAH = stackSizes->cssAH; + const unsigned int cssIS = stackSizes->cssIS; + const unsigned int cssCC = stackSizes->cssCC; + const unsigned int dssDC = stackSizes->dssDC; + + if( directCallableStackSizeFromTraversal ) + *directCallableStackSizeFromTraversal = maxDCDepth * dssDC; + if( directCallableStackSizeFromState ) + *directCallableStackSizeFromState = maxDCDepth * dssDC; + + // upper bound on continuation stack used by call trees of continuation callables + unsigned int cssCCTree = maxCCDepth * cssCC; + + // upper bound on continuation stack used by CH or MS programs including the call tree of + // continuation callables + unsigned int cssCHOrMSPlusCCTree = std::max( cssCH, cssMS ) + cssCCTree; + + // clang-format off + if( continuationStackSize ) + *continuationStackSize + = cssRG + cssCCTree + + ( std::max( maxTraceDepth, 1u ) - 1 ) * cssCHOrMSPlusCCTree + + std::min( maxTraceDepth, 1u ) * std::max( cssCHOrMSPlusCCTree, cssIS + cssAH ); + // clang-format on + + return OPTIX_SUCCESS; +} + +/// Computes the stack size values needed to configure a pipeline. +/// +/// This variant is similar to #optixUtilComputeStackSizes(), except that it expects the values dssDC and +/// maxDCDepth split by call site semantic. +/// +/// See programming guide for an explanation of the formula. +/// +/// \param[in] stackSizes Accumulated stack sizes of all programs in the call graph. +/// \param[in] dssDCFromTraversal Accumulated direct stack size of all DC programs invoked from IS +/// or AH. +/// \param[in] dssDCFromState Accumulated direct stack size of all DC programs invoked from RG, +/// MS, or CH. +/// \param[in] maxTraceDepth Maximum depth of #optixTrace() calls. +/// \param[in] maxCCDepth Maximum depth of calls trees of continuation callables. +/// \param[in] maxDCDepthFromTraversal Maximum depth of calls trees of direct callables invoked from IS +/// or AH. +/// \param[in] maxDCDepthFromState Maximum depth of calls trees of direct callables invoked from RG, +/// MS, or CH. +/// \param[out] directCallableStackSizeFromTraversal Direct stack size requirement for direct callables invoked from +/// IS or AH. +/// \param[out] directCallableStackSizeFromState Direct stack size requirement for direct callables invoked from +/// RG, MS, or CH. +/// \param[out] continuationStackSize Continuation stack requirement. +inline OptixResult optixUtilComputeStackSizesDCSplit( const OptixStackSizes* stackSizes, + unsigned int dssDCFromTraversal, + unsigned int dssDCFromState, + unsigned int maxTraceDepth, + unsigned int maxCCDepth, + unsigned int maxDCDepthFromTraversal, + unsigned int maxDCDepthFromState, + unsigned int* directCallableStackSizeFromTraversal, + unsigned int* directCallableStackSizeFromState, + unsigned int* continuationStackSize ) +{ + if( !stackSizes ) + return OPTIX_ERROR_INVALID_VALUE; + + const unsigned int cssRG = stackSizes->cssRG; + const unsigned int cssMS = stackSizes->cssMS; + const unsigned int cssCH = stackSizes->cssCH; + const unsigned int cssAH = stackSizes->cssAH; + const unsigned int cssIS = stackSizes->cssIS; + const unsigned int cssCC = stackSizes->cssCC; + // use dssDCFromTraversal and dssDCFromState instead of stackSizes->dssDC + + if( directCallableStackSizeFromTraversal ) + *directCallableStackSizeFromTraversal = maxDCDepthFromTraversal * dssDCFromTraversal; + if( directCallableStackSizeFromState ) + *directCallableStackSizeFromState = maxDCDepthFromState * dssDCFromState; + + // upper bound on continuation stack used by call trees of continuation callables + unsigned int cssCCTree = maxCCDepth * cssCC; + + // upper bound on continuation stack used by CH or MS programs including the call tree of + // continuation callables + unsigned int cssCHOrMSPlusCCTree = std::max( cssCH, cssMS ) + cssCCTree; + + // clang-format off + if( continuationStackSize ) + *continuationStackSize + = cssRG + cssCCTree + + ( std::max( maxTraceDepth, 1u ) - 1 ) * cssCHOrMSPlusCCTree + + std::min( maxTraceDepth, 1u ) * std::max( cssCHOrMSPlusCCTree, cssIS + cssAH ); + // clang-format on + + return OPTIX_SUCCESS; +} + +/// Computes the stack size values needed to configure a pipeline. +/// +/// This variant is similar to #optixUtilComputeStackSizes(), except that it expects the value cssCCTree +/// instead of cssCC and maxCCDepth. +/// +/// See programming guide for an explanation of the formula. +/// +/// \param[in] stackSizes Accumulated stack sizes of all programs in the call graph. +/// \param[in] cssCCTree Maximum stack size used by calls trees of continuation callables. +/// \param[in] maxTraceDepth Maximum depth of #optixTrace() calls. +/// \param[in] maxDCDepth Maximum depth of calls trees of direct callables. +/// \param[out] directCallableStackSizeFromTraversal Direct stack size requirement for direct callables invoked from +/// IS or AH. +/// \param[out] directCallableStackSizeFromState Direct stack size requirement for direct callables invoked from +/// RG, MS, or CH. +/// \param[out] continuationStackSize Continuation stack requirement. +inline OptixResult optixUtilComputeStackSizesCssCCTree( const OptixStackSizes* stackSizes, + unsigned int cssCCTree, + unsigned int maxTraceDepth, + unsigned int maxDCDepth, + unsigned int* directCallableStackSizeFromTraversal, + unsigned int* directCallableStackSizeFromState, + unsigned int* continuationStackSize ) +{ + if( !stackSizes ) + return OPTIX_ERROR_INVALID_VALUE; + + const unsigned int cssRG = stackSizes->cssRG; + const unsigned int cssMS = stackSizes->cssMS; + const unsigned int cssCH = stackSizes->cssCH; + const unsigned int cssAH = stackSizes->cssAH; + const unsigned int cssIS = stackSizes->cssIS; + // use cssCCTree instead of stackSizes->cssCC and maxCCDepth + const unsigned int dssDC = stackSizes->dssDC; + + if( directCallableStackSizeFromTraversal ) + *directCallableStackSizeFromTraversal = maxDCDepth * dssDC; + if( directCallableStackSizeFromState ) + *directCallableStackSizeFromState = maxDCDepth * dssDC; + + // upper bound on continuation stack used by CH or MS programs including the call tree of + // continuation callables + unsigned int cssCHOrMSPlusCCTree = std::max( cssCH, cssMS ) + cssCCTree; + + // clang-format off + if( continuationStackSize ) + *continuationStackSize + = cssRG + cssCCTree + + ( std::max( maxTraceDepth, 1u ) - 1 ) * cssCHOrMSPlusCCTree + + std::min( maxTraceDepth, 1u ) * std::max( cssCHOrMSPlusCCTree, cssIS + cssAH ); + // clang-format on + + return OPTIX_SUCCESS; +} + +/// Computes the stack size values needed to configure a pipeline. +/// +/// This variant is a specialization of #optixUtilComputeStackSizes() for a simple path tracer with the following +/// assumptions: There are only two ray types, camera rays and shadow rays. There are only RG, MS, and CH programs, and +/// no AH, IS, CC, or DC programs. The camera rays invoke only the miss and closest hit programs MS1 and CH1, +/// respectively. The CH1 program might trace shadow rays, which invoke only the miss and closest hit programs MS2 and +/// CH2, respectively. +/// +/// For flexibility, we allow for each of CH1 and CH2 not just one single program group, but an array of programs +/// groups, and compute the maximas of the stack size requirements per array. +/// +/// See programming guide for an explanation of the formula. +inline OptixResult optixUtilComputeStackSizesSimplePathTracer( OptixProgramGroup programGroupRG, + OptixProgramGroup programGroupMS1, + const OptixProgramGroup* programGroupCH1, + unsigned int programGroupCH1Count, + OptixProgramGroup programGroupMS2, + const OptixProgramGroup* programGroupCH2, + unsigned int programGroupCH2Count, + unsigned int* directCallableStackSizeFromTraversal, + unsigned int* directCallableStackSizeFromState, + unsigned int* continuationStackSize ) +{ + if( !programGroupCH1 && ( programGroupCH1Count > 0 ) ) + return OPTIX_ERROR_INVALID_VALUE; + if( !programGroupCH2 && ( programGroupCH2Count > 0 ) ) + return OPTIX_ERROR_INVALID_VALUE; + + OptixResult result; + + OptixStackSizes stackSizesRG = {}; + result = optixProgramGroupGetStackSize( programGroupRG, &stackSizesRG ); + if( result != OPTIX_SUCCESS ) + return result; + + OptixStackSizes stackSizesMS1 = {}; + result = optixProgramGroupGetStackSize( programGroupMS1, &stackSizesMS1 ); + if( result != OPTIX_SUCCESS ) + return result; + + OptixStackSizes stackSizesCH1 = {}; + for( unsigned int i = 0; i < programGroupCH1Count; ++i ) + { + result = optixUtilAccumulateStackSizes( programGroupCH1[i], &stackSizesCH1 ); + if( result != OPTIX_SUCCESS ) + return result; + } + + OptixStackSizes stackSizesMS2 = {}; + result = optixProgramGroupGetStackSize( programGroupMS2, &stackSizesMS2 ); + if( result != OPTIX_SUCCESS ) + return result; + + OptixStackSizes stackSizesCH2 = {}; + memset( &stackSizesCH2, 0, sizeof( OptixStackSizes ) ); + for( unsigned int i = 0; i < programGroupCH2Count; ++i ) + { + result = optixUtilAccumulateStackSizes( programGroupCH2[i], &stackSizesCH2 ); + if( result != OPTIX_SUCCESS ) + return result; + } + + const unsigned int cssRG = stackSizesRG.cssRG; + const unsigned int cssMS1 = stackSizesMS1.cssMS; + const unsigned int cssCH1 = stackSizesCH1.cssCH; + const unsigned int cssMS2 = stackSizesMS2.cssMS; + const unsigned int cssCH2 = stackSizesCH2.cssCH; + // no AH, IS, CC, or DC programs + + if( directCallableStackSizeFromTraversal ) + *directCallableStackSizeFromTraversal = 0; + if( directCallableStackSizeFromState ) + *directCallableStackSizeFromState = 0; + + if( continuationStackSize ) + *continuationStackSize = cssRG + std::max( cssMS1, cssCH1 + std::max( cssMS2, cssCH2 ) ); + + return OPTIX_SUCCESS; +} + +/*@}*/ // end group optix_utilities + +#ifdef __cplusplus +} +#endif + +#endif // __optix_optix_stack_size_h__ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_stubs.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_stubs.h new file mode 100644 index 00000000..bca0d50e --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_stubs.h @@ -0,0 +1,651 @@ +/* + * Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of NVIDIA CORPORATION nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/// @file +/// @author NVIDIA Corporation +/// @brief OptiX public API header + +#ifndef __optix_optix_stubs_h__ +#define __optix_optix_stubs_h__ + +#include "optix_function_table.h" + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +// The cfgmgr32 header is necessary for interrogating driver information in the registry. +// For convenience the library is also linked in automatically using the #pragma command. +#include +#pragma comment( lib, "Cfgmgr32.lib" ) +#include +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// The function table needs to be defined in exactly one translation unit. This can be +// achieved by including optix_function_table_definition.h in that translation unit. +extern OptixFunctionTable g_optixFunctionTable; + +#ifdef _WIN32 +#if defined( _MSC_VER ) +// Visual Studio produces warnings suggesting strcpy and friends being replaced with _s +// variants. All the string lengths and allocation sizes have been calculated and should +// be safe, so we are disabling this warning to increase compatibility. +# pragma warning( push ) +# pragma warning( disable : 4996 ) +#endif +static void* optixLoadWindowsDllFromName( const char* optixDllName ) +{ + void* handle = NULL; + + + // Get the size of the path first, then allocate + unsigned int size = GetSystemDirectoryA( NULL, 0 ); + if( size == 0 ) + { + // Couldn't get the system path size, so bail + return NULL; + } + size_t pathSize = size + 1 + strlen( optixDllName ); + char* systemPath = (char*)malloc( pathSize ); + if( systemPath == NULL ) + return NULL; + if( GetSystemDirectoryA( systemPath, size ) != size - 1 ) + { + // Something went wrong + free( systemPath ); + return NULL; + } + strcat( systemPath, "\\" ); + strcat( systemPath, optixDllName ); + handle = LoadLibraryA( systemPath ); + free( systemPath ); + if( handle ) + return handle; + + // If we didn't find it, go looking in the register store. Since nvoptix.dll doesn't + // have its own registry entry, we are going to look for the opengl driver which lives + // next to nvoptix.dll. 0 (null) will be returned if any errors occured. + + static const char* deviceInstanceIdentifiersGUID = "{4d36e968-e325-11ce-bfc1-08002be10318}"; + const ULONG flags = CM_GETIDLIST_FILTER_CLASS | CM_GETIDLIST_FILTER_PRESENT; + ULONG deviceListSize = 0; + if( CM_Get_Device_ID_List_SizeA( &deviceListSize, deviceInstanceIdentifiersGUID, flags ) != CR_SUCCESS ) + { + return NULL; + } + char* deviceNames = (char*)malloc( deviceListSize ); + if( deviceNames == NULL ) + return NULL; + if( CM_Get_Device_ID_ListA( deviceInstanceIdentifiersGUID, deviceNames, deviceListSize, flags ) ) + { + free( deviceNames ); + return NULL; + } + DEVINST devID = 0; + char* dllPath = NULL; + + // Continue to the next device if errors are encountered. + for( char* deviceName = deviceNames; *deviceName; deviceName += strlen( deviceName ) + 1 ) + { + if( CM_Locate_DevNodeA( &devID, deviceName, CM_LOCATE_DEVNODE_NORMAL ) != CR_SUCCESS ) + { + continue; + } + HKEY regKey = 0; + if( CM_Open_DevNode_Key( devID, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, ®Key, CM_REGISTRY_SOFTWARE ) != CR_SUCCESS ) + { + continue; + } + const char* valueName = "OpenGLDriverName"; + DWORD valueSize = 0; + LSTATUS ret = RegQueryValueExA( regKey, valueName, NULL, NULL, NULL, &valueSize ); + if( ret != ERROR_SUCCESS ) + { + RegCloseKey( regKey ); + continue; + } + char* regValue = (char*)malloc( valueSize ); + if( regValue == NULL ) + { + RegCloseKey( regKey ); + continue; + } + ret = RegQueryValueExA( regKey, valueName, NULL, NULL, (LPBYTE)regValue, &valueSize ); + if( ret != ERROR_SUCCESS ) + { + free( regValue ); + RegCloseKey( regKey ); + continue; + } + // Strip the opengl driver dll name from the string then create a new string with + // the path and the nvoptix.dll name + for( int i = (int) valueSize - 1; i >= 0 && regValue[i] != '\\'; --i ) + regValue[i] = '\0'; + size_t newPathSize = strlen( regValue ) + strlen( optixDllName ) + 1; + dllPath = (char*)malloc( newPathSize ); + if( dllPath == NULL ) + { + free( regValue ); + RegCloseKey( regKey ); + continue; + } + strcpy( dllPath, regValue ); + strcat( dllPath, optixDllName ); + free( regValue ); + RegCloseKey( regKey ); + handle = LoadLibraryA( (LPCSTR)dllPath ); + free( dllPath ); + if( handle ) + break; + } + free( deviceNames ); + return handle; +} +#if defined( _MSC_VER ) +# pragma warning( pop ) +#endif + +static void* optixLoadWindowsDll( ) +{ + return optixLoadWindowsDllFromName( "nvoptix.dll" ); +} +#endif + +/// \defgroup optix_utilities Utilities +/// \brief OptiX Utilities + +/** \addtogroup optix_utilities +@{ +*/ + +/// Loads the OptiX library and initializes the function table used by the stubs below. +/// +/// If handlePtr is not nullptr, an OS-specific handle to the library will be returned in *handlePtr. +/// +/// \see #optixUninitWithHandle +inline OptixResult optixInitWithHandle( void** handlePtr ) +{ + // Make sure these functions get initialized to zero in case the DLL and function + // table can't be loaded + g_optixFunctionTable.optixGetErrorName = 0; + g_optixFunctionTable.optixGetErrorString = 0; + + if( !handlePtr ) + return OPTIX_ERROR_INVALID_VALUE; + +#ifdef _WIN32 + *handlePtr = optixLoadWindowsDll(); + if( !*handlePtr ) + return OPTIX_ERROR_LIBRARY_NOT_FOUND; + + void* symbol = GetProcAddress( (HMODULE)*handlePtr, "optixQueryFunctionTable" ); + if( !symbol ) + return OPTIX_ERROR_ENTRY_SYMBOL_NOT_FOUND; +#else + *handlePtr = dlopen( "libnvoptix.so.1", RTLD_NOW ); + if( !*handlePtr ) + return OPTIX_ERROR_LIBRARY_NOT_FOUND; + + void* symbol = dlsym( *handlePtr, "optixQueryFunctionTable" ); + if( !symbol ) + return OPTIX_ERROR_ENTRY_SYMBOL_NOT_FOUND; +#endif + + OptixQueryFunctionTable_t* optixQueryFunctionTable = (OptixQueryFunctionTable_t*)symbol; + + return optixQueryFunctionTable( OPTIX_ABI_VERSION, 0, 0, 0, &g_optixFunctionTable, sizeof( g_optixFunctionTable ) ); +} + +/// Loads the OptiX library and initializes the function table used by the stubs below. +/// +/// A variant of #optixInitWithHandle() that does not make the handle to the loaded library available. +inline OptixResult optixInit( void ) +{ + void* handle; + return optixInitWithHandle( &handle ); +} + +/// Unloads the OptiX library and zeros the function table used by the stubs below. Takes the +/// handle returned by optixInitWithHandle. All OptixDeviceContext objects must be destroyed +/// before calling this function, or the behavior is undefined. +/// +/// \see #optixInitWithHandle +inline OptixResult optixUninitWithHandle( void* handle ) +{ + if( !handle ) + return OPTIX_ERROR_INVALID_VALUE; +#ifdef _WIN32 + if( !FreeLibrary( (HMODULE)handle ) ) + return OPTIX_ERROR_LIBRARY_UNLOAD_FAILURE; +#else + if( dlclose( handle ) ) + return OPTIX_ERROR_LIBRARY_UNLOAD_FAILURE; +#endif + OptixFunctionTable empty = { 0 }; + g_optixFunctionTable = empty; + return OPTIX_SUCCESS; +} + + +/*@}*/ // end group optix_utilities + +#ifndef OPTIX_DOXYGEN_SHOULD_SKIP_THIS + +// Stub functions that forward calls to the corresponding function pointer in the function table. + +inline const char* optixGetErrorName( OptixResult result ) +{ + if( g_optixFunctionTable.optixGetErrorName ) + return g_optixFunctionTable.optixGetErrorName( result ); + + // If the DLL and symbol table couldn't be loaded, provide a set of error strings + // suitable for processing errors related to the DLL loading. + switch( result ) + { + case OPTIX_SUCCESS: + return "OPTIX_SUCCESS"; + case OPTIX_ERROR_INVALID_VALUE: + return "OPTIX_ERROR_INVALID_VALUE"; + case OPTIX_ERROR_UNSUPPORTED_ABI_VERSION: + return "OPTIX_ERROR_UNSUPPORTED_ABI_VERSION"; + case OPTIX_ERROR_FUNCTION_TABLE_SIZE_MISMATCH: + return "OPTIX_ERROR_FUNCTION_TABLE_SIZE_MISMATCH"; + case OPTIX_ERROR_INVALID_ENTRY_FUNCTION_OPTIONS: + return "OPTIX_ERROR_INVALID_ENTRY_FUNCTION_OPTIONS"; + case OPTIX_ERROR_LIBRARY_NOT_FOUND: + return "OPTIX_ERROR_LIBRARY_NOT_FOUND"; + case OPTIX_ERROR_ENTRY_SYMBOL_NOT_FOUND: + return "OPTIX_ERROR_ENTRY_SYMBOL_NOT_FOUND"; + case OPTIX_ERROR_LIBRARY_UNLOAD_FAILURE: + return "OPTIX_ERROR_LIBRARY_UNLOAD_FAILURE"; + default: + return "Unknown OptixResult code"; + } +} + +inline const char* optixGetErrorString( OptixResult result ) +{ + if( g_optixFunctionTable.optixGetErrorString ) + return g_optixFunctionTable.optixGetErrorString( result ); + + // If the DLL and symbol table couldn't be loaded, provide a set of error strings + // suitable for processing errors related to the DLL loading. + switch( result ) + { + case OPTIX_SUCCESS: + return "Success"; + case OPTIX_ERROR_INVALID_VALUE: + return "Invalid value"; + case OPTIX_ERROR_UNSUPPORTED_ABI_VERSION: + return "Unsupported ABI version"; + case OPTIX_ERROR_FUNCTION_TABLE_SIZE_MISMATCH: + return "Function table size mismatch"; + case OPTIX_ERROR_INVALID_ENTRY_FUNCTION_OPTIONS: + return "Invalid options to entry function"; + case OPTIX_ERROR_LIBRARY_NOT_FOUND: + return "Library not found"; + case OPTIX_ERROR_ENTRY_SYMBOL_NOT_FOUND: + return "Entry symbol not found"; + case OPTIX_ERROR_LIBRARY_UNLOAD_FAILURE: + return "Library could not be unloaded"; + default: + return "Unknown OptixResult code"; + } +} + +inline OptixResult optixDeviceContextCreate( CUcontext fromContext, const OptixDeviceContextOptions* options, OptixDeviceContext* context ) +{ + return g_optixFunctionTable.optixDeviceContextCreate( fromContext, options, context ); +} + +inline OptixResult optixDeviceContextDestroy( OptixDeviceContext context ) +{ + return g_optixFunctionTable.optixDeviceContextDestroy( context ); +} + +inline OptixResult optixDeviceContextGetProperty( OptixDeviceContext context, OptixDeviceProperty property, void* value, size_t sizeInBytes ) +{ + return g_optixFunctionTable.optixDeviceContextGetProperty( context, property, value, sizeInBytes ); +} + +inline OptixResult optixDeviceContextSetLogCallback( OptixDeviceContext context, + OptixLogCallback callbackFunction, + void* callbackData, + unsigned int callbackLevel ) +{ + return g_optixFunctionTable.optixDeviceContextSetLogCallback( context, callbackFunction, callbackData, callbackLevel ); +} + +inline OptixResult optixDeviceContextSetCacheEnabled( OptixDeviceContext context, int enabled ) +{ + return g_optixFunctionTable.optixDeviceContextSetCacheEnabled( context, enabled ); +} + +inline OptixResult optixDeviceContextSetCacheLocation( OptixDeviceContext context, const char* location ) +{ + return g_optixFunctionTable.optixDeviceContextSetCacheLocation( context, location ); +} + +inline OptixResult optixDeviceContextSetCacheDatabaseSizes( OptixDeviceContext context, size_t lowWaterMark, size_t highWaterMark ) +{ + return g_optixFunctionTable.optixDeviceContextSetCacheDatabaseSizes( context, lowWaterMark, highWaterMark ); +} + +inline OptixResult optixDeviceContextGetCacheEnabled( OptixDeviceContext context, int* enabled ) +{ + return g_optixFunctionTable.optixDeviceContextGetCacheEnabled( context, enabled ); +} + +inline OptixResult optixDeviceContextGetCacheLocation( OptixDeviceContext context, char* location, size_t locationSize ) +{ + return g_optixFunctionTable.optixDeviceContextGetCacheLocation( context, location, locationSize ); +} + +inline OptixResult optixDeviceContextGetCacheDatabaseSizes( OptixDeviceContext context, size_t* lowWaterMark, size_t* highWaterMark ) +{ + return g_optixFunctionTable.optixDeviceContextGetCacheDatabaseSizes( context, lowWaterMark, highWaterMark ); +} + +inline OptixResult optixModuleCreateFromPTX( OptixDeviceContext context, + const OptixModuleCompileOptions* moduleCompileOptions, + const OptixPipelineCompileOptions* pipelineCompileOptions, + const char* PTX, + size_t PTXsize, + char* logString, + size_t* logStringSize, + OptixModule* module ) +{ + return g_optixFunctionTable.optixModuleCreateFromPTX( context, moduleCompileOptions, pipelineCompileOptions, PTX, + PTXsize, logString, logStringSize, module ); +} + +inline OptixResult optixModuleCreateFromPTXWithTasks( OptixDeviceContext context, + const OptixModuleCompileOptions* moduleCompileOptions, + const OptixPipelineCompileOptions* pipelineCompileOptions, + const char* PTX, + size_t PTXsize, + char* logString, + size_t* logStringSize, + OptixModule* module, + OptixTask* firstTask ) +{ + return g_optixFunctionTable.optixModuleCreateFromPTXWithTasks( context, moduleCompileOptions, pipelineCompileOptions, PTX, + PTXsize, logString, logStringSize, module, firstTask ); +} + +inline OptixResult optixModuleGetCompilationState( OptixModule module, OptixModuleCompileState* state ) +{ + return g_optixFunctionTable.optixModuleGetCompilationState( module, state ); +} + +inline OptixResult optixModuleDestroy( OptixModule module ) +{ + return g_optixFunctionTable.optixModuleDestroy( module ); +} + +inline OptixResult optixBuiltinISModuleGet( OptixDeviceContext context, + const OptixModuleCompileOptions* moduleCompileOptions, + const OptixPipelineCompileOptions* pipelineCompileOptions, + const OptixBuiltinISOptions* builtinISOptions, + OptixModule* builtinModule ) +{ + return g_optixFunctionTable.optixBuiltinISModuleGet( context, moduleCompileOptions, pipelineCompileOptions, + builtinISOptions, builtinModule ); +} + +inline OptixResult optixTaskExecute( OptixTask task, OptixTask* additionalTasks, unsigned int maxNumAdditionalTasks, unsigned int* numAdditionalTasksCreated ) +{ + return g_optixFunctionTable.optixTaskExecute( task, additionalTasks, maxNumAdditionalTasks, numAdditionalTasksCreated ); +} + +inline OptixResult optixProgramGroupCreate( OptixDeviceContext context, + const OptixProgramGroupDesc* programDescriptions, + unsigned int numProgramGroups, + const OptixProgramGroupOptions* options, + char* logString, + size_t* logStringSize, + OptixProgramGroup* programGroups ) +{ + return g_optixFunctionTable.optixProgramGroupCreate( context, programDescriptions, numProgramGroups, options, + logString, logStringSize, programGroups ); +} + +inline OptixResult optixProgramGroupDestroy( OptixProgramGroup programGroup ) +{ + return g_optixFunctionTable.optixProgramGroupDestroy( programGroup ); +} + +inline OptixResult optixProgramGroupGetStackSize( OptixProgramGroup programGroup, OptixStackSizes* stackSizes ) +{ + return g_optixFunctionTable.optixProgramGroupGetStackSize( programGroup, stackSizes ); +} + +inline OptixResult optixPipelineCreate( OptixDeviceContext context, + const OptixPipelineCompileOptions* pipelineCompileOptions, + const OptixPipelineLinkOptions* pipelineLinkOptions, + const OptixProgramGroup* programGroups, + unsigned int numProgramGroups, + char* logString, + size_t* logStringSize, + OptixPipeline* pipeline ) +{ + return g_optixFunctionTable.optixPipelineCreate( context, pipelineCompileOptions, pipelineLinkOptions, programGroups, + numProgramGroups, logString, logStringSize, pipeline ); +} + +inline OptixResult optixPipelineDestroy( OptixPipeline pipeline ) +{ + return g_optixFunctionTable.optixPipelineDestroy( pipeline ); +} + +inline OptixResult optixPipelineSetStackSize( OptixPipeline pipeline, + unsigned int directCallableStackSizeFromTraversal, + unsigned int directCallableStackSizeFromState, + unsigned int continuationStackSize, + unsigned int maxTraversableGraphDepth ) +{ + return g_optixFunctionTable.optixPipelineSetStackSize( pipeline, directCallableStackSizeFromTraversal, directCallableStackSizeFromState, + continuationStackSize, maxTraversableGraphDepth ); +} + +inline OptixResult optixAccelComputeMemoryUsage( OptixDeviceContext context, + const OptixAccelBuildOptions* accelOptions, + const OptixBuildInput* buildInputs, + unsigned int numBuildInputs, + OptixAccelBufferSizes* bufferSizes ) +{ + return g_optixFunctionTable.optixAccelComputeMemoryUsage( context, accelOptions, buildInputs, numBuildInputs, bufferSizes ); +} + +inline OptixResult optixAccelBuild( OptixDeviceContext context, + CUstream stream, + const OptixAccelBuildOptions* accelOptions, + const OptixBuildInput* buildInputs, + unsigned int numBuildInputs, + CUdeviceptr tempBuffer, + size_t tempBufferSizeInBytes, + CUdeviceptr outputBuffer, + size_t outputBufferSizeInBytes, + OptixTraversableHandle* outputHandle, + const OptixAccelEmitDesc* emittedProperties, + unsigned int numEmittedProperties ) +{ + return g_optixFunctionTable.optixAccelBuild( context, stream, accelOptions, buildInputs, numBuildInputs, tempBuffer, + tempBufferSizeInBytes, outputBuffer, outputBufferSizeInBytes, + outputHandle, emittedProperties, numEmittedProperties ); +} + + +inline OptixResult optixAccelGetRelocationInfo( OptixDeviceContext context, OptixTraversableHandle handle, OptixAccelRelocationInfo* info ) +{ + return g_optixFunctionTable.optixAccelGetRelocationInfo( context, handle, info ); +} + + +inline OptixResult optixAccelCheckRelocationCompatibility( OptixDeviceContext context, const OptixAccelRelocationInfo* info, int* compatible ) +{ + return g_optixFunctionTable.optixAccelCheckRelocationCompatibility( context, info, compatible ); +} + +inline OptixResult optixAccelRelocate( OptixDeviceContext context, + CUstream stream, + const OptixAccelRelocationInfo* info, + CUdeviceptr instanceTraversableHandles, + size_t numInstanceTraversableHandles, + CUdeviceptr targetAccel, + size_t targetAccelSizeInBytes, + OptixTraversableHandle* targetHandle ) +{ + return g_optixFunctionTable.optixAccelRelocate( context, stream, info, instanceTraversableHandles, numInstanceTraversableHandles, + targetAccel, targetAccelSizeInBytes, targetHandle ); +} + +inline OptixResult optixAccelCompact( OptixDeviceContext context, + CUstream stream, + OptixTraversableHandle inputHandle, + CUdeviceptr outputBuffer, + size_t outputBufferSizeInBytes, + OptixTraversableHandle* outputHandle ) +{ + return g_optixFunctionTable.optixAccelCompact( context, stream, inputHandle, outputBuffer, outputBufferSizeInBytes, outputHandle ); +} + +inline OptixResult optixConvertPointerToTraversableHandle( OptixDeviceContext onDevice, + CUdeviceptr pointer, + OptixTraversableType traversableType, + OptixTraversableHandle* traversableHandle ) +{ + return g_optixFunctionTable.optixConvertPointerToTraversableHandle( onDevice, pointer, traversableType, traversableHandle ); +} + + +inline OptixResult optixSbtRecordPackHeader( OptixProgramGroup programGroup, void* sbtRecordHeaderHostPointer ) +{ + return g_optixFunctionTable.optixSbtRecordPackHeader( programGroup, sbtRecordHeaderHostPointer ); +} + +inline OptixResult optixLaunch( OptixPipeline pipeline, + CUstream stream, + CUdeviceptr pipelineParams, + size_t pipelineParamsSize, + const OptixShaderBindingTable* sbt, + unsigned int width, + unsigned int height, + unsigned int depth ) +{ + return g_optixFunctionTable.optixLaunch( pipeline, stream, pipelineParams, pipelineParamsSize, sbt, width, height, depth ); +} + +inline OptixResult optixDenoiserCreate( OptixDeviceContext context, OptixDenoiserModelKind modelKind, const OptixDenoiserOptions* options, OptixDenoiser* returnHandle ) +{ + return g_optixFunctionTable.optixDenoiserCreate( context, modelKind, options, returnHandle ); +} + +inline OptixResult optixDenoiserCreateWithUserModel( OptixDeviceContext context, const void* data, size_t dataSizeInBytes, OptixDenoiser* returnHandle ) +{ + return g_optixFunctionTable.optixDenoiserCreateWithUserModel( context, data, dataSizeInBytes, returnHandle ); +} + +inline OptixResult optixDenoiserDestroy( OptixDenoiser handle ) +{ + return g_optixFunctionTable.optixDenoiserDestroy( handle ); +} + +inline OptixResult optixDenoiserComputeMemoryResources( const OptixDenoiser handle, + unsigned int maximumInputWidth, + unsigned int maximumInputHeight, + OptixDenoiserSizes* returnSizes ) +{ + return g_optixFunctionTable.optixDenoiserComputeMemoryResources( handle, maximumInputWidth, maximumInputHeight, returnSizes ); +} + +inline OptixResult optixDenoiserSetup( OptixDenoiser denoiser, + CUstream stream, + unsigned int inputWidth, + unsigned int inputHeight, + CUdeviceptr denoiserState, + size_t denoiserStateSizeInBytes, + CUdeviceptr scratch, + size_t scratchSizeInBytes ) +{ + return g_optixFunctionTable.optixDenoiserSetup( denoiser, stream, inputWidth, inputHeight, denoiserState, + denoiserStateSizeInBytes, scratch, scratchSizeInBytes ); +} + +inline OptixResult optixDenoiserInvoke( OptixDenoiser handle, + CUstream stream, + const OptixDenoiserParams* params, + CUdeviceptr denoiserData, + size_t denoiserDataSize, + const OptixDenoiserGuideLayer* guideLayer, + const OptixDenoiserLayer* layers, + unsigned int numLayers, + unsigned int inputOffsetX, + unsigned int inputOffsetY, + CUdeviceptr scratch, + size_t scratchSizeInBytes ) +{ + return g_optixFunctionTable.optixDenoiserInvoke( handle, stream, params, denoiserData, denoiserDataSize, + guideLayer, layers, numLayers, + inputOffsetX, inputOffsetY, scratch, scratchSizeInBytes ); +} + +inline OptixResult optixDenoiserComputeIntensity( OptixDenoiser handle, + CUstream stream, + const OptixImage2D* inputImage, + CUdeviceptr outputIntensity, + CUdeviceptr scratch, + size_t scratchSizeInBytes ) +{ + return g_optixFunctionTable.optixDenoiserComputeIntensity( handle, stream, inputImage, outputIntensity, scratch, scratchSizeInBytes ); +} + +inline OptixResult optixDenoiserComputeAverageColor( OptixDenoiser handle, + CUstream stream, + const OptixImage2D* inputImage, + CUdeviceptr outputAverageColor, + CUdeviceptr scratch, + size_t scratchSizeInBytes ) +{ + return g_optixFunctionTable.optixDenoiserComputeAverageColor( handle, stream, inputImage, outputAverageColor, scratch, scratchSizeInBytes ); +} + +#endif // OPTIX_DOXYGEN_SHOULD_SKIP_THIS + +#ifdef __cplusplus +} +#endif + +#endif // __optix_optix_stubs_h__ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_types.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_types.h new file mode 100644 index 00000000..35c450fc --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/OptiX SDK 7.5.0/include/optix_types.h @@ -0,0 +1,34 @@ +/* +* SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* SPDX-License-Identifier: LicenseRef-NvidiaProprietary +* +* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +* property and proprietary rights in and to this material, related +* documentation and any modifications thereto. Any use, reproduction, +* disclosure or distribution of this material and related documentation +* without an express license agreement from NVIDIA CORPORATION or +* its affiliates is strictly prohibited. +*/ +/** + * @file optix_types.h + * @author NVIDIA Corporation + * @brief OptiX public API header + * + */ + +#ifndef __optix_optix_types_h__ +#define __optix_optix_types_h__ + +// clang-format off +#if !defined(__OPTIX_INCLUDE_INTERNAL_HEADERS__) +# define __OPTIX_INCLUDE_INTERNAL_HEADERS__ +# define __UNDEF_OPTIX_INCLUDE_INTERNAL_HEADERS_OPTIX_TYPES_H__ +#endif +#include "optix_7_types.h" +#if defined( __UNDEF_OPTIX_INCLUDE_INTERNAL_HEADERS_OPTIX_TYPES_H__ ) +# undef __OPTIX_INCLUDE_INTERNAL_HEADERS__ +# undef __UNDEF_OPTIX_INCLUDE_INTERNAL_HEADERS_OPTIX_TYPES_H__ +#endif +// clang-format on + +#endif // #ifndef __optix_optix_types_h__ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/optixMixSDKs.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/optixMixSDKs.cpp new file mode 100644 index 00000000..6a34875b --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/optixMixSDKs.cpp @@ -0,0 +1,55 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// Calls an optix API function using the current optix SDK +void runSDKCurrent(); + +// Calls an optix API function using the optix SDK 7.5.0 +void runSDK750(); + +int main( int argc, char* argv[] ) +{ + // Multiple distinct SDKs can be mixed within a single application + // as long as each translation unit use only a single SDK. + // Multiple translation units may use the same SDK version. + // Each used SDK must be initialized exactly once across all + // translation units using the SDK. + // Note, mixing multiple SDKs is only supported since SDK 8.1.0 + // Mixing multiple 8.0.0 or older SDKs is not supported. + + // Run some code using the current optix SDK + runSDKCurrent(); + + // Run some code using the optix SDK 7.5.0 + runSDK750(); + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/optixSDK750.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/optixSDK750.cpp new file mode 100644 index 00000000..e33af811 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/optixSDK750.cpp @@ -0,0 +1,234 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +// The OPTIX_ENABLE_SDK_MIXING macro was introduced with optix SDK 8.1.0 +// Therefore, mixing multiple 8.0.0 or older SDKs is not supported. +// However, a single 8.0.0 or older SDK may be mixed with SDK 8.1.0 or newer. +#include "OptiX SDK 7.5.0/include/optix.h" +#include "OptiX SDK 7.5.0/include/optix_function_table_definition.h" +#include "OptiX SDK 7.5.0/include/optix_stubs.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define OPTIX_CHECK( call ) \ + { \ + OptixResult res = call; \ + if( res != OPTIX_SUCCESS ) \ + { \ + fprintf( stderr, "Optix call (%s) failed with code %d\n", #call, res ); \ + exit( 2 ); \ + } \ + } + +#define CUDA_CHECK( call ) \ + { \ + cudaError_t error = call; \ + if( error != cudaSuccess ) \ + { \ + fprintf( stderr, "CUDA call (%s) failed with code %d: %s\n", #call, error, cudaGetErrorString( error ) ); \ + exit( 2 ); \ + } \ + } + +#define CUDA_SYNC_CHECK() \ + { \ + cudaDeviceSynchronize(); \ + cudaError_t error = cudaGetLastError(); \ + if( error != cudaSuccess ) \ + { \ + fprintf( stderr, "error (%s: line %d): %s\n", __FILE__, __LINE__, cudaGetErrorString( error ) ); \ + exit( 2 ); \ + } \ + } + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + +struct Vertex +{ + float x, y, z, pad; +}; +struct IndexedTriangle +{ + unsigned int v1, v2, v3, pad; +}; +struct Instance +{ + float transform[12]; +}; + +// We specifically made one triangle back face and one front faced (back is the left triangle) +static std::vector g_triangleSoup = { + {-0.5f, 1.0f, 0.0f, 999.9f}, {0.0f, -1.0f, 0.f, 999.9f}, {-1.0f, -1.0f, 0.f, 999.9f}, {0.5f, 1.0f, 0.0f, 999.9f}, + {0.0f, -1.0f, 0.f, 999.9f}, {1.0f, -1.0f, 0.f, 999.9f}, {0.1f, 0.0f, 0.0f, 999.9f}, {0.0f, 1.0f, 0.f, 999.9f}, + {0.5f, 1.0f, 0.f, 999.9f}, {-0.1f, 0.0f, 0.0f, 999.9f}, {0.0f, 1.0f, 0.f, 999.9f}, {-0.5f, 1.0f, 0.f, 999.9f}, + +}; + +static std::vector g_indexedTriangleMesh = { + // Note the last value isn't used, so put a big value there + {0, 1, 2, 999}, + {3, 1, 5, 999}, // 4 is the same as 1, so reuse it to test + {6, 7, 3, 999}, // 8 -> 3 + {9, 7, 0, 999} // 10 -> 7, 11 -> 0 +}; + +static std::vector g_instances = { + {{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0}}, + {{1, 0, 0, 2, 0, 1, 0, 0, 0, 0, 1, 0}}, +}; + +void runSDK750() +{ + OPTIX_CHECK( optixInit() ); + + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cuCtx = 0; // zero means take the current context + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + + // upload geometry + + CUdeviceptr d_vertices, d_indices; + size_t verticesSizeInBytes = g_triangleSoup.size() * sizeof( Vertex ); + size_t indicesSizeInBytes = g_indexedTriangleMesh.size() * sizeof( IndexedTriangle ); + CUDA_CHECK( cudaMalloc( ( void** )&d_vertices, verticesSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( ( void** )&d_indices, indicesSizeInBytes ) ); + CUDA_CHECK( cudaMemcpy( ( void* )d_vertices, g_triangleSoup.data(), verticesSizeInBytes, cudaMemcpyHostToDevice ) ); + CUDA_CHECK( cudaMemcpy( ( void* )d_indices, g_indexedTriangleMesh.data(), indicesSizeInBytes, cudaMemcpyHostToDevice ) ); + + // build ias and gas + + OptixBuildInput triangleInput = {}; + + triangleInput.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangleInput.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangleInput.triangleArray.vertexStrideInBytes = sizeof( Vertex ); + triangleInput.triangleArray.numVertices = ( unsigned int )g_triangleSoup.size(); + triangleInput.triangleArray.vertexBuffers = &d_vertices; + + triangleInput.triangleArray.indexFormat = OPTIX_INDICES_FORMAT_UNSIGNED_INT3; + triangleInput.triangleArray.indexStrideInBytes = sizeof( IndexedTriangle ); + ; + triangleInput.triangleArray.numIndexTriplets = ( unsigned int )g_indexedTriangleMesh.size(); + triangleInput.triangleArray.indexBuffer = d_indices; + + unsigned int triangleInputFlags[1] = { OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT }; + triangleInput.triangleArray.flags = triangleInputFlags; + triangleInput.triangleArray.numSbtRecords = 1; + + CUdeviceptr d_instances; + size_t instancesSizeInBytes = g_instances.size() * sizeof( OptixInstance ); + CUDA_CHECK( cudaMalloc( ( void** )&d_instances, instancesSizeInBytes ) ); + + OptixBuildInput instanceInput = {}; + + instanceInput.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; + instanceInput.instanceArray.instances = d_instances; + instanceInput.instanceArray.numInstances = ( unsigned int )g_instances.size(); + + OptixAccelBuildOptions accelOptions = {}; + + accelOptions.buildFlags = OPTIX_BUILD_FLAG_NONE; + accelOptions.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes gasBufferSizes, iasBufferSizes; + + OPTIX_CHECK( optixAccelComputeMemoryUsage( context, &accelOptions, &triangleInput, 1, &gasBufferSizes ) ); + OPTIX_CHECK( optixAccelComputeMemoryUsage( context, &accelOptions, &instanceInput, 1, &iasBufferSizes ) ); + + CUdeviceptr d_tempBuffer, d_gasOutputBuffer, d_iasOutputBuffer; + OptixTraversableHandle gasHandle, iasHandle; + + CUDA_CHECK( cudaMalloc( ( void** )&d_tempBuffer, std::max( gasBufferSizes.tempSizeInBytes, iasBufferSizes.tempSizeInBytes ) ) ); + CUDA_CHECK( cudaMalloc( ( void** )&d_gasOutputBuffer, gasBufferSizes.outputSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( ( void** )&d_iasOutputBuffer, iasBufferSizes.outputSizeInBytes ) ); + + OPTIX_CHECK( optixAccelBuild( context, 0, &accelOptions, &triangleInput, 1, d_tempBuffer, gasBufferSizes.tempSizeInBytes, + d_gasOutputBuffer, gasBufferSizes.outputSizeInBytes, &gasHandle, nullptr, 0 ) ); + + std::vector instances( g_instances.size() ); + + for( unsigned int i = 0; i < g_instances.size(); ++i ) + { + instances[i].flags = OPTIX_INSTANCE_FLAG_NONE; + instances[i].instanceId = 42 + i; + instances[i].sbtOffset = i; + instances[i].visibilityMask = 1; + memcpy( instances[i].transform, g_instances[i].transform, sizeof( float ) * 12 ); + instances[i].traversableHandle = gasHandle; + } + + CUDA_CHECK( cudaMemcpy( ( void* )d_instances, instances.data(), instancesSizeInBytes, cudaMemcpyHostToDevice ) ); + + OPTIX_CHECK( optixAccelBuild( context, 0, &accelOptions, &instanceInput, 1, d_tempBuffer, iasBufferSizes.tempSizeInBytes, + d_iasOutputBuffer, iasBufferSizes.outputSizeInBytes, &iasHandle, nullptr, 0 ) ); + + // relocate gas and ias + + OptixAccelRelocationInfo gasRelocationInfo, iasRelocationInfo; + OPTIX_CHECK( optixAccelGetRelocationInfo( context, gasHandle, &gasRelocationInfo ) ); + OPTIX_CHECK( optixAccelGetRelocationInfo( context, iasHandle, &iasRelocationInfo ) ); + + CUdeviceptr d_gasRelocateBuffer, d_iasRelocateBuffer; + CUDA_CHECK( cudaMalloc( ( void** )&d_gasRelocateBuffer, gasBufferSizes.outputSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( ( void** )&d_iasRelocateBuffer, iasBufferSizes.outputSizeInBytes ) ); + + CUDA_CHECK( cudaMemcpy( ( void* )d_gasRelocateBuffer, ( const void* )d_gasOutputBuffer, gasBufferSizes.outputSizeInBytes, cudaMemcpyDeviceToDevice ) ); + CUDA_CHECK( cudaMemcpy( ( void* )d_iasRelocateBuffer, ( const void* )d_iasOutputBuffer, iasBufferSizes.outputSizeInBytes, cudaMemcpyDeviceToDevice ) ); + + OPTIX_CHECK( optixAccelRelocate( context, 0, &gasRelocationInfo, 0, 0, d_gasRelocateBuffer, gasBufferSizes.outputSizeInBytes, &gasHandle ) ); + + // SDK 7.5.0 Relocation API + + CUdeviceptr d_instanceTraversableHandles; + CUDA_CHECK( cudaMalloc( ( void** )&d_instanceTraversableHandles, sizeof( OptixTraversableHandle ) ) ); + CUDA_CHECK( cudaMemcpy( ( void* )d_instanceTraversableHandles, &gasHandle, sizeof( OptixTraversableHandle ), cudaMemcpyHostToDevice ) ); + OPTIX_CHECK( optixAccelRelocate( context, 0, &iasRelocationInfo, d_instanceTraversableHandles, 1, d_iasRelocateBuffer, iasBufferSizes.outputSizeInBytes, &iasHandle ) ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/optixSDKCurrent.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/optixSDKCurrent.cpp new file mode 100644 index 00000000..ab267c97 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMixSDKs/optixSDKCurrent.cpp @@ -0,0 +1,243 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + + /// Mixing multiple SDKs in a single application by default results in symbol collisions. + /// To enable different compilation units to use different SDKs, define OPTIX_ENABLE_SDK_MIXING before including the optix headers. +#define OPTIX_ENABLE_SDK_MIXING +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define OPTIX_CHECK( call ) \ + { \ + OptixResult res = call; \ + if( res != OPTIX_SUCCESS ) \ + { \ + fprintf( stderr, "Optix call (%s) failed with code %d\n", #call, res ); \ + exit( 2 ); \ + } \ + } + +#define CUDA_CHECK( call ) \ + { \ + cudaError_t error = call; \ + if( error != cudaSuccess ) \ + { \ + fprintf( stderr, "CUDA call (%s) failed with code %d: %s\n", #call, error, cudaGetErrorString( error ) ); \ + exit( 2 ); \ + } \ + } + +#define CUDA_SYNC_CHECK() \ + { \ + cudaDeviceSynchronize(); \ + cudaError_t error = cudaGetLastError(); \ + if( error != cudaSuccess ) \ + { \ + fprintf( stderr, "error (%s: line %d): %s\n", __FILE__, __LINE__, cudaGetErrorString( error ) ); \ + exit( 2 ); \ + } \ + } + +struct Vertex +{ + float x, y, z, pad; +}; +struct IndexedTriangle +{ + unsigned int v1, v2, v3, pad; +}; +struct Instance +{ + float transform[12]; +}; + +// We specifically made one triangle back face and one front faced (back is the left triangle) +static std::vector g_triangleSoup = { + {-0.5f, 1.0f, 0.0f, 999.9f}, {0.0f, -1.0f, 0.f, 999.9f}, {-1.0f, -1.0f, 0.f, 999.9f}, {0.5f, 1.0f, 0.0f, 999.9f}, + {0.0f, -1.0f, 0.f, 999.9f}, {1.0f, -1.0f, 0.f, 999.9f}, {0.1f, 0.0f, 0.0f, 999.9f}, {0.0f, 1.0f, 0.f, 999.9f}, + {0.5f, 1.0f, 0.f, 999.9f}, {-0.1f, 0.0f, 0.0f, 999.9f}, {0.0f, 1.0f, 0.f, 999.9f}, {-0.5f, 1.0f, 0.f, 999.9f}, + +}; + +static std::vector g_indexedTriangleMesh = { + // Note the last value isn't used, so put a big value there + {0, 1, 2, 999}, + {3, 1, 5, 999}, // 4 is the same as 1, so reuse it to test + {6, 7, 3, 999}, // 8 -> 3 + {9, 7, 0, 999} // 10 -> 7, 11 -> 0 +}; + +static std::vector g_instances = { + {{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0}}, + {{1, 0, 0, 2, 0, 1, 0, 0, 0, 0, 1, 0}}, +}; + +static std::vector g_instancesTop = { + {{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0}}, + {{1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0}}, +}; + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + +void runSDKCurrent() +{ + OPTIX_CHECK( optixInit() ); + + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cuCtx = 0; // zero means take the current context + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + + // upload geometry + + CUdeviceptr d_vertices, d_indices; + size_t verticesSizeInBytes = g_triangleSoup.size() * sizeof( Vertex ); + size_t indicesSizeInBytes = g_indexedTriangleMesh.size() * sizeof( IndexedTriangle ); + CUDA_CHECK( cudaMalloc( ( void** )&d_vertices, verticesSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( ( void** )&d_indices, indicesSizeInBytes ) ); + CUDA_CHECK( cudaMemcpy( ( void* )d_vertices, g_triangleSoup.data(), verticesSizeInBytes, cudaMemcpyHostToDevice ) ); + CUDA_CHECK( cudaMemcpy( ( void* )d_indices, g_indexedTriangleMesh.data(), indicesSizeInBytes, cudaMemcpyHostToDevice ) ); + + // build ias and gas + + OptixBuildInput triangleInput = {}; + + triangleInput.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangleInput.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangleInput.triangleArray.vertexStrideInBytes = sizeof( Vertex ); + triangleInput.triangleArray.numVertices = ( unsigned int )g_triangleSoup.size(); + triangleInput.triangleArray.vertexBuffers = &d_vertices; + + triangleInput.triangleArray.indexFormat = OPTIX_INDICES_FORMAT_UNSIGNED_INT3; + triangleInput.triangleArray.indexStrideInBytes = sizeof( IndexedTriangle ); + ; + triangleInput.triangleArray.numIndexTriplets = ( unsigned int )g_indexedTriangleMesh.size(); + triangleInput.triangleArray.indexBuffer = d_indices; + + unsigned int triangleInputFlags[1] = { OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT }; + triangleInput.triangleArray.flags = triangleInputFlags; + triangleInput.triangleArray.numSbtRecords = 1; + + CUdeviceptr d_instances; + size_t instancesSizeInBytes = g_instances.size() * sizeof( OptixInstance ); + CUDA_CHECK( cudaMalloc( ( void** )&d_instances, instancesSizeInBytes ) ); + + OptixBuildInput instanceInput = {}; + + instanceInput.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; + instanceInput.instanceArray.instances = d_instances; + instanceInput.instanceArray.numInstances = ( unsigned int )g_instances.size(); + + OptixAccelBuildOptions accelOptions = {}; + + accelOptions.buildFlags = OPTIX_BUILD_FLAG_NONE; + accelOptions.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes gasBufferSizes, iasBufferSizes; + + OPTIX_CHECK( optixAccelComputeMemoryUsage( context, &accelOptions, &triangleInput, 1, &gasBufferSizes ) ); + OPTIX_CHECK( optixAccelComputeMemoryUsage( context, &accelOptions, &instanceInput, 1, &iasBufferSizes ) ); + + CUdeviceptr d_tempBuffer, d_gasOutputBuffer, d_iasOutputBuffer; + OptixTraversableHandle gasHandle, iasHandle; + + CUDA_CHECK( cudaMalloc( ( void** )&d_tempBuffer, std::max( gasBufferSizes.tempSizeInBytes, iasBufferSizes.tempSizeInBytes ) ) ); + CUDA_CHECK( cudaMalloc( ( void** )&d_gasOutputBuffer, gasBufferSizes.outputSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( ( void** )&d_iasOutputBuffer, iasBufferSizes.outputSizeInBytes ) ); + + OPTIX_CHECK( optixAccelBuild( context, 0, &accelOptions, &triangleInput, 1, d_tempBuffer, gasBufferSizes.tempSizeInBytes, + d_gasOutputBuffer, gasBufferSizes.outputSizeInBytes, &gasHandle, nullptr, 0 ) ); + + std::vector instances( g_instances.size() ); + + for( unsigned int i = 0; i < g_instances.size(); ++i ) + { + instances[i].flags = OPTIX_INSTANCE_FLAG_NONE; + instances[i].instanceId = 42 + i; + instances[i].sbtOffset = i; + instances[i].visibilityMask = 1; + memcpy( instances[i].transform, g_instances[i].transform, sizeof( float ) * 12 ); + instances[i].traversableHandle = gasHandle; + } + + CUDA_CHECK( cudaMemcpy( ( void* )d_instances, instances.data(), instancesSizeInBytes, cudaMemcpyHostToDevice ) ); + + OPTIX_CHECK( optixAccelBuild( context, 0, &accelOptions, &instanceInput, 1, d_tempBuffer, iasBufferSizes.tempSizeInBytes, + d_iasOutputBuffer, iasBufferSizes.outputSizeInBytes, &iasHandle, nullptr, 0 ) ); + + // relocate gas and ias + + OptixRelocationInfo gasRelocationInfo, iasRelocationInfo; + OPTIX_CHECK( optixAccelGetRelocationInfo( context, gasHandle, &gasRelocationInfo ) ); + OPTIX_CHECK( optixAccelGetRelocationInfo( context, iasHandle, &iasRelocationInfo ) ); + + CUdeviceptr d_gasRelocateBuffer, d_iasRelocateBuffer; + CUDA_CHECK( cudaMalloc( ( void** )&d_gasRelocateBuffer, gasBufferSizes.outputSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( ( void** )&d_iasRelocateBuffer, iasBufferSizes.outputSizeInBytes ) ); + + CUDA_CHECK( cudaMemcpy( ( void* )d_gasRelocateBuffer, ( const void* )d_gasOutputBuffer, gasBufferSizes.outputSizeInBytes, cudaMemcpyDeviceToDevice ) ); + CUDA_CHECK( cudaMemcpy( ( void* )d_iasRelocateBuffer, ( const void* )d_iasOutputBuffer, iasBufferSizes.outputSizeInBytes, cudaMemcpyDeviceToDevice ) ); + + OPTIX_CHECK( optixAccelRelocate( context, 0, &gasRelocationInfo, 0, 0, d_gasRelocateBuffer, gasBufferSizes.outputSizeInBytes, &gasHandle ) ); + + CUdeviceptr d_instanceTraversableHandles; + CUDA_CHECK( cudaMalloc( ( void** )&d_instanceTraversableHandles, sizeof( OptixTraversableHandle ) ) ); + CUDA_CHECK( cudaMemcpy( ( void* )d_instanceTraversableHandles, &gasHandle, sizeof( OptixTraversableHandle ), cudaMemcpyHostToDevice ) ); + + // Current SDK Relocation API + + OptixRelocateInput relocateInput = {}; + relocateInput.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; + relocateInput.instanceArray.numInstances = 1; + relocateInput.instanceArray.traversableHandles = d_instanceTraversableHandles; + OPTIX_CHECK( optixAccelRelocate( context, 0, &iasRelocationInfo, &relocateInput, 1, d_iasRelocateBuffer, iasBufferSizes.outputSizeInBytes, &iasHandle ) ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/CMakeLists.txt new file mode 100644 index 00000000..7f1346a6 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/CMakeLists.txt @@ -0,0 +1,54 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixModuleCreateAbort target_name + optixModuleCreateAbort.cu + optixModuleCreateAbort_ch.cu + optixModuleCreateAbort.cpp + optixModuleCreateAbort.h + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) + +add_executable( optixModuleCreateProcess + optixModuleCreateProcess.cpp + ) + +target_link_libraries( optixModuleCreateProcess + glad + sutil_7_sdk + ${CUDA_LIBRARIES} + ) + +set_property( TARGET optixModuleCreateProcess PROPERTY FOLDER "${OPTIX_IDE_FOLDER}" ) + +add_dependencies( ${target_name} optixModuleCreateProcess ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateAbort.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateAbort.cpp new file mode 100644 index 00000000..4dd16fbf --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateAbort.cpp @@ -0,0 +1,1490 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This sample shows how to run module creation in a separate process +// so that it can be aborted at any time by killing that process +// (by pressing the 'A' key). The compiled result is stored in the OptiX +// disk cache, so that when the main application creates the module again, +// there is no compile time. +// +// This sample is a modified version of the optixBoundValues sample. + +#include // Needs to be included before gl_interop + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "optixModuleCreateAbort.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include +#else +#include +#include +#include +#include +#include +#include +#endif + + + +bool resize_dirty = false; +bool minimized = false; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Mouse state +int32_t mouse_button = -1; + +int32_t samples_per_launch = 16; + +// The number of samples to calculate the light are specified in the launch parameters. +// That value can be specialized to a fixed value at compile time. +// Note than when changing the number of light samples at runtime by pressing the PLUS +// or MINUS keys with specialization enabled recompilation of the closest hit module +// is necessary or it needs to be loaded from the cache. +unsigned int light_samples = 1; +bool specialize = true; + +// Keep a list of all compile operations in flight to be able to check their state each frame until completed +struct CompileOperation +{ + std::string ptx; + std::string temp_file; + OptixModuleCompileOptions module_compile_options; + OptixPipelineCompileOptions pipeline_compile_options; + std::vector bound_values; + OptixModule* target_module; +#ifdef WIN32 + HANDLE process_handle; +#else + pid_t process_id; +#endif +}; +std::vector compile_operations_in_flight; + +//------------------------------------------------------------------------------ +// +// Local types +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +template +struct Record +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef Record RayGenRecord; +typedef Record MissRecord; +typedef Record HitGroupRecord; + + +struct Vertex +{ + float x, y, z, pad; +}; + + +struct IndexedTriangle +{ + uint32_t v1, v2, v3, pad; +}; + + +struct Instance +{ + float transform[12]; +}; + + +struct PathTracerState +{ + OptixDeviceContext context = 0; + + OptixTraversableHandle gas_handle = 0; // Traversable handle for triangle AS + CUdeviceptr d_gas_output_buffer = 0; // Triangle AS memory + CUdeviceptr d_vertices = 0; + + OptixModule ptx_module = 0; + OptixModule ptx_module_radiance = 0; + OptixPipelineCompileOptions pipeline_compile_options = {}; + OptixPipeline pipeline = 0; + + OptixProgramGroup raygen_prog_group = 0; + OptixProgramGroup radiance_miss_group = 0; + OptixProgramGroup occlusion_miss_group = 0; + OptixProgramGroup radiance_hit_group = 0; + OptixProgramGroup occlusion_hit_group = 0; + + CUstream stream = 0; + Params params; + Params* d_params; + + OptixShaderBindingTable sbt = {}; +}; + + +//------------------------------------------------------------------------------ +// +// Scene data +// +//------------------------------------------------------------------------------ + +const int32_t TRIANGLE_COUNT = 32; +const int32_t MAT_COUNT = 4; + +const static std::array g_vertices = +{ { + // Floor -- white lambert + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 0.0f, 0.0f }, + + // Ceiling -- white lambert + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + + // Back wall -- white lambert + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + + // Right wall -- green lambert + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + { 0.0f, 0.0f, 559.2f, 0.0f }, + + // Left wall -- red lambert + { 556.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 556.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 0.0f, 0.0f }, + + // Short block -- white lambert + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 242.0f, 165.0f, 274.0f, 0.0f }, + + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 242.0f, 165.0f, 274.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + + { 290.0f, 0.0f, 114.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + + { 290.0f, 0.0f, 114.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + { 240.0f, 0.0f, 272.0f, 0.0f }, + + { 130.0f, 0.0f, 65.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + + { 130.0f, 0.0f, 65.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + { 290.0f, 0.0f, 114.0f, 0.0f }, + + { 82.0f, 0.0f, 225.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + + { 82.0f, 0.0f, 225.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 130.0f, 0.0f, 65.0f, 0.0f }, + + { 240.0f, 0.0f, 272.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + + { 240.0f, 0.0f, 272.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 82.0f, 0.0f, 225.0f, 0.0f }, + + // Tall block -- white lambert + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 314.0f, 330.0f, 455.0f, 0.0f }, + + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 314.0f, 330.0f, 455.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + + { 423.0f, 0.0f, 247.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + + { 423.0f, 0.0f, 247.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + { 472.0f, 0.0f, 406.0f, 0.0f }, + + { 472.0f, 0.0f, 406.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + + { 472.0f, 0.0f, 406.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + { 314.0f, 0.0f, 456.0f, 0.0f }, + + { 314.0f, 0.0f, 456.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + + { 314.0f, 0.0f, 456.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 265.0f, 0.0f, 296.0f, 0.0f }, + + { 265.0f, 0.0f, 296.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + + { 265.0f, 0.0f, 296.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 423.0f, 0.0f, 247.0f, 0.0f }, + + // Ceiling light -- emmissive + { 343.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 332.0f, 0.0f }, + + { 343.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 332.0f, 0.0f }, + { 343.0f, 548.6f, 332.0f, 0.0f } +} }; + +static std::array g_mat_indices = {{ + 0, 0, // Floor -- white lambert + 0, 0, // Ceiling -- white lambert + 0, 0, // Back wall -- white lambert + 1, 1, // Right wall -- green lambert + 2, 2, // Left wall -- red lambert + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Short block -- white lambert + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Tall block -- white lambert + 3, 3 // Ceiling light -- emmissive +}}; + + + +const std::array g_emission_colors = +{ { + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 15.0f, 15.0f, 5.0f } + +} }; + + +const std::array g_diffuse_colors = +{ { + { 0.80f, 0.80f, 0.80f }, + { 0.05f, 0.80f, 0.05f }, + { 0.80f, 0.05f, 0.05f }, + { 0.50f, 0.00f, 0.00f } +} }; + + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking( static_cast( xpos ), static_cast( ypos ) ); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + Params& params = static_cast(glfwGetWindowUserPointer( window ))->params; + + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params.width, params.height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params.width, params.height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + Params& params = static_cast(glfwGetWindowUserPointer( window ))->params; + params.width = res_x; + params.height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + +void createRadianceModule( PathTracerState& state ); + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + } + else if( key == GLFW_KEY_G ) + { + // toggle UI draw + } + else if( key == GLFW_KEY_S ) + { + specialize = !specialize; + // Invoke compile process for new module, pipeline is then later updated in the render loop + createRadianceModule( *static_cast(glfwGetWindowUserPointer( window )) ); + } + else if( key == GLFW_KEY_A ) + { + // Terminate all compile processes in flight + for( const CompileOperation& operation : compile_operations_in_flight ) + { +#ifdef WIN32 + // Ignore failure in case process has already exited + TerminateProcess( operation.process_handle, 1 ); + // Wait for process to actually exit before deleting temporary file, since TerminateProcess is asynchronous and it may still have a handle to it open + WaitForSingleObject( operation.process_handle, 1000 ); + SUTIL_ASSERT( DeleteFileA( operation.temp_file.c_str() ) ); + SUTIL_ASSERT( CloseHandle( operation.process_handle ) ); +#else + SUTIL_ASSERT( kill( operation.process_id, SIGTERM ) == 0 ); + SUTIL_ASSERT( remove( operation.temp_file.c_str() ) == 0 ); +#endif + } + compile_operations_in_flight.clear(); + } +} + + +static void charCallback( GLFWwindow* window, unsigned int codepoint ) +{ + if( codepoint == '+' ) + { + ++light_samples; + if( specialize ) + createRadianceModule( *static_cast(glfwGetWindowUserPointer( window )) ); + } + else if( codepoint == '-' ) + { + if( light_samples > 1 ) + { + --light_samples; + if( specialize ) + createRadianceModule( *static_cast(glfwGetWindowUserPointer( window )) ); + } + } +} + +static void scrollCallback( GLFWwindow* window, double xscroll, double yscroll ) +{ + if( trackball.wheelEvent( (int)yscroll ) ) + camera_changed = true; +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --launch-samples | -s Number of samples per pixel per launch (default 16)\n"; + std::cerr << " --light-samples | -l Number of radiance samples (default 1)\n"; + std::cerr << " --no-specialize ...\n"; + std::cerr << " --no-gl-interop Disable GL interop for display\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 768x768\n"; + std::cerr << " --help | -h Print this usage message\n"; + exit( 0 ); +} + + +void initLaunchParams( PathTracerState& state ) +{ + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &state.params.accum_buffer ), + state.params.width * state.params.height * sizeof( float4 ) + ) ); + state.params.frame_buffer = nullptr; // Will be set when output buffer is mapped + + state.params.samples_per_launch = samples_per_launch; + state.params.light_samples = light_samples; + state.params.subframe_index = 0u; + + state.params.light.emission = make_float3( 15.0f, 15.0f, 5.0f ); + state.params.light.corner = make_float3( 343.0f, 548.5f, 227.0f ); + state.params.light.v1 = make_float3( 0.0f, 0.0f, 105.0f ); + state.params.light.v2 = make_float3( -130.0f, 0.0f, 0.0f ); + state.params.light.normal = normalize( cross( state.params.light.v1, state.params.light.v2 ) ); + state.params.handle = state.gas_handle; + + CUDA_CHECK( cudaStreamCreate( &state.stream ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_params ), sizeof( Params ) ) ); + +} + + +void handleCameraUpdate( Params& params ) +{ + if( !camera_changed ) + return; + camera_changed = false; + + camera.setAspectRatio( static_cast( params.width ) / static_cast( params.height ) ); + params.eye = camera.eye(); + camera.UVWFrame( params.U, params.V, params.W ); +} + + +void handleResize( sutil::CUDAOutputBuffer& output_buffer, Params& params ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + output_buffer.resize( params.width, params.height ); + + // Realloc accumulation buffer + CUDA_CHECK( cudaFree( reinterpret_cast( params.accum_buffer ) ) ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( ¶ms.accum_buffer ), + params.width * params.height * sizeof( float4 ) + ) ); +} + +void updateState( sutil::CUDAOutputBuffer& output_buffer, Params& params ) +{ + // Update params on device + if( camera_changed || resize_dirty ) + params.subframe_index = 0; + + params.light_samples = light_samples; + + handleCameraUpdate( params ); + handleResize( output_buffer, params ); +} + + +void launchSubframe( sutil::CUDAOutputBuffer& output_buffer, PathTracerState& state ) +{ + // Cannot launch while modules are still compiling (on startup) + if( state.pipeline == nullptr ) + return; + + // Launch + uchar4* result_buffer_data = output_buffer.map(); + state.params.frame_buffer = result_buffer_data; + CUDA_CHECK( cudaMemcpyAsync( + reinterpret_cast( state.d_params ), + &state.params, sizeof( Params ), + cudaMemcpyHostToDevice, state.stream + ) ); + + OPTIX_CHECK( optixLaunch( + state.pipeline, + state.stream, + reinterpret_cast( state.d_params ), + sizeof( Params ), + &state.sbt, + state.params.width, // launch width + state.params.height, // launch height + 1 // launch depth + ) ); + output_buffer.unmap(); + CUDA_SYNC_CHECK(); +} + + +void displaySubframe( sutil::CUDAOutputBuffer& output_buffer, sutil::GLDisplay& gl_display, GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( + output_buffer.width(), + output_buffer.height(), + framebuf_res_x, + framebuf_res_y, + output_buffer.getPBO() + ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n"; +} + + +void initCameraState() +{ + camera.setEye( make_float3( 278.0f, 273.0f, -900.0f ) ); + camera.setLookat( make_float3( 278.0f, 273.0f, 330.0f ) ); + camera.setUp( make_float3( 0.0f, 1.0f, 0.0f ) ); + camera.setFovY( 35.0f ); + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( + make_float3( 1.0f, 0.0f, 0.0f ), + make_float3( 0.0f, 0.0f, 1.0f ), + make_float3( 0.0f, 1.0f, 0.0f ) + ); + trackball.setGimbalLock( true ); +} + + +void createContext( PathTracerState& state ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cu_ctx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; +#ifdef DEBUG + // This may incur significant performance cost and should only be done during development. + options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; +#endif + OPTIX_CHECK( optixDeviceContextCreate( cu_ctx, &options, &context ) ); + + state.context = context; +} + + +void buildMeshAccel( PathTracerState& state ) +{ + // + // copy mesh data to device + // + const size_t vertices_size_in_bytes = g_vertices.size() * sizeof( Vertex ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_vertices ), vertices_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( state.d_vertices ), + g_vertices.data(), vertices_size_in_bytes, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr d_mat_indices = 0; + const size_t mat_indices_size_in_bytes = g_mat_indices.size() * sizeof( uint32_t ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_mat_indices ), mat_indices_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_mat_indices ), + g_mat_indices.data(), + mat_indices_size_in_bytes, + cudaMemcpyHostToDevice + ) ); + + // + // Build triangle GAS + // + uint32_t triangle_input_flags[MAT_COUNT] = // One per SBT record for this build input + { + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT + }; + + OptixBuildInput triangle_input = {}; + triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangle_input.triangleArray.vertexStrideInBytes = sizeof( Vertex ); + triangle_input.triangleArray.numVertices = static_cast( g_vertices.size() ); + triangle_input.triangleArray.vertexBuffers = &state.d_vertices; + triangle_input.triangleArray.flags = triangle_input_flags; + triangle_input.triangleArray.numSbtRecords = MAT_COUNT; + triangle_input.triangleArray.sbtIndexOffsetBuffer = d_mat_indices; + triangle_input.triangleArray.sbtIndexOffsetSizeInBytes = sizeof( uint32_t ); + triangle_input.triangleArray.sbtIndexOffsetStrideInBytes = sizeof( uint32_t ); + + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( + state.context, + &accel_options, + &triangle_input, + 1, // num_build_inputs + &gas_buffer_sizes + ) ); + + CUdeviceptr d_temp_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 + ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( (char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( + state.context, + 0, // CUDA stream + &accel_options, + &triangle_input, + 1, // num build inputs + d_temp_buffer, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &state.gas_handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_mat_indices ) ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, (void*)emitProperty.result, sizeof(size_t), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, 0, state.gas_handle, state.d_gas_output_buffer, compacted_gas_size, &state.gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + state.d_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } +} + + +void createModule( OptixDeviceContext context, const std::string& ptx, const OptixModuleCompileOptions& module_compile_options, const OptixPipelineCompileOptions& pipeline_compile_options, OptixModule& module ) +{ + // Get current CUDA device and pass that info to the compile process + int device = 0; + CUDA_CHECK(cudaGetDevice( &device )); + + // Write PTX to a temporary file that can be passed on to the compile process + static int invocation = 0; + const std::string filename = "temp_" + std::to_string( reinterpret_cast(&module) ) + "_" + std::to_string(invocation++) + ".ptx"; + std::ofstream temp_file( filename, std::ios::binary ); + SUTIL_ASSERT( temp_file.is_open() ); + temp_file.write( ptx.data(), ptx.size() ); + temp_file.close(); + + // Build command-line for the compile process + std::string cmd; + cmd += " --file " + filename; + cmd += " --device " + std::to_string( device ); + + cmd += " --maxRegisterCount "; + cmd += std::to_string( module_compile_options.maxRegisterCount ); + cmd += " --optLevel "; + cmd += std::to_string( static_cast(module_compile_options.optLevel) ); + cmd += " --debugLevel "; + cmd += std::to_string( static_cast(module_compile_options.debugLevel) ); + for( unsigned int i = 0; i < module_compile_options.numBoundValues; ++i ) + { + const OptixModuleCompileBoundValueEntry& bound_value = module_compile_options.boundValues[i]; + + cmd += " --boundValue "; + cmd += std::to_string( bound_value.pipelineParamOffsetInBytes ); + cmd += " "; + cmd += std::to_string( bound_value.sizeInBytes ); + cmd += " \""; + cmd += bound_value.annotation; + cmd += "\" \""; + // Encode bound value data as a string + for( size_t byte = 0; byte < bound_value.sizeInBytes; ++byte ) + { + const char byte_value = static_cast(bound_value.boundValuePtr)[byte]; + cmd += '0' + ( byte_value & 0xF); // byte_low + cmd += '0' + ((byte_value >> 4) & 0xF); // byte_high + } + cmd += "\""; + } + + cmd += " --usesMotionBlur "; + cmd += pipeline_compile_options.usesMotionBlur ? "1" : "0"; + cmd += " --traversableGraphFlags "; + cmd += std::to_string( pipeline_compile_options.traversableGraphFlags ); + cmd += " --numPayloadValues "; + cmd += std::to_string( pipeline_compile_options.numPayloadValues ); + cmd += " --numAttributeValues "; + cmd += std::to_string( pipeline_compile_options.numAttributeValues ); + cmd += " --exceptionFlags "; + cmd += std::to_string( pipeline_compile_options.exceptionFlags ); + cmd += " --pipelineLaunchParamsVariableName "; + cmd += pipeline_compile_options.pipelineLaunchParamsVariableName; + cmd += " --usesPrimitiveTypeFlags "; + cmd += std::to_string( pipeline_compile_options.usesPrimitiveTypeFlags ); + + CompileOperation operation; + operation.ptx = ptx; + operation.temp_file = filename; + operation.module_compile_options = module_compile_options; + operation.pipeline_compile_options = pipeline_compile_options; + operation.bound_values.assign( module_compile_options.boundValues, module_compile_options.boundValues + module_compile_options.numBoundValues ); + operation.target_module = &module; + +#ifdef WIN32 + // Get path to the module creation executable (optixModuleCreateProcess.exe), which should be right next to the sample executable + char executablePath[MAX_PATH] = ""; + SUTIL_ASSERT( GetModuleFileNameA( nullptr, executablePath, sizeof( executablePath ) ) ); + std::string createProcessPath = executablePath; + createProcessPath.erase( createProcessPath.rfind( '\\' ) + 1 ); + createProcessPath += "optixModuleCreateProcess.exe"; + + STARTUPINFO si = { sizeof( si ) }; + PROCESS_INFORMATION pi = {}; + SUTIL_ASSERT( CreateProcessA( createProcessPath.c_str(), const_cast(cmd.c_str()), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi ) ); + + operation.process_handle = pi.hProcess; +#else + std::vector argv; + // Split combined argument string into separate arguments + cmd += ' '; + for( size_t offset = 0, next; (next = cmd.find( ' ', offset )) != std::string::npos; offset = next + 1 ) + { + // Remove quotes around argument + if( cmd[offset] == '\"' ) + { + offset++; + cmd[next - 1] = '\0'; + } + + cmd[next] = '\0'; + argv.push_back( const_cast(cmd.c_str()) + offset ); + } + + char executablePath[PATH_MAX] = ""; + std::string createProcessPath; + SUTIL_ASSERT( readlink( "/proc/self/exe", executablePath, sizeof( executablePath ) ) != -1 ); + createProcessPath = executablePath; + createProcessPath.erase( createProcessPath.rfind( '/' ) + 1 ); + createProcessPath += "optixModuleCreateProcess"; + + argv[0] = (char*)createProcessPath.c_str(); + argv.push_back( nullptr ); // Terminate argument list + + extern char **environ; + SUTIL_ASSERT( posix_spawn( &operation.process_id, createProcessPath.c_str(), nullptr, nullptr, argv.data(), environ ) == 0 ); +#endif + + compile_operations_in_flight.push_back( operation ); +} + + +void createRadianceModule( PathTracerState& state ) +{ + OptixModuleCompileOptions module_compile_options ={}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + OptixModuleCompileBoundValueEntry boundValue = {}; + if( specialize ) + { + boundValue.pipelineParamOffsetInBytes = offsetof( Params, light_samples ); + boundValue.sizeInBytes = sizeof( Params::light_samples ); + boundValue.boundValuePtr = &light_samples; + boundValue.annotation = "light_samples"; + module_compile_options.numBoundValues = 1; + module_compile_options.boundValues = &boundValue; + } + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixModuleCreateAbort_ch.cu", inputSize ); + std::string ptx( input, inputSize ); + createModule( state.context, ptx, module_compile_options, state.pipeline_compile_options, state.ptx_module_radiance ); +} + +void createModule( PathTracerState& state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + state.pipeline_compile_options.usesMotionBlur = false; + state.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + state.pipeline_compile_options.numPayloadValues = 2; + state.pipeline_compile_options.numAttributeValues = 2; + state.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + state.pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixModuleCreateAbort.cu", inputSize ); + std::string ptx( input, inputSize ); + + createModule( state.context, ptx, module_compile_options, state.pipeline_compile_options, state.ptx_module ); + + createRadianceModule( state ); +} + +void createRadianceProgramGroup( PathTracerState& state ) +{ + OptixProgramGroupOptions program_group_options ={}; + OptixProgramGroupDesc hit_prog_group_desc ={}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = state.ptx_module_radiance; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__radiance"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.radiance_hit_group + ) ); +} + +void createProgramGroups( PathTracerState& state ) +{ + OptixProgramGroupOptions program_group_options = {}; + + { + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = state.ptx_module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.raygen_prog_group + ) ); + } + + { + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.ptx_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__radiance"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.radiance_miss_group + ) ); + + memset( &miss_prog_group_desc, 0, sizeof( OptixProgramGroupDesc ) ); + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = nullptr; // NULL miss program for occlusion rays + miss_prog_group_desc.miss.entryFunctionName = nullptr; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.occlusion_miss_group + ) ); + } + + { + OptixProgramGroupDesc hit_prog_group_desc = {}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = state.ptx_module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__occlusion"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.occlusion_hit_group + ) ); + } + createRadianceProgramGroup( state ); +} + +void createPipeline( PathTracerState& state ) +{ + OptixProgramGroup program_groups[] = + { + state.raygen_prog_group, + state.radiance_miss_group, + state.occlusion_miss_group, + state.radiance_hit_group, + state.occlusion_hit_group + }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = 2; + + OPTIX_CHECK_LOG( optixPipelineCreate( + state.context, + &state.pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &state.pipeline + ) ); + + // We need to specify the max traversal depth. Calculate the stack sizes, so we can specify all + // parameters to optixPipelineSetStackSize. + OptixStackSizes stack_sizes = {}; + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.raygen_prog_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.radiance_miss_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.occlusion_miss_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.radiance_hit_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.occlusion_hit_group, &stack_sizes, state.pipeline ) ); + + uint32_t max_trace_depth = 2; + uint32_t max_cc_depth = 0; + uint32_t max_dc_depth = 0; + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( + &stack_sizes, + max_trace_depth, + max_cc_depth, + max_dc_depth, + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, + &continuation_stack_size + ) ); + + const uint32_t max_traversal_depth = 1; + OPTIX_CHECK( optixPipelineSetStackSize( + state.pipeline, + direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, + continuation_stack_size, + max_traversal_depth + ) ); +} + +void allocateSBT( PathTracerState& state ) +{ + const size_t raygen_record_size = sizeof( RayGenRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast(&state.sbt.raygenRecord), raygen_record_size ) ); + + const size_t miss_record_size = sizeof( MissRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast(&state.sbt.missRecordBase), miss_record_size * RAY_TYPE_COUNT ) ); + state.sbt.missRecordStrideInBytes = static_cast(miss_record_size); + state.sbt.missRecordCount = RAY_TYPE_COUNT; + + const size_t hitgroup_record_size = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast(&state.sbt.hitgroupRecordBase), + hitgroup_record_size * RAY_TYPE_COUNT * MAT_COUNT + ) ); + state.sbt.hitgroupRecordStrideInBytes = static_cast(hitgroup_record_size); + state.sbt.hitgroupRecordCount = RAY_TYPE_COUNT * MAT_COUNT; +} + +void fillSBT( PathTracerState& state ) +{ + const size_t raygen_record_size = sizeof( RayGenRecord ); + RayGenRecord rg_sbt ={}; + OPTIX_CHECK( optixSbtRecordPackHeader( state.raygen_prog_group, &rg_sbt ) ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast(state.sbt.raygenRecord), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + + + const size_t miss_record_size = sizeof( MissRecord ); + MissRecord ms_sbt[2]; + OPTIX_CHECK( optixSbtRecordPackHeader( state.radiance_miss_group, &ms_sbt[0] ) ); + ms_sbt[0].data.bg_color = make_float4( 0.0f ); + OPTIX_CHECK( optixSbtRecordPackHeader( state.occlusion_miss_group, &ms_sbt[1] ) ); + ms_sbt[1].data.bg_color = make_float4( 0.0f ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast(state.sbt.missRecordBase), + ms_sbt, + miss_record_size*RAY_TYPE_COUNT, + cudaMemcpyHostToDevice + ) ); +} + +void fillHitGroupSBT( PathTracerState& state ) +{ + const size_t hitgroup_record_size = sizeof( HitGroupRecord ); + HitGroupRecord hitgroup_records[RAY_TYPE_COUNT * MAT_COUNT]; + for( int i = 0; i < MAT_COUNT; ++i ) + { + { + const int sbt_idx = i * RAY_TYPE_COUNT + 0; // SBT for radiance ray-type for ith material + + OPTIX_CHECK( optixSbtRecordPackHeader( state.radiance_hit_group, &hitgroup_records[sbt_idx] ) ); + hitgroup_records[sbt_idx].data.emission_color = g_emission_colors[i]; + hitgroup_records[sbt_idx].data.diffuse_color = g_diffuse_colors[i]; + hitgroup_records[sbt_idx].data.vertices = reinterpret_cast(state.d_vertices); + } + + { + const int sbt_idx = i * RAY_TYPE_COUNT + 1; // SBT for occlusion ray-type for ith material + memset( &hitgroup_records[sbt_idx], 0, hitgroup_record_size ); + + OPTIX_CHECK( optixSbtRecordPackHeader( state.occlusion_hit_group, &hitgroup_records[sbt_idx] ) ); + } + } + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast(state.sbt.hitgroupRecordBase), + hitgroup_records, + hitgroup_record_size*RAY_TYPE_COUNT*MAT_COUNT, + cudaMemcpyHostToDevice + ) ); +} + +void updatePipeline( PathTracerState& state ) +{ + // Do not update in case one of the modules was not created yet + if( state.ptx_module == nullptr || state.ptx_module_radiance == nullptr ) + { + return; + } + + // destroy old stuff + if( state.pipeline != nullptr ) + { + OPTIX_CHECK( optixPipelineDestroy( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.occlusion_hit_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.occlusion_miss_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_hit_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_miss_group ) ); + } + + createProgramGroups( state ); + createRadianceProgramGroup( state ); + createPipeline( state ); + fillSBT(state); + fillHitGroupSBT( state ); + + // Force params.subframe_index to zero in updateState (which is called after updatePipeline in the render loop). + // This is done to ensure the frame buffer is reset when rendering with the new pipeline begins. + camera_changed = true; +} + +void updatePipelineWhenChanged( PathTracerState& state ) +{ + if( compile_operations_in_flight.empty() ) + return; + + bool need_pipeline_update = false; + for( auto it = compile_operations_in_flight.begin(); it != compile_operations_in_flight.end(); ) + { +#ifdef WIN32 + // Check if the compile process has already exited + if( WaitForSingleObject( it->process_handle, 0 ) != WAIT_OBJECT_0 ) + { + ++it; + continue; + } + + CompileOperation operation = *it; + // This compile operation is finished, so remove it from the list + it = compile_operations_in_flight.erase( it ); + + // Process has exited, so check the exit code to ensure module compilation was successfull + DWORD exit_code = EXIT_FAILURE; + GetExitCodeProcess( operation.process_handle, &exit_code ); + CloseHandle( operation.process_handle ); + + // Delete temporary file + SUTIL_ASSERT( DeleteFileA( operation.temp_file.c_str() ) ); + SUTIL_ASSERT_MSG( exit_code == 0, "Compile process was not successfull" ); +#else + int status = -1; + if( waitpid( it->process_id, &status, WNOHANG ) == 0 ) + { + ++it; + continue; + } + + CompileOperation operation = *it; + // This compile operation is finished, so remove it from the list + it = compile_operations_in_flight.erase( it ); + + // Delete temporary file + SUTIL_ASSERT( remove( operation.temp_file.c_str() ) == 0 ); + SUTIL_ASSERT_MSG( WEXITSTATUS( status ) == 0, "Compile process was not successfull" ); +#endif + + operation.module_compile_options.boundValues = operation.bound_values.data(); + + // The module should be in cache, so simply create it again in this context + // This API call should now return instantenously (unless caching failed, in which case this would recompile the module again) + OPTIX_CHECK( optixModuleCreate( + state.context, + &operation.module_compile_options, + &operation.pipeline_compile_options, + operation.ptx.c_str(), + operation.ptx.size(), + nullptr, 0, + operation.target_module + ) ); + + need_pipeline_update = true; + } + + if( need_pipeline_update ) + { + updatePipeline( state ); + } +} + +void cleanupState( PathTracerState& state ) +{ + OPTIX_CHECK( optixPipelineDestroy( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_miss_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_hit_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.occlusion_hit_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.occlusion_miss_group ) ); + OPTIX_CHECK( optixModuleDestroy( state.ptx_module ) ); + OPTIX_CHECK( optixModuleDestroy( state.ptx_module_radiance ) ); + OPTIX_CHECK( optixDeviceContextDestroy( state.context ) ); + + + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_vertices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.accum_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_params ) ) ); +} + + +//------------------------------------------------------------------------------ +// +// Main +// +//------------------------------------------------------------------------------ + +void displaySpecializationInfo( GLFWwindow* window ) +{ + static char display_text[256]; + + sutil::beginFrameImGui(); + sprintf( display_text, + "light samples [+/-]: %d\n" + "specialization [S] : %s\n%s", + light_samples, + specialize ? "on" : "off", + !compile_operations_in_flight.empty() ? "[A] to abort compiling ...\n" : ""); + Params& params = static_cast(glfwGetWindowUserPointer( window ))->params; + sutil::displayText( display_text, 10.0f, (float)params.height - 70.f ); + sutil::endFrameImGui(); +} + +int main( int argc, char* argv[] ) +{ + PathTracerState state; + state.params.width = 768; + state.params.height = 768; + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::GL_INTEROP; + + // + // Parse command line options + // + std::string outfile; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--no-gl-interop" ) + { + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + } + else if( arg == "--no-specialize" ) + { + specialize = false; + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + int w, h; + sutil::parseDimensions( dims_arg.c_str(), w, h ); + state.params.width = w; + state.params.height = h; + } + else if( arg == "--launch-samples" || arg == "-s" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + samples_per_launch = atoi( argv[++i] ); + } + else if( arg == "--light-samples" || arg == "-l" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + light_samples = atoi( argv[++i] ); + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outfile = argv[++i]; + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + initCameraState(); + + // + // Set up OptiX state + // + createContext( state ); + buildMeshAccel( state ); + createModule( state ); + allocateSBT( state ); + initLaunchParams( state ); + + if( outfile.empty() ) + { + GLFWwindow* window = sutil::initUI( "optixModuleCreateAbort", state.params.width, state.params.height ); + glfwSetMouseButtonCallback( window, mouseButtonCallback ); + glfwSetCursorPosCallback( window, cursorPosCallback ); + glfwSetWindowSizeCallback( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback( window, keyCallback ); + glfwSetCharCallback( window, charCallback ); + glfwSetScrollCallback( window, scrollCallback ); + glfwSetWindowUserPointer( window, &state ); + + // + // Render loop + // + { + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, state.params.width, state.params.height ); + output_buffer.setStream( state.stream ); + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + updatePipelineWhenChanged( state ); + + updateState( output_buffer, state.params ); + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + launchSubframe( output_buffer, state ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1 - t0; + + sutil::displayStats( state_update_time, render_time, display_time ); + + displaySpecializationInfo( window ); + + glfwSwapBuffers( window ); + + ++state.params.subframe_index; + } while( !glfwWindowShouldClose( window ) ); + CUDA_SYNC_CHECK(); + } + + sutil::cleanupUI( window ); + } + else + { + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + sutil::initGLFW(); // For GL context + sutil::initGL(); + } + + { + // this scope is for output_buffer, to ensure the destructor is called bfore glfwTerminate() + + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, state.params.width, state.params.height ); + output_buffer.setStream( state.stream ); + handleCameraUpdate( state.params ); + handleResize( output_buffer, state.params ); + + // Need to potentially wait on modules to compile since we are not in a render loop. + while( state.ptx_module_radiance == nullptr || state.ptx_module == nullptr ) + updatePipelineWhenChanged( state ); + + launchSubframe( output_buffer, state ); + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + glfwTerminate(); + } + } + + cleanupState( state ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateAbort.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateAbort.cu new file mode 100644 index 00000000..d860e741 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateAbort.cu @@ -0,0 +1,175 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include "optixModuleCreateAbort.h" +#include "random.h" + +extern "C" { +__constant__ Params params; +} + + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + + + +static __forceinline__ __device__ void setPayloadOcclusion( bool occluded ) +{ + optixSetPayload_0( static_cast( occluded ) ); +} + +static __forceinline__ __device__ void traceRadiance( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax, + RadiancePRD* prd + ) +{ + // TODO: deduce stride from num ray-types passed in params + + unsigned int u0, u1; + packPointer( prd, u0, u1 ); + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_NONE, + RAY_TYPE_RADIANCE, // SBT offset + RAY_TYPE_COUNT, // SBT stride + RAY_TYPE_RADIANCE, // missSBTIndex + u0, u1 ); +} + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +extern "C" __global__ void __raygen__rg() +{ + const int w = params.width; + const int h = params.height; + const float3 eye = params.eye; + const float3 U = params.U; + const float3 V = params.V; + const float3 W = params.W; + const uint3 idx = optixGetLaunchIndex(); + const int subframe_index = params.subframe_index; + + unsigned int seed = tea<4>( idx.y*w + idx.x, subframe_index ); + + float3 result = make_float3( 0.0f ); + int i = params.samples_per_launch; + do + { + const float2 subpixel_jitter = make_float2( rnd( seed )-0.5f, rnd( seed )-0.5f ); + + const float2 d = 2.0f * make_float2( + ( static_cast( idx.x ) + subpixel_jitter.x ) / static_cast( w ), + ( static_cast( idx.y ) + subpixel_jitter.y ) / static_cast( h ) + ) - 1.0f; + float3 ray_direction = normalize(d.x*U + d.y*V + W); + float3 ray_origin = eye; + + RadiancePRD prd; + prd.emitted = make_float3(0.f); + prd.radiance = make_float3(0.f); + prd.attenuation = make_float3(1.f); + prd.countEmitted = true; + prd.done = false; + prd.seed = seed; + + int depth = 0; + for( ;; ) + { + traceRadiance( + params.handle, + ray_origin, + ray_direction, + 0.01f, // tmin // TODO: smarter offset + 1e16f, // tmax + &prd ); + + result += prd.emitted; + result += prd.radiance * prd.attenuation; + + if( prd.done || depth >= 3 ) // TODO RR, variable for depth + break; + + ray_origin = prd.origin; + ray_direction = prd.direction; + + ++depth; + } + } + while( --i ); + + const uint3 launch_index = optixGetLaunchIndex(); + const unsigned int image_index = launch_index.y * params.width + launch_index.x; + float3 accum_color = result / static_cast( params.samples_per_launch ); + + if( subframe_index > 0 ) + { + const float a = 1.0f / static_cast( subframe_index+1 ); + const float3 accum_color_prev = make_float3( params.accum_buffer[ image_index ]); + accum_color = lerp( accum_color_prev, accum_color, a ); + } + params.accum_buffer[ image_index ] = make_float4( accum_color, 1.0f); + params.frame_buffer[ image_index ] = make_color ( accum_color ); +} + + +extern "C" __global__ void __miss__radiance() +{ + MissData* rt_data = reinterpret_cast( optixGetSbtDataPointer() ); + RadiancePRD* prd = getPRD(); + + prd->radiance = make_float3( rt_data->bg_color ); + prd->done = true; +} + + +extern "C" __global__ void __closesthit__occlusion() +{ + setPayloadOcclusion( true ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateAbort.h b/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateAbort.h new file mode 100644 index 00000000..89788e16 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateAbort.h @@ -0,0 +1,163 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +enum RayType +{ + RAY_TYPE_RADIANCE = 0, + RAY_TYPE_OCCLUSION = 1, + RAY_TYPE_COUNT +}; + + +struct ParallelogramLight +{ + float3 corner; + float3 v1, v2; + float3 normal; + float3 emission; +}; + + +struct Params +{ + unsigned int subframe_index; + float4* accum_buffer; + uchar4* frame_buffer; + unsigned int width; + unsigned int height; + unsigned int samples_per_launch; + unsigned int light_samples; + + float3 eye; + float3 U; + float3 V; + float3 W; + + ParallelogramLight light; // TODO: make light list + OptixTraversableHandle handle; +}; + + +struct RayGenData +{ +}; + + +struct MissData +{ + float4 bg_color; +}; + + +struct HitGroupData +{ + float3 emission_color; + float3 diffuse_color; + float4* vertices; +}; + +#if defined( __CUDACC__ ) + +#include +#include + +struct RadiancePRD +{ + // TODO: move some state directly into payload registers? + float3 emitted; + float3 radiance; + float3 attenuation; + float3 origin; + float3 direction; + unsigned int seed; + int countEmitted; + int done; + int pad; +}; + + +struct Onb +{ + __forceinline__ __device__ Onb( const float3& normal ) + { + m_normal = normal; + + if( fabs( m_normal.x ) > fabs( m_normal.z ) ) + { + m_binormal.x = -m_normal.y; + m_binormal.y = m_normal.x; + m_binormal.z = 0; + } + else + { + m_binormal.x = 0; + m_binormal.y = -m_normal.z; + m_binormal.z = m_normal.y; + } + + m_binormal = normalize( m_binormal ); + m_tangent = cross( m_binormal, m_normal ); + } + + __forceinline__ __device__ void inverse_transform( float3& p ) const + { + p = p.x*m_tangent + p.y*m_binormal + p.z*m_normal; + } + + float3 m_tangent; + float3 m_binormal; + float3 m_normal; +}; + + +static __forceinline__ __device__ void* unpackPointer( unsigned int i0, unsigned int i1 ) +{ + const unsigned long long uptr = static_cast(i0) << 32 | i1; + void* ptr = reinterpret_cast(uptr); + return ptr; +} + + +static __forceinline__ __device__ void packPointer( void* ptr, unsigned int& i0, unsigned int& i1 ) +{ + const unsigned long long uptr = reinterpret_cast(ptr); + i0 = uptr >> 32; + i1 = uptr & 0x00000000ffffffff; +} + +static __forceinline__ __device__ RadiancePRD* getPRD() +{ + const unsigned int u0 = optixGetPayload_0(); + const unsigned int u1 = optixGetPayload_1(); + return reinterpret_cast(unpackPointer( u0, u1 )); +} + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateAbort_ch.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateAbort_ch.cu new file mode 100644 index 00000000..fb56ca16 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateAbort_ch.cu @@ -0,0 +1,164 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include "optixModuleCreateAbort.h" +#include "random.h" + +extern "C" { +__constant__ Params params; +} + + + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +static __forceinline__ __device__ void cosine_sample_hemisphere(const float u1, const float u2, float3& p) +{ + // Uniformly sample disk. + const float r = sqrtf( u1 ); + const float phi = 2.0f*M_PIf * u2; + p.x = r * cosf( phi ); + p.y = r * sinf( phi ); + + // Project up to hemisphere. + p.z = sqrtf( fmaxf( 0.0f, 1.0f - p.x*p.x - p.y*p.y ) ); +} + +static __forceinline__ __device__ bool traceOcclusion( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax + ) +{ + unsigned int occluded = 0u; + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT, + RAY_TYPE_OCCLUSION, // SBT offset + RAY_TYPE_COUNT, // SBT stride + RAY_TYPE_OCCLUSION, // missSBTIndex + occluded ); + return occluded; +} + +extern "C" __global__ void __closesthit__radiance() +{ + HitGroupData* rt_data = (HitGroupData*)optixGetSbtDataPointer(); + + const int prim_idx = optixGetPrimitiveIndex(); + const float3 ray_dir = optixGetWorldRayDirection(); + const int vert_idx_offset = prim_idx*3; + + const float3 v0 = make_float3( rt_data->vertices[ vert_idx_offset+0 ] ); + const float3 v1 = make_float3( rt_data->vertices[ vert_idx_offset+1 ] ); + const float3 v2 = make_float3( rt_data->vertices[ vert_idx_offset+2 ] ); + const float3 N_0 = normalize( cross( v1-v0, v2-v0 ) ); + + const float3 N = faceforward( N_0, -ray_dir, N_0 ); + const float3 P = optixGetWorldRayOrigin() + optixGetRayTmax()*ray_dir; + + RadiancePRD* prd = getPRD(); + + if( prd->countEmitted ) + prd->emitted = rt_data->emission_color; + else + prd->emitted = make_float3( 0.0f ); + + + unsigned int seed = prd->seed; + + { + const float z1 = rnd(seed); + const float z2 = rnd(seed); + + float3 w_in; + cosine_sample_hemisphere( z1, z2, w_in ); + Onb onb( N ); + onb.inverse_transform( w_in ); + prd->direction = w_in; + prd->origin = P; + + prd->attenuation *= rt_data->diffuse_color; + prd->countEmitted = false; + } + + float3 result = make_float3( 0.0f ); + + for( int i = 0; i < params.light_samples; ++i ) + { + const float z1 = rnd( seed ); + const float z2 = rnd( seed ); + prd->seed = seed; + + ParallelogramLight light = params.light; + const float3 light_pos = light.corner + light.v1 * z1 + light.v2 * z2; + + // Calculate properties of light sample (for area based pdf) + const float Ldist = length( light_pos - P ); + const float3 L = normalize( light_pos - P ); + const float nDl = dot( N, L ); + const float LnDl = -dot( light.normal, L ); + + float weight = 0.0f; + if( nDl > 0.0f && LnDl > 0.0f ) + { + const bool occluded = traceOcclusion( + params.handle, + P, + L, + 0.01f, // tmin + Ldist - 0.01f // tmax + ); + + if( !occluded ) + { + const float A = length( cross( light.v1, light.v2 ) ); + weight = nDl * LnDl * A / (M_PIf * Ldist * Ldist); + result += (light.emission * weight); + } + } + } + + prd->radiance += ( result / params.light_samples ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateProcess.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateProcess.cpp new file mode 100644 index 00000000..badf39e1 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixModuleCreateAbort/optixModuleCreateProcess.cpp @@ -0,0 +1,232 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2020 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +int main( int argc, char* argv[] ) +{ + // Parse command line options + int device = 0; + std::string filename; + OptixModuleCompileOptions module_compile_options = {}; + OptixPipelineCompileOptions pipeline_compile_options = {}; + std::vector bound_values; + std::vector> bound_values_data; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + + if( i + 1 >= argc ) + { + std::cerr << "Incorrect number of arguments to option '" << arg << "'\n"; + return 1; + } + + // Context options + if( arg == "--file" ) + { + filename = argv[++i]; + } + else if( arg == "--device" ) + { + device = atoi( argv[++i] ); + } + + // Module compile options + else if( arg == "--maxRegisterCount" ) + { + module_compile_options.maxRegisterCount = atoi( argv[++i] ); + } + else if( arg == "--optLevel" ) + { + module_compile_options.optLevel = static_cast(atoi( argv[++i] )); + } + else if( arg == "--debugLevel" ) + { + module_compile_options.debugLevel = static_cast(atoi( argv[++i] )); + } + else if( arg == "--boundValue" ) + { + if( i + 4 >= argc ) + { + std::cerr << "Incorrect number of arguments to option '--boundValue'\n"; + return 1; + } + + OptixModuleCompileBoundValueEntry bound_value = {}; + bound_value.pipelineParamOffsetInBytes = atoi( argv[++i] ); + bound_value.sizeInBytes = atoi( argv[++i] ); + bound_value.annotation = argv[++i]; + + const std::string byte_data = argv[++i]; + if( byte_data.size() != bound_value.sizeInBytes * 2 ) + { + std::cerr << "Incorrect size of encoded bound value data (expected " << (bound_value.sizeInBytes * 2) << " characters, but got " << byte_data.size() << ")\n"; + return 1; + } + + // Allocate space for the value data and decode it from the command-line argument + std::vector bound_value_data( bound_value.sizeInBytes ); + for( size_t byte = 0; byte < bound_value.sizeInBytes; ++byte ) + { + const char byte_low = (byte_data[byte * 2] - '0'); + const char byte_high = (byte_data[byte * 2 + 1] - '0') << 4; + bound_value_data[byte] = byte_low | byte_high; + } + bound_value.boundValuePtr = bound_value_data.data(); + + bound_values.push_back( bound_value ); + bound_values_data.push_back( std::move(bound_value_data) ); // Move vector here to data pointer stays valid + continue; + } + + // Pipeline compile options + else if( arg == "--usesMotionBlur" ) + { + pipeline_compile_options.usesMotionBlur = atoi( argv[++i] ) != 0; + } + else if( arg == "--traversableGraphFlags" ) + { + pipeline_compile_options.traversableGraphFlags = atoi( argv[++i] ); + } + else if( arg == "--numPayloadValues" ) + { + pipeline_compile_options.numPayloadValues = atoi( argv[++i] ); + } + else if( arg == "--numAttributeValues" ) + { + pipeline_compile_options.numAttributeValues = atoi( argv[++i] ); + } + else if( arg == "--exceptionFlags" ) + { + pipeline_compile_options.exceptionFlags = atoi( argv[++i] ); + } + else if( arg == "--pipelineLaunchParamsVariableName" ) + { + pipeline_compile_options.pipelineLaunchParamsVariableName = argv[++i]; + } + else if( arg == "--usesPrimitiveTypeFlags" ) + { + pipeline_compile_options.usesPrimitiveTypeFlags = atoi( argv[++i] ); + } + else + { + std::cerr << "Unknown option '" << arg << "'\n"; + return 1; + } + } + + if (argc <= 1 || filename.empty()) + { + std::cerr << "This executable is used by the 'optixModuleCreateAbort' sample to compile OptiX modules.\nIt is not meant to be called directly.\n"; + std::cerr << "Usage : " << argv[0] << " [options]\n"; + std::cerr << "Options: --file PTX file to compile\n"; + std::cerr << " --device CUDA device index of the GPU to target\n"; + std::cerr << " --maxRegisterCount OptixModuleCompileOptions::maxRegisterCount\n"; + std::cerr << " --optLevel OptixModuleCompileOptions::optLevel\n"; + std::cerr << " --debugLevel OptixModuleCompileOptions::debugLevel\n"; + std::cerr << " --usesMotionBlur OptixModuleCompileOptions::usesMotionBlur\n"; + std::cerr << " --traversableGraphFlags OptixModuleCompileOptions::traversableGraphFlags\n"; + std::cerr << " --numPayloadValues OptixModuleCompileOptions::numPayloadValues\n"; + std::cerr << " --numAttributeValues OptixModuleCompileOptions::numAttributeValues\n"; + std::cerr << " --exceptionFlags OptixModuleCompileOptions::exceptionFlags\n"; + std::cerr << " --pipelineLaunchParamsVariableName OptixModuleCompileOptions::pipelineLaunchParamsVariableName\n"; + std::cerr << " --usesPrimitiveTypeFlags OptixModuleCompileOptions::usesPrimitiveTypeFlags\n"; + std::cerr << " --boundValue \n"; + std::cerr << " Add entry to OptixModuleCompileOptions::boundValues\n"; + return 1; + } + + // Now that all bound values where parsed from the command-line, assign them to the compile options + if( !bound_values.empty() ) + { + module_compile_options.boundValues = bound_values.data(); + module_compile_options.numBoundValues = static_cast(bound_values.size()); + } + + try + { + // Initialize CUDA + CUDA_CHECK( cudaSetDevice(device) ); + CUDA_CHECK( cudaFree(0) ); + + // Initialize OptiX (using the CUDA context that was just initialized) + OptixDeviceContext context = nullptr; + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + OPTIX_CHECK( optixDeviceContextCreate( nullptr, &options, &context ) ); + + // Ensure disk cache is enabled, since this relies on the compile result being cached + int cache_enabled = false; + OPTIX_CHECK( optixDeviceContextGetCacheEnabled( context, &cache_enabled ) ); + SUTIL_ASSERT( cache_enabled ); + + // Read the temporary input file + std::ifstream file( filename.c_str(), std::ios::binary ); + SUTIL_ASSERT( file.is_open() ); + std::vector buffer = std::vector( std::istreambuf_iterator( file ), {} ); + const std::string ptx_string( buffer.begin(), buffer.end() ); + + // Actually compile the module and store the result in the OptiX disk cache + OptixModule module = nullptr; + OPTIX_CHECK_LOG( optixModuleCreate( + context, + &module_compile_options, + &pipeline_compile_options, + ptx_string.c_str(), ptx_string.size(), + LOG, &LOG_SIZE, + &module ) ); + + // Clean up + optixModuleDestroy( module ); + optixDeviceContextDestroy( context ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/CMakeLists.txt new file mode 100644 index 00000000..7081ad69 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/CMakeLists.txt @@ -0,0 +1,47 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Tag the following kernel to be compiled to OBJ intead of PTX (which is the default for +# OPTIX_add_sample_executable). Must be called before OPTIX_add_sample_executable. +set_source_files_properties( + ${CMAKE_CURRENT_SOURCE_DIR}/vertices.cu + PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ +) + +OPTIX_add_sample_executable( optixMotionGeometry target_name + optixMotionGeometry.cu + optixMotionGeometry.cpp + optixMotionGeometry.h + motionHelper.hpp + tiny_obj_loader.h + vertices.cu + # OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} ${CUDA_LIBRARIES} ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/motionHelper.hpp b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/motionHelper.hpp new file mode 100644 index 00000000..714df49d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/motionHelper.hpp @@ -0,0 +1,477 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#pragma once + +#include + +namespace { + +struct Matrix3x4 +{ + // row-major matrix with 4 cols, 3 rows + float m[12]; + + inline static const Matrix3x4& Identity() + { + static Matrix3x4 m = { { 1.0, 0.0, 0.0, 0, 0.0, 1.0, 0.0, 0, 0.0, 0.0, 1.0, 0 } }; + return m; + } + inline static Matrix3x4 Scale( const float3& s ) + { + Matrix3x4 m = { { s.x, 0.0, 0.0, 0, 0.0, s.y, 0.0, 0, 0.0, 0.0, s.z, 0 } }; + return m; + } + inline static Matrix3x4 Translation( const float3& t ) + { + Matrix3x4 m = { { 1, 0.0, 0.0, t.x, 0.0, 1, 0.0, t.y, 0.0, 0.0, 1, t.z } }; + return m; + } + + Matrix3x4 operator*( const Matrix3x4& b ) const + { + Matrix3x4 result; + + for( unsigned int r = 0; r < 3; ++r ) + { + for( unsigned int c = 0; c < 4; ++c ) + { + float sum = 0.0f; + for( unsigned int k = 0; k < 3; ++k ) + { + float rk = this->m[r * 4 + k]; + float kc = b.m[k * 4 + c]; + sum += rk * kc; + } + if( c == 3 ) + sum += this->m[r * 4 + c]; + result.m[r * 4 + c] = sum; + } + } + return result; + } + float3 operator*( const float3& v ) const + { + float3 res; + + res.x = v.x * m[0] + v.y * m[1] + v.z * m[2] + m[3]; + res.y = v.x * m[4] + v.y * m[5] + v.z * m[6] + m[7]; + res.z = v.x * m[8] + v.y * m[9] + v.z * m[10] + m[11]; + + return res; + } + + // Returns the determinant of the matrix. + float determinant() const + { + float d = + m[0]*m[5]*m[10]*1- + m[0]*m[5]*m[11]*0+m[0]*m[9]*0*m[7]- + m[0]*m[9]*m[6]*1+m[0]*0*m[6]*m[11]- + m[0]*0*m[10]*m[7]-m[4]*m[1]*m[10]*1+m[4]*m[1]*m[11]*0- + m[4]*m[9]*0*m[3]+m[4]*m[9]*m[2]*1- + m[4]*0*m[2]*m[11]+m[4]*0*m[10]*m[3]+m[8]*m[1]*m[6]*1- + m[8]*m[1]*0*m[7]+m[8]*m[5]*0*m[3]- + m[8]*m[5]*m[2]*1+m[8]*0*m[2]*m[7]- + m[8]*0*m[6]*m[3]- + 0*m[1]*m[6]*m[11]+0*m[1]*m[10]*m[7]- + 0*m[5]*m[10]*m[3]+0*m[5]*m[2]*m[11]- + 0*m[9]*m[2]*m[7]+0*m[9]*m[6]*m[3]; + return d; + } + + // Returns the inverse of the matrix. + Matrix3x4 inverse() const + { + Matrix3x4 result; + + const float d = 1.0f / determinant(); + + result.m[0] = d * (m[5] * (m[10] * 1 - 0 * m[11]) + m[9] * (0 * m[7] - m[6] * 1) + 0 * (m[6] * m[11] - m[10] * m[7])); + result.m[4] = d * (m[6] * (m[8] * 1 - 0 * m[11]) + m[10] * (0 * m[7] - m[4] * 1) + 0 * (m[4] * m[11] - m[8] * m[7])); + result.m[8] = d * (m[7] * (m[8] * 0 - 0 * m[9]) + m[11] * (0 * m[5] - m[4] * 0) + 1 * (m[4] * m[9] - m[8] * m[5])); + result.m[1] = d * (m[9] * (m[2] * 1 - 0 * m[3]) + 0 * (m[10] * m[3] - m[2] * m[11]) + m[1] * (0 * m[11] - m[10] * 1)); + result.m[5] = d * (m[10] * (m[0] * 1 - 0 * m[3]) + 0 * (m[8] * m[3] - m[0] * m[11]) + m[2] * (0 * m[11] - m[8] * 1)); + result.m[9] = d * (m[11] * (m[0] * 0 - 0 * m[1]) + 1 * (m[8] * m[1] - m[0] * m[9]) + m[3] * (0 * m[9] - m[8] * 0)); + result.m[2] = d * (0 * (m[2] * m[7] - m[6] * m[3]) + m[1] * (m[6] * 1 - 0 * m[7]) + m[5] * (0 * m[3] - m[2] * 1)); + result.m[6] = d * (0 * (m[0] * m[7] - m[4] * m[3]) + m[2] * (m[4] * 1 - 0 * m[7]) + m[6] * (0 * m[3] - m[0] * 1)); + result.m[10] = d * (1 * (m[0] * m[5] - m[4] * m[1]) + m[3] * (m[4] * 0 - 0 * m[5]) + m[7] * (0 * m[1] - m[0] * 0)); + result.m[3] = d * (m[1] * (m[10] * m[7] - m[6] * m[11]) + m[5] * (m[2] * m[11] - m[10] * m[3]) + m[9] * (m[6] * m[3] - m[2] * m[7])); + result.m[7] = d * (m[2] * (m[8] * m[7] - m[4] * m[11]) + m[6] * (m[0] * m[11] - m[8] * m[3]) + m[10] * (m[4] * m[3] - m[0] * m[7])); + result.m[11] = d * (m[3] * (m[8] * m[5] - m[4] * m[9]) + m[7] * (m[0] * m[9] - m[8] * m[1]) + m[11] * (m[4] * m[1] - m[0] * m[5])); + + return result; + } +}; + + +class Quaternion +{ +public: + Quaternion(); + Quaternion( float x, float y, float z, float w ); + Quaternion( const float3& axis, double angle ); + + Quaternion& operator*=( const Quaternion& q1 ); + + /** quaternion x, y, z, w */ + float4 m_q; +}; +Quaternion::Quaternion() +{ + m_q = make_float4( 0.0f, 0.0f, 0.0f, 1.0f ); +} +/* +Quaternion::Quaternion( float x, float y, float z, float w ) +{ + m_q = make_float4( x, y, z, w ); +} +*/ +Quaternion::Quaternion( const float3& axis, double angle ) +{ + const float3 naxis = normalize( axis ); + const double radian = angle * ( M_PI / 180 ); + const float s = (float)sin( radian / 2 ); + m_q.x = naxis.x * s; + m_q.y = naxis.y * s; + m_q.z = naxis.z * s; + m_q.w = (float)cos( radian / 2 ); +} +/* +Quaternion& Quaternion::operator*=( const Quaternion& q1 ) +{ + m_q = make_float4( m_q.w * q1.m_q.x + m_q.x * q1.m_q.w + m_q.y * q1.m_q.z - m_q.z * q1.m_q.y, + m_q.w * q1.m_q.y + m_q.y * q1.m_q.w + m_q.z * q1.m_q.x - m_q.x * q1.m_q.z, + m_q.w * q1.m_q.z + m_q.z * q1.m_q.w + m_q.x * q1.m_q.y - m_q.y * q1.m_q.x, + m_q.w * q1.m_q.w - m_q.x * q1.m_q.x - m_q.y * q1.m_q.y - m_q.z * q1.m_q.z ); + + return *this; +} +*/ +static inline Quaternion nlerp( const Quaternion& quat0, const Quaternion& quat1, float t ) +{ + Quaternion q; + q.m_q = lerp( quat0.m_q, quat1.m_q, t ); + q.m_q = normalize( q.m_q ); + return q; +} + + +OptixSRTData lerp( const OptixSRTData& a, const OptixSRTData& b, float t ) +{ + OptixSRTData r; + r.sx = ::lerp( a.sx, b.sx, t ); + r.a = ::lerp( a.a, b.a, t ); + r.b = ::lerp( a.b, b.b, t ); + r.pvx = ::lerp( a.pvx, b.pvx, t ); + r.sy = ::lerp( a.sy, b.sy, t ); + r.c = ::lerp( a.c, b.c, t ); + r.pvy = ::lerp( a.pvy, b.pvy, t ); + r.sz = ::lerp( a.sz, b.sz, t ); + r.pvz = ::lerp( a.pvz, b.pvz, t ); + r.qx = ::lerp( a.qx, b.qx, t ); + r.qy = ::lerp( a.qy, b.qy, t ); + r.qz = ::lerp( a.qz, b.qz, t ); + r.qw = ::lerp( a.qw, b.qw, t ); + r.tx = ::lerp( a.tx, b.tx, t ); + r.ty = ::lerp( a.ty, b.ty, t ); + r.tz = ::lerp( a.tz, b.tz, t ); + + const float inv_qLength = 1.f / sqrtf( r.qx * r.qx + r.qy * r.qy + r.qz * r.qz + r.qw * r.qw ); + r.qx *= inv_qLength; + r.qy *= inv_qLength; + r.qz *= inv_qLength; + r.qw *= inv_qLength; + + return r; +} + +void srtToMatrix( const OptixSRTData& srt, float* m ) +{ + const float4 q = make_float4( srt.qx, srt.qy, srt.qz, srt.qw ); + + // q is assumed to be normalized, but to be sure, normalize again + const float inv_sql = 1.f / ( srt.qx * srt.qx + srt.qy * srt.qy + srt.qz * srt.qz + srt.qw * srt.qw ); + const float4 nq = make_float4( q.x * inv_sql, q.y * inv_sql, q.z * inv_sql, q.w * inv_sql ); + + const float sqw = q.w * nq.w; + const float sqx = q.x * nq.x; + const float sqy = q.y * nq.y; + const float sqz = q.z * nq.z; + + const float xy = q.x * nq.y; + const float zw = q.z * nq.w; + const float xz = q.x * nq.z; + const float yw = q.y * nq.w; + const float yz = q.y * nq.z; + const float xw = q.x * nq.w; + + m[0] = ( sqx - sqy - sqz + sqw ); + m[1] = 2.0f * ( xy - zw ); + m[2] = 2.0f * ( xz + yw ); + + m[4] = 2.0f * ( xy + zw ); + m[5] = ( -sqx + sqy - sqz + sqw ); + m[6] = 2.0f * ( yz - xw ); + + m[8] = 2.0f * ( xz - yw ); + m[9] = 2.0f * ( yz + xw ); + m[10] = ( -sqx - sqy + sqz + sqw ); + + m[3] = m[0] * srt.pvx + m[1] * srt.pvy + m[2] * srt.pvz + srt.tx; + m[7] = m[4] * srt.pvx + m[5] * srt.pvy + m[6] * srt.pvz + srt.ty; + m[11] = m[8] * srt.pvx + m[9] * srt.pvy + m[10] * srt.pvz + srt.tz; + + m[2] = m[0] * srt.b + m[1] * srt.c + m[2] * srt.sz; + m[6] = m[4] * srt.b + m[5] * srt.c + m[6] * srt.sz; + m[10] = m[8] * srt.b + m[9] * srt.c + m[10] * srt.sz; + + m[1] = m[0] * srt.a + m[1] * srt.sy; + m[5] = m[4] * srt.a + m[5] * srt.sy; + m[9] = m[8] * srt.a + m[9] * srt.sy; + + m[0] = m[0] * srt.sx; + m[4] = m[4] * srt.sx; + m[8] = m[8] * srt.sx; +} + +template +struct alignas( 64 ) MatrixMotionTransformFixedSize : OptixMatrixMotionTransform +{ + // must be strictly after OptixMatrixMotionTransform::transform + float additionalTransforms[motionKeys - 2][12]; + + MatrixMotionTransformFixedSize() + { + //static_assert(sizeof(MatrixMotionTransform) == sizeof(OptixMatrixMotionTransform)+(motionKeys-2)*12*sizeof(float), "size/alignment error"); + motionOptions.numKeys = motionKeys; + } + float* motionKey( unsigned int key ) { return transform[key]; } +}; + +template <> +struct alignas( 64 ) MatrixMotionTransformFixedSize<2> : OptixMatrixMotionTransform +{ + MatrixMotionTransformFixedSize() { motionOptions.numKeys = 2; } + float* motionKey( unsigned int key ) { return transform[key]; } +}; + +template +class MotionTransformArrayBase +{ + public: + MotionTransformArrayBase( size_t numTransforms, unsigned int numKeys ) + : m_numTransforms( numTransforms ) + , m_numKeys( numKeys ) + { + if( numKeys < 2 ) + numKeys = 2; + if( numTransforms ) + m_data = std::unique_ptr( new char[numTransforms * Derived::byteSizePerTransform( numKeys )] ); + } + MotionTransformArrayBase( const MotionTransformArrayBase& other ) + : MotionTransformArrayBase( other.m_numTransforms, other.m_numKeys ) + { + memcpy( data(), other.data(), byteSize() ); + } + + MotionTransformArrayBase( MotionTransformArrayBase&& other ) noexcept + : MotionTransformArrayBase( 0, 0 ) + { + swap( *this, other ); + } + + friend void swap( MotionTransformArrayBase& a, MotionTransformArrayBase& b ) + { + using std::swap; + swap( a.m_numTransforms, b.m_numTransforms ); + swap( a.m_numKeys, b.m_numKeys ); + swap( a.m_data, b.m_data ); + } + + MotionTransformArrayBase& operator=( MotionTransformArrayBase other ) + { + swap( *this, other ); + return *this; + } + MotionTransformArrayBase& operator=( MotionTransformArrayBase&& other ) + { + swap( *this, other ); + return *this; + } + + OptixDataType& transform( size_t transformIdx ) + { + return *(OptixDataType*)( (char*)m_data.get() + Derived::byteSizePerTransform( m_numKeys ) * transformIdx ); + } + const OptixDataType& transform( size_t transformIdx ) const + { + return *(OptixDataType*)( (char*)m_data.get() + Derived::byteSizePerTransform( m_numKeys ) * transformIdx ); + } + + void* data() { return m_data.get(); } + const void* data() const { return m_data.get(); } + + unsigned int numKeys() const { return m_numKeys; } + + size_t numTransforms() const { return m_numTransforms; } + + size_t byteSizePerTransform() const { return Derived::byteSizePerTransform( m_numKeys ); } + size_t byteSize() const { return m_numTransforms * Derived::byteSizePerTransform( m_numKeys ); } + + protected: + static size_t roundUp64( size_t i ) { return ( ( i + 64 - 1 ) / 64 ) * 64; } + + private: + size_t m_numTransforms = 0; + unsigned int m_numKeys = 2; + std::unique_ptr m_data; +}; + + +class MatrixMotionTransformArray : public MotionTransformArrayBase +{ + public: + typedef MotionTransformArrayBase Base; + + MatrixMotionTransformArray( size_t numTransforms = 0, unsigned int numKeys = 2 ) + : Base( numTransforms, numKeys ) + { + } + + float* motionData( size_t transformIdx ) { return &transform( transformIdx ).transform[0][0]; } + const float* motionData( size_t transformIdx ) const { return &transform( transformIdx ).transform[0][0]; } + float* motionData( size_t transformIdx, unsigned int key ) { return &transform( transformIdx ).transform[key][0]; } + const float* motionData( size_t transformIdx, unsigned int key ) const + { + return &transform( transformIdx ).transform[key][0]; + } + + using Base::byteSizePerTransform; + static size_t byteSizePerTransform( unsigned int numKeys ) + { + // pad to 64 bytes to ensure 64 byte alignment when using byteSize() to compute size for array of motion transforms with N keys + return roundUp64( sizeof( OptixMatrixMotionTransform ) + sizeof( float ) * 12 * ( numKeys - 2 ) ); + } +}; + +class SRTMotionTransformArray : public MotionTransformArrayBase +{ + public: + typedef MotionTransformArrayBase Base; + + SRTMotionTransformArray( size_t numTransforms = 0, unsigned int numKeys = 2 ) + : Base( numTransforms, numKeys ) + { + } + + OptixSRTData* motionData( size_t transformIdx ) { return transform( transformIdx ).srtData; } + const OptixSRTData* motionData( size_t transformIdx ) const { return transform( transformIdx ).srtData; } + OptixSRTData& motionData( size_t transformIdx, unsigned int key ) { return transform( transformIdx ).srtData[key]; } + const OptixSRTData& motionData( size_t transformIdx, unsigned int key ) const + { + return transform( transformIdx ).srtData[key]; + } + + using Base::byteSizePerTransform; + static size_t byteSizePerTransform( unsigned int numKeys ) + { + // pad to 64 bytes to ensure 64 byte alignment when using byteSize() to compute size for array of motion transforms with N keys + return roundUp64( sizeof( OptixSRTMotionTransform ) + sizeof( OptixSRTData ) * ( numKeys - 2 ) ); + } +}; + +class MatrixMotionTransform : public MatrixMotionTransformArray +{ + public: + typedef MatrixMotionTransformArray Base; + + MatrixMotionTransform( unsigned int numKeys = 2 ) + : MatrixMotionTransformArray( 1, numKeys ) + { + } + float* motionData( unsigned int key ) { return Base::motionData( 0, key ); } + const float* motionData( unsigned int key ) const { return Base::motionData( 0, key ); } + + private: + using Base::numTransforms; +}; + + +OptixSRTData buildSRT( const float3& scale, + const float3& shear, + const float3& scaleShearPivot, + const Quaternion& q, + const float3& rotationPivot, + const float3& translation ) +{ + // Note that a pivot is a point and to do a transformation wrt. a pivot point, we need to apply an inverse translation (hence -pivot) before the transformation + // to go back to 'world' space, the inverse of the pivot translation is applied (+pivot) + + // multiply scale and shear with the scaleShearPivot to bake the pivot into the S transformation, like: S * (p - p') = S*p - S*p' + float3 rotationPivotScalePivot = { + scale.x * -scaleShearPivot.x + shear.x * -scaleShearPivot.y + shear.y * -scaleShearPivot.z, + scale.y * -scaleShearPivot.y + shear.z * -scaleShearPivot.z, scale.z * -scaleShearPivot.z }; + // undo scale pivot after applying scale transformation + rotationPivotScalePivot += scaleShearPivot; + // apply pivot for rotation + // SRT definition actually wants the pivot point, instead of the transformation for the pivot point + // hence, we need to add the pivot point instead of subtracting it + rotationPivotScalePivot -= rotationPivot; + + // apply translation and undo rotation pivot + float3 translationM1RotationPivot = translation + rotationPivot; + + return { scale.x, + shear.x, + shear.y, + rotationPivotScalePivot.x, + scale.y, + shear.z, + rotationPivotScalePivot.y, + scale.z, + rotationPivotScalePivot.z, + q.m_q.x, + q.m_q.y, + q.m_q.z, + q.m_q.w, + translationM1RotationPivot.x, + translationM1RotationPivot.y, + translationM1RotationPivot.z }; +} + +OptixSRTData buildSRT( const float3& scale, const Quaternion& q, const float3& translation ) +{ + return buildSRT( scale, make_float3( 0.0f ), make_float3( 0.0f ), q, make_float3( 0.0f ), translation ); +} + +} // namespace \ No newline at end of file diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/optixMotionGeometry.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/optixMotionGeometry.cpp new file mode 100644 index 00000000..99534a17 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/optixMotionGeometry.cpp @@ -0,0 +1,1817 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include // Needs to be included before gl_interop + +#define TINYOBJLOADER_IMPLEMENTATION +#include "tiny_obj_loader.h" // Needs to be included before gl_interop +#undef TINYOBJLOADER_IMPLEMENTATION + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "optixMotionGeometry.h" +#include "vertices.h" +#include "motionHelper.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +bool resize_dirty = false; +bool minimized = false; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Mouse state +int32_t mouse_button = -1; + + +//------------------------------------------------------------------------------ +// +// Local types +// +//------------------------------------------------------------------------------ + +template +struct Record +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef Record RayGenRecord; +typedef Record MissRecord; +typedef Record HitGroupRecord; + +class ExhaustFume +{ +public: + ExhaustFume() + {} + + ExhaustFume(ExhaustFume&& other) + { + swap( other ); + } + + ExhaustFume& operator=(ExhaustFume&& other) + { + swap( other ); + return *this; + } + + void swap( ExhaustFume& other ) // nothrow + { + // enable ADL (not necessary in our case, but good practice) + using std::swap; + + // by swapping the members of two objects, + // the two objects are effectively swapped + swap(d_exploding_gas_output_buffer, other.d_exploding_gas_output_buffer); + swap(exploding_gas_handle, other.exploding_gas_handle); + swap( srt_animation, other.srt_animation ); + swap( d_srt, other.d_srt ); + swap( timeLastASRebuild, other.timeLastASRebuild ); + swap( localTime, other.localTime ); + swap( rotationSpeed, other.rotationSpeed ); + swap( lastRotationDegree, other.lastRotationDegree ); + swap( relativeEjectionSpeed, other.relativeEjectionSpeed ); + swap( remove, other.remove ); + swap( baseP, other.baseP ); + } + ~ExhaustFume() + { + cudaFree( (void*)d_exploding_gas_output_buffer ); + cudaFree( (void*)d_srt ); + } + + CUdeviceptr d_exploding_gas_output_buffer = 0; + OptixTraversableHandle exploding_gas_handle = 0; + SRTMotionTransformArray srt_animation; + CUdeviceptr d_srt = 0; + float timeLastASRebuild = 0.f; + float localTime = 0.f; + float rotationSpeed = 0.f; // rotation speed of plane at time of ejection + float lastRotationDegree = 0.f; + float relativeEjectionSpeed = 1; // relative ejection speed to give the different fumes some variation + bool remove = false; + float3 baseP; +}; + +struct MotionGeometryState +{ + OptixDeviceContext context = 0; + + size_t temp_buffer_size = 0; + CUdeviceptr d_temp_buffer = 0; + CUdeviceptr d_temp_vertices[2] = {}; + CUdeviceptr d_instances = 0; + size_t d_instances_size = 0; + + unsigned int triangle_flags = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT; + + OptixBuildInput ias_instance_input = {}; + OptixBuildInput triangle_input = {}; + OptixBuildInput triangle_input_fume = {}; + + OptixAccelBuildOptions ias_accel_options ={}; + OptixTraversableHandle ias_handle; + OptixTraversableHandle static_gas_handle; + OptixTraversableHandle deforming_gas_handle; + OptixTraversableHandle exploding_gas_handle; + OptixTraversableHandle plane_gas_handle; + OptixTraversableHandle planePropeller_gas_handle; + + CUdeviceptr d_ias_output_buffer = 0; + CUdeviceptr d_static_gas_output_buffer = 0; + CUdeviceptr d_deforming_gas_output_buffer = 0; + CUdeviceptr d_plane_gas_output_buffer = 0; + CUdeviceptr d_planePropeller_gas_output_buffer = 0; + + sutil::Aabb planeAabb; + + size_t ias_output_buffer_size = 0; + size_t static_gas_output_buffer_size = 0; + size_t deforming_gas_output_buffer_size = 0; + size_t exploding_gas_output_buffer_size = 0; + + OptixModule ptx_module = 0; + OptixPipelineCompileOptions pipeline_compile_options = {}; + OptixPipeline pipeline = 0; + + OptixProgramGroup raygen_prog_group = 0; + OptixProgramGroup miss_group = 0; + OptixProgramGroup miss_group_occlusion = 0; + OptixProgramGroup hit_group = 0; + + CUstream stream = 0; + Params params; + Params* d_params; + + float time = 0.f; + float time_last_frame = 0.f; + float time_last_fume = 0.f; + float targetFrameTime = 0.0333f; + + OptixShaderBindingTable sbt = {}; + + std::vector instances; + std::vector fume; + + bool followPlane = false; + bool renderAO = true; +}; + +//------------------------------------------------------------------------------ +// +// Scene data +// +//------------------------------------------------------------------------------ + +const int32_t g_tessellation_resolution = 128; +const int32_t g_tessellation_resolution_fume = g_tessellation_resolution / 8; + +const float g_exploding_gas_rebuild_frequency = 10.f; + +struct PlaneAnimation { + SRTMotionTransformArray srt_animation; + SRTMotionTransformArray srt_animationPropeller; + CUdeviceptr d_srts; + CUdeviceptr d_srtsPropeller; + float planeSpeed = 0.4f; + float lastRotationDegree = 120; +} plane; + +struct DeformSphereAnimation { + MatrixMotionTransformArray matrix_animation; + CUdeviceptr d_matrices; + float rotationSpeed = 0.1f; + float lastRotationDegree = 0; +} deformSphere; + +void addFume( MotionGeometryState& state ); +void createModule( MotionGeometryState& state ); +void createProgramGroups( MotionGeometryState& state ); +void createPipeline( MotionGeometryState& state ); +void buildMeshAccel( MotionGeometryState& state ); +void createSBT( MotionGeometryState& state ); + + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking( static_cast< int >( xpos ), static_cast< int >( ypos ) ); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + Params& params = static_cast( glfwGetWindowUserPointer( window ) )->params; + + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast< int >( xpos ), static_cast< int >( ypos ), params.width, params.height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast< int >( xpos ), static_cast< int >( ypos ), params.width, params.height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + Params& params = static_cast< MotionGeometryState* >( glfwGetWindowUserPointer( window ) )->params; + params.width = res_x; + params.height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + MotionGeometryState& state = *static_cast( glfwGetWindowUserPointer( window ) ); + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + } + else if( key == GLFW_KEY_G ) + { + // toggle UI draw + } + else if( key == GLFW_KEY_DOWN ) + { + state.targetFrameTime *= 2; + } + else if( key == GLFW_KEY_UP ) + { + state.targetFrameTime /= 2; + } + else if( key == GLFW_KEY_M ) + { + plane.planeSpeed *= 1.5f; + } + else if( key == GLFW_KEY_N ) + { + plane.planeSpeed /= 1.5f; + } + else if( key == GLFW_KEY_J ) + { + deformSphere.rotationSpeed *= 1.5f; + } + else if( key == GLFW_KEY_H ) + { + deformSphere.rotationSpeed /= 1.5f; + } + else if( key == GLFW_KEY_V ) + { + state.followPlane = !state.followPlane; + } + else if( key == GLFW_KEY_B ) + { + addFume( state ); + } + else if( key == GLFW_KEY_A ) + { + state.renderAO = !state.renderAO; + createModule( state ); + createProgramGroups( state ); + createPipeline( state ); + createSBT( state ); + + state.params.ao = state.renderAO; + } +} + + +static void scrollCallback( GLFWwindow* window, double xscroll, double yscroll ) +{ + if( trackball.wheelEvent( ( int )yscroll ) ) + camera_changed = true; +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --time | -t Animation time for image output (default 1)\n"; + std::cerr << " --frames | -n Number of animation frames for image output (default 16)\n"; + std::cerr << " --no-gl-interop Disable GL interop for display\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 1024x768\n"; + std::cerr << " --help | -h Print this usage message\n"; + exit( 0 ); +} + + +void initLaunchParams( MotionGeometryState& state ) +{ + state.params.frame_buffer = nullptr; // Will be set when output buffer is mapped + state.params.subframe_index = 0u; + state.params.spp = 1u; + state.params.ao = true; + + CUDA_CHECK( cudaStreamCreate( &state.stream ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &state.d_params ), sizeof( Params ) ) ); +} + +float3 getPlaneWSPos( const MotionGeometryState& state ) +{ + OptixSRTData lerped = lerp( plane.srt_animation.motionData( 0, 0 ), plane.srt_animation.motionData( 0, 1 ), 0.5f ); + Matrix3x4 m; + srtToMatrix( lerped, m.m ); + return m * state.planeAabb.center(); +} + + +void handleCameraUpdate( MotionGeometryState& state ) +{ + if( state.followPlane ) + { + float3 l = camera.lookat(); + float3 planePos = getPlaneWSPos( state ); + float3 offset = planePos - l; + camera.setLookat( planePos ); + camera.setEye( camera.eye() + offset ); + trackball.reinitOrientationFromCamera(); + camera_changed = true; + } + if( !camera_changed ) + return; + camera_changed = false; + + Params& params = state.params; + camera.setAspectRatio( static_cast< float >( params.width ) / static_cast< float >( params.height ) ); + params.eye = camera.eye(); + camera.UVWFrame( params.U, params.V, params.W ); +} + + +void handleResize( sutil::CUDAOutputBuffer& output_buffer, Params& params ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + output_buffer.resize( params.width, params.height ); +} + + + +void launchSubframe( sutil::CUDAOutputBuffer& output_buffer, MotionGeometryState& state ) +{ + // Launch + uchar4* result_buffer_data = output_buffer.map(); + state.params.frame_buffer = result_buffer_data; + + CUDA_CHECK( cudaMemcpyAsync( + reinterpret_cast< void* >( state.d_params ), + &state.params, sizeof( Params ), + cudaMemcpyHostToDevice, state.stream + ) ); + + OPTIX_CHECK( optixLaunch( + state.pipeline, + state.stream, + reinterpret_cast< CUdeviceptr >( state.d_params ), + sizeof( Params ), + &state.sbt, + state.params.width, // launch width + state.params.height, // launch height + 1 // launch depth + ) ); + output_buffer.unmap(); + CUDA_SYNC_CHECK(); +} + + +void displaySubframe( sutil::CUDAOutputBuffer& output_buffer, sutil::GLDisplay& gl_display, GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( + output_buffer.width(), + output_buffer.height(), + framebuf_res_x, + framebuf_res_y, + output_buffer.getPBO() + ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n"; +} + + +void initCameraState() +{ + camera.setEye( make_float3( -7.f, 3.f, -5.f ) ); + camera.setLookat( make_float3( 0 ) ); + camera.setUp( make_float3( 0.0f, 1.0f, 0.0f ) ); + camera.setFovY( 35.0f ); + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( + make_float3( 1.0f, 0.0f, 0.0f ), + make_float3( 0.0f, 0.0f, 1.0f ), + make_float3( 0.0f, 1.0f, 0.0f ) + ); + trackball.setGimbalLock( true ); +} + + +void createContext( MotionGeometryState& state ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cu_ctx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; +#ifdef DEBUG + // This may incur significant performance cost and should only be done during development. + options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; +#endif + OPTIX_CHECK( optixDeviceContextCreate( cu_ctx, &options, &context ) ); + + state.context = context; +} + +void launchGenerateAnimatedVertices( MotionGeometryState& state, AnimationMode animation_mode, float time_last_frame, float time_now, int tessellation_resolution ) +{ + generateAnimatedVetrices( (float3*)state.d_temp_vertices[0], animation_mode, time_last_frame, tessellation_resolution, tessellation_resolution ); + generateAnimatedVetrices( (float3*)state.d_temp_vertices[1], animation_mode, time_now, tessellation_resolution, tessellation_resolution ); +} + +float randf() +{ + return static_cast( rand() ) / static_cast( RAND_MAX ); +} + +void addFume( MotionGeometryState& state ) +{ + ExhaustFume fume ={}; + + fume.baseP = getPlaneWSPos( state ); + fume.rotationSpeed = plane.planeSpeed * (randf() * 0.1f + 0.8f); + fume.lastRotationDegree = plane.lastRotationDegree; + fume.relativeEjectionSpeed = randf() * 0.4f + 0.6f; + + // using an array is overkill here, but + fume.srt_animation = SRTMotionTransformArray( 1, 2 ); + CUDA_CHECK( cudaMalloc( (void**)&fume.d_srt, fume.srt_animation.byteSize() ) ); + + OptixSRTMotionTransform& t = fume.srt_animation.transform( 0 ); + t.motionOptions.flags = 0; + t.motionOptions.numKeys = fume.srt_animation.numKeys(); + t.motionOptions.timeBegin = 0; + t.motionOptions.timeEnd = 1; + + fume.srt_animation.motionData( 0, 0 ) = plane.srt_animation.motionData( 0, 1 ); + fume.srt_animation.motionData( 0, 1 ) = plane.srt_animation.motionData( 0, 1 ); + + //// Generate exploding sphere vertices + launchGenerateAnimatedVertices( state, AnimationMode_None, 0, 0, g_tessellation_resolution_fume ); + + OptixAccelBuildOptions gas_accel_options = {}; + gas_accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION | OPTIX_BUILD_FLAG_ALLOW_UPDATE + | OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS | OPTIX_BUILD_FLAG_PREFER_FAST_TRACE; + gas_accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + gas_accel_options.motionOptions.numKeys = 2; + gas_accel_options.motionOptions.timeBegin = 0; + gas_accel_options.motionOptions.timeEnd = 1; + + OptixAccelBufferSizes s; + optixAccelComputeMemoryUsage( state.context, &gas_accel_options, &state.triangle_input_fume, 1, &s ); + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &fume.d_exploding_gas_output_buffer ), state.exploding_gas_output_buffer_size ) ); + + OPTIX_CHECK( optixAccelBuild( state.context, + state.stream, // CUDA stream + &gas_accel_options, &state.triangle_input_fume, + 1, // num build inputs + state.d_temp_buffer, state.temp_buffer_size, + fume.d_exploding_gas_output_buffer, state.exploding_gas_output_buffer_size, + &fume.exploding_gas_handle, + nullptr, 0 // emitted property list + ) ); + + state.fume.emplace_back( std::move( fume ) ); +} + +void updateMeshAccel( MotionGeometryState& state ) +{ + // Generate deformed sphere vertices + launchGenerateAnimatedVertices( state, AnimationMode_Deform, state.time_last_frame, state.time, g_tessellation_resolution ); + + // Update deforming GAS + + OptixAccelBuildOptions gas_accel_options = {}; + gas_accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION | OPTIX_BUILD_FLAG_ALLOW_UPDATE | OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS | OPTIX_BUILD_FLAG_PREFER_FAST_TRACE; + gas_accel_options.operation = OPTIX_BUILD_OPERATION_UPDATE; + gas_accel_options.motionOptions.numKeys = 2; + gas_accel_options.motionOptions.timeBegin = 0; + gas_accel_options.motionOptions.timeEnd = 1; + + OPTIX_CHECK( optixAccelBuild( + state.context, + state.stream, // CUDA stream + &gas_accel_options, + &state.triangle_input, + 1, // num build inputs + state.d_temp_buffer, + state.temp_buffer_size, + state.d_deforming_gas_output_buffer, + state.deforming_gas_output_buffer_size, + &state.deforming_gas_handle, + nullptr, // emitted property list + 0 // num emitted properties + ) ); + +#if 1 + { + float timePassed = state.time - state.time_last_frame; + for( size_t i=0; i= maxTime ) + { + launchGenerateAnimatedVertices( state, AnimationMode_Explode, localTime, maxTime, g_tessellation_resolution_fume ); + + fume_gas_accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + fume_gas_accel_options.motionOptions.timeEnd = ( maxTime - localTime ) / timePassed; + fume_gas_accel_options.buildFlags |= OPTIX_MOTION_FLAG_END_VANISH; + + OptixSRTMotionTransform& t = fume.srt_animation.transform( 0 ); + t.motionOptions.timeEnd = ( maxTime - localTime ) / timePassed; + t.motionOptions.flags |= OPTIX_MOTION_FLAG_END_VANISH; + + fume.remove = true; + } + else + { + launchGenerateAnimatedVertices( state, AnimationMode_Explode, localTime, localTime + timePassed, g_tessellation_resolution_fume ); + } + + { + float3 scale = make_float3( 0.05f ); + float3 shear = make_float3( 0 ); + float3 scaleShearPivot = make_float3( 0 ); + float3 rotationPivot = make_float3( 0, -1.2f, 0.0f ); + float3 translation = make_float3( 0, 1.2f, 0.0f ); + float3 ejectTrans = fume.relativeEjectionSpeed * make_float3( 0, 0.2f, 0 ); + + float rotations = fume.rotationSpeed * timePassed * 360; + + float oldRot = fume.lastRotationDegree; + float newRot = oldRot + rotations; + if( newRot >= 360 ) + { + oldRot -= 360; + newRot -= 360; + } + fume.lastRotationDegree = newRot; + + fume.srt_animation.motionData( 0, 0 ) = + buildSRT( scale, shear, scaleShearPivot, Quaternion( make_float3( 1, 0, 0 ), oldRot ), rotationPivot - fume.localTime * ejectTrans, + translation + fume.localTime * ejectTrans ); + fume.srt_animation.motionData( 0, 1 ) = + buildSRT( scale, shear, scaleShearPivot, Quaternion( make_float3( 1, 0, 0 ), newRot ), rotationPivot - ( fume.localTime + timePassed ) * ejectTrans, + translation + ( fume.localTime + timePassed ) * ejectTrans ); + + } + + // Occasionally rebuild to maintain AS quality + if( fume.localTime + timePassed - fume.timeLastASRebuild > 1 / g_exploding_gas_rebuild_frequency ) + { + fume_gas_accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + fume.timeLastASRebuild = fume.localTime + timePassed; + } + fume.localTime += timePassed; + + OptixAccelBufferSizes s; + optixAccelComputeMemoryUsage( state.context, &fume_gas_accel_options, &state.triangle_input_fume, 1, &s ); + + OPTIX_CHECK( optixAccelBuild( state.context, state.stream, + &fume_gas_accel_options, &state.triangle_input_fume, + 1, // num build inputs + state.d_temp_buffer, state.temp_buffer_size, + fume.d_exploding_gas_output_buffer, state.exploding_gas_output_buffer_size, + &fume.exploding_gas_handle, + nullptr, 0 // emitted property list + ) ); + } + } +#endif + + // Update the IAS + // We refit the IAS as the relative positions of the spheres don't change much so AS quality after update is fine. + +#if 1 + { + { + float3 scale = make_float3( 0.2f ); + float3 shear = make_float3( 0 ); + float3 scaleShearPivot = make_float3( 0 ); + float3 rotationPivot = make_float3( 3, 0, 0 ); + float3 translation = -rotationPivot; + + float rotationsPerSecond = deformSphere.rotationSpeed; + float timePassed = state.time - state.time_last_frame; + float rotations = rotationsPerSecond * timePassed * 360; + + float oldRot = deformSphere.lastRotationDegree; + float newRot = oldRot + rotations; + + if( newRot >= 360 ) + { + oldRot -= 360; + newRot -= 360; + } + + deformSphere.lastRotationDegree = fmodf(newRot, 360); + + for(unsigned int i=0; i= 360 ) + { + oldRot -= 360; + newRot -= 360; + } + + plane.lastRotationDegree = fmodf( newRot, 360 ); + + plane.srt_animation.motionData( 0, 0 ) = + buildSRT( scale, shear, scaleShearPivot, Quaternion( make_float3( 1, 0, 0 ), oldRot ), rotationPivot, translation ); + plane.srt_animation.motionData( 0, 1 ) = + buildSRT( scale, shear, scaleShearPivot, Quaternion( make_float3( 1, 0, 0 ), newRot ), rotationPivot, translation ); + + plane.srt_animation.motionData( 1, 0 ) = plane.srt_animation.motionData( 0, 0 ); + plane.srt_animation.motionData( 1, 1 ) = plane.srt_animation.motionData( 0, 1 ); + } + + { + float3 scale = make_float3( 1 ); + float3 shear = make_float3( 0 ); + float3 scaleShearPivot = make_float3( 0 ); + float3 rotationPivot = make_float3( 0.0003f, -0.4179f, 0.0f ); + float3 translation = make_float3( 0 ); + + const float rotationsPerSecond = 5; + + float lastLocalt = fmodf( state.time_last_frame, 1.f / rotationsPerSecond ); + float nowlocalt = fmodf( state.time, 1.f / rotationsPerSecond ); + + if( lastLocalt > nowlocalt ) + lastLocalt -= 1.f / rotationsPerSecond; + + for( unsigned int i = 0; i < plane.srt_animationPropeller.numKeys(); ++i ) + { + plane.srt_animationPropeller.motionData( 0, i ) = + buildSRT( scale, shear, scaleShearPivot, + Quaternion( make_float3( 0, 0, 1 ), lerp(lastLocalt, nowlocalt, i / (plane.srt_animationPropeller.numKeys() - 1.f)) * 360.f * rotationsPerSecond ), + rotationPivot, translation); + } + } + + CUDA_CHECK( cudaMemcpy( (char*)deformSphere.d_matrices, deformSphere.matrix_animation.data(), deformSphere.matrix_animation.byteSize(), cudaMemcpyHostToDevice ) ); + CUDA_CHECK( cudaMemcpy( (char*)plane.d_srts, plane.srt_animation.data(), plane.srt_animation.byteSize(), cudaMemcpyHostToDevice ) ); + CUDA_CHECK( cudaMemcpy( (char*)plane.d_srtsPropeller, plane.srt_animationPropeller.data(), plane.srt_animationPropeller.byteSize(), cudaMemcpyHostToDevice ) ); + } +#endif + +#if 1 + { + std::vector instances = state.instances; + for( size_t i = 0; i < state.fume.size(); ++i ) + { + ExhaustFume& fume = state.fume[i]; + OptixInstance oi = {}; + memcpy( oi.transform, &Matrix3x4::Identity(), sizeof( float ) * 12 ); + oi.visibilityMask = 255; + + OptixSRTMotionTransform& srt = fume.srt_animation.transform( 0 ); + + OptixTraversableHandle handle = fume.exploding_gas_handle; + srt.child = handle; + optixConvertPointerToTraversableHandle( state.context, fume.d_srt, + OPTIX_TRAVERSABLE_TYPE_SRT_MOTION_TRANSFORM, &handle ); + oi.traversableHandle = handle; + + CUDA_CHECK( cudaMemcpy( (char*)fume.d_srt, fume.srt_animation.data(), fume.srt_animation.byteSize(), cudaMemcpyHostToDevice ) ); + instances.emplace_back( oi ); + } + + size_t instances_size_in_bytes = sizeof( OptixInstance ) * instances.size(); + if( state.d_instances_size < instances_size_in_bytes ) + { + if( state.d_instances ) + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_instances ) ) ); + + CUDA_CHECK( cudaMalloc( (void**)&state.d_instances, instances_size_in_bytes ) ); + state.d_instances_size = instances_size_in_bytes; + } + CUDA_CHECK( cudaMemcpy( (void*)state.d_instances, instances.data(), instances_size_in_bytes, cudaMemcpyHostToDevice ) ); + + state.ias_instance_input.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; + state.ias_instance_input.instanceArray.instances = state.d_instances; + state.ias_instance_input.instanceArray.numInstances = static_cast( instances.size() ); + + OptixAccelBufferSizes ias_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( state.context, &state.ias_accel_options, &state.ias_instance_input, 1, &ias_buffer_sizes ) ); + // grow in size if required + if( state.ias_output_buffer_size < ias_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaFree( (void*)state.d_ias_output_buffer ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_ias_output_buffer ), ias_buffer_sizes.outputSizeInBytes ) ); + state.ias_output_buffer_size = ias_buffer_sizes.outputSizeInBytes; + } + } +#endif + + OPTIX_CHECK( optixAccelBuild( state.context, state.stream, + &state.ias_accel_options, &state.ias_instance_input, 1, + state.d_temp_buffer, state.temp_buffer_size, + state.d_ias_output_buffer, state.ias_output_buffer_size, &state.ias_handle, nullptr, 0 ) ); + state.params.handle = state.ias_handle; +} + +void buildMergedGAS( MotionGeometryState& state, const sutil::Scene& scene, CUdeviceptr& gasData, OptixTraversableHandle& gasHandle, sutil::Aabb& aabb ) +{ + auto& meshes = scene.meshes(); + auto& instances = scene.instances(); + + // unify all meshes into a single GAS + std::vector buildInputs; + // since we bake all meshes into a single GAS, we need to apply the transforms + // we do so by using the build input pre-transform property of AS builds + std::vector meshTransforms( meshes.size() ); + CUdeviceptr d_preTransforms = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_preTransforms ), sizeof( Matrix3x4 ) * meshTransforms.size() ) ); + + for( size_t i = 0; i < instances.size(); ++i ) + { + auto& instance = instances[i]; + auto& mesh = meshes[instance->mesh_idx]; + + const size_t num_subMeshes = mesh->indices.size(); + size_t buildInputOffset = buildInputs.size(); + buildInputs.resize( buildInputOffset + num_subMeshes ); + memcpy( &meshTransforms[i], instance->transform.getData(), sizeof( float ) * 12 ); // mesh->transform is a 4x4 matrix, but also row-major + + assert( mesh->positions.size() == num_subMeshes && mesh->normals.size() == num_subMeshes && mesh->colors.size() == num_subMeshes ); + + for( size_t j = 0; j < GeometryData::num_texcoords; ++j ) + assert( mesh->texcoords[j].size() == num_subMeshes ); + + for( size_t j = 0; j < num_subMeshes; ++j ) + { + OptixBuildInput& triangle_input = buildInputs[j + buildInputOffset]; + memset( &triangle_input, 0, sizeof( OptixBuildInput ) ); + triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangle_input.triangleArray.vertexStrideInBytes = + mesh->positions[j].byte_stride ? mesh->positions[j].byte_stride : sizeof( float3 ), + triangle_input.triangleArray.numVertices = mesh->positions[j].count; + triangle_input.triangleArray.vertexBuffers = &( mesh->positions[j].data ); + triangle_input.triangleArray.indexFormat = + mesh->indices[j].elmt_byte_size == 0 ? OPTIX_INDICES_FORMAT_NONE : + mesh->indices[j].elmt_byte_size == 1 ? OPTIX_INDICES_FORMAT_UNSIGNED_BYTE3 : + mesh->indices[j].elmt_byte_size == 2 ? OPTIX_INDICES_FORMAT_UNSIGNED_SHORT3 : + OPTIX_INDICES_FORMAT_UNSIGNED_INT3; + triangle_input.triangleArray.indexStrideInBytes = + mesh->indices[j].byte_stride ? mesh->indices[j].byte_stride * 3 : mesh->indices[j].elmt_byte_size * 3; + triangle_input.triangleArray.numIndexTriplets = mesh->indices[j].count / 3; + triangle_input.triangleArray.indexBuffer = mesh->indices[j].data; + triangle_input.triangleArray.flags = &state.triangle_flags; + triangle_input.triangleArray.numSbtRecords = 1; + triangle_input.triangleArray.preTransform = ( CUdeviceptr )( (char*)d_preTransforms + sizeof( Matrix3x4 ) * i ); + triangle_input.triangleArray.transformFormat = OPTIX_TRANSFORM_FORMAT_MATRIX_FLOAT12; + } + } + + CUDA_CHECK( cudaMemcpy( (void*)d_preTransforms, meshTransforms.data(), sizeof( Matrix3x4 ) * meshTransforms.size(), cudaMemcpyHostToDevice ) ); + + OptixAccelBuildOptions accelOptions = {}; + accelOptions.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION | OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS; + accelOptions.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes gasBufferSizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( state.context, &accelOptions, buildInputs.data(), + static_cast( buildInputs.size() ), &gasBufferSizes ) ); + + // allocate tmp memory + CUdeviceptr d_tempBuffer = 0, d_accelBuffer = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_tempBuffer ), gasBufferSizes.tempSizeInBytes ) ); + + // allocate non-compacted output + compacted size + size_t compactedSizeOffset = roundUp( gasBufferSizes.outputSizeInBytes, sizeof( size_t ) ); + size_t aabbOffset = compactedSizeOffset + sizeof( size_t ); + size_t totalSize = aabbOffset + 6 * sizeof( float ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_accelBuffer ), totalSize ) ); + + OptixAccelEmitDesc emitProperties[2] = {}; + emitProperties[0].type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperties[0].result = ( CUdeviceptr )( (char*)d_accelBuffer + compactedSizeOffset ); + emitProperties[1].type = OPTIX_PROPERTY_TYPE_AABBS; + emitProperties[1].result = ( CUdeviceptr )( (char*)d_accelBuffer + aabbOffset ); + + OPTIX_CHECK( optixAccelBuild( state.context, state.stream, + &accelOptions, buildInputs.data(), + static_cast( buildInputs.size() ), + d_tempBuffer, gasBufferSizes.tempSizeInBytes, + d_accelBuffer, gasBufferSizes.outputSizeInBytes, + &gasHandle, + emitProperties, 2 + ) ); + + CUDA_CHECK( cudaMemcpy( aabb.data(), (const char*)d_accelBuffer + aabbOffset, 6 * sizeof( float ), cudaMemcpyDeviceToHost ) ); + + CUDA_CHECK( cudaFree( (void*)d_tempBuffer ) ); + CUDA_CHECK( cudaFree( (void*)d_preTransforms ) ); + + // Compact GAS + size_t compactedGasSize; + CUDA_CHECK( cudaMemcpy( &compactedGasSize, (const char*)d_accelBuffer + compactedSizeOffset, sizeof( size_t ), cudaMemcpyDeviceToHost ) ); + + if( compactedGasSize < gasBufferSizes.outputSizeInBytes ) + { + CUdeviceptr uncompactedAccel = d_accelBuffer; + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_accelBuffer ), compactedGasSize ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, state.stream, gasHandle, d_accelBuffer, compactedGasSize, &gasHandle ) ); + + CUDA_CHECK( cudaFree( (void*)uncompactedAccel ) ); + } + + gasData = d_accelBuffer; +} + +void buildMeshAccel( MotionGeometryState& state ) +{ + // Allocate temporary space for vertex generation. + // The same memory space is reused for generating the deformed and exploding vertices before updates. + uint32_t numVertices = g_tessellation_resolution * g_tessellation_resolution * 6; + const size_t vertices_size_in_bytes = numVertices * sizeof( float3 ); + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &state.d_temp_vertices[0] ), vertices_size_in_bytes ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &state.d_temp_vertices[1] ), vertices_size_in_bytes ) ); + + // Build static triangulated sphere. + launchGenerateAnimatedVertices( state, AnimationMode_None, 0, 0, g_tessellation_resolution ); + + // Build an AS over the triangles. + // We use un-indexed triangles so we can explode the sphere per triangle. + state.triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + state.triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + state.triangle_input.triangleArray.vertexStrideInBytes = sizeof( float3 ); + state.triangle_input.triangleArray.numVertices = numVertices; + state.triangle_input.triangleArray.vertexBuffers = state.d_temp_vertices; + state.triangle_input.triangleArray.flags = &state.triangle_flags; + state.triangle_input.triangleArray.numSbtRecords = 1; + state.triangle_input.triangleArray.sbtIndexOffsetBuffer = 0; + state.triangle_input.triangleArray.sbtIndexOffsetSizeInBytes = 0; + state.triangle_input.triangleArray.sbtIndexOffsetStrideInBytes = 0; + + state.triangle_input_fume = state.triangle_input; + state.triangle_input_fume.triangleArray.numVertices = g_tessellation_resolution_fume * g_tessellation_resolution_fume * 6; + + OptixAccelBuildOptions gas_accel_options = {}; + gas_accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION | OPTIX_BUILD_FLAG_ALLOW_UPDATE | OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS | OPTIX_BUILD_FLAG_PREFER_FAST_TRACE; + gas_accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + gas_accel_options.motionOptions.numKeys = 2; + gas_accel_options.motionOptions.timeBegin = 0; + gas_accel_options.motionOptions.timeEnd = 1; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( + state.context, + &gas_accel_options, + &state.triangle_input, + 1, // num_build_inputs + &gas_buffer_sizes + ) ); + + state.temp_buffer_size = gas_buffer_sizes.tempSizeInBytes; + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &state.d_temp_buffer ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast< void** >( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 + ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( ( char* )d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( + state.context, + state.stream, // CUDA stream + &gas_accel_options, + &state.triangle_input, + 1, // num build inputs + state.d_temp_buffer, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &state.static_gas_handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + // The memory requirements for the uncompressed exploding GAS (fume) won't change so we can rebuild in-place. + state.exploding_gas_output_buffer_size = gas_buffer_sizes.outputSizeInBytes; + + OptixRelocationInfo relocationInfo; + OPTIX_CHECK( optixAccelGetRelocationInfo( state.context, state.static_gas_handle, &relocationInfo ) ); + + // Compress sphere GAS + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, ( void* )emitProperty.result, sizeof( size_t ), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &state.d_static_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, state.stream, state.static_gas_handle, state.d_static_gas_output_buffer, compacted_gas_size, &state.static_gas_handle ) ); + + CUDA_CHECK( cudaFree( ( void* )d_buffer_temp_output_gas_and_compacted_size ) ); + + state.static_gas_output_buffer_size = compacted_gas_size; + } + else + { + state.d_static_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + + state.static_gas_output_buffer_size = gas_buffer_sizes.outputSizeInBytes; + } + + // Replicate the compressed GAS for the deforming sphere. + // The deforming sphere is never rebuild so we refit the compressed GAS without requiring recompression. + state.deforming_gas_output_buffer_size = state.static_gas_output_buffer_size; + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &state.d_deforming_gas_output_buffer ), state.deforming_gas_output_buffer_size ) ); + CUDA_CHECK( cudaMemcpy( ( void* )state.d_deforming_gas_output_buffer, ( const void* )state.d_static_gas_output_buffer, state.deforming_gas_output_buffer_size, cudaMemcpyDeviceToDevice ) ); + OPTIX_CHECK( optixAccelRelocate( state.context, state.stream, &relocationInfo, 0, 0, state.d_deforming_gas_output_buffer, state.deforming_gas_output_buffer_size, &state.deforming_gas_handle ) ); + + { + deformSphere.matrix_animation = MatrixMotionTransformArray( 1, 10 ); + for(unsigned int i=0; i& instances = state.instances; + instances.resize( INST_COUNT ); + + for( size_t i = 0; i < instances.size(); ++i ) + { + memcpy( instances[i].transform, &Matrix3x4::Identity(), sizeof( float ) * 12 ); + instances[i].sbtOffset = 0; + instances[i].visibilityMask = 255; + } + + unsigned int iIdx = 0; + instances[iIdx++].traversableHandle = state.static_gas_handle; + + { + OptixTraversableHandle handle = state.deforming_gas_handle; + + OptixMatrixMotionTransform& t = deformSphere.matrix_animation.transform( 0 ); + t.child = handle; + t.motionOptions.flags = 0; + t.motionOptions.numKeys = deformSphere.matrix_animation.numKeys(); + t.motionOptions.timeBegin = 0; + t.motionOptions.timeEnd = 1; + + optixConvertPointerToTraversableHandle( state.context, ( CUdeviceptr )( (char*)deformSphere.d_matrices ), + OPTIX_TRAVERSABLE_TYPE_MATRIX_MOTION_TRANSFORM, &handle ); + + instances[iIdx++].traversableHandle = handle; + } + { + OptixTraversableHandle handle = state.plane_gas_handle; + + unsigned int tIdx = 0; + OptixSRTMotionTransform& t = plane.srt_animation.transform( tIdx ); + t.child = handle; + t.motionOptions.flags = 0; + t.motionOptions.numKeys = plane.srt_animation.numKeys(); + t.motionOptions.timeBegin = 0; + t.motionOptions.timeEnd = 1; + + optixConvertPointerToTraversableHandle( state.context, + (CUdeviceptr)((char*)plane.d_srts + plane.srt_animation.byteSizePerTransform() * tIdx), + OPTIX_TRAVERSABLE_TYPE_SRT_MOTION_TRANSFORM, &handle ); + + instances[iIdx++].traversableHandle = handle; + } + { + OptixTraversableHandle handle = state.planePropeller_gas_handle; + + { + unsigned int tIdx = 0; + OptixSRTMotionTransform& t = plane.srt_animationPropeller.transform( tIdx ); + t.child = handle; + t.motionOptions.flags = 0; + t.motionOptions.numKeys = plane.srt_animationPropeller.numKeys(); + t.motionOptions.timeBegin = 0; + t.motionOptions.timeEnd = 1; + + optixConvertPointerToTraversableHandle( state.context, + (CUdeviceptr)((char*)plane.d_srtsPropeller + plane.srt_animationPropeller.byteSizePerTransform() * tIdx), + OPTIX_TRAVERSABLE_TYPE_SRT_MOTION_TRANSFORM, &handle ); + } + + { + unsigned int tIdx = 1; + OptixSRTMotionTransform& t = plane.srt_animation.transform( tIdx ); + t.child = handle; + t.motionOptions.flags = 0; + t.motionOptions.numKeys = plane.srt_animation.numKeys(); + t.motionOptions.timeBegin = 0; + t.motionOptions.timeEnd = 1; + + optixConvertPointerToTraversableHandle( state.context, + (CUdeviceptr)((char*)plane.d_srts + plane.srt_animation.byteSizePerTransform() * tIdx), + OPTIX_TRAVERSABLE_TYPE_SRT_MOTION_TRANSFORM, &handle ); + } + + instances[iIdx++].traversableHandle = handle; + } + CUDA_CHECK( cudaMemcpy( (char*)deformSphere.d_matrices, deformSphere.matrix_animation.data(), deformSphere.matrix_animation.byteSize(), cudaMemcpyHostToDevice ) ); + CUDA_CHECK( cudaMemcpy( (char*)plane.d_srts, plane.srt_animation.data(), plane.srt_animation.byteSize(), cudaMemcpyHostToDevice ) ); + CUDA_CHECK( cudaMemcpy( (char*)plane.d_srtsPropeller, plane.srt_animationPropeller.data(), plane.srt_animationPropeller.byteSize(), cudaMemcpyHostToDevice ) ); + + size_t instances_size_in_bytes = sizeof( OptixInstance ) * instances.size(); + CUDA_CHECK( cudaMalloc( ( void** )&state.d_instances, instances_size_in_bytes ) ); + state.d_instances_size = instances_size_in_bytes; + CUDA_CHECK( cudaMemcpy( ( void* )state.d_instances, instances.data(), instances_size_in_bytes, cudaMemcpyHostToDevice ) ); + + state.ias_instance_input.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; + state.ias_instance_input.instanceArray.instances = state.d_instances; + state.ias_instance_input.instanceArray.numInstances = static_cast( instances.size() ); + + // we choose FAST_BUILD here as we need to rebuild every frame, no update or compaction needed + state.ias_accel_options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_BUILD; + // In this interactive sample, build times can govern render times. + // Hence, we build a static IAS with faster build times despite slower traversal times. +#if 1 + state.ias_accel_options.motionOptions.numKeys = 1; +#else + state.ias_accel_options.motionOptions.numKeys = 2; + state.ias_accel_options.motionOptions.timeBegin = 0; + state.ias_accel_options.motionOptions.timeEnd = 1; +#endif + state.ias_accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes ias_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( state.context, &state.ias_accel_options, &state.ias_instance_input, 1, &ias_buffer_sizes ) ); + + // non-compacted output + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_ias_output_buffer ), ias_buffer_sizes.outputSizeInBytes ) ); + + size_t maxUpdateTempSize = std::max( ias_buffer_sizes.tempSizeInBytes, gas_buffer_sizes.tempUpdateSizeInBytes ); + if( maxUpdateTempSize > state.temp_buffer_size ) + { + CUDA_CHECK( cudaFree( (void*)state.d_temp_buffer ) ); + state.temp_buffer_size = maxUpdateTempSize; + CUDA_CHECK( cudaMalloc( (void**)&state.d_temp_buffer, state.temp_buffer_size ) ); + } + + OPTIX_CHECK( optixAccelBuild( state.context, state.stream, + &state.ias_accel_options, + &state.ias_instance_input, 1, + state.d_temp_buffer, ias_buffer_sizes.tempSizeInBytes, + state.d_ias_output_buffer, ias_buffer_sizes.outputSizeInBytes, + &state.ias_handle, + nullptr, 0 ) ); + + state.params.handle = state.ias_handle; +} + + +void createModule( MotionGeometryState& state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + state.pipeline_compile_options.usesMotionBlur = true; + state.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_ANY; + state.pipeline_compile_options.numPayloadValues = 5; + state.pipeline_compile_options.numAttributeValues = 2; + state.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + state.pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + state.pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE; + + OptixModuleCompileBoundValueEntry boundValue = {}; + { + boundValue.pipelineParamOffsetInBytes = offsetof( Params, ao ); + boundValue.sizeInBytes = sizeof( Params::ao ); + boundValue.boundValuePtr = &state.renderAO; + boundValue.annotation = "ao"; + module_compile_options.numBoundValues = 1; + module_compile_options.boundValues = &boundValue; + } + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixMotionGeometry.cu", inputSize ); + + OPTIX_CHECK_LOG( optixModuleCreate( + state.context, + &module_compile_options, + &state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &state.ptx_module + ) ); +} + + +void createProgramGroups( MotionGeometryState& state ) +{ + OptixProgramGroupOptions program_group_options = {}; + + { + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = state.ptx_module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.raygen_prog_group + ) ); + } + + { + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.ptx_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__ms"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.miss_group + ) ); + } + + { + OptixProgramGroupDesc hit_prog_group_desc = {}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = state.ptx_module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__ch"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.hit_group + ) ); + } + + { + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.ptx_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__occlusion"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.miss_group_occlusion ) ); + } +} + + +void createPipeline( MotionGeometryState& state ) +{ + OptixProgramGroup program_groups[] = + { + state.raygen_prog_group, + state.miss_group, + state.miss_group_occlusion, + state.hit_group + }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = 20; + + OPTIX_CHECK_LOG( optixPipelineCreate( + state.context, + &state.pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &state.pipeline + ) ); + + // We need to specify the max traversal depth. Calculate the stack sizes, so we can specify all + // parameters to optixPipelineSetStackSize. + OptixStackSizes stack_sizes = {}; + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.raygen_prog_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.miss_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.miss_group_occlusion, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.hit_group, &stack_sizes, state.pipeline ) ); + + uint32_t max_trace_depth = pipeline_link_options.maxTraceDepth; + uint32_t max_cc_depth = 0; + uint32_t max_dc_depth = 0; + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( + &stack_sizes, + max_trace_depth, + max_cc_depth, + max_dc_depth, + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, + &continuation_stack_size + ) ); + + // This is 4 since the largest depth is IAS->MT->MT->GAS + const uint32_t max_traversable_graph_depth = 4; + + OPTIX_CHECK( optixPipelineSetStackSize( + state.pipeline, + direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, + continuation_stack_size, + max_traversable_graph_depth + ) ); +} + + +void createSBT( MotionGeometryState& state ) +{ + CUdeviceptr d_raygen_record; + const size_t raygen_record_size = sizeof( RayGenRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &d_raygen_record ), raygen_record_size ) ); + + RayGenRecord rg_sbt = {}; + OPTIX_CHECK( optixSbtRecordPackHeader( state.raygen_prog_group, &rg_sbt ) ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast< void* >( d_raygen_record ), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr d_miss_records; + const unsigned int numMissPrograms = 2; + const size_t miss_record_size = sizeof( MissRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast< void** >( &d_miss_records ), miss_record_size * numMissPrograms ) ); + + MissRecord ms_sbt[numMissPrograms]; + OPTIX_CHECK( optixSbtRecordPackHeader( state.miss_group, &ms_sbt[0] ) ); + OPTIX_CHECK( optixSbtRecordPackHeader( state.miss_group_occlusion, &ms_sbt[1] ) ); + ms_sbt[0].data.bg_color = make_float4( 0.0f ); + ms_sbt[1].data.bg_color = make_float4( 0.0f ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast< void* >( d_miss_records ), + ms_sbt, + miss_record_size * numMissPrograms, + cudaMemcpyHostToDevice + ) ); + + std::vector hitgroup_records( 1 ); + + OPTIX_CHECK( optixSbtRecordPackHeader( state.hit_group, &hitgroup_records[0] ) ); + hitgroup_records[0].data.color = make_float3( 1 ); + + CUdeviceptr d_hitgroup_records; + const size_t hitgroup_record_size = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast< void** >( &d_hitgroup_records ), + hitgroup_record_size * hitgroup_records.size() + ) ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast< void* >( d_hitgroup_records ), + hitgroup_records.data(), + hitgroup_record_size*hitgroup_records.size(), + cudaMemcpyHostToDevice + ) ); + + state.sbt.raygenRecord = d_raygen_record; + state.sbt.missRecordBase = d_miss_records; + state.sbt.missRecordStrideInBytes = static_cast< uint32_t >( miss_record_size ); + state.sbt.missRecordCount = numMissPrograms; + state.sbt.hitgroupRecordBase = d_hitgroup_records; + state.sbt.hitgroupRecordStrideInBytes = static_cast< uint32_t >( hitgroup_record_size ); + state.sbt.hitgroupRecordCount = static_cast< uint32_t >( hitgroup_records.size() ); +} + + +void cleanupState( MotionGeometryState& state ) +{ + OPTIX_CHECK( optixPipelineDestroy( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.miss_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.hit_group ) ); + OPTIX_CHECK( optixModuleDestroy( state.ptx_module ) ); + OPTIX_CHECK( optixDeviceContextDestroy( state.context ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_temp_vertices[0] ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_temp_vertices[1] ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_static_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_deforming_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_plane_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_planePropeller_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_instances ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_ias_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_temp_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( state.d_params ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( deformSphere.d_matrices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( plane.d_srts ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast< void* >( plane.d_srtsPropeller ) ) ); +} + + +//------------------------------------------------------------------------------ +// +// Main +// +//------------------------------------------------------------------------------ + +int main( int argc, char* argv[] ) +{ + MotionGeometryState state; + state.params.width = 1024; + state.params.height = 768; + state.time = 0.f; + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::GL_INTEROP; + + int num_frames = 18; + float animation_time = 10.0f; + + // + // Parse command line options + // + std::string outfile; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--no-gl-interop" ) + { + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outfile = argv[++i]; + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + int w, h; + sutil::parseDimensions( dims_arg.c_str(), w, h ); + state.params.width = w; + state.params.height = h; + } + else if( arg == "--time" || arg == "-t" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + + animation_time = (float)atof( argv[++i] ); + } + else if( arg == "--frames" || arg == "-n" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + + num_frames = atoi( argv[++i] ); + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + initCameraState(); + + // + // Set up OptiX state + // + createContext( state ); + + createModule( state ); + createProgramGroups( state ); + createPipeline( state ); + buildMeshAccel( state ); + createSBT( state ); + initLaunchParams( state ); + + if( outfile.empty() ) + { + std::cout << "Keys: Up/Down Double/half target frame rate\n"; + std::cout << " M/N Increase/reduce plane speed\n"; + std::cout << " J/H Increase/reduce deform sphere orbit speed\n"; + std::cout << " V Toggle: camera follow plane\n"; + std::cout << " B Add exhaust fume\n"; + std::cout << " A Toggle: AO rendering\n"; + GLFWwindow* window = sutil::initUI( "optixMotionGeometry", state.params.width, state.params.height ); + glfwSetMouseButtonCallback( window, mouseButtonCallback ); + glfwSetCursorPosCallback( window, cursorPosCallback ); + glfwSetWindowSizeCallback( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback( window, keyCallback ); + glfwSetScrollCallback( window, scrollCallback ); + glfwSetWindowUserPointer( window, &state ); + + // + // Render loop + // + { + sutil::CUDAOutputBuffer output_buffer( + output_buffer_type, + state.params.width, + state.params.height + ); + + output_buffer.setStream( state.stream ); + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + std::chrono::duration full_frame_time( 1/60.0 ); // init with 60.0 fps + + auto tstart = std::chrono::system_clock::now(); + + state.targetFrameTime = 1 / 30.0f; + + do + { + cudaDeviceSynchronize(); + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + ////////////////////////////////////////////////////////////////////////// + auto tnow = std::chrono::system_clock::now(); + std::chrono::duration time = tnow - tstart; + state.time_last_frame = state.time; + state.time = (float)time.count(); + float timePassed = state.time - state.time_last_frame; + + unsigned int targetSpp = max( 1u, (unsigned int)(state.targetFrameTime / timePassed * state.params.spp) ); + if( abs( (float)targetSpp / state.params.spp - 1u ) > 0.2 ) + { + state.params.spp = ( state.params.spp + targetSpp ) / 2; + } + else + { + if( state.time - state.time_last_frame < state.targetFrameTime ) + state.params.spp++; + else + state.params.spp = max( 1u, state.params.spp - 1 ); + } + ////////////////////////////////////////////////////////////////////////// + + if( state.time - state.time_last_fume > 0.4f ) + { + addFume( state ); + state.time_last_fume = state.time; + } + + ////////////////////////////////////////////////////////////////////////// + + updateMeshAccel( state ); + + handleCameraUpdate( state ); + handleResize( output_buffer, state.params ); + + // sync to correctly attribute where time is spent + cudaDeviceSynchronize(); + + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + launchSubframe( output_buffer, state ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1 - t0; + + full_frame_time = state_update_time + render_time + display_time; + + sutil::displayStats( state_update_time, render_time, display_time ); + + sutil::beginFrameImGui(); + static char display_text[256]; + sprintf( display_text, + "ambient occlusion: %s\n" + "samples per pixel: %d\n", + ( state.renderAO ? "on" : "off" ), state.params.spp ); + sutil::displayText( display_text, 10.0f, 100.0f ); + sutil::endFrameImGui(); + + + glfwSwapBuffers( window ); + + ++state.params.subframe_index; + } while( !glfwWindowShouldClose( window ) ); + CUDA_SYNC_CHECK(); + } + + sutil::cleanupUI( window ); + } + else + { + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + sutil::initGLFW(); // For GL context + sutil::initGL(); + } + + { + // this scope is for output_buffer, to ensure the destructor is called bfore glfwTerminate() + + sutil::CUDAOutputBuffer output_buffer( + output_buffer_type, + state.params.width, + state.params.height + ); + + handleCameraUpdate( state ); + handleResize( output_buffer, state.params ); + + // run animation frames + for( unsigned int i = 0; i < static_cast( num_frames ); ++i ) + { + state.time_last_frame = state.time; + state.time = i * ( animation_time / ( num_frames - 1 ) ); + + if( state.time - state.time_last_fume > 0.4f ) + { + addFume( state ); + state.time_last_fume = state.time; + } + + updateMeshAccel( state ); + launchSubframe( output_buffer, state ); + } + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + glfwTerminate(); + } + } + + cleanupState( state ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/optixMotionGeometry.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/optixMotionGeometry.cu new file mode 100644 index 00000000..903c05e5 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/optixMotionGeometry.cu @@ -0,0 +1,278 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "optixMotionGeometry.h" +#include "random.h" + +#include +#include + +constexpr unsigned int SBT_STRIDE_COLLAPSE = 0; + +extern "C" { + __constant__ Params params; +} + +struct Onb +{ + __forceinline__ __device__ Onb( const float3& normal ) + { + m_normal = normal; + + if( fabs( m_normal.x ) > fabs( m_normal.z ) ) + { + m_binormal.x = -m_normal.y; + m_binormal.y = m_normal.x; + m_binormal.z = 0; + } + else + { + m_binormal.x = 0; + m_binormal.y = -m_normal.z; + m_binormal.z = m_normal.y; + } + + m_binormal = normalize( m_binormal ); + m_tangent = cross( m_binormal, m_normal ); + } + + __forceinline__ __device__ void inverse_transform( float3& p ) const + { + p = p.x * m_tangent + p.y * m_binormal + p.z * m_normal; + } + + float3 m_tangent; + float3 m_binormal; + float3 m_normal; +}; + +static __forceinline__ __device__ void cosine_sample_hemisphere( const float u1, const float u2, float3& p ) +{ + // Uniformly sample disk. + const float r = sqrtf( u1 ); + const float phi = 2.0f * M_PIf * u2; + p.x = r * cosf( phi ); + p.y = r * sinf( phi ); + + // Project up to hemisphere. + p.z = sqrtf( fmaxf( 0.0f, 1.0f - p.x * p.x - p.y * p.y ) ); +} + + +// Use named types for compatibility with nvrtc +// Otherwise these structs can be defined as unnamed structs directly in 'Payload' +// to avoid access via p0123.px and directly access px. +struct t_p0123 { + unsigned int p0, p1, p2, p3; +}; +struct t_cseed { + float3 c; + unsigned int seed; +}; + +struct Payload { + + union { + t_p0123 p0123; + t_cseed cseed; + }; + + __forceinline__ __device__ void setAll() + { + optixSetPayload_0( p0123.p0 ); + optixSetPayload_1( p0123.p1 ); + optixSetPayload_2( p0123.p2 ); + optixSetPayload_3( p0123.p3 ); + } + __forceinline__ __device__ void getAll() + { + p0123.p0 = optixGetPayload_0(); + p0123.p1 = optixGetPayload_1(); + p0123.p2 = optixGetPayload_2(); + p0123.p3 = optixGetPayload_3(); + } + __forceinline__ __device__ void setC() + { + optixSetPayload_0( p0123.p0 ); + optixSetPayload_1( p0123.p1 ); + optixSetPayload_2( p0123.p2 ); + } + __forceinline__ __device__ void getC() + { + p0123.p0 = optixGetPayload_0(); + p0123.p1 = optixGetPayload_1(); + p0123.p2 = optixGetPayload_2(); + } + __forceinline__ __device__ void getSeed() + { + p0123.p3 = optixGetPayload_3(); + } +}; + +static __forceinline__ __device__ void trace( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax, + float time, + Payload& prd +) +{ + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + time, + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_NONE, + 0, // SBT offset, first ray type (only one here) + SBT_STRIDE_COLLAPSE, // SBT stride, forcing a single HitGroup in combination with an sbt offset set to zero for every instance! + 0, // missSBTIndex, used for camera rays + prd.p0123.p0, prd.p0123.p1, prd.p0123.p2, prd.p0123.p3 + ); +} + + +extern "C" __global__ void __raygen__rg() +{ + const uint3 idx = optixGetLaunchIndex(); + const uint3 dim = optixGetLaunchDimensions(); + + const float3 eye = params.eye; + const float3 U = params.U; + const float3 V = params.V; + const float3 W = params.W; + + Payload payload; + payload.cseed.seed = tea<4>( idx.y * dim.x + idx.x, 12346789 + params.subframe_index ); + + float3 final_c = make_float3( 0 ); +#pragma unroll 1 + for( int x = 1; x <= params.spp; ++x ) + { + const float2 d = 2.0f * make_float2( + ( static_cast< float >( idx.x ) + rnd( payload.cseed.seed ) ) / static_cast< float >( dim.x ), + ( static_cast< float >( idx.y ) + rnd( payload.cseed.seed ) ) / static_cast< float >( dim.y ) + ) - 1.0f; + float3 direction = normalize( d.x * U + d.y * V + W ); + + float time = rnd( payload.cseed.seed ); + + payload.cseed.c = make_float3( 0.5f, 0.5f, 0.5f ); + trace( params.handle, + eye, + direction, + 0.00f, // tmin + 1e16f, // tmax + time, + payload ); + final_c += payload.cseed.c; + } + final_c /= params.spp; + params.frame_buffer[idx.y * params.width + idx.x] = make_color( final_c ); +} + + +extern "C" __global__ void __miss__ms() +{ + MissData* rt_data = reinterpret_cast< MissData* >( optixGetSbtDataPointer() ); + Payload p; + p.cseed.c = make_float3( rt_data->bg_color.x, rt_data->bg_color.y, rt_data->bg_color.z ); + p.setC(); +} + + + +extern "C" __global__ void __miss__occlusion() +{ + optixSetPayload_0( 0 ); +} + +extern "C" __global__ void __closesthit__ch() +{ + Payload p; + p.getSeed(); + + // fetch current triangle vertices + float3 data[3]; + optixGetTriangleVertexData( optixGetGASTraversableHandle(), optixGetPrimitiveIndex(), optixGetSbtGASIndex(), + optixGetRayTime(), data ); + + // compute triangle normal + data[1] -= data[0]; + data[2] -= data[0]; + float3 normal = make_float3( + data[1].y*data[2].z - data[1].z*data[2].y, + data[1].z*data[2].x - data[1].x*data[2].z, + data[1].x*data[2].y - data[1].y*data[2].x ); + const float s = 0.5f / sqrtf( normal.x*normal.x + normal.y*normal.y + normal.z*normal.z ); + + float shade = 1.0f; + if( params.ao ) + { + const float z1 = rnd( p.cseed.seed ); + const float z2 = rnd( p.cseed.seed ); + + unsigned int occluded = 1; + float3 w_in; + cosine_sample_hemisphere( z1, z2, w_in ); + float3 wn = normalize( optixTransformNormalFromObjectToWorldSpace( 2.f * s*normal ) ); + wn = faceforward( wn, -optixGetWorldRayDirection(), wn ); + Onb onb( wn ); + onb.inverse_transform( w_in ); + + float3 pHit = optixGetWorldRayOrigin() + optixGetWorldRayDirection() * optixGetRayTmax(); + + optixTrace( + params.handle, + pHit + wn*0.001f, w_in, + 0.00f, 1e16f, optixGetRayTime(), // tmin, tmax, time + 0xff, + OPTIX_RAY_FLAG_DISABLE_CLOSESTHIT | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT | OPTIX_RAY_FLAG_DISABLE_ANYHIT, + 0, SBT_STRIDE_COLLAPSE, // no hit group will even be executed (assuming no IS), hence, set stride and offset to 0 + 1, // select MS program + occluded ); // this is inout here! If MS is called, it will override the payload + + if( occluded ) + shade = 0.f; + } + + HitGroupData* rt_data = reinterpret_cast( optixGetSbtDataPointer() ); + // convert normal to color and store in payload + p.cseed.c = shade * ( normal * s + make_float3( 0.5f ) ) * rt_data->color; + + p.setAll(); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/optixMotionGeometry.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/optixMotionGeometry.h new file mode 100644 index 00000000..30211715 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/optixMotionGeometry.h @@ -0,0 +1,60 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +struct Params +{ + uchar4* frame_buffer; + unsigned int width; + unsigned int height; + unsigned int spp; + float3 eye, U, V, W; + OptixTraversableHandle handle; + int subframe_index; + bool ao; +}; + +struct RayGenData +{ + float3 cam_eye; + float3 camera_u, camera_v, camera_w; +}; + + +struct MissData +{ + float4 bg_color; +}; + + +struct HitGroupData +{ + float3 color; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/tiny_obj_loader.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/tiny_obj_loader.h new file mode 100644 index 00000000..71aac74f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/tiny_obj_loader.h @@ -0,0 +1,3033 @@ +/* +The MIT License (MIT) + +Copyright (c) 2012-2018 Syoyo Fujita and many contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// +// version 2.0.0 : Add new object oriented API. 1.x API is still provided. +// * Support line primitive. +// * Support points primitive. +// * Support multiple search path for .mtl(v1 API). +// version 1.4.0 : Modifed ParseTextureNameAndOption API +// version 1.3.1 : Make ParseTextureNameAndOption API public +// version 1.3.0 : Separate warning and error message(breaking API of LoadObj) +// version 1.2.3 : Added color space extension('-colorspace') to tex opts. +// version 1.2.2 : Parse multiple group names. +// version 1.2.1 : Added initial support for line('l') primitive(PR #178) +// version 1.2.0 : Hardened implementation(#175) +// version 1.1.1 : Support smoothing groups(#162) +// version 1.1.0 : Support parsing vertex color(#144) +// version 1.0.8 : Fix parsing `g` tag just after `usemtl`(#138) +// version 1.0.7 : Support multiple tex options(#126) +// version 1.0.6 : Add TINYOBJLOADER_USE_DOUBLE option(#124) +// version 1.0.5 : Ignore `Tr` when `d` exists in MTL(#43) +// version 1.0.4 : Support multiple filenames for 'mtllib'(#112) +// version 1.0.3 : Support parsing texture options(#85) +// version 1.0.2 : Improve parsing speed by about a factor of 2 for large +// files(#105) +// version 1.0.1 : Fixes a shape is lost if obj ends with a 'usemtl'(#104) +// version 1.0.0 : Change data structure. Change license from BSD to MIT. +// + +// +// Use this in *one* .cc +// #define TINYOBJLOADER_IMPLEMENTATION +// #include "tiny_obj_loader.h" +// + +#ifndef TINY_OBJ_LOADER_H_ +#define TINY_OBJ_LOADER_H_ + +#include +#include +#include + +namespace tinyobj { + +// TODO(syoyo): Better C++11 detection for older compiler +#if __cplusplus > 199711L +#define TINYOBJ_OVERRIDE override +#else +#define TINYOBJ_OVERRIDE +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#pragma clang diagnostic ignored "-Wpadded" + +#endif + +// https://en.wikipedia.org/wiki/Wavefront_.obj_file says ... +// +// -blendu on | off # set horizontal texture blending +// (default on) +// -blendv on | off # set vertical texture blending +// (default on) +// -boost real_value # boost mip-map sharpness +// -mm base_value gain_value # modify texture map values (default +// 0 1) +// # base_value = brightness, +// gain_value = contrast +// -o u [v [w]] # Origin offset (default +// 0 0 0) +// -s u [v [w]] # Scale (default +// 1 1 1) +// -t u [v [w]] # Turbulence (default +// 0 0 0) +// -texres resolution # texture resolution to create +// -clamp on | off # only render texels in the clamped +// 0-1 range (default off) +// # When unclamped, textures are +// repeated across a surface, +// # when clamped, only texels which +// fall within the 0-1 +// # range are rendered. +// -bm mult_value # bump multiplier (for bump maps +// only) +// +// -imfchan r | g | b | m | l | z # specifies which channel of the file +// is used to +// # create a scalar or bump texture. +// r:red, g:green, +// # b:blue, m:matte, l:luminance, +// z:z-depth.. +// # (the default for bump is 'l' and +// for decal is 'm') +// bump -imfchan r bumpmap.tga # says to use the red channel of +// bumpmap.tga as the bumpmap +// +// For reflection maps... +// +// -type sphere # specifies a sphere for a "refl" +// reflection map +// -type cube_top | cube_bottom | # when using a cube map, the texture +// file for each +// cube_front | cube_back | # side of the cube is specified +// separately +// cube_left | cube_right +// +// TinyObjLoader extension. +// +// -colorspace SPACE # Color space of the texture. e.g. +// 'sRGB` or 'linear' +// + +#ifdef TINYOBJLOADER_USE_DOUBLE +//#pragma message "using double" +typedef double real_t; +#else +//#pragma message "using float" +typedef float real_t; +#endif + +typedef enum { + TEXTURE_TYPE_NONE, // default + TEXTURE_TYPE_SPHERE, + TEXTURE_TYPE_CUBE_TOP, + TEXTURE_TYPE_CUBE_BOTTOM, + TEXTURE_TYPE_CUBE_FRONT, + TEXTURE_TYPE_CUBE_BACK, + TEXTURE_TYPE_CUBE_LEFT, + TEXTURE_TYPE_CUBE_RIGHT +} texture_type_t; + +struct texture_option_t { + texture_type_t type; // -type (default TEXTURE_TYPE_NONE) + real_t sharpness; // -boost (default 1.0?) + real_t brightness; // base_value in -mm option (default 0) + real_t contrast; // gain_value in -mm option (default 1) + real_t origin_offset[3]; // -o u [v [w]] (default 0 0 0) + real_t scale[3]; // -s u [v [w]] (default 1 1 1) + real_t turbulence[3]; // -t u [v [w]] (default 0 0 0) + int texture_resolution; // -texres resolution (No default value in the spec. We'll use -1) + bool clamp; // -clamp (default false) + char imfchan; // -imfchan (the default for bump is 'l' and for decal is 'm') + bool blendu; // -blendu (default on) + bool blendv; // -blendv (default on) + real_t bump_multiplier; // -bm (for bump maps only, default 1.0) + + // extension + std::string colorspace; // Explicitly specify color space of stored texel + // value. Usually `sRGB` or `linear` (default empty). +}; + +struct material_t { + std::string name; + + real_t ambient[3]; + real_t diffuse[3]; + real_t specular[3]; + real_t transmittance[3]; + real_t emission[3]; + real_t shininess; + real_t ior; // index of refraction + real_t dissolve; // 1 == opaque; 0 == fully transparent + // illumination model (see http://www.fileformat.info/format/material/) + int illum; + + int dummy; // Suppress padding warning. + + std::string ambient_texname; // map_Ka + std::string diffuse_texname; // map_Kd + std::string specular_texname; // map_Ks + std::string specular_highlight_texname; // map_Ns + std::string bump_texname; // map_bump, map_Bump, bump + std::string displacement_texname; // disp + std::string alpha_texname; // map_d + std::string reflection_texname; // refl + + texture_option_t ambient_texopt; + texture_option_t diffuse_texopt; + texture_option_t specular_texopt; + texture_option_t specular_highlight_texopt; + texture_option_t bump_texopt; + texture_option_t displacement_texopt; + texture_option_t alpha_texopt; + texture_option_t reflection_texopt; + + // PBR extension + // http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr + real_t roughness; // [0, 1] default 0 + real_t metallic; // [0, 1] default 0 + real_t sheen; // [0, 1] default 0 + real_t clearcoat_thickness; // [0, 1] default 0 + real_t clearcoat_roughness; // [0, 1] default 0 + real_t anisotropy; // aniso. [0, 1] default 0 + real_t anisotropy_rotation; // anisor. [0, 1] default 0 + real_t pad0; + std::string roughness_texname; // map_Pr + std::string metallic_texname; // map_Pm + std::string sheen_texname; // map_Ps + std::string emissive_texname; // map_Ke + std::string normal_texname; // norm. For normal mapping. + + texture_option_t roughness_texopt; + texture_option_t metallic_texopt; + texture_option_t sheen_texopt; + texture_option_t emissive_texopt; + texture_option_t normal_texopt; + + int pad2; + + std::map unknown_parameter; + +#ifdef TINY_OBJ_LOADER_PYTHON_BINDING + // For pybind11 + std::array GetDiffuse() { + std::array values; + values[0] = double(diffuse[0]); + values[1] = double(diffuse[1]); + values[2] = double(diffuse[2]); + + return values; + } + + std::array GetSpecular() { + std::array values; + values[0] = double(specular[0]); + values[1] = double(specular[1]); + values[2] = double(specular[2]); + + return values; + } + + std::array GetTransmittance() { + std::array values; + values[0] = double(transmittance[0]); + values[1] = double(transmittance[1]); + values[2] = double(transmittance[2]); + + return values; + } + + std::array GetEmission() { + std::array values; + values[0] = double(emission[0]); + values[1] = double(emission[1]); + values[2] = double(emission[2]); + + return values; + } + + std::array GetAmbient() { + std::array values; + values[0] = double(ambient[0]); + values[1] = double(ambient[1]); + values[2] = double(ambient[2]); + + return values; + } + + void SetDiffuse(std::array &a) { + diffuse[0] = real_t(a[0]); + diffuse[1] = real_t(a[1]); + diffuse[2] = real_t(a[2]); + } + + void SetAmbient(std::array &a) { + ambient[0] = real_t(a[0]); + ambient[1] = real_t(a[1]); + ambient[2] = real_t(a[2]); + } + + void SetSpecular(std::array &a) { + specular[0] = real_t(a[0]); + specular[1] = real_t(a[1]); + specular[2] = real_t(a[2]); + } + + void SetTransmittance(std::array &a) { + transmittance[0] = real_t(a[0]); + transmittance[1] = real_t(a[1]); + transmittance[2] = real_t(a[2]); + } + + std::string GetCustomParameter(const std::string &key) { + std::map::const_iterator it = + unknown_parameter.find(key); + + if (it != unknown_parameter.end()) { + return it->second; + } + return std::string(); + } + +#endif + +}; + +struct tag_t { + std::string name; + + std::vector intValues; + std::vector floatValues; + std::vector stringValues; +}; + +// Index struct to support different indices for vtx/normal/texcoord. +// -1 means not used. +struct index_t { + int vertex_index; + int normal_index; + int texcoord_index; +}; + +struct mesh_t { + std::vector vertex_indices; + std::vector normal_indices; + std::vector texcoord_indices; + std::vector + num_face_vertices; // The number of vertices per + // face. 3 = triangle, 4 = quad, + // ... Up to 255 vertices per face. + std::vector material_ids; // per-face material ID + std::vector smoothing_group_ids; // per-face smoothing group + // ID(0 = off. positive value + // = group id) + std::vector tags; // SubD tag +}; + +// struct path_t { +// std::vector indices; // pairs of indices for lines +//}; + +struct lines_t { + // Linear flattened indices. + std::vector indices; // indices for vertices(poly lines) + std::vector num_line_vertices; // The number of vertices per line. +}; + +struct points_t { + std::vector indices; // indices for points +}; + +struct shape_t { + std::string name; + mesh_t mesh; + lines_t lines; + points_t points; +}; + +// Vertex attributes +struct attrib_t { + std::vector vertices; // 'v'(xyz) + + // For backward compatibility, we store vertex weight in separate array. + std::vector vertex_weights; // 'v'(w) + std::vector normals; // 'vn' + std::vector texcoords; // 'vt'(uv) + + // For backward compatibility, we store texture coordinate 'w' in separate + // array. + std::vector texcoord_ws; // 'vt'(w) + std::vector colors; // extension: vertex colors + + attrib_t() {} + + // + // For pybind11 + // + const std::vector &GetVertices() const { return vertices; } + + const std::vector &GetVertexWeights() const { return vertex_weights; } +}; + +struct callback_t { + // W is optional and set to 1 if there is no `w` item in `v` line + void (*vertex_cb)(void *user_data, real_t x, real_t y, real_t z, real_t w); + void (*normal_cb)(void *user_data, real_t x, real_t y, real_t z); + + // y and z are optional and set to 0 if there is no `y` and/or `z` item(s) in + // `vt` line. + void (*texcoord_cb)(void *user_data, real_t x, real_t y, real_t z); + + // called per 'f' line. num_indices is the number of face indices(e.g. 3 for + // triangle, 4 for quad) + // 0 will be passed for undefined index in index_t members. + void (*index_cb)(void *user_data, index_t *indices, int num_indices); + // `name` material name, `material_id` = the array index of material_t[]. -1 + // if + // a material not found in .mtl + void (*usemtl_cb)(void *user_data, const char *name, int material_id); + // `materials` = parsed material data. + void (*mtllib_cb)(void *user_data, const material_t *materials, + int num_materials); + // There may be multiple group names + void (*group_cb)(void *user_data, const char **names, int num_names); + void (*object_cb)(void *user_data, const char *name); + + callback_t() + : vertex_cb(NULL), + normal_cb(NULL), + texcoord_cb(NULL), + index_cb(NULL), + usemtl_cb(NULL), + mtllib_cb(NULL), + group_cb(NULL), + object_cb(NULL) {} +}; + +class MaterialReader { + public: + MaterialReader() {} + virtual ~MaterialReader(); + + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, std::string *warn, + std::string *err) = 0; +}; + +/// +/// Read .mtl from a file. +/// +class MaterialFileReader : public MaterialReader { + public: + // Path could contain separator(';' in Windows, ':' in Posix) + explicit MaterialFileReader(const std::string &mtl_basedir) + : m_mtlBaseDir(mtl_basedir) {} + virtual ~MaterialFileReader() TINYOBJ_OVERRIDE {} + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, std::string *warn, + std::string *err) TINYOBJ_OVERRIDE; + + private: + std::string m_mtlBaseDir; +}; + +/// +/// Read .mtl from a stream. +/// +class MaterialStreamReader : public MaterialReader { + public: + explicit MaterialStreamReader(std::istream &inStream) + : m_inStream(inStream) {} + virtual ~MaterialStreamReader() TINYOBJ_OVERRIDE {} + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, std::string *warn, + std::string *err) TINYOBJ_OVERRIDE; + + private: + std::istream &m_inStream; +}; + +// v2 API +struct ObjReaderConfig { + bool triangulate; // triangulate polygon? + + /// Parse vertex color. + /// If vertex color is not present, its filled with default value. + /// false = no vertex color + /// This will increase memory of parsed .obj + bool vertex_color; + + /// + /// Search path to .mtl file. + /// Default = "" = search from the same directory of .obj file. + /// Valid only when loading .obj from a file. + /// + std::string mtl_search_path; + + ObjReaderConfig() : triangulate(true), vertex_color(true) {} +}; + +/// +/// Wavefront .obj reader class(v2 API) +/// +class ObjReader { + public: + ObjReader() : valid_(false) {} + ~ObjReader() {} + + /// + /// Load .obj and .mtl from a file. + /// + /// @param[in] filename wavefront .obj filename + /// @param[in] config Reader configuration + /// + bool ParseFromFile(const std::string &filename, + const ObjReaderConfig &config = ObjReaderConfig()); + + /// + /// Parse .obj from a text string. + /// Need to supply .mtl text string by `mtl_text`. + /// This function ignores `mtllib` line in .obj text. + /// + /// @param[in] obj_text wavefront .obj filename + /// @param[in] mtl_text wavefront .mtl filename + /// @param[in] config Reader configuration + /// + bool ParseFromString(const std::string &obj_text, const std::string &mtl_text, + const ObjReaderConfig &config = ObjReaderConfig()); + + /// + /// .obj was loaded or parsed correctly. + /// + bool Valid() const { return valid_; } + + const attrib_t &GetAttrib() const { return attrib_; } + + const std::vector &GetShapes() const { return shapes_; } + + const std::vector &GetMaterials() const { return materials_; } + + /// + /// Warning message(may be filled after `Load` or `Parse`) + /// + const std::string &Warning() const { return warning_; } + + /// + /// Error message(filled when `Load` or `Parse` failed) + /// + const std::string &Error() const { return error_; } + + private: + bool valid_; + + attrib_t attrib_; + std::vector shapes_; + std::vector materials_; + + std::string warning_; + std::string error_; +}; + +/// ==>>========= Legacy v1 API ============================================= + +/// Loads .obj from a file. +/// 'attrib', 'shapes' and 'materials' will be filled with parsed shape data +/// 'shapes' will be filled with parsed shape data +/// Returns true when loading .obj become success. +/// Returns warning message into `warn`, and error message into `err` +/// 'mtl_basedir' is optional, and used for base directory for .mtl file. +/// In default(`NULL'), .mtl file is searched from an application's working +/// directory. +/// 'triangulate' is optional, and used whether triangulate polygon face in .obj +/// or not. +/// Option 'default_vcols_fallback' specifies whether vertex colors should +/// always be defined, even if no colors are given (fallback to white). +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *warn, + std::string *err, const char *filename, + const char *mtl_basedir = NULL, bool triangulate = true, + bool default_vcols_fallback = true); + +/// Loads .obj from a file with custom user callback. +/// .mtl is loaded as usual and parsed material_t data will be passed to +/// `callback.mtllib_cb`. +/// Returns true when loading .obj/.mtl become success. +/// Returns warning message into `warn`, and error message into `err` +/// See `examples/callback_api/` for how to use this function. +bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, + void *user_data = NULL, + MaterialReader *readMatFn = NULL, + std::string *warn = NULL, std::string *err = NULL); + +/// Loads object from a std::istream, uses `readMatFn` to retrieve +/// std::istream for materials. +/// Returns true when loading .obj become success. +/// Returns warning and error message into `err` +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *warn, + std::string *err, std::istream *inStream, + MaterialReader *readMatFn = NULL, bool triangulate = true, + bool default_vcols_fallback = true); + +/// Loads materials into std::map +void LoadMtl(std::map *material_map, + std::vector *materials, std::istream *inStream, + std::string *warning, std::string *err); + +/// +/// Parse texture name and texture option for custom texture parameter through +/// material::unknown_parameter +/// +/// @param[out] texname Parsed texture name +/// @param[out] texopt Parsed texopt +/// @param[in] linebuf Input string +/// +bool ParseTextureNameAndOption(std::string *texname, texture_option_t *texopt, + const char *linebuf); + +/// =<<========== Legacy v1 API ============================================= + +} // namespace tinyobj + +#endif // TINY_OBJ_LOADER_H_ + +#ifdef TINYOBJLOADER_IMPLEMENTATION +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace tinyobj { + +MaterialReader::~MaterialReader() {} + +struct vertex_index_t { + int v_idx, vt_idx, vn_idx; + vertex_index_t() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} + explicit vertex_index_t(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {} + vertex_index_t(int vidx, int vtidx, int vnidx) + : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {} +}; + +// Internal data structure for face representation +// index + smoothing group. +struct face_t { + unsigned int + smoothing_group_id; // smoothing group id. 0 = smoothing groupd is off. + int pad_; + std::vector vertex_indices; // face vertex indices. + + face_t() : smoothing_group_id(0), pad_(0) {} +}; + +// Internal data structure for line representation +struct __line_t { + // l v1/vt1 v2/vt2 ... + // In the specification, line primitrive does not have normal index, but + // TinyObjLoader allow it + std::vector vertex_indices; +}; + +// Internal data structure for points representation +struct __points_t { + // p v1 v2 ... + // In the specification, point primitrive does not have normal index and + // texture coord index, but TinyObjLoader allow it. + std::vector vertex_indices; +}; + +struct tag_sizes { + tag_sizes() : num_ints(0), num_reals(0), num_strings(0) {} + int num_ints; + int num_reals; + int num_strings; +}; + +struct obj_shape { + std::vector v; + std::vector vn; + std::vector vt; +}; + +// +// Manages group of primitives(face, line, points, ...) +struct PrimGroup { + std::vector faceGroup; + std::vector<__line_t> lineGroup; + std::vector<__points_t> pointsGroup; + + void clear() { + faceGroup.clear(); + lineGroup.clear(); + pointsGroup.clear(); + } + + bool IsEmpty() const { + return faceGroup.empty() && lineGroup.empty() && pointsGroup.empty(); + } + + // TODO(syoyo): bspline, surface, ... +}; + +// See +// http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf +static std::istream &safeGetline(std::istream &is, std::string &t) { + t.clear(); + + // The characters in the stream are read one-by-one using a std::streambuf. + // That is faster than reading them one-by-one using the std::istream. + // Code that uses streambuf this way must be guarded by a sentry object. + // The sentry object performs various tasks, + // such as thread synchronization and updating the stream state. + + std::istream::sentry se(is, true); + std::streambuf *sb = is.rdbuf(); + + if (se) { + for (;;) { + int c = sb->sbumpc(); + switch (c) { + case '\n': + return is; + case '\r': + if (sb->sgetc() == '\n') sb->sbumpc(); + return is; + case EOF: + // Also handle the case when the last line has no line ending + if (t.empty()) is.setstate(std::ios::eofbit); + return is; + default: + t += static_cast(c); + } + } + } + + return is; +} + +#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) +#define IS_DIGIT(x) \ + (static_cast((x) - '0') < static_cast(10)) +#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) + +// Make index zero-base, and also support relative index. +static inline bool fixIndex(int idx, int n, int *ret) { + if (!ret) { + return false; + } + + if (idx > 0) { + (*ret) = idx - 1; + return true; + } + + if (idx == 0) { + // zero is not allowed according to the spec. + return false; + } + + if (idx < 0) { + (*ret) = n + idx; // negative value = relative + return true; + } + + return false; // never reach here. +} + +static inline std::string parseString(const char **token) { + std::string s; + (*token) += strspn((*token), " \t"); + size_t e = strcspn((*token), " \t\r"); + s = std::string((*token), &(*token)[e]); + (*token) += e; + return s; +} + +static inline int parseInt(const char **token) { + (*token) += strspn((*token), " \t"); + int i = atoi((*token)); + (*token) += strcspn((*token), " \t\r"); + return i; +} + +// Tries to parse a floating point number located at s. +// +// s_end should be a location in the string where reading should absolutely +// stop. For example at the end of the string, to prevent buffer overflows. +// +// Parses the following EBNF grammar: +// sign = "+" | "-" ; +// END = ? anything not in digit ? +// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; +// integer = [sign] , digit , {digit} ; +// decimal = integer , ["." , integer] ; +// float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; +// +// Valid strings are for example: +// -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 +// +// If the parsing is a success, result is set to the parsed value and true +// is returned. +// +// The function is greedy and will parse until any of the following happens: +// - a non-conforming character is encountered. +// - s_end is reached. +// +// The following situations triggers a failure: +// - s >= s_end. +// - parse failure. +// +static bool tryParseDouble(const char *s, const char *s_end, double *result) { + if (s >= s_end) { + return false; + } + + double mantissa = 0.0; + // This exponent is base 2 rather than 10. + // However the exponent we parse is supposed to be one of ten, + // thus we must take care to convert the exponent/and or the + // mantissa to a * 2^E, where a is the mantissa and E is the + // exponent. + // To get the final double we will use ldexp, it requires the + // exponent to be in base 2. + int exponent = 0; + + // NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED + // TO JUMP OVER DEFINITIONS. + char sign = '+'; + char exp_sign = '+'; + char const *curr = s; + + // How many characters were read in a loop. + int read = 0; + // Tells whether a loop terminated due to reaching s_end. + bool end_not_reached = false; + bool leading_decimal_dots = false; + + /* + BEGIN PARSING. + */ + + // Find out what sign we've got. + if (*curr == '+' || *curr == '-') { + sign = *curr; + curr++; + if ((curr != s_end) && (*curr == '.')) { + // accept. Somethig like `.7e+2`, `-.5234` + leading_decimal_dots = true; + } + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else if (*curr == '.') { + // accept. Somethig like `.7e+2`, `-.5234` + leading_decimal_dots = true; + } else { + goto fail; + } + + // Read the integer part. + end_not_reached = (curr != s_end); + if (!leading_decimal_dots) { + while (end_not_reached && IS_DIGIT(*curr)) { + mantissa *= 10; + mantissa += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + + // We must make sure we actually got something. + if (read == 0) goto fail; + } + + // We allow numbers of form "#", "###" etc. + if (!end_not_reached) goto assemble; + + // Read the decimal part. + if (*curr == '.') { + curr++; + read = 1; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + static const double pow_lut[] = { + 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, + }; + const int lut_entries = sizeof pow_lut / sizeof pow_lut[0]; + + // NOTE: Don't use powf here, it will absolutely murder precision. + mantissa += static_cast(*curr - 0x30) * + (read < lut_entries ? pow_lut[read] : std::pow(10.0, -read)); + read++; + curr++; + end_not_reached = (curr != s_end); + } + } else if (*curr == 'e' || *curr == 'E') { + } else { + goto assemble; + } + + if (!end_not_reached) goto assemble; + + // Read the exponent part. + if (*curr == 'e' || *curr == 'E') { + curr++; + // Figure out if a sign is present and if it is. + end_not_reached = (curr != s_end); + if (end_not_reached && (*curr == '+' || *curr == '-')) { + exp_sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + // Empty E is not allowed. + goto fail; + } + + read = 0; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + exponent *= 10; + exponent += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + exponent *= (exp_sign == '+' ? 1 : -1); + if (read == 0) goto fail; + } + +assemble: + *result = (sign == '+' ? 1 : -1) * + (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent) + : mantissa); + return true; +fail: + return false; +} + +static inline real_t parseReal(const char **token, double default_value = 0.0) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + double val = default_value; + tryParseDouble((*token), end, &val); + real_t f = static_cast(val); + (*token) = end; + return f; +} + +static inline bool parseReal(const char **token, real_t *out) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + double val; + bool ret = tryParseDouble((*token), end, &val); + if (ret) { + real_t f = static_cast(val); + (*out) = f; + } + (*token) = end; + return ret; +} + +static inline void parseReal2(real_t *x, real_t *y, const char **token, + const double default_x = 0.0, + const double default_y = 0.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); +} + +static inline void parseReal3(real_t *x, real_t *y, real_t *z, + const char **token, const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); + (*z) = parseReal(token, default_z); +} + +static inline void parseV(real_t *x, real_t *y, real_t *z, real_t *w, + const char **token, const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0, + const double default_w = 1.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); + (*z) = parseReal(token, default_z); + (*w) = parseReal(token, default_w); +} + +// Extension: parse vertex with colors(6 items) +static inline bool parseVertexWithColor(real_t *x, real_t *y, real_t *z, + real_t *r, real_t *g, real_t *b, + const char **token, + const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); + (*z) = parseReal(token, default_z); + + const bool found_color = + parseReal(token, r) && parseReal(token, g) && parseReal(token, b); + + if (!found_color) { + (*r) = (*g) = (*b) = 1.0; + } + + return found_color; +} + +static inline bool parseOnOff(const char **token, bool default_value = true) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + + bool ret = default_value; + if ((0 == strncmp((*token), "on", 2))) { + ret = true; + } else if ((0 == strncmp((*token), "off", 3))) { + ret = false; + } + + (*token) = end; + return ret; +} + +static inline texture_type_t parseTextureType( + const char **token, texture_type_t default_value = TEXTURE_TYPE_NONE) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + texture_type_t ty = default_value; + + if ((0 == strncmp((*token), "cube_top", strlen("cube_top")))) { + ty = TEXTURE_TYPE_CUBE_TOP; + } else if ((0 == strncmp((*token), "cube_bottom", strlen("cube_bottom")))) { + ty = TEXTURE_TYPE_CUBE_BOTTOM; + } else if ((0 == strncmp((*token), "cube_left", strlen("cube_left")))) { + ty = TEXTURE_TYPE_CUBE_LEFT; + } else if ((0 == strncmp((*token), "cube_right", strlen("cube_right")))) { + ty = TEXTURE_TYPE_CUBE_RIGHT; + } else if ((0 == strncmp((*token), "cube_front", strlen("cube_front")))) { + ty = TEXTURE_TYPE_CUBE_FRONT; + } else if ((0 == strncmp((*token), "cube_back", strlen("cube_back")))) { + ty = TEXTURE_TYPE_CUBE_BACK; + } else if ((0 == strncmp((*token), "sphere", strlen("sphere")))) { + ty = TEXTURE_TYPE_SPHERE; + } + + (*token) = end; + return ty; +} + +static tag_sizes parseTagTriple(const char **token) { + tag_sizes ts; + + (*token) += strspn((*token), " \t"); + ts.num_ints = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + + (*token)++; // Skip '/' + + (*token) += strspn((*token), " \t"); + ts.num_reals = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + (*token)++; // Skip '/' + + ts.num_strings = parseInt(token); + + return ts; +} + +// Parse triples with index offsets: i, i/j/k, i//k, i/j +static bool parseTriple(const char **token, int vsize, int vnsize, int vtsize, + vertex_index_t *ret) { + if (!ret) { + return false; + } + + vertex_index_t vi(-1); + + if (!fixIndex(atoi((*token)), vsize, &(vi.v_idx))) { + return false; + } + + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + (*ret) = vi; + return true; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { + return false; + } + (*token) += strcspn((*token), "/ \t\r"); + (*ret) = vi; + return true; + } + + // i/j/k or i/j + if (!fixIndex(atoi((*token)), vtsize, &(vi.vt_idx))) { + return false; + } + + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + (*ret) = vi; + return true; + } + + // i/j/k + (*token)++; // skip '/' + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { + return false; + } + (*token) += strcspn((*token), "/ \t\r"); + + (*ret) = vi; + + return true; +} + +// Parse raw triples: i, i/j/k, i//k, i/j +static vertex_index_t parseRawTriple(const char **token) { + vertex_index_t vi(static_cast(0)); // 0 is an invalid index in OBJ + + vi.v_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; + } + + // i/j/k or i/j + vi.vt_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + + // i/j/k + (*token)++; // skip '/' + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; +} + +bool ParseTextureNameAndOption(std::string *texname, texture_option_t *texopt, + const char *linebuf) { + // @todo { write more robust lexer and parser. } + bool found_texname = false; + std::string texture_name; + + const char *token = linebuf; // Assume line ends with NULL + + while (!IS_NEW_LINE((*token))) { + token += strspn(token, " \t"); // skip space + if ((0 == strncmp(token, "-blendu", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendu = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-blendv", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendv = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-clamp", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->clamp = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-boost", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->sharpness = parseReal(&token, 1.0); + } else if ((0 == strncmp(token, "-bm", 3)) && IS_SPACE((token[3]))) { + token += 4; + texopt->bump_multiplier = parseReal(&token, 1.0); + } else if ((0 == strncmp(token, "-o", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseReal3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]), + &(texopt->origin_offset[2]), &token); + } else if ((0 == strncmp(token, "-s", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseReal3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]), + &token, 1.0, 1.0, 1.0); + } else if ((0 == strncmp(token, "-t", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseReal3(&(texopt->turbulence[0]), &(texopt->turbulence[1]), + &(texopt->turbulence[2]), &token); + } else if ((0 == strncmp(token, "-type", 5)) && IS_SPACE((token[5]))) { + token += 5; + texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE); + } else if ((0 == strncmp(token, "-texres", 7)) && IS_SPACE((token[7]))) { + token += 7; + // TODO(syoyo): Check if arg is int type. + texopt->texture_resolution = parseInt(&token); + } else if ((0 == strncmp(token, "-imfchan", 8)) && IS_SPACE((token[8]))) { + token += 9; + token += strspn(token, " \t"); + const char *end = token + strcspn(token, " \t\r"); + if ((end - token) == 1) { // Assume one char for -imfchan + texopt->imfchan = (*token); + } + token = end; + } else if ((0 == strncmp(token, "-mm", 3)) && IS_SPACE((token[3]))) { + token += 4; + parseReal2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0); + } else if ((0 == strncmp(token, "-colorspace", 11)) && + IS_SPACE((token[11]))) { + token += 12; + texopt->colorspace = parseString(&token); + } else { +// Assume texture filename +#if 0 + size_t len = strcspn(token, " \t\r"); // untile next space + texture_name = std::string(token, token + len); + token += len; + + token += strspn(token, " \t"); // skip space +#else + // Read filename until line end to parse filename containing whitespace + // TODO(syoyo): Support parsing texture option flag after the filename. + texture_name = std::string(token); + token += texture_name.length(); +#endif + + found_texname = true; + } + } + + if (found_texname) { + (*texname) = texture_name; + return true; + } else { + return false; + } +} + +static void InitTexOpt(texture_option_t *texopt, const bool is_bump) { + if (is_bump) { + texopt->imfchan = 'l'; + } else { + texopt->imfchan = 'm'; + } + texopt->bump_multiplier = static_cast(1.0); + texopt->clamp = false; + texopt->blendu = true; + texopt->blendv = true; + texopt->sharpness = static_cast(1.0); + texopt->brightness = static_cast(0.0); + texopt->contrast = static_cast(1.0); + texopt->origin_offset[0] = static_cast(0.0); + texopt->origin_offset[1] = static_cast(0.0); + texopt->origin_offset[2] = static_cast(0.0); + texopt->scale[0] = static_cast(1.0); + texopt->scale[1] = static_cast(1.0); + texopt->scale[2] = static_cast(1.0); + texopt->turbulence[0] = static_cast(0.0); + texopt->turbulence[1] = static_cast(0.0); + texopt->turbulence[2] = static_cast(0.0); + texopt->texture_resolution = -1; + texopt->type = TEXTURE_TYPE_NONE; +} + +static void InitMaterial(material_t *material) { + InitTexOpt(&material->ambient_texopt, /* is_bump */ false); + InitTexOpt(&material->diffuse_texopt, /* is_bump */ false); + InitTexOpt(&material->specular_texopt, /* is_bump */ false); + InitTexOpt(&material->specular_highlight_texopt, /* is_bump */ false); + InitTexOpt(&material->bump_texopt, /* is_bump */ true); + InitTexOpt(&material->displacement_texopt, /* is_bump */ false); + InitTexOpt(&material->alpha_texopt, /* is_bump */ false); + InitTexOpt(&material->reflection_texopt, /* is_bump */ false); + InitTexOpt(&material->roughness_texopt, /* is_bump */ false); + InitTexOpt(&material->metallic_texopt, /* is_bump */ false); + InitTexOpt(&material->sheen_texopt, /* is_bump */ false); + InitTexOpt(&material->emissive_texopt, /* is_bump */ false); + InitTexOpt(&material->normal_texopt, + /* is_bump */ false); // @fixme { is_bump will be true? } + material->name = ""; + material->ambient_texname = ""; + material->diffuse_texname = ""; + material->specular_texname = ""; + material->specular_highlight_texname = ""; + material->bump_texname = ""; + material->displacement_texname = ""; + material->reflection_texname = ""; + material->alpha_texname = ""; + for (int i = 0; i < 3; i++) { + material->ambient[i] = static_cast(0.0); + material->diffuse[i] = static_cast(0.0); + material->specular[i] = static_cast(0.0); + material->transmittance[i] = static_cast(0.0); + material->emission[i] = static_cast(0.0); + } + material->illum = 0; + material->dissolve = static_cast(1.0); + material->shininess = static_cast(1.0); + material->ior = static_cast(1.0); + + material->roughness = static_cast(0.0); + material->metallic = static_cast(0.0); + material->sheen = static_cast(0.0); + material->clearcoat_thickness = static_cast(0.0); + material->clearcoat_roughness = static_cast(0.0); + material->anisotropy_rotation = static_cast(0.0); + material->anisotropy = static_cast(0.0); + material->roughness_texname = ""; + material->metallic_texname = ""; + material->sheen_texname = ""; + material->emissive_texname = ""; + material->normal_texname = ""; + + material->unknown_parameter.clear(); +} + +// code from https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html +template +static int pnpoly(int nvert, T *vertx, T *verty, T testx, T testy) { + int i, j, c = 0; + for (i = 0, j = nvert - 1; i < nvert; j = i++) { + if (((verty[i] > testy) != (verty[j] > testy)) && + (testx < + (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + + vertx[i])) + c = !c; + } + return c; +} + +// TODO(syoyo): refactor function. +static bool exportGroupsToShape(shape_t *shape, const PrimGroup &prim_group, + const std::vector &tags, + const int material_id, const std::string &name, + bool triangulate, + const std::vector &v) { + if (prim_group.IsEmpty()) { + return false; + } + + shape->name = name; + + // polygon + if (!prim_group.faceGroup.empty()) { + // Flatten vertices and indices + for (size_t i = 0; i < prim_group.faceGroup.size(); i++) { + const face_t &face = prim_group.faceGroup[i]; + + size_t npolys = face.vertex_indices.size(); + + if (npolys < 3) { + // Face must have 3+ vertices. + continue; + } + + vertex_index_t i0 = face.vertex_indices[0]; + vertex_index_t i1(-1); + vertex_index_t i2 = face.vertex_indices[1]; + + if (triangulate) { + // find the two axes to work in + size_t axes[2] = {1, 2}; + for (size_t k = 0; k < npolys; ++k) { + i0 = face.vertex_indices[(k + 0) % npolys]; + i1 = face.vertex_indices[(k + 1) % npolys]; + i2 = face.vertex_indices[(k + 2) % npolys]; + size_t vi0 = size_t(i0.v_idx); + size_t vi1 = size_t(i1.v_idx); + size_t vi2 = size_t(i2.v_idx); + + if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) || + ((3 * vi2 + 2) >= v.size())) { + // Invalid triangle. + // FIXME(syoyo): Is it ok to simply skip this invalid triangle? + continue; + } + real_t v0x = v[vi0 * 3 + 0]; + real_t v0y = v[vi0 * 3 + 1]; + real_t v0z = v[vi0 * 3 + 2]; + real_t v1x = v[vi1 * 3 + 0]; + real_t v1y = v[vi1 * 3 + 1]; + real_t v1z = v[vi1 * 3 + 2]; + real_t v2x = v[vi2 * 3 + 0]; + real_t v2y = v[vi2 * 3 + 1]; + real_t v2z = v[vi2 * 3 + 2]; + real_t e0x = v1x - v0x; + real_t e0y = v1y - v0y; + real_t e0z = v1z - v0z; + real_t e1x = v2x - v1x; + real_t e1y = v2y - v1y; + real_t e1z = v2z - v1z; + real_t cx = std::fabs(e0y * e1z - e0z * e1y); + real_t cy = std::fabs(e0z * e1x - e0x * e1z); + real_t cz = std::fabs(e0x * e1y - e0y * e1x); + const real_t epsilon = std::numeric_limits::epsilon(); + if (cx > epsilon || cy > epsilon || cz > epsilon) { + // found a corner + if (cx > cy && cx > cz) { + } else { + axes[0] = 0; + if (cz > cx && cz > cy) axes[1] = 1; + } + break; + } + } + + real_t area = 0; + for (size_t k = 0; k < npolys; ++k) { + i0 = face.vertex_indices[(k + 0) % npolys]; + i1 = face.vertex_indices[(k + 1) % npolys]; + size_t vi0 = size_t(i0.v_idx); + size_t vi1 = size_t(i1.v_idx); + if (((vi0 * 3 + axes[0]) >= v.size()) || + ((vi0 * 3 + axes[1]) >= v.size()) || + ((vi1 * 3 + axes[0]) >= v.size()) || + ((vi1 * 3 + axes[1]) >= v.size())) { + // Invalid index. + continue; + } + real_t v0x = v[vi0 * 3 + axes[0]]; + real_t v0y = v[vi0 * 3 + axes[1]]; + real_t v1x = v[vi1 * 3 + axes[0]]; + real_t v1y = v[vi1 * 3 + axes[1]]; + area += (v0x * v1y - v0y * v1x) * static_cast(0.5); + } + + face_t remainingFace = face; // copy + size_t guess_vert = 0; + vertex_index_t ind[3]; + real_t vx[3]; + real_t vy[3]; + + // How many iterations can we do without decreasing the remaining + // vertices. + size_t remainingIterations = face.vertex_indices.size(); + size_t previousRemainingVertices = remainingFace.vertex_indices.size(); + + while (remainingFace.vertex_indices.size() > 3 && + remainingIterations > 0) { + npolys = remainingFace.vertex_indices.size(); + if (guess_vert >= npolys) { + guess_vert -= npolys; + } + + if (previousRemainingVertices != npolys) { + // The number of remaining vertices decreased. Reset counters. + previousRemainingVertices = npolys; + remainingIterations = npolys; + } else { + // We didn't consume a vertex on previous iteration, reduce the + // available iterations. + remainingIterations--; + } + + for (size_t k = 0; k < 3; k++) { + ind[k] = remainingFace.vertex_indices[(guess_vert + k) % npolys]; + size_t vi = size_t(ind[k].v_idx); + if (((vi * 3 + axes[0]) >= v.size()) || + ((vi * 3 + axes[1]) >= v.size())) { + // ??? + vx[k] = static_cast(0.0); + vy[k] = static_cast(0.0); + } else { + vx[k] = v[vi * 3 + axes[0]]; + vy[k] = v[vi * 3 + axes[1]]; + } + } + real_t e0x = vx[1] - vx[0]; + real_t e0y = vy[1] - vy[0]; + real_t e1x = vx[2] - vx[1]; + real_t e1y = vy[2] - vy[1]; + real_t cross = e0x * e1y - e0y * e1x; + // if an internal angle + if (cross * area < static_cast(0.0)) { + guess_vert += 1; + continue; + } + + // check all other verts in case they are inside this triangle + bool overlap = false; + for (size_t otherVert = 3; otherVert < npolys; ++otherVert) { + size_t idx = (guess_vert + otherVert) % npolys; + + if (idx >= remainingFace.vertex_indices.size()) { + // ??? + continue; + } + + size_t ovi = size_t(remainingFace.vertex_indices[idx].v_idx); + + if (((ovi * 3 + axes[0]) >= v.size()) || + ((ovi * 3 + axes[1]) >= v.size())) { + // ??? + continue; + } + real_t tx = v[ovi * 3 + axes[0]]; + real_t ty = v[ovi * 3 + axes[1]]; + if (pnpoly(3, vx, vy, tx, ty)) { + overlap = true; + break; + } + } + + if (overlap) { + guess_vert += 1; + continue; + } + + // this triangle is an ear + { + index_t idx0, idx1, idx2; + idx0.vertex_index = ind[0].v_idx; + idx0.normal_index = ind[0].vn_idx; + idx0.texcoord_index = ind[0].vt_idx; + idx1.vertex_index = ind[1].v_idx; + idx1.normal_index = ind[1].vn_idx; + idx1.texcoord_index = ind[1].vt_idx; + idx2.vertex_index = ind[2].v_idx; + idx2.normal_index = ind[2].vn_idx; + idx2.texcoord_index = ind[2].vt_idx; + + shape->mesh.vertex_indices.push_back( idx0.vertex_index ); + shape->mesh.vertex_indices.push_back( idx1.vertex_index ); + shape->mesh.vertex_indices.push_back( idx2.vertex_index ); + + shape->mesh.normal_indices.push_back( idx0.normal_index ); + shape->mesh.normal_indices.push_back( idx1.normal_index ); + shape->mesh.normal_indices.push_back( idx2.normal_index ); + + shape->mesh.texcoord_indices.push_back( idx0.texcoord_index ); + shape->mesh.texcoord_indices.push_back( idx1.texcoord_index ); + shape->mesh.texcoord_indices.push_back( idx2.texcoord_index ); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); + } + + // remove v1 from the list + size_t removed_vert_index = (guess_vert + 1) % npolys; + while (removed_vert_index + 1 < npolys) { + remainingFace.vertex_indices[removed_vert_index] = + remainingFace.vertex_indices[removed_vert_index + 1]; + removed_vert_index += 1; + } + remainingFace.vertex_indices.pop_back(); + } + + if (remainingFace.vertex_indices.size() == 3) { + i0 = remainingFace.vertex_indices[0]; + i1 = remainingFace.vertex_indices[1]; + i2 = remainingFace.vertex_indices[2]; + { + index_t idx0, idx1, idx2; + idx0.vertex_index = i0.v_idx; + idx0.normal_index = i0.vn_idx; + idx0.texcoord_index = i0.vt_idx; + idx1.vertex_index = i1.v_idx; + idx1.normal_index = i1.vn_idx; + idx1.texcoord_index = i1.vt_idx; + idx2.vertex_index = i2.v_idx; + idx2.normal_index = i2.vn_idx; + idx2.texcoord_index = i2.vt_idx; + + shape->mesh.vertex_indices.push_back( idx0.vertex_index ); + shape->mesh.vertex_indices.push_back( idx1.vertex_index ); + shape->mesh.vertex_indices.push_back( idx2.vertex_index ); + + shape->mesh.normal_indices.push_back( idx0.normal_index ); + shape->mesh.normal_indices.push_back( idx1.normal_index ); + shape->mesh.normal_indices.push_back( idx2.normal_index ); + + shape->mesh.texcoord_indices.push_back( idx0.texcoord_index ); + shape->mesh.texcoord_indices.push_back( idx1.texcoord_index ); + shape->mesh.texcoord_indices.push_back( idx2.texcoord_index ); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); + } + } + } else { + for (size_t k = 0; k < npolys; k++) { + index_t idx; + idx.vertex_index = face.vertex_indices[k].v_idx; + idx.normal_index = face.vertex_indices[k].vn_idx; + idx.texcoord_index = face.vertex_indices[k].vt_idx; + + shape->mesh.vertex_indices.push_back( idx.vertex_index ); + shape->mesh.normal_indices.push_back( idx.normal_index ); + shape->mesh.texcoord_indices.push_back( idx.texcoord_index ); + } + + shape->mesh.num_face_vertices.push_back( + static_cast(npolys)); + shape->mesh.material_ids.push_back(material_id); // per face + shape->mesh.smoothing_group_ids.push_back( + face.smoothing_group_id); // per face + } + } + + shape->mesh.tags = tags; + } + + // line + if (!prim_group.lineGroup.empty()) { + // Flatten indices + for (size_t i = 0; i < prim_group.lineGroup.size(); i++) { + for (size_t j = 0; j < prim_group.lineGroup[i].vertex_indices.size(); + j++) { + const vertex_index_t &vi = prim_group.lineGroup[i].vertex_indices[j]; + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + shape->lines.indices.push_back(idx); + } + + shape->lines.num_line_vertices.push_back( + int(prim_group.lineGroup[i].vertex_indices.size())); + } + } + + // points + if (!prim_group.pointsGroup.empty()) { + // Flatten & convert indices + for (size_t i = 0; i < prim_group.pointsGroup.size(); i++) { + for (size_t j = 0; j < prim_group.pointsGroup[i].vertex_indices.size(); + j++) { + const vertex_index_t &vi = prim_group.pointsGroup[i].vertex_indices[j]; + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + shape->points.indices.push_back(idx); + } + } + } + + return true; +} + +// Split a string with specified delimiter character. +// http://stackoverflow.com/questions/236129/split-a-string-in-c +static void SplitString(const std::string &s, char delim, + std::vector &elems) { + std::stringstream ss; + ss.str(s); + std::string item; + while (std::getline(ss, item, delim)) { + elems.push_back(item); + } +} + +static std::string JoinPath(const std::string &dir, + const std::string &filename) { + if (dir.empty()) { + return filename; + } else { + // check '/' + char lastChar = *dir.rbegin(); + if (lastChar != '/') { + return dir + std::string("/") + filename; + } else { + return dir + filename; + } + } +} + +void LoadMtl(std::map *material_map, + std::vector *materials, std::istream *inStream, + std::string *warning, std::string *err) { + (void)err; + + // Create a default material anyway. + material_t material; + InitMaterial(&material); + + // Issue 43. `d` wins against `Tr` since `Tr` is not in the MTL specification. + bool has_d = false; + bool has_tr = false; + + // has_kd is used to set a default diffuse value when map_Kd is present + // and Kd is not. + bool has_kd = false; + + std::stringstream warn_ss; + + size_t line_no = 0; + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + line_no++; + + // Trim trailing whitespace. + if (linebuf.size() > 0) { + linebuf = linebuf.substr(0, linebuf.find_last_not_of(" \t") + 1); + } + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // new mtl + if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) { + // flush previous material. + if (!material.name.empty()) { + material_map->insert(std::pair( + material.name, static_cast(materials->size()))); + materials->push_back(material); + } + + // initial temporary material + InitMaterial(&material); + + has_d = false; + has_tr = false; + + // set new mtl name + token += 7; + { + std::stringstream sstr; + sstr << token; + material.name = sstr.str(); + } + continue; + } + + // ambient + if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.ambient[0] = r; + material.ambient[1] = g; + material.ambient[2] = b; + continue; + } + + // diffuse + if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.diffuse[0] = r; + material.diffuse[1] = g; + material.diffuse[2] = b; + has_kd = true; + continue; + } + + // specular + if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.specular[0] = r; + material.specular[1] = g; + material.specular[2] = b; + continue; + } + + // transmittance + if ((token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) || + (token[0] == 'T' && token[1] == 'f' && IS_SPACE((token[2])))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.transmittance[0] = r; + material.transmittance[1] = g; + material.transmittance[2] = b; + continue; + } + + // ior(index of refraction) + if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) { + token += 2; + material.ior = parseReal(&token); + continue; + } + + // emission + if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.emission[0] = r; + material.emission[1] = g; + material.emission[2] = b; + continue; + } + + // shininess + if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.shininess = parseReal(&token); + continue; + } + + // illum model + if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) { + token += 6; + material.illum = parseInt(&token); + continue; + } + + // dissolve + if ((token[0] == 'd' && IS_SPACE(token[1]))) { + token += 1; + material.dissolve = parseReal(&token); + + if (has_tr) { + warn_ss << "Both `d` and `Tr` parameters defined for \"" + << material.name + << "\". Use the value of `d` for dissolve (line " << line_no + << " in .mtl.)" << std::endl; + } + has_d = true; + continue; + } + if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + if (has_d) { + // `d` wins. Ignore `Tr` value. + warn_ss << "Both `d` and `Tr` parameters defined for \"" + << material.name + << "\". Use the value of `d` for dissolve (line " << line_no + << " in .mtl.)" << std::endl; + } else { + // We invert value of Tr(assume Tr is in range [0, 1]) + // NOTE: Interpretation of Tr is application(exporter) dependent. For + // some application(e.g. 3ds max obj exporter), Tr = d(Issue 43) + material.dissolve = static_cast(1.0) - parseReal(&token); + } + has_tr = true; + continue; + } + + // PBR: roughness + if (token[0] == 'P' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + material.roughness = parseReal(&token); + continue; + } + + // PBR: metallic + if (token[0] == 'P' && token[1] == 'm' && IS_SPACE(token[2])) { + token += 2; + material.metallic = parseReal(&token); + continue; + } + + // PBR: sheen + if (token[0] == 'P' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.sheen = parseReal(&token); + continue; + } + + // PBR: clearcoat thickness + if (token[0] == 'P' && token[1] == 'c' && IS_SPACE(token[2])) { + token += 2; + material.clearcoat_thickness = parseReal(&token); + continue; + } + + // PBR: clearcoat roughness + if ((0 == strncmp(token, "Pcr", 3)) && IS_SPACE(token[3])) { + token += 4; + material.clearcoat_roughness = parseReal(&token); + continue; + } + + // PBR: anisotropy + if ((0 == strncmp(token, "aniso", 5)) && IS_SPACE(token[5])) { + token += 6; + material.anisotropy = parseReal(&token); + continue; + } + + // PBR: anisotropy rotation + if ((0 == strncmp(token, "anisor", 6)) && IS_SPACE(token[6])) { + token += 7; + material.anisotropy_rotation = parseReal(&token); + continue; + } + + // ambient texture + if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.ambient_texname), + &(material.ambient_texopt), token); + continue; + } + + // diffuse texture + if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.diffuse_texname), + &(material.diffuse_texopt), token); + + // Set a decent diffuse default value if a diffuse texture is specified + // without a matching Kd value. + if (!has_kd) + { + material.diffuse[0] = static_cast(0.6); + material.diffuse[1] = static_cast(0.6); + material.diffuse[2] = static_cast(0.6); + } + + continue; + } + + // specular texture + if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_texname), + &(material.specular_texopt), token); + continue; + } + + // specular highlight texture + if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_highlight_texname), + &(material.specular_highlight_texopt), token); + continue; + } + + // bump texture + if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { + token += 9; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token); + continue; + } + + // bump texture + if ((0 == strncmp(token, "map_Bump", 8)) && IS_SPACE(token[8])) { + token += 9; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token); + continue; + } + + // bump texture + if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token); + continue; + } + + // alpha texture + if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) { + token += 6; + material.alpha_texname = token; + ParseTextureNameAndOption(&(material.alpha_texname), + &(material.alpha_texopt), token); + continue; + } + + // displacement texture + if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.displacement_texname), + &(material.displacement_texopt), token); + continue; + } + + // reflection map + if ((0 == strncmp(token, "refl", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.reflection_texname), + &(material.reflection_texopt), token); + continue; + } + + // PBR: roughness texture + if ((0 == strncmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.roughness_texname), + &(material.roughness_texopt), token); + continue; + } + + // PBR: metallic texture + if ((0 == strncmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.metallic_texname), + &(material.metallic_texopt), token); + continue; + } + + // PBR: sheen texture + if ((0 == strncmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.sheen_texname), + &(material.sheen_texopt), token); + continue; + } + + // PBR: emissive texture + if ((0 == strncmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.emissive_texname), + &(material.emissive_texopt), token); + continue; + } + + // PBR: normal map texture + if ((0 == strncmp(token, "norm", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.normal_texname), + &(material.normal_texopt), token); + continue; + } + + // unknown parameter + const char *_space = strchr(token, ' '); + if (!_space) { + _space = strchr(token, '\t'); + } + if (_space) { + std::ptrdiff_t len = _space - token; + std::string key(token, static_cast(len)); + std::string value = _space + 1; + material.unknown_parameter.insert( + std::pair(key, value)); + } + } + // flush last material. + material_map->insert(std::pair( + material.name, static_cast(materials->size()))); + materials->push_back(material); + + if (warning) { + (*warning) = warn_ss.str(); + } +} + +bool MaterialFileReader::operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, + std::string *warn, std::string *err) { + if (!m_mtlBaseDir.empty()) { +#ifdef _WIN32 + char sep = ';'; +#else + char sep = ':'; +#endif + + // https://stackoverflow.com/questions/5167625/splitting-a-c-stdstring-using-tokens-e-g + std::vector paths; + std::istringstream f(m_mtlBaseDir); + + std::string s; + while (getline(f, s, sep)) { + paths.push_back(s); + } + + for (size_t i = 0; i < paths.size(); i++) { + std::string filepath = JoinPath(paths[i], matId); + + std::ifstream matIStream(filepath.c_str()); + if (matIStream) { + LoadMtl(matMap, materials, &matIStream, warn, err); + + return true; + } + } + + std::stringstream ss; + ss << "Material file [ " << matId + << " ] not found in a path : " << m_mtlBaseDir << std::endl; + if (warn) { + (*warn) += ss.str(); + } + return false; + + } else { + std::string filepath = matId; + std::ifstream matIStream(filepath.c_str()); + if (matIStream) { + LoadMtl(matMap, materials, &matIStream, warn, err); + + return true; + } + + std::stringstream ss; + ss << "Material file [ " << filepath + << " ] not found in a path : " << m_mtlBaseDir << std::endl; + if (warn) { + (*warn) += ss.str(); + } + + return false; + } +} + +bool MaterialStreamReader::operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, + std::string *warn, std::string *err) { + (void)err; + (void)matId; + if (!m_inStream) { + std::stringstream ss; + ss << "Material stream in error state. " << std::endl; + if (warn) { + (*warn) += ss.str(); + } + return false; + } + + LoadMtl(matMap, materials, &m_inStream, warn, err); + + return true; +} + +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *warn, + std::string *err, const char *filename, const char *mtl_basedir, + bool trianglulate, bool default_vcols_fallback) { + attrib->vertices.clear(); + attrib->normals.clear(); + attrib->texcoords.clear(); + attrib->colors.clear(); + shapes->clear(); + + std::stringstream errss; + + std::ifstream ifs(filename); + if (!ifs) { + errss << "Cannot open file [" << filename << "]" << std::endl; + if (err) { + (*err) = errss.str(); + } + return false; + } + + std::string baseDir = mtl_basedir ? mtl_basedir : ""; + if (!baseDir.empty()) { +#ifndef _WIN32 + const char dirsep = '/'; +#else + const char dirsep = '\\'; +#endif + if (baseDir[baseDir.length() - 1] != dirsep) baseDir += dirsep; + } + MaterialFileReader matFileReader(baseDir); + + return LoadObj(attrib, shapes, materials, warn, err, &ifs, &matFileReader, + trianglulate, default_vcols_fallback); +} + +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *warn, + std::string *err, std::istream *inStream, + MaterialReader *readMatFn /*= NULL*/, bool triangulate, + bool default_vcols_fallback) { + std::stringstream errss; + + std::vector v; + std::vector vn; + std::vector vt; + std::vector vc; + std::vector tags; + PrimGroup prim_group; + std::string name; + + // material + std::map material_map; + int material = -1; + + // smoothing group id + unsigned int current_smoothing_id = + 0; // Initial value. 0 means no smoothing. + + int greatest_v_idx = -1; + int greatest_vn_idx = -1; + int greatest_vt_idx = -1; + + shape_t shape; + + bool found_all_colors = true; + + size_t line_num = 0; + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + + line_num++; + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + real_t x, y, z; + real_t r, g, b; + + found_all_colors &= parseVertexWithColor(&x, &y, &z, &r, &g, &b, &token); + + v.push_back(x); + v.push_back(y); + v.push_back(z); + + if (found_all_colors || default_vcols_fallback) { + vc.push_back(r); + vc.push_back(g); + vc.push_back(b); + } + + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y, z; + parseReal3(&x, &y, &z, &token); + vn.push_back(x); + vn.push_back(y); + vn.push_back(z); + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y; + parseReal2(&x, &y, &token); + vt.push_back(x); + vt.push_back(y); + continue; + } + + // line + if (token[0] == 'l' && IS_SPACE((token[1]))) { + token += 2; + + __line_t line; + + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi; + if (!parseTriple(&token, static_cast(v.size() / 3), + static_cast(vn.size() / 3), + static_cast(vt.size() / 2), &vi)) { + if (err) { + std::stringstream ss; + ss << "Failed parse `l' line(e.g. zero value for vertex index. " + "line " + << line_num << ".)\n"; + (*err) += ss.str(); + } + return false; + } + + line.vertex_indices.push_back(vi); + + size_t n = strspn(token, " \t\r"); + token += n; + } + + prim_group.lineGroup.push_back(line); + + continue; + } + + // points + if (token[0] == 'p' && IS_SPACE((token[1]))) { + token += 2; + + __points_t pts; + + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi; + if (!parseTriple(&token, static_cast(v.size() / 3), + static_cast(vn.size() / 3), + static_cast(vt.size() / 2), &vi)) { + if (err) { + std::stringstream ss; + ss << "Failed parse `p' line(e.g. zero value for vertex index. " + "line " + << line_num << ".)\n"; + (*err) += ss.str(); + } + return false; + } + + pts.vertex_indices.push_back(vi); + + size_t n = strspn(token, " \t\r"); + token += n; + } + + prim_group.pointsGroup.push_back(pts); + + continue; + } + + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + face_t face; + + face.smoothing_group_id = current_smoothing_id; + face.vertex_indices.reserve(3); + + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi; + if (!parseTriple(&token, static_cast(v.size() / 3), + static_cast(vn.size() / 3), + static_cast(vt.size() / 2), &vi)) { + if (err) { + std::stringstream ss; + ss << "Failed parse `f' line(e.g. zero value for face index. line " + << line_num << ".)\n"; + (*err) += ss.str(); + } + return false; + } + + greatest_v_idx = greatest_v_idx > vi.v_idx ? greatest_v_idx : vi.v_idx; + greatest_vn_idx = + greatest_vn_idx > vi.vn_idx ? greatest_vn_idx : vi.vn_idx; + greatest_vt_idx = + greatest_vt_idx > vi.vt_idx ? greatest_vt_idx : vi.vt_idx; + + face.vertex_indices.push_back(vi); + size_t n = strspn(token, " \t\r"); + token += n; + } + + // replace with emplace_back + std::move on C++11 + prim_group.faceGroup.push_back(face); + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6))) { + token += 6; + std::string namebuf = parseString(&token); + + int newMaterialId = -1; + std::map::const_iterator it = material_map.find(namebuf); + if (it != material_map.end()) { + newMaterialId = it->second; + } else { + // { error!! material not found } + if (warn) { + (*warn) += "material [ '" + namebuf + "' ] not found in .mtl\n"; + } + } + + if (newMaterialId != material) { + // Create per-face material. Thus we don't add `shape` to `shapes` at + // this time. + // just clear `faceGroup` after `exportGroupsToShape()` call. + exportGroupsToShape(&shape, prim_group, tags, material, name, + triangulate, v); + prim_group.faceGroup.clear(); + material = newMaterialId; + } + + continue; + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + token += 7; + + std::vector filenames; + SplitString(std::string(token), ' ', filenames); + + if (filenames.empty()) { + if (warn) { + std::stringstream ss; + ss << "Looks like empty filename for mtllib. Use default " + "material (line " + << line_num << ".)\n"; + + (*warn) += ss.str(); + } + } else { + bool found = false; + for (size_t s = 0; s < filenames.size(); s++) { + std::string warn_mtl; + std::string err_mtl; + bool ok = (*readMatFn)(filenames[s].c_str(), materials, + &material_map, &warn_mtl, &err_mtl); + if (warn && (!warn_mtl.empty())) { + (*warn) += warn_mtl; + } + + if (err && (!err_mtl.empty())) { + (*err) += err_mtl; + } + + if (ok) { + found = true; + break; + } + } + + if (!found) { + if (warn) { + (*warn) += + "Failed to load material file(s). Use default " + "material.\n"; + } + } + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name, + triangulate, v); + (void)ret; // return value not used. + + if (shape.mesh.vertex_indices.size() > 0) { + shapes->push_back(shape); + } + + shape = shape_t(); + + // material = -1; + prim_group.clear(); + + std::vector names; + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + // names[0] must be 'g' + + if (names.size() < 2) { + // 'g' with empty names + if (warn) { + std::stringstream ss; + ss << "Empty group name. line: " << line_num << "\n"; + (*warn) += ss.str(); + name = ""; + } + } else { + std::stringstream ss; + ss << names[1]; + + // tinyobjloader does not support multiple groups for a primitive. + // Currently we concatinate multiple group names with a space to get + // single group name. + + for (size_t i = 2; i < names.size(); i++) { + ss << " " << names[i]; + } + + name = ss.str(); + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name, + triangulate, v); + (void)ret; // return value not used. + + if (shape.mesh.vertex_indices.size() > 0 || shape.lines.indices.size() > 0 || + shape.points.indices.size() > 0) { + shapes->push_back(shape); + } + + // material = -1; + prim_group.clear(); + shape = shape_t(); + + // @todo { multiple object name? } + token += 2; + std::stringstream ss; + ss << token; + name = ss.str(); + + continue; + } + + if (token[0] == 't' && IS_SPACE(token[1])) { + const int max_tag_nums = 8192; // FIXME(syoyo): Parameterize. + tag_t tag; + + token += 2; + + tag.name = parseString(&token); + + tag_sizes ts = parseTagTriple(&token); + + if (ts.num_ints < 0) { + ts.num_ints = 0; + } + if (ts.num_ints > max_tag_nums) { + ts.num_ints = max_tag_nums; + } + + if (ts.num_reals < 0) { + ts.num_reals = 0; + } + if (ts.num_reals > max_tag_nums) { + ts.num_reals = max_tag_nums; + } + + if (ts.num_strings < 0) { + ts.num_strings = 0; + } + if (ts.num_strings > max_tag_nums) { + ts.num_strings = max_tag_nums; + } + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = parseInt(&token); + } + + tag.floatValues.resize(static_cast(ts.num_reals)); + for (size_t i = 0; i < static_cast(ts.num_reals); ++i) { + tag.floatValues[i] = parseReal(&token); + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + tag.stringValues[i] = parseString(&token); + } + + tags.push_back(tag); + + continue; + } + + if (token[0] == 's' && IS_SPACE(token[1])) { + // smoothing group id + token += 2; + + // skip space. + token += strspn(token, " \t"); // skip space + + if (token[0] == '\0') { + continue; + } + + if (token[0] == '\r' || token[1] == '\n') { + continue; + } + + if (strlen(token) >= 3 && token[0] == 'o' && token[1] == 'f' && + token[2] == 'f') { + current_smoothing_id = 0; + } else { + // assume number + int smGroupId = parseInt(&token); + if (smGroupId < 0) { + // parse error. force set to 0. + // FIXME(syoyo): Report warning. + current_smoothing_id = 0; + } else { + current_smoothing_id = static_cast(smGroupId); + } + } + + continue; + } // smoothing group id + + // Ignore unknown command. + } + + // not all vertices have colors, no default colors desired? -> clear colors + if (!found_all_colors && !default_vcols_fallback) { + vc.clear(); + } + + if (greatest_v_idx >= static_cast(v.size() / 3)) { + if (warn) { + std::stringstream ss; + ss << "Vertex indices out of bounds (line " << line_num << ".)\n" + << std::endl; + (*warn) += ss.str(); + } + } + if (greatest_vn_idx >= static_cast(vn.size() / 3)) { + if (warn) { + std::stringstream ss; + ss << "Vertex normal indices out of bounds (line " << line_num << ".)\n" + << std::endl; + (*warn) += ss.str(); + } + } + if (greatest_vt_idx >= static_cast(vt.size() / 2)) { + if (warn) { + std::stringstream ss; + ss << "Vertex texcoord indices out of bounds (line " << line_num << ".)\n" + << std::endl; + (*warn) += ss.str(); + } + } + + bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name, + triangulate, v); + // exportGroupsToShape return false when `usemtl` is called in the last + // line. + // we also add `shape` to `shapes` when `shape.mesh` has already some + // faces(indices) + if (ret || shape.mesh.vertex_indices + .size()) { // FIXME(syoyo): Support other prims(e.g. lines) + shapes->push_back(shape); + } + prim_group.clear(); // for safety + + if (err) { + (*err) += errss.str(); + } + + attrib->vertices.swap(v); + attrib->vertex_weights.swap(v); + attrib->normals.swap(vn); + attrib->texcoords.swap(vt); + attrib->texcoord_ws.swap(vt); + attrib->colors.swap(vc); + + return true; +} + +bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, + void *user_data /*= NULL*/, + MaterialReader *readMatFn /*= NULL*/, + std::string *warn, /* = NULL*/ + std::string *err /*= NULL*/) { + std::stringstream errss; + + // material + std::map material_map; + int material_id = -1; // -1 = invalid + + std::vector indices; + std::vector materials; + std::vector names; + names.reserve(2); + std::vector names_out; + + std::string linebuf; + while (inStream.peek() != -1) { + safeGetline(inStream, linebuf); + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + // TODO(syoyo): Support parsing vertex color extension. + real_t x, y, z, w; // w is optional. default = 1.0 + parseV(&x, &y, &z, &w, &token); + if (callback.vertex_cb) { + callback.vertex_cb(user_data, x, y, z, w); + } + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y, z; + parseReal3(&x, &y, &z, &token); + if (callback.normal_cb) { + callback.normal_cb(user_data, x, y, z); + } + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y, z; // y and z are optional. default = 0.0 + parseReal3(&x, &y, &z, &token); + if (callback.texcoord_cb) { + callback.texcoord_cb(user_data, x, y, z); + } + continue; + } + + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + indices.clear(); + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi = parseRawTriple(&token); + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + indices.push_back(idx); + size_t n = strspn(token, " \t\r"); + token += n; + } + + if (callback.index_cb && indices.size() > 0) { + callback.index_cb(user_data, &indices.at(0), + static_cast(indices.size())); + } + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { + token += 7; + std::stringstream ss; + ss << token; + std::string namebuf = ss.str(); + + int newMaterialId = -1; + std::map::const_iterator it = material_map.find(namebuf); + if (it != material_map.end()) { + newMaterialId = it->second; + } else { + // { warn!! material not found } + if (warn && (!callback.usemtl_cb)) { + (*warn) += "material [ " + namebuf + " ] not found in .mtl\n"; + } + } + + if (newMaterialId != material_id) { + material_id = newMaterialId; + } + + if (callback.usemtl_cb) { + callback.usemtl_cb(user_data, namebuf.c_str(), material_id); + } + + continue; + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + token += 7; + + std::vector filenames; + SplitString(std::string(token), ' ', filenames); + + if (filenames.empty()) { + if (warn) { + (*warn) += + "Looks like empty filename for mtllib. Use default " + "material. \n"; + } + } else { + bool found = false; + for (size_t s = 0; s < filenames.size(); s++) { + std::string warn_mtl; + std::string err_mtl; + bool ok = (*readMatFn)(filenames[s].c_str(), &materials, + &material_map, &warn_mtl, &err_mtl); + + if (warn && (!warn_mtl.empty())) { + (*warn) += warn_mtl; // This should be warn message. + } + + if (err && (!err_mtl.empty())) { + (*err) += err_mtl; + } + + if (ok) { + found = true; + break; + } + } + + if (!found) { + if (warn) { + (*warn) += + "Failed to load material file(s). Use default " + "material.\n"; + } + } else { + if (callback.mtllib_cb) { + callback.mtllib_cb(user_data, &materials.at(0), + static_cast(materials.size())); + } + } + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + names.clear(); + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + assert(names.size() > 0); + + if (callback.group_cb) { + if (names.size() > 1) { + // create const char* array. + names_out.resize(names.size() - 1); + for (size_t j = 0; j < names_out.size(); j++) { + names_out[j] = names[j + 1].c_str(); + } + callback.group_cb(user_data, &names_out.at(0), + static_cast(names_out.size())); + + } else { + callback.group_cb(user_data, NULL, 0); + } + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // @todo { multiple object name? } + token += 2; + + std::stringstream ss; + ss << token; + std::string object_name = ss.str(); + + if (callback.object_cb) { + callback.object_cb(user_data, object_name.c_str()); + } + + continue; + } + +#if 0 // @todo + if (token[0] == 't' && IS_SPACE(token[1])) { + tag_t tag; + + token += 2; + std::stringstream ss; + ss << token; + tag.name = ss.str(); + + token += tag.name.size() + 1; + + tag_sizes ts = parseTagTriple(&token); + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = atoi(token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.floatValues.resize(static_cast(ts.num_reals)); + for (size_t i = 0; i < static_cast(ts.num_reals); ++i) { + tag.floatValues[i] = parseReal(&token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + std::stringstream ss; + ss << token; + tag.stringValues[i] = ss.str(); + token += tag.stringValues[i].size() + 1; + } + + tags.push_back(tag); + } +#endif + + // Ignore unknown command. + } + + if (err) { + (*err) += errss.str(); + } + + return true; +} + +bool ObjReader::ParseFromFile(const std::string &filename, + const ObjReaderConfig &config) { + std::string mtl_search_path; + + if (config.mtl_search_path.empty()) { + // + // split at last '/'(for unixish system) or '\\'(for windows) to get + // the base directory of .obj file + // + size_t pos = filename.find_last_of("/\\"); + if (pos != std::string::npos) { + mtl_search_path = filename.substr(0, pos); + } + } else { + mtl_search_path = config.mtl_search_path; + } + + valid_ = LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_, + filename.c_str(), mtl_search_path.c_str(), + config.triangulate, config.vertex_color); + + return valid_; +} + +bool ObjReader::ParseFromString(const std::string &obj_text, + const std::string &mtl_text, + const ObjReaderConfig &config) { + std::stringbuf obj_buf(obj_text); + std::stringbuf mtl_buf(mtl_text); + + std::istream obj_ifs(&obj_buf); + std::istream mtl_ifs(&mtl_buf); + + MaterialStreamReader mtl_ss(mtl_ifs); + + valid_ = LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_, + &obj_ifs, &mtl_ss, config.triangulate, config.vertex_color); + + return valid_; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +} // namespace tinyobj + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/vertices.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/vertices.cu new file mode 100644 index 00000000..67ef5fb3 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/vertices.cu @@ -0,0 +1,110 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "vertices.h" + +__forceinline__ __device__ float triangle_wave( float x, float shift = 0.f, float period = 2.f * M_PI, float amplitude = 1.f ) +{ + return fabsf( fmodf( ( 4.f / period ) * ( x - shift ), 4.f * amplitude ) - 2.f * amplitude ) - amplitude; +} + +__forceinline__ __device__ void write_animated_triangle( float3* out_vertices, int tidx, float3 v0, float3 v1, float3 v2, AnimationMode mode, float time ) +{ + float3 v = make_float3( 0 ); + + if( mode == AnimationMode_Explode ) + { + // Generate displacement vector from triangle index + const float theta = ( (float)M_PI * ( ( tidx + 1 ) * ( 13 / M_PI ) ) ); + const float phi = ( (float)( 2.0 * M_PI ) * ( ( tidx + 1 ) * ( 97 / M_PI ) ) ); + + // Apply displacement to the sphere triangles + v = make_float3( triangle_wave( phi ) * triangle_wave( theta, M_PI / 2.f ), + triangle_wave( phi, M_PI / 2.f ) * triangle_wave( theta, M_PI / 2.f ), triangle_wave( theta ) ) + * triangle_wave( time, M_PI / 2.f ) * 2.f; + } + + out_vertices[tidx * 3 + 0] = v0 + v; + out_vertices[tidx * 3 + 1] = v1 + v; + out_vertices[tidx * 3 + 2] = v2 + v; +} + +__forceinline__ __device__ float3 deform_vertex( const float3& c, AnimationMode mode, float time ) +{ + // Apply sine wave to the y coordinate of the sphere vertices + if( mode == AnimationMode_Deform ) + return make_float3( c.x, c.y * ( 0.5f + 0.4f * cosf( 4 * ( c.x + time ) ) ), c.z ); + return c; +} + +extern "C" __global__ void generate_vertices(float3* out_vertices, AnimationMode mode, float time, int width, int height) +{ + int idx = blockIdx.x * blockDim.x + threadIdx.x; + + if( idx < width * height ) + { + // generate a single patch (two unindexed triangles) of a tessellated sphere + + int x = idx % width; + int y = idx / width; + + const float theta0 = ( ( float )M_PI * ( y + 0 ) ) / height; + const float theta1 = ( ( float )M_PI * ( y + 1 ) ) / height; + const float phi0 = ( ( float )( 2.0 * M_PI ) * ( x + 0 ) ) / width; + const float phi1 = ( ( float )( 2.0 * M_PI ) * ( x + 1 ) ) / width; + + const float ct0 = cosf( theta0 ); + const float st0 = sinf( theta0 ); + const float ct1 = cosf( theta1 ); + const float st1 = sinf( theta1 ); + + const float cp0 = cosf( phi0 ); + const float sp0 = sinf( phi0 ); + const float cp1 = cosf( phi1 ); + const float sp1 = sinf( phi1 ); + + const float3 v00 = deform_vertex( make_float3( cp0 * st0, sp0 * st0, ct0 ), mode, time ); + const float3 v10 = deform_vertex( make_float3( cp0 * st1, sp0 * st1, ct1 ), mode, time ); + const float3 v01 = deform_vertex( make_float3( cp1 * st0, sp1 * st0, ct0 ), mode, time ); + const float3 v11 = deform_vertex( make_float3( cp1 * st1, sp1 * st1, ct1 ), mode, time ); + + write_animated_triangle( out_vertices, idx * 2 + 0, v00, v10, v11, mode, time ); + write_animated_triangle( out_vertices, idx * 2 + 1, v00, v11, v01, mode, time ); + } +} + +extern "C" __host__ void +generateAnimatedVetrices( float3* out_vertices, AnimationMode animation_mode, float time, int width, int height ) +{ + dim3 threadsPerBlock( 128, 1 ); + int numBlocks = ( width * height ) / threadsPerBlock.x; + generate_vertices <<< numBlocks, threadsPerBlock >>> ( out_vertices, animation_mode, time, width, height ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/vertices.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/vertices.h new file mode 100644 index 00000000..f8da1c48 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMotionGeometry/vertices.h @@ -0,0 +1,44 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +enum AnimationMode +{ + AnimationMode_None, + AnimationMode_Deform, + AnimationMode_Explode +}; + +extern "C" __host__ void generateAnimatedVetrices( float3* out_vertices, AnimationMode animation_mode, float time, int width, int height ); diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/CMakeLists.txt new file mode 100644 index 00000000..43e3da4d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/CMakeLists.txt @@ -0,0 +1,45 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/optixMultiGPU_kernels.cu + PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ + ) + +OPTIX_add_sample_executable( optixMultiGPU target_name + ${SAMPLES_CUDA_DIR}/helpers.h + optixMultiGPU_kernels.cu + optixMultiGPU.cu + optixMultiGPU.cpp + optixMultiGPU.h + ) +set_property(TARGET ${target_name} PROPERTY CUDA_SEPARABLE_COMPILATION ON) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/optixMultiGPU.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/optixMultiGPU.cpp new file mode 100644 index 00000000..c7005fee --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/optixMultiGPU.cpp @@ -0,0 +1,1194 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include // Needs to be included before gl_interop + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "sutil/WorkDistribution.h" +#include "optixMultiGPU.h" + +#include +#include +#include +#include +#include + + +// +// TODO: +// * Use Accel relocation for building instead of independent build per GPU +// * Add cmd line args for specifying desired devices +// +// + +bool resize_dirty = false; +bool minimized = true; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Mouse state +int2 mouse_prev_pos; +int32_t mouse_button = -1; + +int32_t width = 768; +int32_t height = 768; +int32_t samples_per_launch = 16; +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +extern "C" void fillSamplesCUDA( + int32_t num_samples, + cudaStream_t stream, + int32_t gpu_idx, + int32_t num_gpus, + int32_t width, + int32_t height, + int2* samples ); + +//------------------------------------------------------------------------------ +// +// Local types +// +//------------------------------------------------------------------------------ + +template +struct Record +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef Record RayGenRecord; +typedef Record MissRecord; +typedef Record HitGroupRecord; + + +struct Vertex +{ + float x, y, z, pad; +}; + + +struct IndexedTriangle +{ + uint32_t v1, v2, v3, pad; +}; + + +struct Instance +{ + float transform[12]; +}; + + +struct PathTracerState +{ + int32_t device_idx = -1; + OptixDeviceContext context = 0; + + OptixTraversableHandle gas_handle = 0; // Traversable handle for triangle AS + CUdeviceptr d_gas_output_buffer = 0; // Triangle AS memory + CUdeviceptr d_vertices = 0; + + OptixModule ptx_module = 0; + OptixPipelineCompileOptions pipeline_compile_options = {}; + OptixPipeline pipeline = 0; + + OptixProgramGroup raygen_prog_group = 0; + OptixProgramGroup radiance_miss_group = 0; + OptixProgramGroup occlusion_miss_group = 0; + OptixProgramGroup radiance_hit_group = 0; + OptixProgramGroup occlusion_hit_group = 0; + + OptixShaderBindingTable sbt = {}; + + int32_t num_samples = 0; + int2* d_sample_indices = 0; + float4* d_sample_accum = 0; + + Params params; + Params* d_params; + + CUstream stream = 0; +}; + + +//------------------------------------------------------------------------------ +// +// Scene data +// +//------------------------------------------------------------------------------ + +const int32_t TRIANGLE_COUNT = 32; +const int32_t MAT_COUNT = 4; + +const static std::array g_vertices = +{ { + // Floor -- white lambert + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 0.0f, 0.0f }, + + // Ceiling -- white lambert + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + + // Back wall -- white lambert + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + + // Right wall -- green lambert + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + { 0.0f, 0.0f, 559.2f, 0.0f }, + + // Left wall -- red lambert + { 556.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 556.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 0.0f, 0.0f }, + + // Short block -- white lambert + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 242.0f, 165.0f, 274.0f, 0.0f }, + + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 242.0f, 165.0f, 274.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + + { 290.0f, 0.0f, 114.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + + { 290.0f, 0.0f, 114.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + { 240.0f, 0.0f, 272.0f, 0.0f }, + + { 130.0f, 0.0f, 65.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + + { 130.0f, 0.0f, 65.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + { 290.0f, 0.0f, 114.0f, 0.0f }, + + { 82.0f, 0.0f, 225.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + + { 82.0f, 0.0f, 225.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 130.0f, 0.0f, 65.0f, 0.0f }, + + { 240.0f, 0.0f, 272.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + + { 240.0f, 0.0f, 272.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 82.0f, 0.0f, 225.0f, 0.0f }, + + // Tall block -- white lambert + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 314.0f, 330.0f, 455.0f, 0.0f }, + + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 314.0f, 330.0f, 455.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + + { 423.0f, 0.0f, 247.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + + { 423.0f, 0.0f, 247.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + { 472.0f, 0.0f, 406.0f, 0.0f }, + + { 472.0f, 0.0f, 406.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + + { 472.0f, 0.0f, 406.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + { 314.0f, 0.0f, 456.0f, 0.0f }, + + { 314.0f, 0.0f, 456.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + + { 314.0f, 0.0f, 456.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 265.0f, 0.0f, 296.0f, 0.0f }, + + { 265.0f, 0.0f, 296.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + + { 265.0f, 0.0f, 296.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 423.0f, 0.0f, 247.0f, 0.0f }, + + // Ceiling light -- emmissive + { 343.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 332.0f, 0.0f }, + + { 343.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 332.0f, 0.0f }, + { 343.0f, 548.6f, 332.0f, 0.0f } +} }; + + +static std::array g_mat_indices = +{ { + 0, 0, // Floor -- white lambert + 0, 0, // Ceiling -- white lambert + 0, 0, // Back wall -- white lambert + 1, 1, // Right wall -- green lambert + 2, 2, // Left wall -- red lambert + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Short block -- white lambert + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Tall block -- white lambert + 3, 3 // Ceiling light -- emmissive +} }; + + +const std::array g_emission_colors = +{ { + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 15.0f, 15.0f, 5.0f } + +} }; + + +const std::array g_diffuse_colors = +{ { + { 0.80f, 0.80f, 0.80f }, + { 0.05f, 0.80f, 0.05f }, + { 0.80f, 0.05f, 0.05f }, + { 0.50f, 0.00f, 0.00f } +} }; + + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking(static_cast( xpos ), static_cast( ypos )); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), width, height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), width, height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + width = res_x; + height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || + key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + } + else if( key == GLFW_KEY_G ) + { + // toggle UI draw + } +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// +//------------------------------------------------------------------------------ + + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --launch-samples | -s Number of samples per pixel per launch (default 16)\n"; + std::cerr << " --help | -h Print this usage message\n"; + exit( 0 ); +} + + +void initCameraState() +{ + camera.setEye( make_float3( 278.0f, 273.0f, -900.0f ) ); + camera.setLookat( make_float3( 278.0f, 273.0f, 330.0f ) ); + camera.setUp( make_float3( 0.0f, 1.0f, 0.0f ) ); + camera.setFovY( 35.0f ); + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( make_float3( 1.0f, 0.0f, 0.0f ), make_float3( 0.0f, 0.0f, 1.0f ), make_float3( 0.0f, 1.0f, 0.0f ) ); + trackball.setGimbalLock(true); +} + + +void initLaunchParams( PathTracerState& state ) +{ + state.params.subframe_index = 0u; + state.params.width = width; + state.params.height = height; + state.params.samples_per_launch = samples_per_launch; + state.params.device_idx = state.device_idx; + + state.params.light.emission = make_float3( 15.0f, 15.0f, 5.0f ); + state.params.light.corner = make_float3( 343.0f, 548.5f, 227.0f ); + state.params.light.v1 = make_float3( 0.0f, 0.0f, 105.0f ); + state.params.light.v2 = make_float3( -130.0f, 0.0f, 0.0f ); + state.params.light.normal = normalize ( cross( state.params.light.v1, state.params.light.v2) ); + state.params.handle = state.gas_handle; + + // IO buffers are assigned in allocIOBuffers + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_params), sizeof( Params ) ) ); +} + + +void allocIOBuffers( PathTracerState& state, int num_gpus ) +{ + StaticWorkDistribution wd; + wd.setRasterSize( width, height ); + wd.setNumGPUs( num_gpus ); + + state.num_samples = wd.numSamples( state.device_idx ); + + CUDA_CHECK( cudaSetDevice( state.device_idx ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_sample_indices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_sample_accum ) ) ); + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_sample_indices ), state.num_samples*sizeof( int2 ) ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_sample_accum ), state.num_samples*sizeof( float4 ) ) ); + + state.params.sample_index_buffer = state.d_sample_indices; + state.params.sample_accum_buffer = state.d_sample_accum; + state.params.result_buffer = 0; // Managed by CUDAOutputBuffer + + fillSamplesCUDA( + state.num_samples, + state.stream, + state.device_idx, + num_gpus, + width, + height, + state.d_sample_indices + ); +} + + +void handleCameraUpdate( std::vector& states ) +{ + if( !camera_changed ) + return; + camera_changed = false; + + camera.setAspectRatio( static_cast( width ) / static_cast( height ) ); + float3 u, v, w; + camera.UVWFrame( u, v, w ); + + for( auto& state : states ) + { + state.params.eye = camera.eye(); + state.params.U = u; + state.params.V = v; + state.params.W = w; + } +} + + +void handleResize( sutil::CUDAOutputBuffer& output_buffer, std::vector& states ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + CUDA_CHECK( cudaSetDevice( states.front().device_idx ) ); + output_buffer.resize( width, height ); + + // Realloc accumulation buffer + for( auto& state : states ) + { + state.params.width = width; + state.params.height = height; + allocIOBuffers( state, static_cast( states.size() ) ); + } +} + + +void updateState( sutil::CUDAOutputBuffer& output_buffer, std::vector& states ) +{ + // Update params on device + if( camera_changed || resize_dirty ) + for( auto& state : states ) + state.params.subframe_index = 0; + + handleCameraUpdate( states ); + handleResize( output_buffer, states ); +} + + +void launchSubframe( sutil::CUDAOutputBuffer& output_buffer, std::vector& states ) +{ + uchar4* result_buffer_data = output_buffer.map(); + for( auto& state : states ) + { + // Launch + CUDA_CHECK( cudaSetDevice( state.device_idx ) ); + state.params.result_buffer = result_buffer_data; + CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast( state.d_params ), + &state.params, + sizeof( Params ), + cudaMemcpyHostToDevice, + state.stream + ) ); + + OPTIX_CHECK( optixLaunch( + state.pipeline, + state.stream, + reinterpret_cast( state.d_params ), + sizeof( Params ), + &state.sbt, + state.num_samples, // launch width + 1, // launch height + 1 // launch depth + ) ); + } + output_buffer.unmap(); + for( auto& state : states ) + { + CUDA_CHECK( cudaSetDevice( state.device_idx ) ); + CUDA_SYNC_CHECK(); + } +} + + +void displaySubframe( + sutil::CUDAOutputBuffer& output_buffer, + sutil::GLDisplay& gl_display, + GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( + width, + height, + framebuf_res_x, + framebuf_res_y, + output_buffer.getPBO() + ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + + +void createContext( PathTracerState& state ) +{ + // Initialize CUDA on this device + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cuCtx = 0; // zero means take the current context + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + + state.context = context; + + CUDA_CHECK( cudaStreamCreate( &state.stream ) ); +} + + +void createContexts( std::vector& state ) +{ + OPTIX_CHECK( optixInit() ); + + int32_t device_count = 0; + CUDA_CHECK( cudaGetDeviceCount( &device_count ) ); + state.resize( device_count ); + std::cout << "Total GPUs visible: " << device_count << std::endl; + + cudaDeviceProp prop; + for( int i = 0; i < device_count; ++i ) + { + state[i].device_idx = i; + CUDA_CHECK( cudaGetDeviceProperties ( &prop, i ) ); + CUDA_CHECK( cudaSetDevice( i ) ); + std::cout << "\t[" << i << "]: " << prop.name << std::endl; + + createContext( state[i] ); + } +} + + +void buildMeshAccel( PathTracerState& state ) +{ + // + // copy mesh data to device + // + const size_t vertices_size_in_bytes = g_vertices.size() * sizeof( Vertex ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_vertices ), vertices_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( state.d_vertices ), + g_vertices.data(), + vertices_size_in_bytes, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr d_mat_indices = 0; + const size_t mat_indices_size_in_bytes = g_mat_indices.size() * sizeof( uint32_t ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_mat_indices ), + mat_indices_size_in_bytes + ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_mat_indices), + g_mat_indices.data(), + mat_indices_size_in_bytes, + cudaMemcpyHostToDevice + ) ); + + // + // Build triangle GAS + // + uint32_t triangle_input_flags[MAT_COUNT] = + { + // One per SBT record for this build input + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT + }; + + OptixBuildInput triangle_input = {}; + triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangle_input.triangleArray.vertexStrideInBytes = sizeof( Vertex ); + triangle_input.triangleArray.numVertices = static_cast( g_vertices.size() ); + triangle_input.triangleArray.vertexBuffers = &state.d_vertices; + triangle_input.triangleArray.flags = triangle_input_flags; + triangle_input.triangleArray.numSbtRecords = MAT_COUNT; + triangle_input.triangleArray.sbtIndexOffsetBuffer = d_mat_indices; + triangle_input.triangleArray.sbtIndexOffsetSizeInBytes = sizeof(uint32_t); + triangle_input.triangleArray.sbtIndexOffsetStrideInBytes = sizeof(uint32_t); + + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( + state.context, + &accel_options, + &triangle_input, + 1, // num_build_inputs + &gas_buffer_sizes + ) ); + + CUdeviceptr d_temp_buffer; + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_temp_buffer ), + gas_buffer_sizes.tempSizeInBytes + ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 + ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( (char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( + state.context, + 0, // CUDA stream + &accel_options, + &triangle_input, + 1, // num build inputs + d_temp_buffer, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &state.gas_handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_mat_indices ) ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, (void*)emitProperty.result, sizeof(size_t), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, 0, state.gas_handle, state.d_gas_output_buffer, + compacted_gas_size, &state.gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + state.d_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } +} + + + + +void createModule( PathTracerState& state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + state.pipeline_compile_options.usesMotionBlur = false; + state.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + state.pipeline_compile_options.numPayloadValues = 2; + state.pipeline_compile_options.numAttributeValues = 2; + state.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; // should be OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW; + state.pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixMultiGPU.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( + state.context, + &module_compile_options, + &state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &state.ptx_module + ) ); +} + + +void createProgramGroups( PathTracerState& state ) +{ + OptixProgramGroupOptions program_group_options = {}; + + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = state.ptx_module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.raygen_prog_group + ) + ); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.ptx_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__radiance"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.radiance_miss_group + ) + ); + + memset( &miss_prog_group_desc, 0, sizeof( OptixProgramGroupDesc ) ); + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = nullptr; // NULL miss program for occlusion rays + miss_prog_group_desc.miss.entryFunctionName = nullptr; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.occlusion_miss_group + ) + ); + + + OptixProgramGroupDesc hit_prog_group_desc = {}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = state.ptx_module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__radiance"; + + OPTIX_CHECK_LOG( + optixProgramGroupCreate( + state.context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.radiance_hit_group + ) + ); + + memset( &hit_prog_group_desc, 0, sizeof( OptixProgramGroupDesc ) ); + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = state.ptx_module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__occlusion"; + OPTIX_CHECK_LOG( + optixProgramGroupCreate( + state.context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.occlusion_hit_group + ) + ); + +} + + +void createPipeline( PathTracerState& state ) +{ + const uint32_t max_trace_depth = 2; + + OptixProgramGroup program_groups[] = + { + state.raygen_prog_group, + state.radiance_miss_group, + state.occlusion_miss_group, + state.radiance_hit_group, + state.occlusion_hit_group + }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + + OPTIX_CHECK_LOG( optixPipelineCreate( + state.context, + &state.pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &state.pipeline + ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, state.pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( state.pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + ) ); +} + + +void createSBT( PathTracerState& state ) +{ + CUdeviceptr d_raygen_record; + const size_t raygen_record_size = sizeof( RayGenRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_raygen_record ), raygen_record_size ) ); + + RayGenRecord rg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( state.raygen_prog_group, &rg_sbt ) ); + rg_sbt.data = {1.0f, 0.f, 0.f}; + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_raygen_record ), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + + + CUdeviceptr d_miss_records; + const size_t miss_record_size = sizeof( MissRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_miss_records ), miss_record_size*RAY_TYPE_COUNT ) ); + + MissRecord ms_sbt[2]; + OPTIX_CHECK( optixSbtRecordPackHeader( state.radiance_miss_group, &ms_sbt[0] ) ); + ms_sbt[0].data = {0.0f, 0.0f, 0.0f}; + OPTIX_CHECK( optixSbtRecordPackHeader( state.occlusion_miss_group, &ms_sbt[1] ) ); + ms_sbt[1].data = {0.0f, 0.0f, 0.0f}; + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_miss_records ), + ms_sbt, + miss_record_size*RAY_TYPE_COUNT, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr d_hitgroup_records; + const size_t hitgroup_record_size = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_hitgroup_records ), + hitgroup_record_size*RAY_TYPE_COUNT*MAT_COUNT + ) ); + HitGroupRecord hitgroup_records[ RAY_TYPE_COUNT*MAT_COUNT ]; + + for( int i = 0; i < MAT_COUNT; ++i ) + { + { + const int sbt_idx = i*RAY_TYPE_COUNT+0; // SBT for radiance ray-type for ith material + + OPTIX_CHECK( optixSbtRecordPackHeader( state.radiance_hit_group, &hitgroup_records[sbt_idx] ) ); + hitgroup_records[ sbt_idx ].data.emission_color = g_emission_colors[i]; + hitgroup_records[ sbt_idx ].data.diffuse_color = g_diffuse_colors[i]; + hitgroup_records[ sbt_idx ].data.vertices = reinterpret_cast(state.d_vertices); + } + + { + const int sbt_idx = i*RAY_TYPE_COUNT+1; // SBT for occlusion ray-type for ith material + memset( &hitgroup_records[sbt_idx], 0, hitgroup_record_size ); + + OPTIX_CHECK( optixSbtRecordPackHeader( state.occlusion_hit_group, &hitgroup_records[sbt_idx] ) ); + } + } + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_hitgroup_records ), + hitgroup_records, + hitgroup_record_size*RAY_TYPE_COUNT*MAT_COUNT, + cudaMemcpyHostToDevice + ) ); + + state.sbt.raygenRecord = d_raygen_record; + state.sbt.missRecordBase = d_miss_records; + state.sbt.missRecordStrideInBytes = static_cast( miss_record_size ); + state.sbt.missRecordCount = RAY_TYPE_COUNT; + state.sbt.hitgroupRecordBase = d_hitgroup_records; + state.sbt.hitgroupRecordStrideInBytes = static_cast( hitgroup_record_size ); + state.sbt.hitgroupRecordCount = RAY_TYPE_COUNT*MAT_COUNT; +} + + +void cleanupState( PathTracerState& state ) +{ + OPTIX_CHECK( optixPipelineDestroy ( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.radiance_miss_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.radiance_hit_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.occlusion_hit_group ) ); + OPTIX_CHECK( optixModuleDestroy ( state.ptx_module ) ); + OPTIX_CHECK( optixDeviceContextDestroy( state.context ) ); + + + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_vertices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_sample_indices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_sample_accum ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_params ) ) ); +} + + +//------------------------------------------------------------------------------ +// +// Main +// +//------------------------------------------------------------------------------ + +int main( int argc, char* argv[] ) +{ + // + // Parse command line options + // + std::string outfile; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outfile = argv[++i]; + } + else if( arg == "--launch-samples" || arg == "-s" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + samples_per_launch = atoi( argv[++i] ); + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + initCameraState(); + + std::vector states; + createContexts( states ); + + // + // Set up OptiX state + // + for( auto& state : states ) + { + CUDA_CHECK( cudaSetDevice( state.device_idx ) ); + buildMeshAccel ( state ); + createModule ( state ); + createProgramGroups( state ); + createPipeline ( state ); + createSBT ( state ); + allocIOBuffers ( state, static_cast( states.size() ) ); + } + + for( auto& state : states ) + initLaunchParams( state ); + + if( outfile.empty() ) + { + GLFWwindow* window = sutil::initUI( "optixMultiGPU", width, height ); + glfwSetMouseButtonCallback ( window, mouseButtonCallback ); + glfwSetCursorPosCallback ( window, cursorPosCallback ); + glfwSetWindowSizeCallback ( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback ( window, keyCallback ); + + // + // Render loop + // + { + sutil::CUDAOutputBuffer output_buffer( sutil::CUDAOutputBufferType::ZERO_COPY, width, height ); + output_buffer.setDevice( 0 ); + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + updateState( output_buffer, states ); + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + launchSubframe( output_buffer, states ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1-t0; + + sutil::displayStats( state_update_time, render_time, display_time ); + + glfwSwapBuffers(window); + + for( auto& state : states ) + ++state.params.subframe_index; + + } while( !glfwWindowShouldClose( window ) ); + + for( auto& state : states ) + { + CUDA_CHECK( cudaSetDevice( state.device_idx ) ); + CUDA_SYNC_CHECK(); + } + } + + sutil::cleanupUI( window ); + } + else + { + sutil::CUDAOutputBuffer output_buffer( sutil::CUDAOutputBufferType::ZERO_COPY, width, height ); + output_buffer.setDevice( 0 ); + + updateState( output_buffer, states ); + launchSubframe( output_buffer, states ); + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + for( auto& state : states ) + cleanupState( state ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/optixMultiGPU.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/optixMultiGPU.cu new file mode 100644 index 00000000..0bab55fa --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/optixMultiGPU.cu @@ -0,0 +1,390 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include "optixMultiGPU.h" +#include +#include +#include + +extern "C" { +__constant__ Params params; +} + + + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +struct RadiancePRD +{ + // TODO: move some state directly into payload registers? + float3 emitted; + float3 radiance; + float3 attenuation; + float3 origin; + float3 direction; + unsigned int seed; + int countEmitted; + int done; + int pad; +}; + + +struct Onb +{ + __forceinline__ __device__ Onb(const float3& normal) + { + m_normal = normal; + + if( fabs(m_normal.x) > fabs(m_normal.z) ) + { + m_binormal.x = -m_normal.y; + m_binormal.y = m_normal.x; + m_binormal.z = 0; + } + else + { + m_binormal.x = 0; + m_binormal.y = -m_normal.z; + m_binormal.z = m_normal.y; + } + + m_binormal = normalize(m_binormal); + m_tangent = cross( m_binormal, m_normal ); + } + + __forceinline__ __device__ void inverse_transform(float3& p) const + { + p = p.x*m_tangent + p.y*m_binormal + p.z*m_normal; + } + + float3 m_tangent; + float3 m_binormal; + float3 m_normal; +}; + + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +static __forceinline__ __device__ void* unpackPointer( unsigned int i0, unsigned int i1 ) +{ + const unsigned long long uptr = static_cast( i0 ) << 32 | i1; + void* ptr = reinterpret_cast( uptr ); + return ptr; +} + + +static __forceinline__ __device__ void packPointer( void* ptr, unsigned int& i0, unsigned int& i1 ) +{ + const unsigned long long uptr = reinterpret_cast( ptr ); + i0 = uptr >> 32; + i1 = uptr & 0x00000000ffffffff; +} + + +static __forceinline__ __device__ RadiancePRD* getPRD() +{ + const unsigned int u0 = optixGetPayload_0(); + const unsigned int u1 = optixGetPayload_1(); + return reinterpret_cast( unpackPointer( u0, u1 ) ); +} + + +static __forceinline__ __device__ void setPayloadOcclusion( bool occluded ) +{ + optixSetPayload_0( static_cast( occluded ) ); +} + + +static __forceinline__ __device__ void cosine_sample_hemisphere(const float u1, const float u2, float3& p) +{ + // Uniformly sample disk. + const float r = sqrtf( u1 ); + const float phi = 2.0f*M_PIf * u2; + p.x = r * cosf( phi ); + p.y = r * sinf( phi ); + + // Project up to hemisphere. + p.z = sqrtf( fmaxf( 0.0f, 1.0f - p.x*p.x - p.y*p.y ) ); +} + + +static __forceinline__ __device__ void traceRadiance( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax, + RadiancePRD* prd + ) +{ + // TODO: deduce stride from num ray-types passed in params + + unsigned int u0, u1; + packPointer( prd, u0, u1 ); + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_NONE, + RAY_TYPE_RADIANCE, // SBT offset + RAY_TYPE_COUNT, // SBT stride + RAY_TYPE_RADIANCE, // missSBTIndex + u0, u1 ); +} + + +static __forceinline__ __device__ bool traceOcclusion( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax + ) +{ + unsigned int occluded = 0u; + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT, + RAY_TYPE_OCCLUSION, // SBT offset + RAY_TYPE_COUNT, // SBT stride + RAY_TYPE_OCCLUSION, // missSBTIndex + occluded ); + return occluded; +} + +__forceinline__ __device__ float3 deviceColor( unsigned int idx ) +{ + return make_float3( + idx == 0 ? 0.05f : 0.0f, + idx == 1 ? 0.05f : 0.0f, + idx == 2 ? 0.05f : 0.0f + ); +} + + +//------------------------------------------------------------------------------ +// +// +//------------------------------------------------------------------------------ + +extern "C" __global__ void __raygen__rg() +{ + const int w = params.width; + const int h = params.height; + const uint3 launch_idx = optixGetLaunchIndex(); + const int2 pixel_idx = params.sample_index_buffer[ launch_idx.x ]; + + // Work distribution might assign tiles that cross over image boundary + if( pixel_idx.x > w-1 || pixel_idx.y > h-1 ) + return; + + const float3 eye = params.eye; + const float3 U = params.U; + const float3 V = params.V; + const float3 W = params.W; + + const int subframe_index = params.subframe_index; + + unsigned int seed = tea<4>( pixel_idx.y*w + pixel_idx.x, subframe_index ); + + + float3 result = make_float3( 0.0f ); + int i = params.samples_per_launch; + do + { + // The center of each pixel is at fraction (0.5,0.5) + const float2 subpixel_jitter = make_float2( rnd( seed ), rnd( seed ) ); + + const float2 d = 2.0f * make_float2( + ( static_cast( pixel_idx.x ) + subpixel_jitter.x ) / static_cast( w ), + ( static_cast( pixel_idx.y ) + subpixel_jitter.y ) / static_cast( h ) + ) - 1.0f; + float3 ray_direction = normalize(d.x*U + d.y*V + W); + float3 ray_origin = eye; + + RadiancePRD prd; + prd.emitted = make_float3(0.f); + prd.radiance = make_float3(0.f); + prd.attenuation = make_float3(1.f); + prd.countEmitted = true; + prd.done = false; + prd.seed = seed; + + int depth = 0; + for( ;; ) + { + traceRadiance( + params.handle, + ray_origin, + ray_direction, + 0.01f, // tmin // TODO: smarter offset + 1e16f, // tmax + &prd ); + + result += prd.emitted; + result += prd.radiance * prd.attenuation; + + if( prd.done || depth >= 3 ) // TODO RR, variable for depth + break; + + ray_origin = prd.origin; + ray_direction = prd.direction; + + ++depth; + } + } + while( --i ); + + float3 accum_color = result / static_cast( params.samples_per_launch ); + if( subframe_index > 0 ) + { + const float a = 1.0f / static_cast( subframe_index+1 ); + const float3 accum_color_prev = make_float3( params.sample_accum_buffer[ launch_idx.x ]); + accum_color = lerp( accum_color_prev, accum_color, a ); + } + params.sample_accum_buffer [ launch_idx.x ] = make_float4( accum_color, 1.0f); + + const unsigned int image_index = pixel_idx.y * params.width + pixel_idx.x; + params.result_buffer[ image_index ] = make_color ( accum_color + deviceColor( params.device_idx ) ); +} + + +extern "C" __global__ void __miss__radiance() +{ + MissData* rt_data = reinterpret_cast( optixGetSbtDataPointer() ); + RadiancePRD* prd = getPRD(); + + prd->radiance = make_float3( rt_data->r, rt_data->g, rt_data->b ); + prd->done = true; +} + + +extern "C" __global__ void __closesthit__occlusion() +{ + setPayloadOcclusion( true ); +} + + +extern "C" __global__ void __closesthit__radiance() +{ + HitGroupData* rt_data = (HitGroupData*)optixGetSbtDataPointer(); + + const int prim_idx = optixGetPrimitiveIndex(); + const float3 ray_dir = optixGetWorldRayDirection(); + const int vert_idx_offset = prim_idx*3; + + const float3 v0 = make_float3( rt_data->vertices[ vert_idx_offset+0 ] ); + const float3 v1 = make_float3( rt_data->vertices[ vert_idx_offset+1 ] ); + const float3 v2 = make_float3( rt_data->vertices[ vert_idx_offset+2 ] ); + const float3 N_0 = normalize( cross( v1-v0, v2-v0 ) ); + + const float3 N = faceforward( N_0, -ray_dir, N_0 ); + const float3 P = optixGetWorldRayOrigin() + optixGetRayTmax()*ray_dir; + + RadiancePRD* prd = getPRD(); + + if( prd->countEmitted ) + prd->emitted = rt_data->emission_color; + else + prd->emitted = make_float3( 0.0f ); + + + unsigned int seed = prd->seed; + + { + const float z1 = rnd(seed); + const float z2 = rnd(seed); + + float3 w_in; + cosine_sample_hemisphere( z1, z2, w_in ); + Onb onb( N ); + onb.inverse_transform( w_in ); + prd->direction = w_in; + prd->origin = P; + + prd->attenuation *= rt_data->diffuse_color; + prd->countEmitted = false; + } + + const float z1 = rnd(seed); + const float z2 = rnd(seed); + prd->seed = seed; + + ParallelogramLight light = params.light; + const float3 light_pos = light.corner + light.v1 * z1 + light.v2 * z2; + + // Calculate properties of light sample (for area based pdf) + const float Ldist = length(light_pos - P ); + const float3 L = normalize(light_pos - P ); + const float nDl = dot( N, L ); + const float LnDl = -dot( light.normal, L ); + + float weight = 0.0f; + if( nDl > 0.0f && LnDl > 0.0f ) + { + const bool occluded = traceOcclusion( + params.handle, + P, + L, + 0.01f, // tmin + Ldist - 0.01f // tmax + ); + + if( !occluded ) + { + const float A = length(cross(light.v1, light.v2)); + weight = nDl * LnDl * A / (M_PIf * Ldist * Ldist); + } + } + + prd->radiance += light.emission * weight; +} + + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/optixMultiGPU.h b/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/optixMultiGPU.h new file mode 100644 index 00000000..567ec2bd --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/optixMultiGPU.h @@ -0,0 +1,87 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +enum RayType +{ + RAY_TYPE_RADIANCE = 0, + RAY_TYPE_OCCLUSION = 1, + RAY_TYPE_COUNT +}; + + +struct ParallelogramLight +{ + float3 corner; + float3 v1, v2; + float3 normal; + float3 emission; +}; + + +struct Params +{ + unsigned int subframe_index; + int2* sample_index_buffer; + float4* sample_accum_buffer; + uchar4* result_buffer; + unsigned int width; + unsigned int height; + unsigned int samples_per_launch; + unsigned int device_idx; + + float3 eye; + float3 U; + float3 V; + float3 W; + + ParallelogramLight light; // TODO: make light list + OptixTraversableHandle handle; +}; + + +struct RayGenData +{ + float r, g, b; +}; + + +struct MissData +{ + float r, g, b; +}; + + +struct HitGroupData +{ + float3 emission_color; + float3 diffuse_color; + float4* vertices; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/optixMultiGPU_kernels.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/optixMultiGPU_kernels.cu new file mode 100644 index 00000000..63d49884 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixMultiGPU/optixMultiGPU_kernels.cu @@ -0,0 +1,65 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sutil/WorkDistribution.h" + +extern "C" __global__ void fillSamples( + int gpu_idx, + int num_gpus, + int width, + int height, + int2* sample_indices ) +{ + StaticWorkDistribution wd; + wd.setRasterSize( width, height ); + wd.setNumGPUs( num_gpus ); + + const int sample_idx = blockIdx.x; + sample_indices[sample_idx] = wd.getSamplePixel( gpu_idx, sample_idx ); +} + + +extern "C" __host__ void fillSamplesCUDA( + int num_samples, + cudaStream_t stream, + int gpu_idx, + int num_gpus, + int width, + int height, + int2* sample_indices ) +{ + fillSamples<<>>( + gpu_idx, + num_gpus, + width, + height, + sample_indices ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/CMakeLists.txt new file mode 100644 index 00000000..e3beccf5 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/CMakeLists.txt @@ -0,0 +1,74 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set_source_files_properties( ${CMAKE_CURRENT_SOURCE_DIR}/optixNVLink_kernels.cu + PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ + ) + +# Under windows, look for nvml.lib in the cuda toolkit, and the the general cuda path +if( WIN32 ) + find_file( NVML_LIBRARY + NO_DEFAULT_PATH + NAMES nvml.lib + PATHS ${CUDA_TOOLKIT_ROOT_DIR}/lib/x64 $ENV{CUDA_PATH}/lib/x64 + ) +endif() + +# Under Unix, look for the libnvidia-ml library +if( UNIX ) + find_library( NVML_LIBRARY libnvidia-ml.so ) +endif() + +# If an NVML library was found, compile using it +if( NVML_LIBRARY ) + set( OPTIX_USE_NVML ON ) +endif() + +# Set the value of OPTIX_USE_NVML in nvml_configure.h +configure_file( nvml_configure.h.in nvml_configure.h ) +include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) + +# Set up source files for executable +OPTIX_add_sample_executable( optixNVLink target_name + ${SAMPLES_CUDA_DIR}/helpers.h + ${SAMPLES_CUDA_DIR}/random.h + optixNVLink_kernels.cu + optixNVLink.cu + optixNVLink.cpp + optixNVLink.h + + ${CMAKE_CURRENT_BINARY_DIR}/nvml_configure.h + ) +set_property( TARGET ${target_name} PROPERTY CUDA_SEPARABLE_COMPILATION ON ) + +# Set up libraries to link in +# Not linking NVML_LIBRARY, since it will be loaded at runtime +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/nvml_configure.h.in b/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/nvml_configure.h.in new file mode 100644 index 00000000..e9e4c310 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/nvml_configure.h.in @@ -0,0 +1,23 @@ +// +// Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// +// NVIDIA Corporation and its licensors retain all intellectual property and proprietary +// rights in and to this software, related documentation and any modifications thereto. +// Any use, reproduction, disclosure or distribution of this software and related +// documentation without an express license agreement from NVIDIA Corporation is strictly +// prohibited. +// +// TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* +// AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, +// INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY +// SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT +// LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF +// BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR +// INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGES +// +// +// + +#cmakedefine01 OPTIX_USE_NVML diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/optixNVLink.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/optixNVLink.cpp new file mode 100644 index 00000000..34a2781a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/optixNVLink.cpp @@ -0,0 +1,2094 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* +Sample Description: + +If mutliple GPUs are present with nvlink, or other peer-to-peer access, between +them, then this connectivity can be used in several ways. This sample +demonstrates two of these: + +Read-only buffers: nvlink capability divides the available GPUs into +nvlink "islands". Since the connection is so fast, some readable resources +can be shared so that one copy is held per island. Typically, these +resources will be spread across the GPUs of an island so that the memory +burden is shared. This sample shares textures so that only one copy is +held per nvlink island. + +The Frame buffer: (1) In the single-GPU case, a gl interop buffer can +be used to avoid data copies to OpenGL for display. (2) When multiple GPUs are +used which are not all nvlink connected, zero-copy memory, which transfers data +through the host, is typically used for the frame buffer. (3) When all of +GPUs reside in a single nvlink island, the link can be used to transfer +frame buffer data so that it does not need to be transferred through the +host. This sample demonstrates all three of these techniques. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include // Needs to be included before gl_interop + +#include +#include + +#include // configured file to tell if we have nvml +#if OPTIX_USE_NVML +#include +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "optixNVLink.h" + +//------------------------------------------------------------------------------ +// +// Variables related to display +// +//------------------------------------------------------------------------------ + +bool resize_dirty = false; +bool minimized = false; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Mouse state +int2 mouse_prev_pos; +int32_t mouse_button = -1; + +int32_t width = 768; +int32_t height = 768; +int32_t samples_per_launch = 8; + +// Output file name (empty means do not output a file) +std::string g_outfile = ""; +int32_t file_launch_frames = 1; + +// How to scale the device color overlay on the image (0 means do not show) +float g_device_color_scale = 1.0f; + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +extern "C" void fillSamplesCUDA( + int32_t num_samples, + cudaStream_t stream, + int32_t gpu_idx, + int32_t num_gpus, + int32_t width, + int32_t height, + int2* samples ); + +//------------------------------------------------------------------------------ +// +// Local types +// +//------------------------------------------------------------------------------ + +template +struct Record +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef Record RayGenRecord; +typedef Record MissRecord; +typedef Record HitGroupRecord; + + +struct Vertex +{ + float x, y, z, pad; +}; + + +struct TexCoord +{ + float s, t; +}; + + +struct IndexedTriangle +{ + uint32_t v1, v2, v3, pad; +}; + + +struct Instance +{ + float transform[12]; +}; + + +struct PerDeviceSampleState +{ + int32_t device_idx = -1; + OptixDeviceContext context = 0; + + OptixTraversableHandle gas_handle = 0; // Traversable handle for triangle AS + CUdeviceptr d_gas_output_buffer = 0; // Triangle AS memory + CUdeviceptr d_vertices = 0; + CUdeviceptr d_tex_coords = 0; + + OptixModule ptx_module = 0; + OptixPipelineCompileOptions pipeline_compile_options = {}; + OptixPipeline pipeline = 0; + + OptixProgramGroup raygen_prog_group = 0; + OptixProgramGroup radiance_miss_group = 0; + OptixProgramGroup occlusion_miss_group = 0; + OptixProgramGroup radiance_hit_group = 0; + OptixProgramGroup occlusion_hit_group = 0; + + OptixShaderBindingTable sbt = {}; + + int32_t num_samples = 0; + int2* d_sample_indices = 0; + float4* d_sample_accum = 0; + + Params params; + Params* d_params; + + CUstream stream = 0; + + uint32_t peers = 0; +}; + + +//------------------------------------------------------------------------------ +// +// Forward declarations +// +//------------------------------------------------------------------------------ + +cudaTextureObject_t getDiffuseTextureObject( int material_id, PerDeviceSampleState& pd_state ); + + +//------------------------------------------------------------------------------ +// +// Load NVML dynamically +// +//------------------------------------------------------------------------------ +#if OPTIX_USE_NVML + +bool g_nvmlLoaded = false; + +#ifdef WIN32 +#define APIFUNC FAR WINAPI +#else +#define APIFUNC +#endif + +typedef nvmlReturn_t (APIFUNC *NVML_INIT_TYPE)(); +NVML_INIT_TYPE nvmlInit_p; + +typedef nvmlReturn_t (APIFUNC *NVML_DEVICE_GET_HANDLE_BY_INDEX_TYPE)( unsigned int, nvmlDevice_t* ); +NVML_DEVICE_GET_HANDLE_BY_INDEX_TYPE nvmlDeviceGetHandleByIndex_p; + +typedef nvmlReturn_t (APIFUNC *NVML_DEVICE_GET_PCI_INFO_TYPE)( nvmlDevice_t, nvmlPciInfo_t* ); +NVML_DEVICE_GET_PCI_INFO_TYPE nvmlDeviceGetPciInfo_p; + +typedef nvmlReturn_t (APIFUNC *NVML_DEVICE_GET_NVLINK_CAPABILITY_TYPE)( nvmlDevice_t, unsigned int, nvmlNvLinkCapability_t, unsigned int* ); +NVML_DEVICE_GET_NVLINK_CAPABILITY_TYPE nvmlDeviceGetNvLinkCapability_p; + +typedef nvmlReturn_t (APIFUNC *NVML_DEVICE_GET_NVLINK_STATE_TYPE)( nvmlDevice_t, unsigned int, nvmlEnableState_t* ); +NVML_DEVICE_GET_NVLINK_STATE_TYPE nvmlDeviceGetNvLinkState_p; + +typedef nvmlReturn_t (APIFUNC *NVML_DEVICE_GET_NVLINK_REMOTE_PCI_INFO_TYPE)( nvmlDevice_t, unsigned int, nvmlPciInfo_t* ); +NVML_DEVICE_GET_NVLINK_REMOTE_PCI_INFO_TYPE nvmlDeviceGetNvLinkRemotePciInfo_p; + +typedef nvmlReturn_t (APIFUNC *NVML_SYSTEM_GET_DRIVER_VERSION_TYPE)( char*, unsigned int ); +NVML_SYSTEM_GET_DRIVER_VERSION_TYPE nvmlSystemGetDriverVersion_p; + +#ifdef WIN32 +void* loadDllHandle( const char* dllName ) +{ + void* dllHandle = optixLoadWindowsDllFromName( dllName ); + return dllHandle; +} + +void* getProcedureAddress( void* dllHandle, const char* funcName ) +{ + void* proc = GetProcAddress( (HMODULE)dllHandle, funcName ); + if ( proc == NULL ) + std::cerr << funcName << " not found\n"; + return proc; +} + +#else +void* loadSharedObjectHandle( const char* soName ) +{ + void* soHandle = dlopen( soName, RTLD_NOW ); + return soHandle; +} + +void* getProcedureAddress( void* handlePtr, const char* funcName ) +{ + void* proc = dlsym( handlePtr, funcName ); + if( !proc ) + std::cerr << funcName << " not found\n"; + return proc; +} +#endif + +static bool loadNvmlFunctions() +{ + // Load the library +#ifdef WIN32 + const char* soName = "nvml.dll"; + void* handle = loadDllHandle( soName ); +#else + const char* soName = "libnvidia-ml.so"; + void* handle = loadSharedObjectHandle( soName ); +#endif + + if ( !handle ) + { + std::cout << "UNABLE TO LOAD " << soName << "\n"; + return false; + } + + // Set the individual _ptions we are using + nvmlInit_p = reinterpret_cast( getProcedureAddress( handle, "nvmlInit" ) ); + nvmlDeviceGetHandleByIndex_p = reinterpret_cast( getProcedureAddress( handle, "nvmlDeviceGetHandleByIndex" ) ); + nvmlDeviceGetPciInfo_p = reinterpret_cast( getProcedureAddress( handle, "nvmlDeviceGetPciInfo" ) ); + nvmlDeviceGetNvLinkCapability_p = reinterpret_cast( getProcedureAddress( handle, "nvmlDeviceGetNvLinkCapability" ) ); + nvmlDeviceGetNvLinkState_p = reinterpret_cast( getProcedureAddress( handle, "nvmlDeviceGetNvLinkState" ) ); + nvmlDeviceGetNvLinkRemotePciInfo_p = reinterpret_cast( getProcedureAddress( handle, "nvmlDeviceGetNvLinkRemotePciInfo" ) ); + nvmlSystemGetDriverVersion_p = reinterpret_cast( getProcedureAddress( handle, "nvmlSystemGetDriverVersion" ) ); + + std::cout << "LOADED " << soName << "\n"; + return true; +} + +#endif // OPTIX_USE_NVML + +//------------------------------------------------------------------------------ +// +// Scene data +// +//------------------------------------------------------------------------------ + +const int32_t TRIANGLE_COUNT = 32; +const int32_t MAT_COUNT = 4; + +const static std::array g_vertices = +{ { + // Floor -- white lambert + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 0.0f, 0.0f }, + + // Ceiling -- white lambert + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + + // Back wall -- white lambert + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + + // Right wall -- green lambert + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + { 0.0f, 0.0f, 559.2f, 0.0f }, + + // Left wall -- red lambert + { 556.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 556.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 0.0f, 0.0f }, + + // Short block -- white lambert + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 242.0f, 165.0f, 274.0f, 0.0f }, + + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 242.0f, 165.0f, 274.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + + { 290.0f, 0.0f, 114.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + + { 290.0f, 0.0f, 114.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + { 240.0f, 0.0f, 272.0f, 0.0f }, + + { 130.0f, 0.0f, 65.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + + { 130.0f, 0.0f, 65.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + { 290.0f, 0.0f, 114.0f, 0.0f }, + + { 82.0f, 0.0f, 225.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + + { 82.0f, 0.0f, 225.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 130.0f, 0.0f, 65.0f, 0.0f }, + + { 240.0f, 0.0f, 272.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + + { 240.0f, 0.0f, 272.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 82.0f, 0.0f, 225.0f, 0.0f }, + + // Tall block -- white lambert + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 314.0f, 330.0f, 455.0f, 0.0f }, + + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 314.0f, 330.0f, 455.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + + { 423.0f, 0.0f, 247.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + + { 423.0f, 0.0f, 247.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + { 472.0f, 0.0f, 406.0f, 0.0f }, + + { 472.0f, 0.0f, 406.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + + { 472.0f, 0.0f, 406.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + { 314.0f, 0.0f, 456.0f, 0.0f }, + + { 314.0f, 0.0f, 456.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + + { 314.0f, 0.0f, 456.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 265.0f, 0.0f, 296.0f, 0.0f }, + + { 265.0f, 0.0f, 296.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + + { 265.0f, 0.0f, 296.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 423.0f, 0.0f, 247.0f, 0.0f }, + + // Ceiling light -- emmissive + { 343.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 332.0f, 0.0f }, + + { 343.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 332.0f, 0.0f }, + { 343.0f, 548.6f, 332.0f, 0.0f } +} }; + + +const static std::array g_tex_coords = +{ { + // Floor -- white lambert + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + // Ceiling -- white lambert + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + // Back wall -- white lambert + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + // Right wall -- green lambert + { 0.0f, 0.0f }, + { 0.0f, 1.0f }, + { 1.0f, 1.0f }, + + { 0.0f, 0.0f }, + { 1.0f, 1.0f }, + { 1.0f, 0.0f }, + + // Left wall -- red lambert + { 0.0f, 0.0f }, + { 1.0f, 0.0f }, + { 1.0f, 1.0f }, + + { 0.0f, 0.0f }, + { 1.0f, 1.0f }, + { 0.0f, 1.0f }, + + + // Short block -- white lambert + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + // Tall block -- white lambert + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + // Ceiling light -- emmissive + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + + { 0.0f, 0.0f }, + { 0.0f, 0.0f }, + { 0.0f, 0.0f } +} }; + + +static std::array g_mat_indices = +{ { + 0, 0, // Floor -- white lambert + 0, 0, // Ceiling -- white lambert + 0, 0, // Back wall -- white lambert + 1, 1, // Right wall -- green lambert + 2, 2, // Left wall -- red lambert + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Short block -- white lambert + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Tall block -- white lambert + 3, 3 // Ceiling light -- emmissive +} }; + + +const std::array g_emission_colors = +{ { + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 15.0f, 15.0f, 5.0f } + +} }; + + +const std::array g_diffuse_colors = +{ { + { 0.80f, 0.80f, 0.80f }, + { 0.05f, 0.80f, 0.05f }, + { 0.80f, 0.05f, 0.05f }, + { 0.50f, 0.00f, 0.00f } +} }; + + +//------------------------------------------------------------------------------ +// +// Texture tracking +// +//------------------------------------------------------------------------------ + +// Materials for which textures will be made +std::array g_make_diffuse_textures = {0, 1, 1, 0}; + +// Backing storage for the textures. These will be shared per +// P2P island when sharing is enabled. +std::array, MAT_COUNT> g_diffuse_texture_data; + +// Texture objects. Each device must have a texture object for +// each texture, but the backing stores can be shared. +std::array, MAT_COUNT> g_diffuse_textures; + +// Texture memory usage per device +std::vector g_device_tex_usage; + +// Kinds of connections between devices to accept as peers +const int PEERS_NONE = 0; +const int PEERS_NVLINK = 1; +const int PEERS_ALL = 2; + +// Configuration decisions +int g_peer_usage = PEERS_NVLINK; +bool g_share_textures = true; +bool g_optimize_framebuffer = true; + +const int TEXTURE_WIDTH = 1024; + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking(static_cast( xpos ), static_cast( ypos )); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), width, height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), width, height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + width = res_x; + height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || + key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + } + else if( key == GLFW_KEY_G ) + { + // toggle UI draw + } +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// +//------------------------------------------------------------------------------ + + +void printUsageAndExit( const char* argv0 ) +{ + std::cout << "Usage : " << argv0 << " [options]\n"; + std::cout << "Options: --launch-samples | -s Number of samples per pixel per launch (default 8)\n"; + std::cout << " --file | -f Output file name\n"; + std::cout << " --launch-frames Number of frames to accumulate when saving an output file (default 1)\n"; + std::cout << " --device-color-scale | -d Device color overlay scale (default 1.0)\n"; + std::cout << " --peers | -p P2P connections to include [none, nvlink, all] (default nvlink)\n"; + std::cout << " --optimize-framebuffer | -o Optimize the framebuffer for speed [true, false] (default true)\n"; + std::cout << " --share-textures | -t Share textures if allowed [true, false] (default true)\n"; + std::cout << " --help | -h Print this usage message\n"; + + exit( 0 ); +} + + +void initCameraState() +{ + camera.setEye( make_float3( 278.0f, 273.0f, -900.0f ) ); + camera.setLookat( make_float3( 278.0f, 273.0f, 330.0f ) ); + camera.setUp( make_float3( 0.0f, 1.0f, 0.0f ) ); + camera.setFovY( 35.0f ); + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( make_float3( 1.0f, 0.0f, 0.0f ), make_float3( 0.0f, 0.0f, 1.0f ), make_float3( 0.0f, 1.0f, 0.0f ) ); + trackball.setGimbalLock(true); +} + + +void initLaunchParams( PerDeviceSampleState& pd_state ) +{ + pd_state.params.subframe_index = 0u; + pd_state.params.width = width; + pd_state.params.height = height; + pd_state.params.samples_per_launch = samples_per_launch; + pd_state.params.device_idx = pd_state.device_idx; + + pd_state.params.light.emission = make_float3( 15.0f, 15.0f, 5.0f ); + pd_state.params.light.corner = make_float3( 343.0f, 548.5f, 227.0f ); + pd_state.params.light.v1 = make_float3( 0.0f, 0.0f, 105.0f ); + pd_state.params.light.v2 = make_float3( -130.0f, 0.0f, 0.0f ); + pd_state.params.light.normal = normalize ( cross( pd_state.params.light.v1, pd_state.params.light.v2) ); + pd_state.params.handle = pd_state.gas_handle; + + pd_state.params.device_color_scale = g_device_color_scale; + + // IO buffers are assigned in allocIOBuffers + CUDA_CHECK( cudaSetDevice( pd_state.device_idx ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &pd_state.d_params), sizeof( Params ) ) ); +} + + +void allocIOBuffers( PerDeviceSampleState& pd_state, int num_gpus ) +{ + StaticWorkDistribution wd; + wd.setRasterSize( width, height ); + wd.setNumGPUs( num_gpus ); + + pd_state.num_samples = wd.numSamples( pd_state.device_idx ); + + // The correct device has been set by the callers of allocIOBuffers + CUDA_CHECK( cudaFree( reinterpret_cast( pd_state.d_sample_indices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pd_state.d_sample_accum ) ) ); + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &pd_state.d_sample_indices ), pd_state.num_samples*sizeof( int2 ) ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &pd_state.d_sample_accum ), pd_state.num_samples*sizeof( float4 ) ) ); + + pd_state.params.sample_index_buffer = pd_state.d_sample_indices; + pd_state.params.sample_accum_buffer = pd_state.d_sample_accum; + pd_state.params.result_buffer = 0; // Managed by CUDAOutputBuffer + + fillSamplesCUDA( + pd_state.num_samples, + pd_state.stream, + pd_state.device_idx, + num_gpus, + width, + height, + pd_state.d_sample_indices + ); +} + + +void handleCameraUpdate( std::vector& pd_states ) +{ + if( !camera_changed ) + return; + camera_changed = false; + + camera.setAspectRatio( static_cast( width ) / static_cast( height ) ); + float3 u, v, w; + camera.UVWFrame( u, v, w ); + + for( PerDeviceSampleState& pd_state : pd_states ) + { + pd_state.params.eye = camera.eye(); + pd_state.params.U = u; + pd_state.params.V = v; + pd_state.params.W = w; + } +} + + +void handleResize( sutil::CUDAOutputBuffer& output_buffer, std::vector& pd_states ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + output_buffer.resize( width, height ); + + // Realloc accumulation buffer + for( PerDeviceSampleState& pd_state : pd_states ) + { + pd_state.params.width = width; + pd_state.params.height = height; + CUDA_CHECK( cudaSetDevice( pd_state.device_idx ) ); + allocIOBuffers( pd_state, static_cast( pd_states.size() ) ); + } +} + + +void updateDeviceStates( sutil::CUDAOutputBuffer& output_buffer, std::vector& pd_states ) +{ + // Update params on devices + if( camera_changed || resize_dirty ) + for( PerDeviceSampleState& pd_state : pd_states ) + pd_state.params.subframe_index = 0; + + handleCameraUpdate( pd_states ); + handleResize( output_buffer, pd_states ); +} + + +void launchSubframe( sutil::CUDAOutputBuffer& output_buffer, std::vector& pd_states ) +{ + uchar4* result_buffer_data = output_buffer.map(); + for( PerDeviceSampleState& pd_state : pd_states ) + { + // Launch + pd_state.params.result_buffer = result_buffer_data; + CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast( pd_state.d_params ), + &pd_state.params, + sizeof( Params ), + cudaMemcpyHostToDevice, + pd_state.stream + ) ); + + CUDA_CHECK( cudaSetDevice( pd_state.device_idx ) ); + OPTIX_CHECK( optixLaunch( + pd_state.pipeline, + pd_state.stream, + reinterpret_cast( pd_state.d_params ), + sizeof( Params ), + &pd_state.sbt, + pd_state.num_samples, // launch width + 1, // launch height + 1 // launch depth + ) ); + } + output_buffer.unmap(); + for( PerDeviceSampleState& pd_state : pd_states ) + { + CUDA_CHECK( cudaSetDevice( pd_state.device_idx ) ); + CUDA_SYNC_CHECK(); + } +} + + +void displaySubframe( + sutil::CUDAOutputBuffer& output_buffer, + sutil::GLDisplay& gl_display, + GLFWwindow* window ) +{ + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + + GLuint pbo = output_buffer.getPBO(); + gl_display.display( width, height, framebuf_res_x, framebuf_res_y, pbo ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + + +void createContext( PerDeviceSampleState& pd_state ) +{ + // Initialize CUDA on this device + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cuCtx = 0; // zero means take the current context + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + + pd_state.context = context; + + CUDA_CHECK( cudaStreamCreate( &pd_state.stream ) ); +} + + +void createContexts( std::vector& pd_state ) +{ + OPTIX_CHECK( optixInit() ); + + int32_t device_count = 0; + CUDA_CHECK( cudaGetDeviceCount( &device_count ) ); + pd_state.resize( device_count ); + std::cout << "TOTAL VISIBLE GPUs: " << device_count << std::endl; + + cudaDeviceProp prop; + for( int i = 0; i < device_count; ++i ) + { + // note: the device index must be the same as the position in the state vector + pd_state[i].device_idx = i; + CUDA_CHECK( cudaGetDeviceProperties( &prop, i ) ); + CUDA_CHECK( cudaSetDevice( i ) ); + std::cout << "GPU [" << i << "]: " << prop.name << std::endl; + + createContext( pd_state[i] ); + } +} + +void uploadAdditionalShadingData( PerDeviceSampleState& pd_state ) +{ + // texture coordinates + const size_t tex_coords_size_in_bytes = g_tex_coords.size() * sizeof( TexCoord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &pd_state.d_tex_coords ), tex_coords_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( pd_state.d_tex_coords ), + g_tex_coords.data(), + tex_coords_size_in_bytes, + cudaMemcpyHostToDevice + ) ); +} + + +void buildMeshAccel( PerDeviceSampleState& pd_state ) +{ + // + // copy mesh data to device + // + const size_t vertices_size_in_bytes = g_vertices.size() * sizeof( Vertex ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &pd_state.d_vertices ), vertices_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( pd_state.d_vertices ), + g_vertices.data(), + vertices_size_in_bytes, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr d_mat_indices = 0; + const size_t mat_indices_size_in_bytes = g_mat_indices.size() * sizeof( uint32_t ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_mat_indices ), + mat_indices_size_in_bytes + ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_mat_indices), + g_mat_indices.data(), + mat_indices_size_in_bytes, + cudaMemcpyHostToDevice + ) ); + + // + // Build triangle GAS + // + uint32_t triangle_input_flags[MAT_COUNT] = + { + // One per SBT record for this build input + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT + }; + + OptixBuildInput triangle_input = {}; + triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangle_input.triangleArray.vertexStrideInBytes = sizeof( Vertex ); + triangle_input.triangleArray.numVertices = static_cast( g_vertices.size() ); + triangle_input.triangleArray.vertexBuffers = &pd_state.d_vertices; + triangle_input.triangleArray.flags = triangle_input_flags; + triangle_input.triangleArray.numSbtRecords = MAT_COUNT; + triangle_input.triangleArray.sbtIndexOffsetBuffer = d_mat_indices; + triangle_input.triangleArray.sbtIndexOffsetSizeInBytes = sizeof(uint32_t); + triangle_input.triangleArray.sbtIndexOffsetStrideInBytes = sizeof(uint32_t); + + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( + pd_state.context, + &accel_options, + &triangle_input, + 1, // num_build_inputs + &gas_buffer_sizes + ) ); + + CUdeviceptr d_temp_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 + ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( (char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( pd_state.context, + 0, // CUDA stream + &accel_options, + &triangle_input, + 1, // num build inputs + d_temp_buffer, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &pd_state.gas_handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_mat_indices ) ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, (void*)emitProperty.result, sizeof(size_t), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &pd_state.d_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( pd_state.context, 0, pd_state.gas_handle, pd_state.d_gas_output_buffer, + compacted_gas_size, &pd_state.gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + pd_state.d_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } +} + + +void createModule( PerDeviceSampleState& pd_state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + pd_state.pipeline_compile_options.usesMotionBlur = false; + pd_state.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + pd_state.pipeline_compile_options.numPayloadValues = 2; + pd_state.pipeline_compile_options.numAttributeValues = 2; + pd_state.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; // should be OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW; + pd_state.pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixNVLink.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( + pd_state.context, + &module_compile_options, + &pd_state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &pd_state.ptx_module + ) ); +} + + +void createProgramGroups( PerDeviceSampleState& pd_state ) +{ + OptixProgramGroupOptions program_group_options = {}; + + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = pd_state.ptx_module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + pd_state.context, + &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &pd_state.raygen_prog_group + ) ); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = pd_state.ptx_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__radiance"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + pd_state.context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &pd_state.radiance_miss_group + ) ); + + memset( &miss_prog_group_desc, 0, sizeof( OptixProgramGroupDesc ) ); + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = nullptr; // NULL miss program for occlusion rays + miss_prog_group_desc.miss.entryFunctionName = nullptr; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + pd_state.context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &pd_state.occlusion_miss_group + ) ); + + OptixProgramGroupDesc hit_prog_group_desc = {}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = pd_state.ptx_module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__radiance"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + pd_state.context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &pd_state.radiance_hit_group + ) ); + + memset( &hit_prog_group_desc, 0, sizeof( OptixProgramGroupDesc ) ); + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = pd_state.ptx_module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__occlusion"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + pd_state.context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &pd_state.occlusion_hit_group + ) ); + +} + + +void createPipeline( PerDeviceSampleState& pd_state ) +{ + const uint32_t max_trace_depth = 2; + + OptixProgramGroup program_groups[] = + { + pd_state.raygen_prog_group, + pd_state.radiance_miss_group, + pd_state.occlusion_miss_group, + pd_state.radiance_hit_group, + pd_state.occlusion_hit_group + }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + + OPTIX_CHECK_LOG( optixPipelineCreate( + pd_state.context, + &pd_state.pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &pd_state.pipeline + ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, pd_state.pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( pd_state.pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + ) ); +} + + +void createSBT( PerDeviceSampleState& pd_state ) +{ + CUdeviceptr d_raygen_record; + const size_t raygen_record_size = sizeof( RayGenRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_raygen_record ), raygen_record_size ) ); + + RayGenRecord rg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( pd_state.raygen_prog_group, &rg_sbt ) ); + rg_sbt.data = {1.0f, 0.f, 0.f}; + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_raygen_record ), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + + + CUdeviceptr d_miss_records; + const size_t miss_record_size = sizeof( MissRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_miss_records ), miss_record_size*RAY_TYPE_COUNT ) ); + + MissRecord ms_sbt[2]; + OPTIX_CHECK( optixSbtRecordPackHeader( pd_state.radiance_miss_group, &ms_sbt[0] ) ); + ms_sbt[0].data = {0.0f, 0.0f, 0.0f}; + OPTIX_CHECK( optixSbtRecordPackHeader( pd_state.occlusion_miss_group, &ms_sbt[1] ) ); + ms_sbt[1].data = {0.0f, 0.0f, 0.0f}; + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_miss_records ), + ms_sbt, + miss_record_size*RAY_TYPE_COUNT, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr d_hitgroup_records; + const size_t hitgroup_record_size = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_hitgroup_records ), + hitgroup_record_size*RAY_TYPE_COUNT*MAT_COUNT + ) ); + HitGroupRecord hitgroup_records[ RAY_TYPE_COUNT*MAT_COUNT ]; + + for( int i = 0; i < MAT_COUNT; ++i ) + { + { + const int sbt_idx = i*RAY_TYPE_COUNT+0; // SBT for radiance ray-type for ith material + + OPTIX_CHECK( optixSbtRecordPackHeader( pd_state.radiance_hit_group, &hitgroup_records[sbt_idx] ) ); + hitgroup_records[ sbt_idx ].data.emission_color = g_emission_colors[i]; + hitgroup_records[ sbt_idx ].data.diffuse_color = g_diffuse_colors[i]; + hitgroup_records[ sbt_idx ].data.vertices = reinterpret_cast(pd_state.d_vertices); + hitgroup_records[ sbt_idx ].data.tex_coords = reinterpret_cast(pd_state.d_tex_coords); + hitgroup_records[ sbt_idx ].data.diffuse_texture = getDiffuseTextureObject( i, pd_state ); + } + + { + const int sbt_idx = i*RAY_TYPE_COUNT+1; // SBT for occlusion ray-type for ith material + memset( &hitgroup_records[sbt_idx], 0, hitgroup_record_size ); + + OPTIX_CHECK( optixSbtRecordPackHeader( pd_state.occlusion_hit_group, &hitgroup_records[sbt_idx] ) ); + } + } + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_hitgroup_records ), + hitgroup_records, + hitgroup_record_size*RAY_TYPE_COUNT*MAT_COUNT, + cudaMemcpyHostToDevice + ) ); + + pd_state.sbt.raygenRecord = d_raygen_record; + pd_state.sbt.missRecordBase = d_miss_records; + pd_state.sbt.missRecordStrideInBytes = static_cast( miss_record_size ); + pd_state.sbt.missRecordCount = RAY_TYPE_COUNT; + pd_state.sbt.hitgroupRecordBase = d_hitgroup_records; + pd_state.sbt.hitgroupRecordStrideInBytes = static_cast( hitgroup_record_size ); + pd_state.sbt.hitgroupRecordCount = RAY_TYPE_COUNT*MAT_COUNT; +} + + +void cleanupState( PerDeviceSampleState& pd_state ) +{ + OPTIX_CHECK( optixPipelineDestroy ( pd_state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( pd_state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( pd_state.radiance_miss_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( pd_state.radiance_hit_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( pd_state.occlusion_hit_group ) ); + OPTIX_CHECK( optixModuleDestroy ( pd_state.ptx_module ) ); + OPTIX_CHECK( optixDeviceContextDestroy( pd_state.context ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( pd_state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pd_state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pd_state.sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pd_state.d_vertices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pd_state.d_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pd_state.d_sample_indices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pd_state.d_sample_accum ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pd_state.d_params ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( pd_state.d_tex_coords ) ) ); +} + + +//------------------------------------------------------------------------------ +// +// Texture management functions +// +//------------------------------------------------------------------------------ + +void destroyTextures( std::vector& pd_states ) +{ + for( int i = 0; i < static_cast( pd_states.size() ); ++i ) + { + int device_idx = pd_states[i].device_idx; + CUDA_CHECK( cudaSetDevice( device_idx ) ); + for( int material_id = 0; material_id < MAT_COUNT; ++material_id ) + { + if( g_diffuse_textures[material_id][device_idx] != 0 ) + CUDA_CHECK( cudaDestroyTextureObject( g_diffuse_textures[material_id][device_idx] ) ); + + if( g_diffuse_texture_data[material_id][device_idx] != 0 ) + CUDA_CHECK( cudaFreeArray( g_diffuse_texture_data[material_id][device_idx] ) ); + } + } +} + + +cudaTextureObject_t getDiffuseTextureObject( int material_id, PerDeviceSampleState& pd_state ) +{ + // If the device has a texture on it, use that one + int device_idx = pd_state.device_idx; + if( g_diffuse_textures[material_id][device_idx] != 0 ) + return g_diffuse_textures[material_id][device_idx]; + + // Otherwise, try to find a texture on the same island as the device + + int island = pd_state.peers | ( 1 << device_idx ); + size_t num_devices = g_diffuse_textures[material_id].size(); + for( int peer_id = 0; peer_id < static_cast( num_devices ); ++peer_id ) + { + bool peer_in_island = ( island & ( 1 << peer_id ) ) != 0; + bool texture_exists_on_peer = ( g_diffuse_textures[material_id][peer_id] != 0 ); + + if( peer_in_island && texture_exists_on_peer ) + return g_diffuse_textures[material_id][peer_id]; + } + + return 0; +} + + +void createTextureImageOnHost( float4* image_data, int width, int height, int material_id ) +{ + int tiles_per_side = 8; + + for( int j = 0; j < height; j++ ) + { + for( int i = 0; i < width; i++ ) + { + // texture coordinates of pixel + float s = i / (float)width; + float t = j / (float)height; + + // texture coordinates within the current tile + float ss = ( s * tiles_per_side ) - static_cast( s * tiles_per_side ); + float tt = ( t * tiles_per_side ) - static_cast( t * tiles_per_side ); + + // use L-norm distance from center of tile to vary shape + float n = material_id + 0.1f; // L-norm + float d = powf( powf( fabs( ss - 0.5f ), n ) + powf( fabs( tt - 0.5f ), n ), 1.0f / n ) * 2.03f; + d = ( d < 1.0f ) ? 1.0f - powf( d, 80.0f ) : 0.0f; + + image_data[j * width + i] = {d * s, d * t, 0.3f * ( 1.0f - d ), 0.0f}; + } + } +} + + +cudaTextureObject_t defineTextureOnDevice( int device_idx, cudaArray_t tex_array, int tex_width, int tex_height ) +{ + CUDA_CHECK( cudaSetDevice( device_idx ) ); + + cudaResourceDesc res_desc; + std::memset( &res_desc, 0, sizeof( cudaResourceDesc ) ); + res_desc.resType = cudaResourceTypeArray; + res_desc.res.array.array = tex_array; + + cudaTextureDesc tex_desc; + std::memset( &tex_desc, 0, sizeof( cudaTextureDesc ) ); + tex_desc.addressMode[0] = cudaAddressModeClamp; + tex_desc.addressMode[1] = cudaAddressModeClamp; + tex_desc.filterMode = cudaFilterModeLinear; + tex_desc.readMode = cudaReadModeElementType; + tex_desc.normalizedCoords = 1; + + cudaResourceViewDesc* res_view_desc = nullptr; + + cudaTextureObject_t tex; + CUDA_CHECK( cudaCreateTextureObject( &tex, &res_desc, &tex_desc, res_view_desc ) ); + + return tex; +} + + +float loadTextureOnDevice( int mat_index, int device_idx ) +{ + std::cout << "LOADING TEXTURE: material " << mat_index << " on device " << device_idx << ".\n"; + CUDA_CHECK( cudaSetDevice( device_idx ) ); + + cudaChannelFormatDesc channel_desc = cudaCreateChannelDesc( 32, 32, 32, 32, cudaChannelFormatKindFloat ); + + const int tex_width = TEXTURE_WIDTH; + int tex_height = tex_width; + CUDA_CHECK( cudaMallocArray( &g_diffuse_texture_data[mat_index][device_idx], &channel_desc, tex_width, tex_height ) ); + + std::vector h_texture_data( tex_width * tex_height ); + createTextureImageOnHost( h_texture_data.data(), tex_width, tex_height, mat_index ); + int width_in_bytes = tex_width * sizeof( float4 ); + int pitch = width_in_bytes; + CUDA_CHECK( cudaMemcpy2DToArray( g_diffuse_texture_data[mat_index][device_idx], 0, 0, h_texture_data.data(), pitch, + width_in_bytes, tex_height, cudaMemcpyHostToDevice ) ); + + g_diffuse_textures[mat_index][device_idx] = + defineTextureOnDevice( device_idx, g_diffuse_texture_data[mat_index][device_idx], tex_width, tex_height ); + + float tex_mem_usage = static_cast( tex_width * tex_height * sizeof( float4 ) ); + return tex_mem_usage; +} + + +int getIslandDeviceWithLowestTextureUsage( int island ) +{ + int min_device_id = 0; + float min_device_usage = FLT_MAX; + + int device_idx = 0; + while( ( 1 << device_idx ) <= island ) + { + bool device_in_island = ( island & ( 1 << device_idx ) ) != 0; + bool mem_usage_lower = g_device_tex_usage[device_idx] < min_device_usage; + + if( device_in_island && mem_usage_lower ) + { + min_device_usage = g_device_tex_usage[device_idx]; + min_device_id = device_idx; + } + device_idx++; + } + + return min_device_id; +} + + +float loadTexture( std::vector& pd_states, std::vector& p2p_islands, int mat_index ) +{ + bool share_per_island = ( g_peer_usage != PEERS_NONE && g_share_textures ); + float tex_mem = 0.0f; + + if( share_per_island == true ) + { + // Load the texture on one of the devices + for( int i = 0; i < static_cast( p2p_islands.size() ); ++i ) + { + int device_idx = getIslandDeviceWithLowestTextureUsage( p2p_islands[i] ); + float tex_size = loadTextureOnDevice( mat_index, device_idx ); + g_device_tex_usage[device_idx] += tex_size; + tex_mem += tex_size; + + // Make texture samplers for each device in the island, but reuse the data array + int island = p2p_islands[i]; + int peer_idx = 0; + cudaArray_t tex_array = g_diffuse_texture_data[mat_index][device_idx]; + while( ( 1 << peer_idx ) <= island ) + { + // If peer_idx is a peer of device_idx + if ( (peer_idx != device_idx) && (island & (1 << peer_idx)) ) + { + g_diffuse_textures[mat_index][peer_idx] = + defineTextureOnDevice( peer_idx, tex_array, TEXTURE_WIDTH, TEXTURE_WIDTH ); + + } + peer_idx++; + } + } + } + else + { + for( int i = 0; i < static_cast( pd_states.size() ); ++i ) + { + int device_idx = pd_states[i].device_idx; + float tex_size = loadTextureOnDevice( mat_index, device_idx ); + g_device_tex_usage[device_idx] += tex_size; + tex_mem += tex_size; + } + } + + return tex_mem; +} + + +void loadTextures( std::vector& pd_states, std::vector& p2p_islands ) +{ + size_t num_devices = pd_states.size(); + g_device_tex_usage.resize( num_devices, 0.0f ); + float total_tex_mem = 0.0f; + + for( int mat_index = 0; mat_index < MAT_COUNT; ++mat_index ) + { + g_diffuse_texture_data[mat_index].resize( num_devices, 0 ); + g_diffuse_textures[mat_index].resize( num_devices, 0 ); + + // If a texture is required for this material, make it + if( g_make_diffuse_textures[mat_index] ) + { + total_tex_mem += loadTexture( pd_states, p2p_islands, mat_index ); + } + } + + std::cout << "TEXTURE MEMORY USAGE: " << (total_tex_mem / (1<<20)) << " MB\n"; +} + + +//------------------------------------------------------------------------------ +// +// P2P / NVLINK functions +// +//------------------------------------------------------------------------------ + +int getGlInteropDeviceId( int num_devices ) +{ + for ( int device_idx=0; device_idx < num_devices; ++device_idx ) + { + int is_display_device = 0; + CUDA_CHECK( cudaDeviceGetAttribute( &is_display_device, cudaDevAttrKernelExecTimeout, device_idx ) ); + if (is_display_device) + { + std::cout << "DISPLAY DEVICE: " << device_idx << "\n"; + return device_idx; + } + } + + std::cerr << "ERROR: Could not determine GL interop device\n"; + return -1; +} + + +void enablePeerAccess( std::vector& pd_states ) +{ + size_t num_devices = pd_states.size(); + for( int device_idx = 0; device_idx < static_cast( num_devices ); ++device_idx ) + { + CUDA_CHECK( cudaSetDevice( device_idx ) ); + for( int peer_idx = 0; peer_idx < static_cast( num_devices ); ++peer_idx ) + { + if (peer_idx == device_idx) + continue; + + int access = 0; + CUDA_CHECK( cudaDeviceCanAccessPeer(&access, device_idx, peer_idx) ); + if (access) + CUDA_CHECK( cudaDeviceEnablePeerAccess( peer_idx, 0 ) ); + } + } +} + + +void shutdownPeerAccess( std::vector& pd_states ) +{ + size_t num_devices = pd_states.size(); + for( int device_idx = 0; device_idx < static_cast( num_devices ); ++device_idx ) + { + CUDA_CHECK( cudaSetDevice( device_idx ) ); + for( int peer_idx = 0; peer_idx < static_cast( num_devices ); ++peer_idx ) + { + if (peer_idx == device_idx) + continue; + + int access = 0; + CUDA_CHECK( cudaDeviceCanAccessPeer(&access, device_idx, peer_idx) ); + if (access) + CUDA_CHECK( cudaDeviceDisablePeerAccess( peer_idx ) ); + } + } +} + + +#if OPTIX_USE_NVML +nvmlDevice_t getNvmlDeviceHandle( PerDeviceSampleState& pd_state ) +{ + nvmlDevice_t device = nullptr; + nvmlReturn_t result = nvmlDeviceGetHandleByIndex_p( pd_state.device_idx, &device ); + if( result != NVML_SUCCESS ) + std::cerr << "Could not get device handle for index " << pd_state.device_idx << "\n"; + return device; +} +#endif + +#if OPTIX_USE_NVML +std::string getPciBusId( PerDeviceSampleState& pd_state ) +{ + nvmlDevice_t device = getNvmlDeviceHandle( pd_state ); + if( device == nullptr ) + return ""; + + nvmlPciInfo_t pci_info; + memset( &pci_info, 0, sizeof( pci_info ) ); + nvmlReturn_t result = nvmlDeviceGetPciInfo_p( device, &pci_info ); + if( NVML_SUCCESS != result ) + return ""; + + return std::string( pci_info.busId ); +} +#endif + +void printIsland( int island ) +{ + std::cout << "{"; + int device_idx = 0; + while ( (1<& pd_states, std::vector& islands ) +{ + std::cout << "P2P ISLANDS: "; + islands.clear(); + for( int i = 0; i < static_cast( pd_states.size() ); ++i ) + { + int island = pd_states[i].peers | ( 1 << pd_states[i].device_idx ); + if( std::find( islands.begin(), islands.end(), island ) == islands.end() ) + { + islands.push_back( island ); + printIsland( island ); + } + } + std::cout << "\n"; +} + +void findPeersForDevice( std::vector& pd_states, int device_idx, bool require_nvlink ) +{ + +#if OPTIX_USE_NVML + // Clear the set of peers for the current device + pd_states[device_idx].peers = 0; + + nvmlReturn_t result; + nvmlDevice_t device = getNvmlDeviceHandle( pd_states[device_idx] ); + std::string pci_bus_id = getPciBusId( pd_states[device_idx] ); + + // Check each link + for( unsigned int link = 0; link < NVML_NVLINK_MAX_LINKS; ++link ) + { + // Check if P2P is supported on this link + unsigned int capResult = 0; + result = nvmlDeviceGetNvLinkCapability_p( device, link, NVML_NVLINK_CAP_P2P_SUPPORTED, &capResult ); + if( result != NVML_SUCCESS || capResult == 0 ) + continue; + + // Check if NVLINK is active on this link (if required) + if( require_nvlink ) + { + nvmlEnableState_t isActive = NVML_FEATURE_DISABLED; + result = nvmlDeviceGetNvLinkState_p( device, link, &isActive ); + if( result != NVML_SUCCESS || isActive != NVML_FEATURE_ENABLED ) + continue; + } + + // Check if we're connected to another device on this link + nvmlPciInfo_t pci = {{0}}; + result = nvmlDeviceGetNvLinkRemotePciInfo_p( device, link, &pci ); + if( result != NVML_SUCCESS ) + continue; + + + // Find neighbors with the same id as the device we are connected to + // and add them as peers + std::string pci_id( pci.busId ); + bool found = false; + for( int i = 0; i < static_cast( pd_states.size() ); ++i ) + { + std::string peerPciId = getPciBusId( pd_states[i] ); + if( std::string( pci.busId ) == pci_id ) + { + int peer_idx = pd_states[i].device_idx; + pd_states[device_idx].peers |= ( 1 << peer_idx ); + found = true; + //break; + } + } + if( !found ) + std::cerr << "Unable to locate device with id " << pci_id << " in active devices.\n"; + } + +#else + if ( require_nvlink == true && device_idx == 0 ) + std::cout << "NVML NOT SUPPORTED. Cannot query nvlink. Treating all P2P connections as nvlink.\n"; + + size_t num_devices = pd_states.size(); + CUDA_CHECK( cudaSetDevice( device_idx ) ); + for( int peer_idx = 0; peer_idx < static_cast( num_devices ); ++peer_idx ) + { + if( peer_idx == device_idx ) + continue; + + int access = 0; + CUDA_CHECK( cudaDeviceCanAccessPeer( &access, device_idx, peer_idx ) ); + if ( access ) + pd_states[device_idx].peers |= ( 1 << peer_idx ); + } +#endif + +} + + +void findPeers( std::vector& pd_states, bool require_nvlink ) +{ + for( int i = 0; i < static_cast( pd_states.size() ); ++i ) + findPeersForDevice( pd_states, i, require_nvlink ); +} + + +#if OPTIX_USE_NVML +void initializeNvml() +{ + CUDA_CHECK( cudaFree( 0 ) ); // Make sure cuda is initialized first + nvmlReturn_t result = nvmlInit_p(); + + if( result != NVML_SUCCESS ) + std::cerr << "ERROR: nvmlInit() failed (code " << result << ")\n"; + + char buff[1024]; + result = nvmlSystemGetDriverVersion_p( buff, 1024 ); + + if( result == NVML_SUCCESS ) + std::cout << "DRIVER VERSION: " << buff << "\n"; + else + std::cerr << "ERROR: Unable to get driver version (code " << result << ")\n"; +} +#endif + + +//------------------------------------------------------------------------------ +// +// Main +// +//------------------------------------------------------------------------------ + +void parseCommandLine( int argc, char* argv[] ) +{ + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + g_outfile = argv[++i]; + } + else if( arg == "--launch-samples" || arg == "-s" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + samples_per_launch = atoi( argv[++i] ); + } + else if( arg == "--launch-frames" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + file_launch_frames = max( 1, atoi( argv[++i] ) ); + } + else if( arg == "--device-color-scale" || arg == "-d" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + g_device_color_scale = static_cast( atof( argv[++i] ) ); + } + else if ( arg == "--peers" || arg == "-p" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + + const std::string arg1 = argv[++i]; + if (arg1 == "none") + g_peer_usage = PEERS_NONE; + else if (arg1 == "nvlink") + g_peer_usage = PEERS_NVLINK; + else if (arg1 == "all") + g_peer_usage = PEERS_ALL; + else + printUsageAndExit( argv[0] ); + } + else if ( arg == "--optimize-framebuffer" || arg == "-o" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + + const std::string arg1 = argv[++i]; + if (arg1 == "false") + g_optimize_framebuffer = false; + else if (arg1 == "true") + g_optimize_framebuffer = true; + else + printUsageAndExit( argv[0] ); + } + else if ( arg == "--share-textures" || arg == "-t" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + + const std::string arg1 = argv[++i]; + if (arg1 == "false") + g_share_textures = false; + else if (arg1 == "true") + g_share_textures = true; + else + printUsageAndExit( argv[0] ); + } + else + { + std::cerr << "ERROR: Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } +} + + +int main( int argc, char* argv[] ) +{ + parseCommandLine( argc, argv ); + + try + { +#if OPTIX_USE_NVML + g_nvmlLoaded = loadNvmlFunctions(); + if ( g_nvmlLoaded ) + initializeNvml(); +#endif + + // + // Set up per-device render states + // + std::vector pd_states; + createContexts( pd_states ); + + // + // Determine P2P topology, and load textures accordingly + // + if (g_peer_usage != PEERS_NONE) + { + enablePeerAccess( pd_states ); + bool require_nvlink = (g_peer_usage == PEERS_NVLINK); + findPeers( pd_states, require_nvlink ); + } + std::vector p2p_islands; + computeP2PIslands( pd_states, p2p_islands ); + loadTextures( pd_states, p2p_islands ); + + // + // Set up OptiX state + // + for( PerDeviceSampleState& pd_state : pd_states ) + { + CUDA_CHECK( cudaSetDevice( pd_state.device_idx ) ); + uploadAdditionalShadingData( pd_state ); + buildMeshAccel ( pd_state ); + createModule ( pd_state ); + createProgramGroups( pd_state ); + createPipeline ( pd_state ); + createSBT ( pd_state ); + allocIOBuffers ( pd_state, static_cast( pd_states.size() ) ); + } + + for( PerDeviceSampleState& pd_state : pd_states ) + { + initLaunchParams( pd_state ); + } + + initCameraState(); + GLFWwindow* window = nullptr; + + // + // If the output file is empty, go into interactive mode + // + if( g_outfile == "" ) + { + // Set up GUI and callbacks + window = sutil::initUI( "optixNVLink", width, height ); + glfwSetMouseButtonCallback ( window, mouseButtonCallback ); + glfwSetCursorPosCallback ( window, cursorPosCallback ); + glfwSetWindowSizeCallback ( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback ( window, keyCallback ); + + int gl_interop_device = getGlInteropDeviceId( static_cast( pd_states.size() ) ); + + // Decide on the frame buffer type. Use ZERO_COPY memory as a default, + // which copies the frame buffer data through pinned host memory. + sutil::CUDAOutputBufferType buff_type = sutil::CUDAOutputBufferType::ZERO_COPY; + + // When using a single GPU that is also the gl interop device, render directly + // into a gl interop buffer, avoiding copies. + if ( g_optimize_framebuffer && pd_states.size() == 1 && gl_interop_device == 0 ) + { + buff_type = sutil::CUDAOutputBufferType::GL_INTEROP; + } + + // If using multiple GPUs are fully connected (and one of them is the + // gl interop device) use a device-side buffer to avoid copying to host and back. + // Note that it can't render directly into a gl interop buffer in the multi-GPU case. + else if ( g_optimize_framebuffer && p2p_islands.size() == 1 && ((1< output_buffer( buff_type, width, height ); + int output_device = (gl_interop_device >= 0) ? gl_interop_device : 0; + output_buffer.setDevice( output_device ); + sutil::GLDisplay gl_display; + + // Timing variables + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + // Render loop + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + updateDeviceStates( output_buffer, pd_states ); + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + launchSubframe( output_buffer, pd_states ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1-t0; + + sutil::displayStats( state_update_time, render_time, display_time ); + + glfwSwapBuffers(window); + + for( PerDeviceSampleState& pd_state : pd_states ) + ++pd_state.params.subframe_index; + + } while( !glfwWindowShouldClose( window ) ); + + // Make sure all of the CUDA streams finish + for( PerDeviceSampleState& pd_state : pd_states ) + { + CUDA_CHECK( cudaSetDevice( pd_state.device_idx ) ); + CUDA_SYNC_CHECK(); + } + } + + // + // If an output file was named, render and save + // + else + { + sutil::CUDAOutputBuffer output_buffer( sutil::CUDAOutputBufferType::ZERO_COPY, width, height ); + output_buffer.setDevice( 0 ); + + updateDeviceStates( output_buffer, pd_states ); + for( int i = 0; i < file_launch_frames; ++i ) + { + updateDeviceStates( output_buffer, pd_states ); + launchSubframe( output_buffer, pd_states ); + for( PerDeviceSampleState& pd_state : pd_states ) + ++pd_state.params.subframe_index; + } + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + sutil::saveImage( g_outfile.c_str(), buffer, false ); + } + + // + // Clean up resources + // + if ( window ) + sutil::cleanupUI( window ); + destroyTextures( pd_states ); + if (g_peer_usage != PEERS_NONE) + shutdownPeerAccess( pd_states ); + for( PerDeviceSampleState& pd_state : pd_states ) + cleanupState( pd_state ); + + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/optixNVLink.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/optixNVLink.cu new file mode 100644 index 00000000..02333950 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/optixNVLink.cu @@ -0,0 +1,431 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define OPTIX_COMPATIBILITY 7 +#include + +#include "optixNVLink.h" +#include +#include +#include + +extern "C" { +__constant__ Params params; +} + + +//------------------------------------------------------------------------------ +// +// Per ray data, and getting at it +// +//------------------------------------------------------------------------------ + +// Per-ray data for radiance rays +struct RadiancePRD +{ + float3 emitted; + float3 radiance; + float3 attenuation; + float3 origin; + float3 direction; + unsigned int seed; + int countEmitted; + int done; + int pad; +}; + +static __forceinline__ __device__ void* unpackPointer( unsigned int i0, unsigned int i1 ) +{ + const unsigned long long uptr = static_cast( i0 ) << 32 | i1; + void* ptr = reinterpret_cast( uptr ); + return ptr; +} + + +static __forceinline__ __device__ void packPointer( void* ptr, unsigned int& i0, unsigned int& i1 ) +{ + const unsigned long long uptr = reinterpret_cast( ptr ); + i0 = uptr >> 32; + i1 = uptr & 0x00000000ffffffff; +} + + +static __forceinline__ __device__ RadiancePRD* getPRD() +{ + const unsigned int u0 = optixGetPayload_0(); + const unsigned int u1 = optixGetPayload_1(); + return reinterpret_cast( unpackPointer( u0, u1 ) ); +} + + +// Per-ray data for occlusion rays +static __forceinline__ __device__ void setPayloadOcclusion( bool occluded ) +{ + optixSetPayload_0( static_cast( occluded ) ); +} + + +//------------------------------------------------------------------------------ +// +// Sampling and color +// +//------------------------------------------------------------------------------ + +struct Onb +{ + __forceinline__ __device__ Onb(const float3& normal) + { + m_normal = normal; + + if( fabs(m_normal.x) > fabs(m_normal.z) ) + { + m_binormal.x = -m_normal.y; + m_binormal.y = m_normal.x; + m_binormal.z = 0; + } + else + { + m_binormal.x = 0; + m_binormal.y = -m_normal.z; + m_binormal.z = m_normal.y; + } + + m_binormal = normalize(m_binormal); + m_tangent = cross( m_binormal, m_normal ); + } + + __forceinline__ __device__ void inverse_transform(float3& p) const + { + p = p.x*m_tangent + p.y*m_binormal + p.z*m_normal; + } + + float3 m_tangent; + float3 m_binormal; + float3 m_normal; +}; + + +static __forceinline__ __device__ void cosine_sample_hemisphere(const float u1, const float u2, float3& p) +{ + // Uniformly sample disk. + const float r = sqrtf( u1 ); + const float phi = 2.0f*M_PIf * u2; + p.x = r * cosf( phi ); + p.y = r * sinf( phi ); + + // Project up to hemisphere. + p.z = sqrtf( fmaxf( 0.0f, 1.0f - p.x*p.x - p.y*p.y ) ); +} + + +__forceinline__ __device__ float3 deviceColor( unsigned int idx ) +{ + return make_float3( + idx == 0 ? 0.05f : 0.0f, + idx == 1 ? 0.05f : 0.0f, + idx == 2 ? 0.05f : 0.0f + ); +} + + +//------------------------------------------------------------------------------ +// +// Tracing rays +// +//------------------------------------------------------------------------------ + +static __forceinline__ __device__ void traceRadiance( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax, + RadiancePRD* prd + ) +{ + unsigned int u0, u1; + packPointer( prd, u0, u1 ); + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 255 ), + OPTIX_RAY_FLAG_NONE, + RAY_TYPE_RADIANCE, // SBT offset + RAY_TYPE_COUNT, // SBT stride + RAY_TYPE_RADIANCE, // missSBTIndex + u0, u1 ); +} + + +static __forceinline__ __device__ bool traceOcclusion( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax + ) +{ + unsigned int occluded = 0u; + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 255 ), + OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT, + RAY_TYPE_OCCLUSION, // SBT offset + RAY_TYPE_COUNT, // SBT stride + RAY_TYPE_OCCLUSION, // missSBTIndex + occluded ); + return occluded; +} + + +//------------------------------------------------------------------------------ +// +// Optix Programs +// +//------------------------------------------------------------------------------ + +extern "C" __global__ void __raygen__rg() +{ + const int w = params.width; + const int h = params.height; + const uint3 launch_idx = optixGetLaunchIndex(); + const int2 pixel_idx = params.sample_index_buffer[ launch_idx.x ]; + + // Work distribution might assign tiles that cross over image boundary + if( pixel_idx.x > w-1 || pixel_idx.y > h-1 ) + return; + + const float3 eye = params.eye; + const float3 U = params.U; + const float3 V = params.V; + const float3 W = params.W; + + const int subframe_index = params.subframe_index; + + unsigned int seed = tea<4>( pixel_idx.y*w + pixel_idx.x, subframe_index ); + + + float3 result = make_float3( 0.0f ); + int i = params.samples_per_launch; + do + { + // The center of each pixel is at fraction (0.5,0.5) + const float2 subpixel_jitter = make_float2( rnd( seed ), rnd( seed ) ); + + const float2 d = 2.0f * make_float2( + ( static_cast( pixel_idx.x ) + subpixel_jitter.x ) / static_cast( w ), + ( static_cast( pixel_idx.y ) + subpixel_jitter.y ) / static_cast( h ) + ) - 1.0f; + float3 ray_direction = normalize(d.x*U + d.y*V + W); + float3 ray_origin = eye; + + RadiancePRD prd; + prd.emitted = make_float3(0.f); + prd.radiance = make_float3(0.f); + prd.attenuation = make_float3(1.f); + prd.countEmitted = true; + prd.done = false; + prd.seed = seed; + + int depth = 0; + for( ;; ) + { + traceRadiance( + params.handle, + ray_origin, + ray_direction, + 0.01f, // tmin + 1e16f, // tmax + &prd ); + + result += prd.emitted; + result += prd.radiance * prd.attenuation; + + if( prd.done || depth >= 3 ) + break; + + ray_origin = prd.origin; + ray_direction = prd.direction; + + ++depth; + } + } + while( --i ); + + float3 accum_color = result / static_cast( params.samples_per_launch ); + if( subframe_index > 0 ) + { + const float a = 1.0f / static_cast( subframe_index+1 ); + const float3 accum_color_prev = make_float3( params.sample_accum_buffer[ launch_idx.x ]); + accum_color = lerp( accum_color_prev, accum_color, a ); + } + params.sample_accum_buffer [ launch_idx.x ] = make_float4( accum_color, 1.0f); + + const unsigned int image_index = pixel_idx.y * params.width + pixel_idx.x; + + float3 device_color = deviceColor( params.device_idx ) * params.device_color_scale; + params.result_buffer[ image_index ] = make_color ( accum_color + device_color ); +} + + +extern "C" __global__ void __miss__radiance() +{ + MissData* rt_data = reinterpret_cast( optixGetSbtDataPointer() ); + RadiancePRD* prd = getPRD(); + + prd->radiance = make_float3( rt_data->r, rt_data->g, rt_data->b ); + prd->done = true; +} + + +extern "C" __global__ void __closesthit__occlusion() +{ + setPayloadOcclusion( true ); +} + + +extern "C" __global__ void __closesthit__radiance() +{ + HitGroupData* rt_data = (HitGroupData*)optixGetSbtDataPointer(); + RadiancePRD* prd = getPRD(); + + const int prim_idx = optixGetPrimitiveIndex(); + const float3 ray_dir = optixGetWorldRayDirection(); + const int vert_idx_offset = prim_idx*3; + + // Compute normal and hit point + const float3 v0 = make_float3( rt_data->vertices[ vert_idx_offset+0 ] ); + const float3 v1 = make_float3( rt_data->vertices[ vert_idx_offset+1 ] ); + const float3 v2 = make_float3( rt_data->vertices[ vert_idx_offset+2 ] ); + const float3 N_0 = normalize( cross( v1-v0, v2-v0 ) ); + + const float3 N = faceforward( N_0, -ray_dir, N_0 ); + const float3 P = optixGetWorldRayOrigin() + optixGetRayTmax()*ray_dir; + + // Account for emission + if( prd->countEmitted ) + prd->emitted = rt_data->emission_color; + else + prd->emitted = make_float3( 0.0f ); + + // Compute attenuation (diffuse color) using texture if available + cudaTextureObject_t texture = rt_data->diffuse_texture; + if (texture != 0) + { + // get barycentric coordinates + const float2 barycentrics = optixGetTriangleBarycentrics(); + const float b1 = barycentrics.x; + const float b2 = barycentrics.y; + const float b0 = 1.0f - (b1 + b2); + + // compute texture coordinates + const int vindex = optixGetPrimitiveIndex() * 3; + + const float2 t0 = rt_data->tex_coords[ vindex+0 ]; + const float2 t1 = rt_data->tex_coords[ vindex+1 ]; + const float2 t2 = rt_data->tex_coords[ vindex+2 ]; + + float2 tex_coord = b0*t0 + b1*t1 + b2*t2; + float s = tex_coord.x; + float t = tex_coord.y; + + // sample texture + float4 tex_val = tex2D( rt_data->diffuse_texture, s, t ); + prd->attenuation *= make_float3( tex_val ); + } + else + { + prd->attenuation *= rt_data->diffuse_color; + } + + unsigned int seed = prd->seed; + + // Sample a hemisphere direction and place in per-ray data + { + const float z1 = rnd(seed); + const float z2 = rnd(seed); + + float3 w_in; + cosine_sample_hemisphere( z1, z2, w_in ); + Onb onb( N ); + onb.inverse_transform( w_in ); + prd->direction = w_in; + prd->origin = P; + + prd->countEmitted = false; + } + + // Sample a position on the light source + const float z1 = rnd(seed); + const float z2 = rnd(seed); + prd->seed = seed; + + ParallelogramLight light = params.light; + const float3 light_pos = light.corner + light.v1 * z1 + light.v2 * z2; + + // Calculate properties of light sample (for area based pdf) + const float Ldist = length(light_pos - P ); + const float3 L = normalize(light_pos - P ); + const float nDl = dot( N, L ); + const float LnDl = -dot( light.normal, L ); + + // Cast the shadow ray + float weight = 0.0f; + if( nDl > 0.0f && LnDl > 0.0f ) + { + const bool occluded = traceOcclusion( + params.handle, + P, + L, + 0.01f, // tmin + Ldist - 0.01f // tmax + ); + + if( !occluded ) + { + const float A = length(cross(light.v1, light.v2)); + weight = nDl * LnDl * A / (M_PIf * Ldist * Ldist); + } + } + + prd->radiance += light.emission * weight; +} + + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/optixNVLink.h b/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/optixNVLink.h new file mode 100644 index 00000000..2fb44dd8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/optixNVLink.h @@ -0,0 +1,92 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +enum RayType +{ + RAY_TYPE_RADIANCE = 0, + RAY_TYPE_OCCLUSION = 1, + RAY_TYPE_COUNT +}; + + +struct ParallelogramLight +{ + float3 corner; + float3 v1, v2; + float3 normal; + float3 emission; +}; + + +struct Params +{ + unsigned int subframe_index; + + int2* sample_index_buffer; + float4* sample_accum_buffer; + uchar4* result_buffer; + unsigned int width; + unsigned int height; + unsigned int samples_per_launch; + unsigned int device_idx; + + float3 eye; + float3 U; + float3 V; + float3 W; + + ParallelogramLight light; + OptixTraversableHandle handle; + + float device_color_scale; // to turn on/off multi-gpu pattern overlay +}; + + +struct RayGenData +{ + float r, g, b; +}; + + +struct MissData +{ + float r, g, b; +}; + + +struct HitGroupData +{ + float3 emission_color; + float3 diffuse_color; + float4* vertices; + float2* tex_coords; + cudaTextureObject_t diffuse_texture; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/optixNVLink_kernels.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/optixNVLink_kernels.cu new file mode 100644 index 00000000..4cb30da0 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixNVLink/optixNVLink_kernels.cu @@ -0,0 +1,53 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +extern "C" __global__ void fillSamples( int gpu_idx, int num_gpus, int width, int height, int2* sample_indices ) +{ + StaticWorkDistribution wd; + wd.setRasterSize( width, height ); + wd.setNumGPUs( num_gpus ); + + const int sample_idx = blockIdx.x; + sample_indices[sample_idx] = wd.getSamplePixel( gpu_idx, sample_idx ); +} + + +extern "C" __host__ void fillSamplesCUDA( int num_samples, cudaStream_t stream, int gpu_idx, int num_gpus, int width, int height, int2* sample_indices ) +{ + fillSamples<<>>( + gpu_idx, + num_gpus, + width, + height, + sample_indices ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixOpacityMicromap/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixOpacityMicromap/CMakeLists.txt new file mode 100644 index 00000000..55fd68c8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixOpacityMicromap/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2022 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixOpacityMicromap target_name + optixOpacityMicromap.cu + optixOpacityMicromap.cpp + optixOpacityMicromap.h + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixOpacityMicromap/optixOpacityMicromap.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixOpacityMicromap/optixOpacityMicromap.cpp new file mode 100644 index 00000000..fcf16fa5 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixOpacityMicromap/optixOpacityMicromap.cpp @@ -0,0 +1,720 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2022 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +//----------------------------------------------------------------------------- +// +// A simple demonstration of opacity micromaps. +// +// * A single quad, made of two triangles ABC and ACD is rendered with a +// transparent circular cutout at its center. +// * OMMs are applied to the two triangles to accelerate the evaluation of the +// opacity function during traversal. +// * As a preproces, OMM microtriangles are marked as either completely +// transparent, completely opaque, or unknown. +// * During traversal, rays that hit opaque or transparent regions of the OMM +// can skip the anyhit function. +// * Rays that hit 'unknown' regions of the OMM evaluate the anyhit to get +// accurate evaluation of the opacity function. +// * Regions of the micromap which are unknown are tinted a lighter color to +// visualize the regions which required anyhit evaluation. +// +//----------------------------------------------------------------------------- + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include "optixOpacityMicromap.h" + +#include +#include +#include +#include + +#include +#include + + +constexpr int OMM_SUBDIV_LEVEL = 4; +constexpr int NUM_TRIS = 2; +constexpr int DEFAULT_WIDTH = 1024; +constexpr int DEFAULT_HEIGHT = 768; + +constexpr float2 g_uvs[NUM_TRIS][3] = +{ + { { 1.0f, -1.0f }, { -1.0f, -1.0f }, { -1.0f, 1.0f } }, // Triangle ABC + { { 1.0f, -1.0f }, { -1.0f, 1.0f }, { 1.0f, 1.0f } } // Triangle ACD +}; + + +template +struct SbtRecord +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef SbtRecord RayGenSbtRecord; +typedef SbtRecord MissSbtRecord; +typedef SbtRecord HitGroupSbtRecord; + + +void configureCamera( sutil::Camera& cam, const uint32_t width, const uint32_t height ) +{ + cam.setEye( {0.0f, 0.0f, 1.5f} ); + cam.setLookat( {0.0f, 0.0f, 0.0f} ); + cam.setUp( {0.0f, 1.0f, 3.0f} ); + cam.setFovY( 45.0f ); + cam.setAspectRatio( (float)width / (float)height ); +} + + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f Specify file for image output\n"; + std::cerr << " --help | -h Print this usage message\n"; + std::cerr << " --dim=x Set image dimensions; defaults to " + << DEFAULT_WIDTH << "x" << DEFAULT_HEIGHT << "\n"; + exit( 0 ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + + +int main( int argc, char* argv[] ) +{ + std::string outfile; + int width = DEFAULT_WIDTH; + int height = DEFAULT_HEIGHT; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg( argv[i] ); + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--file" || arg == "-f" ) + { + if( i < argc - 1 ) + { + outfile = argv[++i]; + } + else + { + printUsageAndExit( argv[0] ); + } + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + sutil::parseDimensions( dims_arg.c_str(), width, height ); + } + else + { + std::cerr << "Unknown option '" << arg << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + // + // Initialize CUDA and create OptiX context + // + OptixDeviceContext context = nullptr; + { + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + // Initialize the OptiX API, loading all API entry points + OPTIX_CHECK( optixInit() ); + + // Specify context options + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; +#ifdef DEBUG + // This may incur significant performance cost and should only be done during development. + options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; +#endif + // Associate a CUDA context (and therefore a specific GPU) with this + // device context + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + } + + // + // create opacity micromap + // + CUdeviceptr d_omm_array = 0; + { + constexpr int NUM_MICRO_TRIS = 1 << ( OMM_SUBDIV_LEVEL*2 ); + constexpr int BITS_PER_STATE = 2; + + unsigned short omm_input_data[ NUM_TRIS ][ NUM_MICRO_TRIS / 16 * BITS_PER_STATE ] = {}; + + // Calculate the texture coordinate at the micromesh vertices of the triangle and + // determine if the triangle is inside, outside, or spanning the boundary of the circle. + // Note that the tex coords are in [-1, 1] and the circle is centered at uv=(0,0). + auto evaluteOpacity = []( + const float2& bary0, + const float2& bary1, + const float2& bary2, + const float2* uvs + ) + { + const float2 uv0 = computeUV(bary0, uvs[0], uvs[1], uvs[2] ); + const float2 uv1 = computeUV(bary1, uvs[0], uvs[1], uvs[2] ); + const float2 uv2 = computeUV(bary2, uvs[0], uvs[1], uvs[2] ); + const bool in_circle0 = inCircle( uv0 ); + const bool in_circle1 = inCircle( uv1 ); + const bool in_circle2 = inCircle( uv2 ); + if( in_circle0 && in_circle1 && in_circle2 ) + // All 3 verts inside circle, mark transparent + return OPTIX_OPACITY_MICROMAP_STATE_TRANSPARENT; + else if( !in_circle0 && !in_circle1 && !in_circle2 ) + // All 3 verts outside circle, mark it as opaque + return OPTIX_OPACITY_MICROMAP_STATE_OPAQUE; + else + // Mixture of verts inside and outside, mark as unknown and let AH evaluate + return OPTIX_OPACITY_MICROMAP_STATE_UNKNOWN_OPAQUE; + }; + + for( uint32_t uTriI = 0; uTriI < NUM_MICRO_TRIS; ++uTriI ) + { + + // Opacity micromaps for a circular cutout: Check if the micro + // triangle area overlaps the circle, if so, it needs to be + // marked as 'unknown'. If all micro triangle vertices are + // within the circle, it is marked as transparent. Otherwise + // it must be fully outside the circle and can be marked + // opaque. Note that this is not fully accurate as an edge may + // still intersect the circle, we choose to ignore this detail + // in this sample. + // + // NB: This computation must align with the anyhit program (We + // are essentially baking the anyhit program at micro-tri + // vertices). + float2 bary0, bary1, bary2; + optixMicromapIndexToBaseBarycentrics( uTriI, OMM_SUBDIV_LEVEL, bary0, bary1, bary2 ); + + // first triangle (a,b,c) + { + const int opacity = evaluteOpacity( bary0, bary1, bary2, g_uvs[0] ); + omm_input_data[0][uTriI/8] |= opacity << ( uTriI%8 * 2 ); + } + + // second triangle (a,c,d) + { + const int opacity = evaluteOpacity( bary0, bary1, bary2, g_uvs[1] ); + omm_input_data[1][uTriI/8] |= opacity << ( uTriI%8 * 2 ); + } + } + + // Copy the omm array to device + CUdeviceptr d_omm_input_data = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_omm_input_data ), sizeof( omm_input_data ) ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_omm_input_data ), + omm_input_data, + sizeof( omm_input_data ), + cudaMemcpyHostToDevice + ) ); + + // + // Build micromap + // + OptixOpacityMicromapHistogramEntry histogram{}; + histogram.count = NUM_TRIS; + histogram.format = OPTIX_OPACITY_MICROMAP_FORMAT_4_STATE; + histogram.subdivisionLevel = OMM_SUBDIV_LEVEL; + + OptixOpacityMicromapArrayBuildInput build_input = {}; + build_input.flags = OPTIX_OPACITY_MICROMAP_FLAG_NONE; + build_input.inputBuffer = d_omm_input_data; + build_input.numMicromapHistogramEntries = 1; + build_input.micromapHistogramEntries = &histogram; + + OptixMicromapBufferSizes buffer_sizes = {}; + OPTIX_CHECK( optixOpacityMicromapArrayComputeMemoryUsage( context, &build_input, &buffer_sizes) ); + + // Two OMMs, both with the same layout + std::vector omm_descs = + { + { + 0, // byteOffset for triangle 0 + OMM_SUBDIV_LEVEL, + OPTIX_OPACITY_MICROMAP_FORMAT_4_STATE + }, + { + // byteOffset for triangle 1 + static_cast( sizeof(omm_input_data[0]) ), + OMM_SUBDIV_LEVEL, + OPTIX_OPACITY_MICROMAP_FORMAT_4_STATE + } + }; + + CUdeviceptr d_omm_desc = 0; + const size_t omm_desc_size_bytes = omm_descs.size() * sizeof(OptixOpacityMicromapDesc); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_omm_desc ), omm_desc_size_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_omm_desc ), + omm_descs.data(), + omm_desc_size_bytes, + cudaMemcpyHostToDevice + ) ); + + build_input.perMicromapDescBuffer = d_omm_desc; + build_input.perMicromapDescStrideInBytes = 0; + + CUdeviceptr d_temp_buffer = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer ), buffer_sizes.tempSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_omm_array ), buffer_sizes.outputSizeInBytes ) ); + + OptixMicromapBuffers micromap_buffers = {}; + micromap_buffers.output = d_omm_array; + micromap_buffers.outputSizeInBytes = buffer_sizes.outputSizeInBytes; + micromap_buffers.temp = d_temp_buffer; + micromap_buffers.tempSizeInBytes = buffer_sizes.tempSizeInBytes; + + OPTIX_CHECK( optixOpacityMicromapArrayBuild( context, 0, &build_input, µmap_buffers) ); + + cudaFree( reinterpret_cast( d_omm_input_data ) ); + cudaFree( reinterpret_cast( d_omm_desc ) ); + cudaFree( reinterpret_cast( d_temp_buffer ) ); + } + + // + // accel handling + // + OptixTraversableHandle gas_handle; + CUdeviceptr d_gas_output_buffer; + { + + // + // Create OMM input + // + OptixOpacityMicromapUsageCount usage_count={}; + usage_count.count = NUM_TRIS; + // simple 2 state as the OMM perfectly matches the checkerboard pattern. + // 'unknown' states that are resolved in the anyhit program are not needed. + usage_count.format = OPTIX_OPACITY_MICROMAP_FORMAT_4_STATE; + usage_count.subdivisionLevel = OMM_SUBDIV_LEVEL; + + std::array omm_indices = { 0u, 1u }; + const size_t omm_indices_size_bytes = omm_indices.size() * sizeof( unsigned short ); + + CUdeviceptr d_omm_indices = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_omm_indices ), omm_indices_size_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_omm_indices ), + omm_indices.data(), + omm_indices_size_bytes, + cudaMemcpyHostToDevice + ) ); + + OptixBuildInputOpacityMicromap omm_input = {}; + omm_input.indexingMode = OPTIX_OPACITY_MICROMAP_ARRAY_INDEXING_MODE_INDEXED; + omm_input.opacityMicromapArray = d_omm_array; + omm_input.indexBuffer = d_omm_indices; + omm_input.indexSizeInBytes = 2; + omm_input.numMicromapUsageCounts = 1; + omm_input.micromapUsageCounts = &usage_count; + + // + // Build GAS + // + + // Use default options for simplicity. In a real use case we would want to + // enable compaction, etc + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_NONE; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + // Quad ABCD build input: simple list of two triangles: + // * Triangle ABC + // * Triangle ACD + const std::array vertices = + { { + { -0.5f, -0.5f, 0.0f }, + { 0.5f, -0.5f, 0.0f }, + { 0.5f, 0.5f, 0.0f }, + + { -0.5f, -0.5f, 0.0f }, + { 0.5f, 0.5f, 0.0f }, + { -0.5f, 0.5f, 0.0f } + } }; + + const size_t vertices_size = sizeof( float3 )*vertices.size(); + CUdeviceptr d_vertices=0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_vertices ), vertices_size ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_vertices ), + vertices.data(), + vertices_size, + cudaMemcpyHostToDevice + ) ); + + // Our build input is a simple list of non-indexed triangle vertices + const uint32_t triangle_input_flags[1] = { OPTIX_GEOMETRY_FLAG_NONE }; + OptixBuildInput triangle_input = {}; + triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangle_input.triangleArray.numVertices = static_cast( vertices.size() ); + triangle_input.triangleArray.vertexBuffers = &d_vertices; + triangle_input.triangleArray.flags = triangle_input_flags; + triangle_input.triangleArray.numSbtRecords = 1; + triangle_input.triangleArray.opacityMicromap = omm_input; + + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( + context, + &accel_options, + &triangle_input, + 1, // Number of build inputs + &gas_buffer_sizes + ) ); + CUdeviceptr d_temp_buffer_gas; + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_temp_buffer_gas ), + gas_buffer_sizes.tempSizeInBytes + ) ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_gas_output_buffer ), + gas_buffer_sizes.outputSizeInBytes + ) ); + + OPTIX_CHECK( optixAccelBuild( + context, + 0, // CUDA stream + &accel_options, + &triangle_input, + 1, // num build inputs + d_temp_buffer_gas, + gas_buffer_sizes.tempSizeInBytes, + d_gas_output_buffer, + gas_buffer_sizes.outputSizeInBytes, + &gas_handle, + nullptr, // emitted property list + 0 // num emitted properties + ) ); + + // We can now free the scratch space buffer used during build and the vertex + // inputs, since they are not needed by our trivial shading method + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer_gas ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_vertices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_omm_indices ) ) ); + + } + + // + // Create module + // + OptixModule module = nullptr; + OptixPipelineCompileOptions pipeline_compile_options = {}; + { + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + pipeline_compile_options.usesMotionBlur = false; + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + pipeline_compile_options.numPayloadValues = 4; + pipeline_compile_options.numAttributeValues = 2; + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE; + pipeline_compile_options.allowOpacityMicromaps = true; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixOpacityMicromap.cu", inputSize ); + + OPTIX_CHECK_LOG( optixModuleCreate( + context, + &module_compile_options, + &pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &module + ) ); + } + + // + // Create program groups + // + OptixProgramGroup raygen_prog_group = nullptr; + OptixProgramGroup miss_prog_group = nullptr; + OptixProgramGroup hitgroup_prog_group = nullptr; + { + OptixProgramGroupOptions program_group_options = {}; // Initialize to zeros + + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &raygen_prog_group + ) ); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__ms"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &miss_prog_group + ) ); + + OptixProgramGroupDesc hitgroup_prog_group_desc = {}; + hitgroup_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hitgroup_prog_group_desc.hitgroup.moduleCH = module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__ch"; + hitgroup_prog_group_desc.hitgroup.moduleAH = module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameAH = "__anyhit__opacity"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &hitgroup_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &hitgroup_prog_group + ) ); + } + + // + // Link pipeline + // + OptixPipeline pipeline = nullptr; + { + const uint32_t max_trace_depth = 1; + OptixProgramGroup program_groups[] = { raygen_prog_group, miss_prog_group, hitgroup_prog_group }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + OPTIX_CHECK_LOG( optixPipelineCreate( + context, + &pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &pipeline + ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + ) ); + } + + // + // Set up shader binding table + // + OptixShaderBindingTable sbt = {}; + CUdeviceptr d_uvs=0; + { + CUdeviceptr raygen_record; + const size_t raygen_record_size = sizeof( RayGenSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &raygen_record ), raygen_record_size ) ); + RayGenSbtRecord rg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( raygen_prog_group, &rg_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( raygen_record ), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr miss_record; + size_t miss_record_size = sizeof( MissSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &miss_record ), miss_record_size ) ); + MissSbtRecord ms_sbt; + ms_sbt.data = { 0.01f, 0.01f, 0.01f }; + OPTIX_CHECK( optixSbtRecordPackHeader( miss_prog_group, &ms_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( miss_record ), + &ms_sbt, + miss_record_size, + cudaMemcpyHostToDevice + ) ); + + //const size_t uvs_size_bytes = g_uvs.size() * sizeof( float2 ); + const size_t uvs_size_bytes = sizeof( g_uvs ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_uvs ), uvs_size_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_uvs ), + g_uvs, + uvs_size_bytes, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr hitgroup_record; + size_t hitgroup_record_size = sizeof( HitGroupSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &hitgroup_record ), hitgroup_record_size ) ); + HitGroupSbtRecord hg_sbt; + hg_sbt.data.uvs = reinterpret_cast( d_uvs ); + OPTIX_CHECK( optixSbtRecordPackHeader( hitgroup_prog_group, &hg_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( hitgroup_record ), + &hg_sbt, + hitgroup_record_size, + cudaMemcpyHostToDevice + ) ); + + sbt.raygenRecord = raygen_record; + sbt.missRecordBase = miss_record; + sbt.missRecordStrideInBytes = sizeof( MissSbtRecord ); + sbt.missRecordCount = 1; + sbt.hitgroupRecordBase = hitgroup_record; + sbt.hitgroupRecordStrideInBytes = sizeof( HitGroupSbtRecord ); + sbt.hitgroupRecordCount = 1; + } + + sutil::CUDAOutputBuffer output_buffer( sutil::CUDAOutputBufferType::CUDA_DEVICE, width, height ); + + // + // launch + // + { + CUstream stream; + CUDA_CHECK( cudaStreamCreate( &stream ) ); + + sutil::Camera cam; + configureCamera( cam, width, height ); + + Params params; + params.image = output_buffer.map(); + params.image_width = width; + params.image_height = height; + params.handle = gas_handle; + params.cam_eye = cam.eye(); + cam.UVWFrame( params.cam_u, params.cam_v, params.cam_w ); + + CUdeviceptr d_param; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_param ), sizeof( Params ) ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_param ), + ¶ms, sizeof( params ), + cudaMemcpyHostToDevice + ) ); + + OPTIX_CHECK( optixLaunch( pipeline, stream, d_param, sizeof( Params ), &sbt, width, height, /*depth=*/1 ) ); + CUDA_SYNC_CHECK(); + + output_buffer.unmap(); + CUDA_CHECK( cudaFree( reinterpret_cast( d_param ) ) ); + } + + // + // Display results + // + { + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = width; + buffer.height = height; + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + if( outfile.empty() ) + sutil::displayBufferWindow( argv[0], buffer ); + else + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + // + // Cleanup + // + { + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_uvs ) ) ); + + OPTIX_CHECK( optixPipelineDestroy( pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( hitgroup_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( miss_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( raygen_prog_group ) ); + OPTIX_CHECK( optixModuleDestroy( module ) ); + + OPTIX_CHECK( optixDeviceContextDestroy( context ) ); + } + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixOpacityMicromap/optixOpacityMicromap.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixOpacityMicromap/optixOpacityMicromap.cu new file mode 100644 index 00000000..384b6949 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixOpacityMicromap/optixOpacityMicromap.cu @@ -0,0 +1,147 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2022 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "optixOpacityMicromap.h" +#include + +#include + +extern "C" { +__constant__ Params params; +} + + +static __forceinline__ __device__ void setPayloadColor( float3 p ) +{ + optixSetPayload_0( __float_as_uint( p.x ) ); + optixSetPayload_1( __float_as_uint( p.y ) ); + optixSetPayload_2( __float_as_uint( p.z ) ); +} + +static __forceinline__ __device__ void setPayloadAnyhit( unsigned int a ) +{ + optixSetPayload_3( a ); +} + + +static __forceinline__ __device__ void computeRay( uint3 idx, uint3 dim, float3& origin, float3& direction ) +{ + const float3 U = params.cam_u; + const float3 V = params.cam_v; + const float3 W = params.cam_w; + const float2 d = 2.0f * make_float2( + static_cast( idx.x ) / static_cast( dim.x ), + static_cast( idx.y ) / static_cast( dim.y ) + ) - 1.0f; + + origin = params.cam_eye; + direction = normalize( d.x * U + d.y * V + W ); +} + + +extern "C" __global__ void __raygen__rg() +{ + // Lookup our location within the launch grid + const uint3 idx = optixGetLaunchIndex(); + const uint3 dim = optixGetLaunchDimensions(); + + // Map our launch idx to a screen location and create a ray from the camera + // location through the screen + float3 ray_origin, ray_direction; + computeRay( idx, dim, ray_origin, ray_direction ); + + // Trace the ray against our scene hierarchy + unsigned int p0, p1, p2, p3=0; + optixTrace( + params.handle, + ray_origin, + ray_direction, + 0.0f, // Min intersection distance + 1e16f, // Max intersection distance + 0.0f, // rayTime -- used for motion blur + OptixVisibilityMask( 255 ), // Specify always visible + OPTIX_RAY_FLAG_NONE, + 0, // SBT offset -- See SBT discussion + RAY_TYPE_COUNT, // SBT stride -- See SBT discussion + 0, // missSBTIndex -- See SBT discussion + p0, p1, p2, p3 ); + float3 result; + result.x = __uint_as_float( p0 ); + result.y = __uint_as_float( p1 ); + result.z = __uint_as_float( p2 ); + unsigned int anyhit_executed = p3; + + // If anyhit was executed, tint the pixel towards white + if( anyhit_executed ) + result = lerp( result, make_float3( 1.0f), 0.075f ); + + // Record results in our output raster + params.image[idx.y * params.image_width + idx.x] = make_color( result ); +} + + +extern "C" __global__ void __miss__ms() +{ + MissData* miss_data = reinterpret_cast( optixGetSbtDataPointer() ); + setPayloadColor( miss_data->bg_color ); +} + + +extern "C" __global__ void __closesthit__ch() +{ + // When built-in triangle intersection is used, a number of fundamental + // attributes are provided by the OptiX API, including barycentric coordinates. + const float2 barycentrics = optixGetTriangleBarycentrics(); + + setPayloadColor( make_float3( barycentrics*0.5f, 0.5f ) ); +} + + +extern "C" __global__ void __anyhit__opacity() +{ + setPayloadAnyhit( 1u ); // Register that anyhit was invoked + + const HitGroupData* rt_data = reinterpret_cast( optixGetSbtDataPointer() ); + const float2 barycentrics = optixGetTriangleBarycentrics(); + const int prim_idx = optixGetPrimitiveIndex(); + + const float2 uv0 = rt_data->uvs[ prim_idx*3 + 0 ]; + const float2 uv1 = rt_data->uvs[ prim_idx*3 + 1 ]; + const float2 uv2 = rt_data->uvs[ prim_idx*3 + 2 ]; + + const float2 uv = computeUV( barycentrics, uv0, uv1, uv2 ); + + if( inCircle( uv ) ) + optixIgnoreIntersection(); +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixOpacityMicromap/optixOpacityMicromap.h b/Extern/3rdParty/OptiX/Linux/SDK/optixOpacityMicromap/optixOpacityMicromap.h new file mode 100644 index 00000000..712571a8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixOpacityMicromap/optixOpacityMicromap.h @@ -0,0 +1,92 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2022 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#include + +constexpr float CIRCLE_RADIUS = 0.75f; + +enum RayType +{ + RAY_TYPE_RADIANCE = 0, + RAY_TYPE_COUNT +}; + +//----------------------------------------------------------------------------- +// +// Helper functions to be used when pre-baking opacity into OMM and when +// evaluating opacity within anyhit function +// +//----------------------------------------------------------------------------- + +static __host__ __device__ __inline__ float2 computeUV( float2 bary, float2 uv0, float2 uv1, float2 uv2 ) +{ + return ( 1.0f - bary.x - bary.y )*uv0 + bary.x*uv1 + bary.y*uv2; +} + +static __host__ __device__ __inline__ bool inCircle( const float2 uv ) +{ + return ( uv.x * uv.x + uv.y * uv.y ) < ( CIRCLE_RADIUS * CIRCLE_RADIUS ); +}; + + +//----------------------------------------------------------------------------- +// +// Types +// +//----------------------------------------------------------------------------- +struct Params +{ + uchar4* image; + unsigned int image_width; + unsigned int image_height; + float3 cam_eye; + float3 cam_u, cam_v, cam_w; + OptixTraversableHandle handle; +}; + + +struct RayGenData +{ + // No data needed +}; + + +struct MissData +{ + float3 bg_color; +}; + + +struct HitGroupData +{ + float2* uvs; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/CMakeLists.txt new file mode 100644 index 00000000..0695f56d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/CMakeLists.txt @@ -0,0 +1,42 @@ +# +# Copyright (c) 2010 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA Corporation and its licensors retain all intellectual property and proprietary +# rights in and to this software, related documentation and any modifications thereto. +# Any use, reproduction, disclosure or distribution of this software and related +# documentation without an express license agreement from NVIDIA Corporation is strictly +# prohibited. +# +# TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* +# AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, +# INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY +# SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT +# LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF +# BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR +# INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGES +# + +# See top level CMakeLists.txt file for documentation of OPTIX_add_sample_executable. + +if( NOT CUDA_CUDA_LIBRARY ) + return() +endif() + +set_source_files_properties( optixOpticalFlow.cu PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ ) + +OPTIX_add_sample_executable( optixOpticalFlow target_name + optixOpticalFlow.cpp + optixOpticalFlow.cu + nvOpticalFlowCommon.h + nvOpticalFlowCuda.h + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ${CUDA_CUDA_LIBRARY} + ${CMAKE_DL_LIBS} + ) + + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/README.TXT b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/README.TXT new file mode 100644 index 00000000..a5810f79 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/README.TXT @@ -0,0 +1,10 @@ +This sample demonstrates calculation of optical flow between two images. +Examples: + optixOpticalFlow -o flow002.exr \ + ../optixDenoiser/motiondata/soane-BSDF-001.exr \ + ../optixDenoiser/motiondata/soane-BSDF-002.exr + + optixOpticalFlow -F 1-20 -o flow+++.exr ../optixDenoiser/motiondata/soane-BSDF-+++.exr + +The flow vectors can be used for the OptiX denoiser in temporal mode. +The sample runs only on Ampere and newer GPUs. diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/nvOpticalFlowCommon.h b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/nvOpticalFlowCommon.h new file mode 100644 index 00000000..a4c1bc4f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/nvOpticalFlowCommon.h @@ -0,0 +1,548 @@ +/* +* This copyright notice applies to this header file only: +* +* Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the software, and to permit persons to whom the +* software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ +/** +* \file nvOpticalFlowCommon.h +* NVIDIA GPUs - Turing and above contains a hardware-based optical flow engine +* which provides fully-accelerated hardware-based optical flow and stereo estimation. +* nvOpticalFlowCommon.h provides enums, structure definitions and function prototypes which are common across different devices, +* nvOpticalFlowCommon.h uses #pragma directives to pack structure members with one byte alignment. +* \date 2018 +* nvOpticalFlowCommon.h provides common enums, structure definitions and function prototypes. +*/ + +#ifndef _NV_OPTICALFLOW_COMMON_H_ +#define _NV_OPTICALFLOW_COMMON_H_ +#if defined(_MSC_VER_) && (_MSC_VER_ < 1600) +#ifndef _STDINT +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +#endif +#else +#include +#endif + +#ifdef _WIN32 +#define NVOFAPI __stdcall +#else +#define NVOFAPI +#endif +#define NV_OF_API_MAJOR_VERSION 2 +#define NV_OF_API_MINOR_VERSION 0 +#define NV_OF_API_VERSION (uint16_t)((NV_OF_API_MAJOR_VERSION << 4) | NV_OF_API_MINOR_VERSION) +#define MIN_ERROR_STRING_SIZE 80 + +#if defined(__cplusplus) +extern "C" +{ +#endif /* __cplusplus */ + +typedef struct NvOFHandle_st *NvOFHandle; +typedef struct NvOFGPUBufferHandle_st *NvOFGPUBufferHandle; +typedef struct NVOFPrivDataHandle_st *NvOFPrivDataHandle; + +/** + * Supported error codes +*/ +typedef enum _NV_OF_STATUS +{ + /** + * This indicates that API call returned with no errors. + */ + NV_OF_SUCCESS, + + /** + * This indicates that HW Optical flow functionality is not supported + */ + NV_OF_ERR_OF_NOT_AVAILABLE, + + /** + * This indicates that device passed by the client is not supported. + */ + NV_OF_ERR_UNSUPPORTED_DEVICE, + + /** + * This indicates that device passed to the API call is no longer available and + * needs to be reinitialized. + */ + NV_OF_ERR_DEVICE_DOES_NOT_EXIST, + + /** + * This indicates that one or more of the pointers passed to the API call + * is invalid. + */ + NV_OF_ERR_INVALID_PTR, + + /** + * This indicates that one or more of the parameter passed to the API call + * is invalid. + */ + NV_OF_ERR_INVALID_PARAM, + + /** + * This indicates that an API call was made in wrong sequence/order. + */ + NV_OF_ERR_INVALID_CALL, + + /** + * This indicates that an invalid struct version was used by the client. + */ + NV_OF_ERR_INVALID_VERSION, + + /** + * This indicates that the API call failed because it was unable to allocate + * enough memory to perform the requested operation. + */ + NV_OF_ERR_OUT_OF_MEMORY, + + /** + * This indicates that the OF session has not been initialized with + * ::NvOFInit() or that initialization has failed. + */ + NV_OF_ERR_NOT_INITIALIZED, + + /** + * This indicates that an unsupported parameter was passed by the client. + */ + NV_OF_ERR_UNSUPPORTED_FEATURE, + + /** + * This indicates that an unknown internal error has occurred. + */ + NV_OF_ERR_GENERIC, +} NV_OF_STATUS; + +/** +* Supported bool values +*/ +typedef enum _NV_OF_BOOL +{ + NV_OF_FALSE = 0, /* < Represents false bool value */ + NV_OF_TRUE = !NV_OF_FALSE /* < Represents true bool value */ +} NV_OF_BOOL; + +/** +* Supported optical flow and stereo disparity capability values. +*/ +typedef enum _NV_OF_CAPS +{ + NV_OF_CAPS_SUPPORTED_OUTPUT_GRID_SIZES, /**< Indicates supported values of ::NV_OF_OUTPUT_VECTOR_GRID_SIZE, + ::NV_OF_INIT_PARAMS::outGridSize should be set with a supported output gridsize. */ + NV_OF_CAPS_SUPPORTED_HINT_GRID_SIZES, /**< Indicates supported values of ::NV_OF_HINT_VECTOR_GRID_SIZE, + ::NV_OF_INIT_PARAMS::hintGridSize should be set with a supported hint gridsize. */ + NV_OF_CAPS_SUPPORT_HINT_WITH_OF_MODE, /**< Indicates external hint support for ::NV_OF_MODE_OPTICALFLOW mode. + 0: External hint not supported for ::NV_OF_MODE_OPTICALFLOW mode. + 1: External hint is supported for ::NV_OF_MODE_OPTICALFLOW mode. */ + NV_OF_CAPS_SUPPORT_HINT_WITH_ST_MODE, /**< Indicates external hint support for ::NV_OF_MODE_STEREODISPARITY mode. + 0: External hint not supported for ::NV_OF_MODE_STEREODISPARITY mode. + 1: External hint is supported for ::NV_OF_MODE_STEREODISPARITY mode. */ + NV_OF_CAPS_WIDTH_MIN, /**< Minimum input width supported. */ + NV_OF_CAPS_HEIGHT_MIN, /**< Minimum input height supported. */ + NV_OF_CAPS_WIDTH_MAX, /**< Maximum input width supported. */ + NV_OF_CAPS_HEIGHT_MAX, /**< Maximum input height supported. */ + NV_OF_CAPS_SUPPORT_ROI, /**< Indicates ROI support. + 0: ROIs cannot be specified. + 1: One or more ROIs can be specified. */ + NV_OF_CAPS_SUPPORT_ROI_MAX_NUM, /**< Indicates maximum number of ROIs supported. */ + NV_OF_CAPS_SUPPORT_MAX +} NV_OF_CAPS; + +/** +* Supported optical flow/stereo disparity performance levels. +*/ +typedef enum _NV_OF_PERF_LEVEL +{ + NV_OF_PERF_LEVEL_UNDEFINED, + NV_OF_PERF_LEVEL_SLOW = 5, /**< Slow perf level results in lowest performance and best quality */ + NV_OF_PERF_LEVEL_MEDIUM = 10, /**< Medium perf level results in low performance and medium quality */ + NV_OF_PERF_LEVEL_FAST = 20, /**< Fast perf level results in high performance and low quality */ + NV_OF_PERF_LEVEL_MAX +} NV_OF_PERF_LEVEL; + +/** +* Supported grid size for output buffer ::NV_OF_EXECUTE_PARAMS::outputBuffer. +* Client should set ::NV_OF_INIT_PARAMS::outGridSize with ::NV_OF_OUTPUT_VECTOR_GRID_SIZE values. +*/ +typedef enum _NV_OF_OUTPUT_VECTOR_GRID_SIZE +{ + NV_OF_OUTPUT_VECTOR_GRID_SIZE_UNDEFINED, + NV_OF_OUTPUT_VECTOR_GRID_SIZE_1 = 1, /**< Output buffer grid size is 1x1 */ + NV_OF_OUTPUT_VECTOR_GRID_SIZE_2 = 2, /**< Output buffer grid size is 2x2 */ + NV_OF_OUTPUT_VECTOR_GRID_SIZE_4 = 4, /**< Output buffer grid size is 4x4 */ + NV_OF_OUTPUT_VECTOR_GRID_SIZE_MAX +} NV_OF_OUTPUT_VECTOR_GRID_SIZE; + +/** +* Expected grid size for optional paramater ::NV_OF_EXECUTE_PARAMS::externalHints buffer. +* Client should set ::NV_OF_INIT_PARAMS::hintGridSize with ::NV_OF_HINT_VECTOR_GRID_SIZE values. +*/ +typedef enum _NV_OF_HINT_VECTOR_GRID_SIZE +{ + NV_OF_HINT_VECTOR_GRID_SIZE_UNDEFINED, + NV_OF_HINT_VECTOR_GRID_SIZE_1 = 1, /**< Hint buffer grid size is 1x1.*/ + NV_OF_HINT_VECTOR_GRID_SIZE_2 = 2, /**< Hint buffer grid size is 2x2.*/ + NV_OF_HINT_VECTOR_GRID_SIZE_4 = 4, /**< Hint buffer grid size is 4x4.*/ + NV_OF_HINT_VECTOR_GRID_SIZE_8 = 8, /**< Hint buffer grid size is 8x8.*/ + NV_OF_HINT_VECTOR_GRID_SIZE_MAX +} NV_OF_HINT_VECTOR_GRID_SIZE; + +/** +* ::NV_OF_MODE enum define values for Optical flow and Stereo disparity modes. +* Client need to set ::NV_OF_INIT_PARAMS::mode with ::NV_OF_MODE values. +* For the ::NV_OF_MODE_OPTICALFLOW mode, the buffer format for ::NV_OF_EXECUTE_PARAMS::externalHints +* and ::NV_OF_EXECUTE_PARAMS::outputBuffer is ::NV_OF_FLOW_VECTOR. +* For the ::NV_OF_MODE_STEREODISPARITY mode, the buffer format for ::NV_OF_EXECUTE_PARAMS::externalHints +* and ::NV_OF_EXECUTE_PARAMS::outputBuffer is ::NV_OF_STEREO_DISPARITY. +*/ +typedef enum _NV_OF_MODE +{ + NV_OF_MODE_UNDEFINED, + NV_OF_MODE_OPTICALFLOW, /**< Calculate optical flow between two frames. */ + NV_OF_MODE_STEREODISPARITY, /**< Calculate disparity between Stereo view pair. */ + NV_OF_MODE_MAX +} NV_OF_MODE; + +/** +* Supported buffer type for ::NvOFGPUBufferHandle allocation. +* Client need to set NV_OF_CREATE_BUFFER::bufferUsage with ::NV_OF_BUFFER_USAGE enum values. +*/ +typedef enum _NV_OF_BUFFER_USAGE +{ + NV_OF_BUFFER_USAGE_UNDEFINED, + NV_OF_BUFFER_USAGE_INPUT, /**< Input buffer type is used to allocate ::NV_OF_INPUT_EXECUTE_PARAMS::inputFrame, + ::NV_OF_INPUT_EXECUTE_PARAMS::referenceFrame. */ + NV_OF_BUFFER_USAGE_OUTPUT, /**< Output buffer type is used to allocate ::NV_OF_OUTPUT_EXECUTE_PARAMS::outputBuffer. */ + NV_OF_BUFFER_USAGE_HINT, /**< Hint buffer type is used to allocate ::NV_OF_INPUT_EXECUTE_PARAMS::externalHints.*/ + NV_OF_BUFFER_USAGE_COST, /**< Cost buffer type is used to allocate ::NV_OF_OUTPUT_EXECUTE_PARAMS::outputCostBuffer.*/ + NV_OF_BUFFER_USAGE_MAX +} NV_OF_BUFFER_USAGE; + +/** +* Supported buffer formats +*/ +typedef enum _NV_OF_BUFFER_FORMAT +{ + NV_OF_BUFFER_FORMAT_UNDEFINED, + NV_OF_BUFFER_FORMAT_GRAYSCALE8, /**< Input buffer format with 8 bit planar format */ + NV_OF_BUFFER_FORMAT_NV12, /**< Input buffer format with 8 bit plannar, UV interleaved */ + NV_OF_BUFFER_FORMAT_ABGR8, /**< Input buffer format with 8 bit packed A8B8G8R8 */ + NV_OF_BUFFER_FORMAT_SHORT, /**< Output or hint buffer format for stereo disparity */ + NV_OF_BUFFER_FORMAT_SHORT2, /**< Output or hint buffer format for optical flow vector */ + NV_OF_BUFFER_FORMAT_UINT, /**< Legacy 32-bit Cost buffer format for optical flow vector / stereo disparity. + This cost buffer format is not performance efficient and results in additional GPU usage. + Hence users are strongly recommended to use the 8-bit cost buffer format. + Legacy 32-bit cost buffer format is also planned to be deprecated in future. */ + NV_OF_BUFFER_FORMAT_UINT8, /**< 8-bit Cost buffer format for optical flow vector / stereo disparity. */ + NV_OF_BUFFER_FORMAT_MAX +} NV_OF_BUFFER_FORMAT; + +/** +* Supported stereo disparity range. Avaialble for GPUs later than Turing +*/ +typedef enum _NV_OF_STEREO_DISPARITY_RANGE +{ + NV_OF_STEREO_DISPARITY_RANGE_UNDEFINED, + NV_OF_STEREO_DISPARITY_RANGE_128 = 128, + NV_OF_STEREO_DISPARITY_RANGE_256 = 256, + NV_OF_STEREO_DISPARITY_RANGE_MAX, +} NV_OF_STEREO_DISPARITY_RANGE; + +/** +* \struct NV_OF_FLOW_VECTOR +* Struct needed for optical flow. ::NV_OF_EXECUTE_OUTPUT_PARAMS::outputBuffer will be populated with optical flow +* in ::NV_OF_FLOW_VECTOR format for each ::NV_OF_INIT_PARAMS::outGridSize. +* Flow vectors flowx and flowy are 16-bit values with the lowest 5 bits holding fractional value, +* followed by a 10-bit integer value and the most significant bit being a sign bit. +*/ +typedef struct _NV_OF_FLOW_VECTOR +{ + int16_t flowx; /**< x component of flow in S10.5 format */ + int16_t flowy; /**< y component of flow in S10.5 format */ +} NV_OF_FLOW_VECTOR; + +/** +* \struct NV_OF_STEREO_DISPARITY +* Struct needed for stereo /disparity. ::NV_OF_OUTPUT_EXECUTE_PARAMS::outputBuffer will be populated +* with stereo disparity in ::NV_OF_STEREO_DISPARITY format for each ::NV_OF_INIT_PARAMS::outGridSize. +* Stereo disparity is a 16-bit value with the lowest 5 bits holding fractional value, +* followed by a 11-bit unsigned integer value. +*/ +typedef struct _NV_OF_STEREO_DISPARITY +{ + uint16_t disparity; /**< Horizontal displacement[in pixels] in 11.5 format. */ +} NV_OF_STEREO_DISPARITY; + +/** +* \struct NV_OF_INIT_PARAMS +* Optical flow/stereo disparity session initialization parameters. +*/ +typedef struct _NV_OF_INIT_PARAMS +{ + uint32_t width; /**< [in]: Specifies input buffer width */ + uint32_t height; /**< [in]: Specifies input buffer height */ + NV_OF_OUTPUT_VECTOR_GRID_SIZE outGridSize; /**< [in]: Specifies flow vector grid size for ::NV_OF_EXECUTE_PARAMS::outputBuffer buffer.*/ + NV_OF_HINT_VECTOR_GRID_SIZE hintGridSize; /**< [in]: Specifies flow vector grid size for ::NV_OF_EXECUTE_PARAMS::externalHints buffer. + This field is only considered if ::NV_OF_INIT_PARAMS::enableExternalHints is set. + hintGridSize should be equal or greater than outGridSize. */ + NV_OF_MODE mode; /**< [in]: Operating mode for NVOF. Set to a value defined by enum ::NV_OF_MODE. */ + NV_OF_PERF_LEVEL perfLevel; /**< [in]: Specifies perf level. */ + NV_OF_BOOL enableExternalHints; /**< [in]: Set to 1 to enable external hints for optical flow session. */ + NV_OF_BOOL enableOutputCost; /**< [in]: Set to 1 to enable output cost calculation for optical flow session. */ + NvOFPrivDataHandle hPrivData; /**< [in]: Optical flow private data. It is reserved field and should be set to NULL. */ + NV_OF_STEREO_DISPARITY_RANGE disparityRange; /**< [in]: Speicifies maximum disparity range. + Set to NV_OF_STEREO_DISPARITY_RANGE_UNDEFINED for Turing GPUs. */ + NV_OF_BOOL enableRoi; /**< [in]: Set to 1 to enable estimation of optical flow/stereo for roi. */ +} NV_OF_INIT_PARAMS; + +/** +* \struct NV_OF_BUFFER_DESCRIPTOR +* Creation parameters for optical flow buffers. +*/ +typedef struct _NV_OF_BUFFER_DESCRIPTOR +{ + uint32_t width; /**< [in]: Buffer width. */ + uint32_t height; /**< [in]: Buffer height. */ + NV_OF_BUFFER_USAGE bufferUsage; /**< [in]: To specify buffer usage type. + ::NV_OF_BUFFER_USAGE_OUTPUT buffer usage type accepts ::NV_OF_CREATE_BUFFER::width, + ::NV_OF_BUFFER_DESCRIPTOR::height in ::NV_OF_INIT_PARAMS::outGridSize units. + ::NV_OF_BUFFER_USAGE_HINT buffer usage type accepts ::NV_OF_BUFFER_DESCRIPTOR::width, + ::NV_OF_BUFFER_DESCRIPTOR::height in ::NV_OF_INIT_PARAMS::hintGridSize units. */ + NV_OF_BUFFER_FORMAT bufferFormat; /**< [in]: Buffer format. */ + +} NV_OF_BUFFER_DESCRIPTOR; + +/** +* \struct NV_OF_ROI_RECT +* Specifies the co-ordinates of the Region Of Interest (ROI) +* ROI rects should satisfy below requirements: +* 1. NV_OF_ROI_RECT::start_x should align to (32 * NV_OF_INIT_PARAMS::outGridSize) +* 2. NV_OF_ROI_RECT::width should align to (32 * NV_OF_INIT_PARAMS::outGridSize) +* 3. NV_OF_ROI_RECT::start_y should align to (8 * max(NV_OF_INIT_PARAMS::outGridSize, 2)) +* 4. NV_OF_ROI_RECT::height should align to (8 * NV_OF_INIT_PARAMS::outGridSize) +* 5. NV_OF_ROI_RECT::width >= 32 && NV_OF_ROI_RECT::height >= 16; maximum size 8192x8192 +* 6. Whole ROI region should be inside of the image +* Optical flow/stereo disparity vectors out side of ROI are invalid and should not be used. +*/ +struct NV_OF_ROI_RECT +{ + uint32_t start_x; /**< [in]: ROI start position in x-direction. */ + uint32_t start_y; /**< [in]: ROI start position in y-direction. */ + uint32_t width; /**< [in]: Width of ROI. */ + uint32_t height; /**< [in]: Height of ROI. */ +}; + +/** +* \struct NV_OF_EXECUTE_INPUT_PARAMS +* Parameters which are sent per frame for optical flow/stereo disparity execution. +*/ +typedef struct _NV_OF_EXECUTE_INPUT_PARAMS +{ + NvOFGPUBufferHandle inputFrame; /**< [in]: If ::NV_OF_INIT_PARAMS::mode is ::NV_OF_MODE_OPTICALFLOW, this specifies the handle to the buffer containing the input frame. + If ::NV_OF_INIT_PARAMS::mode is ::NV_OF_MODE_STEREODISPARITY, this specifies the handle to the buffer containing the rectified left view. */ + NvOFGPUBufferHandle referenceFrame; /**< [in]: If ::NV_OF_INIT_PARAMS::mode is ::NV_OF_MODE_OPTICALFLOW, this specifies the handle to the buffer containing the reference frame. + If ::NV_OF_INIT_PARAMS::mode is ::NV_OF_MODE_STEREODISPARITY, this specifies the handle to the buffer containing the rectified right view. */ + NvOFGPUBufferHandle externalHints; /**< [in]: It is an optional input, This field will be considered if client had set ::NV_OF_INIT_PARAMS::enableExternalHint flag. + Client can pass some available predictors as hints. + Optical flow driver will search around those hints to optimize flow vectors quality. + Expected hint buffer format is ::NV_OF_FLOW_VECTOR, ::NV_OF_STEREO_DISPARITY + for ::NV_OF_MODE_OPTICALFLOW, ::NV_OF_MODE_STEREODISPARITY modes respectively for + each ::NV_OF_INIT_PARAMS::hintGridSize in a frame. */ + NV_OF_BOOL disableTemporalHints; /**< [in]: Temporal hints yield better accuracy flow vectors when running on successive frames of a continuous video (without major scene changes). + When disableTemporalHints = 0, optical flow vectors from previous NvOFExecute call are automatically used as hints for the current NvOFExecute call. + However, when running optical flow on pairs of images which are completely independent of each other, temporal hints are useless + and in fact, they will degrade the quality. Therefore, it is recommended to set disableTemporalHints = 1 in this case.*/ + uint32_t padding; /**< [in]: Padding. Must be set to 0. */ + NvOFPrivDataHandle hPrivData; /**< [in]: Optical flow private data handle. It is reserved field and should be set to NULL. */ + uint32_t padding2; /**< [in]: Padding. Must be set to 0. */ + uint32_t numRois; /**< [in]: Number of ROIs. */ + NV_OF_ROI_RECT* roiData; /**< [in]: Pointer to the NV_OF_ROI_RECTs data. Size of this buffer should be atleast numROIs * sizeof(NV_OF_ROI_RECT). */ +} NV_OF_EXECUTE_INPUT_PARAMS; + +/** +* \struct NV_OF_EXECUTE_OUTPUT_PARAMS +* Parameters which are received per frame for optical flow/stereo disparity execution. +*/ +typedef struct _NV_OF_EXECUTE_OUTPUT_PARAMS +{ + NvOFGPUBufferHandle outputBuffer; /**< [in]: Specifies the pointer to optical flow or stereo disparity buffer handle. + ::outputBuffer will be populated with optical flow in + ::NV_OF_FLOW_VECTOR format or stereo disparity in + ::NV_OF_STEREO_DISPARITY format for each + ::NV_OF_VECTOR_GRID_SIZE::outGridSize in a frame.*/ + NvOFGPUBufferHandle outputCostBuffer; /**< [in]: Specifies the pointer to output cost calculation buffer handle. */ + NvOFPrivDataHandle hPrivData; /**< [in]: Optical flow private data handle. It is reserved field and should be set to NULL. */ +} NV_OF_EXECUTE_OUTPUT_PARAMS; + +/** +* \brief Initialize NVIDIA Video Optical Flow Interface and validates input params. +* +* Initializes NVIDIA Video Optical Flow Interface and validates input params. +* It also initializes NVIDIA Video Optical Flow driver with the init value passed in ::NV_OF_INIT_PARAMS +* structure. +* +* \param [in] hOf +* Object of ::NvOFHandle type. +* \param [in] initParams +* Pointer to the ::NV_OF_INIT_PARAMS structure. +* +* \return +* ::NV_OF_SUCCESS \n +* ::NV_OF_ERR_INVALID_PTR \n +* ::NV_OF_ERR_UNSUPPORTED_DEVICE \n +* ::NV_OF_ERR_DEVICE_DOES_NOT_EXIST \n +* ::NV_OF_ERR_UNSUPPORTED_PARAM \n +* ::NV_OF_ERR_OUT_OF_MEMORY \n +* ::NV_OF_ERR_INVALID_PARAM \n +* ::NV_OF_ERR_INVALID_VERSION \n +* ::NV_OF_ERR_OF_NOT_INITIALIZED \n +* ::NV_OF_ERR_GENERIC \n +*/ +typedef NV_OF_STATUS(NVOFAPI* PFNNVOFINIT) (NvOFHandle hOf, const NV_OF_INIT_PARAMS *initParams); + +/** +* \brief Kick off computation of optical flow between input and reference frame. +* +* This is asynchronous function call which kicks off computation of optical flow or stereo disparity +* between ::NV_OF_EXECUTE_INPUT_PARAMS::inputFrame and ::NV_OF_EXECUTE_INPUT_PARAMS::referenceFrame and returns +* after submitting execute paramaters to optical flow engine. +* ::NV_OF_EXECUTE_OUTPUT_PARAMS::outputBuffer will be populated with optical flow or stereo disparity +* based on ::NV_OF_INIT_PARAMS:mode is NV_OF_MODE_OPTICALFLOW or NV_OF_MODE_STEREODISPARITY respectively. +* +* \param [in] hOf +* Object of ::NvOFHandle type. +* \param [in] executeInParams +* pointer to the ::NV_OF_EXECUTE_INPUT_PARAMS structure. +* \param [out] executeOutParams +* pointer to the ::NV_OF_EXECUTE_OUTPUT_PARAMS structure. +* +* \return +* ::NV_OF_SUCCESS \n +* ::NV_OF_ERR_INVALID_PTR \n +* ::NV_OF_ERR_INVALID_DEVICE \n +* ::NV_OF_ERR_DEVICE_DOES_NOT_EXIST \n +* ::NV_OF_ERR_UNSUPPORTED_PARAM \n +* ::NV_OF_ERR_OUT_OF_MEMORY \n +* ::NV_OF_ERR_INVALID_PARAM \n +* ::NV_OF_ERR_INVALID_VERSION \n +* ::NV_OF_ERR_OF_NOT_INITIALIZED \n +* ::NV_OF_ERR_GENERIC \n +*/ +typedef NV_OF_STATUS(NVOFAPI* PFNNVOFEXECUTE) (NvOFHandle hOf, const NV_OF_EXECUTE_INPUT_PARAMS *executeInParams, NV_OF_EXECUTE_OUTPUT_PARAMS *executeOutParams); + +/** +* \brief Release optical flow API and driver resources. +* +* Releases resources and waits until all resources are gracefully released. +* +* \param [in] hOf +* Object of ::NvOFHandle type. +* +* \return +* ::NV_OF_SUCCESS \n +* ::NV_OF_ERR_INVALID_PTR \n +* ::NV_OF_ERR_DEVICE_DOES_NOT_EXIST \n +* ::NV_OF_ERR_OF_NOT_INITIALIZED \n +* ::NV_OF_ERR_GENERIC \n +*/ +typedef NV_OF_STATUS(NVOFAPI* PFNNVOFDESTROY) (NvOFHandle hOf); + +/** +* \brief Populate error buffer with the description of last failure. +* +* Populates lastError[] with the description of last failure. +* +* \param [in] hOf +* Object of ::NvOFHandle type. +* \param [in/out] lastError +* lastError is a char array, minimum expected size of lastError[] is MIN_ERROR_STRING_SIZE characters. +* After execution of this function call, lastError[] is populated with error string. +* \param [in/out] As an input parameter, "size" indicates the size of the array provided by the client. +* After execution of this function call, "size" field indicates the number of characters written into +* "lastError" excluding null character. +* \return +* ::NV_OF_SUCCESS \n +* ::NV_OF_ERR_INVALID_PTR \n +* ::NV_OF_ERR_DEVICE_DOES_NOT_EXIST \n +* ::NV_OF_ERR_OF_NOT_INITIALIZED \n +* ::NV_OF_ERR_GENERIC \n +*/ +typedef NV_OF_STATUS(NVOFAPI* PFNNVOFGETLASTERROR) (NvOFHandle hOf, char lastError[], uint32_t *size); + +/** +* \brief Populate capability array for specified ::NV_OF_CAPS value. +* This is to be called in two stages. +* It returns the number of capability values for specified ::NV_OF_CAPS value when +* queried with "capsVal" set to NULL. +* It populates capsVal array with capability values for specified ::NV_OF_CAPS value +* when queried with "capsVal" set to non-NULL value. +* +* \param [in] hOf +* Object of ::NvOFHandle type. +* \param [in] capsParam +* object of ::NV_OF_CAPS type. +* \param [out] capsVal +* Pointer to uint32_t, minimum expected size of capsVal is the "size" returned by the this function call +* queried with "capsVal" set to NULL. +* \param [out] size +* Pointer to uint32_t, which stores size of populated capsVal. +* +* \return +* ::NV_OF_SUCCESS \n +* ::NV_OF_ERR_INVALID_PTR \n +* ::NV_OF_ERR_DEVICE_DOES_NOT_EXIST \n +* ::NV_OF_ERR_OF_NOT_INITIALIZED \n +* ::NV_OF_ERR_GENERIC \n +*/ +typedef NV_OF_STATUS(NVOFAPI* PFNNVOFGETCAPS) (NvOFHandle hOf, NV_OF_CAPS capsParam, uint32_t *capsVal, uint32_t *size); + +/** +* \brief Get the largest API version supported by the driver. +* +* This function can be used by clients to determine if the driver supports +* the API header the application was compiled with. +* +* \param [out] version +* Pointer to the requested value. The 4 least significant bits in the returned +* indicate the minor version and the rest of the bits indicate the major +* version of the largest supported version. +* +* \return +* ::NV_OF_SUCCESS \n +* ::NV_OF_ERR_INVALID_PTR \n +*/ +NV_OF_STATUS NVOFAPI NvOFGetMaxSupportedApiVersion(uint32_t* version); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/nvOpticalFlowCuda.h b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/nvOpticalFlowCuda.h new file mode 100644 index 00000000..22fdedcb --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/nvOpticalFlowCuda.h @@ -0,0 +1,241 @@ +/* +* This copyright notice applies to this header file only: +* +* Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the software, and to permit persons to whom the +* software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ +/** +* \file NvOpticalFlowCuda.h +* NVIDIA GPUs - Turing and above contains a hardware-based optical flow engine +* which provides fully-accelerated hardware-based optical flow and stereo estimation. +* nvOpticalFlowCuda.h provides cuda specific enums, structure definitions and function pointers prototypes. +* \date 2018 +* This file contains CUDA specific enums, structure definitions and function prototypes. +*/ + +#ifndef _NV_OPTICALFLOW_CUDA_H_ +#define _NV_OPTICALFLOW_CUDA_H_ +#include "nvOpticalFlowCommon.h" +#include +#define MAX_NUM_PLANES 3 + +#if defined(__cplusplus) + +extern "C" +{ +#endif /* __cplusplus */ + +/** +* Supported CUDA buffer types. +*/ +typedef enum _NV_OF_CUDA_BUFFER_TYPE +{ + NV_OF_CUDA_BUFFER_TYPE_UNDEFINED, + NV_OF_CUDA_BUFFER_TYPE_CUARRAY, /**< Buffer type is CUarray */ + NV_OF_CUDA_BUFFER_TYPE_CUDEVICEPTR, /**< Buffer type is CUdeviceptr */ + NV_OF_CUDA_BUFFER_TYPE_MAX +} NV_OF_CUDA_BUFFER_TYPE; + +/** +* \struct NV_BUFFER_STRIDE +* Horizontal and vertical strides of a plane. +*/ +typedef struct _NV_OF_BUFFER_STRIDE +{ + uint32_t strideXInBytes; /**< Horizontal stride. */ + uint32_t strideYInBytes; /**< Vertical stride. */ +} NV_OF_BUFFER_STRIDE; + +/** +* \struct NV_OF_CUDA_BUFFER_STRIDE_INFO +* This structure stores buffer stride information which is populated in the ::nvOFGPUBufferGetStrideInfo() API. +*/ +typedef struct _NV_OF_CUDA_BUFFER_STRIDE_INFO +{ + NV_OF_BUFFER_STRIDE strideInfo[MAX_NUM_PLANES]; /**< Stride information of each plane.*/ + uint32_t numPlanes; /**< Number of planes. */ +} NV_OF_CUDA_BUFFER_STRIDE_INFO; + +/** +* \brief Create an instance of NvOFHandle object. +* +* This function creates an instance of NvOFHandle object and returns status. +* Client is expected to release NvOFHandle resource using Destroy function call. +* +* \param [in] cuContext +* Should be set to cuda context created by Client. +* \param [out] NvOFHandle* +* Pointer of class ::NvOFHandle object. +* +* \return +* ::NV_OF_SUCCESS \n +* ::NV_OF_ERR_OUT_OF_MEMORY \n +* ::NV_OF_ERR_INVALID_VERSION \n +* ::NV_OF_ERR_UNSUPPORTED_PARAM \n +*/ +typedef NV_OF_STATUS(NVOFAPI* PFNNVCREATEOPTICALFLOWCUDA) (CUcontext device, NvOFHandle *hOf); + +/** +* \brief Set input and output cuda stream for specified optical flow instance. +* +* Optical flow algorithm may optionally involve cuda preprocessing on the input buffers and post +* processing on the output flow vectors. This function is used to set input and output cuda stream +* to pipeline and synchronize the cuda preprocessing and post processing tasks with OF HW engine. +* Client should call this function before Execute function to update input and/or output streams otherwise +* Execute function will either use preset input, output streams or default streams(If streams are never set before). +* +* \param [in] hOf +* Object of ::NvOFHandle type. +* \param [in] inputStream +* CUstream type object which is used to process ::NV_OF_EXECUTE_PARAMS::inputFrame, +* ::NV_OF_EXECUTE_PARAMS::referenceFrame and optional NV_OF_EXECUTE_PARAMS::externalHints. +* \param [in] outputStream +* CUstream type object which is used to process ::NV_OF_EXECUTE_PARAMS::outputBuffer and +* optional NV_OF_EXECUTE_PARAMS::costBuffer. +* +* \return +* ::NV_OF_SUCCESS \n +* ::NV_OF_ERR_INVALID_PTR \n +* ::NV_OF_ERR_INVALID_DEVICE \n +* ::NV_OF_ERR_DEVICE_DOES_NOT_EXIST \n +* ::NV_OF_ERR_UNSUPPORTED_PARAM \n +* ::NV_OF_ERR_OUT_OF_MEMORY \n +* ::NV_OF_ERR_INVALID_PARAM \n +* ::NV_OF_ERR_INVALID_VERSION \n +* ::NV_OF_ERR_OF_NOT_INITIALIZED \n +* ::NV_OF_ERR_GENERIC \n +*/ +typedef NV_OF_STATUS(NVOFAPI* PFNNVOFSETIOCUDASTREAMS) (NvOFHandle hOf, CUstream inputStream, CUstream outputStream); + +/** +* \brief Create ::NvOFGPUBufferHandle resource. +* +* This function creates ::NvOFGPUBufferHandle resource for specified cuda bufferType. +* +* \param [in] hOf +* Pointer to the NvOFHandle. +* \param [in] createBufferParams +* pointer of the ::NV_OF_CREATE_BUFFER. +* \param [out] ofGpuBuffer +* Output pointer of ::NvOFGPUBufferHandle type. +* +* \return +* ::NV_OF_SUCCESS \n +* ::NV_OF_ERR_INVALID_PTR \n +* ::NV_OF_ERR_DEVICE_DOES_NOT_EXIST \n +* ::NV_OF_ERR_OUT_OF_MEMORY \n +* ::NV_OF_ERR_INVALID_PARAM \n +* ::NV_OF_ERR_GENERIC \n +*/ +typedef NV_OF_STATUS(NVOFAPI* PFNNVOFCREATEGPUBUFFERCUDA) (NvOFHandle hOf, const NV_OF_BUFFER_DESCRIPTOR *bufferDesc, + NV_OF_CUDA_BUFFER_TYPE bufferType, NvOFGPUBufferHandle *hOfGpuBuffer); + +/** +* \brief Return CUarray object associated with ::NvOFGPUBufferHandle type resource. +* +* \param [in] ofGpuBuffer +* Object of type NvOFGPUBufferHandle, created by a call to NvOFCreateGPUBufferCuda() with bufferType set to ::NV_OF_CUDA_BUFFER_TYPE_CUARRAY. +* +* \return +* Object of CUarray type. +* If ofGpubuffer corresponds to a GPU buffer that was not created with buffer type NV_OF_CUDA_BUFFER_TYPE_CUARRAY, +* this function returns NULL +*/ +typedef CUarray(NVOFAPI* PFNNVOFGPUBUFFERGETCUARRAY) (NvOFGPUBufferHandle ofGpuBuffer); + +/** +* \brief Return CUdeviceptr object associated with ::NvOFGPUBufferHandle type resource. +* +* \param [in] ofGpuBuffer +* Object of type NvOFGPUBufferHandle, created by a call to NvOFCreateGPUBufferCuda() with bufferType set to ::NV_OF_CUDA_BUFFER_TYPE_CUDEVICEPTR. +* +* \return +* Object of the CUdeviceptr type. +* If ofGpubuffer corresponds to a GPU buffer that was not created with buffer type NV_OF_CUDA_BUFFER_TYPE_CUDEVICEPTR, +* this function returns 0 +*/ +typedef CUdeviceptr(NVOFAPI* PFNNVOFGPUBUFFERGETCUDEVICEPTR) (NvOFGPUBufferHandle ofGpuBuffer); + +/** +* \brief Populates buffer information associated with ::NvOFGPUBufferHandle type resource. +* +* Populates structure ::NV_OF_CUDA_BUFFER_STRIDE_INFO with the horizontal and vertical stride details of all the planes. +* \param [in] ofGpuBuffer +* Object of type NvOFGPUBufferHandle, created by a call to NvOFCreateGPUBufferCuda(). +* \param [out] strideInfo +* pointer to the ::NV_OF_CUDA_BUFFER_STRIDE_INFO. +* +* \return +* ::NV_OF_SUCCESS \n +* ::NV_OF_ERR_INVALID_PTR \n +*/ +typedef NV_OF_STATUS(NVOFAPI* PFNVOFGPUBUFFERGETSTRIDEINFO) (NvOFGPUBufferHandle ofGpuBuffer, NV_OF_CUDA_BUFFER_STRIDE_INFO *strideInfo); + +/** +* \brief Destroy NvOFGPUBufferHandle object and associated resources. +* +* +* \return +* ::NV_OF_SUCCESS \n +* ::NV_OF_ERR_GENERIC \n +*/ +typedef NV_OF_STATUS(NVOFAPI* PFNNVOFDESTROYGPUBUFFERCUDA) (NvOFGPUBufferHandle buffer); + +/** +* \struct NV_OF_CUDA_API_FUNCTION_LIST +* This is structure of function pointers which are populated by ::NvOFAPICreateInstanceCuda() API. +* Defination of each cuda specific function pointer is defined above. +*/ +typedef struct _NV_OF_CUDA_API_FUNCTION_LIST +{ + PFNNVCREATEOPTICALFLOWCUDA nvCreateOpticalFlowCuda; + PFNNVOFINIT nvOFInit; + PFNNVOFCREATEGPUBUFFERCUDA nvOFCreateGPUBufferCuda; + PFNNVOFGPUBUFFERGETCUARRAY nvOFGPUBufferGetCUarray; + PFNNVOFGPUBUFFERGETCUDEVICEPTR nvOFGPUBufferGetCUdeviceptr; + PFNVOFGPUBUFFERGETSTRIDEINFO nvOFGPUBufferGetStrideInfo; + PFNNVOFSETIOCUDASTREAMS nvOFSetIOCudaStreams; + PFNNVOFEXECUTE nvOFExecute; + PFNNVOFDESTROYGPUBUFFERCUDA nvOFDestroyGPUBufferCuda; + PFNNVOFDESTROY nvOFDestroy; + PFNNVOFGETLASTERROR nvOFGetLastError; + PFNNVOFGETCAPS nvOFGetCaps; +} NV_OF_CUDA_API_FUNCTION_LIST; + +/** +* \brief ::NvOFAPICreateInstanceCuda() API is the entry point to the NvOFAPI interface. +* +* ::NvOFAPICreateInstanceCuda() API populates functionList with function pointers to the API routines implemented by the + * NvOFAPI interface. +* +* \return +* ::NV_OF_SUCCESS \n +* ::NV_OF_ERR_INVALID_VERSION \n +* :: NV_OF_ERR_INVALID_PTR \n +*/ +NV_OF_STATUS NVOFAPI NvOFAPICreateInstanceCuda(uint32_t apiVer, NV_OF_CUDA_API_FUNCTION_LIST *functionList); +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/optixOpticalFlow.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/optixOpticalFlow.cpp new file mode 100644 index 00000000..3153c285 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/optixOpticalFlow.cpp @@ -0,0 +1,282 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "optix_denoiser_opticalflow.h" + +//------------------------------------------------------------------------------ +// +// optixOpticalFlow -- Demonstration of OptiX optical flow +// +//------------------------------------------------------------------------------ + +// filename is copied to result and the first sequence of "+" characters is +// replaced (using leading zeros) with framename. +// true is returned if the framenumber is -1 or if the function was successful. + +static bool getFrameFilename( std::string& result, const std::string& filename, int frame ) +{ + result = filename; + if( frame == -1 ) + return true; + size_t nplus = 0; + size_t ppos = result.find( '+' ); + if( ppos == std::string::npos ) + return true; // static filename without "+" characters + size_t cpos = ppos; + while( result[cpos] != 0 && result[cpos] == '+' ) + { + nplus++; + cpos++; + } + std::string fn = std::to_string( frame ); + if( fn.length() > nplus ) + { + std::cerr << "illegal temporal filename, framenumber requires " << fn.length() + << " digits, \"+\" placeholder length: " << nplus << "too small" << std::endl; + return false; + } + for( size_t i = 0; i < nplus; i++ ) + result[ppos + i] = '0'; + for( size_t i = 0; i < fn.length(); i++ ) + result[ppos + nplus - 1 - i] = fn[fn.length() - 1 - i]; + return true; +} + +void printUsageAndExit( const std::string& argv0 ) +{ + std::cerr << "Usage: " << argv0 << " [-o flow.exr] [-F | --Frames ] frame1.exr [frame2.exr]\n"; + std::cerr << "Input image and flow output filenames could have '+' in the name, which is replaced by the frame number.\n"; + std::cerr << "Calculates flow vectors from frame1 to frame2\n"; + exit( 1 ); +} + +// Create float OptixImage2D with given dimension and channel count. Allocate memory on device. + +static OptixImage2D createOptixImage2D( unsigned int width, unsigned int height, unsigned int nChannels ) +{ + OptixImage2D oi = {}; + + const uint64_t frame_byte_size = width * height * nChannels * sizeof( float ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &oi.data ), frame_byte_size ) ); + oi.width = width; + oi.height = height; + oi.rowStrideInBytes = width * nChannels * sizeof( float ); + oi.pixelStrideInBytes = nChannels * sizeof( float ); + oi.format = nChannels == 2 ? OPTIX_PIXEL_FORMAT_FLOAT2 : nChannels == 3 ? OPTIX_PIXEL_FORMAT_FLOAT3 : OPTIX_PIXEL_FORMAT_FLOAT4; + return oi; +} + +static void destroyOptixImage2D( OptixImage2D& image ) +{ + CUDA_CHECK( cudaFree( reinterpret_cast ( image.data ) ) ); +} + +// Copy host memory to device memory + +static void initOptixImage2D( OptixImage2D& result, const float* hmem ) +{ + const uint64_t frame_byte_size = result.height * result.rowStrideInBytes; + CUDA_CHECK( cudaMemcpy( reinterpret_cast( result.data ), hmem, frame_byte_size, cudaMemcpyHostToDevice ) ); +} + +int32_t main( int32_t argc, char** argv ) +{ + int firstFrame = -1, lastFrame = -1; + + std::string outputFilename; + std::string inputFilename1; + std::string inputFilename2; + + if( argc < 3 ) // minimum: two image filenames + printUsageAndExit( argv[0] ); + + for( int32_t i = 1; i < argc; ++i ) + { + std::string arg( argv[i] ); + + if( arg == "-o" || arg == "--out" ) + { + if( i == argc - 2 ) + printUsageAndExit( argv[0] ); + outputFilename = argv[++i]; + } + else if( arg == "-F" || arg == "--Frames" ) + { + if( i == argc - 2 ) + printUsageAndExit( argv[0] ); + std::string s( argv[++i] ); + size_t cpos = s.find( '-' ); + if( cpos == 0 || cpos == s.length() - 1 || cpos == std::string::npos ) + printUsageAndExit( argv[0] ); + firstFrame = atoi( s.substr( 0, cpos ).c_str() ); + lastFrame = atoi( s.substr( cpos + 1 ).c_str() ); + if( firstFrame < 0 || lastFrame < 0 || firstFrame > lastFrame ) + { + std::cerr << "illegal frame range, first frame must be <= last frame and >= 0" << std::endl; + exit( 0 ); + } + } + else + { + if( inputFilename1.empty() ) + inputFilename1 = arg; + else if( inputFilename2.empty() ) + inputFilename2 = arg; + else + printUsageAndExit( argv[0] ); + } + } + + if( firstFrame >= 0 && ( firstFrame == lastFrame ) ) + { + std::cerr << "Last frame number must be greater than first frame number."; + return 1; + } + + try + { + CUcontext cuCtx = 0; + CUDA_CHECK( (cudaError_t)cuInit( 0 ) ); + CUDA_CHECK( (cudaError_t)cuCtxCreate( &cuCtx, 0, 0 ) ); + CUstream stream = 0; + + OptixUtilOpticalFlow oflow; + + std::string frameFilename; + if( !getFrameFilename( frameFilename, inputFilename1, firstFrame ) ) + return 1; + + sutil::ImageBuffer frame0 = sutil::loadImage( frameFilename.c_str() ); + std::cout << "Optical flow with resolution " << frame0.width << " x " << frame0.height << std::endl; + std::cout << "Loaded " << frameFilename << std::endl; + + unsigned int width = frame0.width; + unsigned int height = frame0.height; + + OptixImage2D images[2] = { createOptixImage2D( width, height, frame0.pixel_format == sutil::FLOAT4 ? 4 : 3 ), + createOptixImage2D( width, height, frame0.pixel_format == sutil::FLOAT4 ? 4 : 3 ) }; + + initOptixImage2D( images[0], (const float*)frame0.data ); + frame0.destroy(); + + if( const OptixResult res = oflow.init( cuCtx, stream, width, height ) ) + { + std::cerr << "Initialization of optical flow failed: " << oflow.getLastError() << "\n"; + return 1; + } + + // We could create a 2-channel format for flow, but sutil::ImageBuffer does not support this format. + // The optical flow implementation will leave the third channel as-is and write only the first two. + // A fp16 format would be sufficient for the flow vectors, for simplicity we use fp32 here. + OptixImage2D flow = createOptixImage2D( width, height, 3 ); + + void * hflow; + CUDA_CHECK( (cudaError_t)cuMemAllocHost( &hflow, images[0].rowStrideInBytes * height ) ); + + if( lastFrame == -1 ) + { + lastFrame = 0; + frameFilename = inputFilename2; + } + + for( int frame = firstFrame; frame < lastFrame; frame++ ) + { + if( frame != -1 && !getFrameFilename( frameFilename, inputFilename1, frame+1 ) ) + return 1; + + sutil::ImageBuffer frame1 = sutil::loadImage( frameFilename.c_str() ); + std::cout << "Loaded " << frameFilename << std::endl; + + if( frame1.width != width || frame1.height != height ) + { + std::cerr << "Input files must have the same resolution" << std::endl; + return 1; + } + if( !( frame1.pixel_format == sutil::FLOAT3 || frame1.pixel_format == sutil::FLOAT4 ) ) + { + std::cerr << "Input files must have three or four channels" << std::endl; + return 1; + } + initOptixImage2D( images[1], (const float*)frame1.data ); + + OptixResult res = oflow.computeFlow( flow, images ); + + if( res != OPTIX_SUCCESS ) + { + std::cerr << "Error in flow calculation: " << oflow.getLastError() << std::endl; + return 1; + } + + initOptixImage2D( images[0], (const float*)frame1.data ); + frame1.destroy(); + + CUDA_CHECK( (cudaError_t)cuMemcpyDtoHAsync( hflow, flow.data, flow.rowStrideInBytes * flow.height, stream ) ); + CUDA_CHECK( (cudaError_t)cuStreamSynchronize( stream ) ); + + sutil::ImageBuffer flowImage = {}; + flowImage.width = width; + flowImage.height = height; + flowImage.data = hflow; + flowImage.pixel_format = sutil::FLOAT3; + + if( !getFrameFilename( frameFilename, outputFilename, frame+1 ) ) + return 1; + + if( !frameFilename.empty() ) + { + sutil::saveImage( frameFilename.c_str(), flowImage, false ); + std::cout << "Wrote " << frameFilename << std::endl; + } + } + CUDA_CHECK( (cudaError_t)cuMemFreeHost( hflow ) ); + + destroyOptixImage2D( images[0] ); + destroyOptixImage2D( images[1] ); + destroyOptixImage2D( flow ); + + oflow.destroy(); + } + catch( std::exception& e ) + { + std::cerr << "ERROR: exception caught '" << e.what() << "'" << std::endl; + } + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/optixOpticalFlow.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/optixOpticalFlow.cu new file mode 100644 index 00000000..4e61cb51 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/optixOpticalFlow.cu @@ -0,0 +1,171 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include "optix_denoiser_opticalflow.h" + + +static inline unsigned int divUp( unsigned int nominator, unsigned int denominator ) +{ + return ( nominator + denominator - 1 ) / denominator; +} + +struct floatRdAccess +{ + inline floatRdAccess( const OptixImage2D& im ) + : image( im ) + , psb( im.pixelStrideInBytes ) + , hf( image.format == OPTIX_PIXEL_FORMAT_HALF2 || image.format == OPTIX_PIXEL_FORMAT_HALF3 || image.format == OPTIX_PIXEL_FORMAT_HALF4 ) + { + if( im.pixelStrideInBytes == 0 ) + { + unsigned int dsize = hf ? sizeof( __half ) : sizeof( float ); + psb = getNumChannels( im ) * dsize; + } + } + inline __device__ float read( int x, int y, int c ) const + { + if( hf ) + return float( *(const __half*)( image.data + y * image.rowStrideInBytes + x * psb + c * sizeof( __half ) ) ); + else + return float( *(const float*)( image.data + y * image.rowStrideInBytes + x * psb + c * sizeof( float ) ) ); + } + OptixImage2D image; + unsigned int psb; + bool hf; +}; + +struct floatWrAccess +{ + inline floatWrAccess( const OptixImage2D& im ) + : image( im ) + , psb( im.pixelStrideInBytes ) + , hf( image.format == OPTIX_PIXEL_FORMAT_HALF2 || image.format == OPTIX_PIXEL_FORMAT_HALF3 || image.format == OPTIX_PIXEL_FORMAT_HALF4 ) + { + if( im.pixelStrideInBytes == 0 ) + { + unsigned int dsize = hf ? sizeof( __half ) : sizeof( float ); + psb = getNumChannels( im ) * dsize; + } + } + inline __device__ void write( int x, int y, int c, float value ) + { + if( hf ) + *(__half*)( image.data + y * image.rowStrideInBytes + x * psb + c * sizeof( __half ) ) = value; + else + *(float*)( image.data + y * image.rowStrideInBytes + x * psb + c * sizeof( float ) ) = value; + } + OptixImage2D image; + unsigned int psb; + bool hf; +}; + +static __global__ void k_convertRGBA( unsigned char* result, floatRdAccess input, int outStrideX ) +{ + const int x = blockIdx.x * blockDim.x + threadIdx.x; + const int y = blockIdx.y * blockDim.y + threadIdx.y; + + if( x >= input.image.width || y >= input.image.height ) + return; + + unsigned int r = __saturatef( input.read( x, y, 0 ) ) * 255.f; + unsigned int g = __saturatef( input.read( x, y, 1 ) ) * 255.f; + unsigned int b = __saturatef( input.read( x, y, 2 ) ) * 255.f; + + *(unsigned int*)&result[y * outStrideX + x * 4] = b | ( g << 8 ) | ( r << 16 ) | ( 255u << 24 ); +} + +static __global__ void k_convertFlow( floatWrAccess result, const int16_t* input, int inStrideX ) +{ + const int x = blockIdx.x * blockDim.x + threadIdx.x; + const int y = blockIdx.y * blockDim.y + threadIdx.y; + + if( x >= result.image.width || y >= result.image.height ) + return; + + result.write( x, y, 0, float( input[y * inStrideX + x * 2 + 0] ) * ( 1.f / 32.f ) ); + result.write( x, y, 1, float( input[y * inStrideX + x * 2 + 1] ) * ( 1.f / 32.f ) ); +} + +OptixResult convertRGBA( unsigned char* result, const OptixImage2D& input, uint32_t inStrideXInBytes, CUstream stream ) +{ + dim3 block( 32, 32, 1 ); + dim3 grid = dim3( divUp( input.width, block.x ), divUp( input.height, block.y ), 1 ); + + k_convertRGBA<<>>( result, floatRdAccess( input ), inStrideXInBytes ); + + return OPTIX_SUCCESS; +} + +OptixResult convertFlow( OptixImage2D& result, const int16_t* flow, uint32_t outStrideXInBytes, CUstream stream ) +{ + dim3 block( 32, 32, 1 ); + dim3 grid = dim3( divUp( result.width, block.x ), divUp( result.height, block.y ), 1 ); + + // convert 2x16 bit fixpoint to 2xfp16/2xfp32 bit flow vectors + k_convertFlow<<>>( floatWrAccess( result ), flow, outStrideXInBytes ); + + return OPTIX_SUCCESS; +} + +extern OptixResult runOpticalFlow( CUcontext ctx, CUstream stream, OptixImage2D & flow, OptixImage2D input[2], float & flowTime, std::string & errMessage ) +{ + OptixUtilOpticalFlow oflow; + + if( const OptixResult res = oflow.init( ctx, stream, input[0].width, input[0].height ) ) + { + errMessage = oflow.getLastError(); + return res; + } + + CUevent start, stop; + cuEventCreate( &start, 0 ); + cuEventCreate( &stop, 0 ); + cuEventRecord( start, stream ); + + if( const OptixResult res = oflow.computeFlow( flow, input ) ) + { + errMessage = oflow.getLastError(); + cuEventDestroy( start ); + cuEventDestroy( stop ); + return res; + } + + cuEventRecord(stop, stream); + cuEventSynchronize( stop ); + cuEventElapsedTime(&flowTime, start, stop); + + cuEventDestroy( start ); + cuEventDestroy( stop ); + + return oflow.destroy(); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/optix_denoiser_opticalflow.h b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/optix_denoiser_opticalflow.h new file mode 100644 index 00000000..23354d5f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixOpticalFlow/optix_denoiser_opticalflow.h @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of NVIDIA CORPORATION nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/// @file +/// @author NVIDIA Corporation +/// @brief OptiX public API header + +#ifndef optix_denoiser_opticalflow_h +#define optix_denoiser_opticalflow_h + +#ifndef _WIN32 +#include +#else +#define no_init_all deprecated +#include +#endif + +#include + +#include "nvOpticalFlowCommon.h" +#include "nvOpticalFlowCuda.h" +#include +#include +#include + +extern OptixResult convertRGBA( unsigned char* result, const OptixImage2D& input, uint32_t inStrideXInBytes, CUstream stream ); +extern OptixResult convertFlow( OptixImage2D& result, const int16_t* flow, uint32_t outStrideXInBytes, CUstream stream ); +extern OptixResult runOpticalFlow( CUcontext ctx, CUstream stream, OptixImage2D & flow, OptixImage2D input[2], float & flowTime, std::string & errMessage ); + +static inline unsigned int getNumChannels( const OptixImage2D& image ) +{ + switch( image.format ) + { + // obsolete formats - not supported + case OPTIX_PIXEL_FORMAT_UCHAR3: + return 3; + case OPTIX_PIXEL_FORMAT_UCHAR4: + return 4; + + case OPTIX_PIXEL_FORMAT_HALF2: + case OPTIX_PIXEL_FORMAT_FLOAT2: + return 2; + case OPTIX_PIXEL_FORMAT_HALF3: + case OPTIX_PIXEL_FORMAT_FLOAT3: + return 3; + case OPTIX_PIXEL_FORMAT_HALF4: + case OPTIX_PIXEL_FORMAT_FLOAT4: + return 4; + + // internal format, not used in this sample + case OPTIX_PIXEL_FORMAT_INTERNAL_GUIDE_LAYER: + return 0; + + default: + return 0; + } +} + +class OptixUtilOpticalFlow +{ + public: + /// Constructor + OptixUtilOpticalFlow() + : m_ofh( nullptr ) + , m_gpuBufferOut( nullptr ) + { + m_gpuBufferIn[0] = nullptr; + m_gpuBufferIn[1] = nullptr; + m_hModule = nullptr; + } + + /// Destructor + ~OptixUtilOpticalFlow(){}; + + /// Initialize optical flow class + /// + /// \param[in] ctx the device context + /// \param[in] stream the stream used for operations in this class + /// \param[in] width width of images passed to this class + /// \param[in] height height of images passed to this class + OptixResult init( CUcontext ctx, CUstream stream, unsigned int width, unsigned int height ) + { + m_stream = stream; + m_width = width; + m_height = height; + + typedef NV_OF_STATUS( NVOFAPI * PFNNvOFAPICreateInstanceCuda )( uint32_t apiVer, NV_OF_CUDA_API_FUNCTION_LIST * cudaOf ); +#if defined( _WIN32 ) + m_hModule = LoadLibrary( TEXT( "nvofapi64.dll" ) ); + PFNNvOFAPICreateInstanceCuda NvOFAPICreateInstanceCuda = + (PFNNvOFAPICreateInstanceCuda)GetProcAddress( m_hModule, "NvOFAPICreateInstanceCuda" ); +#else + m_hModule = dlopen( "libnvidia-opticalflow.so.1", RTLD_LAZY ); + PFNNvOFAPICreateInstanceCuda NvOFAPICreateInstanceCuda = + (PFNNvOFAPICreateInstanceCuda)dlsym( m_hModule, "NvOFAPICreateInstanceCuda" ); +#endif + if( !NvOFAPICreateInstanceCuda ) + return OPTIX_ERROR_INTERNAL_ERROR; + + if( NvOFAPICreateInstanceCuda( NV_OF_API_VERSION, &m_ofl ) != NV_OF_SUCCESS ) + return OPTIX_ERROR_INTERNAL_ERROR; + + if( m_ofl.nvCreateOpticalFlowCuda( ctx, &m_ofh ) != NV_OF_SUCCESS ) + return OPTIX_ERROR_INTERNAL_ERROR; + + m_ofl.nvOFSetIOCudaStreams( m_ofh, stream, stream ); + + NV_OF_INIT_PARAMS ipa = {}; + ipa.width = m_width; + ipa.height = m_height; + ipa.enableExternalHints = NV_OF_FALSE; + ipa.enableOutputCost = NV_OF_FALSE; + ipa.hintGridSize = NV_OF_HINT_VECTOR_GRID_SIZE_UNDEFINED; + ipa.outGridSize = NV_OF_OUTPUT_VECTOR_GRID_SIZE_1; + ipa.mode = NV_OF_MODE_OPTICALFLOW; + ipa.perfLevel = NV_OF_PERF_LEVEL_SLOW; + ipa.enableRoi = NV_OF_FALSE; + + if( m_ofl.nvOFInit( m_ofh, &ipa ) != NV_OF_SUCCESS ) + return OPTIX_ERROR_INTERNAL_ERROR; + + NV_OF_BUFFER_DESCRIPTOR inputBufferDesc = {}; + inputBufferDesc.width = m_width; + inputBufferDesc.height = m_height; + inputBufferDesc.bufferFormat = NV_OF_BUFFER_FORMAT_ABGR8; + inputBufferDesc.bufferUsage = NV_OF_BUFFER_USAGE_INPUT; + + for( int i = 0; i < 2; i++ ) + { + if( m_ofl.nvOFCreateGPUBufferCuda( m_ofh, &inputBufferDesc, NV_OF_CUDA_BUFFER_TYPE_CUDEVICEPTR, &m_gpuBufferIn[i] ) != NV_OF_SUCCESS ) + return OPTIX_ERROR_INTERNAL_ERROR; + m_devPtr[i] = m_ofl.nvOFGPUBufferGetCUdeviceptr( m_gpuBufferIn[i] ); + + NV_OF_CUDA_BUFFER_STRIDE_INFO strideInfo; + if( m_ofl.nvOFGPUBufferGetStrideInfo( m_gpuBufferIn[i], &strideInfo ) != NV_OF_SUCCESS ) + return OPTIX_ERROR_INTERNAL_ERROR; + m_inStrideXInBytes = strideInfo.strideInfo[0].strideXInBytes; + } + + NV_OF_BUFFER_DESCRIPTOR outputBufferDesc = {}; + outputBufferDesc.width = m_width; + outputBufferDesc.height = m_height; + outputBufferDesc.bufferFormat = NV_OF_BUFFER_FORMAT_SHORT2; + outputBufferDesc.bufferUsage = NV_OF_BUFFER_USAGE_OUTPUT; + + if( m_ofl.nvOFCreateGPUBufferCuda( m_ofh, &outputBufferDesc, NV_OF_CUDA_BUFFER_TYPE_CUDEVICEPTR, &m_gpuBufferOut ) != NV_OF_SUCCESS ) + return OPTIX_ERROR_INTERNAL_ERROR; + + m_devPtrOut = m_ofl.nvOFGPUBufferGetCUdeviceptr( m_gpuBufferOut ); + NV_OF_CUDA_BUFFER_STRIDE_INFO strideInfo; + if( m_ofl.nvOFGPUBufferGetStrideInfo( m_gpuBufferOut, &strideInfo ) != NV_OF_SUCCESS ) + return OPTIX_ERROR_INTERNAL_ERROR; + m_outStrideXInBytes = strideInfo.strideInfo[0].strideXInBytes; + + return OPTIX_SUCCESS; + } + + /// Destroy resources created by optical flow class + OptixResult destroy() + { + if( m_gpuBufferIn[0] ) + m_ofl.nvOFDestroyGPUBufferCuda( m_gpuBufferIn[0] ); + if( m_gpuBufferIn[1] ) + m_ofl.nvOFDestroyGPUBufferCuda( m_gpuBufferIn[1] ); + if( m_gpuBufferOut ) + m_ofl.nvOFDestroyGPUBufferCuda( m_gpuBufferOut ); + if( m_ofh ) + m_ofl.nvOFDestroy( m_ofh ); + if( m_hModule ) + { +#if defined( _WIN32 ) + FreeLibrary( m_hModule ); +#else + dlclose( m_hModule ); +#endif + } + m_ofh = nullptr; + return OPTIX_SUCCESS; + } + + /// Calculate optical flow between two given images + /// \param[out] flow returned flow vectors for each pixel + /// \param[in] input array of two images + OptixResult computeFlow( OptixImage2D& flow, const OptixImage2D* input ) + { + // convert float/fp16 RGB input to 4x8 bit ABGR + if( OptixResult res = convertRGBA( (unsigned char*)m_devPtr[0], input[0], m_inStrideXInBytes, m_stream ) ) + return res; + if( OptixResult res = convertRGBA( (unsigned char*)m_devPtr[1], input[1], m_inStrideXInBytes, m_stream ) ) + return res; + + NV_OF_EXECUTE_INPUT_PARAMS execInParams = {}; + execInParams.inputFrame = m_gpuBufferIn[0]; + execInParams.referenceFrame = m_gpuBufferIn[1]; + execInParams.disableTemporalHints = NV_OF_FALSE; + + NV_OF_EXECUTE_OUTPUT_PARAMS execOutParams = {}; + execOutParams.outputBuffer = m_gpuBufferOut; + + if( m_ofl.nvOFExecute( m_ofh, &execInParams, &execOutParams ) != NV_OF_SUCCESS ) + return OPTIX_ERROR_INTERNAL_ERROR; + + if( flow.width != m_width || flow.height != m_height || getNumChannels( flow ) == 0 ) + return OPTIX_ERROR_INVALID_VALUE; + + // convert 2x16 bit fixpoint to 2xfp16/2xfp32 bit flow vectors + if( OptixResult res = convertFlow( flow, (const int16_t*)m_devPtrOut, m_outStrideXInBytes / sizeof( short ), m_stream ) ) + return res; + + return OPTIX_SUCCESS; + } + + std::string getLastError() + { + std::string message; + if( m_ofh == nullptr ) + return std::string( "Class not initialized" ); + char lastError[MIN_ERROR_STRING_SIZE]; + uint32_t eSize = MIN_ERROR_STRING_SIZE; + m_ofl.nvOFGetLastError( m_ofh, lastError, &eSize ); + return std::string( lastError ); + } + + private: + unsigned int m_width; + unsigned int m_height; + CUstream m_stream; + unsigned int m_inStrideXInBytes; + unsigned int m_outStrideXInBytes; + NV_OF_CUDA_API_FUNCTION_LIST m_ofl; + NvOFHandle m_ofh; + NvOFGPUBufferHandle m_gpuBufferIn[2]; + NvOFGPUBufferHandle m_gpuBufferOut; + CUdeviceptr m_devPtr[2]; + CUdeviceptr m_devPtrOut; +#if defined( _WIN32 ) + HMODULE m_hModule; +#else + void* m_hModule; +#endif +}; + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixPathTracer/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixPathTracer/CMakeLists.txt new file mode 100644 index 00000000..80e6d63f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixPathTracer/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixPathTracer target_name + optixPathTracer.cu + optixPathTracer.cpp + optixPathTracer.h + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixPathTracer/optixPathTracer.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixPathTracer/optixPathTracer.cpp new file mode 100644 index 00000000..eef6aeea --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixPathTracer/optixPathTracer.cpp @@ -0,0 +1,1099 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include // Needs to be included before gl_interop + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "optixPathTracer.h" + +#include +#include +#include +#include +#include +#include +#include + + + +bool resize_dirty = false; +bool minimized = false; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Mouse state +int32_t mouse_button = -1; + +int32_t samples_per_launch = 16; + +//------------------------------------------------------------------------------ +// +// Local types +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +template +struct Record +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef Record RayGenRecord; +typedef Record MissRecord; +typedef Record HitGroupRecord; + + +struct Vertex +{ + float x, y, z, pad; +}; + + +struct IndexedTriangle +{ + uint32_t v1, v2, v3, pad; +}; + + +struct Instance +{ + float transform[12]; +}; + + +struct PathTracerState +{ + OptixDeviceContext context = 0; + + OptixTraversableHandle gas_handle = 0; // Traversable handle for triangle AS + CUdeviceptr d_gas_output_buffer = 0; // Triangle AS memory + CUdeviceptr d_vertices = 0; + + OptixModule ptx_module = 0; + OptixPipelineCompileOptions pipeline_compile_options = {}; + OptixPipeline pipeline = 0; + + OptixProgramGroup raygen_prog_group = 0; + OptixProgramGroup radiance_miss_group = 0; + OptixProgramGroup radiance_hit_group = 0; + + CUstream stream = 0; + Params params; + Params* d_params; + + OptixShaderBindingTable sbt = {}; +}; + + +//------------------------------------------------------------------------------ +// +// Scene data +// +//------------------------------------------------------------------------------ + +const int32_t TRIANGLE_COUNT = 32; +const int32_t MAT_COUNT = 4; + +const static std::array g_vertices = +{ { + // Floor -- white lambert + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 0.0f, 0.0f }, + + // Ceiling -- white lambert + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + + // Back wall -- white lambert + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + + // Right wall -- green lambert + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 548.8f, 559.2f, 0.0f }, + { 0.0f, 0.0f, 559.2f, 0.0f }, + + // Left wall -- red lambert + { 556.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 0.0f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + + { 556.0f, 0.0f, 0.0f, 0.0f }, + { 556.0f, 548.8f, 559.2f, 0.0f }, + { 556.0f, 548.8f, 0.0f, 0.0f }, + + // Short block -- white lambert + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 242.0f, 165.0f, 274.0f, 0.0f }, + + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 242.0f, 165.0f, 274.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + + { 290.0f, 0.0f, 114.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + + { 290.0f, 0.0f, 114.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + { 240.0f, 0.0f, 272.0f, 0.0f }, + + { 130.0f, 0.0f, 65.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + + { 130.0f, 0.0f, 65.0f, 0.0f }, + { 290.0f, 165.0f, 114.0f, 0.0f }, + { 290.0f, 0.0f, 114.0f, 0.0f }, + + { 82.0f, 0.0f, 225.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + + { 82.0f, 0.0f, 225.0f, 0.0f }, + { 130.0f, 165.0f, 65.0f, 0.0f }, + { 130.0f, 0.0f, 65.0f, 0.0f }, + + { 240.0f, 0.0f, 272.0f, 0.0f }, + { 240.0f, 165.0f, 272.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + + { 240.0f, 0.0f, 272.0f, 0.0f }, + { 82.0f, 165.0f, 225.0f, 0.0f }, + { 82.0f, 0.0f, 225.0f, 0.0f }, + + // Tall block -- white lambert + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 314.0f, 330.0f, 455.0f, 0.0f }, + + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 314.0f, 330.0f, 455.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + + { 423.0f, 0.0f, 247.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + + { 423.0f, 0.0f, 247.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + { 472.0f, 0.0f, 406.0f, 0.0f }, + + { 472.0f, 0.0f, 406.0f, 0.0f }, + { 472.0f, 330.0f, 406.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + + { 472.0f, 0.0f, 406.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + { 314.0f, 0.0f, 456.0f, 0.0f }, + + { 314.0f, 0.0f, 456.0f, 0.0f }, + { 314.0f, 330.0f, 456.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + + { 314.0f, 0.0f, 456.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 265.0f, 0.0f, 296.0f, 0.0f }, + + { 265.0f, 0.0f, 296.0f, 0.0f }, + { 265.0f, 330.0f, 296.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + + { 265.0f, 0.0f, 296.0f, 0.0f }, + { 423.0f, 330.0f, 247.0f, 0.0f }, + { 423.0f, 0.0f, 247.0f, 0.0f }, + + // Ceiling light -- emmissive + { 343.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 332.0f, 0.0f }, + + { 343.0f, 548.6f, 227.0f, 0.0f }, + { 213.0f, 548.6f, 332.0f, 0.0f }, + { 343.0f, 548.6f, 332.0f, 0.0f } +} }; + +static std::array g_mat_indices = {{ + 0, 0, // Floor -- white lambert + 0, 0, // Ceiling -- white lambert + 0, 0, // Back wall -- white lambert + 1, 1, // Right wall -- green lambert + 2, 2, // Left wall -- red lambert + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Short block -- white lambert + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Tall block -- white lambert + 3, 3 // Ceiling light -- emmissive +}}; + + + +const std::array g_emission_colors = +{ { + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 15.0f, 15.0f, 5.0f } + +} }; + + +const std::array g_diffuse_colors = +{ { + { 0.80f, 0.80f, 0.80f }, + { 0.05f, 0.80f, 0.05f }, + { 0.80f, 0.05f, 0.05f }, + { 0.50f, 0.00f, 0.00f } +} }; + + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking( static_cast( xpos ), static_cast( ypos ) ); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + Params* params = static_cast( glfwGetWindowUserPointer( window ) ); + + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params->width, params->height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params->width, params->height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + Params* params = static_cast( glfwGetWindowUserPointer( window ) ); + params->width = res_x; + params->height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + } + else if( key == GLFW_KEY_G ) + { + // toggle UI draw + } +} + + +static void scrollCallback( GLFWwindow* window, double xscroll, double yscroll ) +{ + if( trackball.wheelEvent( (int)yscroll ) ) + camera_changed = true; +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --launch-samples | -s Number of samples per pixel per launch (default 16)\n"; + std::cerr << " --no-gl-interop Disable GL interop for display\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 768x768\n"; + std::cerr << " --help | -h Print this usage message\n"; + exit( 0 ); +} + + +void initLaunchParams( PathTracerState& state ) +{ + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &state.params.accum_buffer ), + state.params.width * state.params.height * sizeof( float4 ) + ) ); + state.params.frame_buffer = nullptr; // Will be set when output buffer is mapped + + state.params.samples_per_launch = samples_per_launch; + state.params.subframe_index = 0u; + + state.params.light.emission = make_float3( 15.0f, 15.0f, 5.0f ); + state.params.light.corner = make_float3( 343.0f, 548.5f, 227.0f ); + state.params.light.v1 = make_float3( 0.0f, 0.0f, 105.0f ); + state.params.light.v2 = make_float3( -130.0f, 0.0f, 0.0f ); + state.params.light.normal = normalize( cross( state.params.light.v1, state.params.light.v2 ) ); + state.params.handle = state.gas_handle; + + CUDA_CHECK( cudaStreamCreate( &state.stream ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_params ), sizeof( Params ) ) ); + +} + + +void handleCameraUpdate( Params& params ) +{ + if( !camera_changed ) + return; + camera_changed = false; + + camera.setAspectRatio( static_cast( params.width ) / static_cast( params.height ) ); + params.eye = camera.eye(); + camera.UVWFrame( params.U, params.V, params.W ); +} + + +void handleResize( sutil::CUDAOutputBuffer& output_buffer, Params& params ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + output_buffer.resize( params.width, params.height ); + + // Realloc accumulation buffer + CUDA_CHECK( cudaFree( reinterpret_cast( params.accum_buffer ) ) ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( ¶ms.accum_buffer ), + params.width * params.height * sizeof( float4 ) + ) ); +} + + +void updateState( sutil::CUDAOutputBuffer& output_buffer, Params& params ) +{ + // Update params on device + if( camera_changed || resize_dirty ) + params.subframe_index = 0; + + handleCameraUpdate( params ); + handleResize( output_buffer, params ); +} + + +void launchSubframe( sutil::CUDAOutputBuffer& output_buffer, PathTracerState& state ) +{ + // Launch + uchar4* result_buffer_data = output_buffer.map(); + state.params.frame_buffer = result_buffer_data; + CUDA_CHECK( cudaMemcpyAsync( + reinterpret_cast( state.d_params ), + &state.params, sizeof( Params ), + cudaMemcpyHostToDevice, state.stream + ) ); + + OPTIX_CHECK( optixLaunch( + state.pipeline, + state.stream, + reinterpret_cast( state.d_params ), + sizeof( Params ), + &state.sbt, + state.params.width, // launch width + state.params.height, // launch height + 1 // launch depth + ) ); + output_buffer.unmap(); + CUDA_SYNC_CHECK(); +} + + +void displaySubframe( sutil::CUDAOutputBuffer& output_buffer, sutil::GLDisplay& gl_display, GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( + output_buffer.width(), + output_buffer.height(), + framebuf_res_x, + framebuf_res_y, + output_buffer.getPBO() + ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n"; +} + + +void initCameraState() +{ + camera.setEye( make_float3( 278.0f, 273.0f, -900.0f ) ); + camera.setLookat( make_float3( 278.0f, 273.0f, 330.0f ) ); + camera.setUp( make_float3( 0.0f, 1.0f, 0.0f ) ); + camera.setFovY( 35.0f ); + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( + make_float3( 1.0f, 0.0f, 0.0f ), + make_float3( 0.0f, 0.0f, 1.0f ), + make_float3( 0.0f, 1.0f, 0.0f ) + ); + trackball.setGimbalLock( true ); +} + + +void createContext( PathTracerState& state ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cu_ctx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; +#ifdef DEBUG + // This may incur significant performance cost and should only be done during development. + options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; +#endif + OPTIX_CHECK( optixDeviceContextCreate( cu_ctx, &options, &context ) ); + + state.context = context; +} + + +void buildMeshAccel( PathTracerState& state ) +{ + // + // copy mesh data to device + // + const size_t vertices_size_in_bytes = g_vertices.size() * sizeof( Vertex ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_vertices ), vertices_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( state.d_vertices ), + g_vertices.data(), vertices_size_in_bytes, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr d_mat_indices = 0; + const size_t mat_indices_size_in_bytes = g_mat_indices.size() * sizeof( uint32_t ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_mat_indices ), mat_indices_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_mat_indices ), + g_mat_indices.data(), + mat_indices_size_in_bytes, + cudaMemcpyHostToDevice + ) ); + + // + // Build triangle GAS + // + uint32_t triangle_input_flags[MAT_COUNT] = // One per SBT record for this build input + { + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT + }; + + OptixBuildInput triangle_input = {}; + triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangle_input.triangleArray.vertexStrideInBytes = sizeof( Vertex ); + triangle_input.triangleArray.numVertices = static_cast( g_vertices.size() ); + triangle_input.triangleArray.vertexBuffers = &state.d_vertices; + triangle_input.triangleArray.flags = triangle_input_flags; + triangle_input.triangleArray.numSbtRecords = MAT_COUNT; + triangle_input.triangleArray.sbtIndexOffsetBuffer = d_mat_indices; + triangle_input.triangleArray.sbtIndexOffsetSizeInBytes = sizeof( uint32_t ); + triangle_input.triangleArray.sbtIndexOffsetStrideInBytes = sizeof( uint32_t ); + + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( + state.context, + &accel_options, + &triangle_input, + 1, // num_build_inputs + &gas_buffer_sizes + ) ); + + CUdeviceptr d_temp_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 + ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( (char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( + state.context, + 0, // CUDA stream + &accel_options, + &triangle_input, + 1, // num build inputs + d_temp_buffer, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &state.gas_handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_mat_indices ) ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, (void*)emitProperty.result, sizeof(size_t), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, 0, state.gas_handle, state.d_gas_output_buffer, compacted_gas_size, &state.gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + state.d_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } +} + +void createModule( PathTracerState& state ) +{ + OptixPayloadType payloadType = {}; + // radiance prd + payloadType.numPayloadValues = sizeof( radiancePayloadSemantics ) / sizeof( radiancePayloadSemantics[0] ); + payloadType.payloadSemantics = radiancePayloadSemantics; + + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + module_compile_options.numPayloadTypes = 1; + module_compile_options.payloadTypes = &payloadType; + + state.pipeline_compile_options.usesMotionBlur = false; + state.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + state.pipeline_compile_options.numPayloadValues = 0; + state.pipeline_compile_options.numAttributeValues = 2; + state.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + state.pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixPathTracer.cu", inputSize ); + + OPTIX_CHECK_LOG( optixModuleCreate( + state.context, + &module_compile_options, + &state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &state.ptx_module + ) ); +} + + +void createProgramGroups( PathTracerState& state ) +{ + OptixProgramGroupOptions program_group_options = {}; + + { + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = state.ptx_module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.raygen_prog_group + ) ); + } + + { + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.ptx_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__radiance"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.radiance_miss_group + ) ); + } + + { + OptixProgramGroupDesc hit_prog_group_desc = {}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = state.ptx_module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__radiance"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.radiance_hit_group + ) ); + } +} + + +void createPipeline( PathTracerState& state ) +{ + OptixProgramGroup program_groups[] = + { + state.raygen_prog_group, + state.radiance_miss_group, + state.radiance_hit_group, + }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = 2; + + OPTIX_CHECK_LOG( optixPipelineCreate( + state.context, + &state.pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &state.pipeline + ) ); + + // We need to specify the max traversal depth. Calculate the stack sizes, so we can specify all + // parameters to optixPipelineSetStackSize. + OptixStackSizes stack_sizes = {}; + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.raygen_prog_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.radiance_miss_group, &stack_sizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.radiance_hit_group, &stack_sizes, state.pipeline ) ); + + uint32_t max_trace_depth = 2; + uint32_t max_cc_depth = 0; + uint32_t max_dc_depth = 0; + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( + &stack_sizes, + max_trace_depth, + max_cc_depth, + max_dc_depth, + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, + &continuation_stack_size + ) ); + + const uint32_t max_traversal_depth = 1; + OPTIX_CHECK( optixPipelineSetStackSize( + state.pipeline, + direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, + continuation_stack_size, + max_traversal_depth + ) ); +} + + +void createSBT( PathTracerState& state ) +{ + CUdeviceptr d_raygen_record; + const size_t raygen_record_size = sizeof( RayGenRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_raygen_record ), raygen_record_size ) ); + + RayGenRecord rg_sbt = {}; + OPTIX_CHECK( optixSbtRecordPackHeader( state.raygen_prog_group, &rg_sbt ) ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_raygen_record ), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + + + CUdeviceptr d_miss_records; + const size_t miss_record_size = sizeof( MissRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_miss_records ), miss_record_size * RAY_TYPE_COUNT ) ); + + MissRecord ms_sbt[1]; + OPTIX_CHECK( optixSbtRecordPackHeader( state.radiance_miss_group, &ms_sbt[0] ) ); + ms_sbt[0].data.bg_color = make_float4( 0.0f ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_miss_records ), + ms_sbt, + miss_record_size*RAY_TYPE_COUNT, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr d_hitgroup_records; + const size_t hitgroup_record_size = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_hitgroup_records ), + hitgroup_record_size * RAY_TYPE_COUNT * MAT_COUNT + ) ); + + HitGroupRecord hitgroup_records[RAY_TYPE_COUNT * MAT_COUNT]; + for( int i = 0; i < MAT_COUNT; ++i ) + { + { + const int sbt_idx = i * RAY_TYPE_COUNT + 0; // SBT for radiance ray-type for ith material + + OPTIX_CHECK( optixSbtRecordPackHeader( state.radiance_hit_group, &hitgroup_records[sbt_idx] ) ); + hitgroup_records[sbt_idx].data.emission_color = g_emission_colors[i]; + hitgroup_records[sbt_idx].data.diffuse_color = g_diffuse_colors[i]; + hitgroup_records[sbt_idx].data.vertices = reinterpret_cast( state.d_vertices ); + } + + // Note that we do not need to use any program groups for occlusion + // rays as they are traced as 'probe rays' with no shading. + } + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_hitgroup_records ), + hitgroup_records, + hitgroup_record_size*RAY_TYPE_COUNT*MAT_COUNT, + cudaMemcpyHostToDevice + ) ); + + state.sbt.raygenRecord = d_raygen_record; + state.sbt.missRecordBase = d_miss_records; + state.sbt.missRecordStrideInBytes = static_cast( miss_record_size ); + state.sbt.missRecordCount = RAY_TYPE_COUNT; + state.sbt.hitgroupRecordBase = d_hitgroup_records; + state.sbt.hitgroupRecordStrideInBytes = static_cast( hitgroup_record_size ); + state.sbt.hitgroupRecordCount = RAY_TYPE_COUNT * MAT_COUNT; +} + + +void cleanupState( PathTracerState& state ) +{ + OPTIX_CHECK( optixPipelineDestroy( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_miss_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.radiance_hit_group ) ); + OPTIX_CHECK( optixModuleDestroy( state.ptx_module ) ); + OPTIX_CHECK( optixDeviceContextDestroy( state.context ) ); + + + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_vertices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.accum_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_params ) ) ); +} + + +//------------------------------------------------------------------------------ +// +// Main +// +//------------------------------------------------------------------------------ + +int main( int argc, char* argv[] ) +{ + PathTracerState state; + state.params.width = 768; + state.params.height = 768; + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::GL_INTEROP; + + // + // Parse command line options + // + std::string outfile; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--no-gl-interop" ) + { + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outfile = argv[++i]; + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + int w, h; + sutil::parseDimensions( dims_arg.c_str(), w, h ); + state.params.width = w; + state.params.height = h; + } + else if( arg == "--launch-samples" || arg == "-s" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + samples_per_launch = atoi( argv[++i] ); + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + initCameraState(); + + // + // Set up OptiX state + // + createContext( state ); + buildMeshAccel( state ); + createModule( state ); + createProgramGroups( state ); + createPipeline( state ); + createSBT( state ); + initLaunchParams( state ); + + + if( outfile.empty() ) + { + GLFWwindow* window = sutil::initUI( "optixPathTracer", state.params.width, state.params.height ); + glfwSetMouseButtonCallback( window, mouseButtonCallback ); + glfwSetCursorPosCallback( window, cursorPosCallback ); + glfwSetWindowSizeCallback( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback( window, keyCallback ); + glfwSetScrollCallback( window, scrollCallback ); + glfwSetWindowUserPointer( window, &state.params ); + + // + // Render loop + // + { + sutil::CUDAOutputBuffer output_buffer( + output_buffer_type, + state.params.width, + state.params.height + ); + + output_buffer.setStream( state.stream ); + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + updateState( output_buffer, state.params ); + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + launchSubframe( output_buffer, state ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1 - t0; + + sutil::displayStats( state_update_time, render_time, display_time ); + + glfwSwapBuffers( window ); + + ++state.params.subframe_index; + } while( !glfwWindowShouldClose( window ) ); + CUDA_SYNC_CHECK(); + } + + sutil::cleanupUI( window ); + } + else + { + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + sutil::initGLFW(); // For GL context + sutil::initGL(); + } + + { + // this scope is for output_buffer, to ensure the destructor is called bfore glfwTerminate() + + sutil::CUDAOutputBuffer output_buffer( + output_buffer_type, + state.params.width, + state.params.height + ); + + handleCameraUpdate( state.params ); + handleResize( output_buffer, state.params ); + launchSubframe( output_buffer, state ); + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + glfwTerminate(); + } + } + + cleanupState( state ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixPathTracer/optixPathTracer.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixPathTracer/optixPathTracer.cu new file mode 100644 index 00000000..b6ee973c --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixPathTracer/optixPathTracer.cu @@ -0,0 +1,416 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include "optixPathTracer.h" +#include "random.h" + +#include +#include + +extern "C" { +__constant__ Params params; +} + +//------------------------------------------------------------------------------ +// +// Orthonormal basis helper +// +//------------------------------------------------------------------------------ + + +struct Onb +{ + __forceinline__ __device__ Onb(const float3& normal) + { + m_normal = normal; + + if( fabs(m_normal.x) > fabs(m_normal.z) ) + { + m_binormal.x = -m_normal.y; + m_binormal.y = m_normal.x; + m_binormal.z = 0; + } + else + { + m_binormal.x = 0; + m_binormal.y = -m_normal.z; + m_binormal.z = m_normal.y; + } + + m_binormal = normalize(m_binormal); + m_tangent = cross( m_binormal, m_normal ); + } + + __forceinline__ __device__ void inverse_transform(float3& p) const + { + p = p.x*m_tangent + p.y*m_binormal + p.z*m_normal; + } + + float3 m_tangent; + float3 m_binormal; + float3 m_normal; +}; + + +//------------------------------------------------------------------------------ +// +// Utility functions +// +//------------------------------------------------------------------------------ + + +static __forceinline__ __device__ RadiancePRD loadClosesthitRadiancePRD() +{ + RadiancePRD prd = {}; + + prd.attenuation.x = __uint_as_float( optixGetPayload_0() ); + prd.attenuation.y = __uint_as_float( optixGetPayload_1() ); + prd.attenuation.z = __uint_as_float( optixGetPayload_2() ); + prd.seed = optixGetPayload_3(); + prd.depth = optixGetPayload_4(); + return prd; +} + +static __forceinline__ __device__ RadiancePRD loadMissRadiancePRD() +{ + RadiancePRD prd = {}; + return prd; +} + +static __forceinline__ __device__ void storeClosesthitRadiancePRD( RadiancePRD prd ) +{ + optixSetPayload_0( __float_as_uint( prd.attenuation.x ) ); + optixSetPayload_1( __float_as_uint( prd.attenuation.y ) ); + optixSetPayload_2( __float_as_uint( prd.attenuation.z ) ); + + optixSetPayload_3( prd.seed ); + optixSetPayload_4( prd.depth ); + + optixSetPayload_5( __float_as_uint( prd.emitted.x ) ); + optixSetPayload_6( __float_as_uint( prd.emitted.y ) ); + optixSetPayload_7( __float_as_uint( prd.emitted.z ) ); + + optixSetPayload_8( __float_as_uint( prd.radiance.x ) ); + optixSetPayload_9( __float_as_uint( prd.radiance.y ) ); + optixSetPayload_10( __float_as_uint( prd.radiance.z ) ); + + optixSetPayload_11( __float_as_uint( prd.origin.x ) ); + optixSetPayload_12( __float_as_uint( prd.origin.y ) ); + optixSetPayload_13( __float_as_uint( prd.origin.z ) ); + + optixSetPayload_14( __float_as_uint( prd.direction.x ) ); + optixSetPayload_15( __float_as_uint( prd.direction.y ) ); + optixSetPayload_16( __float_as_uint( prd.direction.z ) ); + + optixSetPayload_17( prd.done ); +} + + +static __forceinline__ __device__ void storeMissRadiancePRD( RadiancePRD prd ) +{ + optixSetPayload_5( __float_as_uint( prd.emitted.x ) ); + optixSetPayload_6( __float_as_uint( prd.emitted.y ) ); + optixSetPayload_7( __float_as_uint( prd.emitted.z ) ); + + optixSetPayload_8( __float_as_uint( prd.radiance.x ) ); + optixSetPayload_9( __float_as_uint( prd.radiance.y ) ); + optixSetPayload_10( __float_as_uint( prd.radiance.z ) ); + + optixSetPayload_17( prd.done ); +} + + +static __forceinline__ __device__ void cosine_sample_hemisphere(const float u1, const float u2, float3& p) +{ + // Uniformly sample disk. + const float r = sqrtf( u1 ); + const float phi = 2.0f*M_PIf * u2; + p.x = r * cosf( phi ); + p.y = r * sinf( phi ); + + // Project up to hemisphere. + p.z = sqrtf( fmaxf( 0.0f, 1.0f - p.x*p.x - p.y*p.y ) ); +} + + +static __forceinline__ __device__ void traceRadiance( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax, + RadiancePRD& prd + ) +{ + unsigned int u0, u1, u2, u3, u4, u5, u6, u7, u8, u9, u10, u11, u12, u13, u14, u15, u16, u17; + + u0 = __float_as_uint( prd.attenuation.x ); + u1 = __float_as_uint( prd.attenuation.y ); + u2 = __float_as_uint( prd.attenuation.z ); + u3 = prd.seed; + u4 = prd.depth; + + // Note: + // This demonstrates the usage of the OptiX shader execution reordering + // (SER) API. In the case of this computationally simple shading code, + // there is no real performance benefit. However, with more complex shaders + // the potential performance gains offered by reordering are significant. + optixTraverse( + PAYLOAD_TYPE_RADIANCE, + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_NONE, + 0, // SBT offset + RAY_TYPE_COUNT, // SBT stride + 0, // missSBTIndex + u0, u1, u2, u3, u4, u5, u6, u7, u8, u9, u10, u11, u12, u13, u14, u15, u16, u17 ); + optixReorder( + // Application specific coherence hints could be passed in here + ); + + optixInvoke( PAYLOAD_TYPE_RADIANCE, + u0, u1, u2, u3, u4, u5, u6, u7, u8, u9, u10, u11, u12, u13, u14, u15, u16, u17 ); + + prd.attenuation = make_float3( __uint_as_float( u0 ), __uint_as_float( u1 ), __uint_as_float( u2 ) ); + prd.seed = u3; + prd.depth = u4; + + prd.emitted = make_float3( __uint_as_float( u5 ), __uint_as_float( u6 ), __uint_as_float( u7 ) ); + prd.radiance = make_float3( __uint_as_float( u8 ), __uint_as_float( u9 ), __uint_as_float( u10 ) ); + prd.origin = make_float3( __uint_as_float( u11 ), __uint_as_float( u12 ), __uint_as_float( u13 ) ); + prd.direction = make_float3( __uint_as_float( u14 ), __uint_as_float( u15 ), __uint_as_float( u16 ) ); + prd.done = u17; +} + + +// Returns true if ray is occluded, else false +static __forceinline__ __device__ bool traceOcclusion( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax + ) +{ + // We are only casting probe rays so no shader invocation is needed + optixTraverse( + handle, + ray_origin, + ray_direction, + tmin, + tmax, 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT | OPTIX_RAY_FLAG_DISABLE_ANYHIT, + 0, // SBT offset + RAY_TYPE_COUNT, // SBT stride + 0 // missSBTIndex + ); + return optixHitObjectIsHit(); +} + + +//------------------------------------------------------------------------------ +// +// Programs +// +//------------------------------------------------------------------------------ + +extern "C" __global__ void __raygen__rg() +{ + const int w = params.width; + const int h = params.height; + const float3 eye = params.eye; + const float3 U = params.U; + const float3 V = params.V; + const float3 W = params.W; + const uint3 idx = optixGetLaunchIndex(); + const int subframe_index = params.subframe_index; + + unsigned int seed = tea<4>( idx.y*w + idx.x, subframe_index ); + + float3 result = make_float3( 0.0f ); + int i = params.samples_per_launch; + do + { + // The center of each pixel is at fraction (0.5,0.5) + const float2 subpixel_jitter = make_float2( rnd( seed ), rnd( seed ) ); + + const float2 d = 2.0f * make_float2( + ( static_cast( idx.x ) + subpixel_jitter.x ) / static_cast( w ), + ( static_cast( idx.y ) + subpixel_jitter.y ) / static_cast( h ) + ) - 1.0f; + float3 ray_direction = normalize(d.x*U + d.y*V + W); + float3 ray_origin = eye; + + RadiancePRD prd; + prd.attenuation = make_float3(1.f); + prd.seed = seed; + prd.depth = 0; + + for( ;; ) + { + traceRadiance( + params.handle, + ray_origin, + ray_direction, + 0.01f, // tmin // TODO: smarter offset + 1e16f, // tmax + prd ); + + result += prd.emitted; + result += prd.radiance * prd.attenuation; + + const float p = dot( prd.attenuation, make_float3( 0.30f, 0.59f, 0.11f ) ); + const bool done = prd.done || rnd( prd.seed ) > p; + if( done ) + break; + prd.attenuation /= p; + + ray_origin = prd.origin; + ray_direction = prd.direction; + + ++prd.depth; + } + } + while( --i ); + + const uint3 launch_index = optixGetLaunchIndex(); + const unsigned int image_index = launch_index.y * params.width + launch_index.x; + float3 accum_color = result / static_cast( params.samples_per_launch ); + + if( subframe_index > 0 ) + { + const float a = 1.0f / static_cast( subframe_index+1 ); + const float3 accum_color_prev = make_float3( params.accum_buffer[ image_index ]); + accum_color = lerp( accum_color_prev, accum_color, a ); + } + params.accum_buffer[ image_index ] = make_float4( accum_color, 1.0f); + params.frame_buffer[ image_index ] = make_color ( accum_color ); +} + + +extern "C" __global__ void __miss__radiance() +{ + optixSetPayloadTypes( PAYLOAD_TYPE_RADIANCE ); + + MissData* rt_data = reinterpret_cast( optixGetSbtDataPointer() ); + RadiancePRD prd = loadMissRadiancePRD(); + + prd.radiance = make_float3( rt_data->bg_color ); + prd.emitted = make_float3( 0.f ); + prd.done = true; + + storeMissRadiancePRD( prd ); +} + + +extern "C" __global__ void __closesthit__radiance() +{ + optixSetPayloadTypes( PAYLOAD_TYPE_RADIANCE ); + + HitGroupData* rt_data = (HitGroupData*)optixGetSbtDataPointer(); + + const int prim_idx = optixGetPrimitiveIndex(); + const float3 ray_dir = optixGetWorldRayDirection(); + const int vert_idx_offset = prim_idx*3; + + const float3 v0 = make_float3( rt_data->vertices[ vert_idx_offset+0 ] ); + const float3 v1 = make_float3( rt_data->vertices[ vert_idx_offset+1 ] ); + const float3 v2 = make_float3( rt_data->vertices[ vert_idx_offset+2 ] ); + const float3 N_0 = normalize( cross( v1-v0, v2-v0 ) ); + + const float3 N = faceforward( N_0, -ray_dir, N_0 ); + const float3 P = optixGetWorldRayOrigin() + optixGetRayTmax()*ray_dir; + + RadiancePRD prd = loadClosesthitRadiancePRD(); + + if( prd.depth == 0 ) + prd.emitted = rt_data->emission_color; + else + prd.emitted = make_float3( 0.0f ); + + unsigned int seed = prd.seed; + { + const float z1 = rnd(seed); + const float z2 = rnd(seed); + + float3 w_in; + cosine_sample_hemisphere( z1, z2, w_in ); + Onb onb( N ); + onb.inverse_transform( w_in ); + prd.direction = w_in; + prd.origin = P; + + prd.attenuation *= rt_data->diffuse_color; + } + + const float z1 = rnd(seed); + const float z2 = rnd(seed); + prd.seed = seed; + + ParallelogramLight light = params.light; + const float3 light_pos = light.corner + light.v1 * z1 + light.v2 * z2; + + // Calculate properties of light sample (for area based pdf) + const float Ldist = length(light_pos - P ); + const float3 L = normalize(light_pos - P ); + const float nDl = dot( N, L ); + const float LnDl = -dot( light.normal, L ); + + float weight = 0.0f; + if( nDl > 0.0f && LnDl > 0.0f ) + { + const bool occluded = + traceOcclusion( + params.handle, + P, + L, + 0.01f, // tmin + Ldist - 0.01f); // tmax + + if( !occluded ) + { + const float A = length(cross(light.v1, light.v2)); + weight = nDl * LnDl * A / (M_PIf * Ldist * Ldist); + } + } + + prd.radiance = light.emission * weight; + prd.done = false; + + storeClosesthitRadiancePRD( prd ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixPathTracer/optixPathTracer.h b/Extern/3rdParty/OptiX/Linux/SDK/optixPathTracer/optixPathTracer.h new file mode 100644 index 00000000..32ec3a20 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixPathTracer/optixPathTracer.h @@ -0,0 +1,129 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +constexpr unsigned int RAY_TYPE_COUNT = 1; + +constexpr OptixPayloadTypeID PAYLOAD_TYPE_RADIANCE = OPTIX_PAYLOAD_TYPE_ID_0; + +struct RadiancePRD +{ + // these are produced by the caller, passed into trace, consumed/modified by CH and MS and consumed again by the caller after trace returned. + float3 attenuation; + unsigned int seed; + int depth; + + // these are produced by CH and MS, and consumed by the caller after trace returned. + float3 emitted; + float3 radiance; + float3 origin; + float3 direction; + int done; +}; + + +const unsigned int radiancePayloadSemantics[18] = +{ + // RadiancePRD::attenuation + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ_WRITE | OPTIX_PAYLOAD_SEMANTICS_CH_READ_WRITE, + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ_WRITE | OPTIX_PAYLOAD_SEMANTICS_CH_READ_WRITE, + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ_WRITE | OPTIX_PAYLOAD_SEMANTICS_CH_READ_WRITE, + // RadiancePRD::seed + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ_WRITE | OPTIX_PAYLOAD_SEMANTICS_CH_READ_WRITE, + // RadiancePRD::depth + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ_WRITE | OPTIX_PAYLOAD_SEMANTICS_CH_READ_WRITE, + // RadiancePRD::emitted + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ | OPTIX_PAYLOAD_SEMANTICS_CH_WRITE | OPTIX_PAYLOAD_SEMANTICS_MS_WRITE, + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ | OPTIX_PAYLOAD_SEMANTICS_CH_WRITE | OPTIX_PAYLOAD_SEMANTICS_MS_WRITE, + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ | OPTIX_PAYLOAD_SEMANTICS_CH_WRITE | OPTIX_PAYLOAD_SEMANTICS_MS_WRITE, + // RadiancePRD::radiance + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ | OPTIX_PAYLOAD_SEMANTICS_CH_WRITE | OPTIX_PAYLOAD_SEMANTICS_MS_WRITE, + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ | OPTIX_PAYLOAD_SEMANTICS_CH_WRITE | OPTIX_PAYLOAD_SEMANTICS_MS_WRITE, + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ | OPTIX_PAYLOAD_SEMANTICS_CH_WRITE | OPTIX_PAYLOAD_SEMANTICS_MS_WRITE, + // RadiancePRD::origin + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ | OPTIX_PAYLOAD_SEMANTICS_CH_WRITE, + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ | OPTIX_PAYLOAD_SEMANTICS_CH_WRITE, + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ | OPTIX_PAYLOAD_SEMANTICS_CH_WRITE, + // RadiancePRD::direction + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ | OPTIX_PAYLOAD_SEMANTICS_CH_WRITE, + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ | OPTIX_PAYLOAD_SEMANTICS_CH_WRITE, + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ | OPTIX_PAYLOAD_SEMANTICS_CH_WRITE, + // RadiancePRD::done + OPTIX_PAYLOAD_SEMANTICS_TRACE_CALLER_READ | OPTIX_PAYLOAD_SEMANTICS_CH_WRITE | OPTIX_PAYLOAD_SEMANTICS_MS_WRITE +}; + + +struct ParallelogramLight +{ + float3 corner; + float3 v1, v2; + float3 normal; + float3 emission; +}; + + +struct Params +{ + unsigned int subframe_index; + float4* accum_buffer; + uchar4* frame_buffer; + unsigned int width; + unsigned int height; + unsigned int samples_per_launch; + + float3 eye; + float3 U; + float3 V; + float3 W; + + ParallelogramLight light; // TODO: make light list + OptixTraversableHandle handle; +}; + + +struct RayGenData +{ +}; + + +struct MissData +{ + float4 bg_color; +}; + + +struct HitGroupData +{ + float3 emission_color; + float3 diffuse_color; + float4* vertices; +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/CMakeLists.txt new file mode 100644 index 00000000..1c65f3d0 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/CMakeLists.txt @@ -0,0 +1,44 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/optixRaycastingKernels.cu + PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ + ) + +OPTIX_add_sample_executable( optixRaycasting target_name + optixRaycasting.cu + optixRaycasting.cpp + optixRaycasting.h + optixRaycastingKernels.cu + optixRaycastingKernels.h + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycasting.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycasting.cpp new file mode 100644 index 00000000..d297488f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycasting.cpp @@ -0,0 +1,452 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include + +#include +#include +#include +#include + +#include + +#include "cuda/whitted.h" +#include +#include +#include +#include +#include + +#include "optixRaycasting.h" +#include "optixRaycastingKernels.h" + +#include + + +struct RaycastingState +{ + int width = 0; + int height = 0; + + OptixDeviceContext context = 0; + sutil::Scene scene = {}; + + OptixPipelineCompileOptions pipeline_compile_options = {}; + OptixModule ptx_module = 0; + OptixPipeline pipeline_1 = 0; + OptixPipeline pipeline_2 = 0; + + OptixProgramGroup raygen_prog_group = 0; + OptixProgramGroup miss_prog_group = 0; + OptixProgramGroup hit_prog_group = 0; + + Params params = {}; + Params params_translated = {}; + OptixShaderBindingTable sbt = {}; + + sutil::Texture mask = {}; +}; + + +typedef sutil::Record HitGroupRecord; + + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n" + << "Options:\n" + << " -h | --help Print this usage message\n" + << " -f | --file Prefix of output file\n" + << " -m | --model Model to be rendered\n" + << " -w | --width Output image width\n" + << std::endl; + + exit( 1 ); +} + + +void createModule( RaycastingState& state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#else + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_DEFAULT; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_MINIMAL; +#endif + + state.pipeline_compile_options.usesMotionBlur = false; + state.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING; + state.pipeline_compile_options.numPayloadValues = 4; + state.pipeline_compile_options.numAttributeValues = 2; + state.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + state.pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixRaycasting.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( state.context, &module_compile_options, &state.pipeline_compile_options, input, + inputSize, LOG, &LOG_SIZE, &state.ptx_module ) ); +} + +void createProgramGroups( RaycastingState& state ) +{ + OptixProgramGroupOptions program_group_options = {}; + + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = state.ptx_module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__from_buffer"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.raygen_prog_group ) ); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.ptx_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__buffer_miss"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.miss_prog_group ) ); + + + OptixProgramGroupDesc hit_prog_group_desc = {}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleAH = state.ptx_module; + hit_prog_group_desc.hitgroup.entryFunctionNameAH = "__anyhit__texture_mask"; + hit_prog_group_desc.hitgroup.moduleCH = state.ptx_module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__buffer_hit"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &hit_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &state.hit_prog_group ) ); +} + + +void createPipelines( RaycastingState& state ) +{ + const uint32_t max_trace_depth = 1; + OptixProgramGroup program_groups[3] = {state.raygen_prog_group, state.miss_prog_group, state.hit_prog_group}; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + + OPTIX_CHECK_LOG( optixPipelineCreate( state.context, &state.pipeline_compile_options, &pipeline_link_options, + program_groups, sizeof( program_groups ) / sizeof( program_groups[0] ), LOG, + &LOG_SIZE, &state.pipeline_1 ) ); + OPTIX_CHECK_LOG( optixPipelineCreate( state.context, &state.pipeline_compile_options, &pipeline_link_options, + program_groups, sizeof( program_groups ) / sizeof( program_groups[0] ), LOG, + &LOG_SIZE, &state.pipeline_2 ) ); + + OptixStackSizes stack_sizes_1 = {}; + OptixStackSizes stack_sizes_2 = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes_1, state.pipeline_1 ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes_2, state.pipeline_2 ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes_1, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( state.pipeline_1, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 2 // maxTraversableDepth + ) ); + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes_2, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( state.pipeline_2, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 2 // maxTraversableDepth + ) ); +} + + +void createSBT( RaycastingState& state ) +{ + // raygen + CUdeviceptr d_raygen_record = 0; + const size_t raygen_record_size = sizeof( sutil::EmptyRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_raygen_record ), raygen_record_size ) ); + + sutil::EmptyRecord rg_record; + OPTIX_CHECK( optixSbtRecordPackHeader( state.raygen_prog_group, &rg_record ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_raygen_record ), &rg_record, raygen_record_size, cudaMemcpyHostToDevice ) ); + + // miss + CUdeviceptr d_miss_record = 0; + const size_t miss_record_size = sizeof( sutil::EmptyRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_miss_record ), miss_record_size ) ); + + sutil::EmptyRecord ms_record; + OPTIX_CHECK( optixSbtRecordPackHeader( state.miss_prog_group, &ms_record ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_miss_record ), &ms_record, miss_record_size, cudaMemcpyHostToDevice ) ); + + // hit group + std::vector hitgroup_records; + for( const auto& mesh : state.scene.meshes() ) + { + for( size_t i = 0; i < mesh->material_idx.size(); ++i ) + { + HitGroupRecord rec = {}; + OPTIX_CHECK( optixSbtRecordPackHeader( state.hit_prog_group, &rec ) ); + GeometryData::TriangleMesh triangle_mesh = {}; + triangle_mesh.positions = mesh->positions[i]; + triangle_mesh.normals = mesh->normals[i]; + for( size_t j = 0; j < GeometryData::num_texcoords; ++j ) + triangle_mesh.texcoords[j] = mesh->texcoords[j][i]; + triangle_mesh.indices = mesh->indices[i]; + rec.data.geometry_data.setTriangleMesh( triangle_mesh ); + rec.data.material_data = state.scene.materials()[mesh->material_idx[i]]; + hitgroup_records.push_back( rec ); + } + } + + CUdeviceptr d_hitgroup_record = 0; + const size_t hitgroup_record_size = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_hitgroup_record ), hitgroup_record_size * hitgroup_records.size() ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_hitgroup_record ), hitgroup_records.data(), + hitgroup_record_size * hitgroup_records.size(), cudaMemcpyHostToDevice ) ); + + state.sbt.raygenRecord = d_raygen_record; + state.sbt.missRecordBase = d_miss_record; + state.sbt.missRecordStrideInBytes = static_cast( miss_record_size ); + state.sbt.missRecordCount = RAY_TYPE_COUNT; + state.sbt.hitgroupRecordBase = d_hitgroup_record; + state.sbt.hitgroupRecordStrideInBytes = static_cast( hitgroup_record_size ); + state.sbt.hitgroupRecordCount = static_cast( hitgroup_records.size() ); +} + + +void bufferRays( RaycastingState& state ) +{ + // Create CUDA buffers for rays and hits + sutil::Aabb aabb = state.scene.aabb(); + aabb.invalidate(); + for( const auto& instance : state.scene.instances() ) + aabb.include( instance->world_aabb ); + const float3 bbox_span = aabb.extent(); + state.height = static_cast( state.width * bbox_span.y / bbox_span.x ); + + Ray* rays_d = 0; + Ray* translated_rays_d = 0; + size_t rays_size_in_bytes = sizeof( Ray ) * state.width * state.height; + CUDA_CHECK( cudaMalloc( &rays_d, rays_size_in_bytes ) ); + CUDA_CHECK( cudaMalloc( &translated_rays_d, rays_size_in_bytes ) ); + + createRaysOrthoOnDevice( rays_d, state.width, state.height, aabb.m_min, aabb.m_max, 0.05f ); + CUDA_CHECK( cudaGetLastError() ); + CUDA_CHECK( cudaMemcpy( translated_rays_d, rays_d, rays_size_in_bytes, cudaMemcpyDeviceToDevice ) ); + + translateRaysOnDevice( translated_rays_d, state.width * state.height, bbox_span * make_float3( 0.2f, 0, 0 ) ); + CUDA_CHECK( cudaGetLastError() ); + + Hit* hits_d = 0; + Hit* translated_hits_d = 0; + size_t hits_size_in_bytes = sizeof( Hit ) * state.width * state.height; + CUDA_CHECK( cudaMalloc( &hits_d, hits_size_in_bytes ) ); + CUDA_CHECK( cudaMalloc( &translated_hits_d, hits_size_in_bytes ) ); + + state.params = {state.scene.traversableHandle(), rays_d, hits_d}; + state.params_translated = {state.scene.traversableHandle(), translated_rays_d, translated_hits_d}; +} + + +void launch( RaycastingState& state ) +{ + CUstream stream_1 = 0; + CUstream stream_2 = 0; + CUDA_CHECK( cudaStreamCreate( &stream_1 ) ); + CUDA_CHECK( cudaStreamCreate( &stream_2 ) ); + + Params* d_params = 0; + Params* d_params_translated = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_params ), sizeof( Params ) ) ); + CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast( d_params ), &state.params, sizeof( Params ), + cudaMemcpyHostToDevice, stream_1 ) ); + + OPTIX_CHECK( optixLaunch( state.pipeline_1, stream_1, reinterpret_cast( d_params ), sizeof( Params ), + &state.sbt, state.width, state.height, 1 ) ); + + // Translated + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_params_translated ), sizeof( Params ) ) ); + CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast( d_params_translated ), &state.params_translated, + sizeof( Params ), cudaMemcpyHostToDevice, stream_2 ) ); + + OPTIX_CHECK( optixLaunch( state.pipeline_2, stream_2, reinterpret_cast( d_params_translated ), + sizeof( Params ), &state.sbt, state.width, state.height, 1 ) ); + + CUDA_SYNC_CHECK(); + + CUDA_CHECK( cudaFree( reinterpret_cast( d_params ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_params_translated ) ) ); +} + + +void shadeHits( RaycastingState& state, const std::string& outfile ) +{ + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, state.width, state.height ); + + sutil::ImageBuffer buffer; + buffer.width = state.width; + buffer.height = state.height; + buffer.pixel_format = sutil::BufferImageFormat::FLOAT3; + + // Original + shadeHitsOnDevice( output_buffer.map(), state.width * state.height, state.params.hits ); + CUDA_CHECK( cudaGetLastError() ); + output_buffer.unmap(); + + std::string ppmfile = outfile + ".ppm"; + buffer.data = output_buffer.getHostPointer(); + sutil::saveImage( ppmfile.c_str(), buffer, false ); + std::cerr << "Wrote image to " << ppmfile << std::endl; + + // Translated + shadeHitsOnDevice( output_buffer.map(), state.width * state.height, state.params_translated.hits ); + CUDA_CHECK( cudaGetLastError() ); + output_buffer.unmap(); + + ppmfile = outfile + "_translated.ppm"; + buffer.data = output_buffer.getHostPointer(); + sutil::saveImage( ppmfile.c_str(), buffer, false ); + std::cerr << "Wrote translated image to " << ppmfile << std::endl; +} + + +void cleanup( RaycastingState& state ) +{ + OPTIX_CHECK( optixPipelineDestroy( state.pipeline_1 ) ); + OPTIX_CHECK( optixPipelineDestroy( state.pipeline_2 ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.miss_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( state.hit_prog_group ) ); + OPTIX_CHECK( optixModuleDestroy( state.ptx_module ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.rays ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.hits ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params_translated.rays ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params_translated.hits ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.hitgroupRecordBase ) ) ); + + CUDA_CHECK( cudaDestroyTextureObject( state.mask.texture ) ); + CUDA_CHECK( cudaFreeArray( state.mask.array ) ); +} + + +int main( int argc, char** argv ) +{ + std::string infile, outfile; + RaycastingState state; + state.width = 640; + + // parse arguments + for( int i = 1; i < argc; ++i ) + { + std::string arg( argv[i] ); + if( arg == "-h" || arg == "--help" ) + { + printUsageAndExit( argv[0] ); + } + else if( ( arg == "-f" || arg == "--file" ) && i + 1 < argc ) + { + outfile = argv[++i]; + } + else if( ( arg == "-m" || arg == "--model" ) && i + 1 < argc ) + { + infile = argv[++i]; + } + else if( ( arg == "-w" || arg == "--width" ) && i + 1 < argc ) + { + state.width = atoi( argv[++i] ); + } + else + { + std::cerr << "Bad option: '" << arg << "'" << std::endl; + printUsageAndExit( argv[0] ); + } + } + + // Set default scene if user did not specify scene + if( infile.empty() ) + { + std::cerr << "No model specified, using default model (DuckHole.gltf)" << std::endl; + infile = sutil::sampleDataFilePath( "Duck/DuckHole.gltf" ); + } + + // Set default output file prefix + if( outfile.empty() ) + { + std::cerr << "No file prefix specified, using default file prefix (output)" << std::endl; + outfile = "output"; + } + + try + { + sutil::loadScene( infile.c_str(), state.scene ); + state.scene.createContext(); + + state.scene.buildMeshAccels(); + state.scene.buildInstanceAccel( RAY_TYPE_COUNT ); + state.context = state.scene.context(); + + OPTIX_CHECK( optixInit() ); // Need to initialize function table + createModule( state ); + createProgramGroups( state ); + createPipelines( state ); + createSBT( state ); + + bufferRays( state ); + launch( state ); + shadeHits( state, outfile ); + cleanup( state ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << std::endl; + return 1; + } + + return 0; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycasting.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycasting.cu new file mode 100644 index 00000000..d70922f3 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycasting.cu @@ -0,0 +1,106 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "optixRaycasting.h" +#include "optixRaycastingKernels.h" + +#include "cuda/LocalGeometry.h" +#include "cuda/whitted.h" +#include "cuda/LocalShading.h" + +#include + +extern "C" { +__constant__ Params params; +} + + +extern "C" __global__ void __raygen__from_buffer() +{ + const uint3 idx = optixGetLaunchIndex(); + const uint3 dim = optixGetLaunchDimensions(); + const unsigned int linear_idx = idx.z * dim.y * dim.x + idx.y * dim.x + idx.x; + + unsigned int t, nx, ny, nz; + Ray ray = params.rays[linear_idx]; + optixTrace( params.handle, ray.origin, ray.dir, ray.tmin, ray.tmax, 0.0f, OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_NONE, RAY_TYPE_RADIANCE, RAY_TYPE_COUNT, RAY_TYPE_RADIANCE, t, nx, ny, nz ); + + Hit hit; + hit.t = __uint_as_float( t ); + hit.geom_normal.x = __uint_as_float( nx ); + hit.geom_normal.y = __uint_as_float( ny ); + hit.geom_normal.z = __uint_as_float( nz ); + params.hits[linear_idx] = hit; +} + + +extern "C" __global__ void __miss__buffer_miss() +{ + optixSetPayload_0( __float_as_uint( -1.0f ) ); + optixSetPayload_1( __float_as_uint( 1.0f ) ); + optixSetPayload_2( __float_as_uint( 0.0f ) ); + optixSetPayload_3( __float_as_uint( 0.0f ) ); +} + + +extern "C" __global__ void __closesthit__buffer_hit() +{ + const float t = optixGetRayTmax(); + + whitted::HitGroupData* rt_data = (whitted::HitGroupData*)optixGetSbtDataPointer(); + LocalGeometry geom = getLocalGeometry( rt_data->geometry_data ); + + // Set the hit data + optixSetPayload_0( __float_as_uint( t ) ); + optixSetPayload_1( __float_as_uint( geom.N.x ) ); + optixSetPayload_2( __float_as_uint( geom.N.y ) ); + optixSetPayload_3( __float_as_uint( geom.N.z ) ); +} + + +extern "C" __global__ void __anyhit__texture_mask() +{ + whitted::HitGroupData* rt_data = (whitted::HitGroupData*)optixGetSbtDataPointer(); + + if( rt_data->material_data.alpha_mode == MaterialData::ALPHA_MODE_MASK ) + { + LocalGeometry geom = getLocalGeometry( rt_data->geometry_data ); + float4 mask = sampleTexture( rt_data->material_data.pbr.base_color_tex, geom ); + if( mask.w < rt_data->material_data.alpha_cutoff ) + { + optixIgnoreIntersection(); + } + } +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycasting.h b/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycasting.h new file mode 100644 index 00000000..9d8c4f21 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycasting.h @@ -0,0 +1,50 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + + +enum RayType +{ + RAY_TYPE_RADIANCE = 0, + RAY_TYPE_COUNT +}; + +struct Ray; +struct Hit; + +struct Params +{ + OptixTraversableHandle handle; + Ray* rays; + Hit* hits; +}; + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycastingKernels.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycastingKernels.cu new file mode 100644 index 00000000..e1e17556 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycastingKernels.cu @@ -0,0 +1,119 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "optixRaycastingKernels.h" + +#include + + +inline int idivCeil( int x, int y ) +{ + return ( x + y - 1 ) / y; +} + + +__global__ void createRaysOrthoKernel( Ray* rays, int width, int height, float x0, float y0, float z, float dx, float dy ) +{ + const int rayx = threadIdx.x + blockIdx.x * blockDim.x; + const int rayy = threadIdx.y + blockIdx.y * blockDim.y; + if( rayx >= width || rayy >= height ) + return; + + const int idx = rayx + rayy * width; + rays[idx].origin = make_float3( x0 + rayx * dx, y0 + rayy * dy, z ); + rays[idx].tmin = 0.0f; + rays[idx].dir = make_float3( 0, 0, 1 ); + rays[idx].tmax = 1e34f; +} + + +// Note: uses left handed coordinate system +void createRaysOrthoOnDevice( Ray* rays_device, int width, int height, float3 bbmin, float3 bbmax, float padding ) +{ + const float3 bbspan = bbmax - bbmin; + float dx = bbspan.x * ( 1 + 2 * padding ) / width; + float dy = bbspan.y * ( 1 + 2 * padding ) / height; + float x0 = bbmin.x - bbspan.x * padding + dx / 2; + float y0 = bbmin.y - bbspan.y * padding + dy / 2; + float z = bbmin.z - fmaxf( bbspan.z, 1.0f ) * .001f; + + dim3 blockSize( 32, 16 ); + dim3 gridSize( idivCeil( width, blockSize.x ), idivCeil( height, blockSize.y ) ); + createRaysOrthoKernel<<>>( rays_device, width, height, x0, y0, z, dx, dy ); +} + + +__global__ void translateRaysKernel( Ray* rays, int count, float3 offset ) +{ + int idx = threadIdx.x + blockIdx.x * blockDim.x; + if( idx >= count ) + return; + + rays[idx].origin = rays[idx].origin + offset; +} + + +void translateRaysOnDevice( Ray* rays_device, int count, float3 offset ) +{ + const int blockSize = 512; + const int blockCount = idivCeil( count, blockSize ); + translateRaysKernel<<>>( rays_device, count, offset ); +} + + +__global__ void shadeHitsKernel( float3* image, int count, const Hit* hits ) +{ + + int idx = threadIdx.x + blockIdx.x * blockDim.x; + if( idx >= count ) + return; + + const float3 backgroundColor = make_float3( 0.2f, 0.2f, 0.2f ); + if( hits[idx].t < 0.0f ) + { + image[idx] = backgroundColor; + } + else + { + image[idx] = 0.5f * hits[idx].geom_normal + make_float3( 0.5f, 0.5f, 0.5f ); + } +} + + +void shadeHitsOnDevice( float3* image_device, int count, const Hit* hits_device ) +{ + const int blockSize = 512; + const int blockCount = idivCeil( count, blockSize ); + shadeHitsKernel<<>>( image_device, count, hits_device ); +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycastingKernels.h b/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycastingKernels.h new file mode 100644 index 00000000..21e4ee1b --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixRaycasting/optixRaycastingKernels.h @@ -0,0 +1,57 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +// +// Kernels for processing hits and rays outside of OptiX +// + +struct Ray +{ + float3 origin; + float tmin; + float3 dir; + float tmax; +}; + +struct Hit +{ + float t; + float3 geom_normal; +}; + +void createRaysOrthoOnDevice( Ray* rays_device, int width, int height, float3 bbmin, float3 bbmax, float padding ); + +void translateRaysOnDevice( Ray* rays_device, int count, float3 offset ); + +void shadeHitsOnDevice( float3* image_device, int count, const Hit* hits_device ); + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixRibbons/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixRibbons/CMakeLists.txt new file mode 100644 index 00000000..84426f4b --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixRibbons/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixRibbons target_name + optixRibbons.cpp + optixRibbons.h + optixRibbons.cu + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixRibbons/optixRibbons.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixRibbons/optixRibbons.cpp new file mode 100644 index 00000000..32ca138f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixRibbons/optixRibbons.cpp @@ -0,0 +1,464 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include "optixRibbons.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +template +struct SbtRecord +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef SbtRecord RayGenSbtRecord; +typedef SbtRecord MissSbtRecord; +typedef SbtRecord HitGroupSbtRecord; + +void configureCamera( sutil::Camera& cam, const uint32_t width, const uint32_t height ) +{ + cam.setEye( { -8.0f, 3.7f, 2.6f } ); + cam.setLookat( { -7.7f, 2.92f, 4.4f } ); + + cam.setUp( {0.0f, 1.0f, 0.0f} ); + cam.setFovY( 35.0f ); + cam.setAspectRatio( (float)width / (float)height ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n"; +} + + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f Specify file for image output.\n"; + std::cerr << " --help | -h Print this usage message.\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 1024x768.\n"; + std::cerr << " --normals Use input normals for orienting ribbons.\n"; + exit( 1 ); +} + + +int main( int argc, char* argv[] ) +{ + // + // Command-line parameter parsing + // + + std::string outfile; + int width = 1024; + int height = 768; + bool ribbon_normals = false; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg( argv[i] ); + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--file" || arg == "-f" ) + { + if( i < argc - 1 ) + { + outfile = argv[++i]; + } + else + { + printUsageAndExit( argv[0] ); + } + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + sutil::parseDimensions( dims_arg.c_str(), width, height ); + } + else if( arg == "--normals" ) + { + ribbon_normals = true; + } + else + { + std::cerr << "Unknown option '" << arg << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + // + // Initialize CUDA and create OptiX context + // + OptixDeviceContext context = nullptr; + { + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + // Initialize the OptiX API, loading all API entry points + OPTIX_CHECK( optixInit() ); + + // Specify context options + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; +#if !defined( NDEBUG ) + // This may incur significant performance cost and should only be done during development. + options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; +#endif + + // Associate a CUDA context (and therefore a specific GPU) with this + // device context + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + } + + // + // build acceleration structure for ribbons + // + OptixTraversableHandle gas_handle; + CUdeviceptr d_gas_output_buffer; + + const unsigned int buildFlags = OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS | OPTIX_BUILD_FLAG_PREFER_FAST_TRACE; + { + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = buildFlags; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + // Ribbon build input, quadratic B-spline, given as lists of vertices, widths, indices, + // and optional normals. + // See optixRibbons.h for the input data used here. + + const size_t vertices_size = sizeof( float3 ) * num_vertices; + CUdeviceptr d_vertices = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_vertices ), vertices_size ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_vertices ), vertices.data(), vertices_size, cudaMemcpyHostToDevice ) ); + + + const size_t widthsSize = sizeof( float ) * num_vertices; + CUdeviceptr d_widths = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_widths ), widthsSize ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_widths ), widths.data(), widthsSize, cudaMemcpyHostToDevice ) ); + + CUdeviceptr d_normals = 0; + if( ribbon_normals ) + { + const size_t normals_size = sizeof( float3 ) * num_vertices; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_normals ), normals_size ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_normals ), normals.data(), normals_size, cudaMemcpyHostToDevice ) ); + } + + const size_t indicesSize = sizeof( int ) * num_indices; + CUdeviceptr d_indices = 0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_indices ), indicesSize ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_indices ), indices.data(), indicesSize, cudaMemcpyHostToDevice ) ); + + // Curve build input. + OptixBuildInput curve_input = {}; + + curve_input.type = OPTIX_BUILD_INPUT_TYPE_CURVES; + curve_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_FLAT_QUADRATIC_BSPLINE; + + curve_input.curveArray.numPrimitives = num_indices; + curve_input.curveArray.vertexBuffers = &d_vertices; + curve_input.curveArray.numVertices = num_vertices; + curve_input.curveArray.vertexStrideInBytes = sizeof( float3 ); + curve_input.curveArray.widthBuffers = &d_widths; + curve_input.curveArray.widthStrideInBytes = sizeof( float ); + curve_input.curveArray.normalBuffers = ribbon_normals ? &d_normals : 0; + curve_input.curveArray.normalStrideInBytes = ribbon_normals ? sizeof( float3 ) : 0; + curve_input.curveArray.indexBuffer = d_indices; + curve_input.curveArray.indexStrideInBytes = sizeof( int ); + curve_input.curveArray.flag = OPTIX_GEOMETRY_FLAG_NONE; + curve_input.curveArray.primitiveIndexOffset = 0; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( context, &accel_options, &curve_input, + 1, // Number of build inputs + &gas_buffer_sizes ) ); + + CUdeviceptr d_temp_buffer_gas; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer_gas ), gas_buffer_sizes.tempSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_gas_output_buffer ), gas_buffer_sizes.outputSizeInBytes ) ); + + OPTIX_CHECK( optixAccelBuild( context, 0, // CUDA stream + &accel_options, &curve_input, + 1, // num build inputs + d_temp_buffer_gas, gas_buffer_sizes.tempSizeInBytes, d_gas_output_buffer, + gas_buffer_sizes.outputSizeInBytes, &gas_handle, + nullptr, // emitted property list + 0 ) ); // num emitted properties + + // We can now free the scratch space buffer used during build and the vertex + // inputs, since they are not needed by our trivial shading method + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer_gas ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_vertices ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_widths ) ) ); + if( ribbon_normals ) + CUDA_CHECK( cudaFree( reinterpret_cast( d_normals ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_indices ) ) ); + } + + // + // Create modules + // + OptixModule shading_module = nullptr; + OptixModule geometry_module = nullptr; + OptixPipelineCompileOptions pipeline_compile_options = {}; + { + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + pipeline_compile_options.numPayloadValues = 3; + pipeline_compile_options.numAttributeValues = 2; // u, v ribbon parameters + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_FLAT_QUADRATIC_BSPLINE; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixRibbons.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( context, &module_compile_options, &pipeline_compile_options, input, + inputSize, LOG, &LOG_SIZE, &shading_module ) ); + + OptixBuiltinISOptions builtinISOptions = {}; + builtinISOptions.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_FLAT_QUADRATIC_BSPLINE; + builtinISOptions.buildFlags = buildFlags; + OPTIX_CHECK( optixBuiltinISModuleGet( context, &module_compile_options, &pipeline_compile_options, + &builtinISOptions, &geometry_module ) ); + } + + // + // Create program groups + // + OptixProgramGroup raygen_prog_group = nullptr; + OptixProgramGroup miss_prog_group = nullptr; + OptixProgramGroup hitgroup_prog_group = nullptr; + { + OptixProgramGroupOptions program_group_options = {}; // Initialize to zeros + + OptixProgramGroupDesc raygen_prog_group_desc = {}; // + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = shading_module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__basic"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( context, &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &raygen_prog_group ) ); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = shading_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__ms"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( context, &miss_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &miss_prog_group ) ); + + OptixProgramGroupDesc hitgroup_prog_group_desc = {}; + hitgroup_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hitgroup_prog_group_desc.hitgroup.moduleCH = shading_module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__ch"; + hitgroup_prog_group_desc.hitgroup.moduleIS = geometry_module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameIS = 0; // automatically supplied for built-in module + OPTIX_CHECK_LOG( optixProgramGroupCreate( context, &hitgroup_prog_group_desc, + 1, // num program groups + &program_group_options, LOG, &LOG_SIZE, &hitgroup_prog_group ) ); + } + + // + // Link pipeline + // + OptixPipeline pipeline = nullptr; + { + const uint32_t max_trace_depth = 1; + OptixProgramGroup program_groups[] = {raygen_prog_group, miss_prog_group, hitgroup_prog_group}; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + OPTIX_CHECK_LOG( optixPipelineCreate( context, &pipeline_compile_options, &pipeline_link_options, + program_groups, sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, &pipeline ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + ) ); + } + + // + // Set up shader binding table + // + OptixShaderBindingTable sbt = {}; + { + CUdeviceptr raygen_record; + const size_t raygen_record_size = sizeof( RayGenSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &raygen_record ), raygen_record_size ) ); + RayGenSbtRecord rg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( raygen_prog_group, &rg_sbt ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( raygen_record ), &rg_sbt, raygen_record_size, cudaMemcpyHostToDevice ) ); + + CUdeviceptr miss_record; + size_t miss_record_size = sizeof( MissSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &miss_record ), miss_record_size ) ); + MissSbtRecord ms_sbt; + ms_sbt.data = {0.0f, 0.2f, 0.6f}; // background color (blue) + OPTIX_CHECK( optixSbtRecordPackHeader( miss_prog_group, &ms_sbt ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( miss_record ), &ms_sbt, miss_record_size, cudaMemcpyHostToDevice ) ); + + CUdeviceptr hitgroup_record; + size_t hitgroup_record_size = sizeof( HitGroupSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &hitgroup_record ), hitgroup_record_size ) ); + HitGroupSbtRecord hg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( hitgroup_prog_group, &hg_sbt ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( hitgroup_record ), &hg_sbt, hitgroup_record_size, cudaMemcpyHostToDevice ) ); + + sbt.raygenRecord = raygen_record; + sbt.missRecordBase = miss_record; + sbt.missRecordStrideInBytes = sizeof( MissSbtRecord ); + sbt.missRecordCount = 1; + sbt.hitgroupRecordBase = hitgroup_record; + sbt.hitgroupRecordStrideInBytes = sizeof( HitGroupSbtRecord ); + sbt.hitgroupRecordCount = 1; + } + + sutil::CUDAOutputBuffer output_buffer( sutil::CUDAOutputBufferType::CUDA_DEVICE, width, height ); + + // + // launch + // + { + CUstream stream; + CUDA_CHECK( cudaStreamCreate( &stream ) ); + + sutil::Camera cam; + configureCamera( cam, width, height ); + + Params params; + params.image = output_buffer.map(); + params.image_width = width; + params.image_height = height; + params.handle = gas_handle; + params.cam_eye = cam.eye(); + cam.UVWFrame( params.cam_u, params.cam_v, params.cam_w ); + + CUdeviceptr d_param; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_param ), sizeof( Params ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_param ), ¶ms, sizeof( params ), cudaMemcpyHostToDevice ) ); + + OPTIX_CHECK( optixLaunch( pipeline, stream, d_param, sizeof( Params ), &sbt, width, height, /*depth=*/1 ) ); + CUDA_SYNC_CHECK(); + + output_buffer.unmap(); + CUDA_CHECK( cudaFree( reinterpret_cast( d_param ) ) ); + } + + // + // Display results + // + { + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = width; + buffer.height = height; + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + if( outfile.empty() ) + sutil::displayBufferWindow( argv[0], buffer ); + else + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + // + // Cleanup + // + { + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_gas_output_buffer ) ) ); + + OPTIX_CHECK( optixPipelineDestroy( pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( hitgroup_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( miss_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( raygen_prog_group ) ); + OPTIX_CHECK( optixModuleDestroy( shading_module ) ); + OPTIX_CHECK( optixModuleDestroy( geometry_module ) ); + + OPTIX_CHECK( optixDeviceContextDestroy( context ) ); + } + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixRibbons/optixRibbons.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixRibbons/optixRibbons.cu new file mode 100644 index 00000000..d81e8812 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixRibbons/optixRibbons.cu @@ -0,0 +1,129 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include "optixRibbons.h" +#include + +#include + + +extern "C" { +__constant__ Params params; +} + + +static __forceinline__ __device__ void setPayload( float3 p ) +{ + optixSetPayload_0( __float_as_uint( p.x ) ); + optixSetPayload_1( __float_as_uint( p.y ) ); + optixSetPayload_2( __float_as_uint( p.z ) ); +} + + +static __forceinline__ __device__ void computeRay( uint3 idx, uint3 dim, float3& origin, float3& direction ) +{ + const float3 U = params.cam_u; + const float3 V = params.cam_v; + const float3 W = params.cam_w; + const float2 d = 2.0f * make_float2( + static_cast( idx.x ) / static_cast( dim.x ), + static_cast( idx.y ) / static_cast( dim.y ) + ) - 1.0f; + + origin = params.cam_eye; + direction = normalize( d.x * U + d.y * V + W ); +} + + +extern "C" __global__ void __raygen__basic() +{ + // Lookup our location within the launch grid + const uint3 idx = optixGetLaunchIndex(); + const uint3 dim = optixGetLaunchDimensions(); + + // Map our launch idx to a screen location and create a ray from the camera + // location through the screen + float3 ray_origin, ray_direction; + computeRay( idx, dim, ray_origin, ray_direction ); + + // Trace the ray against our scene hierarchy + unsigned int p0, p1, p2; + optixTrace( + params.handle, + ray_origin, + ray_direction, + 0.0f, // Min intersection distance + 1e16f, // Max intersection distance + 0.0f, // rayTime -- used for motion blur + OptixVisibilityMask( 255 ), // Specify always visible + OPTIX_RAY_FLAG_NONE, + 0, // SBT offset -- See SBT discussion + RAY_TYPE_COUNT, // SBT stride -- See SBT discussion + 0, // missSBTIndex -- See SBT discussion + p0, p1, p2 ); + float3 result; + result.x = __uint_as_float( p0 ); + result.y = __uint_as_float( p1 ); + result.z = __uint_as_float( p2 ); + + // Record results in our output raster + params.image[idx.y * params.image_width + idx.x] = make_color( result ); +} + +extern "C" __global__ void __miss__ms() +{ + MissData* miss_data = reinterpret_cast( optixGetSbtDataPointer() ); + setPayload( miss_data->bg_color ); +} + + +extern "C" __global__ void __closesthit__ch() +{ + // When built-in ribbon intersection is used, the curve parameters u and v are provided + // by the OptiX API using optixGetRibbonParameters. + // The u range is [0,1] over the curve segment, v is [-1,1] over the width. + // The geometric normal at the intersection position is provided by optixGetRibbonNormal. + + const unsigned int prim_idx = optixGetPrimitiveIndex(); + const OptixTraversableHandle gas = optixGetGASTraversableHandle(); + const unsigned int sbtGASIndex = optixGetSbtGASIndex(); + const float2 uv = optixGetRibbonParameters(); + float3 obj_normal = optixGetRibbonNormal( gas, prim_idx, sbtGASIndex, 0.f /*time*/, uv ); + + float3 world_normal = normalize( optixTransformNormalFromObjectToWorldSpace( obj_normal ) ); + // 2-sided ribbon surface + world_normal = faceforward( world_normal, -optixGetWorldRayDirection(), world_normal ); + + setPayload( make_float3( world_normal.x * 0.5f + 0.5f, + world_normal.y * 0.5f + 0.5f, + world_normal.z * 0.5f + 0.5f ) ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixRibbons/optixRibbons.h b/Extern/3rdParty/OptiX/Linux/SDK/optixRibbons/optixRibbons.h new file mode 100644 index 00000000..2c9e97e6 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixRibbons/optixRibbons.h @@ -0,0 +1,353 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#ifndef __CUDACC__ + +#include + +const unsigned int num_vertices = 470; +const unsigned int num_indices = 410; + +std::vector vertices = { + { -8.670039f, 0.000000f, 7.822359f }, { -8.670039f, 0.000000f, 7.822359f }, + { -8.584811f, 0.166265f, 7.772195f }, { -8.508430f, 0.313932f, 7.727035f }, + { -8.440895f, 0.443001f, 7.686878f }, { -8.382207f, 0.553473f, 7.651725f }, + { -8.332366f, 0.645347f, 7.621576f }, { -8.282078f, 0.734969f, 7.591182f }, + { -8.222047f, 0.838685f, 7.555293f }, { -8.152273f, 0.956495f, 7.513909f }, + { -8.072758f, 1.088400f, 7.467031f }, { -7.983500f, 1.234398f, 7.414657f }, + { -7.983500f, 1.234398f, 7.414657f }, { -8.670039f, 0.000000f, 7.822359f }, + { -8.670039f, 0.000000f, 7.822359f }, { -8.582369f, 0.170223f, 7.849607f }, + { -8.503665f, 0.321036f, 7.875956f }, { -8.433928f, 0.452438f, 7.901403f }, + { -8.373159f, 0.564431f, 7.925951f }, { -8.321358f, 0.657013f, 7.949597f }, + { -8.269210f, 0.746435f, 7.976940f }, { -8.207405f, 0.848946f, 8.012576f }, + { -8.135942f, 0.964546f, 8.056506f }, { -8.054822f, 1.093235f, 8.108728f }, + { -7.964044f, 1.235012f, 8.169245f }, { -7.964044f, 1.235012f, 8.169245f }, + { -8.670039f, 0.000000f, 7.822359f }, { -8.670039f, 0.000000f, 7.822359f }, + { -8.646622f, 0.191696f, 7.811856f }, { -8.627491f, 0.362598f, 7.803891f }, + { -8.612647f, 0.512706f, 7.798461f }, { -8.602090f, 0.642019f, 7.795568f }, + { -8.595820f, 0.750538f, 7.795213f }, { -8.592780f, 0.857554f, 7.797716f }, + { -8.591914f, 0.982359f, 7.803401f }, { -8.593221f, 1.124952f, 7.812267f }, + { -8.596701f, 1.285334f, 7.824315f }, { -8.602355f, 1.463504f, 7.839545f }, + { -8.602355f, 1.463504f, 7.839545f }, { -8.738152f, 0.000000f, 7.673146f }, + { -8.738152f, 0.000000f, 7.673146f }, { -8.709185f, 0.170485f, 7.626663f }, + { -8.681140f, 0.321934f, 7.585022f }, { -8.654017f, 0.454345f, 7.548224f }, + { -8.627818f, 0.567720f, 7.516268f }, { -8.602541f, 0.662057f, 7.489155f }, + { -8.576440f, 0.746096f, 7.464618f }, { -8.547768f, 0.828572f, 7.440392f }, + { -8.516524f, 0.909487f, 7.416477f }, { -8.482709f, 0.988840f, 7.392871f }, + { -8.446323f, 1.066631f, 7.369577f }, { -8.404433f, 1.150952f, 7.346392f }, + { -8.354105f, 1.249896f, 7.323114f }, { -8.295340f, 1.363464f, 7.299744f }, + { -8.228136f, 1.491653f, 7.276282f }, { -8.152495f, 1.634466f, 7.252727f }, + { -8.152495f, 1.634466f, 7.252727f }, { -8.738152f, 0.000000f, 7.673146f }, + { -8.738152f, 0.000000f, 7.673146f }, { -8.664515f, 0.163133f, 7.680197f }, + { -8.598255f, 0.308313f, 7.686074f }, { -8.539371f, 0.435541f, 7.690777f }, + { -8.487863f, 0.544817f, 7.694306f }, { -8.443730f, 0.636140f, 7.696661f }, + { -8.402942f, 0.717970f, 7.698318f }, { -8.361461f, 0.798769f, 7.699749f }, + { -8.319290f, 0.878535f, 7.700956f }, { -8.276427f, 0.957269f, 7.701938f }, + { -8.232874f, 1.034971f, 7.702695f }, { -8.185812f, 1.119633f, 7.705873f }, + { -8.132421f, 1.219250f, 7.714118f }, { -8.072702f, 1.333822f, 7.727427f }, + { -8.006656f, 1.463348f, 7.745804f }, { -7.934282f, 1.607828f, 7.769246f }, + { -7.934282f, 1.607828f, 7.769246f }, { -8.236132f, 0.000000f, 7.791636f }, + { -8.236132f, 0.000000f, 7.791636f }, { -8.146681f, 0.221473f, 7.769691f }, + { -8.066971f, 0.418645f, 7.750065f }, { -7.997001f, 0.591517f, 7.732759f }, + { -7.936772f, 0.740088f, 7.717772f }, { -7.886283f, 0.864359f, 7.705105f }, + { -7.836252f, 0.986598f, 7.692789f }, { -7.777395f, 1.129073f, 7.678853f }, + { -7.709711f, 1.291785f, 7.663298f }, { -7.633201f, 1.474733f, 7.646125f }, + { -7.547864f, 1.677917f, 7.627332f }, { -7.547864f, 1.677917f, 7.627332f }, + { -8.236132f, 0.000000f, 7.791636f }, { -8.236132f, 0.000000f, 7.791636f }, + { -8.191101f, 0.227125f, 7.853988f }, { -8.150015f, 0.428371f, 7.911890f }, + { -8.112872f, 0.603739f, 7.965343f }, { -8.079673f, 0.753229f, 8.014347f }, + { -8.050418f, 0.876840f, 8.058901f }, { -8.019703f, 0.996361f, 8.107233f }, + { -7.982127f, 1.133582f, 8.167569f }, { -7.937689f, 1.288502f, 8.239908f }, + { -7.886389f, 1.461122f, 8.324252f }, { -7.828228f, 1.651441f, 8.420600f }, + { -7.828228f, 1.651441f, 8.420600f }, { -8.510754f, 0.000000f, 7.150823f }, + { -8.510754f, 0.000000f, 7.150823f }, { -8.359742f, 0.226911f, 7.177612f }, + { -8.223524f, 0.427066f, 7.204529f }, { -8.102100f, 0.600465f, 7.231576f }, + { -7.995471f, 0.747107f, 7.258750f }, { -7.903635f, 0.866993f, 7.286054f }, + { -7.818839f, 0.971781f, 7.314842f }, { -7.733330f, 1.073132f, 7.346471f }, + { -7.647109f, 1.171044f, 7.380941f }, { -7.560174f, 1.265519f, 7.418252f }, + { -7.472526f, 1.356555f, 7.458403f }, { -7.376465f, 1.453485f, 7.504345f }, + { -7.264292f, 1.565641f, 7.559027f }, { -7.136007f, 1.693021f, 7.622449f }, + { -6.991611f, 1.835626f, 7.694611f }, { -6.831102f, 1.993457f, 7.775513f }, + { -6.831102f, 1.993457f, 7.775513f }, { -8.510754f, 0.000000f, 7.150823f }, + { -8.510754f, 0.000000f, 7.150823f }, { -8.456405f, 0.261047f, 7.213643f }, + { -8.407352f, 0.492561f, 7.272115f }, { -8.363595f, 0.694540f, 7.326238f }, + { -8.325134f, 0.866985f, 7.376011f }, { -8.291969f, 1.009896f, 7.421436f }, + { -8.261172f, 1.136849f, 7.465682f }, { -8.229816f, 1.261420f, 7.511918f }, + { -8.197903f, 1.383609f, 7.560145f }, { -8.165429f, 1.503416f, 7.610364f }, + { -8.132398f, 1.620841f, 7.662573f }, { -8.095483f, 1.746328f, 7.722568f }, + { -8.051359f, 1.890320f, 7.796140f }, { -8.000028f, 2.052819f, 7.883292f }, + { -7.941488f, 2.233824f, 7.984022f }, { -7.875740f, 2.433334f, 8.098331f }, + { -7.875740f, 2.433334f, 8.098331f }, { -8.510754f, 0.000000f, 7.150823f }, + { -8.510754f, 0.000000f, 7.150823f }, { -8.436205f, 0.259978f, 7.107025f }, + { -8.369174f, 0.491458f, 7.069734f }, { -8.309660f, 0.694439f, 7.038951f }, + { -8.257663f, 0.868921f, 7.014676f }, { -8.213183f, 1.014904f, 6.996907f }, + { -8.172123f, 1.145914f, 6.983563f }, { -8.130383f, 1.275474f, 6.972561f }, + { -8.087967f, 1.403584f, 6.963900f }, { -8.044871f, 1.530245f, 6.957581f }, + { -8.001098f, 1.655456f, 6.953603f }, { -7.951534f, 1.790527f, 6.952733f }, + { -7.891068f, 1.946769f, 6.955737f }, { -7.819700f, 2.124182f, 6.962614f }, + { -7.737430f, 2.322765f, 6.973364f }, { -7.644258f, 2.542518f, 6.987988f }, + { -7.644258f, 2.542518f, 6.987988f }, { -8.397420f, 0.000000f, 7.149617f }, + { -8.397420f, 0.000000f, 7.149617f }, { -8.272721f, 0.182657f, 7.155383f }, + { -8.160598f, 0.344651f, 7.160014f }, { -8.061049f, 0.485982f, 7.163509f }, + { -7.974075f, 0.606651f, 7.165869f }, { -7.899676f, 0.706657f, 7.167092f }, + { -7.831263f, 0.795503f, 7.167651f }, { -7.762244f, 0.882692f, 7.168016f }, + { -7.692619f, 0.968223f, 7.168186f }, { -7.622390f, 1.052097f, 7.168162f }, + { -7.551555f, 1.134313f, 7.167944f }, { -7.473679f, 1.222770f, 7.170103f }, + { -7.382326f, 1.325367f, 7.177211f }, { -7.277496f, 1.442103f, 7.189268f }, + { -7.159189f, 1.572978f, 7.206275f }, { -7.027404f, 1.717992f, 7.228230f }, + { -7.027404f, 1.717992f, 7.228230f }, { -8.397420f, 0.000000f, 7.149617f }, + { -8.397420f, 0.000000f, 7.149617f }, { -8.338680f, 0.205089f, 7.208059f }, + { -8.284274f, 0.386778f, 7.261158f }, { -8.234200f, 0.545068f, 7.308914f }, + { -8.188461f, 0.679958f, 7.351326f }, { -8.147055f, 0.791449f, 7.388395f }, + { -8.106851f, 0.890077f, 7.423254f }, { -8.064715f, 0.986378f, 7.459036f }, + { -8.020649f, 1.080354f, 7.495741f }, { -7.974653f, 1.172003f, 7.533369f }, + { -7.926727f, 1.261327f, 7.571919f }, { -7.871441f, 1.356288f, 7.614641f }, + { -7.803368f, 1.464853f, 7.664784f }, { -7.722507f, 1.587021f, 7.722348f }, + { -7.628858f, 1.722792f, 7.787333f }, { -7.522421f, 1.872165f, 7.859740f }, + { -7.522421f, 1.872165f, 7.859740f }, { -8.032948f, 0.000000f, 7.825102f }, + { -8.032948f, 0.000000f, 7.825102f }, { -8.013132f, 0.341121f, 7.810423f }, + { -7.991465f, 0.678998f, 7.796645f }, { -7.967945f, 1.013630f, 7.783768f }, + { -7.942573f, 1.345017f, 7.771792f }, { -7.915349f, 1.673159f, 7.760717f }, + { -7.915349f, 1.673159f, 7.760717f }, { -8.032948f, 0.000000f, 7.825102f }, + { -8.032948f, 0.000000f, 7.825102f }, { -7.885149f, 0.306930f, 7.794697f }, + { -7.739688f, 0.611640f, 7.766084f }, { -7.596562f, 0.914130f, 7.739262f }, + { -7.455772f, 1.214401f, 7.714231f }, { -7.317318f, 1.512452f, 7.690991f }, + { -7.317318f, 1.512452f, 7.690991f }, { -8.032948f, 0.000000f, 7.825102f }, + { -8.032948f, 0.000000f, 7.825102f }, { -7.936470f, 0.313923f, 7.920269f }, + { -7.839081f, 0.622782f, 8.019278f }, { -7.740781f, 0.926576f, 8.122128f }, + { -7.641569f, 1.225306f, 8.228818f }, { -7.541445f, 1.518972f, 8.339350f }, + { -7.541445f, 1.518972f, 8.339350f }, { -7.883137f, 0.000000f, 7.619610f }, + { -7.883137f, 0.000000f, 7.619610f }, { -7.778723f, 0.211165f, 7.643391f }, + { -7.684823f, 0.398653f, 7.665671f }, { -7.601436f, 0.562464f, 7.686450f }, + { -7.528561f, 0.702597f, 7.705729f }, { -7.466199f, 0.819054f, 7.723506f }, + { -7.402702f, 0.932359f, 7.743283f }, { -7.326420f, 1.063036f, 7.768560f }, + { -7.237355f, 1.211087f, 7.799338f }, { -7.135505f, 1.376511f, 7.835615f }, + { -7.020872f, 1.559309f, 7.877392f }, { -7.020872f, 1.559309f, 7.877392f }, + { -7.883137f, 0.000000f, 7.619610f }, { -7.883137f, 0.000000f, 7.619610f }, + { -7.867801f, 0.231450f, 7.667086f }, { -7.855600f, 0.437772f, 7.708887f }, + { -7.846536f, 0.618967f, 7.745014f }, { -7.840607f, 0.775035f, 7.775466f }, + { -7.837814f, 0.905975f, 7.800244f }, { -7.837637f, 1.035229f, 7.824006f }, + { -7.839559f, 1.186239f, 7.851407f }, { -7.843577f, 1.359004f, 7.882447f }, + { -7.849694f, 1.553525f, 7.917128f }, { -7.857907f, 1.769801f, 7.955449f }, + { -7.857907f, 1.769801f, 7.955449f }, { -7.883137f, 0.000000f, 7.619610f }, + { -7.883137f, 0.000000f, 7.619610f }, { -7.843293f, 0.229593f, 7.577678f }, + { -7.808427f, 0.434416f, 7.541631f }, { -7.778541f, 0.614467f, 7.511471f }, + { -7.753633f, 0.769747f, 7.487196f }, { -7.733704f, 0.900256f, 7.468808f }, + { -7.714710f, 1.029390f, 7.453807f }, { -7.692610f, 1.180545f, 7.439697f }, + { -7.667404f, 1.353721f, 7.426477f }, { -7.639090f, 1.548917f, 7.414146f }, + { -7.607670f, 1.766134f, 7.402706f }, { -7.607670f, 1.766134f, 7.402706f }, + { -8.307483f, 0.000000f, 8.109686f }, { -8.307483f, 0.000000f, 8.109686f }, + { -8.270832f, 0.255216f, 8.136321f }, { -8.238932f, 0.482493f, 8.160245f }, + { -8.211782f, 0.681830f, 8.181458f }, { -8.189382f, 0.853227f, 8.199960f }, + { -8.171733f, 0.996684f, 8.215751f }, { -8.156961f, 1.125576f, 8.230362f }, + { -8.143195f, 1.253277f, 8.245325f }, { -8.130434f, 1.379789f, 8.260641f }, + { -8.118677f, 1.505110f, 8.276308f }, { -8.107924f, 1.629241f, 8.292327f }, + { -8.097789f, 1.752148f, 8.308618f }, { -8.087881f, 1.873797f, 8.325098f }, + { -8.078200f, 1.994189f, 8.341769f }, { -8.068748f, 2.113324f, 8.358631f }, + { -8.059523f, 2.231201f, 8.375684f }, { -8.050627f, 2.347852f, 8.392744f }, + { -8.042158f, 2.463310f, 8.409629f }, { -8.034120f, 2.577573f, 8.426338f }, + { -8.026509f, 2.690643f, 8.442871f }, { -8.019328f, 2.802519f, 8.459229f }, + { -8.012767f, 2.913069f, 8.476151f }, { -8.007018f, 3.022165f, 8.494381f }, + { -8.002081f, 3.129804f, 8.513916f }, { -7.997956f, 3.235987f, 8.534759f }, + { -7.994642f, 3.340714f, 8.556907f }, { -7.991648f, 3.453553f, 8.583124f }, + { -7.988479f, 3.584071f, 8.616174f }, { -7.985135f, 3.732266f, 8.656054f }, + { -7.981617f, 3.898141f, 8.702768f }, { -7.977925f, 4.081694f, 8.756313f }, + { -7.977925f, 4.081694f, 8.756313f }, { -8.307483f, 0.000000f, 8.109686f }, + { -8.307483f, 0.000000f, 8.109686f }, { -8.181755f, 0.217729f, 8.172421f }, + { -8.069973f, 0.410590f, 8.231261f }, { -7.972136f, 0.578583f, 8.286208f }, + { -7.888244f, 0.721708f, 8.337261f }, { -7.818297f, 0.839966f, 8.384420f }, + { -7.755838f, 0.944644f, 8.430925f }, { -7.694408f, 1.047029f, 8.480017f }, + { -7.634007f, 1.147120f, 8.531694f }, { -7.574635f, 1.244919f, 8.585958f }, + { -7.516292f, 1.340425f, 8.642807f }, { -7.458507f, 1.434043f, 8.700855f }, + { -7.400812f, 1.526178f, 8.758715f }, { -7.343204f, 1.616830f, 8.816385f }, + { -7.285686f, 1.705999f, 8.873868f }, { -7.228256f, 1.793686f, 8.931161f }, + { -7.170918f, 1.879972f, 8.988116f }, { -7.113672f, 1.964940f, 9.044586f }, + { -7.056520f, 2.048589f, 9.100571f }, { -6.999461f, 2.130921f, 9.156068f }, + { -6.942495f, 2.211935f, 9.211080f }, { -6.886177f, 2.292158f, 9.265375f }, + { -6.831057f, 2.372120f, 9.318723f }, { -6.777137f, 2.451820f, 9.371123f }, + { -6.724417f, 2.531257f, 9.422577f }, { -6.672897f, 2.610433f, 9.473083f }, + { -6.617935f, 2.697112f, 9.526937f }, { -6.554892f, 2.799060f, 9.588433f }, + { -6.483766f, 2.916276f, 9.657571f }, { -6.404559f, 3.048761f, 9.734352f }, + { -6.317269f, 3.196514f, 9.818774f }, { -6.317269f, 3.196514f, 9.818774f }, + { -7.594878f, 0.000000f, 7.429878f }, { -7.594878f, 0.000000f, 7.429878f }, + { -7.528560f, 0.166761f, 7.398273f }, { -7.468292f, 0.315035f, 7.370658f }, + { -7.414075f, 0.444820f, 7.347034f }, { -7.365910f, 0.556118f, 7.327400f }, + { -7.323794f, 0.648927f, 7.311758f }, { -7.279458f, 0.739546f, 7.297550f }, + { -7.224627f, 0.844268f, 7.282222f }, { -7.159304f, 0.963096f, 7.265774f }, + { -7.083487f, 1.096028f, 7.248206f }, { -6.997175f, 1.243064f, 7.229518f }, + { -6.997175f, 1.243064f, 7.229518f }, { -7.594878f, 0.000000f, 7.429878f }, + { -7.594878f, 0.000000f, 7.429878f }, { -7.517504f, 0.160118f, 7.469549f }, + { -7.448520f, 0.302312f, 7.506748f }, { -7.387926f, 0.426580f, 7.541473f }, + { -7.335723f, 0.532924f, 7.573724f }, { -7.291910f, 0.621343f, 7.603503f }, + { -7.248291f, 0.707335f, 7.636390f }, { -7.196671f, 0.806402f, 7.677967f }, + { -7.137051f, 0.918541f, 7.728235f }, { -7.069430f, 1.043754f, 7.787194f }, + { -6.993807f, 1.182041f, 7.854843f }, { -6.993807f, 1.182041f, 7.854843f }, + { -7.594878f, 0.000000f, 7.429878f }, { -7.594878f, 0.000000f, 7.429878f }, + { -7.581472f, 0.181002f, 7.445610f }, { -7.568405f, 0.341963f, 7.461755f }, + { -7.555676f, 0.482880f, 7.478315f }, { -7.543285f, 0.603756f, 7.495288f }, + { -7.531233f, 0.704588f, 7.512675f }, { -7.516715f, 0.802937f, 7.534356f }, + { -7.496925f, 0.916360f, 7.564211f }, { -7.471865f, 1.044857f, 7.602240f }, + { -7.441533f, 1.188428f, 7.648443f }, { -7.405929f, 1.347073f, 7.702820f }, + { -7.405929f, 1.347073f, 7.702820f }, { -8.093362f, 0.000000f, 8.079795f }, + { -8.093362f, 0.000000f, 8.079795f }, { -8.001437f, 0.152696f, 8.124266f }, + { -7.920665f, 0.288835f, 8.165910f }, { -7.851046f, 0.408416f, 8.204726f }, + { -7.792579f, 0.511440f, 8.240714f }, { -7.745264f, 0.597906f, 8.273875f }, + { -7.704288f, 0.675689f, 8.306500f }, { -7.664837f, 0.752664f, 8.340881f }, + { -7.626910f, 0.828829f, 8.377018f }, { -7.590508f, 0.904186f, 8.414910f }, + { -7.555630f, 0.978733f, 8.454559f }, { -7.518137f, 1.059076f, 8.499926f }, + { -7.473887f, 1.151817f, 8.554968f }, { -7.422883f, 1.256957f, 8.619688f }, + { -7.365122f, 1.374496f, 8.694085f }, { -7.300605f, 1.504433f, 8.778160f }, + { -7.300605f, 1.504433f, 8.778160f }, { -8.093362f, 0.000000f, 8.079795f }, + { -8.093362f, 0.000000f, 8.079795f }, { -8.006337f, 0.159178f, 8.050700f }, + { -7.928403f, 0.300619f, 8.023419f }, { -7.859559f, 0.424323f, 7.997952f }, + { -7.799805f, 0.530289f, 7.974298f }, { -7.749141f, 0.618519f, 7.952458f }, + { -7.702960f, 0.697317f, 7.931009f }, { -7.656652f, 0.774992f, 7.908530f }, + { -7.610218f, 0.851542f, 7.885020f }, { -7.563658f, 0.926967f, 7.860479f }, + { -7.516971f, 1.001269f, 7.834908f }, { -7.464770f, 1.081640f, 7.807999f }, + { -7.401668f, 1.175276f, 7.779442f }, { -7.327663f, 1.282176f, 7.749238f }, + { -7.242757f, 1.402340f, 7.717386f }, { -7.146949f, 1.535769f, 7.683887f }, + { -7.146949f, 1.535769f, 7.683887f }, { -7.521180f, 0.000000f, 7.366457f }, + { -7.521180f, 0.000000f, 7.366457f }, { -7.486225f, 0.259586f, 7.321877f }, + { -7.451504f, 0.517666f, 7.279280f }, { -7.417017f, 0.774240f, 7.238667f }, + { -7.382764f, 1.029308f, 7.200037f }, { -7.348745f, 1.282871f, 7.163393f }, + { -7.348745f, 1.282871f, 7.163393f }, { -7.521180f, 0.000000f, 7.366457f }, + { -7.521180f, 0.000000f, 7.366457f }, { -7.396802f, 0.234625f, 7.373309f }, + { -7.269887f, 0.465718f, 7.380208f }, { -7.140438f, 0.693280f, 7.387153f }, + { -7.008452f, 0.917311f, 7.394145f }, { -6.873930f, 1.137811f, 7.401186f }, + { -6.873930f, 1.137811f, 7.401186f }, { -7.356729f, 0.000000f, 7.962389f }, + { -7.356729f, 0.000000f, 7.962389f }, { -7.291108f, 0.183815f, 7.932908f }, + { -7.231727f, 0.347323f, 7.906398f }, { -7.178586f, 0.490523f, 7.882861f }, + { -7.131686f, 0.613417f, 7.862296f }, { -7.091026f, 0.716004f, 7.844703f }, + { -7.053041f, 0.807857f, 7.828533f }, { -7.014165f, 0.898551f, 7.812236f }, + { -6.974399f, 0.988085f, 7.795814f }, { -6.933742f, 1.076460f, 7.779265f }, + { -6.892194f, 1.163675f, 7.762591f }, { -6.846416f, 1.258571f, 7.745053f }, + { -6.793065f, 1.369989f, 7.725915f }, { -6.732143f, 1.497930f, 7.705175f }, + { -6.663651f, 1.642393f, 7.682836f }, { -6.587586f, 1.803379f, 7.658895f }, + { -6.587586f, 1.803379f, 7.658895f }, { -7.216461f, 0.000000f, 7.699934f }, + { -7.216461f, 0.000000f, 7.699934f }, { -7.089989f, 0.198293f, 7.728107f }, + { -6.976520f, 0.374039f, 7.755132f }, { -6.876053f, 0.527237f, 7.781010f }, + { -6.788590f, 0.657887f, 7.805740f }, { -6.714129f, 0.765990f, 7.829322f }, + { -6.645981f, 0.861854f, 7.853003f }, { -6.577454f, 0.955787f, 7.878027f }, + { -6.508548f, 1.047790f, 7.904397f }, { -6.439263f, 1.137863f, 7.932111f }, + { -6.369599f, 1.226005f, 7.961170f }, { -6.291316f, 1.319250f, 7.993738f }, + { -6.196169f, 1.424630f, 8.031981f }, { -6.084159f, 1.542145f, 8.075898f }, + { -5.955287f, 1.671795f, 8.125489f }, { -5.809553f, 1.813581f, 8.180756f }, + { -5.809553f, 1.813581f, 8.180756f }, { -7.120879f, 0.000000f, 7.276439f }, + { -7.120879f, 0.000000f, 7.276439f }, { -7.093204f, 0.169843f, 7.240611f }, + { -7.067285f, 0.320988f, 7.208515f }, { -7.043121f, 0.453434f, 7.180151f }, + { -7.020713f, 0.567183f, 7.155518f }, { -7.000062f, 0.662233f, 7.134617f }, + { -6.979599f, 0.747422f, 7.115569f }, { -6.957760f, 0.831586f, 7.096496f }, + { -6.934544f, 0.914725f, 7.077397f }, { -6.909950f, 0.996840f, 7.058272f }, + { -6.883979f, 1.077930f, 7.039121f }, { -6.856466f, 1.157883f, 7.020153f }, + { -6.827244f, 1.236588f, 7.001574f }, { -6.796315f, 1.314044f, 6.983384f }, + { -6.763678f, 1.390253f, 6.965583f }, { -6.729332f, 1.465212f, 6.948173f }, + { -6.689106f, 1.545533f, 6.929567f }, { -6.638829f, 1.637824f, 6.908183f }, + { -6.578499f, 1.742085f, 6.884019f }, { -6.508118f, 1.858316f, 6.857076f }, + { -6.427684f, 1.986518f, 6.827353f }, { -6.427684f, 1.986518f, 6.827353f } +}; + +// Normals are given at segment borders and are linearly interpolated along the segments. +// A segment starting at control point i uses normals i and i+1. + +std::vector normals( num_vertices, { 0.f, 0.f, 1.f } ); + +std::vector widths( num_vertices, 0.05f ); + +std::vector indices = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 191, 192, 193, 194, 195, 196, 199, 200, 201, 202, 203, 204, + 207, 208, 209, 210, 211, 212, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, + 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 333, 334, 335, 336, + 337, 338, 339, 340, 341, 342, 343, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 359, + 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, + 395, 396, 397, 398, 399, 400, + 403, 404, 405, 406, 407, 408, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, + 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, + 463, 464, 465, 466, 467 +}; + +#endif // ifndef __CUDACC__ + +enum RayType +{ + RAY_TYPE_RADIANCE = 0, + RAY_TYPE_COUNT +}; + +struct Params +{ + uchar4* image; + unsigned int image_width; + unsigned int image_height; + float3 cam_eye; + float3 cam_u, cam_v, cam_w; + OptixTraversableHandle handle; +}; + + +struct RayGenData +{ + // No data needed +}; + + +struct MissData +{ + float3 bg_color; +}; + + +struct HitGroupData +{ + // No data needed +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixSimpleMotionBlur/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixSimpleMotionBlur/CMakeLists.txt new file mode 100644 index 00000000..6a0accaa --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixSimpleMotionBlur/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixSimpleMotionBlur target_name + optixSimpleMotionBlur.cu + optixSimpleMotionBlur.cpp + optixSimpleMotionBlur.h + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixSimpleMotionBlur/optixSimpleMotionBlur.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixSimpleMotionBlur/optixSimpleMotionBlur.cpp new file mode 100644 index 00000000..179caa5c --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixSimpleMotionBlur/optixSimpleMotionBlur.cpp @@ -0,0 +1,1162 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include // Needs to be included before gl_interop + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "optixSimpleMotionBlur.h" + +#include +#include +#include +#include +#include +#include +#include + +bool resize_dirty = false; +bool minimized = false; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Mouse state +int2 mouse_prev_pos; +int32_t mouse_button = -1; + +int32_t samples_per_launch = 16; + +//------------------------------------------------------------------------------ +// +// Local types +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +template +struct Record +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef Record RayGenRecord; +typedef Record MissRecord; +typedef Record HitGroupRecord; + + +enum InstanceType +{ + SPHERE=0, + TRI, + COUNT +}; + + +struct Vertex +{ + float x, y, z, pad; +}; + + +struct IndexedTriangle +{ + uint32_t v1, v2, v3, pad; +}; + + +struct Instance +{ + float transform[12]; +}; + + +struct SimpleMotionBlurState +{ + OptixDeviceContext context = 0; + + OptixTraversableHandle tri_gas_handle = 0; // Traversable handle for triangle AS + CUdeviceptr d_tri_gas_output_buffer = 0; // Triangle AS memory + + OptixTraversableHandle sphere_gas_handle = 0; // Traversable handle for sphere + CUdeviceptr d_sphere_gas_output_buffer = 0; // Sphere AS memory + OptixTraversableHandle sphere_motion_transform_handle = 0; + CUdeviceptr d_sphere_motion_transform = 0; + + OptixTraversableHandle ias_handle = 0; // Traversable handle for instance AS + CUdeviceptr d_ias_output_buffer = 0; // Instance AS memory + + OptixModule ptx_module = 0; + OptixPipelineCompileOptions pipeline_compile_options = {}; + OptixPipeline pipeline = 0; + + OptixProgramGroup raygen_prog_group = 0; + OptixProgramGroup miss_group = 0; + OptixProgramGroup tri_hit_group = 0; + OptixProgramGroup sphere_hit_group = 0; + + CUstream stream = 0; + Params params; + Params* d_params; + + OptixShaderBindingTable sbt = {}; +}; + + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking(static_cast( xpos ), static_cast( ypos )); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + Params* params = static_cast( glfwGetWindowUserPointer( window ) ); + + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params->width, params->height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params->width, params->height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + Params* params = static_cast( glfwGetWindowUserPointer( window ) ); + params->width = res_x; + params->height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || + key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + } + else if( key == GLFW_KEY_G ) + { + // toggle UI draw + } +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --no-gl-interop Disable GL interop for display\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 768x768\n"; + std::cerr << " --help | -h Print this usage message\n"; + exit( 0 ); +} + + +void initLaunchParams( SimpleMotionBlurState& state ) +{ + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &state.params.accum_buffer ), + state.params.width*state.params.height*sizeof(float4) + ) ); + + state.params.frame_buffer = nullptr; // Will be set when output buffer is mapped + + state.params.subframe_index = 0u; + + CUDA_CHECK( cudaStreamCreate( &state.stream ) ); + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_params ), sizeof( Params ) ) ); + + state.params.handle = state.ias_handle; +} + + +void handleCameraUpdate( Params& params ) +{ + if( !camera_changed ) + return; + camera_changed = false; + + camera.setAspectRatio( static_cast( params.width ) / static_cast( params.height ) ); + params.eye = camera.eye(); + camera.UVWFrame( params.U, params.V, params.W ); +} + + +void handleResize( sutil::CUDAOutputBuffer& output_buffer, Params& params ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + output_buffer.resize( params.width, params.height ); + + // Realloc accumulation buffer + CUDA_CHECK( cudaFree( reinterpret_cast( params.accum_buffer ) ) ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( ¶ms.accum_buffer ), + params.width*params.height*sizeof(float4) + ) ); +} + + +void updateState( sutil::CUDAOutputBuffer& output_buffer, Params& params ) +{ + // Update params on device + if( camera_changed || resize_dirty ) + params.subframe_index = 0; + + handleCameraUpdate( params ); + handleResize( output_buffer, params ); +} + + +void launchSubframe( sutil::CUDAOutputBuffer& output_buffer, SimpleMotionBlurState& state ) +{ + + // Launch + uchar4* result_buffer_data = output_buffer.map(); + state.params.frame_buffer = result_buffer_data; + CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast( state.d_params ), + &state.params, + sizeof( Params ), + cudaMemcpyHostToDevice, + state.stream + ) ); + + OPTIX_CHECK( optixLaunch( + state.pipeline, + state.stream, + reinterpret_cast( state.d_params ), + sizeof( Params ), + &state.sbt, + state.params.width, // launch width + state.params.height, // launch height + 1 // launch depth + ) ); + output_buffer.unmap(); +} + + +void displaySubframe( + sutil::CUDAOutputBuffer& output_buffer, + sutil::GLDisplay& gl_display, + GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( + output_buffer.width(), + output_buffer.height(), + framebuf_res_x, + framebuf_res_y, + output_buffer.getPBO() + ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + + +void initCameraState() +{ + camera.setEye( make_float3( 0.0f, 0.0f, 5.0f ) ); + camera.setLookat( make_float3( 0.0f, 0.0f, 0.0f ) ); + camera.setUp( make_float3( 0.0f, 1.0f, 0.0f ) ); + camera.setFovY( 35.0f ); + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( make_float3( 1.0f, 0.0f, 0.0f ), make_float3( 0.0f, 0.0f, 1.0f ), make_float3( 0.0f, 1.0f, 0.0f ) ); + trackball.setGimbalLock(true); +} + + +void createContext( SimpleMotionBlurState& state ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + + state.context = context; +} + + +void buildGAS( SimpleMotionBlurState& state ) +{ + // + // Build triangle GAS + // + { + const int NUM_KEYS = 3; + + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + accel_options.motionOptions.numKeys = NUM_KEYS; + accel_options.motionOptions.timeBegin = 0.0f; + accel_options.motionOptions.timeEnd = 1.0f; + accel_options.motionOptions.flags = OPTIX_MOTION_FLAG_NONE; + + // + // copy triangle mesh data to device + // + const int NUM_VERTS = 3; + const std::array tri_vertices = + { { + { 0.0f, 0.0f, 0.0f, 0.0f }, // + { 1.0f, 0.0f, 0.0f, 0.0f }, // Motion key 0 + { 0.5f, 1.0f, 0.0f, 0.0f }, // + + { 0.5f, 0.0f, 0.0f, 0.0f }, // + { 1.5f, 0.0f, 0.0f, 0.0f }, // Motion key 1 + { 1.0f, 1.0f, 0.0f, 0.0f }, // + + { 0.5f, -0.5f, 0.0f, 0.0f }, // + { 1.5f, -0.5f, 0.0f, 0.0f }, // Motion key 2 + { 1.0f, 0.5f, 0.0f, 0.0f }, // + + } }; + + const size_t vertices_size_in_bytes = NUM_VERTS*NUM_KEYS*sizeof( Vertex ); + CUdeviceptr d_tri_vertices; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_tri_vertices ), vertices_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_tri_vertices ), + tri_vertices.data(), + vertices_size_in_bytes, + cudaMemcpyHostToDevice + ) ); + + uint32_t triangle_input_flag = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT; + CUdeviceptr vertex_buffer_ptrs[ NUM_KEYS ]; + for( int i = 0; i < NUM_KEYS; ++i ) + vertex_buffer_ptrs[i] = d_tri_vertices + i*NUM_VERTS*sizeof(Vertex); + + + OptixBuildInput triangle_input = {}; + triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangle_input.triangleArray.vertexStrideInBytes = sizeof( Vertex ); + triangle_input.triangleArray.numVertices = NUM_VERTS; + triangle_input.triangleArray.vertexBuffers = vertex_buffer_ptrs; + triangle_input.triangleArray.flags = &triangle_input_flag; + triangle_input.triangleArray.numSbtRecords = 1; + triangle_input.triangleArray.sbtIndexOffsetBuffer = 0; + + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( + state.context, + &accel_options, + &triangle_input, + 1, // num_build_inputs + &gas_buffer_sizes + ) ); + + CUdeviceptr d_temp_buffer; + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_temp_buffer ), + gas_buffer_sizes.tempSizeInBytes + ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 + ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = (CUdeviceptr)((char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset); + + OPTIX_CHECK( optixAccelBuild( + state.context, + 0, // CUDA stream + &accel_options, + &triangle_input, + 1, // num build inputs + d_temp_buffer, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &state.tri_gas_handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + CUDA_CHECK( cudaFree( (void*)d_temp_buffer ) ); + CUDA_CHECK( cudaFree( (void*)d_tri_vertices ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, (void*)emitProperty.result, sizeof(size_t), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_tri_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, 0, state.tri_gas_handle, state.d_tri_gas_output_buffer, + compacted_gas_size, &state.tri_gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + state.d_tri_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } + } + + // + // Build sphere GAS + // + { + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + // AABB build input + OptixAabb aabb = { -1.5f, -1.0f, -0.5f, + -0.5f, 0.0f, 0.5f}; + CUdeviceptr d_aabb_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_aabb_buffer ), sizeof( OptixAabb ) ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_aabb_buffer ), + &aabb, + sizeof( OptixAabb ), + cudaMemcpyHostToDevice + ) ); + + uint32_t sphere_input_flag = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT; + OptixBuildInput sphere_input = {}; + sphere_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES; + sphere_input.customPrimitiveArray.aabbBuffers = &d_aabb_buffer; + sphere_input.customPrimitiveArray.numPrimitives = 1; + sphere_input.customPrimitiveArray.flags = &sphere_input_flag; + sphere_input.customPrimitiveArray.numSbtRecords = 1; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( state.context, &accel_options, &sphere_input, + 1, // num_build_inputs + &gas_buffer_sizes ) ); + + CUdeviceptr d_temp_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 + ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( (char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( state.context, + 0, // CUDA stream + &accel_options, + &sphere_input, + 1, // num build inputs + d_temp_buffer, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &state.sphere_gas_handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_aabb_buffer ) ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, (void*)emitProperty.result, sizeof(size_t), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_sphere_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, 0, state.sphere_gas_handle, state.d_sphere_gas_output_buffer, + compacted_gas_size, &state.sphere_gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + state.d_sphere_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } + + { + const float motion_matrix_keys[2][12] = + { + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f + }, + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.5f, + 0.0f, 0.0f, 1.0f, 0.0f + } + }; + + OptixMatrixMotionTransform motion_transform = {}; + motion_transform.child = state.sphere_gas_handle; + motion_transform.motionOptions.numKeys = 2; + motion_transform.motionOptions.timeBegin = 0.0f; + motion_transform.motionOptions.timeEnd = 1.0f; + motion_transform.motionOptions.flags = OPTIX_MOTION_FLAG_NONE; + memcpy( motion_transform.transform, motion_matrix_keys, 2 * 12 * sizeof( float ) ); + + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &state.d_sphere_motion_transform), + sizeof( OptixMatrixMotionTransform ) + ) ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( state.d_sphere_motion_transform ), + &motion_transform, + sizeof( OptixMatrixMotionTransform ), + cudaMemcpyHostToDevice + ) ); + + OPTIX_CHECK( optixConvertPointerToTraversableHandle( + state.context, + state.d_sphere_motion_transform, + OPTIX_TRAVERSABLE_TYPE_MATRIX_MOTION_TRANSFORM, + &state.sphere_motion_transform_handle + ) ); + } + } +} + + +void buildInstanceAccel( SimpleMotionBlurState& state ) +{ + Instance instance = { {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 } }; + + const size_t instance_size_in_bytes = sizeof( OptixInstance ) * InstanceType::COUNT; + OptixInstance optix_instances[ InstanceType::COUNT ]; + memset( optix_instances, 0, instance_size_in_bytes ); + + optix_instances[InstanceType::SPHERE].flags = OPTIX_INSTANCE_FLAG_NONE; + optix_instances[InstanceType::SPHERE].instanceId = 1; + optix_instances[InstanceType::SPHERE].sbtOffset = 0; + optix_instances[InstanceType::SPHERE].visibilityMask = 1; + optix_instances[InstanceType::SPHERE].traversableHandle = state.sphere_motion_transform_handle; + memcpy( optix_instances[InstanceType::SPHERE].transform, instance.transform, sizeof( float ) * 12 ); + + optix_instances[InstanceType::TRI].flags = OPTIX_INSTANCE_FLAG_NONE; + optix_instances[InstanceType::TRI].instanceId = 0; + optix_instances[InstanceType::TRI].sbtOffset = 1; // Prefix sum of previous instance numSBT records + optix_instances[InstanceType::TRI].visibilityMask = 1; + optix_instances[InstanceType::TRI].traversableHandle = state.tri_gas_handle; + memcpy( optix_instances[InstanceType::TRI].transform, instance.transform, sizeof( float ) * 12 ); + + CUdeviceptr d_instances; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_instances ), instance_size_in_bytes) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_instances ), + optix_instances, + instance_size_in_bytes, + cudaMemcpyHostToDevice + ) ); + + OptixBuildInput instance_input = {}; + instance_input.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; + instance_input.instanceArray.instances = d_instances; + instance_input.instanceArray.numInstances = InstanceType::COUNT; + + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_NONE; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + accel_options.motionOptions.numKeys = 2; + accel_options.motionOptions.timeBegin = 0.0f; + accel_options.motionOptions.timeEnd = 1.0f; + accel_options.motionOptions.flags = OPTIX_MOTION_FLAG_NONE; + + OptixAccelBufferSizes ias_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( + state.context, + &accel_options, + &instance_input, + 1, // num build inputs + &ias_buffer_sizes + ) ); + + CUdeviceptr d_temp_buffer; + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_temp_buffer ), + ias_buffer_sizes.tempSizeInBytes + ) ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &state.d_ias_output_buffer ), + ias_buffer_sizes.outputSizeInBytes + ) ); + + OPTIX_CHECK( optixAccelBuild( + state.context, + 0, // CUDA stream + &accel_options, + &instance_input, + 1, // num build inputs + d_temp_buffer, + ias_buffer_sizes.tempSizeInBytes, + state.d_ias_output_buffer, + ias_buffer_sizes.outputSizeInBytes, + &state.ias_handle, + nullptr, // emitted property list + 0 // num emitted properties + ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_instances ) ) ); +} + + +void createModule( SimpleMotionBlurState& state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + state.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_ANY; // IMPORTANT: if not set to 'ANY', instance traversables will not work + state.pipeline_compile_options.numPayloadValues = 3; + state.pipeline_compile_options.numAttributeValues = 3; + state.pipeline_compile_options.usesMotionBlur = true; + state.pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; // should be OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW; + state.pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixSimpleMotionBlur.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( + state.context, + &module_compile_options, + &state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &state.ptx_module + ) ); +} + + +void createProgramGroups( SimpleMotionBlurState& state ) +{ + OptixProgramGroupOptions program_group_options = {}; + + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = state.ptx_module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.raygen_prog_group + ) + ); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.ptx_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__camera"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.miss_group + ) + ); + + OptixProgramGroupDesc hit_prog_group_desc = {}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = state.ptx_module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__camera"; + OPTIX_CHECK_LOG( + optixProgramGroupCreate( + state.context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.tri_hit_group + ) + ); + + hit_prog_group_desc.hitgroup.moduleIS = state.ptx_module; + hit_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__sphere"; + OPTIX_CHECK_LOG( + optixProgramGroupCreate( + state.context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &state.sphere_hit_group + ) + ); +} + + +void createPipeline( SimpleMotionBlurState& state ) +{ + OptixProgramGroup program_groups[] = + { + state.raygen_prog_group, + state.miss_group, + state.sphere_hit_group, + state.tri_hit_group + }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = 2; + + OPTIX_CHECK_LOG( optixPipelineCreate( + state.context, + &state.pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &state.pipeline + ) ); + + // We need to specify the max traversal depth. Calculate the stack sizes, so we can specify all + // parameters to optixPipelineSetStackSize. + OptixStackSizes stackSizes = {}; + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.raygen_prog_group, &stackSizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.miss_group, &stackSizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.sphere_hit_group, &stackSizes, state.pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( state.tri_hit_group, &stackSizes, state.pipeline ) ); + + unsigned int maxTraceDepth = 1; + unsigned int maxCCDepth = 0; + unsigned int maxDCDepth = 0; + unsigned int directCallableStackSizeFromTraversal; + unsigned int directCallableStackSizeFromState; + unsigned int continuationStackSize; + OPTIX_CHECK( optixUtilComputeStackSizes( + &stackSizes, + maxTraceDepth, + maxCCDepth, + maxDCDepth, + &directCallableStackSizeFromTraversal, + &directCallableStackSizeFromState, + &continuationStackSize + ) ); + + // This is 3 since the largest depth is IAS->MT->GAS + unsigned int maxTraversalDepth = 3; + + OPTIX_CHECK( optixPipelineSetStackSize( + state.pipeline, + directCallableStackSizeFromTraversal, + directCallableStackSizeFromState, + continuationStackSize, + maxTraversalDepth + ) ); +} + + +void createSBT( SimpleMotionBlurState& state ) +{ + CUdeviceptr d_raygen_record; + const size_t raygen_record_size = sizeof( RayGenRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_raygen_record ), raygen_record_size ) ); + + RayGenRecord rg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( state.raygen_prog_group, &rg_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_raygen_record ), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr d_miss_records; + const size_t miss_record_size = sizeof( MissRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_miss_records ), miss_record_size) ); + + MissRecord ms_sbt[2]; + OPTIX_CHECK( optixSbtRecordPackHeader( state.miss_group, &ms_sbt[0] ) ); + ms_sbt[0].data.color = {0.1f, 0.1f, 0.1f}; + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_miss_records ), + ms_sbt, + miss_record_size, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr d_hitgroup_records; + const size_t hitgroup_record_size = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_hitgroup_records ), + hitgroup_record_size*InstanceType::COUNT + ) ); + HitGroupRecord hitgroup_records[ InstanceType::COUNT ]; + + // + // Hit groups + // + OPTIX_CHECK( optixSbtRecordPackHeader( state.sphere_hit_group, &hitgroup_records[ InstanceType::SPHERE ] ) ); + hitgroup_records[ InstanceType::SPHERE ].data.color = make_float3( 0.9f, 0.1f, 0.1f ); + hitgroup_records[ InstanceType::SPHERE ].data.center = make_float3( -1.0f, -0.5f, 0.0f ); + hitgroup_records[ InstanceType::SPHERE ].data.radius = 0.5f; + + + OPTIX_CHECK( optixSbtRecordPackHeader( state.sphere_hit_group, &hitgroup_records[ InstanceType::SPHERE ] ) ); + OPTIX_CHECK( optixSbtRecordPackHeader( state.tri_hit_group, &hitgroup_records[ InstanceType::TRI ] ) ); + hitgroup_records[ InstanceType::TRI ].data.color = make_float3( 0.1f, 0.1f, 0.9f ); + hitgroup_records[ InstanceType::TRI ].data.center = make_float3( 0.0f ); // Not used + hitgroup_records[ InstanceType::TRI ].data.radius = 0.0f; // Not used + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_hitgroup_records ), + hitgroup_records, + hitgroup_record_size*InstanceType::COUNT, + cudaMemcpyHostToDevice + ) ); + + state.sbt.raygenRecord = d_raygen_record; + state.sbt.missRecordBase = d_miss_records; + state.sbt.missRecordStrideInBytes = static_cast( miss_record_size ); + state.sbt.missRecordCount = RAY_TYPE_COUNT; + state.sbt.hitgroupRecordBase = d_hitgroup_records; + state.sbt.hitgroupRecordStrideInBytes = static_cast( hitgroup_record_size ); + state.sbt.hitgroupRecordCount = InstanceType::COUNT; +} + + +void cleanupState( SimpleMotionBlurState& state ) +{ + OPTIX_CHECK( optixPipelineDestroy ( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.miss_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.tri_hit_group ) ); + OPTIX_CHECK( optixModuleDestroy ( state.ptx_module ) ); + OPTIX_CHECK( optixDeviceContextDestroy( state.context ) ); + + + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_tri_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_sphere_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.accum_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_params ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_ias_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_sphere_motion_transform ) ) ); +} + + +//------------------------------------------------------------------------------ +// +// Main +// +//------------------------------------------------------------------------------ + +int main( int argc, char* argv[] ) +{ + SimpleMotionBlurState state; + state.params.width = 768; + state.params.height = 768; + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::GL_INTEROP; + + // + // Parse command line options + // + std::string outfile; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--no-gl-interop" ) + { + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outfile = argv[++i]; + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + int w, h; + sutil::parseDimensions( dims_arg.c_str(), w, h ); + state.params.width = w; + state.params.height = h; + } + else if( arg == "--launch-samples" || arg == "-s" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + samples_per_launch = atoi( argv[++i] ); + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + initCameraState(); + + + // + // Set up OptiX state + // + createContext ( state ); + buildGAS ( state ); + buildInstanceAccel ( state ); + createModule ( state ); + createProgramGroups( state ); + createPipeline ( state ); + createSBT ( state ); + + initLaunchParams( state ); + + if( outfile.empty() ) + { + GLFWwindow* window = sutil::initUI( "optixSimpleMotionBlur", state.params.width, state.params.height ); + glfwSetMouseButtonCallback ( window, mouseButtonCallback ); + glfwSetCursorPosCallback ( window, cursorPosCallback ); + glfwSetWindowSizeCallback ( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback ( window, keyCallback ); + glfwSetWindowUserPointer ( window, &state.params ); + + { + // output_buffer needs to be destroyed before cleanupUI is called + sutil::CUDAOutputBuffer output_buffer( + output_buffer_type, + state.params.width, + state.params.height + ); + + output_buffer.setStream( state.stream ); + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + // + // Render loop + // + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + updateState( output_buffer, state.params ); + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + launchSubframe( output_buffer, state ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1-t0; + + sutil::displayStats(state_update_time, render_time, display_time); + + glfwSwapBuffers(window); + + ++state.params.subframe_index; + } + while( !glfwWindowShouldClose( window ) ); + } + + sutil::cleanupUI( window ); + } + else + { + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + sutil::initGLFW(); // For GL context + sutil::initGL(); + } + + { + // this scope is for output_buffer, to ensure the destructor is called bfore glfwTerminate() + + sutil::CUDAOutputBuffer output_buffer( + output_buffer_type, + state.params.width, + state.params.height + ); + + handleCameraUpdate( state.params ); + handleResize( output_buffer, state.params ); + launchSubframe( output_buffer, state ); + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + glfwTerminate(); + } + } + + cleanupState( state ); + + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixSimpleMotionBlur/optixSimpleMotionBlur.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixSimpleMotionBlur/optixSimpleMotionBlur.cu new file mode 100644 index 00000000..5e4b4480 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixSimpleMotionBlur/optixSimpleMotionBlur.cu @@ -0,0 +1,180 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include "optixSimpleMotionBlur.h" +#include "random.h" + +#include +#include + +extern "C" { +__constant__ Params params; +} + + + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +static __forceinline__ __device__ float3 traceCamera( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float ray_time + ) +{ + unsigned int r, g, b; + + optixTrace( + handle, + ray_origin, + ray_direction, + 0.0f, // tmin + 1e16f, // tmax + ray_time, + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_NONE, + RAY_TYPE_RADIANCE, // SBT offset + RAY_TYPE_COUNT, // SBT stride + RAY_TYPE_RADIANCE, // missSBTIndex + r, g, b ); + + return make_float3( + __uint_as_float( r ), + __uint_as_float( g ), + __uint_as_float( b ) + ); +} + + +static __forceinline__ __device__ void setPayload( float3 p ) +{ + optixSetPayload_0( __float_as_uint( p.x ) ); + optixSetPayload_1( __float_as_uint( p.y ) ); + optixSetPayload_2( __float_as_uint( p.z ) ); +} + +//------------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------------ + +extern "C" __global__ void __raygen__rg() +{ + const int w = params.width; + const int h = params.height; + const float3 eye = params.eye; + const float3 U = params.U; + const float3 V = params.V; + const float3 W = params.W; + const uint3 idx = optixGetLaunchIndex(); + const int subframe_index = params.subframe_index; + + unsigned int seed = tea<4>( idx.y*w + idx.x, subframe_index ); + // The center of each pixel is at fraction (0.5,0.5) + const float2 subpixel_jitter = make_float2( rnd( seed ), rnd( seed ) ); + + const float2 d = 2.0f * make_float2( + ( static_cast( idx.x ) + subpixel_jitter.x ) / static_cast( w ), + ( static_cast( idx.y ) + subpixel_jitter.y ) / static_cast( h ) + ) - 1.0f; + float3 ray_direction = normalize(d.x*U + d.y*V + W); + float3 ray_origin = eye; + + const float3 result = traceCamera( params.handle, ray_origin, ray_direction, rnd( seed ) ); + + const int image_index = idx.y*w + idx.x; + float3 accum_color = result; + if( subframe_index > 0 ) + { + const float a = 1.0f / static_cast( subframe_index+1 ); + const float3 accum_color_prev = make_float3( params.accum_buffer[ image_index ]); + accum_color = lerp( accum_color_prev, accum_color, a ); + } + params.accum_buffer[ image_index ] = make_float4( accum_color, 1.0f); + params.frame_buffer[ image_index ] = make_color ( accum_color ); +} + + +extern "C" __global__ void __miss__camera() +{ + MissData* rt_data = reinterpret_cast( optixGetSbtDataPointer() ); + setPayload( rt_data->color ); +} + + +extern "C" __global__ void __closesthit__camera() +{ + HitGroupData* rt_data = (HitGroupData*)optixGetSbtDataPointer(); + setPayload( rt_data->color ); +} + + +extern "C" __global__ void __intersection__sphere() +{ + HitGroupData* hg_data = reinterpret_cast( optixGetSbtDataPointer() ); + const float3 orig = optixGetObjectRayOrigin(); + const float3 dir = optixGetObjectRayDirection(); + + const float3 center = hg_data->center; + const float radius = hg_data->radius; + + const float3 O = orig - center; + const float l = 1 / length( dir ); + const float3 D = dir * l; + + const float b = dot( O, D ); + const float c = dot( O, O ) - radius * radius; + const float disc = b * b - c; + if( disc > 0.0f ) + { + const float sdisc = sqrtf( disc ); + const float root1 = ( -b - sdisc ); + + const float root11 = 0.0f; + const float3 shading_normal = ( O + ( root1 + root11 ) * D ) / radius; + unsigned int p0, p1, p2; + p0 = __float_as_uint( shading_normal.x ); + p1 = __float_as_uint( shading_normal.y ); + p2 = __float_as_uint( shading_normal.z ); + + optixReportIntersection( + root1, // t hit + 0, // user hit kind + p0, p1, p2 + ); + } +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixSimpleMotionBlur/optixSimpleMotionBlur.h b/Extern/3rdParty/OptiX/Linux/SDK/optixSimpleMotionBlur/optixSimpleMotionBlur.h new file mode 100644 index 00000000..8cd1c3e1 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixSimpleMotionBlur/optixSimpleMotionBlur.h @@ -0,0 +1,87 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +enum RayType +{ + RAY_TYPE_RADIANCE = 0, + RAY_TYPE_COUNT +}; + + +struct Params +{ + unsigned int width; + unsigned int height; + float4* accum_buffer; + uchar4* frame_buffer; + unsigned int subframe_index; + + float3 eye; + float3 U; + float3 V; + float3 W; + + OptixTraversableHandle handle; +}; + + +struct RayGenData +{ +}; + + +struct MissData +{ + float3 color; + unsigned int pad; +}; + + +struct SphereData +{ + float3 center; + float radius; +}; + + +struct HitGroupData +{ + float3 color; + + // For spheres. In real use case, we would have an abstraction for geom data/ material data + float3 center; + float radius; + + unsigned int pad; + +}; + + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixSphere/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixSphere/CMakeLists.txt new file mode 100644 index 00000000..aaead202 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixSphere/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixSphere target_name + optixSphere.cu + optixSphere.cpp + optixSphere.h + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixSphere/optixSphere.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixSphere/optixSphere.cpp new file mode 100644 index 00000000..2f950b94 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixSphere/optixSphere.cpp @@ -0,0 +1,493 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include "optixSphere.h" + +#include +#include +#include + +#include +#include + + + +template +struct SbtRecord +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef SbtRecord RayGenSbtRecord; +typedef SbtRecord MissSbtRecord; +typedef SbtRecord HitGroupSbtRecord; + + +void configureCamera( sutil::Camera& cam, const uint32_t width, const uint32_t height ) +{ + cam.setEye( {0.0f, 0.0f, 3.0f} ); + cam.setLookat( {0.0f, 0.0f, 0.0f} ); + cam.setUp( {0.0f, 1.0f, 3.0f} ); + cam.setFovY( 60.0f ); + cam.setAspectRatio( (float)width / (float)height ); +} + + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f Specify file for image output\n"; + std::cerr << " --help | -h Print this usage message\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 1024x768\n"; + exit( 1 ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + + +int main( int argc, char* argv[] ) +{ + std::string outfile; + int width = 1024; + int height = 768; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg( argv[i] ); + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--file" || arg == "-f" ) + { + if( i < argc - 1 ) + { + outfile = argv[++i]; + } + else + { + printUsageAndExit( argv[0] ); + } + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + sutil::parseDimensions( dims_arg.c_str(), width, height ); + } + else + { + std::cerr << "Unknown option '" << arg << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + // + // Initialize CUDA and create OptiX context + // + OptixDeviceContext context = nullptr; + { + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; +#ifndef NDEBUG + options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; +#endif + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + } + + // + // accel handling + // + OptixTraversableHandle gas_handle; + CUdeviceptr d_gas_output_buffer; + { + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION | OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + // sphere build input + + float3 sphereVertex = make_float3( 0.f, 0.f, 0.f ); + float sphereRadius = 1.5f; + + CUdeviceptr d_vertex_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_vertex_buffer ), sizeof( float3 ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_vertex_buffer ), &sphereVertex, + sizeof( float3 ), cudaMemcpyHostToDevice ) ); + + CUdeviceptr d_radius_buffer; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_radius_buffer ), sizeof( float ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_radius_buffer ), &sphereRadius, sizeof( float ), + cudaMemcpyHostToDevice ) ); + + OptixBuildInput sphere_input = {}; + + sphere_input.type = OPTIX_BUILD_INPUT_TYPE_SPHERES; + sphere_input.sphereArray.vertexBuffers = &d_vertex_buffer; + sphere_input.sphereArray.numVertices = 1; + sphere_input.sphereArray.radiusBuffers = &d_radius_buffer; + + uint32_t sphere_input_flags[1] = {OPTIX_GEOMETRY_FLAG_NONE}; + sphere_input.sphereArray.flags = sphere_input_flags; + sphere_input.sphereArray.numSbtRecords = 1; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( context, &accel_options, &sphere_input, 1, &gas_buffer_sizes ) ); + CUdeviceptr d_temp_buffer_gas; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer_gas ), gas_buffer_sizes.tempSizeInBytes ) ); + + // non-compacted output + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = ( CUdeviceptr )( (char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset ); + + OPTIX_CHECK( optixAccelBuild( context, + 0, // CUDA stream + &accel_options, &sphere_input, + 1, // num build inputs + d_temp_buffer_gas, gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, gas_buffer_sizes.outputSizeInBytes, &gas_handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + d_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + + CUDA_CHECK( cudaFree( (void*)d_temp_buffer_gas ) ); + CUDA_CHECK( cudaFree( (void*)d_vertex_buffer ) ); + CUDA_CHECK( cudaFree( (void*)d_radius_buffer ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, (void*)emitProperty.result, sizeof( size_t ), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( context, 0, gas_handle, d_gas_output_buffer, compacted_gas_size, &gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + d_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } + } + + // + // Create module + // + OptixModule module = nullptr; + OptixModule sphere_module = nullptr; + OptixPipelineCompileOptions pipeline_compile_options = {}; + { + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + pipeline_compile_options.usesMotionBlur = false; + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + pipeline_compile_options.numPayloadValues = 3; + pipeline_compile_options.numAttributeValues = 1; + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_SPHERE; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixSphere.cu", inputSize ); + + OPTIX_CHECK_LOG( optixModuleCreate( context, &module_compile_options, &pipeline_compile_options, input, + inputSize, LOG, &LOG_SIZE, &module ) ); + + OptixBuiltinISOptions builtin_is_options = {}; + + builtin_is_options.usesMotionBlur = false; + builtin_is_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_SPHERE; + OPTIX_CHECK_LOG( optixBuiltinISModuleGet( context, &module_compile_options, &pipeline_compile_options, + &builtin_is_options, &sphere_module ) ); + } + + // + // Create program groups + // + OptixProgramGroup raygen_prog_group = nullptr; + OptixProgramGroup miss_prog_group = nullptr; + OptixProgramGroup hitgroup_prog_group = nullptr; + { + OptixProgramGroupOptions program_group_options = {}; // Initialize to zeros + + OptixProgramGroupDesc raygen_prog_group_desc = {}; // + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &raygen_prog_group + ) ); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__ms"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &miss_prog_group + ) ); + + OptixProgramGroupDesc hitgroup_prog_group_desc = {}; + hitgroup_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hitgroup_prog_group_desc.hitgroup.moduleCH = module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__ch"; + hitgroup_prog_group_desc.hitgroup.moduleAH = nullptr; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + hitgroup_prog_group_desc.hitgroup.moduleIS = sphere_module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameIS = nullptr; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &hitgroup_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &hitgroup_prog_group + ) ); + } + + // + // Link pipeline + // + OptixPipeline pipeline = nullptr; + { + const uint32_t max_trace_depth = 1; + OptixProgramGroup program_groups[] = { raygen_prog_group, miss_prog_group, hitgroup_prog_group }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + OPTIX_CHECK_LOG( optixPipelineCreate( + context, + &pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &pipeline + ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + ) ); + } + + // + // Set up shader binding table + // + OptixShaderBindingTable sbt = {}; + { + CUdeviceptr raygen_record; + const size_t raygen_record_size = sizeof( RayGenSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &raygen_record ), raygen_record_size ) ); + sutil::Camera cam; + configureCamera( cam, width, height ); + RayGenSbtRecord rg_sbt; + rg_sbt.data ={}; + rg_sbt.data.cam_eye = cam.eye(); + cam.UVWFrame( rg_sbt.data.camera_u, rg_sbt.data.camera_v, rg_sbt.data.camera_w ); + OPTIX_CHECK( optixSbtRecordPackHeader( raygen_prog_group, &rg_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( raygen_record ), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr miss_record; + size_t miss_record_size = sizeof( MissSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &miss_record ), miss_record_size ) ); + MissSbtRecord ms_sbt; + ms_sbt.data = { 0.3f, 0.1f, 0.2f }; + OPTIX_CHECK( optixSbtRecordPackHeader( miss_prog_group, &ms_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( miss_record ), + &ms_sbt, + miss_record_size, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr hitgroup_record; + size_t hitgroup_record_size = sizeof( HitGroupSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &hitgroup_record ), hitgroup_record_size ) ); + HitGroupSbtRecord hg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( hitgroup_prog_group, &hg_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( hitgroup_record ), + &hg_sbt, + hitgroup_record_size, + cudaMemcpyHostToDevice + ) ); + + sbt.raygenRecord = raygen_record; + sbt.missRecordBase = miss_record; + sbt.missRecordStrideInBytes = sizeof( MissSbtRecord ); + sbt.missRecordCount = 1; + sbt.hitgroupRecordBase = hitgroup_record; + sbt.hitgroupRecordStrideInBytes = sizeof( HitGroupSbtRecord ); + sbt.hitgroupRecordCount = 1; + } + + sutil::CUDAOutputBuffer output_buffer( sutil::CUDAOutputBufferType::CUDA_DEVICE, width, height ); + + // + // launch + // + { + CUstream stream; + CUDA_CHECK( cudaStreamCreate( &stream ) ); + + Params params; + params.image = output_buffer.map(); + params.image_width = width; + params.image_height = height; + params.origin_x = width / 2; + params.origin_y = height / 2; + params.handle = gas_handle; + + CUdeviceptr d_param; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_param ), sizeof( Params ) ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_param ), + ¶ms, sizeof( params ), + cudaMemcpyHostToDevice + ) ); + + OPTIX_CHECK( optixLaunch( pipeline, stream, d_param, sizeof( Params ), &sbt, width, height, /*depth=*/1 ) ); + CUDA_SYNC_CHECK(); + + output_buffer.unmap(); + CUDA_CHECK( cudaFree( reinterpret_cast( d_param ) ) ); + } + + // + // Display results + // + { + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = width; + buffer.height = height; + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + if( outfile.empty() ) + sutil::displayBufferWindow( argv[0], buffer ); + else + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + // + // Cleanup + // + { + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_gas_output_buffer ) ) ); + + OPTIX_CHECK( optixPipelineDestroy( pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( hitgroup_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( miss_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( raygen_prog_group ) ); + OPTIX_CHECK( optixModuleDestroy( module ) ); + OPTIX_CHECK( optixModuleDestroy( sphere_module ) ); + + OPTIX_CHECK( optixDeviceContextDestroy( context ) ); + } + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixSphere/optixSphere.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixSphere/optixSphere.cu new file mode 100644 index 00000000..beaf05ab --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixSphere/optixSphere.cu @@ -0,0 +1,154 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "optixSphere.h" +#include + +#include + +extern "C" { +__constant__ Params params; +} + +constexpr unsigned int SBT_STRIDE_COLLAPSE = 0; + +static __forceinline__ __device__ void trace( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax, + float3* prd + ) +{ + unsigned int p0, p1, p2; + p0 = __float_as_uint( prd->x ); + p1 = __float_as_uint( prd->y ); + p2 = __float_as_uint( prd->z ); + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + OptixVisibilityMask( 1 ), + OPTIX_RAY_FLAG_NONE, + 0, // SBT offset + SBT_STRIDE_COLLAPSE, // SBT stride + 0, // missSBTIndex + p0, p1, p2 ); + prd->x = __uint_as_float( p0 ); + prd->y = __uint_as_float( p1 ); + prd->z = __uint_as_float( p2 ); +} + + +static __forceinline__ __device__ void setPayload( float3 p ) +{ + optixSetPayload_0( __float_as_uint( p.x ) ); + optixSetPayload_1( __float_as_uint( p.y ) ); + optixSetPayload_2( __float_as_uint( p.z ) ); +} + + +static __forceinline__ __device__ float3 getPayload() +{ + return make_float3( + __uint_as_float( optixGetPayload_0() ), + __uint_as_float( optixGetPayload_1() ), + __uint_as_float( optixGetPayload_2() ) + ); +} + + +extern "C" __global__ void __raygen__rg() +{ + const uint3 idx = optixGetLaunchIndex(); + const uint3 dim = optixGetLaunchDimensions(); + + const RayGenData* rtData = (RayGenData*)optixGetSbtDataPointer(); + const float3 U = rtData->camera_u; + const float3 V = rtData->camera_v; + const float3 W = rtData->camera_w; + const float2 d = 2.0f * make_float2( + static_cast( idx.x ) / static_cast( dim.x ), + static_cast( idx.y ) / static_cast( dim.y ) + ) - 1.0f; + + const float3 origin = rtData->cam_eye; + const float3 direction = normalize( d.x * U + d.y * V + W ); + float3 payload_rgb = make_float3( 0.5f, 0.5f, 0.5f ); + trace( params.handle, + origin, + direction, + 0.00f, // tmin + 1e16f, // tmax + &payload_rgb ); + + params.image[idx.y * params.image_width + idx.x] = make_color( payload_rgb ); +} + + +extern "C" __global__ void __miss__ms() +{ + MissData* rt_data = reinterpret_cast( optixGetSbtDataPointer() ); + float3 payload = getPayload(); + setPayload( make_float3( rt_data->r, rt_data->g, rt_data->b ) ); +} + + +extern "C" __global__ void __closesthit__ch() +{ + float t_hit = optixGetRayTmax(); + // Backface hit not used. + //float t_hit2 = __uint_as_float( optixGetAttribute_0() ); + + const float3 ray_orig = optixGetWorldRayOrigin(); + const float3 ray_dir = optixGetWorldRayDirection(); + + const unsigned int prim_idx = optixGetPrimitiveIndex(); + const OptixTraversableHandle gas = optixGetGASTraversableHandle(); + const unsigned int sbtGASIndex = optixGetSbtGASIndex(); + + float4 q; + // sphere center (q.x, q.y, q.z), sphere radius q.w + optixGetSphereData( gas, prim_idx, sbtGASIndex, 0.f, &q ); + + float3 world_raypos = ray_orig + t_hit * ray_dir; + float3 obj_raypos = optixTransformPointFromWorldToObjectSpace( world_raypos ); + float3 obj_normal = ( obj_raypos - make_float3( q ) ) / q.w; + float3 world_normal = normalize( optixTransformNormalFromObjectToWorldSpace( obj_normal ) ); + + setPayload( world_normal * 0.5f + 0.5f ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixSphere/optixSphere.h b/Extern/3rdParty/OptiX/Linux/SDK/optixSphere/optixSphere.h new file mode 100644 index 00000000..0777e7a7 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixSphere/optixSphere.h @@ -0,0 +1,59 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +struct Params +{ + uchar4* image; + unsigned int image_width; + unsigned int image_height; + int origin_x; + int origin_y; + OptixTraversableHandle handle; +}; + + +struct RayGenData +{ + float3 cam_eye; + float3 camera_u, camera_v, camera_w; +}; + + +struct MissData +{ + float r, g, b; +}; + + +struct HitGroupData +{ + // No data needed +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixTriangle/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixTriangle/CMakeLists.txt new file mode 100644 index 00000000..d0c151fe --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixTriangle/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixTriangle target_name + optixTriangle.cu + optixTriangle.cpp + optixTriangle.h + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixTriangle/optixTriangle.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixTriangle/optixTriangle.cpp new file mode 100644 index 00000000..04e316b8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixTriangle/optixTriangle.cpp @@ -0,0 +1,488 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include "optixTriangle.h" + +#include +#include +#include +#include + +#include +#include + + + +template +struct SbtRecord +{ + __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef SbtRecord RayGenSbtRecord; +typedef SbtRecord MissSbtRecord; +typedef SbtRecord HitGroupSbtRecord; + + +void configureCamera( sutil::Camera& cam, const uint32_t width, const uint32_t height ) +{ + cam.setEye( {0.0f, 0.0f, 2.0f} ); + cam.setLookat( {0.0f, 0.0f, 0.0f} ); + cam.setUp( {0.0f, 1.0f, 3.0f} ); + cam.setFovY( 45.0f ); + cam.setAspectRatio( (float)width / (float)height ); +} + + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f Specify file for image output\n"; + std::cerr << " --help | -h Print this usage message\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 512x384\n"; + exit( 1 ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + + +int main( int argc, char* argv[] ) +{ + std::string outfile; + int width = 1024; + int height = 768; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg( argv[i] ); + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--file" || arg == "-f" ) + { + if( i < argc - 1 ) + { + outfile = argv[++i]; + } + else + { + printUsageAndExit( argv[0] ); + } + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + sutil::parseDimensions( dims_arg.c_str(), width, height ); + } + else + { + std::cerr << "Unknown option '" << arg << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + // + // Initialize CUDA and create OptiX context + // + OptixDeviceContext context = nullptr; + { + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + // Initialize the OptiX API, loading all API entry points + OPTIX_CHECK( optixInit() ); + + // Specify context options + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; +#ifdef DEBUG + // This may incur significant performance cost and should only be done during development. + options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; +#endif + + // Associate a CUDA context (and therefore a specific GPU) with this + // device context + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + } + + + // + // accel handling + // + OptixTraversableHandle gas_handle; + CUdeviceptr d_gas_output_buffer; + { + // Use default options for simplicity. In a real use case we would want to + // enable compaction, etc + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_NONE; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + // Triangle build input: simple list of three vertices + const std::array vertices = + { { + { -0.5f, -0.5f, 0.0f }, + { 0.5f, -0.5f, 0.0f }, + { 0.0f, 0.5f, 0.0f } + } }; + + const size_t vertices_size = sizeof( float3 )*vertices.size(); + CUdeviceptr d_vertices=0; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_vertices ), vertices_size ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_vertices ), + vertices.data(), + vertices_size, + cudaMemcpyHostToDevice + ) ); + + // Our build input is a simple list of non-indexed triangle vertices + const uint32_t triangle_input_flags[1] = { OPTIX_GEOMETRY_FLAG_NONE }; + OptixBuildInput triangle_input = {}; + triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangle_input.triangleArray.numVertices = static_cast( vertices.size() ); + triangle_input.triangleArray.vertexBuffers = &d_vertices; + triangle_input.triangleArray.flags = triangle_input_flags; + triangle_input.triangleArray.numSbtRecords = 1; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( + context, + &accel_options, + &triangle_input, + 1, // Number of build inputs + &gas_buffer_sizes + ) ); + CUdeviceptr d_temp_buffer_gas; + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_temp_buffer_gas ), + gas_buffer_sizes.tempSizeInBytes + ) ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_gas_output_buffer ), + gas_buffer_sizes.outputSizeInBytes + ) ); + + OPTIX_CHECK( optixAccelBuild( + context, + 0, // CUDA stream + &accel_options, + &triangle_input, + 1, // num build inputs + d_temp_buffer_gas, + gas_buffer_sizes.tempSizeInBytes, + d_gas_output_buffer, + gas_buffer_sizes.outputSizeInBytes, + &gas_handle, + nullptr, // emitted property list + 0 // num emitted properties + ) ); + + // We can now free the scratch space buffer used during build and the vertex + // inputs, since they are not needed by our trivial shading method + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer_gas ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_vertices ) ) ); + } + + // + // Create module + // + OptixModule module = nullptr; + OptixPipelineCompileOptions pipeline_compile_options = {}; + { + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + pipeline_compile_options.usesMotionBlur = false; + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + pipeline_compile_options.numPayloadValues = 3; + pipeline_compile_options.numAttributeValues = 3; + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE; + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixTriangle.cu", inputSize ); + + OPTIX_CHECK_LOG( optixModuleCreate( + context, + &module_compile_options, + &pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &module + ) ); + } + + // + // Create program groups + // + OptixProgramGroup raygen_prog_group = nullptr; + OptixProgramGroup miss_prog_group = nullptr; + OptixProgramGroup hitgroup_prog_group = nullptr; + { + OptixProgramGroupOptions program_group_options = {}; // Initialize to zeros + + OptixProgramGroupDesc raygen_prog_group_desc = {}; // + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &raygen_prog_group + ) ); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__ms"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &miss_prog_group + ) ); + + OptixProgramGroupDesc hitgroup_prog_group_desc = {}; + hitgroup_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hitgroup_prog_group_desc.hitgroup.moduleCH = module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__ch"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &hitgroup_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &hitgroup_prog_group + ) ); + } + + // + // Link pipeline + // + OptixPipeline pipeline = nullptr; + { + const uint32_t max_trace_depth = 1; + OptixProgramGroup program_groups[] = { raygen_prog_group, miss_prog_group, hitgroup_prog_group }; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + OPTIX_CHECK_LOG( optixPipelineCreate( + context, + &pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof( program_groups ) / sizeof( program_groups[0] ), + LOG, &LOG_SIZE, + &pipeline + ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + ) ); + } + + // + // Set up shader binding table + // + OptixShaderBindingTable sbt = {}; + { + CUdeviceptr raygen_record; + const size_t raygen_record_size = sizeof( RayGenSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &raygen_record ), raygen_record_size ) ); + RayGenSbtRecord rg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( raygen_prog_group, &rg_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( raygen_record ), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr miss_record; + size_t miss_record_size = sizeof( MissSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &miss_record ), miss_record_size ) ); + MissSbtRecord ms_sbt; + ms_sbt.data = { 0.3f, 0.1f, 0.2f }; + OPTIX_CHECK( optixSbtRecordPackHeader( miss_prog_group, &ms_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( miss_record ), + &ms_sbt, + miss_record_size, + cudaMemcpyHostToDevice + ) ); + + CUdeviceptr hitgroup_record; + size_t hitgroup_record_size = sizeof( HitGroupSbtRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &hitgroup_record ), hitgroup_record_size ) ); + HitGroupSbtRecord hg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( hitgroup_prog_group, &hg_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( hitgroup_record ), + &hg_sbt, + hitgroup_record_size, + cudaMemcpyHostToDevice + ) ); + + sbt.raygenRecord = raygen_record; + sbt.missRecordBase = miss_record; + sbt.missRecordStrideInBytes = sizeof( MissSbtRecord ); + sbt.missRecordCount = 1; + sbt.hitgroupRecordBase = hitgroup_record; + sbt.hitgroupRecordStrideInBytes = sizeof( HitGroupSbtRecord ); + sbt.hitgroupRecordCount = 1; + } + + sutil::CUDAOutputBuffer output_buffer( sutil::CUDAOutputBufferType::CUDA_DEVICE, width, height ); + + // + // launch + // + { + CUstream stream; + CUDA_CHECK( cudaStreamCreate( &stream ) ); + + sutil::Camera cam; + configureCamera( cam, width, height ); + + Params params; + params.image = output_buffer.map(); + params.image_width = width; + params.image_height = height; + params.handle = gas_handle; + params.cam_eye = cam.eye(); + cam.UVWFrame( params.cam_u, params.cam_v, params.cam_w ); + + CUdeviceptr d_param; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_param ), sizeof( Params ) ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_param ), + ¶ms, sizeof( params ), + cudaMemcpyHostToDevice + ) ); + + OPTIX_CHECK( optixLaunch( pipeline, stream, d_param, sizeof( Params ), &sbt, width, height, /*depth=*/1 ) ); + CUDA_SYNC_CHECK(); + + output_buffer.unmap(); + CUDA_CHECK( cudaFree( reinterpret_cast( d_param ) ) ); + } + + // + // Display results + // + { + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = width; + buffer.height = height; + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + if( outfile.empty() ) + sutil::displayBufferWindow( argv[0], buffer ); + else + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + // + // Cleanup + // + { + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_gas_output_buffer ) ) ); + + OPTIX_CHECK( optixPipelineDestroy( pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy( hitgroup_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( miss_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy( raygen_prog_group ) ); + OPTIX_CHECK( optixModuleDestroy( module ) ); + + OPTIX_CHECK( optixDeviceContextDestroy( context ) ); + } + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixTriangle/optixTriangle.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixTriangle/optixTriangle.cu new file mode 100644 index 00000000..cf584847 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixTriangle/optixTriangle.cu @@ -0,0 +1,117 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "optixTriangle.h" +#include + +#include + +extern "C" { +__constant__ Params params; +} + + +static __forceinline__ __device__ void setPayload( float3 p ) +{ + optixSetPayload_0( __float_as_uint( p.x ) ); + optixSetPayload_1( __float_as_uint( p.y ) ); + optixSetPayload_2( __float_as_uint( p.z ) ); +} + + +static __forceinline__ __device__ void computeRay( uint3 idx, uint3 dim, float3& origin, float3& direction ) +{ + const float3 U = params.cam_u; + const float3 V = params.cam_v; + const float3 W = params.cam_w; + const float2 d = 2.0f * make_float2( + static_cast( idx.x ) / static_cast( dim.x ), + static_cast( idx.y ) / static_cast( dim.y ) + ) - 1.0f; + + origin = params.cam_eye; + direction = normalize( d.x * U + d.y * V + W ); +} + + +extern "C" __global__ void __raygen__rg() +{ + // Lookup our location within the launch grid + const uint3 idx = optixGetLaunchIndex(); + const uint3 dim = optixGetLaunchDimensions(); + + // Map our launch idx to a screen location and create a ray from the camera + // location through the screen + float3 ray_origin, ray_direction; + computeRay( idx, dim, ray_origin, ray_direction ); + + // Trace the ray against our scene hierarchy + unsigned int p0, p1, p2; + optixTrace( + params.handle, + ray_origin, + ray_direction, + 0.0f, // Min intersection distance + 1e16f, // Max intersection distance + 0.0f, // rayTime -- used for motion blur + OptixVisibilityMask( 255 ), // Specify always visible + OPTIX_RAY_FLAG_NONE, + 0, // SBT offset -- See SBT discussion + RAY_TYPE_COUNT, // SBT stride -- See SBT discussion + 0, // missSBTIndex -- See SBT discussion + p0, p1, p2 ); + float3 result; + result.x = __uint_as_float( p0 ); + result.y = __uint_as_float( p1 ); + result.z = __uint_as_float( p2 ); + + // Record results in our output raster + params.image[idx.y * params.image_width + idx.x] = make_color( result ); +} + + +extern "C" __global__ void __miss__ms() +{ + MissData* miss_data = reinterpret_cast( optixGetSbtDataPointer() ); + setPayload( miss_data->bg_color ); +} + + +extern "C" __global__ void __closesthit__ch() +{ + // When built-in triangle intersection is used, a number of fundamental + // attributes are provided by the OptiX API, indlucing barycentric coordinates. + const float2 barycentrics = optixGetTriangleBarycentrics(); + + setPayload( make_float3( barycentrics, 1.0f ) ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixTriangle/optixTriangle.h b/Extern/3rdParty/OptiX/Linux/SDK/optixTriangle/optixTriangle.h new file mode 100644 index 00000000..f75ed52a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixTriangle/optixTriangle.h @@ -0,0 +1,65 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +enum RayType +{ + RAY_TYPE_RADIANCE = 0, + RAY_TYPE_COUNT +}; + +struct Params +{ + uchar4* image; + unsigned int image_width; + unsigned int image_height; + float3 cam_eye; + float3 cam_u, cam_v, cam_w; + OptixTraversableHandle handle; +}; + + +struct RayGenData +{ + // No data needed +}; + + +struct MissData +{ + float3 bg_color; +}; + + +struct HitGroupData +{ + // No data needed +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/CMakeLists.txt new file mode 100644 index 00000000..4f8a2d6d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/CMakeLists.txt @@ -0,0 +1,52 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${SAMPLES_DIR}/lib/NanoVDB/include/) + +OPTIX_add_sample_executable( optixVolumeViewer target_name + optixVolumeViewer.h + optixVolumeViewer.cpp + volume.h + volume_cuda.h + volume.cu + + nanovdb/NanoVDB.h + nanovdb/util/GridHandle.h + nanovdb/util/HDDA.h + nanovdb/util/HostBuffer.h + nanovdb/util/IO.h + nanovdb/util/Ray.h + + OPTIONS -rdc true + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/LICENSE.TXT b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/LICENSE.TXT new file mode 100644 index 00000000..f4bbcd20 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/LICENSE.TXT @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. \ No newline at end of file diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/NanoVDB.h b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/NanoVDB.h new file mode 100644 index 00000000..533a20b8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/NanoVDB.h @@ -0,0 +1,3909 @@ +// Copyright Contributors to the OpenVDB Project +// SPDX-License-Identifier: MPL-2.0 + +/*! + \file NanoVDB.h + + \author Ken Museth + + \date January 8, 2020 + + \brief Implements a light-weight self-contained VDB data-structure in a + single file! In other words, this is a significantly watered-down + version of the OpenVDB implementation, with few dependencies - so + a one-stop-shop for a minimalistic VDB data structure that run on + most platforms! + + \note It is important to note that NanoVDB (by design) is a read-only + sparse GPU (and CPU) friendly data structure intended for applications + like rendering and collision detection. As such it obviously lacks + a lot of the functionality and features of OpenVDB grids. NanoVDB + is essentially a compact linearized (or serialized) representation of + an OpenVDB tree with getValue methods only. For best performance use + the ReadAccessor::getValue method as opposed to the Tree::getValue + method. Note that since a ReadAccessor caches previous access patterns + it is by design not thread-safe, so use one instantiation per thread + (it is very light-weight). Also, it is not safe to copy accessors between + the GPU and CPU! In fact, client code should only interface + with the API of the Grid class (all other nodes of the NanoVDB data + structure can safely be ignored by most client codes)! + + + \warning NanoVDB grids can only be constructed via tools like openToNanoVDB + or the GridBuilder. This explains why none of the grid nodes defined below + have public constructors or destructors. + + \details Please see the following paper for more details on the data structure: + K. Museth, �VDB: High-Resolution Sparse Volumes with Dynamic Topology�, + ACM Transactions on Graphics 32(3), 2013, which can be found here: + http://www.museth.org/Ken/Publications_files/Museth_TOG13.pdf + + + Overview: This file implements the following fundamental class that when combined + forms the backbone of the VDB tree data structure: + + Coord- a signed integer coordinate + Vec3 - a 3D vector + Vec4 - a 4D vector + BBox - a bounding box + Mask - a bitmask essential to the non-root tree nodes + Map - an affine coordinate transformation + Grid - contains a Tree and a map for world<->index transformations. Use + this class as the main API with client code! + Tree - contains a RootNode and getValue methods that should only be used for debugging + RootNode - the top-level node of the VDB data structure + InternalNode - the internal nodes of the VDB data structure + LeafNode - the lowest level tree nodes that encode voxel values and state + ReadAccessor - implements accelerated random access operations + + Semantics: A VDB data structure encodes values and (binary) states associated with + signed integer coordinates. Values encoded at the leaf node level are + denoted voxel values, and values associated with other tree nodes are referred + to as tile values, which by design cover a larger coordinate index domain. + + + Memory layout: + + GridData: 672 bytes (e.g. magic, checksum, major, flags, world bbox, grid name, and affine transformation) + + TreeData: 64 bytes (node counts and byte offsets) + + ... optional padding ... + + RootData: size depends on ValueType (index bbox, voxel count, tile count, min/max/avg/standard deviation) + + Array of: RootData::Tile + + ... optional padding ... + + Array of: Upper InternalNodes of size 32^3: bbox, two bit masks, 32768 tile values, and min/max/avg/standard deviation values + + ... optional padding ... + + Array of: Lower InternalNodes of size 16^3: bbox, two bit masks, 4096 tile values, and min/max/avg/standard deviation values + + ... optional padding ... + + Array of: LeafNodes of size 8^3: bbox, bit masks, 512 voxel values, and min/max/avg/standard deviation values + + + Example layout: ("---" implies it has a custom offset, "..." implies zero or more) + [GridData(672B)][TreeData(64B)]---[RootData][N x Root::Tile]---[NodeData<5>]---[ModeData<4>]---[LeafData<3>]---[BLINDMETA...]---[BLIND0]---[BLIND1]---etc. + +*/ + +#ifndef NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED +#define NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED + +#define NANOVDB_MAGIC_NUMBER 0x304244566f6e614eUL // "NanoVDB0" in hex - little endian (uint64_t) + +#define NANOVDB_MAJOR_VERSION_NUMBER 29 // reflects changes to the ABI +#define NANOVDB_MINOR_VERSION_NUMBER 0 // reflects changes to the API but not ABI +#define NANOVDB_PATCH_VERSION_NUMBER 0 // reflects bug-fixes with no ABI or API changes + +// This replaces a Coord key at the root level with a single uint64_t +#define USE_SINGLE_ROOT_KEY + +// This replaces three levels of Coord keys in the ReadAccessor with one Coord +#define USE_SINGLE_ACCESSOR_KEY + +#define NANOVDB_DATA_ALIGNMENT 32 + +#if !defined(NANOVDB_ALIGN) +#define NANOVDB_ALIGN(n) alignas(n) +#endif // !defined(NANOVDB_ALIGN) + +#ifdef __CUDACC_RTC__ + +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +#ifndef UINT64_C +#define UINT64_C(value) value##ULL +#endif + +#else // __CUDACC_RTC__ + +#include // for abs in clang7 +#include // for types like int32_t etc +#include // for size_t type +#include // for assert +#include // for sprinf +#include // for sqrt and fma +#include // for numeric_limits + +#if defined(NANOVDB_USE_INTRINSICS) && defined(_MSC_VER) +#include +#pragma intrinsic(_BitScanReverse) +#pragma intrinsic(_BitScanForward) +#pragma intrinsic(_BitScanReverse64) +#pragma intrinsic(_BitScanForward64) +#endif + +#endif // __CUDACC_RTC__ + +#ifdef __CUDACC__ +// Only define __hostdev__ when using NVIDIA CUDA compiler +#define __hostdev__ __host__ __device__ +#else +#define __hostdev__ +#endif + +namespace nanovdb { + +/// @brief C++11 implementation of std::is_same +template +struct is_same +{ + static const bool value = false; +}; + +template +struct is_same +{ + static const bool value = true; +}; + +/// @brief C++11 implementation of std::is_floating_point +template +struct is_floating_point +{ + static const bool value = is_same::value || is_same::value; +}; + +/// @brief Metafunction used to determine if the first template +/// parameter is a specialization of the class template +/// given in the second template parameter. +/// +/// @details is_specialization, Vec3>::value == true; +template class TemplateType> +struct is_specialization +{ + static const bool value = false; +}; +template class TemplateType> +struct is_specialization, TemplateType> +{ + static const bool value = true; +}; + +// Dummy type for a voxel with a binary mask value, e.g. the active state +class ValueMask +{ +}; + +/// @brief List of types that are currently supported by NanoVDB +/// +/// @note To expand on this list do: +/// 1) Add the new type between Unknown and End in the enum below +/// 2) Add the new type to Serializer::processGrid that maps OpenVDB types to GridType +/// 3) Verify that the Deserializer::ConvertTrait works correctly with the new type +/// 4) Add the new type to GridHandle::map that maps NanoVDB types to GridType +/// 5) Optionally add the new type to mapToStr in cmd/nanovdb_print.cpp +enum class GridType : uint32_t { Unknown = 0, + Float = 1, + Double = 2, + Int16 = 3, + Int32 = 4, + Int64 = 5, + Vec3f = 6, + Vec3d = 7, + Mask = 8, + FP16 = 9, + UInt32 = 10, + End = 11 }; + +/// @brief Classes (defined in OpenVDB) that are currently supported by NanoVDB +enum class GridClass : uint32_t { Unknown = 0, + LevelSet = 1, + FogVolume = 2, + Staggered = 3, + PointIndex = 4, + PointData = 5, + End = 6 }; + +/// @brief Grid flags which indicate what extra information is present in the grid buffer. +enum class GridFlags : uint32_t { + HasTruncatedGridname = 1 << 0, + HasBBox = 1 << 1, + HasMinMax = 1 << 2, + HasAverage = 1 << 3, + HasStdDeviation = 1 << 4, + End = 1 << 5, +}; + +/// @brief Blind-data Classes that are currently supported by NanoVDB +enum class GridBlindDataClass : uint32_t { Unknown = 0, + IndexArray = 1, + AttributeArray = 2, + GridName = 3, + End = 4 }; + +/// @brief Blind-data Semantics that are currently understood by NanoVDB +enum class GridBlindDataSemantic : uint32_t { Unknown = 0, + PointPosition = 1, + PointColor = 2, + PointNormal = 3, + PointRadius = 4, + PointVelocity = 5, + PointId = 6, + End = 7 }; + +// ----------------------------> Version class <------------------------------------- + +/// @brief Bit-complated representation of all three version numbers +/// +/// @details major are the top 11 bits, minor are the 11 middle bits and patch are the lower 10 bits +class Version +{ + uint32_t mData;// 11 + 11 + 10 bit packing of major + minor + patch +public: + __hostdev__ Version() : mData( uint32_t(NANOVDB_MAJOR_VERSION_NUMBER) << 21 | + uint32_t(NANOVDB_MINOR_VERSION_NUMBER) << 10 | + uint32_t(NANOVDB_PATCH_VERSION_NUMBER) ) + { + } + __hostdev__ Version(uint32_t major, uint32_t minor, uint32_t patch) + : mData( major << 21 | minor << 10 | patch ) + { + assert(major < (1u << 11));// max value of major is 2047 + assert(minor < (1u << 11));// max value of minor is 2047 + assert(patch < (1u << 10));// max value of patch is 1023 + } + __hostdev__ bool operator==(const Version &rhs) const {return mData == rhs.mData;} + __hostdev__ bool operator< (const Version &rhs) const {return mData < rhs.mData;} + __hostdev__ bool operator<=(const Version &rhs) const {return mData <= rhs.mData;} + __hostdev__ bool operator> (const Version &rhs) const {return mData > rhs.mData;} + __hostdev__ bool operator>=(const Version &rhs) const {return mData >= rhs.mData;} + __hostdev__ uint32_t id() const { return mData; } + __hostdev__ uint32_t getMajor() const { return (mData >> 21) & ((1u << 11) - 1);} + __hostdev__ uint32_t getMinor() const { return (mData >> 10) & ((1u << 11) - 1);} + __hostdev__ uint32_t getPatch() const { return mData & ((1u << 10) - 1);} + +#ifndef __CUDACC_RTC__ + const char* c_str() const + { + char *buffer = (char*)malloc(4 + 1 + 4 + 1 + 4 + 1);// xxxx.xxxx.xxxx\n + sprintf(buffer, "%d.%d.%d", this->getMajor(), this->getMinor(), this->getPatch()); + return buffer; + } +#endif +};// Version + +// ----------------------------> Various math functions <------------------------------------- + +//@{ +/// Tolerance for floating-point comparison +template +struct Tolerance; +template<> +struct Tolerance +{ + __hostdev__ static float value() { return 1e-8f; } +}; +template<> +struct Tolerance +{ + __hostdev__ static double value() { return 1e-15; } +}; +//@} + +//@{ +/// Delta for small floating-point offsets +template +struct Delta; +template<> +struct Delta +{ + __hostdev__ static float value() { return 1e-5f; } +}; +template<> +struct Delta +{ + __hostdev__ static double value() { return 1e-9; } +}; +//@} + +//@{ +/// Maximum floating-point values +template +struct Maximum; +#ifdef __CUDA_ARCH__ +template<> +struct Maximum +{ + __hostdev__ static int value() { return 2147483647; } +}; +template<> +struct Maximum +{ + __hostdev__ static uint32_t value() { return 4294967295; } +}; +template<> +struct Maximum +{ + __hostdev__ static float value() { return 1e+38f; } +}; +template<> +struct Maximum +{ + __hostdev__ static double value() { return 1e+308; } +}; +#else +template +struct Maximum +{ + static T value() { return std::numeric_limits::max(); } +}; +#endif +//@} + +template +__hostdev__ inline bool isApproxZero(const Type& x) +{ + return !(x > Tolerance::value()) && !(x < -Tolerance::value()); +} + +template +__hostdev__ inline Type Min(Type a, Type b) +{ + return (a < b) ? a : b; +} +__hostdev__ inline int32_t Min(int32_t a, int32_t b) +{ + return int32_t(fminf(float(a), float(b))); +} +__hostdev__ inline uint32_t Min(uint32_t a, uint32_t b) +{ + return uint32_t(fminf(float(a), float(b))); +} +__hostdev__ inline float Min(float a, float b) +{ + return fminf(a, b); +} +__hostdev__ inline double Min(double a, double b) +{ + return fmin(a, b); +} +template +__hostdev__ inline Type Max(Type a, Type b) +{ + return (a > b) ? a : b; +} + +__hostdev__ inline int32_t Max(int32_t a, int32_t b) +{ + return int32_t(fmaxf(float(a), float(b))); +} +__hostdev__ inline uint32_t Max(uint32_t a, uint32_t b) +{ + return uint32_t(fmaxf(float(a), float(b))); +} +__hostdev__ inline float Max(float a, float b) +{ + return fmaxf(a, b); +} +__hostdev__ inline double Max(double a, double b) +{ + return fmax(a, b); +} +__hostdev__ inline float Clamp(float x, float a, float b) +{ + return Max(Min(x, b), a); +} +__hostdev__ inline double Clamp(double x, double a, double b) +{ + return Max(Min(x, b), a); +} + +__hostdev__ inline float Fract(float x) +{ + return x - floorf(x); +} +__hostdev__ inline double Fract(double x) +{ + return x - floor(x); +} + +__hostdev__ inline int32_t Floor(float x) +{ + return int32_t(floorf(x)); +} +__hostdev__ inline int32_t Floor(double x) +{ + return int32_t(floor(x)); +} + +__hostdev__ inline int32_t Ceil(float x) +{ + return int32_t(ceilf(x)); +} +__hostdev__ inline int32_t Ceil(double x) +{ + return int32_t(ceil(x)); +} + +template +__hostdev__ inline T Pow2(T x) +{ + return x * x; +} + +template +__hostdev__ inline T Abs(T x) +{ + return x < 0 ? -x : x; +} + +template<> +__hostdev__ inline float Abs(float x) +{ + return fabs(x); +} + +template<> +__hostdev__ inline double Abs(double x) +{ + return fabs(x); +} + +template<> +__hostdev__ inline int Abs(int x) +{ + return abs(x); +} + +template class Vec3T> +__hostdev__ inline CoordT Round(const Vec3T& xyz); + +template class Vec3T> +__hostdev__ inline CoordT Round(const Vec3T& xyz) +{ + return CoordT(int32_t(rintf(xyz[0])), int32_t(rintf(xyz[1])), int32_t(rintf(xyz[2]))); + //return CoordT(int32_t(roundf(xyz[0])), int32_t(roundf(xyz[1])), int32_t(roundf(xyz[2])) ); + //return CoordT(int32_t(floorf(xyz[0] + 0.5f)), int32_t(floorf(xyz[1] + 0.5f)), int32_t(floorf(xyz[2] + 0.5f))); +} + +template class Vec3T> +__hostdev__ inline CoordT Round(const Vec3T& xyz) +{ + return CoordT(int32_t(floor(xyz[0] + 0.5)), int32_t(floor(xyz[1] + 0.5)), int32_t(floor(xyz[2] + 0.5))); +} + +template class Vec3T> +__hostdev__ inline CoordT RoundDown(const Vec3T& xyz) +{ + return CoordT(Floor(xyz[0]), Floor(xyz[1]), Floor(xyz[2])); +} + +//@{ +/// Return the square root of a floating-point value. +inline __hostdev__ float Sqrt(float x) +{ + return sqrtf(x); +} +inline __hostdev__ double Sqrt(double x) +{ + return sqrt(x); +} +//@} + +template +__hostdev__ inline int MinIndex(const Vec3T& v) +{ +#if 0 + static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values + const int hashKey = ((v[0] < v[1]) << 2) + ((v[0] < v[2]) << 1) + (v[1] < v[2]); // ?*4+?*2+?*1 + return hashTable[hashKey]; +#else + if (v[0] < v[1] && v[0] < v[2]) + return 0; + if (v[1] < v[2]) + return 1; + else + return 2; +#endif +} + +template +__hostdev__ inline int MaxIndex(const Vec3T& v) +{ +#if 0 + static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values + const int hashKey = ((v[0] > v[1]) << 2) + ((v[0] > v[2]) << 1) + (v[1] > v[2]); // ?*4+?*2+?*1 + return hashTable[hashKey]; +#else + if (v[0] > v[1] && v[0] > v[2]) + return 0; + if (v[1] > v[2]) + return 1; + else + return 2; +#endif +} + +// round up byteSize to the nearest wordSize, e.g. to align to machine word: AlignUp +__hostdev__ inline uint64_t AlignUp(uint64_t byteCount) +{ + const uint64_t r = byteCount % wordSize; + return r ? byteCount - r + wordSize : byteCount; +} + +// ------------------------------> Coord <-------------------------------------- + +// forward decleration so we can define Coord::asVec3s and Coord::asVec3d +template class Vec3; + +/// @brief Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord +class Coord +{ + int32_t mVec[3]; // private member data - three signed index coordinates +public: + using ValueType = int32_t; + using IndexType = uint32_t; + + /// @brief Initialize all coordinates to zero. + __hostdev__ Coord() + : mVec{0, 0, 0} + { + } + + /// @brief Initializes all coordinates to the given signed integer. + __hostdev__ explicit Coord(ValueType n) + : mVec{n, n, n} + { + } + + /// @brief Initializes coordinate to the given signed integers. + __hostdev__ Coord(ValueType i, ValueType j, ValueType k) + : mVec{i, j, k} + { + } + + __hostdev__ Coord(ValueType *ptr) + : mVec{ptr[0], ptr[1], ptr[2]} + { + } + + __hostdev__ int32_t x() const { return mVec[0]; } + __hostdev__ int32_t y() const { return mVec[1]; } + __hostdev__ int32_t z() const { return mVec[2]; } + + __hostdev__ int32_t& x() { return mVec[0]; } + __hostdev__ int32_t& y() { return mVec[1]; } + __hostdev__ int32_t& z() { return mVec[2]; } + + __hostdev__ static Coord max() { return Coord(int32_t((1u << 31) - 1)); } + + __hostdev__ static Coord min() { return Coord(-int32_t((1u << 31) - 1) - 1); } + + __hostdev__ static size_t memUsage() { return sizeof(Coord); } + + /// @brief Return a const reference to the given Coord component. + /// @warning The argument is assumed to be 0, 1, or 2. + __hostdev__ const ValueType& operator[](IndexType i) const { return mVec[i]; } + + /// @brief Return a non-const reference to the given Coord component. + /// @warning The argument is assumed to be 0, 1, or 2. + __hostdev__ ValueType& operator[](IndexType i) { return mVec[i]; } + + /// @brief Return a new instance with coordinates masked by the given unsigned integer. + __hostdev__ Coord operator&(IndexType n) const { return Coord(mVec[0] & n, mVec[1] & n, mVec[2] & n); } + + // @brief Return a new instance with coordinates left-shifted by the given unsigned integer. + __hostdev__ Coord operator<<(IndexType n) const { return Coord(mVec[0] << n, mVec[1] << n, mVec[2] << n); } + + // @brief Return a new instance with coordinates right-shifted by the given unsigned integer. + __hostdev__ Coord operator>>(IndexType n) const { return Coord(mVec[0] >> n, mVec[1] >> n, mVec[2] >> n); } + + /// @brief Return true if this Coord is lexicographically less than the given Coord. + __hostdev__ bool operator<(const Coord& rhs) const + { + return mVec[0] < rhs[0] ? true : mVec[0] > rhs[0] ? false : mVec[1] < rhs[1] ? true : mVec[1] > rhs[1] ? false : mVec[2] < rhs[2] ? true : false; + } + + // @brief Return true if the Coord components are identical. + __hostdev__ bool operator==(const Coord& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2]; } + __hostdev__ bool operator!=(const Coord& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2]; } + __hostdev__ Coord& operator&=(int n) + { + mVec[0] &= n; + mVec[1] &= n; + mVec[2] &= n; + return *this; + } + __hostdev__ Coord& operator<<=(uint32_t n) + { + mVec[0] <<= n; + mVec[1] <<= n; + mVec[2] <<= n; + return *this; + } + __hostdev__ Coord& operator+=(int n) + { + mVec[0] += n; + mVec[1] += n; + mVec[2] += n; + return *this; + } + __hostdev__ Coord operator+(const Coord& rhs) const { return Coord(mVec[0] + rhs[0], mVec[1] + rhs[1], mVec[2] + rhs[2]); } + __hostdev__ Coord operator-(const Coord& rhs) const { return Coord(mVec[0] - rhs[0], mVec[1] - rhs[1], mVec[2] - rhs[2]); } + __hostdev__ Coord& operator+=(const Coord& rhs) + { + mVec[0] += rhs[0]; + mVec[1] += rhs[1]; + mVec[2] += rhs[2]; + return *this; + } + __hostdev__ Coord& operator-=(const Coord& rhs) + { + mVec[0] -= rhs[0]; + mVec[1] -= rhs[1]; + mVec[2] -= rhs[2]; + return *this; + } + + /// @brief Perform a component-wise minimum with the other Coord. + __hostdev__ Coord& minComponent(const Coord& other) + { + if (other[0] < mVec[0]) + mVec[0] = other[0]; + if (other[1] < mVec[1]) + mVec[1] = other[1]; + if (other[2] < mVec[2]) + mVec[2] = other[2]; + return *this; + } + + /// @brief Perform a component-wise maximum with the other Coord. + __hostdev__ Coord& maxComponent(const Coord& other) + { + if (other[0] > mVec[0]) + mVec[0] = other[0]; + if (other[1] > mVec[1]) + mVec[1] = other[1]; + if (other[2] > mVec[2]) + mVec[2] = other[2]; + return *this; + } + + /// Return true if any of the components of @a a are smaller than the + /// corresponding components of @a b. + __hostdev__ static inline bool lessThan(const Coord& a, const Coord& b) + { + return (a[0] < b[0] || a[1] < b[1] || a[2] < b[2]); + } + + /// @brief Return the largest integer coordinates that are not greater + /// than @a xyz (node centered conversion). + template + __hostdev__ static Coord Floor(const Vec3T& xyz) { return Coord(nanovdb::Floor(xyz[0]), nanovdb::Floor(xyz[1]), nanovdb::Floor(xyz[2])); } + + /// @brief Return a hash key derived from the existing coordinates. + /// @details For details on this hash function please see the VDB paper. + template + __hostdev__ uint32_t hash() const { return ((1 << Log2N) - 1) & (mVec[0] * 73856093 ^ mVec[1] * 19349663 ^ mVec[2] * 83492791); } + + /// @brief Return the octant of this Coord + //__hostdev__ size_t octant() const { return (uint32_t(mVec[0])>>31) | ((uint32_t(mVec[1])>>31)<<1) | ((uint32_t(mVec[2])>>31)<<2); } + __hostdev__ uint8_t octant() const { return (uint8_t(bool(mVec[0] & (1u << 31)))) | + (uint8_t(bool(mVec[1] & (1u << 31))) << 1) | + (uint8_t(bool(mVec[2] & (1u << 31))) << 2); } + + /// @brief Return a single precision floating-point vector of this coordinate + inline __hostdev__ Vec3 asVec3s() const; + + /// @brief Return a double precision floating-point vector of this coordinate + inline __hostdev__ Vec3 asVec3d() const; +}; // Coord class + +// ----------------------------> Vec3 <-------------------------------------- + +/// @brief A simple vector class with three double components, similar to openvdb::math::Vec3 +template +class Vec3 +{ + T mVec[3]; + +public: + static const int SIZE = 3; + using ValueType = T; + Vec3() = default; + __hostdev__ explicit Vec3(T x) + : mVec{x, x, x} + { + } + __hostdev__ Vec3(T x, T y, T z) + : mVec{x, y, z} + { + } + template + __hostdev__ explicit Vec3(const Vec3& v) + : mVec{T(v[0]), T(v[1]), T(v[2])} + { + } + __hostdev__ explicit Vec3(const Coord& ijk) + : mVec{T(ijk[0]), T(ijk[1]), T(ijk[2])} + { + } + __hostdev__ bool operator==(const Vec3& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2]; } + __hostdev__ bool operator!=(const Vec3& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2]; } + template + __hostdev__ Vec3& operator=(const Vec3T& rhs) + { + mVec[0] = rhs[0]; + mVec[1] = rhs[1]; + mVec[2] = rhs[2]; + return *this; + } + __hostdev__ const T& operator[](int i) const { return mVec[i]; } + __hostdev__ T& operator[](int i) { return mVec[i]; } + template + __hostdev__ T dot(const Vec3T& v) const { return mVec[0] * v[0] + mVec[1] * v[1] + mVec[2] * v[2]; } + template + __hostdev__ Vec3 cross(const Vec3T& v) const + { + return Vec3(mVec[1] * v[2] - mVec[2] * v[1], + mVec[2] * v[0] - mVec[0] * v[2], + mVec[0] * v[1] - mVec[1] * v[0]); + } + __hostdev__ T lengthSqr() const + { + return mVec[0] * mVec[0] + mVec[1] * mVec[1] + mVec[2] * mVec[2]; // 5 flops + } + __hostdev__ T length() const { return Sqrt(this->lengthSqr()); } + __hostdev__ Vec3 operator-() const { return Vec3(-mVec[0], -mVec[1], -mVec[2]); } + __hostdev__ Vec3 operator*(const Vec3& v) const { return Vec3(mVec[0] * v[0], mVec[1] * v[1], mVec[2] * v[2]); } + __hostdev__ Vec3 operator/(const Vec3& v) const { return Vec3(mVec[0] / v[0], mVec[1] / v[1], mVec[2] / v[2]); } + __hostdev__ Vec3 operator+(const Vec3& v) const { return Vec3(mVec[0] + v[0], mVec[1] + v[1], mVec[2] + v[2]); } + __hostdev__ Vec3 operator-(const Vec3& v) const { return Vec3(mVec[0] - v[0], mVec[1] - v[1], mVec[2] - v[2]); } + __hostdev__ Vec3 operator*(const T& s) const { return Vec3(s * mVec[0], s * mVec[1], s * mVec[2]); } + __hostdev__ Vec3 operator/(const T& s) const { return (T(1) / s) * (*this); } + __hostdev__ Vec3& operator+=(const Vec3& v) + { + mVec[0] += v[0]; + mVec[1] += v[1]; + mVec[2] += v[2]; + return *this; + } + __hostdev__ Vec3& operator-=(const Vec3& v) + { + mVec[0] -= v[0]; + mVec[1] -= v[1]; + mVec[2] -= v[2]; + return *this; + } + __hostdev__ Vec3& operator*=(const T& s) + { + mVec[0] *= s; + mVec[1] *= s; + mVec[2] *= s; + return *this; + } + __hostdev__ Vec3& operator/=(const T& s) { return (*this) *= T(1) / s; } + __hostdev__ Vec3& normalize() { return (*this) /= this->length(); } + /// @brief Perform a component-wise minimum with the other Coord. + __hostdev__ void minComponent(const Vec3& other) + { + if (other[0] < mVec[0]) + mVec[0] = other[0]; + if (other[1] < mVec[1]) + mVec[1] = other[1]; + if (other[2] < mVec[2]) + mVec[2] = other[2]; + } + + /// @brief Perform a component-wise maximum with the other Coord. + __hostdev__ void maxComponent(const Vec3& other) + { + if (other[0] > mVec[0]) + mVec[0] = other[0]; + if (other[1] > mVec[1]) + mVec[1] = other[1]; + if (other[2] > mVec[2]) + mVec[2] = other[2]; + } + /// @brief Return the smallest vector component + __hostdev__ ValueType min() const + { + return mVec[0] < mVec[1] ? (mVec[0] < mVec[2] ? mVec[0] : mVec[2]) : (mVec[1] < mVec[2] ? mVec[1] : mVec[2]); + } + /// @brief Return the largest vector component + __hostdev__ ValueType max() const + { + return mVec[0] > mVec[1] ? (mVec[0] > mVec[2] ? mVec[0] : mVec[2]) : (mVec[1] > mVec[2] ? mVec[1] : mVec[2]); + } + __hostdev__ Coord floor() const { return Coord(Floor(mVec[0]), Floor(mVec[1]), Floor(mVec[2])); } + __hostdev__ Coord ceil() const { return Coord(Ceil(mVec[0]), Ceil(mVec[1]), Ceil(mVec[2])); } + __hostdev__ Coord round() const { return Coord(Floor(mVec[0] + 0.5), Floor(mVec[1] + 0.5), Floor(mVec[2] + 0.5)); } +}; // Vec3 + +template +inline __hostdev__ Vec3 operator*(T1 scalar, const Vec3& vec) +{ + return Vec3(scalar * vec[0], scalar * vec[1], scalar * vec[2]); +} +template +inline __hostdev__ Vec3 operator/(T1 scalar, const Vec3& vec) +{ + return Vec3(scalar / vec[0], scalar / vec[1], scalar / vec[2]); +} + +using Vec3R = Vec3; +using Vec3d = Vec3; +using Vec3f = Vec3; +using Vec3i = Vec3; + +/// @brief Return a single precision floating-point vector of this coordinate +Vec3f Coord::asVec3s() const { return Vec3f(float(mVec[0]), float(mVec[1]), float(mVec[2])); } + +/// @brief Return a double precision floating-point vector of this coordinate +Vec3d Coord::asVec3d() const { return Vec3d(double(mVec[0]), double(mVec[1]), double(mVec[2])); } + +// ----------------------------> Vec4 <-------------------------------------- + +/// @brief A simple vector class with three double components, similar to openvdb::math::Vec4 +template +class Vec4 +{ + T mVec[4]; + +public: + static const int SIZE = 4; + using ValueType = T; + Vec4() = default; + __hostdev__ explicit Vec4(T x) + : mVec{x, x, x, x} + { + } + __hostdev__ Vec4(T x, T y, T z, T w) + : mVec{x, y, z, w} + { + } + template + __hostdev__ explicit Vec4(const Vec4& v) + : mVec{T(v[0]), T(v[1]), T(v[2]), T(v[3])} + { + } + __hostdev__ bool operator==(const Vec4& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2] && mVec[3] == rhs[3]; } + __hostdev__ bool operator!=(const Vec4& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2] != mVec[3] != rhs[3]; } + template + __hostdev__ Vec4& operator=(const Vec4T& rhs) + { + mVec[0] = rhs[0]; + mVec[1] = rhs[1]; + mVec[2] = rhs[2]; + mVec[3] = rhs[3]; + return *this; + } + __hostdev__ const T& operator[](int i) const { return mVec[i]; } + __hostdev__ T& operator[](int i) { return mVec[i]; } + template + __hostdev__ T dot(const Vec4T& v) const { return mVec[0] * v[0] + mVec[1] * v[1] + mVec[2] * v[2] + mVec[3] * v[3]; } + __hostdev__ T lengthSqr() const + { + return mVec[0] * mVec[0] + mVec[1] * mVec[1] + mVec[2] * mVec[2] + mVec[3] * mVec[3]; // 7 flops + } + __hostdev__ T length() const { return Sqrt(this->lengthSqr()); } + __hostdev__ Vec4 operator-() const { return Vec4(-mVec[0], -mVec[1], -mVec[2], -mVec[3]); } + __hostdev__ Vec4 operator*(const Vec4& v) const { return Vec4(mVec[0] * v[0], mVec[1] * v[1], mVec[2] * v[2], mVec[3] * v[3]); } + __hostdev__ Vec4 operator/(const Vec4& v) const { return Vec4(mVec[0] / v[0], mVec[1] / v[1], mVec[2] / v[2], mVec[3] / v[3]); } + __hostdev__ Vec4 operator+(const Vec4& v) const { return Vec4(mVec[0] + v[0], mVec[1] + v[1], mVec[2] + v[2], mVec[3] + v[3]); } + __hostdev__ Vec4 operator-(const Vec4& v) const { return Vec4(mVec[0] - v[0], mVec[1] - v[1], mVec[2] - v[2], mVec[3] - v[3]); } + __hostdev__ Vec4 operator*(const T& s) const { return Vec4(s * mVec[0], s * mVec[1], s * mVec[2], s * mVec[3]); } + __hostdev__ Vec4 operator/(const T& s) const { return (T(1) / s) * (*this); } + __hostdev__ Vec4& operator+=(const Vec4& v) + { + mVec[0] += v[0]; + mVec[1] += v[1]; + mVec[2] += v[2]; + mVec[3] += v[3]; + return *this; + } + __hostdev__ Vec4& operator-=(const Vec4& v) + { + mVec[0] -= v[0]; + mVec[1] -= v[1]; + mVec[2] -= v[2]; + mVec[3] -= v[3]; + return *this; + } + __hostdev__ Vec4& operator*=(const T& s) + { + mVec[0] *= s; + mVec[1] *= s; + mVec[2] *= s; + mVec[3] *= s; + return *this; + } + __hostdev__ Vec4& operator/=(const T& s) { return (*this) *= T(1) / s; } + __hostdev__ Vec4& normalize() { return (*this) /= this->length(); } + /// @brief Perform a component-wise minimum with the other Coord. + __hostdev__ void minComponent(const Vec4& other) + { + if (other[0] < mVec[0]) + mVec[0] = other[0]; + if (other[1] < mVec[1]) + mVec[1] = other[1]; + if (other[2] < mVec[2]) + mVec[2] = other[2]; + if (other[3] < mVec[3]) + mVec[3] = other[3]; + } + + /// @brief Perform a component-wise maximum with the other Coord. + __hostdev__ void maxComponent(const Vec4& other) + { + if (other[0] > mVec[0]) + mVec[0] = other[0]; + if (other[1] > mVec[1]) + mVec[1] = other[1]; + if (other[2] > mVec[2]) + mVec[2] = other[2]; + if (other[3] > mVec[3]) + mVec[3] = other[3]; + } +}; // Vec4 + +template +inline __hostdev__ Vec4 operator*(T1 scalar, const Vec4& vec) +{ + return Vec4(scalar * vec[0], scalar * vec[1], scalar * vec[2], scalar * vec[3]); +} +template +inline __hostdev__ Vec4 operator/(T1 scalar, const Vec3& vec) +{ + return Vec4(scalar / vec[0], scalar / vec[1], scalar / vec[2], scalar / vec[3]); +} + +using Vec4R = Vec4; +using Vec4d = Vec4; +using Vec4f = Vec4; +using Vec4i = Vec4; + +// ----------------------------> TensorTraits <-------------------------------------- + +template::value || + is_specialization::value) ? 1 : 0> +struct TensorTraits; + +template +struct TensorTraits +{ + static const int Rank = 0; // i.e. scalar + static const bool IsScalar = true; + static const bool IsVector = false; + static const int Size = 1; + using ElementType = T; + static T scalar(const T& s) { return s; } +}; + +template +struct TensorTraits +{ + static const int Rank = 1; // i.e. vector + static const bool IsScalar = false; + static const bool IsVector = true; + static const int Size = T::SIZE; + using ElementType = typename T::ValueType; + static ElementType scalar(const T& v) { return v.length(); } +}; + +// ----------------------------> FloatTraits <-------------------------------------- + +template::ElementType)> +struct FloatTraits +{ + using FloatType = float; +}; + +template +struct FloatTraits +{ + using FloatType = double; +}; + +// ----------------------------> mapping ValueType -> GridType <-------------------------------------- + +/// @brief Maps from a templated value type to a GridType enum +template +__hostdev__ GridType mapToGridType() +{ + if (is_same::value) { // resolved at compile-time + return GridType::Float; + } else if (is_same::value) { + return GridType::Double; + } else if (is_same::value) { + return GridType::Int16; + } else if (is_same::value) { + return GridType::Int32; + } else if (is_same::value) { + return GridType::Int64; + } else if (is_same::value) { + return GridType::Vec3f; + } else if (is_same::value) { + return GridType::Vec3d; + } else if (is_same::value) { + return GridType::UInt32; + } else if (is_same::value) { + return GridType::Mask; + } + return GridType::Unknown; +} + +// ----------------------------> matMult <-------------------------------------- + +template +inline __hostdev__ Vec3T matMult(const float* mat, const Vec3T& xyz) +{ + return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[1], xyz[2] * mat[2])), + fmaf(xyz[0], mat[3], fmaf(xyz[1], mat[4], xyz[2] * mat[5])), + fmaf(xyz[0], mat[6], fmaf(xyz[1], mat[7], xyz[2] * mat[8]))); // 6 fmaf + 3 mult = 9 flops +} + +template +inline __hostdev__ Vec3T matMult(const double* mat, const Vec3T& xyz) +{ + return Vec3T(fma(static_cast(xyz[0]), mat[0], fma(static_cast(xyz[1]), mat[1], static_cast(xyz[2]) * mat[2])), + fma(static_cast(xyz[0]), mat[3], fma(static_cast(xyz[1]), mat[4], static_cast(xyz[2]) * mat[5])), + fma(static_cast(xyz[0]), mat[6], fma(static_cast(xyz[1]), mat[7], static_cast(xyz[2]) * mat[8]))); // 6 fmaf + 3 mult = 9 flops +} + +template +inline __hostdev__ Vec3T matMult(const float* mat, const float* vec, const Vec3T& xyz) +{ + return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[1], fmaf(xyz[2], mat[2], vec[0]))), + fmaf(xyz[0], mat[3], fmaf(xyz[1], mat[4], fmaf(xyz[2], mat[5], vec[1]))), + fmaf(xyz[0], mat[6], fmaf(xyz[1], mat[7], fmaf(xyz[2], mat[8], vec[2])))); // 9 fmaf = 9 flops +} + +template +inline __hostdev__ Vec3T matMult(const double* mat, const double* vec, const Vec3T& xyz) +{ + return Vec3T(fma(static_cast(xyz[0]), mat[0], fma(static_cast(xyz[1]), mat[1], fma(static_cast(xyz[2]), mat[2], vec[0]))), + fma(static_cast(xyz[0]), mat[3], fma(static_cast(xyz[1]), mat[4], fma(static_cast(xyz[2]), mat[5], vec[1]))), + fma(static_cast(xyz[0]), mat[6], fma(static_cast(xyz[1]), mat[7], fma(static_cast(xyz[2]), mat[8], vec[2])))); // 9 fma = 9 flops +} + +// matMultT: Multiply with the transpose: + +template +inline __hostdev__ Vec3T matMultT(const float* mat, const Vec3T& xyz) +{ + return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[3], xyz[2] * mat[6])), + fmaf(xyz[0], mat[1], fmaf(xyz[1], mat[4], xyz[2] * mat[7])), + fmaf(xyz[0], mat[2], fmaf(xyz[1], mat[5], xyz[2] * mat[8]))); // 6 fmaf + 3 mult = 9 flops +} + +template +inline __hostdev__ Vec3T matMultT(const double* mat, const Vec3T& xyz) +{ + return Vec3T(fma(static_cast(xyz[0]), mat[0], fma(static_cast(xyz[1]), mat[3], static_cast(xyz[2]) * mat[6])), + fma(static_cast(xyz[0]), mat[1], fma(static_cast(xyz[1]), mat[4], static_cast(xyz[2]) * mat[7])), + fma(static_cast(xyz[0]), mat[2], fma(static_cast(xyz[1]), mat[5], static_cast(xyz[2]) * mat[8]))); // 6 fmaf + 3 mult = 9 flops +} + +template +inline __hostdev__ Vec3T matMultT(const float* mat, const float* vec, const Vec3T& xyz) +{ + return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[3], fmaf(xyz[2], mat[6], vec[0]))), + fmaf(xyz[0], mat[1], fmaf(xyz[1], mat[4], fmaf(xyz[2], mat[7], vec[1]))), + fmaf(xyz[0], mat[2], fmaf(xyz[1], mat[5], fmaf(xyz[2], mat[8], vec[2])))); // 9 fmaf = 9 flops +} + +template +inline __hostdev__ Vec3T matMultT(const double* mat, const double* vec, const Vec3T& xyz) +{ + return Vec3T(fma(static_cast(xyz[0]), mat[0], fma(static_cast(xyz[1]), mat[3], fma(static_cast(xyz[2]), mat[6], vec[0]))), + fma(static_cast(xyz[0]), mat[1], fma(static_cast(xyz[1]), mat[4], fma(static_cast(xyz[2]), mat[7], vec[1]))), + fma(static_cast(xyz[0]), mat[2], fma(static_cast(xyz[1]), mat[5], fma(static_cast(xyz[2]), mat[8], vec[2])))); // 9 fma = 9 flops +} + +// ----------------------------> BBox <------------------------------------- + +// Base-class for static polymorphism (cannot be constructed directly) +template +struct BaseBBox +{ + Vec3T mCoord[2]; + __hostdev__ bool operator==(const BaseBBox& rhs) const { return mCoord[0] == rhs.mCoord[0] && mCoord[1] == rhs.mCoord[1]; }; + __hostdev__ bool operator!=(const BaseBBox& rhs) const { return mCoord[0] != rhs.mCoord[0] || mCoord[1] != rhs.mCoord[1]; }; + __hostdev__ const Vec3T& operator[](int i) const { return mCoord[i]; } + __hostdev__ Vec3T& operator[](int i) { return mCoord[i]; } + __hostdev__ Vec3T& min() { return mCoord[0]; } + __hostdev__ Vec3T& max() { return mCoord[1]; } + __hostdev__ const Vec3T& min() const { return mCoord[0]; } + __hostdev__ const Vec3T& max() const { return mCoord[1]; } + __hostdev__ void translate(const Vec3T& xyz) + { + mCoord[0] += xyz; + mCoord[1] += xyz; + } + // @brief Expand this bounding box to enclose point (i, j, k). + __hostdev__ void expand(const Vec3T& xyz) + { + mCoord[0].minComponent(xyz); + mCoord[1].maxComponent(xyz); + } + __hostdev__ bool isInside(const Vec3T& xyz) + { + if (xyz[0] < mCoord[0][0] || xyz[1] < mCoord[0][1] || xyz[2] < mCoord[0][2]) + return false; + if (xyz[0] > mCoord[1][0] || xyz[1] > mCoord[1][1] || xyz[2] > mCoord[1][2]) + return false; + return true; + } + +protected: + __hostdev__ BaseBBox() {} + __hostdev__ BaseBBox(const Vec3T& min, const Vec3T& max) + : mCoord{min, max} + { + } +}; // BaseBBox + +template::value> +struct BBox; + +/// @brief Partial template specialization for floating point coordinate types. +/// +/// @note Min is inclusive and max is exclusive. If min = max the dimension of +/// the bounding box is zero and therefore it is also empty. +template +struct BBox : public BaseBBox +{ + using Vec3Type = Vec3T; + using ValueType = typename Vec3T::ValueType; + static_assert(is_floating_point::value, "Expected a floating point coordinate type"); + using BaseT = BaseBBox; + using BaseT::mCoord; + __hostdev__ BBox() + : BaseT(Vec3T( Maximum::value()), + Vec3T(-Maximum::value())) + { + } + __hostdev__ BBox(const Vec3T& min, const Vec3T& max) + : BaseT(min, max) + { + } + __hostdev__ BBox(const Coord& min, const Coord& max) + : BaseT(Vec3T(ValueType(min[0]), ValueType(min[1]), ValueType(min[2])), + Vec3T(ValueType(max[0] + 1), ValueType(max[1] + 1), ValueType(max[2] + 1))) + { + } + __hostdev__ BBox(const BaseBBox& bbox) : BBox(bbox[0], bbox[1]) {} + __hostdev__ bool empty() const { return mCoord[0][0] >= mCoord[1][0] || + mCoord[0][1] >= mCoord[1][1] || + mCoord[0][2] >= mCoord[1][2]; } + __hostdev__ Vec3T dim() const { return this->empty() ? Vec3T(0) : this->max() - this->min(); } + __hostdev__ bool isInside(const Vec3T& p) const + { + return p[0] > mCoord[0][0] && p[1] > mCoord[0][1] && p[2] > mCoord[0][2] && + p[0] < mCoord[1][0] && p[1] < mCoord[1][1] && p[2] < mCoord[1][2]; + } +};// BBox + +/// @brief Partial template specialization for integer coordinate types +/// +/// @note Both min and max are INCLUDED in the bbox so dim = max - min + 1. So, +/// if min = max the bounding box contains exactly one point and dim = 1! +template +struct BBox : public BaseBBox +{ + static_assert(is_same::value, "Expected \"int\" coordinate type"); + using BaseT = BaseBBox; + using BaseT::mCoord; + /// @brief Iterator over the domain covered by a BBox + /// @details z is the fastest-moving coordinate. + class Iterator + { + const BBox& mBBox; + CoordT mPos; + + public: + __hostdev__ Iterator(const BBox& b) + : mBBox(b) + , mPos(b.min()) + { + } + __hostdev__ Iterator& operator++() + { + if (mPos[2] < mBBox[1][2]) { + ++mPos[2]; + } // this is the most common case + else if (mPos[1] < mBBox[1][1]) { + mPos[2] = mBBox[0][2]; + ++mPos[1]; + } else if (mPos[0] <= mBBox[1][0]) { + mPos[2] = mBBox[0][2]; + mPos[1] = mBBox[0][1]; + ++mPos[0]; + } + return *this; + } + __hostdev__ Iterator operator++(int) + { + auto tmp = *this; + ++(*this); + return tmp; + } + /// @brief Return @c true if the iterator still points to a valid coordinate. + __hostdev__ operator bool() const { return mPos[0] <= mBBox[1][0]; } + __hostdev__ const CoordT& operator*() const { return mPos; } + }; // Iterator + __hostdev__ Iterator begin() const { return Iterator{*this}; } + __hostdev__ BBox() + : BaseT(CoordT::max(), CoordT::min()) + { + } + __hostdev__ BBox(const CoordT& min, const CoordT& max) + : BaseT(min, max) + { + } + template + __hostdev__ BBox(BBox& other, const SplitT&) + : BaseT(other.mCoord[0], other.mCoord[1]) + { + assert(this->is_divisible()); + const int n = MaxIndex(this->dim()); + mCoord[1][n] = (mCoord[0][n] + mCoord[1][n]) >> 1; + other.mCoord[0][n] = mCoord[1][n] + 1; + } + __hostdev__ bool is_divisible() const { return mCoord[0][0] < mCoord[1][0] && + mCoord[0][1] < mCoord[1][1] && + mCoord[0][2] < mCoord[1][2]; } + /// @brief Return true if this bounding box is empty, i.e. uninitialized + __hostdev__ bool empty() const { return mCoord[0][0] > mCoord[1][0] || + mCoord[0][1] > mCoord[1][1] || + mCoord[0][2] > mCoord[1][2]; } + __hostdev__ CoordT dim() const { return this->empty() ? Coord(0) : this->max() - this->min() + Coord(1); } + __hostdev__ bool isInside(const CoordT& p) const { return !(CoordT::lessThan(p, this->min()) || CoordT::lessThan(this->max(), p)); } + __hostdev__ bool isInside(const BBox& b) const + { + return !(CoordT::lessThan(b.min(), this->min()) || CoordT::lessThan(this->max(), b.max())); + } + + /// @warning This converts a CoordBBox into a floating-point bounding box which implies that max += 1 ! + template + __hostdev__ BBox> asReal() const + { + static_assert(is_floating_point::value, "CoordBBox::asReal: Expected a floating point coordinate"); + return BBox>(Vec3(RealT(mCoord[0][0]), RealT(mCoord[0][1]), RealT(mCoord[0][2])), + Vec3(RealT(mCoord[1][0] + 1), RealT(mCoord[1][1] + 1), RealT(mCoord[1][2] + 1))); + } +};// BBox + +using CoordBBox = BBox; +using BBoxR = BBox; + +// -------------------> Find lowest and highest bit in a word <---------------------------- + +/// @brief Returns the index of the lowest, i.e. least significant, on bit in the specified 32 bit word +/// +/// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)! +__hostdev__ static inline uint32_t FindLowestOn(uint32_t v) +{ + assert(v); +#if defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS) + unsigned long index; + _BitScanForward(&index, v); + return static_cast(index); +#elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS) + return static_cast(__builtin_ctzl(v)); +#else + static const unsigned char DeBruijn[32] = { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}; +// disable unary minus on unsigned warning +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4146) +#endif + return DeBruijn[uint32_t((v & -v) * 0x077CB531U) >> 27]; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#endif +} + +/// @brief Returns the index of the highest, i.e. most significant, on bit in the specified 32 bit word +/// +/// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)! +__hostdev__ static inline uint32_t FindHighestOn(uint32_t v) +{ + assert(v); +#if defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS) + unsigned long index; + _BitScanReverse(&index, v); + return static_cast(index); +#elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS) + return sizeof(unsigned long) * 8 - 1 - __builtin_clzl(v); + +#else + static const unsigned char DeBruijn[32] = { + 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31}; + v |= v >> 1; // first round down to one less than a power of 2 + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return DeBruijn[uint32_t(v * 0x07C4ACDDU) >> 27]; +#endif +} + +/// @brief Returns the index of the lowest, i.e. least significant, on bit in the specified 64 bit word +/// +/// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)! +__hostdev__ static inline uint32_t FindLowestOn(uint64_t v) +{ + assert(v); +#if defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS) + unsigned long index; + _BitScanForward64(&index, v); + return static_cast(index); +#elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS) + return static_cast(__builtin_ctzll(v)); +#else + static const unsigned char DeBruijn[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12, + }; +// disable unary minus on unsigned warning +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4146) +#endif + return DeBruijn[uint64_t((v & -v) * UINT64_C(0x022FDD63CC95386D)) >> 58]; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#endif +} + +/// @brief Returns the index of the highest, i.e. most significant, on bit in the specified 64 bit word +/// +/// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)! +__hostdev__ static inline uint32_t FindHighestOn(uint64_t v) +{ + assert(v); +#if defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS) + unsigned long index; + _BitScanReverse64(&index, v); + return static_cast(index); +#elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS) + return sizeof(unsigned long) * 8 - 1 - __builtin_clzll(v); +#else + const uint32_t* p = reinterpret_cast(&v); + return p[1] ? 32u + FindHighestOn(p[1]) : FindHighestOn(p[0]); +#endif +} + +// ----------------------------> Mask <-------------------------------------- + +/// @brief Bit-mask to encode active states and facilitate sequential iterators +/// and a fast codec for I/O compression. +template +class Mask +{ + static constexpr uint32_t SIZE = 1U << (3 * LOG2DIM); // Number of bits in mask + static constexpr uint32_t WORD_COUNT = SIZE >> 6; // Number of 64 bit words + uint64_t mWords[WORD_COUNT]; + +public: + /// @brief Return the memory footprint in bytes of this Mask + __hostdev__ static size_t memUsage() { return sizeof(Mask); } + + /// @brief Return the number of bits available in this Mask + __hostdev__ static uint32_t bitCount() { return SIZE; } + + /// @brief Return the number of machine words used by this Mask + __hostdev__ static uint32_t wordCount() { return WORD_COUNT; } + + __hostdev__ uint32_t countOn() const + { + uint32_t sum = 0, n = WORD_COUNT; + for (const uint64_t* w = mWords; n--; ++w) + sum += CountOn(*w); + return sum; + } + + class Iterator + { + public: + __hostdev__ Iterator() + : mPos(Mask::SIZE) + , mParent(nullptr) + { + } + __hostdev__ Iterator(uint32_t pos, const Mask* parent) + : mPos(pos) + , mParent(parent) + { + } + Iterator& operator=(const Iterator&) = default; + __hostdev__ uint32_t operator*() const { return mPos; } + __hostdev__ operator bool() const { return mPos != Mask::SIZE; } + __hostdev__ Iterator& operator++() + { + mPos = mParent->findNextOn(mPos + 1); + return *this; + } + + private: + uint32_t mPos; + const Mask* mParent; + }; // Memeber class MaskIterator + + /// @brief Initialize all bits to zero. + __hostdev__ Mask() + { + for (uint32_t i = 0; i < WORD_COUNT; ++i) + mWords[i] = 0; + } + __hostdev__ Mask(bool on) + { + const uint64_t v = on ? ~uint64_t(0) : uint64_t(0); + for (uint32_t i = 0; i < WORD_COUNT; ++i) + mWords[i] = v; + } + + /// @brief Copy constructor + __hostdev__ Mask(const Mask& other) + { + for (uint32_t i = 0; i < WORD_COUNT; ++i) + mWords[i] = other.mWords[i]; + } + + /// @breif Return the nth word of the bit mask, for a word of arbitrary size. + template + __hostdev__ WordT getWord(int n) const + { + assert(n * 8 * sizeof(WordT) < SIZE); + return reinterpret_cast(mWords)[n]; + } + + /// @brief Assignment operator from another Mask type + __hostdev__ Mask& operator=(const Mask& other) + { + for (uint32_t i = 0; i < WORD_COUNT; ++i) + mWords[i] = other.mWords[i]; + return *this; + } + + __hostdev__ Iterator beginOn() const { return Iterator(this->findFirstOn(), this); } + + /// @brief Return true if the given bit is set. + __hostdev__ bool isOn(uint32_t n) const { return 0 != (mWords[n >> 6] & (uint64_t(1) << (n & 63))); } + + __hostdev__ bool isOn() const + { + for (uint32_t i = 0; i < WORD_COUNT; ++i) + if (mWords[i] != ~uint64_t(0)) + return false; + return true; + } + + __hostdev__ bool isOff() const + { + for (uint32_t i = 0; i < WORD_COUNT; ++i) + if (mWords[i] != uint64_t(0)) + return false; + return true; + } + + /// @brief Set the given bit on. + __hostdev__ void setOn(uint32_t n) { mWords[n >> 6] |= uint64_t(1) << (n & 63); } + __hostdev__ void setOff(uint32_t n) { mWords[n >> 6] &= ~(uint64_t(1) << (n & 63)); } + + __hostdev__ void set(uint32_t n, bool On) { On ? this->setOn(n) : this->setOff(n); } + + /// @brief Set all bits off + __hostdev__ void setOff() + { + for (uint32_t i = 0; i < WORD_COUNT; ++i) + mWords[i] = 0; + } + + /// @brief Set all bits off + __hostdev__ void set(bool on) + { + const uint64_t v = on ? ~uint64_t(0) : uint64_t(0); + for (uint32_t i = 0; i < WORD_COUNT; ++i) + mWords[i] = v; + } + /// brief Toggle the state of all bits in the mask + __hostdev__ void toggle() + { + uint32_t n = WORD_COUNT; + for (auto* w = mWords; n--; ++w) + *w = ~*w; + } + __hostdev__ void toggle(uint32_t n) { mWords[n >> 6] ^= uint64_t(1) << (n & 63); } + +private: + __hostdev__ static inline uint32_t CountOn(uint64_t v) + { + v = v - ((v >> 1) & uint64_t(0x5555555555555555)); + v = (v & uint64_t(0x3333333333333333)) + ((v >> 2) & uint64_t(0x3333333333333333)); + return (((v + (v >> 4)) & uint64_t(0xF0F0F0F0F0F0F0F)) * uint64_t(0x101010101010101)) >> 56; + } + + __hostdev__ uint32_t findFirstOn() const + { + uint32_t n = 0; + const uint64_t* w = mWords; + for (; n < WORD_COUNT && !*w; ++w, ++n) + ; + return n == WORD_COUNT ? SIZE : (n << 6) + FindLowestOn(*w); + } + __hostdev__ uint32_t findNextOn(uint32_t start) const + { + uint32_t n = start >> 6; // initiate + if (n >= WORD_COUNT) + return SIZE; // check for out of bounds + uint32_t m = start & 63; + uint64_t b = mWords[n]; + if (b & (uint64_t(1) << m)) + return start; // simple case: start is on + b &= ~uint64_t(0) << m; // mask out lower bits + while (!b && ++n < WORD_COUNT) + b = mWords[n]; // find next non-zero word + return (!b ? SIZE : (n << 6) + FindLowestOn(b)); // catch last word=0 + } +}; // Mask class + +// ----------------------------> Map <-------------------------------------- + +/// @brief Defines an affine transform and its inverse represented as a 3x3 matrix and a vec3 translation +struct Map +{ + float mMatF[9]; // 9*4B <- 3x3 matrix + float mInvMatF[9]; // 9*4B <- 3x3 matrix + float mVecF[3]; // 3*4B <- translation + float mTaperF; // 4B, placeholder for taper value + double mMatD[9]; // 9*8B <- 3x3 matrix + double mInvMatD[9]; // 9*8B <- 3x3 matrix + double mVecD[3]; // 3*8B <- translation + double mTaperD; // 8B, placeholder for taper value + + // This method can only be called on the host to initialize the member data + template + __hostdev__ void set(const Mat4T& mat, const Mat4T& invMat, double taper); + + template + __hostdev__ Vec3T applyMap(const Vec3T& xyz) const { return matMult(mMatD, mVecD, xyz); } + template + __hostdev__ Vec3T applyMapF(const Vec3T& xyz) const { return matMult(mMatF, mVecF, xyz); } + + template + __hostdev__ Vec3T applyJacobian(const Vec3T& xyz) const { return matMult(mMatD, xyz); } + template + __hostdev__ Vec3T applyJacobianF(const Vec3T& xyz) const { return matMult(mMatF, xyz); } + + template + __hostdev__ Vec3T applyInverseMap(const Vec3T& xyz) const + { + return matMult(mInvMatD, Vec3T(xyz[0] - mVecD[0], xyz[1] - mVecD[1], xyz[2] - mVecD[2])); + } + template + __hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const + { + return matMult(mInvMatF, Vec3T(xyz[0] - mVecF[0], xyz[1] - mVecF[1], xyz[2] - mVecF[2])); + } + + template + __hostdev__ Vec3T applyInverseJacobian(const Vec3T& xyz) const { return matMult(mInvMatD, xyz); } + template + __hostdev__ Vec3T applyInverseJacobianF(const Vec3T& xyz) const { return matMult(mInvMatF, xyz); } + + template + __hostdev__ Vec3T applyIJT(const Vec3T& xyz) const { return matMultT(mInvMatD, xyz); } + template + __hostdev__ Vec3T applyIJTF(const Vec3T& xyz) const { return matMultT(mInvMatF, xyz); } +}; // Map + +template +void Map::set(const Mat4T& mat, const Mat4T& invMat, double taper) +{ + float * mf = mMatF, *vf = mVecF; + float* mif = mInvMatF; + double *md = mMatD, *vd = mVecD; + double* mid = mInvMatD; + mTaperF = static_cast(taper); + mTaperD = taper; + for (int i = 0; i < 3; ++i) { + *vd++ = mat[3][i]; //translation + *vf++ = static_cast(mat[3][i]); + for (int j = 0; j < 3; ++j) { + *md++ = mat[j][i]; //transposed + *mid++ = invMat[j][i]; + *mf++ = static_cast(mat[j][i]); + *mif++ = static_cast(invMat[j][i]); + } + } +} + +// ----------------------------> GridBlindMetaData <-------------------------------------- + +struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridBlindMetaData +{ + static const int MaxNameSize = 256; + int64_t mByteOffset; // byte offset to the blind data, relative to the GridData. + uint64_t mElementCount; // number of elements, e.g. point count + uint32_t mFlags; // flags + GridBlindDataSemantic mSemantic; // semantic meaning of the data. + GridBlindDataClass mDataClass; // 4 bytes + GridType mDataType; // 4 bytes + char mName[MaxNameSize]; + + /// @brief return memory usage in bytes for the class (note this computes for all blindMetaData structures.) + __hostdev__ static uint64_t memUsage(uint64_t blindDataCount = 0) + { + return blindDataCount * sizeof(GridBlindMetaData); + } + +}; // GridBlindMetaData + +// ----------------------------> Grid <-------------------------------------- + +/* + The following class and comment is for internal use only + + Memory layout: + + Grid -> 39 x double (world bbox and affine transformation) + Tree -> Root 3 x ValueType + int32_t + N x Tiles (background,min,max,tileCount + tileCount x Tiles) + + N2 upper InternalNodes each with 2 bit masks, N2 tiles, and min/max values + + N1 lower InternalNodes each with 2 bit masks, N1 tiles, and min/max values + + N0 LeafNodes each with a bit mask, N0 ValueTypes and min/max + + Example layout: ("---" implies it has a custom offset, "..." implies zero or more) + [GridData][TreeData]---[RootData][ROOT TILES...]---[NodeData<5>]---[ModeData<4>]---[LeafData<3>]---[BLINDMETA...]---[BLIND0]---[BLIND1]---etc. +*/ + +/// @brief Struct with all the member data of the Grid (useful during serialization of an openvdb grid) +/// +/// @note The transform is assumed to be affine (so linear) and have uniform scale! So frustum transforms +/// and non-uniform scaling are not supported (primarily because they complicate ray-tracing in index space) +/// +/// @note No client code should (or can) interface with this struct so it can safely be ignored! +struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData +{ + static const int MaxNameSize = 256; + uint64_t mMagic; // 8B magic to validate it is valid grid data. + uint64_t mChecksum; // 8B. Checksum of grid buffer. + Version mVersion;// 4B major, minor, and patch version numbers + uint32_t mFlags; // 4B. flags for grid. + uint64_t mGridSize; // 8B. byte count of entire grid buffer. + char mGridName[MaxNameSize]; // 256B + Map mMap; // 264B. affine transformation between index and world space in both single and double precision + BBox mWorldBBox; // 48B. floating-point AABB of active values in WORLD SPACE (2 x 3 doubles) + Vec3R mVoxelSize; // 24B. size of a voxel in world units + GridClass mGridClass; // 4B. + GridType mGridType; // 4B. + uint64_t mBlindMetadataOffset; // 8B. offset of GridBlindMetaData structures that follow this grid. + uint32_t mBlindMetadataCount; // 4B. count of GridBlindMetaData structures that follow this grid. + + // Set and unset various bit flags + __hostdev__ void setFlagsOff() { mFlags = uint32_t(0); } + __hostdev__ void setMinMaxOn(bool on = true) + { + if (on) { + mFlags |= static_cast(GridFlags::HasMinMax); + } else { + mFlags &= ~static_cast(GridFlags::HasMinMax); + } + } + __hostdev__ void setBBoxOn(bool on = true) + { + if (on) { + mFlags |= static_cast(GridFlags::HasBBox); + } else { + mFlags &= ~static_cast(GridFlags::HasBBox); + } + } + __hostdev__ void setTruncatedGridNameOn(bool on = true) + { + if (on) { + mFlags |= static_cast(GridFlags::HasTruncatedGridname); + } else { + mFlags &= ~static_cast(GridFlags::HasTruncatedGridname); + } + } + __hostdev__ void setAverageOn(bool on = true) + { + if (on) { + mFlags |= static_cast(GridFlags::HasAverage); + } else { + mFlags &= ~static_cast(GridFlags::HasAverage); + } + } + __hostdev__ void setStdDeviationOn(bool on = true) + { + if (on) { + mFlags |= static_cast(GridFlags::HasStdDeviation); + } else { + mFlags &= ~static_cast(GridFlags::HasStdDeviation); + } + } + + // Affine transformations based on double precision + template + __hostdev__ Vec3T applyMap(const Vec3T& xyz) const { return mMap.applyMap(xyz); } // Pos: index -> world + template + __hostdev__ Vec3T applyInverseMap(const Vec3T& xyz) const { return mMap.applyInverseMap(xyz); } // Pos: world -> index + template + __hostdev__ Vec3T applyJacobian(const Vec3T& xyz) const { return mMap.applyJacobian(xyz); } // Dir: index -> world + template + __hostdev__ Vec3T applyInverseJacobian(const Vec3T& xyz) const { return mMap.applyInverseJacobian(xyz); } // Dir: world -> index + template + __hostdev__ Vec3T applyIJT(const Vec3T& xyz) const { return mMap.applyIJT(xyz); } + // Affine transformations based on single precision + template + __hostdev__ Vec3T applyMapF(const Vec3T& xyz) const { return mMap.applyMapF(xyz); } // Pos: index -> world + template + __hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const { return mMap.applyInverseMapF(xyz); } // Pos: world -> index + template + __hostdev__ Vec3T applyJacobianF(const Vec3T& xyz) const { return mMap.applyJacobianF(xyz); } // Dir: index -> world + template + __hostdev__ Vec3T applyInverseJacobianF(const Vec3T& xyz) const { return mMap.applyInverseJacobianF(xyz); } // Dir: world -> index + template + __hostdev__ Vec3T applyIJTF(const Vec3T& xyz) const { return mMap.applyIJTF(xyz); } + + /// @brief Return a const pointer to the blind meta data + __hostdev__ const GridBlindMetaData* metaPtr() const + { + return reinterpret_cast(reinterpret_cast(this) + mBlindMetadataOffset); + } + + // @brief Return a non-const void pointer to the tree + __hostdev__ void* treePtr() { return this + 1; } + + // @brief Return a const void pointer to the tree + __hostdev__ const void* treePtr() const { return this + 1; } + + /// @brief Returns a const reference to the blindMetaData at the specified linear offset. + /// + /// @warning The linear offset is assumed to be in the valid range + __hostdev__ const GridBlindMetaData& blindMetaData(uint32_t n) const + { + assert(n < mBlindMetadataCount); + return *(this->metaPtr() + n); + } + +}; // GridData + +// Forward declaration of accelerated random access class +template +class ReadAccessor; + +template +using DefaultReadAccessor = ReadAccessor; + +/// @brief Highest level of the data structure. Contains a tree and a world->index +/// transform (that currently only supports uniform scaling and translation). +/// +/// @note This the API of this class to interface with client code +template +class Grid : private GridData +{ +public: + using TreeType = TreeT; + using DataType = GridData; + using ValueType = typename TreeT::ValueType; + using CoordType = typename TreeT::CoordType; + using AccessorType = DefaultReadAccessor; + + //static constexpr bool IgnoreValues = TreeT::IgnoreValues; + + /// @brief Disallow constructions, copy and assignment + /// + /// @note Only a Serializer, defined elsewhere, can instantiate this class + Grid(const Grid&) = delete; + Grid& operator=(const Grid&) = delete; + ~Grid() = delete; + + __hostdev__ Version version() const { return DataType::mVersion; } + + __hostdev__ DataType* data() { return reinterpret_cast(this); } + + __hostdev__ const DataType* data() const { return reinterpret_cast(this); } + + /// @brief return memory usage in bytes for the class (note this computes room for blindMetaData structures.) + __hostdev__ static uint64_t memUsage() { return sizeof(GridData); } + + /// @brief return the memory footprint of the entire grid, i.e. including all nodes and blind data + __hostdev__ uint64_t totalMemUsage() const { return DataType::mGridSize; } + + /// @brief Return a const reference to the tree + __hostdev__ const TreeT& tree() const { return *reinterpret_cast(this->treePtr()); } + + /// @brief Return a non-const reference to the tree + __hostdev__ TreeT& tree() { return *reinterpret_cast(this->treePtr()); } + + /// @brief Return a new instance of a ReadAccessor used to access values in this grid + __hostdev__ AccessorType getAccessor() const { return AccessorType(this->tree().root()); } + + /// @brief Return a const reference to the size of a voxel in world units + __hostdev__ const Vec3R& voxelSize() const { return DataType::mVoxelSize; } + + /// @brief Return a const reference to the Map for this grid + __hostdev__ const Map& map() const { return DataType::mMap; } + + /// @brief world to index space transformation + template + __hostdev__ Vec3T worldToIndex(const Vec3T& xyz) const { return this->applyInverseMap(xyz); } + + /// @brief world to index space transformation + template + __hostdev__ Vec3T indexToWorld(const Vec3T& xyz) const { return this->applyMap(xyz); } + + /// @brief transformation from index space direction to world space direction + /// @warning assumes dir to be normalized + template + __hostdev__ Vec3T indexToWorldDir(const Vec3T& dir) const { return this->applyJacobian(dir); } + + /// @brief transformation from world space direction to index space direction + /// @warning assumes dir to be normalized + template + __hostdev__ Vec3T worldToIndexDir(const Vec3T& dir) const { return this->applyInverseJacobian(dir); } + + /// @brief Trnasform the gradient from index space to world space. + /// @details Applies the inverse jacobian transform map. + template + __hostdev__ Vec3T indexToWorldGrad(const Vec3T& grad) const { return this->applyIJT(grad); } + + /// @brief world to index space transformation + template + __hostdev__ Vec3T worldToIndexF(const Vec3T& xyz) const { return this->applyInverseMapF(xyz); } + + /// @brief index to world space transformation + template + __hostdev__ Vec3T indexToWorldF(const Vec3T& xyz) const { return this->applyMapF(xyz); } + + /// @brief transformation from index space direction to world space direction + /// @warning assumes dir to be normalized + template + __hostdev__ Vec3T indexToWorldDirF(const Vec3T& dir) const { return this->applyJacobianF(dir); } + + /// @brief transformation from world space direction to index space direction + /// @warning assumes dir to be normalized + template + __hostdev__ Vec3T worldToIndexDirF(const Vec3T& dir) const { return this->applyInverseJacobianF(dir); } + + /// @brief Transforms the gradient from index space to world space. + /// @details Applies the inverse jacobian transform map. + template + __hostdev__ Vec3T indexToWorldGradF(const Vec3T& grad) const { return DataType::applyIJTF(grad); } + + /// @brief Computes a AABB of active values in world space + __hostdev__ const BBox& worldBBox() const { return DataType::mWorldBBox; } + + /// @brief Computes a AABB of active values in index space + /// + /// @note This method is returning a floating point bounding box and not a CoordBBox. This makes + /// it more useful for clipping rays. + __hostdev__ const BBox& indexBBox() const { return this->tree().bbox(); } + + /// @brief Return the total number of active voxels in this tree. + __hostdev__ const uint64_t& activeVoxelCount() const { return this->tree().activeVoxelCount(); } + + /// @brief Methods related to the classification of this grid + __hostdev__ bool isValid() const { return DataType::mMagic == NANOVDB_MAGIC_NUMBER; } + __hostdev__ const GridType& gridType() const { return DataType::mGridType; } + __hostdev__ const GridClass& gridClass() const { return DataType::mGridClass; } + __hostdev__ bool isLevelSet() const { return DataType::mGridClass == GridClass::LevelSet; } + __hostdev__ bool isFogVolume() const { return DataType::mGridClass == GridClass::FogVolume; } + __hostdev__ bool isStaggered() const { return DataType::mGridClass == GridClass::Staggered; } + __hostdev__ bool isPointIndex() const { return DataType::mGridClass == GridClass::PointIndex; } + __hostdev__ bool isPointData() const { return DataType::mGridClass == GridClass::PointData; } + __hostdev__ bool isUnknown() const { return DataType::mGridClass == GridClass::Unknown; } + __hostdev__ bool hasMinMax() const { return DataType::mFlags & static_cast(GridFlags::HasMinMax); } + __hostdev__ bool hasBBox() const { return DataType::mFlags & static_cast(GridFlags::HasBBox); } + __hostdev__ bool hasTrunctedGridName() const { return DataType::mFlags & static_cast(GridFlags::HasTruncatedGridname); } + __hostdev__ bool hasAverage() const { return DataType::mFlags & static_cast(GridFlags::HasAverage); } + __hostdev__ bool hasStdDeviation() const { return DataType::mFlags & static_cast(GridFlags::HasStdDeviation); } + + /// @brief Return a c-string with the name of this grid + __hostdev__ const char* gridName() const { return DataType::mGridName; } + + /// @brief Return checksum of the grid buffer. + __hostdev__ uint64_t checksum() const { return DataType::mChecksum; } + + /// @brief Return true if this grid is empty, i.e. contains no values or nodes. + __hostdev__ bool isEmpty() const { return this->tree().isEmpty(); } + + /// @brief Return the count of blind-data encoded in this grid + __hostdev__ int blindDataCount() const { return DataType::mBlindMetadataCount; } + + /// @brief Return the index of the blind data with specified semantic if found, otherwise -1. + __hostdev__ int findBlindDataForSemantic(GridBlindDataSemantic semantic) const; + + /// @brief Returns a const pointer to the blindData at the specified linear offset. + /// + /// @warning Point might be NULL and the linear offset is assumed to be in the valid range + __hostdev__ const void* blindData(uint32_t n) const + { + if (DataType::mBlindMetadataCount == 0) + return nullptr; + assert(n < DataType::mBlindMetadataCount); + return reinterpret_cast(this) + this->blindMetaData(n).mByteOffset; + } + + __hostdev__ const GridBlindMetaData& blindMetaData(int n) const { return DataType::blindMetaData(n); } + +private: + static_assert(sizeof(GridData) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(GridData) is misaligned"); +}; // Class Grid + +template +int Grid::findBlindDataForSemantic(GridBlindDataSemantic semantic) const +{ + for (uint32_t i = 0, n = blindDataCount(); i < n; ++i) + if (blindMetaData(i).mSemantic == semantic) + return int(i); + return -1; +} + +// ----------------------------> Tree <-------------------------------------- + +template +struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) TreeData +{ + static_assert(ROOT_LEVEL == 3, "Root level is assumed to be three"); + uint64_t mBytes[ROOT_LEVEL + 1]; // 32B. byte offsets to nodes of type: leaf, lower internal, upper internal, and root + uint32_t mCount[ROOT_LEVEL + 1]; // 16B. total number of nodes of type: leaf, lower internal, upper internal, and root + uint32_t mPFSum[ROOT_LEVEL + 1]; // 16B. reversed prefix sum of mCount - useful for accessing blind data associated with nodes +}; + +/// @brief Struct to derive node type from its level in a given tree +template +struct TreeNode; + +// Partial template specialization of above Node struct +template +struct TreeNode +{ + static_assert(TreeT::RootType::LEVEL == 3, "Tree depth is not supported"); + using type = typename TreeT::LeafNodeType; +}; +template +struct TreeNode +{ + static_assert(TreeT::RootType::LEVEL == 3, "Tree depth is not supported"); + using type = typename TreeT::RootType::ChildNodeType::ChildNodeType; +}; +template +struct TreeNode +{ + static_assert(TreeT::RootType::LEVEL == 3, "Tree depth is not supported"); + using type = typename TreeT::RootType::ChildNodeType; +}; +template +struct TreeNode +{ + static_assert(TreeT::RootType::LEVEL == 3, "Tree depth is not supported"); + using type = typename TreeT::RootType; +}; + +/// @brief VDB Tree, which is a thin wrapper around a RootNode. +template +class Tree : private TreeData +{ + static_assert(RootT::LEVEL == 3, "Tree depth is not supported"); + static_assert(RootT::ChildNodeType::LOG2DIM == 5, "Tree configuration is not supported"); + static_assert(RootT::ChildNodeType::ChildNodeType::LOG2DIM == 4, "Tree configuration is not supported"); + static_assert(RootT::LeafNodeType::LOG2DIM == 3, "Tree configuration is not supported"); + +public: + using DataType = TreeData; + using RootType = RootT; + using LeafNodeType = typename RootT::LeafNodeType; + using ValueType = typename RootT::ValueType; + using CoordType = typename RootT::CoordType; + using AccessorType = DefaultReadAccessor; + + using Node3 = RootT; + using Node2 = typename RootT::ChildNodeType; + using Node1 = typename Node2::ChildNodeType; + using Node0 = LeafNodeType; + + template + using TreeNodeT = typename TreeNode::type; + + //static constexpr bool IgnoreValues = RootT::IgnoreValues; + static_assert(is_same, Node0>::value, "TreeNodeT<0> error"); + static_assert(is_same, Node1>::value, "TreeNodeT<1> error"); + static_assert(is_same, Node2>::value, "TreeNodeT<2> error"); + static_assert(is_same, Node3>::value, "TreeNodeT<3> error"); + + /// @brief This class cannot be constructed or deleted + Tree() = delete; + Tree(const Tree&) = delete; + Tree& operator=(const Tree&) = delete; + ~Tree() = delete; + + __hostdev__ DataType* data() { return reinterpret_cast(this); } + + __hostdev__ const DataType* data() const { return reinterpret_cast(this); } + + /// @brief return memory usage in bytes for the class + __hostdev__ static uint64_t memUsage() { return sizeof(DataType); } + + __hostdev__ RootT& root() { return *reinterpret_cast(reinterpret_cast(this) + DataType::mBytes[RootT::LEVEL]); } + + __hostdev__ const RootT& root() const { return *reinterpret_cast(reinterpret_cast(this) + DataType::mBytes[RootT::LEVEL]); } + + __hostdev__ AccessorType getAccessor() const { return AccessorType(this->root()); } + + /// @brief Return the value of the given voxel (regardless of state or location in the tree.) + __hostdev__ const ValueType& getValue(const CoordType& ijk) const { return this->root().getValue(ijk); } + + /// @brief Return the active state of the given voxel (regardless of state or location in the tree.) + __hostdev__ bool isActive(const CoordType& ijk) const { return this->root().isActive(ijk); } + + /// @brief Return true if this tree is empty, i.e. contains no values or nodes + __hostdev__ bool isEmpty() const { return this->root().isEmpty(); } + + /// @brief Combines the previous two methods in a single call + __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->root().probeValue(ijk, v); } + + /// @brief Return a const reference to the background value. + __hostdev__ const ValueType& background() const { return this->root().background(); } + + /// @brief Sets the extrema values of all the active values in this tree, i.e. in all nodes of the tree + __hostdev__ void extrema(ValueType& min, ValueType& max) const; + + /// @brief Return a const reference to the index bounding box of all the active values in this tree, i.e. in all nodes of the tree + __hostdev__ const BBox& bbox() const { return this->root().bbox(); } + + /// @brief Return the total number of active voxels in this tree. + __hostdev__ const uint64_t& activeVoxelCount() const { return this->root().activeVoxelCount(); } + + template + __hostdev__ uint32_t nodeCount() const { return DataType::mCount[NodeT::LEVEL]; } + + __hostdev__ uint32_t nodeCount(int level) const { return DataType::mCount[level]; } + + template + __hostdev__ const NodeT* getNode(uint32_t i) const; + + template + __hostdev__ const TreeNodeT* getNode(uint32_t i) const; + + template + __hostdev__ NodeT* getNode(uint32_t i); + + template + __hostdev__ TreeNodeT* getNode(uint32_t i); + + /// @brief Returns the linear index, i.e. 0 -> ( # of nodes of type NodeT - 1), of the specified node + template + __hostdev__ uint32_t getNodeID(const NodeT& node) const; + + /// @brief Returns the linear index of the specified node. 0 corresponds to the root node, followed by all the upper + /// internal nodes, then the lower internal nodes and finally the leaf nodes. So the highest linear index is + /// is total number of tree nodes minus one. + /// + /// @details This is useful when accessing blind data associated with tree nodes, e.g. auxiliary value buffers + template + __hostdev__ uint32_t getLinearOffset(const NodeT& node) const; + +private: + static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(TreeData) is misaligned"); + +}; // Tree class + +template +void Tree::extrema(ValueType& min, ValueType& max) const +{ + min = this->root().valueMin(); + max = this->root().valueMax(); +} + +template +template +const NodeT* Tree::getNode(uint32_t i) const +{ + static_assert(is_same, NodeT>::value, "Tree::getNode: unvalid node type"); + assert(i < DataType::mCount[NodeT::LEVEL]); + return reinterpret_cast(reinterpret_cast(this) + DataType::mBytes[NodeT::LEVEL]) + i; +} + +template +template +const typename TreeNode, LEVEL>::type* Tree::getNode(uint32_t i) const +{ + assert(i < DataType::mCount[LEVEL]); + return reinterpret_cast*>(reinterpret_cast(this) + DataType::mBytes[LEVEL]) + i; +} + +template +template +NodeT* Tree::getNode(uint32_t i) +{ + static_assert(is_same, NodeT>::value, "Tree::getNode: invalid node type"); + assert(i < DataType::mCount[NodeT::LEVEL]); + return reinterpret_cast(reinterpret_cast(this) + DataType::mBytes[NodeT::LEVEL]) + i; +} + +template +template +typename TreeNode, LEVEL>::type* Tree::getNode(uint32_t i) +{ + assert(i < DataType::mCount[LEVEL]); + return reinterpret_cast*>(reinterpret_cast(this) + DataType::mBytes[LEVEL]) + i; +} + +template +template +uint32_t Tree::getNodeID(const NodeT& node) const +{ + static_assert(is_same, NodeT>::value, "Tree::getNodeID: invalid node type"); + const NodeT* first = reinterpret_cast(reinterpret_cast(this) + DataType::mBytes[NodeT::LEVEL]); + assert(&node >= first); + return static_cast(&node - first); //we know that there can never be more than 2^32 nodes of any type +} + +template +template +uint32_t Tree::getLinearOffset(const NodeT& node) const +{ + return this->getNodeID(node) + DataType::mPFSum[NodeT::LEVEL]; +} + +// --------------------------> RootNode <------------------------------------ + +/// @brief Struct with all the member data of the RootNode (useful during serialization of an openvdb RootNode) +/// +/// @note No client code should (or can) interface with this struct so it can safely be ignored! +template +struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) RootData +{ + using ValueT = typename ChildT::ValueType; + using CoordT = typename ChildT::CoordType; + using StatsT = typename ChildT::FloatType; + /// @brief Return a key based on the coordinates of a voxel +#ifdef USE_SINGLE_ROOT_KEY + using KeyT = uint64_t; + __hostdev__ static KeyT CoordToKey(const CoordT& ijk) + { + static_assert(32 - ChildT::TOTAL <= 21, "Cannot use 64 bit root keys"); + return (KeyT(uint32_t(ijk[2]) >> ChildT::TOTAL)) | // lower 21 bits + (KeyT(uint32_t(ijk[1]) >> ChildT::TOTAL) << 21) | // middle 21 bits + (KeyT(uint32_t(ijk[0]) >> ChildT::TOTAL) << 42); // upper 21 bits + } + __hostdev__ static CoordT KeyToCoord(const KeyT& key) + { + static constexpr uint64_t MASK = (1u << 21) - 1; + return Coord((key & MASK) << ChildT::TOTAL, + ((key >> 21) & MASK) << ChildT::TOTAL, + ((key >> 42) & MASK) << ChildT::TOTAL); + } +#else + using KeyT = CoordT; + __hostdev__ static KeyT CoordToKey(const CoordT& ijk) { return ijk & ~ChildT::MASK; } + __hostdev__ static CoordT KeyToCoord(const KeyT& key) { return key; } +#endif + BBox mBBox; // 24B. AABB if active values in index space. + uint64_t mActiveVoxelCount; // 8B. total number of active voxels in the root and all its child nodes. + uint32_t mTileCount; // 4B. number of tiles and child pointers in the root node + + ValueT mBackground; // background value, i.e. value of any unset voxel + ValueT mMinimum; // typically 4B, minmum of all the active values + ValueT mMaximum; // typically 4B, maximum of all the active values + StatsT mAverage; // typically 4B, average of all the active values in this node and its child nodes + StatsT mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes + + struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) Tile + { + __hostdev__ void setChild(const CoordT& k, int32_t n) + { + key = CoordToKey(k); + childID = n; + } + __hostdev__ void setValue(const CoordT& k, bool s, ValueT v) + { + key = CoordToKey(k); + state = s; + value = v; + childID = -1; + } + __hostdev__ bool isChild() const { return childID >= 0; } + __hostdev__ CoordT origin() const { return KeyToCoord(key); } + KeyT key; // (USE_SINGLE_ROOT_KEY)?8B:12B + int32_t childID; // 4B. negative values indicate no child node, i.e. this is a value tile + uint32_t state; // 4B. state of tile value + ValueT value; // value of tile (i.e. no child node) + }; // Tile + + /// @brief Returns a non-const reference to the tile at the specified linear offset. + /// + /// @warning The linear offset is assumed to be in the valid range + __hostdev__ Tile& tile(uint32_t n) const + { + assert(n < mTileCount); + return *(reinterpret_cast(const_cast(this) + 1) + n); + } + + /// @brief Returns a const reference to the child node in the specified tile. + /// + /// @warning A child node is assumed to exist in the specified tile + __hostdev__ const ChildT& child(const Tile& tile) const + { + assert(tile.isChild() && tile.childID < int32_t(ChildT::SIZE)); + return *(reinterpret_cast(reinterpret_cast(this + 1) + mTileCount) + tile.childID); + } + + /// @brief This class cannot be constructed or deleted + RootData() = delete; + RootData(const RootData&) = delete; + RootData& operator=(const RootData&) = delete; + ~RootData() = delete; +}; // RootData + +/// @brief Top-most node of the VDB tree structure. +template +class RootNode : private RootData +{ +public: + using DataType = RootData; + using LeafNodeType = typename ChildT::LeafNodeType; + using ChildNodeType = ChildT; + using ValueType = typename ChildT::ValueType; + using FloatType = typename ChildT::FloatType; + using CoordType = typename ChildT::CoordType; + using AccessorType = DefaultReadAccessor; + using Tile = typename DataType::Tile; + + static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf + //static constexpr bool IgnoreValues = ChildT::IgnoreValues; + + /// @brief This class cannot be constructed or deleted + RootNode() = delete; + RootNode(const RootNode&) = delete; + RootNode& operator=(const RootNode&) = delete; + ~RootNode() = delete; + + __hostdev__ AccessorType getAccessor() const { return AccessorType(*this); } + + __hostdev__ DataType* data() { return reinterpret_cast(this); } + + __hostdev__ const DataType* data() const { return reinterpret_cast(this); } + + /// @brief Return a const reference to the index bounding box of all the active values in this tree, i.e. in all nodes of the tree + __hostdev__ const BBox& bbox() const { return DataType::mBBox; } + + /// @brief Return the total number of active voxels in the root and all its child nodes. + __hostdev__ const uint64_t& activeVoxelCount() const { return DataType::mActiveVoxelCount; } + + /// @brief Return a const reference to the background value, i.e. the value associated with + /// any coordinate location that has not been set explicitly. + __hostdev__ const ValueType& background() const { return DataType::mBackground; } + + /// @brief Return the number of tiles encoded in this root node + __hostdev__ const uint32_t& tileCount() const { return DataType::mTileCount; } + + /// @brief Return a const reference to the minimum active value encoded in this root node and any of its child nodes + __hostdev__ const ValueType& valueMin() const { return DataType::mMinimum; } + + /// @brief Return a const reference to the maximum active value encoded in this root node and any of its child nodes + __hostdev__ const ValueType& valueMax() const { return DataType::mMaximum; } + + /// @brief Return a const reference to the average of all the active values encoded in this root node and any of its child nodes + __hostdev__ const FloatType& average() const { return DataType::mAverage; } + + /// @brief Return the variance of all the active values encoded in this root node and any of its child nodes + __hostdev__ FloatType variance() const { return DataType::mStdDevi * DataType::mStdDevi; } + + /// @brief Return a const reference to the standard deviation of all the active values encoded in this root node and any of its child nodes + __hostdev__ const FloatType& stdDeviation() const { return DataType::mStdDevi; } + + /// @brief Return the expected memory footprint in bytes with the specified number of tiles + __hostdev__ static uint64_t memUsage(uint32_t _tileCount) { return sizeof(RootNode) + _tileCount * sizeof(Tile); } + + /// @brief Return the actual memory footprint of this root node + __hostdev__ uint64_t memUsage() const { return sizeof(RootNode) + DataType::mTileCount * sizeof(Tile); } + + /// @brief Return the value of the given voxel + __hostdev__ const ValueType& getValue(const CoordType& ijk) const + { + const Tile* tile = this->findTile(ijk); + return tile ? (tile->childID < 0 ? tile->value : this->child(*tile).getValue(ijk)) : DataType::mBackground; + } + + __hostdev__ bool isActive(const CoordType& ijk) const + { + const Tile* tile = this->findTile(ijk); + return tile ? (tile->childID < 0 ? tile->state : this->child(*tile).isActive(ijk)) : false; + } + + /// @brief Return true if this RootNode is empty, i.e. contains no values or nodes + __hostdev__ bool isEmpty() const { return DataType::mTileCount == uint32_t(0); } + + __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const + { + if (const Tile* tile = this->findTile(ijk)) { + if (tile->childID < 0) { + v = tile->value; + return tile->state; + } else { + return this->child(*tile).probeValue(ijk, v); + } + } + v = DataType::mBackground; + return false; + } + + __hostdev__ const LeafNodeType* probeLeaf(const CoordType& ijk) const + { + const Tile* tile = this->findTile(ijk); + if (tile == nullptr || tile->childID < 0) + return nullptr; + return this->child(*tile).probeLeaf(ijk); + } + +private: + static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(RootData) is misaligned"); + static_assert(sizeof(typename DataType::Tile) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(RootData::Tile) is misaligned"); + + template + friend class ReadAccessor; + + template + friend class Tree; + + /// @brief Private method to find a Tile of this root node by means of binary-search. This is obviously + /// much slower then direct lookup into a linear array (as in the other nodes) which is exactly + /// why it is important to use the ReadAccessor which amortizes this overhead by node caching and + /// inverse tree traversal! + __hostdev__ const Tile* findTile(const CoordType& ijk) const + { + // binary-search of pre-sorted elements + int32_t low = 0, high = DataType::mTileCount; // low is inclusive and high is exclusive + const Tile* tiles = reinterpret_cast(this + 1); + const auto key = DataType::CoordToKey(ijk); +#if 1 // switch between linear and binary seach + for (int i = low; i < high; i++) { + const Tile* tile = &tiles[i]; + if (tile->key == key) + return tile; + } +#else + while (low != high) { + int mid = low + ((high - low) >> 1); + const Tile* tile = &tiles[mid]; + if (tile->key == key) { + return tile; + } else if (tile->key < key) { + low = mid + 1; + } else { + high = mid; + } + } +#endif + return nullptr; + } + + /// @brief Private method to return node information and update a ReadAccessor + template + __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(const CoordType& ijk, const AccT& acc) const + { + using NodeInfoT = typename AccT::NodeInfo; + if (const Tile* tile = this->findTile(ijk)) { + if (tile->childID < 0) { + return NodeInfoT{LEVEL, ChildT::dim(), tile->value, tile->value, tile->value, + 0, tile->origin(), tile->origin() + CoordType(ChildT::DIM)}; + } + const ChildT& child = this->child(*tile); + acc.insert(ijk, &child); + return child.getNodeInfoAndCache(ijk, acc); + } + return NodeInfoT{LEVEL, Maximum::value(), this->valueMin(), this->valueMax(), + this->average(), this->stdDeviation(), this->bbox()[0], this->bbox()[1]}; + } + + /// @brief Private method to return a voxel value and update a ReadAccessor + template + __hostdev__ const ValueType& getValueAndCache(const CoordType& ijk, const AccT& acc) const + { + if (const Tile* tile = this->findTile(ijk)) { + if (tile->childID < 0) + return tile->value; + const ChildT& child = this->child(*tile); + acc.insert(ijk, &child); + return child.getValueAndCache(ijk, acc); + } + return DataType::mBackground; + } + + template + __hostdev__ bool isActiveAndCache(const CoordType& ijk, const AccT& acc) const + { + if (const Tile* tile = this->findTile(ijk)) { + if (tile->childID < 0) + return tile->state; + const ChildT& child = this->child(*tile); + acc.insert(ijk, &child); + return child.isActiveAndCache(ijk, acc); + } + return false; + } + + template + __hostdev__ bool probeValueAndCache(const CoordType& ijk, ValueType& v, const AccT& acc) const + { + if (const Tile* tile = this->findTile(ijk)) { + if (tile->childID < 0) { + v = tile->value; + return tile->state; + } + const ChildT& child = this->child(*tile); + acc.insert(ijk, &child); + return child.probeValueAndCache(ijk, v, acc); + } + v = DataType::mBackground; + return false; + } + + template + __hostdev__ const LeafNodeType* probeLeafAndCache(const CoordType& ijk, const AccT& acc) const + { + const Tile* tile = this->findTile(ijk); + if (tile == nullptr || tile->childID < 0) + return nullptr; + const ChildT& child = this->child(*tile); + acc.insert(ijk, &child); + return child.probeLeafAndCache(ijk, acc); + } + + template + __hostdev__ uint32_t getDimAndCache(const CoordType& ijk, const RayT& ray, const AccT& acc) const + { + if (const Tile* tile = this->findTile(ijk)) { + if (tile->childID < 0) + return 1 << ChildT::TOTAL; //tile value + const ChildT& child = this->child(*tile); + acc.insert(ijk, &child); + return child.getDimAndCache(ijk, ray, acc); + } + return ChildNodeType::dim(); // background + } + +}; // RootNode class + +// After the RootNode the memory layout is assumed to be the sorted Tiles + +// --------------------------> InternalNode <------------------------------------ + +/// @brief Struct with all the member data of the InternalNode (useful during serialization of an openvdb InternalNode) +/// +/// @note No client code should (or can) interface with this struct so it can safely be ignored! +template +struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) InternalData +{ + using ValueT = typename ChildT::ValueType; + using StatsT = typename ChildT::FloatType; + using CoordT = typename ChildT::CoordType; + using MaskT = typename ChildT::template MaskType; + + union Tile + { + ValueT value; + uint32_t childID; + + /// @brief This class cannot be constructed or deleted + Tile() = delete; + Tile(const Tile&) = delete; + Tile& operator=(const Tile&) = delete; + ~Tile() = delete; + }; // if ValueType is a float this has a footprint of only 4 bytes! + + BBox mBBox; // 24B. node bounding box. | + int32_t mOffset; // 4B. number of node offsets till first child | 32B aligned + uint32_t mFlags; // 4B. node flags. | + MaskT mValueMask; // LOG2DIM(5): 4096B, LOG2DIM(4): 512B | 32B aligned + MaskT mChildMask; // LOG2DIM(5): 4096B, LOG2DIM(4): 512B | 32B aligned + + ValueT mMinimum; // typically 4B + ValueT mMaximum; // typically 4B + StatsT mAverage; // typically 4B, average of all the active values in this node and its child nodes + StatsT mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes + alignas(32) Tile mTable[1u << (3 * LOG2DIM)]; // sizeof(ValueT) x (16*16*16 or 32*32*32) + + /// @brief Returns a const pointer to the child node at the specifed linear offset. + __hostdev__ const ChildT* child(uint32_t n) const + { + assert(mChildMask.isOn(n)); + return reinterpret_cast(this + mOffset) + mTable[n].childID; + } + + /// @brief This class cannot be constructed or deleted + InternalData() = delete; + InternalData(const InternalData&) = delete; + InternalData& operator=(const InternalData&) = delete; + ~InternalData() = delete; +}; // InternalData + +/// @brief Interal nodes of a VDB treedim(), +template +class InternalNode : private InternalData +{ +public: + using LeafNodeType = typename ChildT::LeafNodeType; + using ChildNodeType = ChildT; + using ValueType = typename ChildT::ValueType; + using FloatType = typename ChildT::FloatType; + using CoordType = typename ChildT::CoordType; + template + using MaskType = typename ChildT::template MaskType; + using DataType = InternalData; + + static constexpr uint32_t LOG2DIM = Log2Dim; + static constexpr uint32_t TOTAL = LOG2DIM + ChildT::TOTAL; // dimension in index space + static constexpr uint32_t DIM = 1u << TOTAL; // number of voxels along each axis of this node + static constexpr uint32_t SIZE = 1u << (3 * LOG2DIM); // number of tile values (or child pointers) + static constexpr uint32_t MASK = (1u << TOTAL) - 1u; + static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf + static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node + //static constexpr bool IgnoreValues = ChildT::IgnoreValues; + + /// @brief This class cannot be constructed or deleted + InternalNode() = delete; + InternalNode(const InternalNode&) = delete; + InternalNode& operator=(const InternalNode&) = delete; + ~InternalNode() = delete; + + __hostdev__ DataType* data() { return reinterpret_cast(this); } + + __hostdev__ const DataType* data() const { return reinterpret_cast(this); } + + /// @brief Return the dimension, in voxel units, of this internal node (typically 8*16 or 8*16*32) + __hostdev__ static uint32_t dim() { return 1u << TOTAL; } + + /// @brief Return memory usage in bytes for the class + __hostdev__ static size_t memUsage() { return sizeof(DataType); } + + /// @brief Return a const reference to the bit mask of active voxels in this internal node + __hostdev__ const MaskType& valueMask() const { return DataType::mValueMask; } + + /// @brief Return a const reference to the bit mask of child nodes in this internal node + __hostdev__ const MaskType& childMask() const { return DataType::mChildMask; } + + /// @brief Return the origin in index space of this leaf node + __hostdev__ CoordType origin() const { return DataType::mBBox.min() & ~MASK; } + + /// @brief Return a const reference to the minimum active value encoded in this internal node and any of its child nodes + __hostdev__ const ValueType& valueMin() const { return DataType::mMinimum; } + + /// @brief Return a const reference to the maximum active value encoded in this internal node and any of its child nodes + __hostdev__ const ValueType& valueMax() const { return DataType::mMaximum; } + + /// @brief Return a const reference to the average of all the active values encoded in this internal node and any of its child nodes + __hostdev__ const FloatType& average() const { return DataType::mAverage; } + + /// @brief Return the variance of all the active values encoded in this internal node and any of its child nodes + __hostdev__ FloatType variance() const { return DataType::mStdDevi*DataType::mStdDevi; } + + /// @brief Return a const reference to the standard deviation of all the active values encoded in this internal node and any of its child nodes + __hostdev__ const FloatType& stdDeviation() const { return DataType::mStdDevi; } + + /// @brief Return a const reference to the bounding box in index space of active values in this internal node and any of its child nodes + __hostdev__ const BBox& bbox() const { return DataType::mBBox; } + + /// @brief Return the value of the given voxel + __hostdev__ const ValueType& getValue(const CoordType& ijk) const + { + const uint32_t n = CoordToOffset(ijk); + return DataType::mChildMask.isOn(n) ? this->child(n)->getValue(ijk) : DataType::mTable[n].value; + } + + __hostdev__ bool isActive(const CoordType& ijk) const + { + const uint32_t n = CoordToOffset(ijk); + return DataType::mChildMask.isOn(n) ? this->child(n)->isActive(ijk) : DataType::mValueMask.isOn(n); + } + + __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const + { + const uint32_t n = CoordToOffset(ijk); + if (DataType::mChildMask.isOn(n)) + return this->child(n)->probeValue(ijk, v); + v = DataType::mTable[n].value; + return DataType::mValueMask.isOn(n); + } + + __hostdev__ const LeafNodeType* probeLeaf(const CoordType& ijk) const + { + const uint32_t n = CoordToOffset(ijk); + if (DataType::mChildMask.isOn(n)) + return this->child(n)->probeLeaf(ijk); + return nullptr; + } + + /// @brief Return the linear offset corresponding to the given coordinate + __hostdev__ static uint32_t CoordToOffset(const CoordType& ijk) + { + return (((ijk[0] & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) + + (((ijk[1] & MASK) >> ChildT::TOTAL) << (LOG2DIM)) + + ((ijk[2] & MASK) >> ChildT::TOTAL); + } + + __hostdev__ static Coord OffsetToLocalCoord(uint32_t n) + { + assert(n < SIZE); + const uint32_t m = n & ((1 << 2 * LOG2DIM) - 1); + return Coord(n >> 2 * LOG2DIM, m >> LOG2DIM, m & ((1 << LOG2DIM) - 1)); + } + + __hostdev__ void localToGlobalCoord(Coord& ijk) const + { + ijk <<= ChildT::TOTAL; + ijk += this->origin(); + } + + __hostdev__ Coord offsetToGlobalCoord(uint32_t n) const + { + Coord ijk = InternalNode::OffsetToLocalCoord(n); + this->localToGlobalCoord(ijk); + return ijk; + } + + /// @brief Retrun true if this node or any of its child nodes contain active values + __hostdev__ bool isActive() const + { + return DataType::mFlags & uint32_t(2); + } + +private: + static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(InternalData) is misaligned"); + //static_assert(offsetof(DataType, mTable) % 32 == 0, "InternalData::mTable is misaligned"); + + template + friend class ReadAccessor; + + template + friend class RootNode; + template + friend class InternalNode; + + /// @biref Private read access method used by the ReadAccessor + template + __hostdev__ const ValueType& getValueAndCache(const CoordType& ijk, const AccT& acc) const + { + const uint32_t n = CoordToOffset(ijk); + if (!DataType::mChildMask.isOn(n)) + return DataType::mTable[n].value; + const ChildT* child = this->child(n); + acc.insert(ijk, child); + return child->getValueAndCache(ijk, acc); + } + + template + __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(const CoordType& ijk, const AccT& acc) const + { + using NodeInfoT = typename AccT::NodeInfo; + const uint32_t n = CoordToOffset(ijk); + if (!DataType::mChildMask.isOn(n)) { + return NodeInfoT{LEVEL, this->dim(), this->valueMin(), this->valueMax(), this->average(), + this->stdDeviation(), this->bbox()[0], this->bbox()[1]}; + } + const ChildT* child = this->child(n); + acc.insert(ijk, child); + return child->getNodeInfoAndCache(ijk, acc); + } + + template + __hostdev__ bool isActiveAndCache(const CoordType& ijk, const AccT& acc) const + { + const uint32_t n = CoordToOffset(ijk); + if (!DataType::mChildMask.isOn(n)) + return DataType::mValueMask.isOn(n); + const ChildT* child = this->child(n); + acc.insert(ijk, child); + return child->isActiveAndCache(ijk, acc); + } + + template + __hostdev__ bool probeValueAndCache(const CoordType& ijk, ValueType& v, const AccT& acc) const + { + const uint32_t n = CoordToOffset(ijk); + if (!DataType::mChildMask.isOn(n)) { + v = DataType::mTable[n].value; + return DataType::mValueMask.isOn(n); + } + const ChildT* child = this->child(n); + acc.insert(ijk, child); + return child->probeValueAndCache(ijk, v, acc); + } + + template + __hostdev__ const LeafNodeType* probeLeafAndCache(const CoordType& ijk, const AccT& acc) const + { + const uint32_t n = CoordToOffset(ijk); + if (!DataType::mChildMask.isOn(n)) + return nullptr; + const ChildT* child = this->child(n); + acc.insert(ijk, child); + return child->probeLeafAndCache(ijk, acc); + } + + template + __hostdev__ uint32_t getDimAndCache(const CoordType& ijk, const RayT& ray, const AccT& acc) const + { + if (DataType::mFlags & uint32_t(1)) + this->dim(); //ship this node if first bit is set + //if (!ray.intersects( this->bbox() )) return 1<child(n); + acc.insert(ijk, child); + return child->getDimAndCache(ijk, ray, acc); + } + return ChildNodeType::dim(); // tile value + } + +}; // InternalNode class + +// --------------------------> LeafNode <------------------------------------ + +/// @brief Stuct with all the member data of the LeafNode (useful during serialization of an openvdb LeafNode) +/// +/// @note No client code should (or can) interface with this struct so it can safely be ignored! +template class MaskT, uint32_t LOG2DIM> +struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData +{ + using ValueType = ValueT; + using FloatType = typename FloatTraits::FloatType; + //static constexpr bool IgnoreValues = false; + + CoordT mBBoxMin; // 12B. + uint8_t mBBoxDif[3]; // 3B. + uint8_t mFlags; // 1B. + MaskT mValueMask; // LOG2DIM(3): 64B. + + ValueType mMinimum; // typically 4B + ValueType mMaximum; // typically 4B + FloatType mAverage; // typically 4B, average of all the active values in this node and its child nodes + FloatType mStdDevi; //typically 4B, standard deviation of all the active values in this node and its child nodes + alignas(32) ValueType mValues[1u << 3 * LOG2DIM]; + + __hostdev__ const ValueType* values() const { return mValues; } + __hostdev__ const ValueType& value(uint32_t i) const { return mValues[i]; } + __hostdev__ void setValueOnly(uint32_t offset, const ValueType& value) { mValues[offset] = value; } + __hostdev__ void setValue(uint32_t offset, const ValueType& value) + { + mValueMask.setOn(offset); + mValues[offset] = value; + } + + __hostdev__ const ValueType& valueMin() const { return mMinimum; } + __hostdev__ const ValueType& valueMax() const { return mMaximum; } + __hostdev__ const FloatType& average() const { return mAverage; } + __hostdev__ const FloatType& stdDeviation() const { return mStdDevi; } + + /// @brief This class cannot be constructed or deleted + LeafData() = delete; + LeafData(const LeafData&) = delete; + LeafData& operator=(const LeafData&) = delete; + ~LeafData() = delete; +}; // LeafData + +// Partial template specialization of LeafData with ValueMask +template class MaskT, uint32_t LOG2DIM> +struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData +{ + using ValueType = uint32_t; // dummy value type + using FloatType = uint32_t; // dummy value type + //static constexpr bool IgnoreValues = true; + static const uint32_t mDummy; + + CoordT mBBoxMin; // 12B. + uint8_t mBBoxDif[3]; // 3B. + uint8_t mFlags; // 1B. + MaskT mValueMask; // LOG2DIM(3): 64B. + + __hostdev__ const ValueType* values() const { return nullptr; } + __hostdev__ const ValueType& value(uint32_t) const { return mDummy; } + __hostdev__ const ValueType& valueMin() const { return mDummy; } + __hostdev__ const ValueType& valueMax() const { return mDummy; } + __hostdev__ const FloatType& average() const { return mDummy; } + __hostdev__ const FloatType& stdDeviation() const { return mDummy; } + + /// @brief This class cannot be constructed or deleted + LeafData() = delete; + LeafData(const LeafData&) = delete; + LeafData& operator=(const LeafData&) = delete; + ~LeafData() = delete; +}; // LeafData + +template class MaskT, uint32_t LOG2DIM> +const uint32_t LeafData::mDummy = 1u; + +/// @brief Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels) +template class MaskT = Mask, + uint32_t Log2Dim = 3> +class LeafNode : private LeafData +{ +public: + struct ChildNodeType + { + __hostdev__ static uint32_t dim() { return 1u; } + }; // Voxel + using LeafNodeType = LeafNode; + using DataType = LeafData; + using ValueType = typename DataType::ValueType; + using FloatType = typename DataType::FloatType; + using CoordType = CoordT; + template + using MaskType = MaskT; + + static constexpr uint32_t LOG2DIM = Log2Dim; + static constexpr uint32_t TOTAL = LOG2DIM; // needed by parent nodes + static constexpr uint32_t DIM = 1u << TOTAL; // number of voxels along each axis of this node + static constexpr uint32_t SIZE = 1u << 3 * LOG2DIM; // total number of voxels represented by this node + static constexpr uint32_t MASK = (1u << LOG2DIM) - 1u; // mask for bit operations + static constexpr uint32_t LEVEL = 0; // level 0 = leaf + static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node + //static constexpr bool IgnoreValues = DataType::IgnoreValues; + + __hostdev__ DataType* data() { return reinterpret_cast(this); } + + __hostdev__ const DataType* data() const { return reinterpret_cast(this); } + + /// @brief Return a const reference to the bit mask of active voxels in this leaf node + __hostdev__ const MaskType& valueMask() const { return DataType::mValueMask; } + + /// @brief Return a const pointer to the c-style array of voxel values of this leaf node + __hostdev__ const ValueType* voxels() const { return DataType::values(); } + + /// @brief Return a const reference to the minimum active value encoded in this leaf node + __hostdev__ const ValueType& valueMin() const { return DataType::valueMin(); } + + /// @brief Return a const reference to the maximum active value encoded in this leaf node + __hostdev__ const ValueType& valueMax() const { return DataType::valueMax(); } + + /// @brief Return a const reference to the average of all the active values encoded in this leaf node + __hostdev__ const FloatType& average() const { return DataType::average(); } + + /// @brief Return the variance of all the active values encoded in this leaf node + __hostdev__ FloatType variance() const { return DataType::stdDeviation()*DataType::stdDeviation(); } + + /// @brief Return a const reference to the standard deviation of all the active values encoded in this leaf node + __hostdev__ const FloatType& stdDeviation() const { return DataType::stdDeviation(); } + + __hostdev__ uint8_t flags() const { return DataType::mFlags; } + + /// @brief Return the origin in index space of this leaf node + __hostdev__ CoordT origin() const { return DataType::mBBoxMin & ~MASK; } + + __hostdev__ static CoordT OffsetToLocalCoord(uint32_t n) + { + assert(n < SIZE); + const uint32_t m = n & ((1 << 2 * LOG2DIM) - 1); + return CoordT(n >> 2 * LOG2DIM, m >> LOG2DIM, m & MASK); + } + + /// @brief Converts (in place) a local index coordinate to a global index coordinate + __hostdev__ void localToGlobalCoord(Coord& ijk) const { ijk += this->origin(); } + + __hostdev__ CoordT offsetToGlobalCoord(uint32_t n) const + { + return OffsetToLocalCoord(n) + this->origin(); + } + + /// @brief Return the dimension, in index space, of this leaf node (typically 8 as for openvdb leaf nodes!) + __hostdev__ static uint32_t dim() { return 1u << LOG2DIM; } + + /// @brief Return the bounding box in index space of active values in this leaf node + __hostdev__ BBox bbox() const + { + BBox bbox(DataType::mBBoxMin, DataType::mBBoxMin); + if ( this->isActive() ) { + bbox.max()[0] += DataType::mBBoxDif[0]; + bbox.max()[1] += DataType::mBBoxDif[1]; + bbox.max()[2] += DataType::mBBoxDif[2]; + } else {// very rare case + bbox = BBox();// invalid + } + return bbox; + } + + /// @brief Return the total number of voxels (e.g. values) encoded in this leaf node + __hostdev__ static uint32_t voxelCount() { return 1u << (3 * LOG2DIM); } + + /// @brief return memory usage in bytes for the class + __hostdev__ static uint64_t memUsage() { return sizeof(LeafNodeType); } + + /// @brief This class cannot be constructed or deleted + LeafNode() = delete; + LeafNode(const LeafNode&) = delete; + LeafNode& operator=(const LeafNode&) = delete; + ~LeafNode() = delete; + + /// @brief Return the voxel value at the given offset. + __hostdev__ const ValueType& getValue(uint32_t offset) const { return DataType::value(offset); } + + /// @brief Return the voxel value at the given coordinate. + __hostdev__ const ValueType& getValue(const CoordT& ijk) const { return DataType::value(CoordToOffset(ijk)); } + + /// @brief Sets the value at the specified location and activate its state. + /// + /// @note This is safe since it does not change the topology of the tree (unlike setValue methods on the other nodes) + __hostdev__ void setValue(const CoordT& ijk, const ValueType& v) { DataType::setValue(CoordToOffset(ijk), v); } + + /// @brief Sets the value at the specified location but leaves its state unchanged. + /// + /// @note This is safe since it does not change the topology of the tree (unlike setValue methods on the other nodes) + __hostdev__ void setValueOnly(const CoordT& ijk, const ValueType& v) { DataType::setValueOnly(CoordToOffset(ijk), v); } + + /// @brief Return @c true if the voxel value at the given coordinate is active. + __hostdev__ bool isActive(const CoordT& ijk) const { return DataType::mValueMask.isOn(CoordToOffset(ijk)); } + __hostdev__ bool isActive(uint32_t n) const { return DataType::mValueMask.isOn(n); } + + /// @brief Return @c true if any of the voxel value are active in this leaf node. + __hostdev__ bool isActive() const + { + assert( bool(DataType::mFlags & uint8_t(2)) != DataType::mValueMask.isOff() ); + return DataType::mFlags & uint8_t(2); + } + + + /// @brief Return @c true if the voxel value at the given coordinate is active and updates @c v with the value. + __hostdev__ bool probeValue(const CoordT& ijk, ValueType& v) const + { + const uint32_t n = CoordToOffset(ijk); + v = DataType::value(n); + return DataType::mValueMask.isOn(n); + } + + __hostdev__ const LeafNode* probeLeaf(const CoordT&) const { return this; } + + /// @brief Return the linear offset corresponding to the given coordinate + __hostdev__ static uint32_t CoordToOffset(const CoordT& ijk) + { + return ((ijk[0] & MASK) << (2 * LOG2DIM)) + ((ijk[1] & MASK) << LOG2DIM) + (ijk[2] & MASK); + } + + /// @brief Updates the local bounding box of active voxels in this node. + /// + /// @warning It assumes that the origin and value mask have already been set. + /// + /// @details This method is based on few (intrinsic) bit operations and hence is relatively fast. + /// However, it should only only be called of either the value mask has changed or if the + /// active bounding box is still undefined. e.g. during constrution of this node. + __hostdev__ void updateBBox(); + +private: + static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(LeafData) is misaligned"); + //static_assert(offsetof(DataType, mValues) % 32 == 0, "LeafData::mValues is misaligned"); + + template + friend class ReadAccessor; + + template + friend class RootNode; + template + friend class InternalNode; + + /// @brief Private method to return a voxel value and update a (dummy) ReadAccessor + template + __hostdev__ const ValueType& getValueAndCache(const CoordT& ijk, const AccT&) const { return this->getValue(ijk); } + + /// @brief Return the node information. + template + __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(const CoordType& /*ijk*/, const AccT& /*acc*/) const { + using NodeInfoT = typename AccT::NodeInfo; + return NodeInfoT{LEVEL, this->dim(), this->valueMin(), this->valueMax(), + this->average(), this->stdDeviation(), this->bbox()[0], this->bbox()[1]}; + } + + template + __hostdev__ bool isActiveAndCache(const CoordT& ijk, const AccT&) const { return this->isActive(ijk); } + + template + __hostdev__ bool probeValueAndCache(const CoordT& ijk, ValueType& v, const AccT&) const { return this->probeValue(ijk, v); } + + template + __hostdev__ const LeafNode* probeLeafAndCache(const CoordT&, const AccT&) const { return this; } + + template + __hostdev__ uint32_t getDimAndCache(const CoordT&, const RayT& /*ray*/, const AccT&) const + { + if (DataType::mFlags & uint8_t(1)) + return this->dim(); // skip this node if first bit is set + //if (!ray.intersects( this->bbox() )) return 1 << LOG2DIM; + return ChildNodeType::dim(); + } + +}; // LeafNode class + +template class MaskT, uint32_t LOG2DIM> +inline void LeafNode::updateBBox() +{ + static_assert(LOG2DIM == 3, "LeafNode::updateBBox: only supports LOGDIM = 3!"); + if (!this->isActive()) return; + auto update = [&](uint32_t min, uint32_t max, int axis) { + assert(min <= max && max < 8); + DataType::mBBoxMin[axis] = (DataType::mBBoxMin[axis] & ~MASK) + int(min); + DataType::mBBoxDif[axis] = uint8_t(max - min); + }; + uint64_t word64 = DataType::mValueMask.template getWord(0); + uint32_t Xmin = word64 ? 0u : 8u, Xmax = Xmin; + for (int i = 1; i < 8; ++i) { // last loop over 8 64 words + if (uint64_t w = DataType::mValueMask.template getWord(i)) { // skip if word has no set bits + word64 |= w; // union 8 x 64 bits words into one 64 bit word + if (Xmin == 8) + Xmin = i; // only set once + Xmax = i; + } + } + assert(word64); + update(Xmin, Xmax, 0); + update(FindLowestOn(word64) >> 3, FindHighestOn(word64) >> 3, 1); + const uint32_t *p = reinterpret_cast(&word64), word32 = p[0] | p[1]; + const uint16_t *q = reinterpret_cast(&word32), word16 = q[0] | q[1]; + const uint8_t *b = reinterpret_cast(&word16), byte = b[0] | b[1]; + assert(byte); + update(FindLowestOn(static_cast(byte)), FindHighestOn(static_cast(byte)), 2); +} + +// --------------------------> Template specializations and traits <------------------------------------ + +/// @brief Template specializations to the default configuration used in OpenVDB: +/// Root->32^3->16^3->8^3 +template +using NanoLeaf = LeafNode; +template +using NanoNode1 = InternalNode, 4>; +template +using NanoNode2 = InternalNode, 5>; +template +using NanoRoot = RootNode>; +template +using NanoTree = Tree>; +template +using NanoGrid = Grid>; + +using FloatTree = NanoTree; +using DoubleTree = NanoTree; +using Int32Tree = NanoTree; +using UInt32Tree = NanoTree; +using Int64Tree = NanoTree; +using Vec3fTree = NanoTree; +using Vec3dTree = NanoTree; +using Vec3ITree = NanoTree; +using MaskTree = NanoTree; + +using FloatGrid = Grid; +using DoubleGrid = Grid; +using Int32Grid = Grid; +using UInt32Grid = Grid; +using Int64Grid = Grid; +using Vec3fGrid = Grid; +using Vec3dGrid = Grid; +using Vec3IGrid = Grid; +using MaskGrid = Grid; + +// --------------------------> ReadAccessor <------------------------------------ + +/// @brief A read-only value accessor with three levels of node caching. This allows for +/// inverse tree traversal during lookup, which is on average significantly faster +/// than calling the equivalent method on the tree (i.e. top-down traversal). +/// +/// @note By virtue of the fact that a value accessor accelerates random access operations +/// by re-using cached access patterns, this access should be reused for multiple access +/// operations. In other words, never create an instance of this accessor for a single +/// acccess only. In general avoid single access operations with this accessor, and +/// if that is not possible call the corresponding method on the tree instead. +/// +/// @warning Since this ReadAccessor internally caches raw pointers to the nodes of the tree +/// structure, it is not safe to copy between host and device, or even to share among +/// multiple threads on the same host or device. However, it is light-weight so simple +/// instantiate one per thread (on the host and/or device). +/// +/// @details Used to accelerated random access into a VDB tree. Provides on average +/// O(1) random access operations by means of inverse tree traversal, +/// which amortizes the non-const time complexity of the root node. + +template +class ReadAccessor +{ + using RootT = NanoRoot; // root node + using FloatType = typename RootT::FloatType; + using CoordValueType = typename RootT::CoordType::ValueType; + + mutable const RootT* mRoot; // 8 bytes (mutable to allow for access methods to be const) +public: + using ValueType = ValueT; + using CoordType = typename RootT::CoordType; + + static const int CacheLevels = 0; + + struct NodeInfo { + uint32_t mLevel; // 4B + uint32_t mDim; // 4B + ValueType mMinimum; // typically 4B + ValueType mMaximum; // typically 4B + FloatType mAverage; // typically 4B + FloatType mStdDevi; // typically 4B + CoordType mBBoxMin; // 3*4B + CoordType mBBoxMax; // 3*4B + }; + + /// @brief Constructor from a root node + __hostdev__ ReadAccessor(const RootT& root) : mRoot{&root} {} + + __hostdev__ const RootT& root() const { return *mRoot; } + + /// @brief Defaults constructors + ReadAccessor(const ReadAccessor&) = default; + ~ReadAccessor() = default; + ReadAccessor& operator=(const ReadAccessor&) = default; + + __hostdev__ const ValueType& getValue(const CoordType& ijk) const + { + return mRoot->getValueAndCache(ijk, *this); + } + + __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const + { + return mRoot->getNodeInfoAndCache(ijk, *this); + } + + __hostdev__ bool isActive(const CoordType& ijk) const + { + return mRoot->isActiveAndCache(ijk, *this); + } + + __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const + { + return mRoot->probeValueAndCache(ijk, v, *this); + } + + __hostdev__ const NanoLeaf* probeLeaf(const CoordType& ijk) const + { + return mRoot->probeLeafAndCache(ijk, *this); + } + + template + __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const + { + return mRoot->getDimAndCache(ijk, ray, *this); + } + +private: + /// @brief Allow nodes to insert themselves into the cache. + template + friend class RootNode; + template + friend class InternalNode; + template class, uint32_t> + friend class LeafNode; + + /// @brief No-op + template + __hostdev__ void insert(const CoordType&, const NodeT*) const {} +}; // ReadAccessor class + +/// @brief Node caching at a single tree level +template +class ReadAccessor// 0, 1, 2 +{ + static_assert(LEVEL0 >= 0 && LEVEL0 <= 2, "LEVEL0 should be 0, 1, 2"); + + using TreeT = NanoTree; + using RootT = NanoRoot; // root node + using LeafT = NanoLeaf< ValueT>; // Leaf node + using NodeT = typename TreeNode::type; + using CoordT = typename RootT::CoordType; + + using FloatType = typename RootT::FloatType; + using CoordValueType = typename RootT::CoordT::ValueType; + + // All member data are mutable to allow for access methods to be const + mutable CoordT mKey; // 3*4 = 12 bytes + mutable const RootT* mRoot; // 8 bytes + mutable const NodeT* mNode; // 8 bytes + +public: + using ValueType = ValueT; + using CoordType = CoordT; + + static const int CacheLevels = 1; + + using NodeInfo = typename ReadAccessor::NodeInfo; + + /// @brief Constructor from a root node + __hostdev__ ReadAccessor(const RootT& root) + : mKey(CoordType::max()) + , mRoot(&root) + , mNode(nullptr) + { + } + + __hostdev__ const RootT& root() const { return *mRoot; } + + /// @brief Defaults constructors + ReadAccessor(const ReadAccessor&) = default; + ~ReadAccessor() = default; + ReadAccessor& operator=(const ReadAccessor&) = default; + + __hostdev__ bool isCached(const CoordType& ijk) const + { + return (ijk[0] & int32_t(~NodeT::MASK)) == mKey[0] && + (ijk[1] & int32_t(~NodeT::MASK)) == mKey[1] && + (ijk[2] & int32_t(~NodeT::MASK)) == mKey[2]; + } + + __hostdev__ const ValueType& getValue(const CoordType& ijk) const + { + if (this->isCached(ijk)) { + return mNode->getValueAndCache(ijk, *this); + } + return mRoot->getValueAndCache(ijk, *this); + } + + __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const + { + if (this->isCached(ijk)) { + return mNode->getNodeInfoAndCache(ijk, *this); + } + return mRoot->getNodeInfoAndCache(ijk, *this); + } + + __hostdev__ bool isActive(const CoordType& ijk) const + { + if (this->isCached(ijk)) { + return mNode->isActiveAndCache(ijk, *this); + } + return mRoot->isActiveAndCache(ijk, *this); + } + + __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const + { + if (this->isCached(ijk)) { + return mNode->probeValueAndCache(ijk, v, *this); + } + return mRoot->probeValueAndCache(ijk, v, *this); + } + + __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const + { + if (this->isCached(ijk)) { + return mNode->probeLeafAndCache(ijk, *this); + } + return mRoot->probeLeafAndCache(ijk, *this); + } + + template + __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const + { + if (this->isCached(ijk)) { + return mNode->getDimAndCache(ijk, ray, *this); + } + return mRoot->getDimAndCache(ijk, ray, *this); + } + +private: + /// @brief Allow nodes to insert themselves into the cache. + template + friend class RootNode; + template + friend class InternalNode; + template class, uint32_t> + friend class LeafNode; + + /// @brief Inserts a leaf node and key pair into this ReadAccessor + __hostdev__ void insert(const CoordType& ijk, const NodeT* node) const + { + mKey = ijk & ~NodeT::MASK; + mNode = node; + } + + // no-op + template + __hostdev__ void insert(const CoordType&, const OtherNodeT*) const {} + +}; // ReadAccessor + +template +class ReadAccessor// (0,1), (1,2), (0,2) +{ + static_assert(LEVEL0 >=0 && LEVEL0 <=2, "LEVEL0 must be 0, 1, 2"); + static_assert(LEVEL1 >=0 && LEVEL1 <=2, "LEVEL1 must be 0, 1, 2"); + static_assert(LEVEL0 < LEVEL1, "Level 0 must be lower than level 1"); + using TreeT = NanoTree; + using RootT = NanoRoot; + using LeafT = NanoLeaf; + using Node1T = typename TreeNode::type; + using Node2T = typename TreeNode::type; + using CoordT = typename RootT::CoordType; + + using FloatType = typename RootT::FloatType; + using CoordValueType = typename RootT::CoordT::ValueType; + + // All member data are mutable to allow for access methods to be const +#ifdef USE_SINGLE_ACCESSOR_KEY // 44 bytes total + mutable CoordT mKey; // 3*4 = 12 bytes +#else // 68 bytes total + mutable CoordT mKeys[2]; // 2*3*4 = 24 bytes +#endif + mutable const RootT* mRoot; + mutable const Node1T* mNode1; + mutable const Node2T* mNode2; + +public: + using ValueType = ValueT; + using CoordType = CoordT; + + static const int CacheLevels = 2; + + using NodeInfo = typename ReadAccessor::NodeInfo; + + /// @brief Constructor from a root node + __hostdev__ ReadAccessor(const RootT& root) +#ifdef USE_SINGLE_ACCESSOR_KEY + : mKey(CoordType::max()) +#else + : mKeys{CoordType::max(), CoordType::max()} +#endif + , mRoot(&root) + , mNode1(nullptr) + , mNode2(nullptr) + { + } + + __hostdev__ const RootT& root() const { return *mRoot; } + + /// @brief Defaults constructors + ReadAccessor(const ReadAccessor&) = default; + ~ReadAccessor() = default; + ReadAccessor& operator=(const ReadAccessor&) = default; + +#ifdef USE_SINGLE_ACCESSOR_KEY + __hostdev__ bool isCached1(CoordValueType dirty) const + { + if (!mNode1) + return false; + if (dirty & int32_t(~Node1T::MASK)) { + mNode1 = nullptr; + return false; + } + return true; + } + __hostdev__ bool isCached2(CoordValueType dirty) const + { + if (!mNode2) + return false; + if (dirty & int32_t(~Node2T::MASK)) { + mNode2 = nullptr; + return false; + } + return true; + } + __hostdev__ CoordValueType computeDirty(const CoordType& ijk) const + { + return (ijk[0] ^ mKey[0]) | (ijk[1] ^ mKey[1]) | (ijk[2] ^ mKey[2]); + } +#else + __hostdev__ bool isCached1(const CoordType& ijk) const + { + return (ijk[0] & int32_t(~Node1T::MASK)) == mKeys[0][0] && + (ijk[1] & int32_t(~Node1T::MASK)) == mKeys[0][1] && + (ijk[2] & int32_t(~Node1T::MASK)) == mKeys[0][2]; + } + __hostdev__ bool isCached2(const CoordType& ijk) const + { + return (ijk[0] & int32_t(~Node2T::MASK)) == mKeys[1][0] && + (ijk[1] & int32_t(~Node2T::MASK)) == mKeys[1][1] && + (ijk[2] & int32_t(~Node2T::MASK)) == mKeys[1][2]; + } +#endif + + __hostdev__ const ValueType& getValue(const CoordType& ijk) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); +#else + auto&& dirty = ijk; +#endif + if (this->isCached1(dirty)) { + return mNode1->getValueAndCache(ijk, *this); + } else if (this->isCached2(dirty)) { + return mNode2->getValueAndCache(ijk, *this); + } + return mRoot->getValueAndCache(ijk, *this); + } + + __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); +#else + auto&& dirty = ijk; +#endif + if (this->isCached1(dirty)) { + return mNode1->getNodeInfoAndCache(ijk, *this); + } else if (this->isCached2(dirty)) { + return mNode2->getNodeInfoAndCache(ijk, *this); + } + return mRoot->getNodeInfoAndCache(ijk, *this); + } + + __hostdev__ bool isActive(const CoordType& ijk) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); +#else + auto&& dirty = ijk; +#endif + if (this->isCached1(dirty)) { + return mNode1->isActiveAndCache(ijk, *this); + } else if (this->isCached2(dirty)) { + return mNode2->isActiveAndCache(ijk, *this); + } + return mRoot->isActiveAndCache(ijk, *this); + } + + __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); +#else + auto&& dirty = ijk; +#endif + if (this->isCached1(dirty)) { + return mNode1->probeValueAndCache(ijk, v, *this); + } else if (this->isCached2(dirty)) { + return mNode2->probeValueAndCache(ijk, v, *this); + } + return mRoot->probeValueAndCache(ijk, v, *this); + } + + __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); +#else + auto&& dirty = ijk; +#endif + if (this->isCached1(dirty)) { + return mNode1->probeLeafAndCache(ijk, *this); + } else if (this->isCached2(dirty)) { + return mNode2->probeLeafAndCache(ijk, *this); + } + return mRoot->probeLeafAndCache(ijk, *this); + } + + template + __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); +#else + auto&& dirty = ijk; +#endif + if (this->isCached1(dirty)) { + return mNode1->getDimAndCache(ijk, ray, *this); + } else if (this->isCached2(dirty)) { + return mNode2->getDimAndCache(ijk, ray, *this); + } + return mRoot->getDimAndCache(ijk, ray, *this); + } + +private: + /// @brief Allow nodes to insert themselves into the cache. + template + friend class RootNode; + template + friend class InternalNode; + template class, uint32_t> + friend class LeafNode; + + /// @brief Inserts a leaf node and key pair into this ReadAccessor + __hostdev__ void insert(const CoordType& ijk, const Node1T* node) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + mKey = ijk; +#else + mKeys[0] = ijk & ~NodeT::MASK; +#endif + mNode1 = node; + } + __hostdev__ void insert(const CoordType& ijk, const Node2T* node) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + mKey = ijk; +#else + mKeys[1] = ijk & ~NodeT::MASK; +#endif + mNode2 = node; + } + template + __hostdev__ void insert(const CoordType&, const OtherNodeT*) const {} +}; // ReadAccessor + + +/// @brief Node caching at all (three) tree levels +template +class ReadAccessor +{ + using TreeT = NanoTree; + using RootT = NanoRoot; // root node + using NodeT2 = NanoNode2; // upper internal node + using NodeT1 = NanoNode1; // lower internal node + using LeafT = NanoLeaf< ValueT>; // Leaf node + using CoordT = typename RootT::CoordType; + + using FloatType = typename RootT::FloatType; + using CoordValueType = typename RootT::CoordT::ValueType; + + // All member data are mutable to allow for access methods to be const +#ifdef USE_SINGLE_ACCESSOR_KEY // 44 bytes total + mutable CoordT mKey; // 3*4 = 12 bytes +#else // 68 bytes total + mutable CoordT mKeys[3]; // 3*3*4 = 36 bytes +#endif + mutable const RootT* mRoot; + mutable const void* mNode[3]; // 4*8 = 32 bytes + +public: + using ValueType = ValueT; + using CoordType = CoordT; + + static const int CacheLevels = 3; + + using NodeInfo = typename ReadAccessor::NodeInfo; + + /// @brief Constructor from a root node + __hostdev__ ReadAccessor(const RootT& root) +#ifdef USE_SINGLE_ACCESSOR_KEY + : mKey(CoordType::max()) +#else + : mKeys{CoordType::max(), CoordType::max(), CoordType::max()} +#endif + , mRoot(&root) + , mNode{nullptr, nullptr, nullptr} + { + } + + __hostdev__ const RootT& root() const { return *mRoot; } + + /// @brief Defaults constructors + ReadAccessor(const ReadAccessor&) = default; + ~ReadAccessor() = default; + ReadAccessor& operator=(const ReadAccessor&) = default; + + /// @brief Return a const point to the cached node of the specified type + /// + /// @warning The return value could be NULL. + template + __hostdev__ const NodeT* getNode() const + { + using T = typename TreeNode::type; + static_assert(is_same::value, "ReadAccessor::getNode: Invalid node type"); + return reinterpret_cast(mNode[NodeT::LEVEL]); + } + +#ifdef USE_SINGLE_ACCESSOR_KEY + template + __hostdev__ bool isCached(CoordValueType dirty) const + { + if (!mNode[NodeT::LEVEL]) + return false; + if (dirty & int32_t(~NodeT::MASK)) { + mNode[NodeT::LEVEL] = nullptr; + return false; + } + return true; + } + + __hostdev__ CoordValueType computeDirty(const CoordType& ijk) const + { + return (ijk[0] ^ mKey[0]) | (ijk[1] ^ mKey[1]) | (ijk[2] ^ mKey[2]); + } +#else + template + __hostdev__ bool isCached(const CoordType& ijk) const + { + return (ijk[0] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][0] && (ijk[1] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][1] && (ijk[2] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][2]; + } +#endif + + __hostdev__ const ValueType& getValue(const CoordType& ijk) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); +#else + auto&& dirty = ijk; +#endif + if (this->isCached(dirty)) { + return ((LeafT*)mNode[0])->getValue(ijk); + } else if (this->isCached(dirty)) { + return ((NodeT1*)mNode[1])->getValueAndCache(ijk, *this); + } else if (this->isCached(dirty)) { + return ((NodeT2*)mNode[2])->getValueAndCache(ijk, *this); + } + return mRoot->getValueAndCache(ijk, *this); + } + + __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); +#else + auto&& dirty = ijk; +#endif + if (this->isCached(dirty)) { + return ((LeafT*)mNode[0])->getNodeInfoAndCache(ijk, *this); + } else if (this->isCached(dirty)) { + return ((NodeT1*)mNode[1])->getNodeInfoAndCache(ijk, *this); + } else if (this->isCached(dirty)) { + return ((NodeT2*)mNode[2])->getNodeInfoAndCache(ijk, *this); + } + return mRoot->getNodeInfoAndCache(ijk, *this); + } + + __hostdev__ bool isActive(const CoordType& ijk) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); +#else + auto&& dirty = ijk; +#endif + if (this->isCached(dirty)) { + return ((LeafT*)mNode[0])->isActive(ijk); + } else if (this->isCached(dirty)) { + return ((NodeT1*)mNode[1])->isActiveAndCache(ijk, *this); + } else if (this->isCached(dirty)) { + return ((NodeT2*)mNode[2])->isActiveAndCache(ijk, *this); + } + return mRoot->isActiveAndCache(ijk, *this); + } + + __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); +#else + auto&& dirty = ijk; +#endif + if (this->isCached(dirty)) { + return ((LeafT*)mNode[0])->probeValue(ijk, v); + } else if (this->isCached(dirty)) { + return ((NodeT1*)mNode[1])->probeValueAndCache(ijk, v, *this); + } else if (this->isCached(dirty)) { + return ((NodeT2*)mNode[2])->probeValueAndCache(ijk, v, *this); + } + return mRoot->probeValueAndCache(ijk, v, *this); + } + + __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); +#else + auto&& dirty = ijk; +#endif + if (this->isCached(dirty)) { + return ((LeafT*)mNode[0]); + } else if (this->isCached(dirty)) { + return ((NodeT1*)mNode[1])->probeLeafAndCache(ijk, *this); + } else if (this->isCached(dirty)) { + return ((NodeT2*)mNode[2])->probeLeafAndCache(ijk, *this); + } + return mRoot->probeLeafAndCache(ijk, *this); + } + + template + __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); +#else + auto&& dirty = ijk; +#endif + if (this->isCached(dirty)) { + return ((LeafT*)mNode[0])->getDimAndCache(ijk, ray, *this); + } else if (this->isCached(dirty)) { + return ((NodeT1*)mNode[1])->getDimAndCache(ijk, ray, *this); + } else if (this->isCached(dirty)) { + return ((NodeT2*)mNode[2])->getDimAndCache(ijk, ray, *this); + } + return mRoot->getDimAndCache(ijk, ray, *this); + } + +private: + /// @brief Allow nodes to insert themselves into the cache. + template + friend class RootNode; + template + friend class InternalNode; + template class, uint32_t> + friend class LeafNode; + + /// @brief Inserts a leaf node and key pair into this ReadAccessor + template + __hostdev__ void insert(const CoordType& ijk, const NodeT* node) const + { +#ifdef USE_SINGLE_ACCESSOR_KEY + mKey = ijk; +#else + mKeys[NodeT::LEVEL] = ijk & ~NodeT::MASK; +#endif + mNode[NodeT::LEVEL] = node; + } +}; // ReadAccessor + +////////////////////////////////////////////////// + +/// @brief Free-standing function for convenient creation of a ReadAccessor with +/// optional and customizable node caching. +/// +/// @details createAccessor<>(grid): No caching of nodes and hence it's thread-safe but slow +/// createAccessor<0>(grid): Caching of leaf nodes only +/// createAccessor<1>(grid): Caching of lower internal nodes only +/// createAccessor<2>(grid): Caching of upper internal nodes only +/// createAccessor<0,1>(grid): Caching of leaf and lower internal nodes +/// createAccessor<0,2>(grid): Caching of leaf and upper internal nodes +/// createAccessor<1,2>(grid): Caching of lower and upper internal nodes +/// createAccessor<0,1,0>(grid): Caching of all nodes at all tree levels + +template +ReadAccessor createAccessor(const NanoGrid &grid) +{ + return ReadAccessor(grid.tree().root()); +} + +template +ReadAccessor createAccessor(const NanoTree &tree) +{ + return ReadAccessor(tree().root()); +} + +template +ReadAccessor createAccessor(const NanoRoot &root) +{ + return ReadAccessor(root); +} + +////////////////////////////////////////////////// + +/// @brief This is a convenient class that allows for access to grid meta-data +/// that are independent of the value type of a grid. That is, this class +/// can be used to get information about a grid without actually knowing +/// its ValueType. +class GridMetaData +{ + // We cast to a grid templated on a dummy ValueType which is safe because we are very + // careful only to call certain methods which are known to be invariant to the ValueType! + // In other words, don't use this technique unless you are intimately familiar with the + // memory-layout of the data structure and the reasons why certain methods are safe + // to call and others are not! + using GridT = NanoGrid; + __hostdev__ const GridT& grid() const { return *reinterpret_cast(this); } + +public: + __hostdev__ bool isValid() const { return this->grid().isValid(); } + __hostdev__ const char* gridName() const { return this->grid().gridName(); } + __hostdev__ GridType gridType() const { return this->grid().gridType(); } + __hostdev__ GridClass gridClass() const { return this->grid().gridClass(); } + __hostdev__ bool isLevelSet() const { return this->grid().isLevelSet(); } + __hostdev__ bool isFogVolume() const { return this->grid().isFogVolume(); } + __hostdev__ bool isPointIndex() const { return this->grid().isPointIndex(); } + __hostdev__ bool isPointData() const { return this->grid().isPointData(); } + __hostdev__ bool isStaggered() const { return this->grid().isStaggered(); } + __hostdev__ bool isUnknown() const { return this->grid().isUnknown(); } + __hostdev__ const Map& map() const { return this->grid().map(); } + __hostdev__ const BBox& worldBBox() const { return this->grid().worldBBox(); } + __hostdev__ const BBox& indexBBox() const { return this->grid().indexBBox(); } + __hostdev__ Vec3R voxelSize() const { return this->grid().voxelSize(); } + __hostdev__ int blindDataCount() const { return this->grid().blindDataCount(); } + __hostdev__ const GridBlindMetaData& blindMetaData(int n) const { return this->grid().blindMetaData(n); } + __hostdev__ uint64_t activeVoxelCount() const { return this->grid().activeVoxelCount(); } + __hostdev__ uint32_t nodeCount(uint32_t level) const { return this->grid().tree().nodeCount(level); } + __hostdev__ uint64_t checksum() const { return this->grid().checksum(); } + __hostdev__ bool isEmpty() const { return this->grid().isEmpty(); } + __hostdev__ Version version() const { return this->grid().version(); } +}; // GridMetaData + +/// @brief Class to access points at a specific voxel location +template +class PointAccessor : public DefaultReadAccessor +{ + using AccT = DefaultReadAccessor; + const UInt32Grid* mGrid; + const AttT* mData; + +public: + using LeafNodeType = typename NanoRoot::LeafNodeType; + + PointAccessor(const UInt32Grid& grid) + : AccT(grid.tree().root()) + , mGrid(&grid) + , mData(reinterpret_cast(grid.blindData(0))) + { + assert(grid.gridType() == GridType::UInt32); + assert((grid.gridClass() == GridClass::PointIndex && is_same::value) || + (grid.gridClass() == GridClass::PointData && is_same::value)); + assert(grid.blindDataCount() >= 1); + } + /// @brief Return the total number of point in the grid and set the + /// iterators to the complete range of points. + __hostdev__ uint64_t gridPoints(const AttT*& begin, const AttT*& end) const + { + const uint64_t count = mGrid->blindMetaData(0).mElementCount; + begin = mData; + end = begin + count; + return count; + } + /// @brief Return the number of points in the leaf node containing the coordinate @a ijk. + /// If this return value is larger than zero then the iterators @a begin and @end + /// will point to all the attributes contained within that leaf node. + __hostdev__ uint64_t leafPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const + { + auto* leaf = this->probeLeaf(ijk); + if (leaf == nullptr) { + return 0; + } + begin = mData + leaf->valueMin(); + end = begin + leaf->valueMax(); + return leaf->valueMax(); + } + + /// @brief get iterators over offsets to points at a specific voxel location + __hostdev__ uint64_t voxelPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const + { + auto* leaf = this->probeLeaf(ijk); + if (leaf == nullptr) + return 0; + const uint32_t offset = LeafNodeType::CoordToOffset(ijk); + if (leaf->isActive(offset)) { + auto* p = mData + leaf->valueMin(); + begin = p + (offset == 0 ? 0 : leaf->getValue(offset - 1)); + end = p + leaf->getValue(offset); + return end - begin; + } + return 0; + } +}; // PointAccessor + +} // namespace nanovdb + +#endif // end of NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/GridHandle.h b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/GridHandle.h new file mode 100644 index 00000000..eef49931 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/GridHandle.h @@ -0,0 +1,195 @@ +// Copyright Contributors to the OpenVDB Project +// SPDX-License-Identifier: MPL-2.0 + +/*! + \file GridHandle.h + + \author Ken Museth + + \date January 8, 2020 + + \brief Defines two classes, a GridRegister the defines the value type (e.g. Double, Float etc) + of a NanoVDB grid, and a GridHandle and manages the memory of a NanoVDB grid. + + \note This file has NO dependency on OpenVDB. +*/ + +#ifndef NANOVDB_GRID_HANDLE_H_HAS_BEEN_INCLUDED +#define NANOVDB_GRID_HANDLE_H_HAS_BEEN_INCLUDED + +#include "../NanoVDB.h"// for mapToGridType +#include "HostBuffer.h" + +#include // for std::ifstream +#include // for std::cerr/cout +#include // for std::string +#include // for std::is_pod + +namespace nanovdb { + +template +struct BufferTraits +{ + static const bool hasDeviceDual = false; +}; + +// --------------------------> GridHandleBase <------------------------------------ + +class GridHandleBase +{ +public: + virtual ~GridHandleBase() {} + + /// @brief Returns the size in bytes of the raw memory buffer managed by this GridHandle's allocator. + virtual uint64_t size() const = 0; + + virtual uint8_t* data() = 0; + virtual const uint8_t* data() const = 0; + + /// @brief Return true if this handle is empty, i.e. has no allocated memory + bool empty() const { return size() == 0; } + + /// @brief Return true if this handle contains a grid + operator bool() const { return !empty(); } + + /// @brief Returns a const point to the grid meta data (see definition above). + /// + /// @warning Note that the return pointer can be NULL if the GridHandle was not initialized + const GridMetaData* gridMetaData() const { return reinterpret_cast(data()); } +}; + +// --------------------------> GridHandle <------------------------------------ + +/// @brief This class serves to manage a raw memory buffer of a NanoVDB Grid. +/// +/// @note It is important to note that is class does NOT depend on OpenVDB. +template +class GridHandle : public GridHandleBase +{ + BufferT mBuffer; + +public: + GridHandle(BufferT&& resources); + + GridHandle() = default; + /// @brief Disallow copy-construction + GridHandle(const GridHandle&) = delete; + /// @brief Disallow copy assignment operation + GridHandle& operator=(const GridHandle&) = delete; + /// @brief Move copy assignment operation + GridHandle& operator=(GridHandle&& other) noexcept + { + mBuffer = std::move(other.mBuffer); + return *this; + } + /// @brief Move copy-constructor + GridHandle(GridHandle&& other) noexcept + { + mBuffer = std::move(other.mBuffer); + } + /// @brief Default destructor + ~GridHandle() override { reset(); } + + void reset() { mBuffer.clear(); } + + BufferT& buffer() { return mBuffer; } + const BufferT& buffer() const { return mBuffer; } + + /// @brief Returns a non-const pointer to the data. + /// + /// @warning Note that the return pointer can be NULL if the GridHandle was not initialized + uint8_t* data() override + { + return mBuffer.data(); + } + + /// @brief Returns a const pointer to the data. + /// + /// @warning Note that the return pointer can be NULL if the GridHandle was not initialized + const uint8_t* data() const override + { + return mBuffer.data(); + } + + /// @brief Returns the size in bytes of the raw memory buffer managed by this GridHandle's allocator. + uint64_t size() const override + { + return mBuffer.size(); + } + + /// @brief Returns a const pointer to the NanoVDB grid encoded in the GridHandle. + /// + /// @warning Note that the return pointer can be NULL if the GridHandle was not initialized or the template + /// parameter does not match! + template + const NanoGrid* grid() const; + + template + NanoGrid* grid(); + + template + typename std::enable_if::hasDeviceDual, const NanoGrid*>::type + deviceGrid() const; + + template + typename std::enable_if::hasDeviceDual, void>::type + deviceUpload(void* stream = nullptr, bool sync = true); + + template + typename std::enable_if::hasDeviceDual, void>::type + deviceDownload(void* stream = nullptr, bool sync = true); +}; // GridHandle + +// --------------------------> Implementation of GridHandle <------------------------------------ + +template +GridHandle::GridHandle(BufferT&& resources) +{ + mBuffer = std::move(resources); +} + +template +template +inline const NanoGrid* GridHandle::grid() const +{ + using GridT = const NanoGrid; + GridT* grid = reinterpret_cast(mBuffer.data()); + return (grid && grid->gridType() == mapToGridType()) ? grid : nullptr; +} + +template +template +inline NanoGrid* GridHandle::grid() +{ + using GridT = NanoGrid; + GridT* grid = reinterpret_cast(mBuffer.data()); + return (grid && grid->gridType() == mapToGridType()) ? grid : nullptr; +} + +template +template +inline typename std::enable_if::hasDeviceDual, const NanoGrid*>::type +GridHandle::deviceGrid() const +{ + using GridT = const NanoGrid; + GridT* grid = reinterpret_cast(mBuffer.deviceData()); + return (grid && this->gridMetaData()->gridType() == mapToGridType()) ? grid : nullptr; +} + +template +template +inline typename std::enable_if::hasDeviceDual, void>::type GridHandle::deviceUpload(void* stream, bool sync) +{ + mBuffer.deviceUpload(stream, sync); +} + +template +template +inline typename std::enable_if::hasDeviceDual, void>::type GridHandle::deviceDownload(void* stream, bool sync) +{ + mBuffer.deviceDownload(stream, sync); +} + +} // namespace nanovdb + +#endif // NANOVDB_GRID_HANDLE_H_HAS_BEEN_INCLUDED diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/HDDA.h b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/HDDA.h new file mode 100644 index 00000000..a1f3bd8d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/HDDA.h @@ -0,0 +1,481 @@ +// Copyright Contributors to the OpenVDB Project +// SPDX-License-Identifier: MPL-2.0 + +/// @file HDDA.h +/// +/// @author Ken Museth +/// +/// @brief Hierachical Digital Differential Analyzers specialized for VDB. + +#ifndef NANOVDB_HDDA_H_HAS_BEEN_INCLUDED +#define NANOVDB_HDDA_H_HAS_BEEN_INCLUDED + +// Comment out to disable this explicit round-off check +#define ENFORCE_FORWARD_STEPPING + +#include // only dependency + +namespace nanovdb { + +/// @brief A Digital Differential Analyzer specialized for OpenVDB grids +/// @note Conceptually similar to Bresenham's line algorithm applied +/// to a 3D Ray intersecting OpenVDB nodes or voxels. Log2Dim = 0 +/// corresponds to a voxel and Log2Dim a tree node of size 2^Log2Dim. +/// +/// @note The Ray template class is expected to have the following +/// methods: test(time), t0(), t1(), invDir(), and operator()(time). +/// See the example Ray class above for their definition. +template +class HDDA +{ +public: + using RealType = typename RayT::RealType; + using RealT = RealType; + using Vec3Type = typename RayT::Vec3Type; + using Vec3T = Vec3Type; + using CoordType = CoordT; + + /// @brief Default ctor + HDDA() = default; + + /// @brief ctor from ray and dimension at which the DDA marches + __hostdev__ HDDA(const RayT& ray, int dim) { this->init(ray, dim); } + + /// @brief Re-initializes the HDDA + __hostdev__ void init(const RayT& ray, RealT startTime, RealT maxTime, int dim) + { + assert(startTime <= maxTime); + mDim = dim; + mT0 = startTime; + mT1 = maxTime; + const Vec3T &pos = ray(mT0), &dir = ray.dir(), &inv = ray.invDir(); + mVoxel = RoundDown(pos) & (~(dim - 1)); + for (int axis = 0; axis < 3; ++axis) { + if (dir[axis] == RealT(0)) { //handles dir = +/- 0 + mNext[axis] = Maximum::value(); //i.e. disabled! + mStep[axis] = 0; + } else if (inv[axis] > 0) { + mStep[axis] = 1; + mNext[axis] = mT0 + (mVoxel[axis] + dim - pos[axis]) * inv[axis]; + mDelta[axis] = inv[axis]; + } else { + mStep[axis] = -1; + mNext[axis] = mT0 + (mVoxel[axis] - pos[axis]) * inv[axis]; + mDelta[axis] = -inv[axis]; + } + } + } + + /// @brief Simular to init above except it uses the bounds of the input ray + __hostdev__ void init(const RayT& ray, int dim) { this->init(ray, ray.t0(), ray.t1(), dim); } + + /// @brief Updates the HDDA to march with the specified dimension + __hostdev__ bool update(const RayT& ray, int dim) + { + if (mDim == dim) + return false; + mDim = dim; + const Vec3T &pos = ray(mT0), &inv = ray.invDir(); + mVoxel = RoundDown(pos) & (~(dim - 1)); + for (int axis = 0; axis < 3; ++axis) { + if (mStep[axis] == 0) + continue; + mNext[axis] = mT0 + (mVoxel[axis] - pos[axis]) * inv[axis]; + if (mStep[axis] > 0) + mNext[axis] += dim * inv[axis]; + } + + return true; + } + + __hostdev__ int dim() const { return mDim; } + + /// @brief Increment the voxel index to next intersected voxel or node + /// and returns true if the step in time does not exceed maxTime. + __hostdev__ bool step() + { + const int axis = MinIndex(mNext); +#if 1 + switch (axis) { + case 0: + return step<0>(); + case 1: + return step<1>(); + default: + return step<2>(); + } +#else + mT0 = mNext[axis]; + mNext[axis] += mDim * mDelta[axis]; + mVoxel[axis] += mDim * mStep[axis]; + return mT0 <= mT1; +#endif + } + + /// @brief Return the index coordinates of the next node or voxel + /// intersected by the ray. If Log2Dim = 0 the return value is the + /// actual signed coordinate of the voxel, else it is the origin + /// of the corresponding VDB tree node or tile. + /// @note Incurs no computational overhead. + __hostdev__ const CoordT& voxel() const { return mVoxel; } + + /// @brief Return the time (parameterized along the Ray) of the + /// first hit of a tree node of size 2^Log2Dim. + /// @details This value is initialized to startTime or ray.t0() + /// depending on the constructor used. + /// @note Incurs no computational overhead. + __hostdev__ RealType time() const { return mT0; } + + /// @brief Return the maximum time (parameterized along the Ray). + __hostdev__ RealType maxTime() const { return mT1; } + + /// @brief Return the time (parameterized along the Ray) of the + /// second (i.e. next) hit of a tree node of size 2^Log2Dim. + /// @note Incurs a (small) computational overhead. + __hostdev__ RealType next() const + { +#if 1 //def __CUDA_ARCH__ + return fminf(mT1, fminf(mNext[0], fminf(mNext[1], mNext[2]))); +#else + return std::min(mT1, std::min(mNext[0], std::min(mNext[1], mNext[2]))); +#endif + } + +private: + // helper to implement the general form + template + __hostdev__ bool step() + { +#ifdef ENFORCE_FORWARD_STEPPING + //if (mNext[axis] <= mT0) mNext[axis] += mT0 - mNext[axis] + fmaxf(mNext[axis]*1.0e-6f, 1.0e-6f); + //if (mNext[axis] <= mT0) mNext[axis] += mT0 - mNext[axis] + (mNext[axis] + 1.0f)*1.0e-6f; + if (mNext[axis] <= mT0) { + mNext[axis] += mT0 - 0.999999f * mNext[axis] + 1.0e-6f; + } +#endif + mT0 = mNext[axis]; + mNext[axis] += mDim * mDelta[axis]; + mVoxel[axis] += mDim * mStep[axis]; + return mT0 <= mT1; + } + + int32_t mDim; + RealT mT0, mT1; // min and max allowed times + CoordT mVoxel, mStep; // current voxel location and step to next voxel location + Vec3T mDelta, mNext; // delta time and next time +}; // class HDDA + +/////////////////////////////////////////// ZeroCrossing //////////////////////////////////////////// + +template +inline __hostdev__ bool ZeroCrossing(RayT& ray, AccT& acc, Coord& ijk, typename AccT::ValueType& v, float& t) +{ + if (!ray.clip(acc.root().bbox()) || ray.t1() > 1e20) + return false; // clip ray to bbox + static const float Delta = 1.0001f; + ijk = RoundDown(ray.start()); // first hit of bbox + HDDA hdda(ray, acc.getDim(ijk, ray)); + const auto v0 = acc.getValue(ijk); + while (hdda.step()) { + ijk = RoundDown(ray(hdda.time() + Delta)); + hdda.update(ray, acc.getDim(ijk, ray)); + if (hdda.dim() > 1 || !acc.isActive(ijk)) + continue; // either a tile value or an inactive voxel + while (hdda.step() && acc.isActive(hdda.voxel())) { // in the narrow band + v = acc.getValue(hdda.voxel()); + if (v * v0 < 0) { // zero crossing + ijk = hdda.voxel(); + t = hdda.time(); + return true; + } + } + } + return false; +} + +/////////////////////////////////////////// DDA //////////////////////////////////////////// + +/// @brief A Digital Differential Analyzer +/// +/// @note The Ray template class is expected to have the following +/// methods: test(time), t0(), t1(), invDir(), and operator()(time). +/// See the example Ray class above for their definition. +template +class DDA +{ + static_assert(Dim >= 1, "Dim must be >= 1"); + +public: + using RealType = typename RayT::RealType; + using RealT = RealType; + using Vec3Type = typename RayT::Vec3Type; + using Vec3T = Vec3Type; + using CoordType = CoordT; + + /// @brief Default ctor + DDA() = default; + + /// @brief ctor from ray and dimension at which the DDA marches + __hostdev__ DDA(const RayT& ray) { this->init(ray); } + + /// @brief Re-initializes the DDA + __hostdev__ void init(const RayT& ray, RealT startTime, RealT maxTime) + { + assert(startTime <= maxTime); + mT0 = startTime; + mT1 = maxTime; + const Vec3T &pos = ray(mT0), &dir = ray.dir(), &inv = ray.invDir(); + mVoxel = RoundDown(pos) & (~(Dim - 1)); + for (int axis = 0; axis < 3; ++axis) { + if (dir[axis] == RealT(0)) { //handles dir = +/- 0 + mNext[axis] = Maximum::value(); //i.e. disabled! + mStep[axis] = 0; + } else if (inv[axis] > 0) { + mStep[axis] = Dim; + mNext[axis] = (mT0 + (mVoxel[axis] + Dim - pos[axis]) * inv[axis]); + mDelta[axis] = inv[axis]; + } else { + mStep[axis] = -Dim; + mNext[axis] = mT0 + (mVoxel[axis] - pos[axis]) * inv[axis]; + mDelta[axis] = -inv[axis]; + } + } + } + + /// @brief Simular to init above except it uses the bounds of the input ray + __hostdev__ void init(const RayT& ray) { this->init(ray, ray.t0(), ray.t1()); } + + /// @brief Increment the voxel index to next intersected voxel or node + /// and returns true if the step in time does not exceed maxTime. + __hostdev__ bool step() + { + const int axis = MinIndex(mNext); +#if 1 + switch (axis) { + case 0: + return step<0>(); + case 1: + return step<1>(); + default: + return step<2>(); + } +#else +#ifdef ENFORCE_FORWARD_STEPPING + if (mNext[axis] <= mT0) { + mNext[axis] += mT0 - 0.999999f * mNext[axis] + 1.0e-6f; + } +#endif + mT0 = mNext[axis]; + mNext[axis] += mDelta[axis]; + mVoxel[axis] += mStep[axis]; + return mT0 <= mT1; +#endif + } + + /// @brief Return the index coordinates of the next node or voxel + /// intersected by the ray. If Log2Dim = 0 the return value is the + /// actual signed coordinate of the voxel, else it is the origin + /// of the corresponding VDB tree node or tile. + /// @note Incurs no computational overhead. + __hostdev__ const CoordT& voxel() const { return mVoxel; } + + /// @brief Return the time (parameterized along the Ray) of the + /// first hit of a tree node of size 2^Log2Dim. + /// @details This value is initialized to startTime or ray.t0() + /// depending on the constructor used. + /// @note Incurs no computational overhead. + __hostdev__ RealType time() const { return mT0; } + + /// @brief Return the maximum time (parameterized along the Ray). + __hostdev__ RealType maxTime() const { return mT1; } + + /// @brief Return the time (parameterized along the Ray) of the + /// second (i.e. next) hit of a tree node of size 2^Log2Dim. + /// @note Incurs a (small) computational overhead. + __hostdev__ RealType next() const + { + return Min(mT1, Min(mNext[0], Min(mNext[1], mNext[2]))); + } + + __hostdev__ int nextAxis() const + { + return nanovdb::MinIndex(mNext); + } + +private: + // helper to implement the general form + template + __hostdev__ bool step() + { +#ifdef ENFORCE_FORWARD_STEPPING + if (mNext[axis] <= mT0) { + mNext[axis] += mT0 - 0.999999f * mNext[axis] + 1.0e-6f; + } +#endif + mT0 = mNext[axis]; + mNext[axis] += mDelta[axis]; + mVoxel[axis] += mStep[axis]; + return mT0 <= mT1; + } + + RealT mT0, mT1; // min and max allowed times + CoordT mVoxel, mStep; // current voxel location and step to next voxel location + Vec3T mDelta, mNext; // delta time and next time +}; // class DDA + +/////////////////////////////////////////// ZeroCrossingNode //////////////////////////////////////////// + +template +inline __hostdev__ bool ZeroCrossingNode(RayT& ray, const NodeT& node, float v0, nanovdb::Coord& ijk, float& v, float& t) +{ + BBox bbox(node.origin(), node.origin() + Coord(node.dim() - 1)); + + if (!ray.clip(node.bbox())) { + return false; + } + + const float t0 = ray.t0(); + + static const float Delta = 1.0001f; + ijk = Coord::Floor(ray(ray.t0() + Delta)); + + t = t0; + v = 0; + + DDA dda(ray); + while (dda.step()) { + ijk = dda.voxel(); + + if (bbox.isInside(ijk) == false) + return false; + + v = node.getValue(ijk); + if (v * v0 < 0) { + t = dda.time(); + return true; + } + } + return false; +} + +/////////////////////////////////////////// TreeMarcher //////////////////////////////////////////// + +/// @brief A Tree Marcher for Generic Grids + +template +class TreeMarcher +{ +public: + using ChildT = typename NodeT::ChildNodeType; + using RealType = typename RayT::RealType; + using RealT = RealType; + using CoordType = CoordT; + + inline __hostdev__ TreeMarcher(AccT& acc) + : mAcc(acc) + { + } + + /// @brief Initialize the TreeMarcher with an index-space ray. + inline __hostdev__ bool init(const RayT& indexRay) + { + mRay = indexRay; + if (!mRay.clip(mAcc.root().bbox())) + return false; // clip ray to bbox + + // tweak the intersection span into the bbox. + // CAVEAT: this will potentially clip some tiny corner intersections. + static const float Eps = 0.000001f; + const float t0 = mRay.t0() + Eps; + const float t1 = mRay.t1() - Eps; + if (t0 > t1) + return false; + + const CoordT ijk = RoundDown(mRay(t0)); + const uint32_t dim = mAcc.getDim(ijk, mRay); + mHdda.init(mRay, t0, t1, nanovdb::Max(dim, NodeT::dim())); + + mT0 = (dim <= ChildT::dim()) ? mHdda.time() : -1; // potentially begin a span. + mTmax = t1; + return true; + } + + /// @brief step the ray through the tree. If the ray hits a node then + /// populate t0 & t1, and the node. + /// @return true when a node of type NodeT is intersected, false otherwise. + inline __hostdev__ bool step(const NodeT** node, float& t0, float& t1) + { + // CAVEAT: if Delta is too large then it will clip corners of nodes in a visible way. + // but it has to be quite large when very far from the grid (due to fp32 rounding) + static const float Delta = 0.01f; + bool hddaIsValid; + + do { + t0 = mT0; + + auto currentNode = mAcc.template getNode(); + + // get next node intersection... + hddaIsValid = mHdda.step(); + const CoordT nextIjk = RoundDown(mRay(mHdda.time() + Delta)); + const auto nextDim = mAcc.getDim(nextIjk, mRay); + mHdda.update(mRay, (int)Max(nextDim, NodeT::dim())); + mT0 = (nextDim <= ChildT::dim()) ? mHdda.time() : -1; // potentially begin a span. + + if (t0 >= 0) { // we are in a span. + t1 = Min(mTmax, mHdda.time()); + + // TODO: clean this up! + if (t0 >= t1 || currentNode == nullptr) + continue; + + *node = currentNode; + return true; + } + + } while (hddaIsValid); + + return false; + } + + inline __hostdev__ const RayT& ray() const { return mRay; } + + inline __hostdev__ RayT& ray() { return mRay; } + +private: + AccT& mAcc; + RayT mRay; + HDDA mHdda; + float mT0; + float mTmax; +};// TreeMarcher + +/////////////////////////////////////////// PointTreeMarcher //////////////////////////////////////////// + +/// @brief A Tree Marcher for Point Grids +/// +/// @note This class will handle correctly offseting the ray by 0.5 to ensure that +/// the underlying HDDA will intersect with the grid-cells. See details below. + +template +class PointTreeMarcher : public TreeMarcher, RayT, AccT, CoordT> +{ + using BaseT = TreeMarcher, RayT, AccT, CoordT>; +public: + __hostdev__ PointTreeMarcher(AccT& acc) : BaseT(acc) {} + + /// @brief Initiates this instance with a ray in index space. + /// + /// @details An offset by 0.5 is applied to the ray to account for the fact that points in vdb + /// grids are bucketed into so-called grid cell, which are centered round grid voxels, + /// whereas the DDA is based on so-called grid nodes, which are coincident with grid + /// voxels. So, rather than offsettting the points by 0.5 to bring them into a grid + /// node representation this method offsets the eye of the ray by 0.5, which effectively + /// ensures that the DDA operates on grid cells as oppose to grid nodes. This subtle + /// but important offset by 0.5 is explined in more details in our online documentation. + __hostdev__ bool init(RayT ray) { return BaseT::init(ray.offsetEye(0.5)); } +};// PointTreeMarcher + +} // namespace nanovdb + +#endif // NANOVDB_HDDA_HAS_BEEN_INCLUDED diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/HostBuffer.h b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/HostBuffer.h new file mode 100644 index 00000000..419bebef --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/HostBuffer.h @@ -0,0 +1,135 @@ +// Copyright Contributors to the OpenVDB Project +// SPDX-License-Identifier: MPL-2.0 + +/*! + \file HostBuffer.h + + \author Ken Museth + + \date January 8, 2020 + + \brief HostBuffer - a class for simple buffer allocation and management +*/ + +#ifndef NANOVDB_HOSTBUFFER_H_HAS_BEEN_INCLUDED +#define NANOVDB_HOSTBUFFER_H_HAS_BEEN_INCLUDED + +#include + +#include // for types like int32_t etc +#include // for fprintf +#include // for std::malloc/std::free + +#define checkPtr(ptr, msg) \ + { \ + ptrAssert((ptr), (msg), __FILE__, __LINE__); \ + } + +namespace nanovdb { + +// ----------------------------> HostBuffer <-------------------------------------- + +/// @brief Simple memory allocator using host memory. +class HostBuffer +{ + uint64_t mSize; // total number of bytes for the NanoVDB grid. + uint8_t* mData; // raw buffer for the NanoVDB grid. + +#if defined(DEBUG) || defined(_DEBUG) + static inline void ptrAssert(void* ptr, const char* msg, const char* file, int line, bool abort = true) + { + if (ptr == nullptr) { + fprintf(stderr, "NULL pointer error: %s %s %d\n", msg, file, line); + if (abort) + exit(1); + } + } +#else + static inline void ptrAssert(void*, const char*, const char*, int, bool = true) + { + } +#endif + +public: + HostBuffer(uint64_t size = 0) + : mSize(0) + , mData(nullptr) + { + this->init(size); + } + /// @brief Disallow copy-construction + HostBuffer(const HostBuffer&) = delete; + /// @brief Move copy-constructor + HostBuffer(HostBuffer&& other) noexcept + : mSize(other.mSize) + , mData(other.mData) + { + other.mSize = 0; + other.mData = nullptr; + } + /// @brief Disallow copy assignment operation + HostBuffer& operator=(const HostBuffer&) = delete; + /// @brief Move copy assignment operation + HostBuffer& operator=(HostBuffer&& other) noexcept + { + clear(); + mSize = other.mSize; + mData = other.mData; + other.mSize = 0; + other.mData = nullptr; + return *this; + } + /// @brief Destructor frees memory allocated on the heap + ~HostBuffer() { this->clear(); }; + + void init(uint64_t size); + + /// @brief Retuns a pointer to the raw memory buffer managed by this allocator. + /// + /// @warning Note that the pointer can be NULL if the allocator was not initialized! + const uint8_t* data() const { return mData; } + uint8_t* data() { return mData; } + + /// @brief Returns the size in bytes of the raw memory buffer managed by this allocator. + uint64_t size() const { return mSize; } + + /// @brief Returns true if this allocator is empty, i.e. has no allocated memory + bool empty() const { return mSize == 0; } + + /// @brief De-allocate all memory managed by this allocator and set all pointer to NULL + void clear(); + + static HostBuffer create(uint64_t size, const HostBuffer* context = nullptr); + +}; // HostBuffer class + +// --------------------------> Implementations below <------------------------------------ + +inline HostBuffer HostBuffer::create(uint64_t size, const HostBuffer*) +{ + return HostBuffer(size); +} + +inline void HostBuffer::init(uint64_t size) +{ + if (size == mSize) + return; + if (mSize > 0) + this->clear(); + if (size == 0) + return; + mSize = size; + mData = static_cast(std::malloc(size)); + checkPtr(mData, "failed to allocate host data"); +} // HostBuffer::init + +inline void HostBuffer::clear() +{ + std::free(mData); + mData = nullptr; + mSize = 0; +} // HostBuffer::clear + +} // namespace nanovdb + +#endif // end of NANOVDB_HOSTBUFFER_H_HAS_BEEN_INCLUDED diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/IO.h b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/IO.h new file mode 100644 index 00000000..462b658c --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/IO.h @@ -0,0 +1,759 @@ +// Copyright Contributors to the OpenVDB Project +// SPDX-License-Identifier: MPL-2.0 + +/*! + \file IO.h + + \author Ken Museth + + \date May 1, 2020 + + \brief Implements I/O for NanoVDB grids. Features optional BLOSC and ZIP + file compression, support for multiple grids per file as well as + multiple grid types. + + \note This file does NOT depend on OpenVDB, but optionally on ZIP and BLOSC +*/ + +#ifndef NANOVDB_IO_H_HAS_BEEN_INCLUDED +#define NANOVDB_IO_H_HAS_BEEN_INCLUDED + +#include "GridHandle.h" + +#include // for std::ifstream +#include // for std::cerr/cout +#include // for std::string +#include // for std::stringstream +#include // for std::strcmp +#include // for std::unique_ptr +#include // for std::vector +#ifdef NANOVDB_USE_ZIP +#include // for ZIP compression +#endif +#ifdef NANOVDB_USE_BLOSC +#include // for BLOSC compression +#endif + +// Due to a bug in older versions of gcc, including fstream might +// define "major" and "minor" which are used as member data below. +// See https://bugzilla.redhat.com/show_bug.cgi?id=130601 +#if defined(major) || defined(minor) +#undef major +#undef minor +#endif + +namespace nanovdb { + +namespace io { + +/// We fix a specific size for counting bytes in files so that they +/// are saved the same regardless of machine precision. (Note there are +/// still little/bigendian issues, however) +using fileSize_t = uint64_t; + +/// @brief Optional compression codecs +/// +/// @note NONE is the default, ZIP is slow but compact and BLOSC offers a great balance. +/// +/// @warning NanoVDB optionally supports ZIP and BLOSC compression and will throw an exception +/// if it support is required but missing. +enum class Codec : uint16_t { NONE = 0, + ZIP = 1, + BLOSC = 2, + END = 3 }; + +/// @brief Internal functions for compressed read/write of a NanoVDB GridHandle into a stream +/// +/// @warning These functions should never be called directly by client code +namespace Internal { +static constexpr fileSize_t MAX_SIZE = 1UL << 30; // size is 1 GB + +template +static fileSize_t write(std::ostream& os, const GridHandle& handle, Codec codec); + +template +static void read(std::istream& is, GridHandle& handle, Codec codec); +}; // namespace Internal + +/// @brief Standard hash function to use on strings; std::hash may vary by +/// platform/implementation and is know to produce frequent collisions. +uint64_t stringHash(const char* cstr); + +/// @brief Return a uint64_t hash key of a std::string +inline uint64_t stringHash(const std::string& str) +{ + return stringHash(str.c_str()); +} + +/// @brief Return a uint64_t with its bytes reversed so we can check for endianness +inline uint64_t reverseEndianness(uint64_t val) +{ + return (((val) >> 56) & 0x00000000000000FF) | (((val) >> 40) & 0x000000000000FF00) | + (((val) >> 24) & 0x0000000000FF0000) | (((val) >> 8) & 0x00000000FF000000) | + (((val) << 8) & 0x000000FF00000000) | (((val) << 24) & 0x0000FF0000000000) | + (((val) << 40) & 0x00FF000000000000) | (((val) << 56) & 0xFF00000000000000); +} + +/// @brief Data encoded at the head of each segment of a file or stream. +/// +/// @note A file or stream is composed of one or more segments that each contain +// one or more grids. +// Magic number of NanoVDB files (uint64_t) | +// Version numbers of this file (uint32_t) | one header for each segment +// Compression mode (uint16_t) | +// Number of grids in this segment (uint16_t) | +struct Header +{ + uint64_t magic; // 8 bytes + Version version;// 4 bytes version numbers + uint16_t gridCount; // 2 bytes + Codec codec; // 2 bytes + Header(Codec c = Codec::NONE) + : magic(NANOVDB_MAGIC_NUMBER) // Magic number: "NanoVDB" in hex + , version()// major, minor and patch version numbers + , gridCount(0) + , codec(c) + { + } +}; // Header ( 16 bytes = 2 words ) + +/// @brief Data encoded for each of the grids associated with a segment. +// Grid size in memory (uint64_t) | +// Grid size on disk (uint64_t) | +// Grid name hash key (uint64_t) | +// Numer of active voxels (uint64_t) | +// Grid type (uint32_t) | one per grid in file +// Grid class (uint32_t) | +// Characters in grid name (uint32_t) | +// AABB in world space (2*3*double) | +// AABB in index space (2*3*int) | +// Size of a voxel in world units (3*double) | +struct MetaData +{ + uint64_t gridSize, fileSize, nameKey, voxelCount; // 4 * 8 = 32B. + GridType gridType; // 4B. + GridClass gridClass; // 4B. + BBox worldBBox; // 2 * 3 * 8 = 48B. + CoordBBox indexBBox; // 2 * 3 * 4 = 24B. + Vec3R voxelSize; // 24B. + uint32_t nameSize; // 4B. + uint32_t nodeCount[4]; //4 x 4 = 16B + Codec codec; // 2B + Version version;// 4B +}; // MetaData ( for backwards compatibility only the first 160B are used in I/O ) + +struct GridMetaData : public MetaData +{ + std::string gridName; + void read(std::istream& is); + void write(std::ostream& os) const; + GridMetaData() {} + template + GridMetaData(uint64_t size, Codec c, const NanoGrid& grid); + // for backwards compatibility we only write and read 160 bytes + uint64_t memUsage() const { return 160 + nameSize; } +}; // GridMetaData + +struct Segment +{ + // Check assumptions made during read and write of Header and MetaData + static_assert(sizeof(Header) == 16u, "Unexpected sizeof(Header)"); + Header header; + std::vector meta; + Segment(Codec c = Codec::NONE) + : header(c) + , meta() + { + } + template + void add(const GridHandle& h); + bool read(std::istream& is); + void write(std::ostream& os) const; + uint64_t memUsage() const; +}; // Segment + +/// @brief Write a single grid to file (over-writing existing content of the file) +template +void writeGrid(const std::string& fileName, const GridHandle& handle, Codec codec = Codec::NONE, int verbose = 0); + +/// @brief Write a single grid to stream (starting at the current position) +/// +/// @note This method can be used to append grid to an existing stream +template +void writeGrid(std::ostream& os, const GridHandle& handle, Codec codec = Codec::NONE); + +/// @brief Write multiple grids to file (over-writing existing content of the file) +template class VecT = std::vector> +void writeGrids(const std::string& fileName, const VecT>& handles, Codec codec = Codec::NONE, int verbose = 0); + +/// @brief Writes multiple grids to stream (starting at its current position) +/// +/// @note This method can be used to append multiple grids to an existing stream +template class VecT = std::vector> +void writeGrids(std::ostream& os, const VecT>& handles, Codec codec = Codec::NONE); + +/// @brief Read the n'th grid from file (defaults to first grid) +/// +/// @throw If n exceeds the number of grids in the file +template +GridHandle readGrid(const std::string& fileName, uint64_t n = 0, int verbose = 0, const BufferT& buffer = BufferT()); + +/// @brief Read the n'th grid from stream (defaults to first grid) +/// +/// @throw If n exceeds the number of grids in the stream +template +GridHandle readGrid(std::istream& is, uint64_t n = 0, const BufferT& buffer = BufferT()); + +/// @brief Read the first grid with a specific name +/// +/// @warning If not grid exists with the specified name the resulting GridHandle is empty +template +GridHandle readGrid(const std::string& fileName, const std::string& gridName, int verbose = 0, const BufferT& buffer = BufferT()); + +/// @brief Read the first grid with a specific name +template +GridHandle readGrid(std::istream& is, const std::string& gridName, const BufferT& buffer = BufferT()); + +/// @brief Read all the grids in the file +template class VecT = std::vector> +VecT> readGrids(const std::string& fileName, int verbose = 0, const BufferT& buffer = BufferT()); + +/// @brief Real all grids at the current position of the input stream +template class VecT = std::vector> +VecT> readGrids(std::istream& is, const BufferT& buffer = BufferT()); + +/// @brief Return true if the file contains a grid with the specified name +bool hasGrid(const std::string& fileName, const std::string& gridName); + +/// @brief Return true if the stream contains a grid with the specified name +bool hasGrid(std::istream& is, const std::string& gridName); + +/// @brief Reads and returns a vector of meta data for all the grids found in the specified file +std::vector readGridMetaData(const std::string& fileName); + +/// @brief Reads and returns a vector of meta data for all the grids found in the specified stream +std::vector readGridMetaData(std::istream& is); + +// --------------------------> Implementations for Internal <------------------------------------ + +template +fileSize_t Internal::write(std::ostream& os, const GridHandle& handle, Codec codec) +{ + const char* data = reinterpret_cast(handle.data()); + fileSize_t total = 0, residual = handle.size(); + + switch (codec) { + case Codec::ZIP: { +#ifdef NANOVDB_USE_ZIP + uLongf size = compressBound(residual); // Get an upper bound on the size of the compressed data. + std::unique_ptr tmp(new Bytef[size]); + const int status = compress(tmp.get(), &size, reinterpret_cast(data), residual); + if (status != Z_OK) + std::runtime_error("Internal write error in ZIP"); + if (size > residual) + std::cerr << "\nWarning: Unexpected ZIP compression from " << residual << " to " << size << " bytes\n"; + const fileSize_t outBytes = size; + os.write(reinterpret_cast(&outBytes), sizeof(fileSize_t)); + os.write(reinterpret_cast(tmp.get()), outBytes); + total += sizeof(fileSize_t) + outBytes; +#else + throw std::runtime_error("ZIP compression codec was disabled during build"); +#endif + break; + } + case Codec::BLOSC: { +#ifdef NANOVDB_USE_BLOSC + do { + fileSize_t chunk = residual < MAX_SIZE ? residual : MAX_SIZE, size = chunk + BLOSC_MAX_OVERHEAD; + std::unique_ptr tmp(new char[size]); + const int count = blosc_compress_ctx(9, 1, sizeof(float), chunk, data, tmp.get(), size, BLOSC_LZ4_COMPNAME, 1 << 18, 1); + if (count <= 0) + std::runtime_error("Internal write error in BLOSC"); + const fileSize_t outBytes = count; + os.write(reinterpret_cast(&outBytes), sizeof(fileSize_t)); + os.write(reinterpret_cast(tmp.get()), outBytes); + total += sizeof(fileSize_t) + outBytes; + data += chunk; + residual -= chunk; + } while (residual > 0); +#else + throw std::runtime_error("BLOSC compression codec was disabled during build"); +#endif + break; + } + default: + os.write(data, residual); + total += residual; + } + if (!os) { + throw std::runtime_error("Failed to write Tree to file"); + } + return total; +} // Internal::write + +template +void Internal::read(std::istream& is, GridHandle& handle, Codec codec) +{ + char* data = reinterpret_cast(handle.buffer().data()); + fileSize_t residual = handle.buffer().size(); + + // read tree using optional compression + switch (codec) { + case Codec::ZIP: { +#ifdef NANOVDB_USE_ZIP + fileSize_t size; + is.read(reinterpret_cast(&size), sizeof(fileSize_t)); + std::unique_ptr tmp(new Bytef[size]); + is.read(reinterpret_cast(tmp.get()), size); + uLongf numBytes = residual; + int status = uncompress(reinterpret_cast(data), &numBytes, tmp.get(), static_cast(size)); + if (status != Z_OK) + std::runtime_error("Internal read error in ZIP"); + if (fileSize_t(numBytes) != residual) + throw std::runtime_error("UNZIP failed on byte size"); +#else + throw std::runtime_error("ZIP compression codec was disabled during build"); +#endif + break; + } + case Codec::BLOSC: { +#ifdef NANOVDB_USE_BLOSC + do { + fileSize_t size; + is.read(reinterpret_cast(&size), sizeof(fileSize_t)); + std::unique_ptr tmp(new char[size]); + is.read(reinterpret_cast(tmp.get()), size); + const fileSize_t chunk = residual < MAX_SIZE ? residual : MAX_SIZE; + const int count = blosc_decompress_ctx(tmp.get(), data, size_t(chunk), 1); //fails with more threads :( + if (count < 1) + std::runtime_error("Internal read error in BLOSC"); + if (count != int(chunk)) + throw std::runtime_error("BLOSC failed on byte size"); + data += size_t(chunk); + residual -= chunk; + } while (residual > 0); +#else + throw std::runtime_error("BLOSC compression codec was disabled during build"); +#endif + break; + } + default: + is.read(data, residual); + } + if (!is) { + throw std::runtime_error("Failed to read Tree from file"); + } +} // Internal::read + +// --------------------------> Implementations for GridMetaData <------------------------------------ + +template +inline GridMetaData::GridMetaData(uint64_t size, Codec c, const NanoGrid& grid) + : MetaData{size, // gridSize + 0, // fileSize + 0, // nameKey + grid.activeVoxelCount(), // voxelCount + grid.gridType(), // gridType + grid.gridClass(), // gridClass + grid.worldBBox(), // worldBBox + grid.tree().bbox(), // indexBBox + grid.voxelSize(), // voxelSize + 0, // nameSize + {0, 0, 0, 0}, // nodeCount[4] + c, // codec + Version()}// version + , gridName(grid.gridName()) +{ + nameKey = stringHash(gridName); + nameSize = static_cast(gridName.size() + 1); // include '\0' + const uint32_t* ptr = reinterpret_cast*>(&grid.tree())->mCount; + for (int i = 0; i < 4; ++i) { + MetaData::nodeCount[i] = *ptr++; + } +} + +inline void GridMetaData::write(std::ostream& os) const +{ + os.write(reinterpret_cast(this), 160); // for backwards compatibility + os.write(gridName.c_str(), nameSize); + if (!os) { + throw std::runtime_error("Failed writing GridMetaData"); + } +} + +inline void GridMetaData::read(std::istream& is) +{ + is.read(reinterpret_cast(this), 160); // for backwards compatibility + std::unique_ptr tmp(new char[nameSize]); + is.read(reinterpret_cast(tmp.get()), nameSize); + gridName.assign(tmp.get()); + if (!is) { + throw std::runtime_error("Failed reading GridMetaData"); + } +} + +// --------------------------> Implementations for Segment <------------------------------------ + +inline uint64_t Segment::memUsage() const +{ + uint64_t sum = sizeof(Header); + for (auto& m : meta) { + sum += m.memUsage(); + } + return sum; +} + +template +inline void Segment::add(const GridHandle& h) +{ + if (auto* grid = h.template grid()) { // most common + meta.emplace_back(h.size(), header.codec, *grid); + } else if (auto* grid = h.template grid()) { + meta.emplace_back(h.size(), header.codec, *grid); + } else if (auto* grid = h.template grid()) { + meta.emplace_back(h.size(), header.codec, *grid); + } else if (auto* grid = h.template grid()) { + meta.emplace_back(h.size(), header.codec, *grid); + } else if (auto* grid = h.template grid()) { + meta.emplace_back(h.size(), header.codec, *grid); + } else if (auto* grid = h.template grid()) { + meta.emplace_back(h.size(), header.codec, *grid); + } else if (auto* grid = h.template grid()) { + meta.emplace_back(h.size(), header.codec, *grid); + } else if (auto* grid = h.template grid()) { + meta.emplace_back(h.size(), header.codec, *grid); + } else { + throw std::runtime_error("Cannot write empty or unknown grids to file"); + } + header.gridCount += 1; +} + +inline void Segment::write(std::ostream& os) const +{ + if (header.gridCount == 0) { + throw std::runtime_error("Segment contains no grids"); + } else if (!os.write(reinterpret_cast(&header), sizeof(Header))) { + throw std::runtime_error("Failed to write Header of Segment"); + } + for (auto& m : meta) { + m.write(os); + } +} + +inline bool Segment::read(std::istream& is) +{ + is.read(reinterpret_cast(&header), sizeof(Header)); + if (is.eof()) { + return false; + } + if (!is || header.magic != NANOVDB_MAGIC_NUMBER) { + // first check for byte-swapped header magic. + if (header.magic == reverseEndianness(NANOVDB_MAGIC_NUMBER)) + throw std::runtime_error("This nvdb file has reversed endianness"); + throw std::runtime_error("Magic number error: This is not a valid nvdb file"); + } else if ( header.version >= Version(29,0,0) && header.version.getMajor() != NANOVDB_MAJOR_VERSION_NUMBER) { + std::stringstream ss; + if (header.version.getMajor() < NANOVDB_MAJOR_VERSION_NUMBER) { + ss << "The file is written in an older version of NanoVDB: " << std::string(header.version.c_str()) << "!\n\t" + << "Recommendation: Re-generate this NanoVDB file with the never version " << NANOVDB_MAJOR_VERSION_NUMBER << ".X of NanoVDB"; + } else { + ss << "This tool was compiled against an older version of NanoVDB: " << NANOVDB_MAJOR_VERSION_NUMBER << ".X!\n\t" + << "Recommendation: Re-compile this tool against version " << header.version.getMajor() << ".X of NanoVDB"; + } + throw std::runtime_error("An unrecoverable error in nanovdb::Segment::read:\n\tIncompatible file format: " + ss.str()); + } else if (header.version < Version(29,0,0)) {// old format: uint16_t major, minor + struct T {union {Version v; struct {uint16_t major, minor;};}; T(Version a) : v(a) {}} t(header.version);// old format + static_assert( sizeof(uint32_t) == sizeof(T), "Expected sizeof(T) == sizeof(uint32_t)" ); + if (t.major != 28u ) { + std::stringstream ss; + ss << "The file is written in an older version of NanoVDB: " << t.major << "." << t.minor << ".X!\n\t" + << "Recommendation: Re-generate this NanoVDB file with the never version " << NANOVDB_MAJOR_VERSION_NUMBER << ".X of NanoVDB"; + throw std::runtime_error("An unrecoverable error in nanovdb::Segment::read:\n\tIncompatible file format: " + ss.str()); + } + header.version = Version(t.major, t.minor, 0); + } + meta.resize(header.gridCount); + for (auto& m : meta) { + m.read(is); + m.version = header.version; + } + return true; +} + +// --------------------------> Implementations for read/write <------------------------------------ + +template +void writeGrid(const std::string& fileName, const GridHandle& handle, Codec codec, int verbose) +{ + std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc); + if (!os.is_open()) { + throw std::runtime_error("Unable to open file named \"" + fileName + "\" for output"); + } + writeGrid(os, handle, codec); + if (verbose) { + std::cout << "Wrote nanovdb::Grid to file named \"" << fileName << "\"" << std::endl; + } +} + +template +void writeGrid(std::ostream& os, const GridHandle& handle, Codec codec) +{ + Segment s(codec); + s.add(handle); + const uint64_t headerSize = s.memUsage(); + std::streamoff seek = headerSize; + os.seekp(seek, std::ios_base::cur); // skip forward from the current position + s.meta[0].fileSize = Internal::write(os, handle, codec); + seek += s.meta[0].fileSize; + os.seekp(-seek, std::ios_base::cur); // rewind to start of stream + s.write(os); // write header + os.seekp(seek - headerSize, std::ios_base::cur); // skip to end +} + +template class VecT> +void writeGrids(const std::string& fileName, const VecT>& handles, Codec codec, int verbose) +{ + std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc); + if (!os.is_open()) { + throw std::runtime_error("Unable to open file named \"" + fileName + "\" for output"); + } + writeGrids(os, handles, codec); + if (verbose) { + std::cout << "Wrote " << handles.size() << " nanovdb::Grid(s) to file named \"" << fileName << "\"" << std::endl; + } +} + +template class VecT> +void writeGrids(std::ostream& os, const VecT>& handles, Codec codec) +{ + Segment s(codec); + for (auto& h : handles) { + s.add(h); + } + const uint64_t headerSize = s.memUsage(); + std::streamoff seek = headerSize; + os.seekp(seek, std::ios_base::cur); // skip forward from the current position + for (size_t i = 0; i < handles.size(); ++i) { + s.meta[i].fileSize = Internal::write(os, handles[i], codec); + seek += s.meta[i].fileSize; + } + os.seekp(-seek, std::ios_base::cur); // rewind to start of stream + s.write(os); // write header + os.seekp(seek - headerSize, std::ios_base::cur); // skip to end +} + +/// @brief Read the n'th grid +template +GridHandle readGrid(const std::string& fileName, uint64_t n, int verbose, const BufferT& buffer) +{ + std::ifstream is(fileName, std::ios::in | std::ios::binary); + if (!is.is_open()) { + throw std::runtime_error("Unable to open file named \"" + fileName + "\" for input"); + } + auto handle = readGrid(is, n, buffer); + if (verbose) { + std::cout << "Read NanoGrid # " << n << " from the file named \"" << fileName << "\"" << std::endl; + } + return handle; // is converted to r-value and return value is move constructed. +} + +template +GridHandle readGrid(std::istream& is, uint64_t n, const BufferT& buffer) +{ + Segment s; + uint64_t counter = 0; + while (s.read(is)) { + std::streamoff seek = 0; + for (auto& m : s.meta) { + if (counter == n) { + GridHandle handle(BufferT::create(m.gridSize, &buffer)); + is.seekg(seek, std::ios_base::cur); // skip forward from the current position + Internal::read(is, handle, s.header.codec); + return handle; // is converted to r-value and return value is move constructed. + } else { + seek += m.fileSize; + } + ++counter; + } + is.seekg(seek, std::ios_base::cur); // skip forward from the current position + } + throw std::runtime_error("Grid index exceeds grid count in file"); +} + +/// @brief Read the first grid with a specific name +template +GridHandle readGrid(const std::string& fileName, const std::string& gridName, int verbose, const BufferT& buffer) +{ + std::ifstream is(fileName, std::ios::in | std::ios::binary); + if (!is.is_open()) { + throw std::runtime_error("Unable to open file named \"" + fileName + "\" for input"); + } + auto handle = readGrid(is, gridName, buffer); + if (verbose) { + if (handle) { + std::cout << "Read NanoGrid named \"" << gridName << "\" from the file named \"" << fileName << "\"" << std::endl; + } else { + std::cout << "File named \"" << fileName << "\" does not contain a grid named \"" + gridName + "\"" << std::endl; + } + } + return handle; // is converted to r-value and return value is move constructed. +} + +template +GridHandle readGrid(std::istream& is, const std::string& gridName, const BufferT& buffer) +{ + const auto key = stringHash(gridName); + Segment s; + while (s.read(is)) { + std::streamoff seek = 0; + for (auto& m : s.meta) { + if (m.nameKey == key && m.gridName == gridName) { // check for hask key collision + GridHandle handle(BufferT::create(m.gridSize, &buffer)); + is.seekg(seek, std::ios_base::cur); // rewind + Internal::read(is, handle, s.header.codec); + return handle; // is converted to r-value and return value is move constructed. + } else { + seek += m.fileSize; + } + } + is.seekg(seek, std::ios_base::cur); // skip forward from the current position + } + return GridHandle(); // empty handle +} + +/// @brief Read all the grids +template class VecT> +VecT> readGrids(const std::string& fileName, int verbose, const BufferT& buffer) +{ + std::ifstream is(fileName, std::ios::in | std::ios::binary); + if (!is.is_open()) { + throw std::runtime_error("Unable to open file named \"" + fileName + "\" for input"); + } + auto handles = readGrids(is, buffer); + if (verbose) { + std::cout << "Read " << handles.size() << " NanoGrid(s) from the file named \"" << fileName << "\"" << std::endl; + } + return handles; // is converted to r-value and return value is move constructed. +} + +template class VecT> +VecT> readGrids(std::istream& is, const BufferT& buffer) +{ + VecT> handles; + Segment seg; + while (seg.read(is)) { + for (auto& m : seg.meta) { + GridHandle handle(BufferT::create(m.gridSize, &buffer)); + Internal::read(is, handle, seg.header.codec); + handles.push_back(std::move(handle)); // force move copy assignment + } + } + return handles; // is converted to r-value and return value is move constructed. +} + +inline std::vector readGridMetaData(const std::string& fileName) +{ + std::ifstream is(fileName, std::ios::in | std::ios::binary); + if (!is.is_open()) { + throw std::runtime_error("Unable to open file named \"" + fileName + "\" for input"); + } + return readGridMetaData(is); // is converted to r-value and return value is move constructed. +} + +inline std::vector readGridMetaData(std::istream& is) +{ + std::vector meta; + Segment seg; + while (seg.read(is)) { + std::streamoff seek = 0; + for (auto& m : seg.meta) { + meta.push_back(m); + seek += m.fileSize; + } + is.seekg(seek, std::ios_base::cur); + } + return meta; // is converted to r-value and return value is move constructed. +} + +inline bool hasGrid(const std::string& fileName, const std::string& gridName) +{ + std::ifstream is(fileName, std::ios::in | std::ios::binary); + if (!is.is_open()) { + throw std::runtime_error("Unable to open file named \"" + fileName + "\" for input"); + } + return hasGrid(is, gridName); +} + +inline bool hasGrid(std::istream& is, const std::string& gridName) +{ + const auto key = stringHash(gridName); + Segment s; + while (s.read(is)) { + std::streamoff seek = 0; + for (auto& m : s.meta) { + if (m.nameKey == key && m.gridName == gridName) { + return true; // check for hash key collision + } + seek += m.fileSize; + } + is.seekg(seek, std::ios_base::cur); + } + return false; +} + +inline uint64_t stringHash(const char* cstr) +{ + uint64_t hash = 0; + if (!cstr) { + return hash; + } + for (auto* str = reinterpret_cast(cstr); *str; ++str) { + uint64_t overflow = hash >> (64 - 8); + hash *= 67; // Next-ish prime after 26 + 26 + 10 + hash += *str + overflow; + } + return hash; +} + +inline std::string getStringForGridType(nanovdb::GridType t) +{ + switch (t) { + case GridType::Float: return "float"; break; + case GridType::Double: return "double"; break; + case GridType::Int16: return "int16"; break; + case GridType::Int32: return "int32"; break; + case GridType::UInt32: return "uint32"; break; + case GridType::Int64: return "int64"; break; + case GridType::Vec3f: return "Vec3f"; break; + case GridType::Vec3d: return "Vec3d"; break; + case GridType::Mask: return "Mask"; break; + default: return "?"; + } +} + +inline std::string getStringForGridClass(nanovdb::GridClass t) +{ + switch (t) { + case GridClass::LevelSet: return "SDF"; break; + case GridClass::FogVolume: return "FOG"; break; + case GridClass::Staggered: return "MAC"; break; + case GridClass::PointIndex: return "PNTIDX"; break; + case GridClass::PointData: return "PNTDAT"; break; + default: return "?"; + } +} + +inline std::string getStringForCodec(nanovdb::io::Codec c) +{ + switch (c) { + case Codec::NONE: return "None"; break; + case Codec::ZIP: return "Zip"; break; + case Codec::BLOSC: return "Blosc"; break; + default: return "?"; + } +} + +} +} // namespace nanovdb::io + +#endif // NANOVDB_IO_H_HAS_BEEN_INCLUDED diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/Ray.h b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/Ray.h new file mode 100644 index 00000000..1535e2df --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/nanovdb/util/Ray.h @@ -0,0 +1,557 @@ +// Copyright Contributors to the OpenVDB Project +// SPDX-License-Identifier: MPL-2.0 + +/// @file Ray.h +/// +/// @author Ken Museth +/// +/// @brief A Ray class. + +#ifndef NANOVDB_RAY_H_HAS_BEEN_INCLUDED +#define NANOVDB_RAY_H_HAS_BEEN_INCLUDED + +#include // for Vec3 + +namespace nanovdb { + +template +class Ray +{ +public: + using RealType = RealT; + using Vec3Type = Vec3; + using Vec3T = Vec3Type; + + struct TimeSpan + { + RealT t0, t1; + /// @brief Default constructor + __hostdev__ TimeSpan() {} + /// @brief Constructor + __hostdev__ TimeSpan(RealT _t0, RealT _t1) + : t0(_t0) + , t1(_t1) + { + } + /// @brief Set both times + __hostdev__ void set(RealT _t0, RealT _t1) + { + t0 = _t0; + t1 = _t1; + } + /// @brief Get both times + __hostdev__ void get(RealT& _t0, RealT& _t1) const + { + _t0 = t0; + _t1 = t1; + } + /// @brief Return @c true if t1 is larger than t0 by at least eps. + __hostdev__ bool valid(RealT eps = Delta::value()) const { return (t1 - t0) > eps; } + /// @brief Return the midpoint of the ray. + __hostdev__ RealT mid() const { return 0.5 * (t0 + t1); } + /// @brief Multiplies both times + __hostdev__ void scale(RealT s) + { + assert(s > 0); + t0 *= s; + t1 *= s; + } + /// @brief Return @c true if time is inclusive + __hostdev__ bool test(RealT t) const { return (t >= t0 && t <= t1); } + }; + + __hostdev__ Ray(const Vec3Type& eye = Vec3Type(0, 0, 0), + const Vec3Type& direction = Vec3Type(1, 0, 0), + RealT t0 = Delta::value(), + RealT t1 = Maximum::value()) + : mEye(eye) + , mDir(direction) + , mInvDir(1 / mDir[0], 1 / mDir[1], 1 / mDir[2]) + , mTimeSpan(t0, t1) + , mSign{mInvDir[0] < 0, mInvDir[1] < 0, mInvDir[2] < 0} + { + } + + __hostdev__ Ray& offsetEye(RealT offset) + { + mEye[0] += offset; + mEye[1] += offset; + mEye[2] += offset; + return *this; + } + + __hostdev__ Ray& setEye(const Vec3Type& eye) + { + mEye = eye; + return *this; + } + + __hostdev__ Ray& setDir(const Vec3Type& dir) + { + mDir = dir; + mInvDir[0] = 1.0 / mDir[0]; + mInvDir[1] = 1.0 / mDir[1]; + mInvDir[2] = 1.0 / mDir[2]; + mSign[0] = mInvDir[0] < 0; + mSign[1] = mInvDir[1] < 0; + mSign[2] = mInvDir[2] < 0; + return *this; + } + + __hostdev__ Ray& setMinTime(RealT t0) + { + mTimeSpan.t0 = t0; + return *this; + } + + __hostdev__ Ray& setMaxTime(RealT t1) + { + mTimeSpan.t1 = t1; + return *this; + } + + __hostdev__ Ray& setTimes( + RealT t0 = Delta::value(), + RealT t1 = Maximum::value()) + { + assert(t0 > 0 && t1 > 0); + mTimeSpan.set(t0, t1); + return *this; + } + + __hostdev__ Ray& scaleTimes(RealT scale) + { + mTimeSpan.scale(scale); + return *this; + } + + __hostdev__ Ray& reset( + const Vec3Type& eye, + const Vec3Type& direction, + RealT t0 = Delta::value(), + RealT t1 = Maximum::value()) + { + this->setEye(eye); + this->setDir(direction); + this->setTimes(t0, t1); + return *this; + } + + __hostdev__ const Vec3T& eye() const { return mEye; } + + __hostdev__ const Vec3T& dir() const { return mDir; } + + __hostdev__ const Vec3T& invDir() const { return mInvDir; } + + __hostdev__ RealT t0() const { return mTimeSpan.t0; } + + __hostdev__ RealT t1() const { return mTimeSpan.t1; } + + __hostdev__ int sign(int i) const { return mSign[i]; } + + /// @brief Return the position along the ray at the specified time. + __hostdev__ Vec3T operator()(RealT time) const + { +#if 1 + return Vec3T(fmaf(time, mDir[0], mEye[0]), + fmaf(time, mDir[1], mEye[1]), + fmaf(time, mDir[2], mEye[2])); +#else + return mEye + mDir * time; +#endif + } + + /// @brief Return the starting point of the ray. + __hostdev__ Vec3T start() const { return (*this)(mTimeSpan.t0); } + + /// @brief Return the endpoint of the ray. + __hostdev__ Vec3T end() const { return (*this)(mTimeSpan.t1); } + + /// @brief Return the midpoint of the ray. + __hostdev__ Vec3T mid() const { return (*this)(mTimeSpan.mid()); } + + /// @brief Return @c true if t1 is larger than t0 by at least eps. + __hostdev__ bool valid(RealT eps = Delta::value()) const { return mTimeSpan.valid(eps); } + + /// @brief Return @c true if @a time is within t0 and t1, both inclusive. + __hostdev__ bool test(RealT time) const { return mTimeSpan.test(time); } + + /// @brief Return a new Ray that is transformed with the specified map. + /// + /// @param map the map from which to construct the new Ray. + /// + /// @warning Assumes a linear map and a normalized direction. + /// + /// @details The requirement that the direction is normalized + /// follows from the transformation of t0 and t1 - and that fact that + /// we want applyMap and applyInverseMap to be inverse operations. + template + __hostdev__ Ray applyMap(const MapType& map) const + { + const Vec3T eye = map.applyMap(mEye); + const Vec3T dir = map.applyJacobian(mDir); + const RealT length = dir.length(), invLength = RealT(1) / length; + RealT t1 = mTimeSpan.t1; + if (mTimeSpan.t1 < Maximum::value()) { + t1 *= length; + } + return Ray(eye, dir * invLength, length * mTimeSpan.t0, t1); + } + template + __hostdev__ Ray applyMapF(const MapType& map) const + { + const Vec3T eye = map.applyMapF(mEye); + const Vec3T dir = map.applyJacobianF(mDir); + const RealT length = dir.length(), invLength = RealT(1) / length; + RealT t1 = mTimeSpan.t1; + if (mTimeSpan.t1 < Maximum::value()) { + t1 *= length; + } + return Ray(eye, dir * invLength, length * mTimeSpan.t0, t1); + } + + /// @brief Return a new Ray that is transformed with the inverse of the specified map. + /// + /// @param map the map from which to construct the new Ray by inverse mapping. + /// + /// @warning Assumes a linear map and a normalized direction. + /// + /// @details The requirement that the direction is normalized + /// follows from the transformation of t0 and t1 - and that fact that + /// we want applyMap and applyInverseMap to be inverse operations. + template + __hostdev__ Ray applyInverseMap(const MapType& map) const + { + const Vec3T eye = map.applyInverseMap(mEye); + const Vec3T dir = map.applyInverseJacobian(mDir); + const RealT length = dir.length(), invLength = RealT(1) / length; + return Ray(eye, dir * invLength, length * mTimeSpan.t0, length * mTimeSpan.t1); + } + template + __hostdev__ Ray applyInverseMapF(const MapType& map) const + { + const Vec3T eye = map.applyInverseMapF(mEye); + const Vec3T dir = map.applyInverseJacobianF(mDir); + const RealT length = dir.length(), invLength = RealT(1) / length; + return Ray(eye, dir * invLength, length * mTimeSpan.t0, length * mTimeSpan.t1); + } + + /// @brief Return a new ray in world space, assuming the existing + /// ray is represented in the index space of the specified grid. + template + __hostdev__ Ray indexToWorldF(const GridType& grid) const + { + const Vec3T eye = grid.indexToWorldF(mEye); + const Vec3T dir = grid.indexToWorldDirF(mDir); + const RealT length = dir.length(), invLength = RealT(1) / length; + RealT t1 = mTimeSpan.t1; + if (mTimeSpan.t1 < Maximum::value()) { + t1 *= length; + } + return Ray(eye, dir * invLength, length * mTimeSpan.t0, t1); + } + + /// @brief Return a new ray in index space, assuming the existing + /// ray is represented in the world space of the specified grid. + template + __hostdev__ Ray worldToIndexF(const GridType& grid) const + { + const Vec3T eye = grid.worldToIndexF(mEye); + const Vec3T dir = grid.worldToIndexDirF(mDir); + const RealT length = dir.length(), invLength = RealT(1) / length; + RealT t1 = mTimeSpan.t1; + if (mTimeSpan.t1 < Maximum::value()) { + t1 *= length; + } + return Ray(eye, dir * invLength, length * mTimeSpan.t0, t1); + } + + /// @brief Return true if this ray intersects the specified sphere. + /// + /// @param center The center of the sphere in the same space as this ray. + /// @param radius The radius of the sphere in the same units as this ray. + /// @param t0 The first intersection point if an intersection exists. + /// @param t1 The second intersection point if an intersection exists. + /// + /// @note If the return value is true, i.e. a hit, and t0 = + /// this->t0() or t1 == this->t1() only one true intersection exist. + __hostdev__ bool intersects(const Vec3T& center, RealT radius, RealT& t0, RealT& t1) const + { + const Vec3T origin = mEye - center; + const RealT A = mDir.lengthSqr(); + const RealT B = 2 * mDir.dot(origin); + const RealT C = origin.lengthSqr() - radius * radius; + const RealT D = B * B - 4 * A * C; + + if (D < 0) { + return false; + } + const RealT Q = RealT(-0.5) * (B < 0 ? (B + Sqrt(D)) : (B - Sqrt(D))); + + t0 = Q / A; + t1 = C / Q; + + if (t0 > t1) { + RealT tmp = t0; + t0 = t1; + t1 = tmp; + } + if (t0 < mTimeSpan.t0) { + t0 = mTimeSpan.t0; + } + if (t1 > mTimeSpan.t1) { + t1 = mTimeSpan.t1; + } + return t0 <= t1; + } + + /// @brief Return true if this ray intersects the specified sphere. + /// + /// @param center The center of the sphere in the same space as this ray. + /// @param radius The radius of the sphere in the same units as this ray. + __hostdev__ bool intersects(const Vec3T& center, RealT radius) const + { + RealT t0, t1; + return this->intersects(center, radius, t0, t1) > 0; + } + + /// @brief Return true if this ray intersects the specified sphere. + /// + /// @note For intersection this ray is clipped to the two intersection points. + /// + /// @param center The center of the sphere in the same space as this ray. + /// @param radius The radius of the sphere in the same units as this ray. + __hostdev__ bool clip(const Vec3T& center, RealT radius) + { + RealT t0, t1; + const bool hit = this->intersects(center, radius, t0, t1); + if (hit) { + mTimeSpan.set(t0, t1); + } + return hit; + } +#if 0 + /// @brief Return true if the Ray intersects the specified + /// axisaligned bounding box. + /// + /// @param bbox Axis-aligned bounding box in the same space as the Ray. + /// @param t0 If an intersection is detected this is assigned + /// the time for the first intersection point. + /// @param t1 If an intersection is detected this is assigned + /// the time for the second intersection point. + template + __hostdev__ bool intersects(const BBoxT& bbox, RealT& t0, RealT& t1) const + { + t0 = (bbox[ mSign[0]][0] - mEye[0]) * mInvDir[0]; + RealT t2 = (bbox[1-mSign[1]][1] - mEye[1]) * mInvDir[1]; + if (t0 > t2) return false; + t1 = (bbox[1-mSign[0]][0] - mEye[0]) * mInvDir[0]; + RealT t3 = (bbox[ mSign[1]][1] - mEye[1]) * mInvDir[1]; + if (t3 > t1) return false; + if (t3 > t0) t0 = t3; + if (t2 < t1) t1 = t2; + t3 = (bbox[ mSign[2]][2] - mEye[2]) * mInvDir[2]; + if (t3 > t1) return false; + t2 = (bbox[1-mSign[2]][2] - mEye[2]) * mInvDir[2]; + if (t0 > t2) return false; + if (t3 > t0) t0 = t3; + if (mTimeSpan.t1 < t0) return false; + if (t2 < t1) t1 = t2; + if (mTimeSpan.t0 > t1) return false; + if (mTimeSpan.t0 > t0) t0 = mTimeSpan.t0; + if (mTimeSpan.t1 < t1) t1 = mTimeSpan.t1; + return true; + /* + mTimeSpan.get(_t0, _t1); + double t0 = _t0, t1 = _t1; + for (int i = 0; i < 3; ++i) { + //if (abs(mDir[i])<1e-3) continue; + double a = (double(bbox.min()[i]) - mEye[i]) * mInvDir[i]; + double b = (double(bbox.max()[i]) - mEye[i]) * mInvDir[i]; + if (a > b) { + double tmp = a; + a = b; + b = tmp; + } + if (a > t0) t0 = a; + if (b < t1) t1 = b; + if (t0 > t1) { + //if (gVerbose) printf("Missed BBOX: (%i,%i,%i) -> (%i,%i,%i) t0=%f t1=%f\n", + // bbox.min()[0], bbox.min()[1], bbox.min()[2], + // bbox.max()[0], bbox.max()[1], bbox.max()[2], t0, t1); + return false; + } + } + _t0 = t0; _t1 = t1; + return true; + */ + } +#else + /// @brief Returns true if this ray intersects an index bounding box. + /// If the return value is true t0 and t1 are set to the intersection + /// times along the ray. + /// + /// @warning Intersection with a CoordBBox internally converts to a floating-point bbox + /// which imples that the max is padded with one voxel, i.e. bbox.max += 1! This + /// avoids gaps between neighboring CoordBBox'es, say from neighboring tree nodes. + __hostdev__ bool intersects(const CoordBBox& bbox, RealT& t0, RealT& t1) const + { + mTimeSpan.get(t0, t1); + for (int i = 0; i < 3; ++i) { + RealT a = RealT(bbox.min()[i]), b = RealT(bbox.max()[i] + 1); + if (a >= b) { // empty bounding box + return false; + } + a = (a - mEye[i]) * mInvDir[i]; + b = (b - mEye[i]) * mInvDir[i]; + if (a > b) { + RealT tmp = a; + a = b; + b = tmp; + } + if (a > t0) { + t0 = a; + } + if (b < t1) { + t1 = b; + } + if (t0 > t1) { + return false; + } + } + return true; + } + /// @brief Returns true if this ray intersects a floating-point bounding box. + /// If the return value is true t0 and t1 are set to the intersection + /// times along the ray. + template + __hostdev__ bool intersects(const BBox& bbox, RealT& t0, RealT& t1) const + { + static_assert(is_floating_point::value, "Ray::intersects: Expected a floating point coordinate"); + mTimeSpan.get(t0, t1); + for (int i = 0; i < 3; ++i) { + RealT a = RealT(bbox.min()[i]), b = RealT(bbox.max()[i]); + if (a >= b) { // empty bounding box + return false; + } + a = (a - mEye[i]) * mInvDir[i]; + b = (b - mEye[i]) * mInvDir[i]; + if (a > b) { + RealT tmp = a; + a = b; + b = tmp; + } + if (a > t0) { + t0 = a; + } + if (b < t1) { + t1 = b; + } + if (t0 > t1) { + return false; + } + } + return true; + } +#endif + + /// @brief Return true if this ray intersects the specified bounding box. + /// + /// @param bbox Axis-aligned bounding box in the same space as this ray. + /// + /// @warning If @a bbox is of the type CoordBBox it is converted to a floating-point + /// bounding box, which imples that the max is padded with one voxel, i.e. + /// bbox.max += 1! This avoids gaps between neighboring CoordBBox'es, say + /// from neighboring tree nodes. + template + __hostdev__ bool intersects(const BBoxT& bbox) const + { +#if 1 + RealT t0, t1; + return this->intersects(bbox, t0, t1); +#else + //BBox bbox(Vec3T(_bbox[0][0]-1e-4,_bbox[0][1]-1e-4,_bbox[0][2]-1e-4), + // Vec3T(_bbox[1][0]+1e-4,_bbox[1][1]+1e-4,_bbox[1][2]+1e-4)); + RealT t0 = (bbox[mSign[0]][0] - mEye[0]) * mInvDir[0]; + RealT t2 = (bbox[1 - mSign[1]][1] - mEye[1]) * mInvDir[1]; + if (t0 > t2) + return false; + RealT t1 = (bbox[1 - mSign[0]][0] - mEye[0]) * mInvDir[0]; + RealT t3 = (bbox[mSign[1]][1] - mEye[1]) * mInvDir[1]; + if (t3 > t1) + return false; + if (t3 > t0) + t0 = t3; + if (t2 < t1) + t1 = t2; + t3 = (bbox[mSign[2]][2] - mEye[2]) * mInvDir[2]; + if (t3 > t1) + return false; + t2 = (bbox[1 - mSign[2]][2] - mEye[2]) * mInvDir[2]; + if (t0 > t2) + return false; + //if (t3 > t0) t0 = t3; + //if (mTimeSpan.t1 < t0) return false; + //if (t2 < t1) t1 = t2; + //return mTimeSpan.t0 < t1; + return true; +#endif + } + + /// @brief Return true if this ray intersects the specified bounding box. + /// + /// @note For intersection this ray is clipped to the two intersection points + ///. + /// @param bbox Axis-aligned bounding box in the same space as this ray. + /// + /// @warning If @a bbox is of the type CoordBBox it is converted to a floating-point + /// bounding box, which imples that the max is padded with one voxel, i.e. + /// bbox.max += 1! This avoids gaps between neighboring CoordBBox'es, say + /// from neighboring tree nodes. + template + __hostdev__ bool clip(const BBoxT& bbox) + { + RealT t0, t1; + const bool hit = this->intersects(bbox, t0, t1); + if (hit) { + mTimeSpan.set(t0, t1); + } + return hit; + } + + /// @brief Return true if the Ray intersects the plane specified + /// by a normal and distance from the origin. + /// + /// @param normal Normal of the plane. + /// @param distance Distance of the plane to the origin. + /// @param t Time of intersection, if one exists. + __hostdev__ bool intersects(const Vec3T& normal, RealT distance, RealT& t) const + { + const RealT cosAngle = mDir.dot(normal); + if (isApproxZero(cosAngle)) { + return false; // ray is parallel to plane + } + t = (distance - mEye.dot(normal)) / cosAngle; + return this->test(t); + } + + /// @brief Return true if the Ray intersects the plane specified + /// by a normal and point. + /// + /// @param normal Normal of the plane. + /// @param point Point in the plane. + /// @param t Time of intersection, if one exists. + __hostdev__ bool intersects(const Vec3T& normal, const Vec3T& point, RealT& t) const + { + return this->intersects(normal, point.dot(normal), t); + } + +private: + Vec3T mEye, mDir, mInvDir; + TimeSpan mTimeSpan; + int mSign[3]; +}; // end of Ray class + +} // namespace nanovdb + +#endif // NANOVDB_RAY_HAS_BEEN_INCLUDED diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/optixVolumeViewer.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/optixVolumeViewer.cpp new file mode 100644 index 00000000..11cd6b81 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/optixVolumeViewer.cpp @@ -0,0 +1,1791 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "optixVolumeViewer.h" + +#include +#include + +#include + +#include // Needs to be included before gl_interop + +#include +#include + +#include "nanovdb/util/IO.h" // this is required to read (and write) NanoVDB files on the host + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + + + +// ---------------------------------------------------------------------------- +// This sample demonstrates the basic mechanism of visualizing a NanoVDB +// volume using Optix. +// +// The NanoVDB volume is represented in the Optix acceleration structure by its +// overall AABB. Its intersection program advances t-max to the ray's entry +// into the volume or, if current t-max falls inside of the volume, leaves it +// unchanged. In addition to advancing t-max, the intersection program also +// reports the t-value of the ray exit location from the volume in payload 0. +// +// The volume's closest hit shader fires a continuation ray to +// a) obtain radiance as the ray enters the volume and +// b) a depth value with the continution ray's intersection. +// Then the transmittance through the volume is computed using a 3D DDA +// algorithm. For this the volume's density is integrated for the ray segment +// from t-max to either the continuation-ray depth or the exit-t, whichever is +// is closer. This makes it possible for solids to essentially displace the +// volume. Result radiance is computed by multiplying the incoming radiance +// with the transmittance. +// +// The (simplistic) use of a single AABB to represent a potentially large +// (relative to scene extent), sparse volume leads to integration happening +// along ray segments that may traverse large stretches of "empty volume". +// To leverage hardware accelerated ray-object intersection and "skip over" +// areas where the volume function is zero one may represent the volume in +// Optix's BVH by a series of AABBs of inner nodes of the NanoVDB tree +// structure. This was done in the viewer example that ships with the OpenVDB/ +// NanoVDB distribution (/~https://github.com/AcademySoftwareFoundation/openvdb). +// For the level-set rendering in that example, bounding-boxes for all leaf- +// nodes were added. +// ---------------------------------------------------------------------------- + + +// ---------------------------------------------------------------------------- +// +// Global settings +// +// ---------------------------------------------------------------------------- + +const float plane_scale_factor = 2.5f; +const float cube_scale_factor = 0.25f; + +// ---------------------------------------------------------------------------- +// +// Global state +// +// ---------------------------------------------------------------------------- + +OptixDeviceContext g_context; + +Volume g_volume = {}; +Plane g_plane = {}; +Cube g_cube = {}; + +VolumeAccel g_volume_accel = {}; +PlaneAccel g_plane_accel = {}; +CubeAccel g_cube_accel = {}; +IAS ias = {}; + +Params launch_params = {}; + +OptixModule module = 0; +ProgramGroups program_groups = {}; +OptixPipeline pipeline = 0; +OptixShaderBindingTable sbt = {}; + + +// ---------------------------------------------------------------------------- +// +// Global state for GUI +// +// ---------------------------------------------------------------------------- +bool resize_dirty = false; +bool minimized = false; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Mouse state +int32_t mouse_button = -1; + +int32_t width = 768; +int32_t height = 768; + + +// device-pointers to state that can be interactively changed, i.e. +// moving the cube via arrow-keys, moving the plane with 'u' and 'd', +// and changing the volume's opacity +std::vector dp_opacities; // the volume's opacity in the SBT (one for each ray-type) +CUdeviceptr dp_plane_y; // plane's y-coordinate in the device-instance array +CUdeviceptr dp_cube_x; // cube's x-coordinate in the device-instance array +CUdeviceptr dp_cube_z; // cube's z-coordinate in the device-instance array + +// boolean to track if object transformations were changed (e.g. plane_y, cube_x/y) +// when true the IAS must be rebuilt for the next frame +bool ias_changed = false; + + +// ----------------------------------------------------------------------------- +// state controls +// ----------------------------------------------------------------------------- + +// retrieve a single float from a device pointer location +float peek( CUdeviceptr location ) +{ + float value; + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( &value ), + reinterpret_cast( location ), + sizeof( float ), + cudaMemcpyDeviceToHost + ) ); + return value; +} + +// put a single float into a device pointer location +void poke( CUdeviceptr location, float value ) +{ + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( location ), + reinterpret_cast( &value ), + sizeof( float ), + cudaMemcpyHostToDevice + ) ); +} + +inline void increaseOpacity() +{ + for( CUdeviceptr dp_opacity : dp_opacities ) + { + float opacity = peek(dp_opacity); + opacity *= 1.1f; + if( opacity > 1.0f ) opacity = 1.0f; + poke(dp_opacity, opacity); + } + camera_changed = true; +} + +inline void decreaseOpacity() +{ + for( CUdeviceptr dp_opacity : dp_opacities ) + { + float opacity = peek(dp_opacity); + opacity /= 1.1f; + if( opacity > 1.0f ) opacity = 1.0f; + poke( dp_opacity, opacity ); + } + camera_changed = true; +} + +inline void raisePlane() +{ + float plane_y = peek( dp_plane_y ); + plane_y += 5.0f; + poke( dp_plane_y, plane_y ); + ias_changed = true; +} + +inline void lowerPlane() +{ + float plane_y = peek( dp_plane_y ); + plane_y -= 5.0f; + poke( dp_plane_y, plane_y ); + ias_changed = true; +} + +inline void zoomIn() +{ + // decrease field-of-view angle by 5% + camera.setFovY(camera.fovY() / 1.05f); + camera_changed = true; +} + +inline void zoomOut() +{ + // increase field-of-view angle by 5% + camera.setFovY(camera.fovY() * 1.05f); + camera_changed = true; +} + +inline void incCubeX() +{ + float cube_x = peek( dp_cube_x ); + cube_x += 5.0f; + poke( dp_cube_x, cube_x ); + ias_changed = true; +} + +inline void decCubeX() +{ + float cube_x = peek( dp_cube_x ); + cube_x -= 5.0f; + poke( dp_cube_x, cube_x ); + ias_changed = true; +} + +inline void incCubeZ() +{ + float cube_z = peek( dp_cube_z ); + cube_z += 5.0f; + poke( dp_cube_z, cube_z ); + ias_changed = true; +} + +inline void decCubeZ() +{ + float cube_z = peek( dp_cube_z ); + cube_z -= 5.0f; + poke( dp_cube_z, cube_z ); + ias_changed = true; +} + +inline void toggleCubeVisibility() +{ + launch_params.params.solid_objects ^= CUBE_OBJECT; +} + +inline void togglePlaneVisibility() +{ + launch_params.params.solid_objects ^= PLANE_OBJECT; +} + +inline void toggleVolumeVisibility() +{ + launch_params.params.volume_object ^= VOLUME_OBJECT; +} + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking(static_cast( xpos ), static_cast( ypos )); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), width, height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), width, height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + width = res_x; + height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || + key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + else if (key == GLFW_KEY_V ) + { + toggleVolumeVisibility(); + } + else if (key == GLFW_KEY_P ) + { + togglePlaneVisibility(); + } + else if (key == GLFW_KEY_C ) + { + toggleCubeVisibility(); + } + else if( key == GLFW_KEY_U ) + { + raisePlane(); + } + else if( key == GLFW_KEY_D ) + { + lowerPlane(); + } + else if( key == GLFW_KEY_I ) + { + zoomIn(); + } + else if( key == GLFW_KEY_O ) + { + zoomOut(); + } + else if( key == GLFW_KEY_RIGHT ) + { + incCubeX(); + } + else if( key == GLFW_KEY_LEFT ) + { + decCubeX(); + } + else if( key == GLFW_KEY_UP ) + { + incCubeZ(); + } + else if( key == GLFW_KEY_DOWN ) + { + decCubeZ(); + } + camera_changed = true; + } +} + +static void charCallback( GLFWwindow* window, unsigned int codepoint ) +{ + if( codepoint == '+' ) + { + increaseOpacity(); + } + else if( codepoint == '-' ) + { + decreaseOpacity(); + } +} + +static void scrollCallback( GLFWwindow* window, double xscroll, double yscroll ) +{ + if( trackball.wheelEvent( ( int )yscroll ) ) + camera_changed = true; +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// +//------------------------------------------------------------------------------ + +void printShortcuts() +{ + std::cerr << "Interactive controls:\n"; + std::cerr << " - 'v', 'p', 'c': toggle volume/plane/cube visibility\n"; + std::cerr << " - Cursor keys: move the cube around the horizontal plane\n"; + std::cerr << " - Keypad +/-: increase/decrease volume density\n"; + std::cerr << " - 'u'/'d': move the ground plane up or down\n"; + std::cerr << " - 'i'/'o': zoom in and out in 5% increments" << std::endl; +} + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage: " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 768x768\n"; + std::cerr << " --no-gl-interop Disable GL interop for display\n"; + std::cerr << " --volume Specify volume to render (required)\n"; + std::cerr << " --help | -h Print this usage message\n" << std::endl; + printShortcuts(); + exit( 0 ); +} + + +void initLaunchParams( Params& launch_params, const OptixTraversableHandle& handle, const sutil::Aabb& aabb ) +{ + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &launch_params.params.accum_buffer ), + width*height*sizeof( float4 ) + ) ); + launch_params.params.frame_buffer = nullptr; // Will be set when output buffer is mapped + + launch_params.params.width = width; + launch_params.params.height = height; + launch_params.params.subframe_index = 0u; + + const float loffset = aabb.maxExtent(); + + + std::vector lights( 2 ); + lights[0].type = Light::Type::POINT; + lights[0].point.color = {1.0f, 1.0f, 0.8f}; + lights[0].point.intensity = 5.0f; + lights[0].point.position = aabb.center() + make_float3( loffset ); + lights[0].point.falloff = Light::Falloff::QUADRATIC; + + lights[1].type = Light::Type::POINT; + lights[1].point.color = {0.8f, 0.8f, 1.0f}; + lights[1].point.intensity = 3.0f; + lights[1].point.position = aabb.center() + make_float3( -loffset, 1.f * loffset, -1.0f * loffset ); + lights[1].point.falloff = Light::Falloff::QUADRATIC; + + + launch_params.params.lights.count = static_cast( lights.size() ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &launch_params.params.lights.data ), + lights.size() * sizeof( Light ) + ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( launch_params.params.lights.data ), + lights.data(), + lights.size() * sizeof( Light ), + cudaMemcpyHostToDevice + ) ); + + launch_params.params.miss_color = make_float3( 0.3f, 0.3f, 0.9f ); + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &launch_params.d_params ), sizeof( LaunchParams ) ) ); + + launch_params.params.handle = handle; + + launch_params.params.solid_objects = PLANE_OBJECT | CUBE_OBJECT; + launch_params.params.volume_object = VOLUME_OBJECT; +} + +void cleanupLaunchParams( Params& launch_params ) +{ + CUDA_CHECK( cudaFree( reinterpret_cast( launch_params.params.accum_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( launch_params.params.lights.data ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( launch_params.d_params ) ) ); +} + + +void handleCameraUpdate( LaunchParams& params ) +{ + if( !camera_changed ) + return; + camera_changed = false; + + camera.setAspectRatio( static_cast( width ) / static_cast( height ) ); + params.eye = camera.eye(); + camera.UVWFrame( params.U, params.V, params.W ); +} + + +void handleResize( sutil::CUDAOutputBuffer& output_buffer ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + output_buffer.resize( width, height ); + + // Realloc accumulation buffer + CUDA_CHECK( cudaFree( reinterpret_cast( launch_params.params.accum_buffer ) ) ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &launch_params.params.accum_buffer ), + width*height*sizeof( float4 ) + ) ); +} + + +void handleIASUpdate() +{ + if( !ias_changed ) + return; + ias_changed = false; + updateIAS(ias, g_context); +} + + +void updateState( sutil::CUDAOutputBuffer& output_buffer, LaunchParams& params ) +{ + // Update params on device + if( camera_changed || resize_dirty ) + params.subframe_index = 0; + + handleIASUpdate(); + handleCameraUpdate( params ); + handleResize( output_buffer ); +} + + +void launchSubframe( sutil::CUDAOutputBuffer& output_buffer ) +{ + // Launch + uchar4* result_buffer_data = output_buffer.map(); + launch_params.params.frame_buffer = result_buffer_data; + CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast( launch_params.d_params ), + &launch_params.params, + sizeof( LaunchParams ), + cudaMemcpyHostToDevice, + 0 // stream + ) ); + + OPTIX_CHECK( optixLaunch( + pipeline, + 0, // stream + reinterpret_cast( launch_params.d_params ), + sizeof( LaunchParams ), + &sbt, + width, // launch width + height, // launch height + 1 // launch depth + ) ); + output_buffer.unmap(); + + CUDA_SYNC_CHECK(); +} + + +void displaySubframe( + sutil::CUDAOutputBuffer& output_buffer, + sutil::GLDisplay& gl_display, + GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( + output_buffer.width(), + output_buffer.height(), + framebuf_res_x, + framebuf_res_y, + output_buffer.getPBO() + ); +} + + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */ ) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n"; +} + + +void createContext( OptixDeviceContext& context ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + CUcontext cu_ctx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cu_ctx, &options, &context ) ); +} + + +// ---------------------------------------------------------------------------- +// Functions for manipulating Volume instances +// ---------------------------------------------------------------------------- + +void loadVolume( Volume& grid, const std::string& filename ) +{ + // NanoVDB files are containers for NanoVDB Grids. + // Each Grid represents a distinct volume, point-cloud, or level-set. + // For the purpose of this sample only the first grid is loaded, additional + // grids are ignored. + auto list = nanovdb::io::readGridMetaData( filename ); + std::cerr << "Opened file " << filename << std::endl; + std::cerr << " grids:" << std::endl; + for (auto& m : list) { + std::cerr << " " << m.gridName << std::endl; + } + assert( list.size() > 0 ); + // load the first grid in the file + createGrid( grid, filename, list[0].gridName ); +} + + void createGrid( Volume& grid, std::string filename, std::string gridname ) +{ + nanovdb::GridHandle<> gridHdl; + + if( gridname.length() > 0 ) + gridHdl = nanovdb::io::readGrid<>( filename, gridname ); + else + gridHdl = nanovdb::io::readGrid<>( filename ); + + if( !gridHdl ) + { + std::stringstream ss; + ss << "Unable to read " << gridname << " from " << filename; + throw std::runtime_error( ss.str() ); + } + + // NanoVDB Grids can represent several kinds of 3D data, but this sample is + // only concerned with volumetric data. + auto* meta = gridHdl.gridMetaData(); + if( meta->isPointData() ) + throw std::runtime_error("NanoVDB Point Data cannot be handled by VolumeViewer"); + if( meta->isLevelSet() ) + throw std::runtime_error("NanoVDB Level Sets cannot be handled by VolumeViewer"); + + // NanoVDB files represent the sparse data-structure as flat arrays that can be + // uploaded to the device "as-is". + assert( gridHdl.size() != 0 ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &grid.d_volume ), gridHdl.size() ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( grid.d_volume ), gridHdl.data(), gridHdl.size(), + cudaMemcpyHostToDevice ) ); + + grid.handle = std::move( gridHdl ); +} + + +void cleanupVolume( Volume& volume ) +{ + // OptiX cleanup + CUDA_CHECK_NOTHROW( cudaFree( reinterpret_cast( volume.d_volume ) ) ); +} + +void buildVolumeAccel( VolumeAccel& accel, const Volume& volume, const OptixDeviceContext& context ) +{ + // Build accel for the volume and store it in a VolumeAccel struct. + // + // For Optix the NanoVDB volume is represented as a 3D box in index coordinate space. The volume's + // GAS is created from a single AABB. Because the index space is by definition axis aligned with the + // volume's voxels, this AABB is the bounding-box of the volume's "active voxels". + + { + auto grid_handle = volume.handle.grid(); + + // get this grid's aabb + sutil::Aabb aabb; + { + // indexBBox returns the extrema of the (integer) voxel coordinates. + // Thus the actual bounds of the space covered by those voxels extends + // by one unit (or one "voxel size") beyond those maximum indices. + auto bbox = grid_handle->indexBBox(); + nanovdb::Coord boundsMin( bbox.min() ); + nanovdb::Coord boundsMax( bbox.max() + nanovdb::Coord( 1 ) ); // extend by one unit + + float3 min = { + static_cast( boundsMin[0] ), + static_cast( boundsMin[1] ), + static_cast( boundsMin[2] )}; + float3 max = { + static_cast( boundsMax[0] ), + static_cast( boundsMax[1] ), + static_cast( boundsMax[2] )}; + + aabb =sutil::Aabb( min, max ); + } + + // up to device + CUdeviceptr d_aabb; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_aabb ), sizeof( sutil::Aabb ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( d_aabb ), &aabb, + sizeof( sutil::Aabb ), cudaMemcpyHostToDevice ) ); + + // Make build input for this grid + uint32_t aabb_input_flags = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT; + OptixBuildInput build_input = {}; + build_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES; + build_input.customPrimitiveArray.aabbBuffers = &d_aabb; + build_input.customPrimitiveArray.flags = &aabb_input_flags; + build_input.customPrimitiveArray.numSbtRecords = 1; + build_input.customPrimitiveArray.numPrimitives = 1; + build_input.customPrimitiveArray.sbtIndexOffsetBuffer = 0; + build_input.customPrimitiveArray.sbtIndexOffsetSizeInBytes = 0; + build_input.customPrimitiveArray.primitiveIndexOffset = 0; + + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( context, &accel_options, + &build_input, 1, &gas_buffer_sizes ) ); + + CUdeviceptr d_temp_buffer_gas; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_buffer_gas ), + gas_buffer_sizes.tempSizeInBytes ) ); + CUdeviceptr d_output_buffer_gas; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_output_buffer_gas ), + gas_buffer_sizes.outputSizeInBytes ) ); + CUdeviceptr d_compacted_size; + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_compacted_size ), sizeof( size_t ) ) ); + + OptixAccelEmitDesc emit_property = {}; + emit_property.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emit_property.result = d_compacted_size; + + OPTIX_CHECK( optixAccelBuild( context, + 0, + &accel_options, + &build_input, + 1, + d_temp_buffer_gas, + gas_buffer_sizes.tempSizeInBytes, + d_output_buffer_gas, + gas_buffer_sizes.outputSizeInBytes, + &accel.handle, + &emit_property, + 1 ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_aabb ) ) ); + size_t compacted_size; + CUDA_CHECK( cudaMemcpy( &compacted_size, reinterpret_cast( emit_property.result ), + sizeof( size_t ), cudaMemcpyDeviceToHost ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_compacted_size ) ) ); + if( compacted_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &accel.d_buffer ), compacted_size ) ); + OPTIX_CHECK( optixAccelCompact( context, 0, accel.handle, + accel.d_buffer, compacted_size, &accel.handle ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_output_buffer_gas ) ) ); + } + else + { + accel.d_buffer = d_output_buffer_gas; + } + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer_gas ) ) ); + } +} + +void cleanupVolumeAccel( VolumeAccel& accel ) +{ + CUDA_CHECK_NOTHROW( cudaFree( reinterpret_cast( accel.d_buffer ) ) ); +} + +void getOptixTransform( const Volume& grid, float transform[] ) +{ + // Extract the index-to-world-space affine transform from the Grid and convert + // to 3x4 row-major matrix for Optix. + auto* grid_handle = grid.handle.grid(); + const nanovdb::Map& map = grid_handle->map(); + transform[0] = map.mMatF[0]; transform[1] = map.mMatF[1]; transform[2] = map.mMatF[2]; transform[3] = map.mVecF[0]; + transform[4] = map.mMatF[3]; transform[5] = map.mMatF[4]; transform[6] = map.mMatF[5]; transform[7] = map.mVecF[1]; + transform[8] = map.mMatF[6]; transform[9] = map.mMatF[7]; transform[10] = map.mMatF[8]; transform[11] = map.mVecF[2]; +} + +sutil::Aabb worldAabb( const Volume& grid ) +{ + auto* meta = grid.handle.gridMetaData(); + auto bbox = meta->worldBBox(); + float3 min = { static_cast( bbox.min()[0] ), + static_cast( bbox.min()[1] ), + static_cast( bbox.min()[2] ) }; + float3 max = { static_cast( bbox.max()[0] ), + static_cast( bbox.max()[1] ), + static_cast( bbox.max()[2] ) }; + + return sutil::Aabb( min, max ); +} + +// ---------------------------------------------------------------------------- +// Plane stuff +// ---------------------------------------------------------------------------- + +void createPlane( Plane& plane, const sutil::Aabb& aabb ) +{ + plane.transform = sutil::Matrix4x4::identity(); + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &plane.d_indices ), + plane.num_indices * sizeof( unsigned int ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( plane.d_indices ), plane.indices, + plane.num_indices * sizeof(unsigned int), cudaMemcpyHostToDevice)); + + float extent = plane_scale_factor * aabb.maxExtent(); + float3 center = aabb.center(); + + plane.positions[0] = make_float3( center.x - extent, aabb.m_min.y - 1.0f, center.z - extent ); + plane.positions[1] = make_float3( center.x - extent, aabb.m_min.y - 1.0f, center.z + extent ); + plane.positions[2] = make_float3( center.x + extent, aabb.m_min.y - 1.0f, center.z + extent ); + plane.positions[3] = make_float3( center.x + extent, aabb.m_min.y - 1.0f, center.z - extent ); + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &plane.d_positions ), + plane.num_positions * sizeof( float3 ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( plane.d_positions ), plane.positions, + plane.num_positions * sizeof( float3 ), cudaMemcpyHostToDevice ) ); + + plane.material.base_color = make_float3( 0.1f, 0.1f, 0.1f ); + + plane.aabb = sutil::Aabb( + make_float3( -10.0f, 0.0f, -10.0f ), + make_float3( 10.0f, 0.0f, 10.0f ) ); +} + +void cleanupPlane( Plane& plane ) +{ + CUDA_CHECK_NOTHROW( cudaFree( reinterpret_cast( plane.d_indices ) ) ); + CUDA_CHECK_NOTHROW( cudaFree( reinterpret_cast( plane.d_positions ) ) ); +} + +void buildPlaneAccel( PlaneAccel& plane_accel, const Plane& plane, const OptixDeviceContext& context ) +{ + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION + | OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS; // needed to compute normals in closest-hit program + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + uint32_t triangle_input_flags = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT; + + OptixBuildInput build_input = {}; + build_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + build_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + build_input.triangleArray.vertexStrideInBytes = sizeof( float3 ); + build_input.triangleArray.numVertices = plane.num_positions; + build_input.triangleArray.vertexBuffers = &( plane.d_positions ); + build_input.triangleArray.indexFormat = OPTIX_INDICES_FORMAT_UNSIGNED_BYTE3; + build_input.triangleArray.indexStrideInBytes = sizeof( unsigned char ) * 3; + build_input.triangleArray.numIndexTriplets = plane.num_indices / 3; + build_input.triangleArray.indexBuffer = plane.d_indices; + build_input.triangleArray.flags = &triangle_input_flags; + build_input.triangleArray.numSbtRecords = 1; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( context, &accel_options, &build_input, + 1, &gas_buffer_sizes ) ); + + CUdeviceptr d_temp = 0; + CUdeviceptr d_temp_output; + CUdeviceptr d_temp_compactedSizes; + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp ), gas_buffer_sizes.tempSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_output ), gas_buffer_sizes.outputSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_compactedSizes ), sizeof(size_t) ) ); + + emitProperty.result = d_temp_compactedSizes; + + OPTIX_CHECK( optixAccelBuild( + context, + 0, // CUDA stream + &accel_options, + &build_input, + 1, + d_temp, + gas_buffer_sizes.tempSizeInBytes, + d_temp_output, + gas_buffer_sizes.outputSizeInBytes, + &plane_accel.handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + size_t compacted_size = 0; + CUDA_CHECK( cudaMemcpy( reinterpret_cast( &compacted_size ), + reinterpret_cast( d_temp_compactedSizes ), sizeof( size_t ), + cudaMemcpyDeviceToHost + ) ); + + if( gas_buffer_sizes.outputSizeInBytes > compacted_size ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &plane_accel.d_buffer ), compacted_size ) ); + OPTIX_CHECK( optixAccelCompact( context, 0, plane_accel.handle, plane_accel.d_buffer, + compacted_size, &plane_accel.handle ) ); + } + else + { + plane_accel.d_buffer = d_temp_output; + d_temp_output = 0; + } + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_output ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_compactedSizes ) ) ); +} + +void cleanupPlaneAccel( PlaneAccel& plane_accel ) +{ + CUDA_CHECK( cudaFree( reinterpret_cast( plane_accel.d_buffer ) ) ); +} + + +// ---------------------------------------------------------------------------- +// Cube stuff +// ---------------------------------------------------------------------------- + +void createCube( Cube& cube, const sutil::Aabb& aabb ) +{ + cube.transform = sutil::Matrix4x4::identity(); + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &cube.d_indices ), + cube.num_indices * sizeof( unsigned int ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( cube.d_indices ), cube.indices, + cube.num_indices * sizeof(unsigned int), cudaMemcpyHostToDevice)); + + float extent = cube_scale_factor * aabb.maxExtent(); + float3 center = aabb.center(); + float height_offset = center.y - extent; + + cube.positions[0] = make_float3( 0, height_offset, extent ); + cube.positions[1] = make_float3( 0, height_offset, 0 ); + cube.positions[2] = make_float3( extent, height_offset, 0 ); + cube.positions[3] = make_float3( extent, height_offset, extent ); + + cube.positions[4] = make_float3( 0, height_offset + extent, extent ); + cube.positions[5] = make_float3( extent, height_offset + extent, extent ); + cube.positions[6] = make_float3( extent, height_offset + extent, 0 ); + cube.positions[7] = make_float3( 0, height_offset + extent, 0 ); + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &cube.d_positions ), + cube.num_positions * sizeof( float3 ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( cube.d_positions ), cube.positions, + cube.num_positions * sizeof( float3 ), cudaMemcpyHostToDevice ) ); + + cube.material.base_color = make_float3( 0.2f, 0.05f, 0.05f ); // redish cube + + cube.aabb = sutil::Aabb( + make_float3( 0, 0, 0 ), + make_float3( extent, extent, extent ) + ); +} + +void cleanupCube( Cube& cube ) +{ + CUDA_CHECK_NOTHROW( cudaFree( reinterpret_cast( cube.d_indices ) ) ); + CUDA_CHECK_NOTHROW( cudaFree( reinterpret_cast( cube.d_positions ) ) ); +} + +void buildCubeAccel( CubeAccel& cube_accel, const Cube& cube, const OptixDeviceContext& context ) +{ + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION + | OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS; // needed to compute normals in closest-hit program + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + uint32_t triangle_input_flags = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT; + + OptixBuildInput build_input = {}; + build_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + build_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + build_input.triangleArray.vertexStrideInBytes = sizeof( float3 ); + build_input.triangleArray.numVertices = cube.num_positions; + build_input.triangleArray.vertexBuffers = &( cube.d_positions ); + build_input.triangleArray.indexFormat = OPTIX_INDICES_FORMAT_UNSIGNED_BYTE3; + build_input.triangleArray.indexStrideInBytes = sizeof( unsigned char ) * 3; + build_input.triangleArray.numIndexTriplets = cube.num_indices / 3; + build_input.triangleArray.indexBuffer = cube.d_indices; + build_input.triangleArray.flags = &triangle_input_flags; + build_input.triangleArray.numSbtRecords = 1; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK( optixAccelComputeMemoryUsage( context, &accel_options, &build_input, + 1, &gas_buffer_sizes ) ); + + CUdeviceptr d_temp = 0; + CUdeviceptr d_temp_output; + CUdeviceptr d_temp_compactedSizes; + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp ), gas_buffer_sizes.tempSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_output ), gas_buffer_sizes.outputSizeInBytes ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_temp_compactedSizes ), sizeof(size_t) ) ); + + emitProperty.result = d_temp_compactedSizes; + + OPTIX_CHECK( optixAccelBuild( + context, + 0, // CUDA stream + &accel_options, + &build_input, + 1, + d_temp, + gas_buffer_sizes.tempSizeInBytes, + d_temp_output, + gas_buffer_sizes.outputSizeInBytes, + &cube_accel.handle, + &emitProperty, // emitted property list + 1 // num emitted properties + ) ); + + size_t compacted_size = 0; + CUDA_CHECK( cudaMemcpy( reinterpret_cast( &compacted_size ), + reinterpret_cast( d_temp_compactedSizes ), sizeof( size_t ), + cudaMemcpyDeviceToHost + ) ); + + if( gas_buffer_sizes.outputSizeInBytes > compacted_size ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &cube_accel.d_buffer ), compacted_size ) ); + OPTIX_CHECK( optixAccelCompact( context, 0, cube_accel.handle, cube_accel.d_buffer, + compacted_size, &cube_accel.handle ) ); + } + else + { + cube_accel.d_buffer = d_temp_output; + d_temp_output = 0; + } + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_output ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_compactedSizes ) ) ); +} + +void cleanupCubeAccel( CubeAccel& cube_accel ) +{ + CUDA_CHECK( cudaFree( reinterpret_cast( cube_accel.d_buffer ) ) ); +} + + +// ---------------------------------------------------------------------------- +// IAS stuff +// ---------------------------------------------------------------------------- + +void buildIAS( IAS& ias, int rayTypeCount, + const Volume& volume, const VolumeAccel& volume_accel, + const Plane& plane, const PlaneAccel& plane_accel, + const Cube& cube, const CubeAccel& cube_accel, + const OptixDeviceContext& context ) +{ + // The three scene elements, volume, box, and plane, are added to a single- + // level IAS; each receiving its own world-space transform. For the volume, + // this is the transform stored in the Grid. + std::vector optix_instances; + optix_instances.reserve( 2 ); + + unsigned int sbt_offset = 0; + + // process plane + { + OptixInstance optix_instance = {}; + + optix_instance.flags = OPTIX_INSTANCE_FLAG_NONE; + optix_instance.instanceId = static_cast( optix_instances.size() ); + optix_instance.sbtOffset = sbt_offset; + optix_instance.visibilityMask = PLANE_OBJECT; + optix_instance.traversableHandle = plane_accel.handle; + memcpy( optix_instance.transform, plane.transform.getData(), sizeof( float ) * 12 ); + + sbt_offset += rayTypeCount; // one sbt record per GAS build input per RAY_TYPE + optix_instances.push_back( optix_instance ); + } + + // process cube + { + OptixInstance optix_instance = {}; + + optix_instance.flags = OPTIX_INSTANCE_FLAG_NONE; + optix_instance.instanceId = static_cast( optix_instances.size() ); + optix_instance.sbtOffset = sbt_offset; + optix_instance.visibilityMask = CUBE_OBJECT; + optix_instance.traversableHandle = cube_accel.handle; + memcpy( optix_instance.transform, cube.transform.getData(), sizeof( float ) * 12 ); + + sbt_offset += rayTypeCount; // one sbt record per GAS build input per RAY_TYPE + optix_instances.push_back( optix_instance ); + } + + // process volume + { + OptixInstance optix_instance = {}; + + optix_instance.flags = OPTIX_INSTANCE_FLAG_NONE; + optix_instance.instanceId = static_cast( optix_instances.size() ); + optix_instance.sbtOffset = sbt_offset; + optix_instance.visibilityMask = VOLUME_OBJECT; + optix_instance.traversableHandle = volume_accel.handle; + getOptixTransform( volume, optix_instance.transform ); // transform as stored in Grid + + sbt_offset += rayTypeCount; // one sbt record per GAS build input per RAY_TYPE + optix_instances.push_back( optix_instance ); + } + + const size_t instances_size_in_bytes = sizeof( OptixInstance ) * optix_instances.size(); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &ias.d_instances ), instances_size_in_bytes ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( ias.d_instances ), + optix_instances.data(), + instances_size_in_bytes, + cudaMemcpyHostToDevice + ) ); + dp_plane_y = ias.d_instances + 7 * sizeof( float ); // seventh element of first transform is y offset + + dp_cube_x = ias.d_instances + sizeof( OptixInstance ) + 3 * sizeof( float ); // 3rd element of second transform is x offset + dp_cube_z = ias.d_instances + sizeof( OptixInstance ) + 11 * sizeof( float ); // 11th element of second transform is z offset + + ias.build_input.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; + ias.build_input.instanceArray.instances = ias.d_instances; + ias.build_input.instanceArray.numInstances = static_cast( optix_instances.size() ); + + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_UPDATE; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + OPTIX_CHECK( optixAccelComputeMemoryUsage( + context, + &accel_options, + &ias.build_input, + 1, // num build inputs + &ias.buffer_sizes + ) ); + + CUdeviceptr d_temp_buffer; + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_temp_buffer ), + ias.buffer_sizes.tempSizeInBytes + ) ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &ias.d_buffer ), + ias.buffer_sizes.outputSizeInBytes + ) ); + + OPTIX_CHECK( optixAccelBuild( + context, + nullptr, // CUDA stream + &accel_options, + &ias.build_input, + 1, // num build inputs + d_temp_buffer, + ias.buffer_sizes.tempSizeInBytes, + ias.d_buffer, + ias.buffer_sizes.outputSizeInBytes, + &ias.handle, + nullptr, // emitted property list + 0 // num emitted properties + ) ); + + CUDA_CHECK( cudaFree( reinterpret_cast( d_temp_buffer ) ) ); + +} + + +void updateIAS( IAS& ias, const OptixDeviceContext& context ) +{ + // Rebuild the IAS after scene elements were moved. + if( !ias.d_update_buffer ) + { + // make update temp buffer for ias + CUDA_CHECK( cudaMalloc( reinterpret_cast( &ias.d_update_buffer ), ias.buffer_sizes.tempUpdateSizeInBytes ) ); + } + + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_ALLOW_UPDATE; + accel_options.operation = OPTIX_BUILD_OPERATION_UPDATE; + + OPTIX_CHECK( optixAccelBuild( + context, + nullptr, // CUDA stream + &accel_options, + &ias.build_input, + 1, // num build inputs + ias.d_update_buffer, + ias.buffer_sizes.tempUpdateSizeInBytes, + ias.d_buffer, + ias.buffer_sizes.outputSizeInBytes, + &ias.handle, + nullptr, // emitted property list + 0 // num emitted properties + ) ); +} + +void cleanupIAS( IAS& ias ) +{ + CUDA_CHECK( cudaFree( reinterpret_cast( ias.d_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( ias.d_update_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( ias.d_instances ) ) ); +} + + +void createModule( OptixModule& module, const OptixDeviceContext& context ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + OptixPipelineCompileOptions pipeline_compile_options = {}; + pipeline_compile_options.usesMotionBlur = false; + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING; + pipeline_compile_options.numPayloadValues = NUM_PAYLOAD_VALUES; + pipeline_compile_options.numAttributeValues = 0; // TODO + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW; + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + + + size_t inputSize = 0; + const char* input = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "volume.cu", inputSize ); + module = {}; + OPTIX_CHECK_LOG( optixModuleCreate( + context, + &module_compile_options, + &pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &module + ) ); +} + + +// ---------------------------------------------------------------------------- +// ProgramGroups +// ---------------------------------------------------------------------------- + +void createProgramGroups( ProgramGroups& program_groups, + const OptixModule& module, + const OptixDeviceContext& context ) +{ + OptixProgramGroupOptions program_group_options = {}; + + // + // Ray generation + // + { + OptixProgramGroupDesc raygen_prog_group_desc = {}; + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__pinhole"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &program_groups.raygen + ) ); + } + + // + // Miss + // + { + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__radiance"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &program_groups.miss_radiance + ) ); + + memset( &miss_prog_group_desc, 0, sizeof( OptixProgramGroupDesc ) ); + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__occlusion"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &program_groups.miss_occlusion + ) ); + } + + // + // Mesh hit group + // + // This implements simple diffuse shading for the mesh surfaces (plane and cube). + // + { + OptixProgramGroupDesc hit_prog_group_desc = {}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__radiance_mesh"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &program_groups.mesh_radiance + ) ); + + memset( &hit_prog_group_desc, 0, sizeof( OptixProgramGroupDesc ) ); + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__occlusion_mesh"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &program_groups.mesh_occlusion + ) ); + } + + // + // Volume hit group + // + { + OptixProgramGroupDesc hit_prog_group_desc = {}; + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__radiance_volume"; + hit_prog_group_desc.hitgroup.moduleAH = nullptr; + hit_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + hit_prog_group_desc.hitgroup.moduleIS = module; + hit_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__volume"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &program_groups.volume_radiance + ) ); + + memset( &hit_prog_group_desc, 0, sizeof( OptixProgramGroupDesc ) ); + hit_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hit_prog_group_desc.hitgroup.moduleCH = module; + hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__occlusion_volume"; + hit_prog_group_desc.hitgroup.moduleAH = nullptr; + hit_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + hit_prog_group_desc.hitgroup.moduleIS = module; + hit_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__volume"; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + context, + &hit_prog_group_desc, + 1, // num program groups + &program_group_options, + LOG, &LOG_SIZE, + &program_groups.volume_occlusion + ) ); + } +} + +void cleanupProgramGroups( ProgramGroups& program_groups ) +{ + OPTIX_CHECK( optixProgramGroupDestroy( program_groups.raygen ) ); + OPTIX_CHECK( optixProgramGroupDestroy( program_groups.miss_radiance ) ); + OPTIX_CHECK( optixProgramGroupDestroy( program_groups.miss_occlusion ) ); + OPTIX_CHECK( optixProgramGroupDestroy( program_groups.mesh_radiance ) ); + OPTIX_CHECK( optixProgramGroupDestroy( program_groups.mesh_occlusion ) ); + OPTIX_CHECK( optixProgramGroupDestroy( program_groups.volume_radiance ) ); + OPTIX_CHECK( optixProgramGroupDestroy( program_groups.volume_occlusion ) ); +} + + +void createPipeline( OptixPipeline& pipeline, const ProgramGroups& programs, const OptixDeviceContext& context ) +{ + OptixPipelineCompileOptions pipeline_compile_options = {}; + pipeline_compile_options.usesMotionBlur = false; + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING; + pipeline_compile_options.numPayloadValues = NUM_PAYLOAD_VALUES; + pipeline_compile_options.numAttributeValues = 0; // TODO + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW; + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = 4; + + OPTIX_CHECK_LOG( optixPipelineCreate( + context, + &pipeline_compile_options, + &pipeline_link_options, + &programs.raygen, // ptr to first program group + sizeof( ProgramGroups ) / sizeof( OptixProgramGroup ), // number of program groups + LOG, &LOG_SIZE, + &pipeline + ) ); + + // We need to specify the max traversal depth. Calculate the stack sizes, so we can specify all + // parameters to optixPipelineSetStackSize. + OptixStackSizes stack_sizes = {}; + OPTIX_CHECK( optixUtilAccumulateStackSizes( programs.raygen, &stack_sizes, pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( programs.miss_radiance, &stack_sizes, pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( programs.miss_occlusion, &stack_sizes, pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( programs.mesh_radiance, &stack_sizes, pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( programs.mesh_occlusion, &stack_sizes, pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( programs.volume_radiance, &stack_sizes, pipeline ) ); + OPTIX_CHECK( optixUtilAccumulateStackSizes( programs.volume_occlusion, &stack_sizes, pipeline ) ); + + uint32_t max_trace_depth = 4; + uint32_t max_cc_depth = 0; + uint32_t max_dc_depth = 4; + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( + &stack_sizes, + max_trace_depth, + max_cc_depth, + max_dc_depth, + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, + &continuation_stack_size + ) ); + + const uint32_t max_traversal_depth = 2; + OPTIX_CHECK( optixPipelineSetStackSize( + pipeline, + direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, + continuation_stack_size, + max_traversal_depth + ) ); + +} + + +void createSBT( OptixShaderBindingTable& sbt, const ProgramGroups& program_groups, + const Volume& volume, const Plane& plane, const Cube& cube ) +{ + { + const size_t raygen_record_size = sizeof( sutil::EmptyRecord ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &sbt.raygenRecord ), raygen_record_size ) ); + + sutil::EmptyRecord rg_sbt; + OPTIX_CHECK( optixSbtRecordPackHeader( program_groups.raygen, &rg_sbt ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( sbt.raygenRecord ), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice + ) ); + } + + { + const size_t miss_record_size = sizeof( sutil::EmptyRecord ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &sbt.missRecordBase ), + miss_record_size * RAY_TYPE_COUNT + ) ); + + sutil::EmptyRecord ms_sbt[RAY_TYPE_COUNT]; + OPTIX_CHECK( optixSbtRecordPackHeader( program_groups.miss_radiance, &ms_sbt[0] ) ); + OPTIX_CHECK( optixSbtRecordPackHeader( program_groups.miss_occlusion, &ms_sbt[1] ) ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( sbt.missRecordBase ), + ms_sbt, + miss_record_size * RAY_TYPE_COUNT, + cudaMemcpyHostToDevice + ) ); + sbt.missRecordStrideInBytes = static_cast( miss_record_size ); + sbt.missRecordCount = RAY_TYPE_COUNT; + } + + { + std::vector hitgroup_records; + // plane sbt record + { + HitGroupRecord rec = {}; + OPTIX_CHECK(optixSbtRecordPackHeader( program_groups.mesh_radiance, &rec ) ); + + rec.data.material_data.lambert = plane.material; + hitgroup_records.push_back( rec ); + + OPTIX_CHECK( optixSbtRecordPackHeader( program_groups.mesh_occlusion, &rec ) ); + hitgroup_records.push_back( rec ); + } + + // cube sbt record + { + HitGroupRecord rec = {}; + OPTIX_CHECK(optixSbtRecordPackHeader( program_groups.mesh_radiance, &rec ) ); + + rec.data.material_data.lambert = cube.material; + hitgroup_records.push_back( rec ); + + OPTIX_CHECK( optixSbtRecordPackHeader( program_groups.mesh_occlusion, &rec ) ); + hitgroup_records.push_back( rec ); + } + + // volume sbt record + { + HitGroupRecord rec = {}; + OPTIX_CHECK( optixSbtRecordPackHeader( program_groups.volume_radiance, &rec ) ); + rec.data.geometry_data.volume.grid = reinterpret_cast( volume.d_volume ); + rec.data.material_data.volume.opacity = 0.125f; + hitgroup_records.push_back( rec ); + + OPTIX_CHECK(optixSbtRecordPackHeader( program_groups.volume_occlusion, &rec ) ); + hitgroup_records.push_back( rec ); + } + + const size_t hitgroup_record_size = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &sbt.hitgroupRecordBase ), + hitgroup_record_size*hitgroup_records.size() + ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( sbt.hitgroupRecordBase ), + hitgroup_records.data(), + hitgroup_record_size*hitgroup_records.size(), + cudaMemcpyHostToDevice + ) ); + + sbt.hitgroupRecordStrideInBytes = static_cast( hitgroup_record_size ); + sbt.hitgroupRecordCount = static_cast( hitgroup_records.size() ); + + // get device pointer to the opacity value in first volume hit record (radiosity) + CUdeviceptr dp_opacity = sbt.hitgroupRecordBase + 4 * sizeof( HitGroupRecord ) + + OPTIX_SBT_RECORD_HEADER_SIZE + sizeof( GeometryData ); + { + dp_opacities.push_back( dp_opacity ); + dp_opacity += sizeof( HitGroupRecord ); // advance device pointer to second opacity (occlusion) + dp_opacities.push_back( dp_opacity ); + dp_opacity += sizeof( HitGroupRecord ); + } + } +} + +void cleanupSBT( OptixShaderBindingTable& sbt ) +{ + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( sbt.hitgroupRecordBase ) ) ); +} + + +void initCameraState( const sutil::Aabb& aabb ) +{ + camera.setFovY( 45.0f ); + camera.setLookat( aabb.center() ); + camera.setEye ( aabb.center() + make_float3( 0.0f, 0.0f, 1.5f * aabb.maxExtent() ) ); + + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( make_float3( 1.0f, 0.0f, 0.0f ), make_float3( 0.0f, 0.0f, 1.0f ), make_float3( 0.0f, 1.0f, 0.0f ) ); + trackball.setGimbalLock( true ); +} + +//------------------------------------------------------------------------------ +// +// Main +// +//------------------------------------------------------------------------------ + +int main( int argc, char* argv[] ) +{ + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::GL_INTEROP; + + // + // Parse command line options + // + std::string outfile; + std::string infile; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--no-gl-interop" ) + { + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + } + else if( arg == "--volume" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + infile = argv[++i]; + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outfile = argv[++i]; + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + sutil::parseDimensions( dims_arg.c_str(), width, height ); + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + if( infile.empty() ) // ...use default + infile = sutil::sampleDataFilePath( "Volumes/smoke.nvdb" ); + + try + { + createContext( g_context ); + + loadVolume( g_volume, infile.c_str() ); + buildVolumeAccel( g_volume_accel, g_volume, g_context ); + createPlane( g_plane, worldAabb( g_volume ) ); + buildPlaneAccel( g_plane_accel, g_plane, g_context ); + createCube( g_cube, worldAabb( g_volume ) ); + buildCubeAccel( g_cube_accel, g_cube, g_context ); + createModule( module, g_context ); + createProgramGroups( program_groups, module, g_context ); + createPipeline( pipeline, program_groups, g_context ); + createSBT( sbt, program_groups, g_volume, g_plane, g_cube ); + buildIAS( ias, RAY_TYPE_COUNT, + g_volume, g_volume_accel, + g_plane, g_plane_accel, + g_cube, g_cube_accel, + g_context ); + + initCameraState( worldAabb( g_volume) ); + initLaunchParams( launch_params, ias.handle, worldAabb( g_volume ) ); + + printShortcuts(); + + if( outfile.empty() ) + { + GLFWwindow* window = sutil::initUI( "optixVolumeViewer", width, height ); + glfwSetMouseButtonCallback ( window, mouseButtonCallback ); + glfwSetCursorPosCallback ( window, cursorPosCallback ); + glfwSetWindowSizeCallback ( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback ( window, keyCallback ); + glfwSetCharCallback ( window, charCallback ); + glfwSetScrollCallback ( window, scrollCallback ); + + // + // Render loop + // + { + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, width, height ); + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + updateState( output_buffer, launch_params.params ); + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + launchSubframe( output_buffer ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1 - t0; + + sutil::displayStats( state_update_time, render_time, display_time ); + + glfwSwapBuffers(window); + + ++launch_params.params.subframe_index; + } + while( !glfwWindowShouldClose( window ) ); + CUDA_SYNC_CHECK(); + } + + sutil::cleanupUI( window ); + } + else + { + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + sutil::initGLFW(); // For GL context + sutil::initGL(); + } + + { + // this scope is for output_buffer, to ensure the destructor is called bfore glfwTerminate() + + sutil::CUDAOutputBuffer output_buffer( output_buffer_type, width, height ); + handleCameraUpdate( launch_params.params ); + handleResize( output_buffer ); + launchSubframe( output_buffer ); + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + glfwTerminate(); + } + } + + cleanupSBT( sbt ); + OPTIX_CHECK( optixPipelineDestroy( pipeline ) ); + cleanupProgramGroups( program_groups ); + OPTIX_CHECK( optixModuleDestroy( module ) ); + cleanupLaunchParams( launch_params ); + cleanupIAS( ias ); + cleanupPlaneAccel( g_plane_accel ); + cleanupVolumeAccel( g_volume_accel ); + cleanupPlane( g_plane ); + cleanupVolume( g_volume ); + cleanupCube( g_cube ); + cleanupCubeAccel( g_cube_accel ); + optixDeviceContextDestroy( g_context ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/optixVolumeViewer.h b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/optixVolumeViewer.h new file mode 100644 index 00000000..97fb8aa8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/optixVolumeViewer.h @@ -0,0 +1,200 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "volume.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + + +// The Volume struct ties together the NanoVDB host representation +// (NanoVDB Grid) and the device-buffer containing the sparse volume +// representation (NanoVDB Tree). In addition to the Tree, the Grid +// also contains an affine transform relating index space (i.e. voxel +// indices) to world-space. +// +struct Volume +{ + nanovdb::GridHandle<> handle; + CUdeviceptr d_volume = 0; +}; + +void loadVolume( Volume& volume, const std::string& filename ); +void cleanupVolume( Volume& volume ); +void createGrid( Volume& volume, std::string filename, std::string gridname ); +void getOptixTransform( const Volume& volume, float transform[] ); +sutil::Aabb worldAabb( const Volume& volume ); + +// The VolumeAccel struct contains a volume's geometric representation for +// Optix: a traversalbe handle, and the (compacted) GAS device-buffer. +struct VolumeAccel +{ + OptixTraversableHandle handle = 0; + CUdeviceptr d_buffer = 0; +}; + +void buildVolumeAccel( VolumeAccel& accel, const Volume& volume, const OptixDeviceContext& context ); +void cleanupVolumeAccel( VolumeAccel& accel ); + + +struct Plane +{ + sutil::Matrix4x4 transform; + + static const unsigned int num_indices = 6; + const unsigned char indices[num_indices] = {0, 1, 3, 1, 2, 3}; + CUdeviceptr d_indices = 0; + + static const unsigned int num_positions = 4; + float3 positions[num_positions] = {}; + CUdeviceptr d_positions = 0; + + MaterialData::Lambert material; + + sutil::Aabb aabb; +}; + +void createPlane( Plane& plane, const sutil::Aabb& aabb ); +void cleanupPlane( Plane& plane ); + + +struct PlaneAccel +{ + OptixTraversableHandle handle = 0; + CUdeviceptr d_buffer = 0; +}; + +void buildPlaneAccel( PlaneAccel& plane_accel, const Plane& plane, const OptixDeviceContext& context ); +void cleanupPlaneAccel( PlaneAccel& plane_accel ); + + +// Cube is for more testing of volume-solid interactions, ignore for review +// as this will be taken out for release. +struct Cube +{ + sutil::Matrix4x4 transform; + + static const unsigned int num_indices = 6 * 2 * 3; + const unsigned char indices[num_indices] = {0, 1, 2, 0, 2, 3, + 0, 3, 5, 0, 5, 4, + 3, 2, 6, 3, 6, 5, + 0, 4, 7, 0, 7, 1, + 1, 7, 6, 1, 6, 2, + 4, 5, 6, 4, 6, 7}; + CUdeviceptr d_indices = 0; + + static const unsigned int num_positions = 8; + float3 positions[num_positions] = {}; + CUdeviceptr d_positions = 0; + + MaterialData::Lambert material; + + sutil::Aabb aabb; +}; + +void createCube( Cube& cube, const sutil::Aabb& aabb ); +void cleanupCube( Cube& cube); + + +struct CubeAccel +{ + OptixTraversableHandle handle = 0; + CUdeviceptr d_buffer = 0; +}; + +void buildCubeAccel( CubeAccel& cube_accel, const Cube& cube, const OptixDeviceContext& context ); +void cleanupCubeAccel( CubeAccel& cube_accel ); + + +struct ProgramGroups +{ + OptixProgramGroup raygen = 0; + + OptixProgramGroup miss_radiance = 0; + OptixProgramGroup miss_occlusion = 0; + + OptixProgramGroup mesh_radiance = 0; + OptixProgramGroup mesh_occlusion = 0; + + OptixProgramGroup volume_radiance = 0; + OptixProgramGroup volume_occlusion = 0; +}; + +void createProgramGroups( ProgramGroups& program_groups, + const OptixModule& module, + const OptixDeviceContext& context ); +void cleanupProgramGroups( ProgramGroups& program_groups ); + + +struct Params +{ + LaunchParams params = {}; + LaunchParams* d_params = 0; +}; + +void initLaunchParams( Params& launch_params, const OptixTraversableHandle& handle, const sutil::Aabb& aabb ); +void cleanupLaunchParams( Params& launch_params ); + + +struct IAS +{ + OptixTraversableHandle handle = 0; + CUdeviceptr d_buffer = 0; + OptixAccelBufferSizes buffer_sizes = {}; + OptixBuildInput build_input = {}; + CUdeviceptr d_instances = 0; + CUdeviceptr d_update_buffer = 0; +}; + +void buildIAS( IAS& ias, int rayTypeCount, + const Volume& volume, const VolumeAccel& volume_accel, + const Plane& plane, const PlaneAccel& plane_accel, + const Cube& cube, const CubeAccel& cube_accel, + const OptixDeviceContext& context ); +void updateIAS( IAS& ias, const OptixDeviceContext& context ); +void cleanupIAS( IAS& ias ); + + +typedef sutil::Record HitGroupRecord; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/volume.cu b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/volume.cu new file mode 100644 index 00000000..e6fe647f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/volume.cu @@ -0,0 +1,411 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "volume_cuda.h" + +#include +#include +#include +#include + +#include +#include + + +__constant__ LaunchParams params; + + +// ---------------------------------------------------------------------------- +// Raygen program +// ---------------------------------------------------------------------------- +extern "C" __global__ void __raygen__pinhole() +{ + const uint3 launch_idx = optixGetLaunchIndex(); + const uint3 launch_dims = optixGetLaunchDimensions(); + const float3 eye = params.eye; + const float3 U = params.U; + const float3 V = params.V; + const float3 W = params.W; + const int subframe_index = params.subframe_index; + + // + // Generate camera ray + // + unsigned int seed = tea<4>( launch_idx.y * launch_dims.x + launch_idx.x, subframe_index ); + + const float2 subpixel_jitter = + subframe_index == 0 ? make_float2( 0.5f, 0.5f ) : make_float2( rnd( seed ), rnd( seed ) ); + + const float2 d = + 2.0f * make_float2( ( static_cast( launch_idx.x ) + subpixel_jitter.x ) / static_cast( launch_dims.x ), + ( static_cast( launch_idx.y ) + subpixel_jitter.y ) / static_cast( launch_dims.y ) ) + - 1.0f; + const float3 ray_direction = normalize( d.x * U + d.y * V + W ); + const float3 ray_origin = eye; + + // + // Trace camera ray + // + PayloadRadiance payload; + payload.result = make_float3( 0.0f ); + + traceRadiance( params.handle, ray_origin, ray_direction, + 0.01f, // tmin + 1e16f, // tmax + params.solid_objects | params.volume_object, + &payload ); + + // + // Update results + // + const unsigned int image_index = launch_idx.y * launch_dims.x + launch_idx.x; + const float4 accum_color = make_float4( payload.result, 1.0f ); + if( subframe_index ) + params.accum_buffer[image_index] += accum_color; + else + params.accum_buffer[image_index] = accum_color; + const float scale = 1.0f / (subframe_index + 1); + params.frame_buffer[image_index] = make_color( scale * params.accum_buffer[image_index] ); +} + +// ---------------------------------------------------------------------------- +// Miss programs +// ---------------------------------------------------------------------------- +extern "C" __global__ void __miss__radiance() +{ + optixSetPayload_0( __float_as_uint( params.miss_color.x ) ); + optixSetPayload_1( __float_as_uint( params.miss_color.y ) ); + optixSetPayload_2( __float_as_uint( params.miss_color.z ) ); + optixSetPayload_3( __float_as_uint( 1e16 ) ); // report depth (here "infinity") +} + +extern "C" __global__ void __miss__occlusion() +{ + optixSetPayload_0( __float_as_uint( 1.0f ) ); // report transmittance +} + +inline __device__ void transformNormalObjectToWorld(float3 &n) +{ + // because the sample only uses the translation part of the instance + // transform, this can be a no-op + // enforcing, that linear part of the affine transform is identity + // matrix: + for( unsigned int i = 0; i < optixGetTransformListSize(); ++i ) + { + OptixTraversableHandle handle = optixGetTransformListHandle( i ); + switch( optixGetTransformTypeFromHandle( handle ) ) + { + case OPTIX_TRANSFORM_TYPE_INSTANCE: { + const float4* trns = optixGetInstanceInverseTransformFromHandle( handle ); + assert(trns[0].x == 1.0f && trns[0].y == 0.0f && trns[0].z == 0.0f); + assert(trns[1].x == 0.0f && trns[1].y == 1.0f && trns[1].z == 0.0f); + assert(trns[2].x == 0.0f && trns[2].y == 0.0f && trns[2].z == 1.0f); + } + break; + default: + assert(false); // there can only be a single instance transform + } + } +} + +// ---------------------------------------------------------------------------- +// Closest hit programs +// ---------------------------------------------------------------------------- +extern "C" __global__ void __closesthit__radiance_mesh() +{ + const HitGroupData* hit_group_data = reinterpret_cast( optixGetSbtDataPointer() ); + const float3 base_color = hit_group_data->material_data.lambert.base_color; + const float ray_tmax = optixGetRayTmax(); + const float3 P = optixGetWorldRayOrigin() + ray_tmax * optixGetWorldRayDirection(); + + // + // compute direct lighting + // + + const OptixTraversableHandle gas = optixGetGASTraversableHandle(); + const unsigned int gasSbtIdx = optixGetSbtGASIndex(); + const unsigned int primIdx = optixGetPrimitiveIndex(); + float3 vertices[3] = {}; + optixGetTriangleVertexData( + gas, + primIdx, + gasSbtIdx, + 0, + vertices ); + + // compute normal from vertices (all objects have planar surfaces) + float3 N = normalize( + cross( vertices[1] - vertices[0], vertices[2] - vertices[0] ) + ); + transformNormalObjectToWorld(N); + + + float3 result = make_float3( 0.0f ); + + for( int i = 0; i < params.lights.count; ++i ) + { + Light light = params.lights[i]; + if( light.type == Light::Type::POINT ) + { + const float L_dist = length( light.point.position - P ); + const float3 L = ( light.point.position - P ) / L_dist; + const float N_dot_L = dot( N, L ); + + if( N_dot_L > 0.0f ) + { + const float tmin = 0.001f; + const float tmax = L_dist - 0.001f; + float transmittance = 1.0f; + traceOcclusion( + params.handle, + P, + L, + tmin, + tmax, + params.solid_objects | params.volume_object, + &transmittance + ); + result += transmittance * base_color * light.point.color * light.point.intensity * N_dot_L; + } + } + } + optixSetPayload_0( __float_as_uint( result.x ) ); + optixSetPayload_1( __float_as_uint( result.y ) ); + optixSetPayload_2( __float_as_uint( result.z ) ); + optixSetPayload_3( __float_as_uint( ray_tmax ) ); // report depth +} + +extern "C" __global__ void __closesthit__occlusion_mesh() +{ + optixSetPayload_0( __float_as_uint( 0.0f ) ); // report transmittance, i.e. plane is opaque +} + + +// ---------------------------------------------------------------------------- +// Volume programs +// ---------------------------------------------------------------------------- + +inline __device__ void confine( const nanovdb::BBox &bbox, nanovdb::Vec3f &iVec ) +{ + // NanoVDB's voxels and tiles are formed from half-open intervals, i.e. + // voxel[0, 0, 0] spans the set [0, 1) x [0, 1) x [0, 1). To find a point's voxel, + // its coordinates are simply truncated to integer. Ray-box intersections yield + // pairs of points that, because of numerical errors, fall randomly on either side + // of the voxel boundaries. + // This confine method, given a point and a (integer-based/Coord-based) bounding + // box, moves points outside the bbox into it. That means coordinates at lower + // boundaries are snapped to the integer boundary, and in case of the point being + // close to an upper boundary, it is move one EPS below that bound and into the volume. + + // get the tighter box around active values + auto iMin = nanovdb::Vec3f( bbox.min() ); + auto iMax = nanovdb::Vec3f( bbox.max() ) + nanovdb::Vec3f( 1.0f ); + + // move the start and end points into the bbox + float eps = 1e-7f; + if( iVec[0] < iMin[0] ) iVec[0] = iMin[0]; + if( iVec[1] < iMin[1] ) iVec[1] = iMin[1]; + if( iVec[2] < iMin[2] ) iVec[2] = iMin[2]; + if( iVec[0] >= iMax[0] ) iVec[0] = iMax[0] - fmaxf( 1.0f, fabsf( iVec[0] ) ) * eps; + if( iVec[1] >= iMax[1] ) iVec[1] = iMax[1] - fmaxf( 1.0f, fabsf( iVec[1] ) ) * eps; + if( iVec[2] >= iMax[2] ) iVec[2] = iMax[2] - fmaxf( 1.0f, fabsf( iVec[2] ) ) * eps; +} + +inline __hostdev__ void confine( const nanovdb::BBox &bbox, nanovdb::Vec3f &iStart, nanovdb::Vec3f &iEnd ) +{ + confine( bbox, iStart ); + confine( bbox, iEnd ); +} + +template +inline __device__ float transmittanceHDDA( + const nanovdb::Vec3f& start, + const nanovdb::Vec3f& end, + AccT& acc, const float opacity ) +{ + + // transmittance along a ray through the volume is computed by + // taking the negative exponential of volume's density integrated + // along the ray. + float transmittance = 1.f; + auto dir = end - start; + auto len = dir.length(); + nanovdb::Ray ray( start, dir / len, 0.0f, len ); + nanovdb::Coord ijk = nanovdb::RoundDown( ray.start() ); // first hit of bbox + + // Use NanoVDB's HDDA line digitization for fast integration. + // This algorithm (http://www.museth.org/Ken/Publications_files/Museth_SIG14.pdf) + // can skip over sparse parts of the data structure. + // + nanovdb::HDDA > hdda( ray, acc.getDim( ijk, ray ) ); + + float t = 0.0f; + float density = acc.getValue( ijk ) * opacity; + while( hdda.step() ) + { + float dt = hdda.time() - t; // compute length of ray-segment intersecting current voxel/tile + transmittance *= expf( -density * dt ); + t = hdda.time(); + ijk = hdda.voxel(); + + density = acc.getValue( ijk ) * opacity; + hdda.update( ray, acc.getDim( ijk, ray ) ); // if necessary adjust DDA step size + } + + return transmittance; +} + + +extern "C" __global__ void __intersection__volume() +{ + const auto* sbt_data = reinterpret_cast( optixGetSbtDataPointer() ); + const nanovdb::FloatGrid* grid = reinterpret_cast( + sbt_data->geometry_data.volume.grid ); + assert( grid ); + + // compute intersection points with the volume's bounds in index (object) space. + const float3 ray_orig = optixGetObjectRayOrigin(); + const float3 ray_dir = optixGetObjectRayDirection(); + + auto bbox = grid->indexBBox(); + float t0 = optixGetRayTmin(); + float t1 = optixGetRayTmax(); + auto iRay = nanovdb::Ray( reinterpret_cast( ray_orig ), + reinterpret_cast( ray_dir ), t0, t1 ); + + if( iRay.intersects( bbox, t0, t1 ) ) + { + // report the exit point via payload + optixSetPayload_0( __float_as_uint( t1 ) ); + // report the entry-point as hit-point + optixReportIntersection( fmaxf( t0, optixGetRayTmin() ), 0 ); + } +} + +extern "C" __global__ void __closesthit__radiance_volume() +{ + const HitGroupData* sbt_data = reinterpret_cast( optixGetSbtDataPointer() ); + + const auto* grid = reinterpret_cast( + sbt_data->geometry_data.volume.grid ); + const auto& tree = grid->tree(); + auto acc = tree.getAccessor(); + + const float3 ray_orig = optixGetWorldRayOrigin(); + const float3 ray_dir = optixGetWorldRayDirection(); + + const float t0 = optixGetRayTmax(); + const float t1 = __uint_as_float( optixGetPayload_0() ); + + // trace a continuation ray + // + // the continuation ray provides two things: + // - the radiance "entering the volume" + // - the "depth" to the next closest object intersected by the ray. + // Note, that such an object might be inside the volume. In that case, + // transmittance needs to be integrated through the volume along the ray + // up to that closer hit-point. + PayloadRadiance payload = {}; + traceRadiance( + params.handle, + ray_orig, + ray_dir, + 0.0f, + 1e16f, + params.solid_objects, // visibility mask - limit intersections to solid objects + &payload + ); + + const auto ray = nanovdb::Ray( reinterpret_cast( ray_orig ), + reinterpret_cast( ray_dir ) ); + auto start = grid->worldToIndexF( ray( t0 ) ); + auto end = grid->worldToIndexF( ray( fminf( payload.depth, t1 ) ) ); + + auto bbox = grid->indexBBox(); + confine( bbox, start, end ); + + // compute transmittance from the entry-point into the volume to either + // the ray's exit point out of the volume, or the hit point found by the + // continuation ray, if that is closer. + const float opacity = sbt_data->material_data.volume.opacity; + float transmittance = transmittanceHDDA( start, end, acc, opacity ); + + float3 result = payload.result * transmittance; + + optixSetPayload_0( __float_as_uint( result.x ) ); + optixSetPayload_1( __float_as_uint( result.y ) ); + optixSetPayload_2( __float_as_uint( result.z ) ); + optixSetPayload_3( __float_as_uint( 0.0f ) ); +} + +extern "C" __global__ void __closesthit__occlusion_volume() +{ + const HitGroupData* sbt_data = ( HitGroupData* )optixGetSbtDataPointer(); + + const auto* grid = reinterpret_cast( sbt_data->geometry_data.volume.grid ); + auto acc = grid->tree().getAccessor(); + + const float3 ray_orig = optixGetWorldRayOrigin(); + const float3 ray_dir = optixGetWorldRayDirection(); + + const float t0 = optixGetRayTmax(); + const float t1 = __uint_as_float( optixGetPayload_0() ); + + float transmittance = 1.0f; + + // trace a continuation ray + traceOcclusion( + params.handle, + ray_orig, + ray_dir, + 0.01f, + 1e16f, + params.solid_objects, + &transmittance + ); + + // if the continuation ray didn't hit a solid, compute how much the volume + // attenuates/shadows the light along the ray + if( transmittance != 0.0f ) + { + const auto ray = nanovdb::Ray( reinterpret_cast( ray_orig ), + reinterpret_cast( ray_dir ) ); + auto start = grid->worldToIndexF( ray( t0 ) ); + auto end = grid->worldToIndexF( ray( t1 ) ); + + auto bbox = grid->indexBBox(); + confine( bbox, start, end ); + + const float opacity = sbt_data->material_data.volume.opacity; + transmittance *= transmittanceHDDA( start, end, acc, opacity ); + } + optixSetPayload_0( __float_as_uint( transmittance ) ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/volume.h b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/volume.h new file mode 100644 index 00000000..93d72c7c --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/volume.h @@ -0,0 +1,142 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include + + +const unsigned int NUM_PAYLOAD_VALUES = 4u; + + +enum ObjectType +{ + PLANE_OBJECT = 1, + CUBE_OBJECT = 1 << 1, + VOLUME_OBJECT = 1 << 2, + ANY_OBJECT = 0xFF, +}; + + +enum RayType +{ + RAY_TYPE_RADIANCE = 0, + RAY_TYPE_OCCLUSION = 1, + RAY_TYPE_COUNT = 2 +}; + + +struct LaunchParams +{ + unsigned int width; + unsigned int height; + unsigned int subframe_index; + float4* accum_buffer; + uchar4* frame_buffer; + int max_depth; + + float3 eye; + float3 U; + float3 V; + float3 W; + + BufferView lights; + float3 miss_color; + OptixTraversableHandle handle; + + // Visbility masks + unsigned int solid_objects; + unsigned int volume_object; +}; + + +struct MaterialData +{ + struct Lambert + { + float3 base_color; + }; + + struct Volume + { + float opacity; // effectively a scale factor for volume density + }; + + + union + { + Lambert lambert; + Volume volume; + }; +}; + + +struct GeometryData +{ + struct Plane + { + float3 normal; + }; + + struct Volume + { + void* grid; + }; + + + union + { + Plane plane; + Volume volume; + }; +}; + + +struct HitGroupData +{ + GeometryData geometry_data; + MaterialData material_data; +}; + + +struct PayloadRadiance +{ + float3 result; + float depth; +}; + + +struct PayloadOcclusion +{ +}; diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/volume_cuda.h b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/volume_cuda.h new file mode 100644 index 00000000..51eee67b --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixVolumeViewer/volume_cuda.h @@ -0,0 +1,94 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2021 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "volume.h" + +#include +#include "nanovdb/NanoVDB.h" + + +static __forceinline__ __device__ void traceRadiance( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax, + unsigned int mask, + PayloadRadiance* payload ) +{ + unsigned int u0=0, u1=0, u2=0, u3=0; + optixTrace( + handle, + ray_origin, ray_direction, + tmin, + tmax, + 0.0f, // rayTime + mask, + OPTIX_RAY_FLAG_NONE, + RAY_TYPE_RADIANCE, // SBT offset + RAY_TYPE_COUNT, // SBT stride + RAY_TYPE_RADIANCE, // missSBTIndex + u0, u1, u2, u3 ); + + payload->result.x = __uint_as_float( u0 ); + payload->result.y = __uint_as_float( u1 ); + payload->result.z = __uint_as_float( u2 ); + payload->depth = __uint_as_float( u3 ); +} + + +static __forceinline__ __device__ void traceOcclusion( + OptixTraversableHandle handle, + float3 ray_origin, + float3 ray_direction, + float tmin, + float tmax, + unsigned int mask, + float* transmittance + ) +{ + optixTrace( + handle, + ray_origin, + ray_direction, + tmin, + tmax, + 0.0f, // rayTime + mask, + OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT, //OPTIX_RAY_FLAG_NONE, + RAY_TYPE_OCCLUSION, // SBT offset + RAY_TYPE_COUNT, // SBT stride + RAY_TYPE_OCCLUSION, // missSBTIndex + reinterpret_cast( *transmittance ) + ); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixWhitted/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/optixWhitted/CMakeLists.txt new file mode 100644 index 00000000..c634e9f7 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixWhitted/CMakeLists.txt @@ -0,0 +1,41 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OPTIX_add_sample_executable( optixWhitted target_name + ${SAMPLES_CUDA_DIR}/helpers.h + ${SAMPLES_CUDA_DIR}/whitted.h + ${SAMPLES_CUDA_DIR}/camera.cu + ${SAMPLES_CUDA_DIR}/geometry.cu + ${SAMPLES_CUDA_DIR}/shading.cu + optixWhitted.cpp + ) + +target_link_libraries( ${target_name} + ${CUDA_LIBRARIES} + ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/optixWhitted/optixWhitted.cpp b/Extern/3rdParty/OptiX/Linux/SDK/optixWhitted/optixWhitted.cpp new file mode 100644 index 00000000..107676cc --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/optixWhitted/optixWhitted.cpp @@ -0,0 +1,1223 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include // Needs to be included before gl_interop + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +//------------------------------------------------------------------------------ +// +// Globals +// +//------------------------------------------------------------------------------ + +bool resize_dirty = false; +bool minimized = false; + +// Camera state +bool camera_changed = true; +sutil::Camera camera; +sutil::Trackball trackball; + +// Mouse state +int32_t mouse_button = -1; + +const int max_trace = 12; + +//------------------------------------------------------------------------------ +// +// Local types +// TODO: some of these should move to sutil or optix util header +// +//------------------------------------------------------------------------------ +typedef sutil::Record HitGroupRecord; + +const uint32_t OBJ_COUNT = 3; + +struct WhittedState +{ + OptixDeviceContext context = 0; + OptixTraversableHandle gas_handle = {}; + CUdeviceptr d_gas_output_buffer = {}; + + OptixModule geometry_module = 0; + OptixModule camera_module = 0; + OptixModule shading_module = 0; + OptixModule sphere_module = 0; + + OptixProgramGroup raygen_prog_group = 0; + OptixProgramGroup radiance_miss_prog_group = 0; + OptixProgramGroup occlusion_miss_prog_group = 0; + OptixProgramGroup radiance_glass_sphere_prog_group = 0; + OptixProgramGroup occlusion_glass_sphere_prog_group = 0; + OptixProgramGroup radiance_metal_sphere_prog_group = 0; + OptixProgramGroup occlusion_metal_sphere_prog_group = 0; + OptixProgramGroup radiance_floor_prog_group = 0; + OptixProgramGroup occlusion_floor_prog_group = 0; + + OptixPipeline pipeline = 0; + OptixPipelineCompileOptions pipeline_compile_options = {}; + + CUstream stream = 0; + whitted::LaunchParams params; + whitted::LaunchParams* d_params = nullptr; + + OptixShaderBindingTable sbt = {}; +}; + +//------------------------------------------------------------------------------ +// +// Geometry and Camera data +// +//------------------------------------------------------------------------------ + +// Metal sphere, glass sphere, floor +const GeometryData::Sphere g_sphere = { + { 2.0f, 1.5f, -2.5f }, // center + 1.0f // radius +}; +const GeometryData::SphereShell g_sphere_shell = { + { 4.0f, 2.3f, -4.0f }, // center + 0.96f, // radius1 + 1.0f // radius2 +}; +const GeometryData::Parallelogram g_floor( + make_float3( 32.0f, 0.0f, 0.0f ), // v1 + make_float3( 0.0f, 0.0f, 16.0f ), // v2 + make_float3( -16.0f, 0.01f, -8.0f ) // anchor + ); + +//------------------------------------------------------------------------------ +// +// GLFW callbacks +// +//------------------------------------------------------------------------------ + +static void mouseButtonCallback( GLFWwindow* window, int button, int action, int mods ) +{ + double xpos, ypos; + glfwGetCursorPos( window, &xpos, &ypos ); + + if( action == GLFW_PRESS ) + { + mouse_button = button; + trackball.startTracking(static_cast( xpos ), static_cast( ypos )); + } + else + { + mouse_button = -1; + } +} + + +static void cursorPosCallback( GLFWwindow* window, double xpos, double ypos ) +{ + whitted::LaunchParams* params = static_cast( glfwGetWindowUserPointer( window ) ); + + if( mouse_button == GLFW_MOUSE_BUTTON_LEFT ) + { + trackball.setViewMode( sutil::Trackball::LookAtFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params->width, params->height ); + camera_changed = true; + } + else if( mouse_button == GLFW_MOUSE_BUTTON_RIGHT ) + { + trackball.setViewMode( sutil::Trackball::EyeFixed ); + trackball.updateTracking( static_cast( xpos ), static_cast( ypos ), params->width, params->height ); + camera_changed = true; + } +} + + +static void windowSizeCallback( GLFWwindow* window, int32_t res_x, int32_t res_y ) +{ + // Keep rendering at the current resolution when the window is minimized. + if( minimized ) + return; + + // Output dimensions must be at least 1 in both x and y. + sutil::ensureMinimumSize( res_x, res_y ); + + whitted::LaunchParams* params = static_cast( glfwGetWindowUserPointer( window ) ); + params->width = res_x; + params->height = res_y; + camera_changed = true; + resize_dirty = true; +} + + +static void windowIconifyCallback( GLFWwindow* window, int32_t iconified ) +{ + minimized = ( iconified > 0 ); +} + + +static void keyCallback( GLFWwindow* window, int32_t key, int32_t /*scancode*/, int32_t action, int32_t /*mods*/ ) +{ + if( action == GLFW_PRESS ) + { + if( key == GLFW_KEY_Q || + key == GLFW_KEY_ESCAPE ) + { + glfwSetWindowShouldClose( window, true ); + } + } + else if( key == GLFW_KEY_G ) + { + // toggle UI draw + } +} + + +static void scrollCallback( GLFWwindow* window, double xscroll, double yscroll ) +{ + if(trackball.wheelEvent((int)yscroll)) + camera_changed = true; +} + + +//------------------------------------------------------------------------------ +// +// Helper functions +// +//------------------------------------------------------------------------------ + +void printUsageAndExit( const char* argv0 ) +{ + std::cerr << "Usage : " << argv0 << " [options]\n"; + std::cerr << "Options: --file | -f File for image output\n"; + std::cerr << " --no-gl-interop Disable GL interop for display\n"; + std::cerr << " --dim=x Set image dimensions; defaults to 768x768\n"; + std::cerr << " --help | -h Print this usage message\n"; + exit( 0 ); +} + +void initLaunchParams( WhittedState& state ) +{ + const size_t accum_buffer_size = state.params.width * state.params.height * sizeof(float4); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &state.params.accum_buffer ), + accum_buffer_size + ) ); + CUDA_CHECK( cudaMemset( reinterpret_cast( state.params.accum_buffer ), 0, accum_buffer_size )); + + state.params.frame_buffer = nullptr; // Will be set when output buffer is mapped + + state.params.subframe_index = 0u; + + // Set ambient light color and point light position + std::vector lights( 2 ); + lights[0].type = Light::Type::AMBIENT; + lights[0].ambient.color = make_float3( 0.4f, 0.4f, 0.4f ); + lights[1].type = Light::Type::POINT; + lights[1].point.color = make_float3( 1.0f, 1.0f, 1.0f ); + lights[1].point.intensity = 1.0f; + lights[1].point.position = make_float3( 60.0f, 40.0f, 0.0f ); + lights[1].point.falloff = Light::Falloff::QUADRATIC; + + state.params.lights.count = static_cast( lights.size() ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.params.lights.data ), lights.size() * sizeof( Light ) ) ); + CUDA_CHECK( cudaMemcpy( reinterpret_cast( state.params.lights.data ), lights.data(), + lights.size() * sizeof( Light ), cudaMemcpyHostToDevice ) ); + state.params.miss_color = { 0.34f, 0.55f, 0.85f }; + + state.params.max_depth = max_trace; + state.params.scene_epsilon = 1.e-4f; + + CUDA_CHECK( cudaStreamCreate( &state.stream ) ); + CUDA_CHECK( cudaMalloc( reinterpret_cast( &state.d_params ), sizeof( whitted::LaunchParams ) ) ); + + state.params.handle = state.gas_handle; +} + +inline OptixAabb sphere_bound( float3 center, float radius ) +{ + float3 m_min = center - radius; + float3 m_max = center + radius; + + return { + m_min.x, m_min.y, m_min.z, + m_max.x, m_max.y, m_max.z + }; +} + + +inline OptixAabb parallelogram_bound( float3 v1, float3 v2, float3 anchor ) +{ + // v1 and v2 are scaled by 1./length^2. Rescale back to normal for the bounds computation. + const float3 tv1 = v1 / dot( v1, v1 ); + const float3 tv2 = v2 / dot( v2, v2 ); + const float3 p00 = anchor; + const float3 p01 = anchor + tv1; + const float3 p10 = anchor + tv2; + const float3 p11 = anchor + tv1 + tv2; + + float3 m_min = fminf( fminf( p00, p01 ), fminf( p10, p11 )); + float3 m_max = fmaxf( fmaxf( p00, p01 ), fmaxf( p10, p11 )); + return { + m_min.x, m_min.y, m_min.z, + m_max.x, m_max.y, m_max.z + }; +} + +static void buildGas( + const WhittedState &state, + const OptixAccelBuildOptions &accel_options, + const OptixBuildInput &build_input, + OptixTraversableHandle &gas_handle, + CUdeviceptr &d_gas_output_buffer + ) +{ + OptixAccelBufferSizes gas_buffer_sizes; + CUdeviceptr d_temp_buffer_gas; + + OPTIX_CHECK( optixAccelComputeMemoryUsage( + state.context, + &accel_options, + &build_input, + 1, + &gas_buffer_sizes)); + + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_temp_buffer_gas ), + gas_buffer_sizes.tempSizeInBytes)); + + // non-compacted output and size of compacted GAS + CUdeviceptr d_buffer_temp_output_gas_and_compacted_size; + size_t compactedSizeOffset = roundUp( gas_buffer_sizes.outputSizeInBytes, 8ull ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_buffer_temp_output_gas_and_compacted_size ), + compactedSizeOffset + 8 + ) ); + + OptixAccelEmitDesc emitProperty = {}; + emitProperty.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; + emitProperty.result = (CUdeviceptr)((char*)d_buffer_temp_output_gas_and_compacted_size + compactedSizeOffset); + + OPTIX_CHECK( optixAccelBuild( + state.context, + 0, + &accel_options, + &build_input, + 1, + d_temp_buffer_gas, + gas_buffer_sizes.tempSizeInBytes, + d_buffer_temp_output_gas_and_compacted_size, + gas_buffer_sizes.outputSizeInBytes, + &gas_handle, + &emitProperty, + 1) ); + + CUDA_CHECK( cudaFree( (void*)d_temp_buffer_gas ) ); + + size_t compacted_gas_size; + CUDA_CHECK( cudaMemcpy( &compacted_gas_size, (void*)emitProperty.result, sizeof(size_t), cudaMemcpyDeviceToHost ) ); + + if( compacted_gas_size < gas_buffer_sizes.outputSizeInBytes ) + { + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_gas_output_buffer ), compacted_gas_size ) ); + + // use handle as input and output + OPTIX_CHECK( optixAccelCompact( state.context, 0, gas_handle, d_gas_output_buffer, compacted_gas_size, &gas_handle ) ); + + CUDA_CHECK( cudaFree( (void*)d_buffer_temp_output_gas_and_compacted_size ) ); + } + else + { + d_gas_output_buffer = d_buffer_temp_output_gas_and_compacted_size; + } +} + +void createGeometry( WhittedState &state ) +{ + // + // Build Custom Primitives + // + + // Load AABB into device memory + OptixAabb aabb[OBJ_COUNT] = { sphere_bound( g_sphere.center, g_sphere.radius ), + sphere_bound( g_sphere_shell.center, g_sphere_shell.radius2 ), + parallelogram_bound( g_floor.v1, g_floor.v2, g_floor.anchor ) }; + CUdeviceptr d_aabb; + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_aabb + ), OBJ_COUNT * sizeof( OptixAabb ) ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_aabb ), + &aabb, + OBJ_COUNT * sizeof( OptixAabb ), + cudaMemcpyHostToDevice + ) ); + + // Setup AABB build input + uint32_t aabb_input_flags[] = { + /* flags for metal sphere */ + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + /* flag for glass sphere */ + OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL, + /* flag for floor */ + OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT, + }; + /* TODO: This API cannot control flags for different ray type */ + + const uint32_t sbt_index[] = { 0, 1, 2 }; + CUdeviceptr d_sbt_index; + + CUDA_CHECK( cudaMalloc( reinterpret_cast( &d_sbt_index ), sizeof(sbt_index) ) ); + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_sbt_index ), + sbt_index, + sizeof( sbt_index ), + cudaMemcpyHostToDevice ) ); + + OptixBuildInput aabb_input = {}; + aabb_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES; + aabb_input.customPrimitiveArray.aabbBuffers = &d_aabb; + aabb_input.customPrimitiveArray.flags = aabb_input_flags; + aabb_input.customPrimitiveArray.numSbtRecords = OBJ_COUNT; + aabb_input.customPrimitiveArray.numPrimitives = OBJ_COUNT; + aabb_input.customPrimitiveArray.sbtIndexOffsetBuffer = d_sbt_index; + aabb_input.customPrimitiveArray.sbtIndexOffsetSizeInBytes = sizeof( uint32_t ); + aabb_input.customPrimitiveArray.primitiveIndexOffset = 0; + + + OptixAccelBuildOptions accel_options = { + OPTIX_BUILD_FLAG_ALLOW_COMPACTION, // buildFlags + OPTIX_BUILD_OPERATION_BUILD // operation + }; + + + buildGas( + state, + accel_options, + aabb_input, + state.gas_handle, + state.d_gas_output_buffer); + + CUDA_CHECK( cudaFree( (void*)d_aabb) ); + CUDA_CHECK( cudaFree( reinterpret_cast(d_sbt_index) ) ); +} + +void createModules( WhittedState &state ) +{ + OptixModuleCompileOptions module_compile_options = {}; +#if !defined( NDEBUG ) + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + { + size_t inputSize = 0; + const char* input = sutil::getInputData( nullptr, nullptr, "geometry.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( + state.context, + &module_compile_options, + &state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &state.geometry_module ) ); + } + + { + size_t inputSize = 0; + const char* input = sutil::getInputData( nullptr, nullptr, "camera.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( + state.context, + &module_compile_options, + &state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &state.camera_module ) ); + } + + { + size_t inputSize = 0; + const char* input = sutil::getInputData( nullptr, nullptr, "shading.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( + state.context, + &module_compile_options, + &state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &state.shading_module ) ); + } + + { + size_t inputSize = 0; + const char* input = sutil::getInputData( nullptr, nullptr, "sphere.cu", inputSize ); + OPTIX_CHECK_LOG( optixModuleCreate( + state.context, + &module_compile_options, + &state.pipeline_compile_options, + input, + inputSize, + LOG, &LOG_SIZE, + &state.sphere_module ) ); + } +} + +static void createCameraProgram( WhittedState &state, std::vector &program_groups ) +{ + OptixProgramGroup cam_prog_group; + OptixProgramGroupOptions cam_prog_group_options = {}; + OptixProgramGroupDesc cam_prog_group_desc = {}; + cam_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + cam_prog_group_desc.raygen.module = state.camera_module; + cam_prog_group_desc.raygen.entryFunctionName = "__raygen__pinhole_camera"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &cam_prog_group_desc, + 1, + &cam_prog_group_options, + LOG, &LOG_SIZE, + &cam_prog_group ) ); + + program_groups.push_back(cam_prog_group); + state.raygen_prog_group = cam_prog_group; +} + +static void createGlassSphereProgram( WhittedState &state, std::vector &program_groups ) +{ + OptixProgramGroup radiance_sphere_prog_group; + OptixProgramGroupOptions radiance_sphere_prog_group_options = {}; + OptixProgramGroupDesc radiance_sphere_prog_group_desc = {}; + radiance_sphere_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + radiance_sphere_prog_group_desc.hitgroup.moduleIS = state.geometry_module; + radiance_sphere_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__sphere_shell"; + radiance_sphere_prog_group_desc.hitgroup.moduleCH = state.shading_module; + radiance_sphere_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__glass_radiance"; + radiance_sphere_prog_group_desc.hitgroup.moduleAH = nullptr; + radiance_sphere_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &radiance_sphere_prog_group_desc, + 1, + &radiance_sphere_prog_group_options, + LOG, &LOG_SIZE, + &radiance_sphere_prog_group ) ); + + program_groups.push_back(radiance_sphere_prog_group); + state.radiance_glass_sphere_prog_group = radiance_sphere_prog_group; + + OptixProgramGroup occlusion_sphere_prog_group; + OptixProgramGroupOptions occlusion_sphere_prog_group_options = {}; + OptixProgramGroupDesc occlusion_sphere_prog_group_desc = {}; + occlusion_sphere_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + occlusion_sphere_prog_group_desc.hitgroup.moduleIS = state.geometry_module; + occlusion_sphere_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__sphere_shell"; + occlusion_sphere_prog_group_desc.hitgroup.moduleCH = nullptr; + occlusion_sphere_prog_group_desc.hitgroup.entryFunctionNameCH = nullptr; + occlusion_sphere_prog_group_desc.hitgroup.moduleAH = state.shading_module; + occlusion_sphere_prog_group_desc.hitgroup.entryFunctionNameAH = "__anyhit__glass_occlusion"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &occlusion_sphere_prog_group_desc, + 1, + &occlusion_sphere_prog_group_options, + LOG, &LOG_SIZE, + &occlusion_sphere_prog_group ) ); + + program_groups.push_back(occlusion_sphere_prog_group); + state.occlusion_glass_sphere_prog_group = occlusion_sphere_prog_group; +} + +static void createMetalSphereProgram( WhittedState &state, std::vector &program_groups ) +{ + OptixProgramGroup radiance_sphere_prog_group; + OptixProgramGroupOptions radiance_sphere_prog_group_options = {}; + OptixProgramGroupDesc radiance_sphere_prog_group_desc = {}; + radiance_sphere_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP, + radiance_sphere_prog_group_desc.hitgroup.moduleIS = state.sphere_module; + radiance_sphere_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__sphere"; + radiance_sphere_prog_group_desc.hitgroup.moduleCH = state.shading_module; + radiance_sphere_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__metal_radiance"; + radiance_sphere_prog_group_desc.hitgroup.moduleAH = nullptr; + radiance_sphere_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &radiance_sphere_prog_group_desc, + 1, + &radiance_sphere_prog_group_options, + LOG, &LOG_SIZE, + &radiance_sphere_prog_group ) ); + + program_groups.push_back(radiance_sphere_prog_group); + state.radiance_metal_sphere_prog_group = radiance_sphere_prog_group; + + OptixProgramGroup occlusion_sphere_prog_group; + OptixProgramGroupOptions occlusion_sphere_prog_group_options = {}; + OptixProgramGroupDesc occlusion_sphere_prog_group_desc = {}; + occlusion_sphere_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP, + occlusion_sphere_prog_group_desc.hitgroup.moduleIS = state.sphere_module; + occlusion_sphere_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__sphere"; + occlusion_sphere_prog_group_desc.hitgroup.moduleCH = state.shading_module; + occlusion_sphere_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__full_occlusion"; + occlusion_sphere_prog_group_desc.hitgroup.moduleAH = nullptr; + occlusion_sphere_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &occlusion_sphere_prog_group_desc, + 1, + &occlusion_sphere_prog_group_options, + LOG, &LOG_SIZE, + &occlusion_sphere_prog_group ) ); + + program_groups.push_back(occlusion_sphere_prog_group); + state.occlusion_metal_sphere_prog_group = occlusion_sphere_prog_group; +} + +static void createFloorProgram( WhittedState &state, std::vector &program_groups ) +{ + OptixProgramGroup radiance_floor_prog_group; + OptixProgramGroupOptions radiance_floor_prog_group_options = {}; + OptixProgramGroupDesc radiance_floor_prog_group_desc = {}; + radiance_floor_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + radiance_floor_prog_group_desc.hitgroup.moduleIS = state.geometry_module; + radiance_floor_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__parallelogram"; + radiance_floor_prog_group_desc.hitgroup.moduleCH = state.shading_module; + radiance_floor_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__checker_radiance"; + radiance_floor_prog_group_desc.hitgroup.moduleAH = nullptr; + radiance_floor_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &radiance_floor_prog_group_desc, + 1, + &radiance_floor_prog_group_options, + LOG, &LOG_SIZE, + &radiance_floor_prog_group ) ); + + program_groups.push_back(radiance_floor_prog_group); + state.radiance_floor_prog_group = radiance_floor_prog_group; + + OptixProgramGroup occlusion_floor_prog_group; + OptixProgramGroupOptions occlusion_floor_prog_group_options = {}; + OptixProgramGroupDesc occlusion_floor_prog_group_desc = {}; + occlusion_floor_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + occlusion_floor_prog_group_desc.hitgroup.moduleIS = state.geometry_module; + occlusion_floor_prog_group_desc.hitgroup.entryFunctionNameIS = "__intersection__parallelogram"; + occlusion_floor_prog_group_desc.hitgroup.moduleCH = state.shading_module; + occlusion_floor_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__full_occlusion"; + occlusion_floor_prog_group_desc.hitgroup.moduleAH = nullptr; + occlusion_floor_prog_group_desc.hitgroup.entryFunctionNameAH = nullptr; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &occlusion_floor_prog_group_desc, + 1, + &occlusion_floor_prog_group_options, + LOG, &LOG_SIZE, + &occlusion_floor_prog_group ) ); + + program_groups.push_back(occlusion_floor_prog_group); + state.occlusion_floor_prog_group = occlusion_floor_prog_group; +} + +static void createMissProgram( WhittedState &state, std::vector &program_groups ) +{ + OptixProgramGroupOptions miss_prog_group_options = {}; + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = state.shading_module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__constant_bg"; + + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &miss_prog_group_desc, + 1, + &miss_prog_group_options, + LOG, &LOG_SIZE, + &state.radiance_miss_prog_group ) ); + + program_groups.push_back(state.radiance_miss_prog_group); + + miss_prog_group_desc.miss = { + nullptr, // module + nullptr // entryFunctionName + }; + OPTIX_CHECK_LOG( optixProgramGroupCreate( + state.context, + &miss_prog_group_desc, + 1, + &miss_prog_group_options, + LOG, &LOG_SIZE, + &state.occlusion_miss_prog_group ) ); + + program_groups.push_back(state.occlusion_miss_prog_group); +} + +void createPipeline( WhittedState &state ) +{ + std::vector program_groups; + + state.pipeline_compile_options = { + false, // usesMotionBlur + OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS, // traversableGraphFlags + 5, /* RadiancePRD uses 5 payloads */ // numPayloadValues + 5, /* Parallelogram intersection uses 5 attrs */ // numAttributeValues + OPTIX_EXCEPTION_FLAG_NONE, // exceptionFlags + "params" // pipelineLaunchParamsVariableName + }; + + // Prepare program groups + createModules( state ); + createCameraProgram( state, program_groups ); + createGlassSphereProgram( state, program_groups ); + createMetalSphereProgram( state, program_groups ); + createFloorProgram( state, program_groups ); + createMissProgram( state, program_groups ); + + // Link program groups to pipeline + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace; + OPTIX_CHECK_LOG( optixPipelineCreate( + state.context, + &state.pipeline_compile_options, + &pipeline_link_options, + program_groups.data(), + static_cast( program_groups.size() ), + LOG, &LOG_SIZE, + &state.pipeline ) ); + + OptixStackSizes stack_sizes = {}; + for( auto& prog_group : program_groups ) + { + OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes, state.pipeline ) ); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes, max_trace, + 0, // maxCCDepth + 0, // maxDCDepth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size ) ); + OPTIX_CHECK( optixPipelineSetStackSize( state.pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + ) ); +} + +void createSBT( WhittedState &state ) +{ + // Raygen program record + { + CUdeviceptr d_raygen_record; + size_t sizeof_raygen_record = sizeof( sutil::EmptyRecord ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_raygen_record ), + sizeof_raygen_record ) ); + + sutil::EmptyRecord rg_sbt; + optixSbtRecordPackHeader( state.raygen_prog_group, &rg_sbt ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_raygen_record ), + &rg_sbt, + sizeof_raygen_record, + cudaMemcpyHostToDevice + ) ); + + state.sbt.raygenRecord = d_raygen_record; + } + + // Miss program record + { + CUdeviceptr d_miss_record; + size_t sizeof_miss_record = sizeof( sutil::EmptyRecord ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_miss_record ), + sizeof_miss_record*whitted::RAY_TYPE_COUNT ) ); + + sutil::EmptyRecord ms_sbt[whitted::RAY_TYPE_COUNT]; + optixSbtRecordPackHeader( state.radiance_miss_prog_group, &ms_sbt[0] ); + optixSbtRecordPackHeader( state.occlusion_miss_prog_group, &ms_sbt[1] ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_miss_record ), + ms_sbt, + sizeof_miss_record*whitted::RAY_TYPE_COUNT, + cudaMemcpyHostToDevice + ) ); + + state.sbt.missRecordBase = d_miss_record; + state.sbt.missRecordCount = whitted::RAY_TYPE_COUNT; + state.sbt.missRecordStrideInBytes = static_cast( sizeof_miss_record ); + } + + // Hitgroup program record + { + const size_t count_records = whitted::RAY_TYPE_COUNT * OBJ_COUNT; + HitGroupRecord hitgroup_records[count_records]; + + // Note: Fill SBT record array the same order like AS is built. + int sbt_idx = 0; + + // Metal Sphere + OPTIX_CHECK( optixSbtRecordPackHeader( + state.radiance_metal_sphere_prog_group, + &hitgroup_records[sbt_idx] ) ); + hitgroup_records[ sbt_idx ].data.geometry_data.setSphere( g_sphere ); + hitgroup_records[ sbt_idx ].data.material_data.metal = { + { 0.2f, 0.5f, 0.5f }, // Ka + { 0.2f, 0.7f, 0.8f }, // Kd + { 0.9f, 0.9f, 0.9f }, // Ks + { 0.5f, 0.5f, 0.5f }, // Kr + 64, // phong_exp + }; + sbt_idx ++; + + OPTIX_CHECK( optixSbtRecordPackHeader( + state.occlusion_metal_sphere_prog_group, + &hitgroup_records[sbt_idx] ) ); + hitgroup_records[ sbt_idx ].data.geometry_data.setSphere( g_sphere ); + sbt_idx ++; + + // Glass Sphere + OPTIX_CHECK( optixSbtRecordPackHeader( + state.radiance_glass_sphere_prog_group, + &hitgroup_records[sbt_idx] ) ); + hitgroup_records[ sbt_idx ].data.geometry_data.setSphereShell( g_sphere_shell ); + hitgroup_records[ sbt_idx ].data.material_data.glass = { + 1e-2f, // importance_cutoff + { 0.034f, 0.055f, 0.085f }, // cutoff_color + 3.0f, // fresnel_exponent + 0.1f, // fresnel_minimum + 1.0f, // fresnel_maximum + 1.4f, // refraction_index + { 1.0f, 1.0f, 1.0f }, // refraction_color + { 1.0f, 1.0f, 1.0f }, // reflection_color + { logf(.83f), logf(.83f), logf(.83f) }, // extinction_constant + { 0.6f, 0.6f, 0.6f }, // shadow_attenuation + 10, // refraction_maxdepth + 5 // reflection_maxdepth + }; + sbt_idx ++; + + OPTIX_CHECK( optixSbtRecordPackHeader( + state.occlusion_glass_sphere_prog_group, + &hitgroup_records[sbt_idx] ) ); + hitgroup_records[ sbt_idx ].data.geometry_data.setSphereShell( g_sphere_shell ); + hitgroup_records[ sbt_idx ].data.material_data.glass.shadow_attenuation = { 0.6f, 0.6f, 0.6f }; + sbt_idx ++; + + // Floor + OPTIX_CHECK( optixSbtRecordPackHeader( + state.radiance_floor_prog_group, + &hitgroup_records[sbt_idx] ) ); + hitgroup_records[ sbt_idx ].data.geometry_data.setParallelogram( g_floor ); + hitgroup_records[ sbt_idx ].data.material_data.checker = { + { 0.8f, 0.3f, 0.15f }, // Kd1 + { 0.9f, 0.85f, 0.05f }, // Kd2 + { 0.8f, 0.3f, 0.15f }, // Ka1 + { 0.9f, 0.85f, 0.05f }, // Ka2 + { 0.0f, 0.0f, 0.0f }, // Ks1 + { 0.0f, 0.0f, 0.0f }, // Ks2 + { 0.0f, 0.0f, 0.0f }, // Kr1 + { 0.0f, 0.0f, 0.0f }, // Kr2 + 0.0f, // phong_exp1 + 0.0f, // phong_exp2 + { 32.0f, 16.0f } // inv_checker_size + }; + sbt_idx++; + + OPTIX_CHECK( optixSbtRecordPackHeader( + state.occlusion_floor_prog_group, + &hitgroup_records[sbt_idx] ) ); + hitgroup_records[ sbt_idx ].data.geometry_data.setParallelogram( g_floor ); + + CUdeviceptr d_hitgroup_records; + size_t sizeof_hitgroup_record = sizeof( HitGroupRecord ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( &d_hitgroup_records ), + sizeof_hitgroup_record*count_records + ) ); + + CUDA_CHECK( cudaMemcpy( + reinterpret_cast( d_hitgroup_records ), + hitgroup_records, + sizeof_hitgroup_record*count_records, + cudaMemcpyHostToDevice + ) ); + + state.sbt.hitgroupRecordBase = d_hitgroup_records; + state.sbt.hitgroupRecordCount = count_records; + state.sbt.hitgroupRecordStrideInBytes = static_cast( sizeof_hitgroup_record ); + } +} + +static void context_log_cb( unsigned int level, const char* tag, const char* message, void* /*cbdata */) +{ + std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " + << message << "\n"; +} + +void createContext( WhittedState& state ) +{ + // Initialize CUDA + CUDA_CHECK( cudaFree( 0 ) ); + + OptixDeviceContext context; + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK( optixInit() ); + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + OPTIX_CHECK( optixDeviceContextCreate( cuCtx, &options, &context ) ); + + state.context = context; +} + +// +// +// + +void initCameraState() +{ + camera.setEye( make_float3( 8.0f, 2.0f, -4.0f ) ); + camera.setLookat( make_float3( 4.0f, 2.3f, -4.0f ) ); + camera.setUp( make_float3( 0.0f, 1.0f, 0.0f ) ); + camera.setFovY( 60.0f ); + camera_changed = true; + + trackball.setCamera( &camera ); + trackball.setMoveSpeed( 10.0f ); + trackball.setReferenceFrame( make_float3( 1.0f, 0.0f, 0.0f ), make_float3( 0.0f, 0.0f, 1.0f ), make_float3( 0.0f, 1.0f, 0.0f ) ); + trackball.setGimbalLock(true); +} + +void handleCameraUpdate( WhittedState &state ) +{ + if( !camera_changed ) + return; + camera_changed = false; + + camera.setAspectRatio( static_cast( state.params.width ) / static_cast( state.params.height ) ); + state.params.eye = camera.eye(); + camera.UVWFrame( state.params.U, state.params.V, state.params.W ); +} + +void handleResize( sutil::CUDAOutputBuffer& output_buffer, whitted::LaunchParams& params ) +{ + if( !resize_dirty ) + return; + resize_dirty = false; + + output_buffer.resize( params.width, params.height ); + + // Realloc accumulation buffer + CUDA_CHECK( cudaFree( reinterpret_cast( params.accum_buffer ) ) ); + CUDA_CHECK( cudaMalloc( + reinterpret_cast( ¶ms.accum_buffer ), + params.width*params.height*sizeof(float4) + ) ); +} + +void updateState( sutil::CUDAOutputBuffer& output_buffer, WhittedState &state ) +{ + // Update params on device + if( camera_changed || resize_dirty ) + state.params.subframe_index = 0; + + handleCameraUpdate( state ); + handleResize( output_buffer, state.params ); +} + +void launchSubframe( sutil::CUDAOutputBuffer& output_buffer, WhittedState& state ) +{ + + // Launch + uchar4* result_buffer_data = output_buffer.map(); + state.params.frame_buffer = result_buffer_data; + CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast( state.d_params ), + &state.params, + sizeof( whitted::LaunchParams ), + cudaMemcpyHostToDevice, + state.stream + ) ); + + OPTIX_CHECK( optixLaunch( + state.pipeline, + state.stream, + reinterpret_cast( state.d_params ), + sizeof( whitted::LaunchParams ), + &state.sbt, + state.params.width, // launch width + state.params.height, // launch height + 1 // launch depth + ) ); + output_buffer.unmap(); + CUDA_SYNC_CHECK(); +} + + +void displaySubframe( + sutil::CUDAOutputBuffer& output_buffer, + sutil::GLDisplay& gl_display, + GLFWwindow* window ) +{ + // Display + int framebuf_res_x = 0; // The display's resolution (could be HDPI res) + int framebuf_res_y = 0; // + glfwGetFramebufferSize( window, &framebuf_res_x, &framebuf_res_y ); + gl_display.display( + output_buffer.width(), + output_buffer.height(), + framebuf_res_x, + framebuf_res_y, + output_buffer.getPBO() + ); +} + + +void cleanupState( WhittedState& state ) +{ + OPTIX_CHECK( optixPipelineDestroy ( state.pipeline ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.raygen_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.radiance_metal_sphere_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.occlusion_metal_sphere_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.radiance_glass_sphere_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.occlusion_glass_sphere_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.radiance_miss_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.radiance_floor_prog_group ) ); + OPTIX_CHECK( optixProgramGroupDestroy ( state.occlusion_floor_prog_group ) ); + OPTIX_CHECK( optixModuleDestroy ( state.shading_module ) ); + OPTIX_CHECK( optixModuleDestroy ( state.geometry_module ) ); + OPTIX_CHECK( optixModuleDestroy ( state.camera_module ) ); + OPTIX_CHECK( optixModuleDestroy ( state.sphere_module ) ); + OPTIX_CHECK( optixDeviceContextDestroy( state.context ) ); + + + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.raygenRecord ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.missRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.sbt.hitgroupRecordBase ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_gas_output_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.accum_buffer ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.params.lights.data ) ) ); + CUDA_CHECK( cudaFree( reinterpret_cast( state.d_params ) ) ); +} + +int main( int argc, char* argv[] ) +{ + WhittedState state; + state.params.width = 768; + state.params.height = 768; + sutil::CUDAOutputBufferType output_buffer_type = sutil::CUDAOutputBufferType::GL_INTEROP; + + // + // Parse command line options + // + std::string outfile; + + for( int i = 1; i < argc; ++i ) + { + const std::string arg = argv[i]; + if( arg == "--help" || arg == "-h" ) + { + printUsageAndExit( argv[0] ); + } + else if( arg == "--no-gl-interop" ) + { + output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE; + } + else if( arg == "--file" || arg == "-f" ) + { + if( i >= argc - 1 ) + printUsageAndExit( argv[0] ); + outfile = argv[++i]; + } + else if( arg.substr( 0, 6 ) == "--dim=" ) + { + const std::string dims_arg = arg.substr( 6 ); + int w, h; + sutil::parseDimensions( dims_arg.c_str(), w, h ); + state.params.width = w; + state.params.height = h; + } + else + { + std::cerr << "Unknown option '" << argv[i] << "'\n"; + printUsageAndExit( argv[0] ); + } + } + + try + { + initCameraState(); + + // + // Set up OptiX state + // + createContext ( state ); + createGeometry ( state ); + createPipeline ( state ); + createSBT ( state ); + + initLaunchParams( state ); + + // + // Render loop + // + if( outfile.empty() ) + { + GLFWwindow* window = sutil::initUI( "optixWhitted", state.params.width, state.params.height ); + glfwSetMouseButtonCallback ( window, mouseButtonCallback ); + glfwSetCursorPosCallback ( window, cursorPosCallback ); + glfwSetWindowSizeCallback ( window, windowSizeCallback ); + glfwSetWindowIconifyCallback( window, windowIconifyCallback ); + glfwSetKeyCallback ( window, keyCallback ); + glfwSetScrollCallback ( window, scrollCallback ); + glfwSetWindowUserPointer ( window, &state.params ); + + { + // output_buffer needs to be destroyed before cleanupUI is called + sutil::CUDAOutputBuffer output_buffer( + output_buffer_type, + state.params.width, + state.params.height + ); + + output_buffer.setStream( state.stream ); + sutil::GLDisplay gl_display; + + std::chrono::duration state_update_time( 0.0 ); + std::chrono::duration render_time( 0.0 ); + std::chrono::duration display_time( 0.0 ); + + do + { + auto t0 = std::chrono::steady_clock::now(); + glfwPollEvents(); + + updateState( output_buffer, state ); + auto t1 = std::chrono::steady_clock::now(); + state_update_time += t1 - t0; + t0 = t1; + + launchSubframe( output_buffer, state ); + t1 = std::chrono::steady_clock::now(); + render_time += t1 - t0; + t0 = t1; + + displaySubframe( output_buffer, gl_display, window ); + t1 = std::chrono::steady_clock::now(); + display_time += t1 - t0; + + sutil::displayStats( state_update_time, render_time, display_time ); + + glfwSwapBuffers( window ); + + ++state.params.subframe_index; + } + while( !glfwWindowShouldClose( window ) ); + + } + sutil::cleanupUI( window ); + } + else + { + if ( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + sutil::initGLFW(); // For GL context + sutil::initGL(); + } + + { + // this scope is for output_buffer, to ensure the destructor is called bfore glfwTerminate() + + sutil::CUDAOutputBuffer output_buffer( + output_buffer_type, + state.params.width, + state.params.height + ); + + handleCameraUpdate( state ); + handleResize( output_buffer, state.params ); + launchSubframe( output_buffer, state ); + + sutil::ImageBuffer buffer; + buffer.data = output_buffer.getHostPointer(); + buffer.width = output_buffer.width(); + buffer.height = output_buffer.height(); + buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4; + sutil::saveImage( outfile.c_str(), buffer, false ); + } + + if( output_buffer_type == sutil::CUDAOutputBufferType::GL_INTEROP ) + { + glfwTerminate(); + } + } + + cleanupState( state ); + } + catch( std::exception& e ) + { + std::cerr << "Caught exception: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/sampleConfig.h.in b/Extern/3rdParty/OptiX/Linux/SDK/sampleConfig.h.in new file mode 100644 index 00000000..24a88c5a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/sampleConfig.h.in @@ -0,0 +1,54 @@ +/* + + * SPDX-FileCopyrightText: Copyright (c) 2009 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#define SAMPLES_DIR "@SAMPLES_DIR@" +#define SAMPLES_PTX_DIR "@SAMPLES_PTX_DIR@" +#define SAMPLES_CUDA_DIR "@SAMPLES_CUDA_DIR@" + +// Include directories +#define SAMPLES_RELATIVE_INCLUDE_DIRS @SAMPLES_RELATIVE_INCLUDE_DIRS@ +#define SAMPLES_ABSOLUTE_INCLUDE_DIRS @SAMPLES_ABSOLUTE_INCLUDE_DIRS@ + +// Signal whether to use NVRTC or not +#cmakedefine01 CUDA_NVRTC_ENABLED + +// NVRTC compiler options +#if defined( NDEBUG ) +#define CUDA_NVRTC_OPTIONS @CUDA_NVRTC_OPTIONS@ +#else +#define CUDA_NVRTC_OPTIONS @CUDA_NVRTC_OPTIONS_DEBUG@ +#endif + +// Indicate what input we are generating +#cmakedefine01 SAMPLES_INPUT_GENERATE_OPTIXIR +#cmakedefine01 SAMPLES_INPUT_GENERATE_PTX diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/support/CMakeLists.txt new file mode 100644 index 00000000..219d2efb --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/CMakeLists.txt @@ -0,0 +1,74 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +find_package( OpenGL REQUIRED ) + +if( UNIX ) + # On Unix-like systems, shared libraries can use the soname system. + set(GLFW_LIB_NAME glfw) +else() + set(GLFW_LIB_NAME glfw3) +endif() + +# Filter out warnings that cause problems with GLFW. +if( WARNINGS_AS_ERRORS AND (USING_GNU_CXX OR USING_CLANG_CXX)) + string( REPLACE "-Wdeclaration-after-statement" "" filtered_c_flags ${CMAKE_C_FLAGS} ) + string( REPLACE "-Wsign-compare" "" filtered_c_flags ${filtered_c_flags} ) + push_variable( CMAKE_C_FLAGS "${filtered_c_flags} -Wno-format-truncation -Wno-deprecated" ) +endif() +add_subdirectory( GLFW ) +set_property( TARGET glfw PROPERTY C_STANDARD 99 ) +if( WARNINGS_AS_ERRORS AND (USING_GNU_CXX OR USING_CLANG_CXX)) + pop_variable( CMAKE_C_FLAGS ) +endif() + +if( WARNINGS_AS_ERRORS AND (USING_GNU_CXX OR USING_CLANG_CXX)) + push_variable( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-class-memaccess" ) +endif() +add_subdirectory( imgui ) +if( WARNINGS_AS_ERRORS AND (USING_GNU_CXX OR USING_CLANG_CXX)) + pop_variable( CMAKE_CXX_FLAGS ) +endif() + +add_library( glad SHARED + KHR/khrplatform.h + glad/glad.c + glad/glad.h +) +target_compile_definitions( glad + PRIVATE GLAD_GLAPI_EXPORT_BUILD + PUBLIC GLAD_GLAPI_EXPORT ) +target_include_directories( glad PUBLIC . ) +target_link_libraries( glad PUBLIC ${OPENGL_LIBRARIES} ) + + +# Set IDE folders for targets +set_property( TARGET glad PROPERTY FOLDER ${OPTIX_IDE_FOLDER} ) +set_property( TARGET glfw PROPERTY FOLDER ${OPTIX_IDE_FOLDER} ) +set_property( TARGET imgui PROPERTY FOLDER ${OPTIX_IDE_FOLDER} ) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/.appveyor.yml b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/.appveyor.yml new file mode 100644 index 00000000..ae658cc3 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/.appveyor.yml @@ -0,0 +1,22 @@ +branches: + only: + - ci + - master +skip_tags: true +environment: + matrix: + - BUILD_SHARED_LIBS: ON + - BUILD_SHARED_LIBS: OFF +matrix: + fast_finish: true +build_script: + - mkdir build + - cd build + - cmake -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% .. + - cmake --build . +notifications: + - provider: Email + to: + - ci@glfw.org + - on_build_failure: true + - on_build_success: false diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/.travis.yml b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/.travis.yml new file mode 100644 index 00000000..ff1c6c35 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/.travis.yml @@ -0,0 +1,30 @@ +language: c +compiler: clang +branches: + only: + - ci + - master +os: + - linux + - osx +sudo: false +addons: + apt: + sources: + - kubuntu-backports + packages: + - cmake +env: + - BUILD_SHARED_LIBS=ON + - BUILD_SHARED_LIBS=OFF +script: + - mkdir build + - cd build + - cmake -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} .. + - cmake --build . +notifications: + email: + recipients: + - ci@glfw.org + on_success: never + on_failure: always diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/MacOSXBundleInfo.plist.in b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/MacOSXBundleInfo.plist.in new file mode 100644 index 00000000..684ad790 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/MacOSXBundleInfo.plist.in @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CSResourcesFileMapped + + LSRequiresCarbon + + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + NSHighResolutionCapable + + + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/amd64-mingw32msvc.cmake b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/amd64-mingw32msvc.cmake new file mode 100644 index 00000000..705e251d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/amd64-mingw32msvc.cmake @@ -0,0 +1,13 @@ +# Define the environment for cross compiling from Linux to Win64 +SET(CMAKE_SYSTEM_NAME Windows) +SET(CMAKE_SYSTEM_VERSION 1) +SET(CMAKE_C_COMPILER "amd64-mingw32msvc-gcc") +SET(CMAKE_CXX_COMPILER "amd64-mingw32msvc-g++") +SET(CMAKE_RC_COMPILER "amd64-mingw32msvc-windres") +SET(CMAKE_RANLIB "amd64-mingw32msvc-ranlib") + +# Configure the behaviour of the find commands +SET(CMAKE_FIND_ROOT_PATH "/usr/amd64-mingw32msvc") +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/i586-mingw32msvc.cmake b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/i586-mingw32msvc.cmake new file mode 100644 index 00000000..393ddbda --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/i586-mingw32msvc.cmake @@ -0,0 +1,13 @@ +# Define the environment for cross compiling from Linux to Win32 +SET(CMAKE_SYSTEM_NAME Windows) +SET(CMAKE_SYSTEM_VERSION 1) +SET(CMAKE_C_COMPILER "i586-mingw32msvc-gcc") +SET(CMAKE_CXX_COMPILER "i586-mingw32msvc-g++") +SET(CMAKE_RC_COMPILER "i586-mingw32msvc-windres") +SET(CMAKE_RANLIB "i586-mingw32msvc-ranlib") + +# Configure the behaviour of the find commands +SET(CMAKE_FIND_ROOT_PATH "/usr/i586-mingw32msvc") +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/i686-pc-mingw32.cmake b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/i686-pc-mingw32.cmake new file mode 100644 index 00000000..9a46aef7 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/i686-pc-mingw32.cmake @@ -0,0 +1,13 @@ +# Define the environment for cross compiling from Linux to Win32 +SET(CMAKE_SYSTEM_NAME Windows) # Target system name +SET(CMAKE_SYSTEM_VERSION 1) +SET(CMAKE_C_COMPILER "i686-pc-mingw32-gcc") +SET(CMAKE_CXX_COMPILER "i686-pc-mingw32-g++") +SET(CMAKE_RC_COMPILER "i686-pc-mingw32-windres") +SET(CMAKE_RANLIB "i686-pc-mingw32-ranlib") + +#Configure the behaviour of the find commands +SET(CMAKE_FIND_ROOT_PATH "/opt/mingw/usr/i686-pc-mingw32") +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/i686-w64-mingw32.cmake b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/i686-w64-mingw32.cmake new file mode 100644 index 00000000..9bd60936 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/i686-w64-mingw32.cmake @@ -0,0 +1,13 @@ +# Define the environment for cross compiling from Linux to Win32 +SET(CMAKE_SYSTEM_NAME Windows) # Target system name +SET(CMAKE_SYSTEM_VERSION 1) +SET(CMAKE_C_COMPILER "i686-w64-mingw32-gcc") +SET(CMAKE_CXX_COMPILER "i686-w64-mingw32-g++") +SET(CMAKE_RC_COMPILER "i686-w64-mingw32-windres") +SET(CMAKE_RANLIB "i686-w64-mingw32-ranlib") + +# Configure the behaviour of the find commands +SET(CMAKE_FIND_ROOT_PATH "/usr/i686-w64-mingw32") +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/modules/FindMir.cmake b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/modules/FindMir.cmake new file mode 100644 index 00000000..b1a495ba --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/modules/FindMir.cmake @@ -0,0 +1,18 @@ +# Try to find Mir on a Unix system +# +# This will define: +# +# MIR_LIBRARIES - Link these to use Wayland +# MIR_INCLUDE_DIR - Include directory for Wayland +# +# Copyright (c) 2014 Brandon Schaefer + +if (NOT WIN32) + + find_package (PkgConfig) + pkg_check_modules (PKG_MIR QUIET mirclient) + + set (MIR_INCLUDE_DIR ${PKG_MIR_INCLUDE_DIRS}) + set (MIR_LIBRARIES ${PKG_MIR_LIBRARIES}) + +endif () diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/modules/FindVulkan.cmake b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/modules/FindVulkan.cmake new file mode 100644 index 00000000..d3a664a8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/modules/FindVulkan.cmake @@ -0,0 +1,34 @@ +# Find Vulkan +# +# VULKAN_INCLUDE_DIR +# VULKAN_LIBRARY +# VULKAN_FOUND + +if (WIN32) + find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS + "$ENV{VULKAN_SDK}/Include" + "$ENV{VK_SDK_PATH}/Include") + if (CMAKE_CL_64) + find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS + "$ENV{VULKAN_SDK}/Bin" + "$ENV{VK_SDK_PATH}/Bin") + find_library(VULKAN_STATIC_LIBRARY NAMES vkstatic.1 HINTS + "$ENV{VULKAN_SDK}/Bin" + "$ENV{VK_SDK_PATH}/Bin") + else() + find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS + "$ENV{VULKAN_SDK}/Bin32" + "$ENV{VK_SDK_PATH}/Bin32") + endif() +else() + find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS + "$ENV{VULKAN_SDK}/include") + find_library(VULKAN_LIBRARY NAMES vulkan HINTS + "$ENV{VULKAN_SDK}/lib") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Vulkan DEFAULT_MSG VULKAN_LIBRARY VULKAN_INCLUDE_DIR) + +mark_as_advanced(VULKAN_INCLUDE_DIR VULKAN_LIBRARY VULKAN_STATIC_LIBRARY) + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/modules/FindWaylandProtocols.cmake b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/modules/FindWaylandProtocols.cmake new file mode 100644 index 00000000..8eb83f27 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/modules/FindWaylandProtocols.cmake @@ -0,0 +1,26 @@ +find_package(PkgConfig) + +pkg_check_modules(WaylandProtocols QUIET wayland-protocols>=${WaylandProtocols_FIND_VERSION}) + +execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=pkgdatadir wayland-protocols + OUTPUT_VARIABLE WaylandProtocols_PKGDATADIR + RESULT_VARIABLE _pkgconfig_failed) +if (_pkgconfig_failed) + message(FATAL_ERROR "Missing wayland-protocols pkgdatadir") +endif() + +string(REGEX REPLACE "[\r\n]" "" WaylandProtocols_PKGDATADIR "${WaylandProtocols_PKGDATADIR}") + +find_package_handle_standard_args(WaylandProtocols + FOUND_VAR + WaylandProtocols_FOUND + REQUIRED_VARS + WaylandProtocols_PKGDATADIR + VERSION_VAR + WaylandProtocols_VERSION + HANDLE_COMPONENTS +) + +set(WAYLAND_PROTOCOLS_FOUND ${WaylandProtocols_FOUND}) +set(WAYLAND_PROTOCOLS_PKGDATADIR ${WaylandProtocols_PKGDATADIR}) +set(WAYLAND_PROTOCOLS_VERSION ${WaylandProtocols_VERSION}) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/modules/FindXKBCommon.cmake b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/modules/FindXKBCommon.cmake new file mode 100644 index 00000000..0f571eea --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/modules/FindXKBCommon.cmake @@ -0,0 +1,34 @@ +# - Try to find XKBCommon +# Once done, this will define +# +# XKBCOMMON_FOUND - System has XKBCommon +# XKBCOMMON_INCLUDE_DIRS - The XKBCommon include directories +# XKBCOMMON_LIBRARIES - The libraries needed to use XKBCommon +# XKBCOMMON_DEFINITIONS - Compiler switches required for using XKBCommon + +find_package(PkgConfig) +pkg_check_modules(PC_XKBCOMMON QUIET xkbcommon) +set(XKBCOMMON_DEFINITIONS ${PC_XKBCOMMON_CFLAGS_OTHER}) + +find_path(XKBCOMMON_INCLUDE_DIR + NAMES xkbcommon/xkbcommon.h + HINTS ${PC_XKBCOMMON_INCLUDE_DIR} ${PC_XKBCOMMON_INCLUDE_DIRS} +) + +find_library(XKBCOMMON_LIBRARY + NAMES xkbcommon + HINTS ${PC_XKBCOMMON_LIBRARY} ${PC_XKBCOMMON_LIBRARY_DIRS} +) + +set(XKBCOMMON_LIBRARIES ${XKBCOMMON_LIBRARY}) +set(XKBCOMMON_LIBRARY_DIRS ${XKBCOMMON_LIBRARY_DIRS}) +set(XKBCOMMON_INCLUDE_DIRS ${XKBCOMMON_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(XKBCommon DEFAULT_MSG + XKBCOMMON_LIBRARY + XKBCOMMON_INCLUDE_DIR +) + +mark_as_advanced(XKBCOMMON_LIBRARY XKBCOMMON_INCLUDE_DIR) + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/x86_64-w64-mingw32.cmake b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/x86_64-w64-mingw32.cmake new file mode 100644 index 00000000..84b2c701 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMake/x86_64-w64-mingw32.cmake @@ -0,0 +1,13 @@ +# Define the environment for cross compiling from Linux to Win32 +SET(CMAKE_SYSTEM_NAME Windows) # Target system name +SET(CMAKE_SYSTEM_VERSION 1) +SET(CMAKE_C_COMPILER "x86_64-w64-mingw32-gcc") +SET(CMAKE_CXX_COMPILER "x86_64-w64-mingw32-g++") +SET(CMAKE_RC_COMPILER "x86_64-w64-mingw32-windres") +SET(CMAKE_RANLIB "x86_64-w64-mingw32-ranlib") + +# Configure the behaviour of the find commands +SET(CMAKE_FIND_ROOT_PATH "/usr/x86_64-w64-mingw32") +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMakeLists.txt new file mode 100644 index 00000000..fbd36eee --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/CMakeLists.txt @@ -0,0 +1,420 @@ +set(CMAKE_LEGACY_CYGWIN_WIN32 OFF) + +project(GLFW C) + +cmake_minimum_required(VERSION 2.8.12) + +if (NOT CMAKE_VERSION VERSION_LESS "3.0") + # Until all major package systems have moved to CMake 3, + # we stick with the older INSTALL_NAME_DIR mechanism + # NV: Disabled to silence deprecation warning + # cmake_policy(SET CMP0042 OLD) +endif() + +set(GLFW_VERSION_MAJOR "3") +set(GLFW_VERSION_MINOR "2") +set(GLFW_VERSION_PATCH "1") +set(GLFW_VERSION_EXTRA "") +set(GLFW_VERSION "${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR}") +set(GLFW_VERSION_FULL "${GLFW_VERSION}.${GLFW_VERSION_PATCH}${GLFW_VERSION_EXTRA}") +set(LIB_SUFFIX "" CACHE STRING "Takes an empty string or 64. Directory where lib will be installed: lib or lib64") + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +option(BUILD_SHARED_LIBS "Build shared libraries" OFF) +option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" OFF ) +option(GLFW_BUILD_TESTS "Build the GLFW test programs" OFF) +option(GLFW_BUILD_DOCS "Build the GLFW documentation" OFF) +option(GLFW_INSTALL "Generate installation target" OFF) +option(GLFW_VULKAN_STATIC "Use the Vulkan loader statically linked into application" OFF) +option(GLFW_DOCUMENT_INTERNALS "Include internals in documentation" OFF) + +if (WIN32) + option(GLFW_USE_HYBRID_HPG "Force use of high-performance GPU on hybrid systems" OFF) +endif() + +if (APPLE) + option(GLFW_USE_CHDIR "Make glfwInit chdir to Contents/Resources" ON) + option(GLFW_USE_MENUBAR "Populate the menu bar on first window creation" ON) + option(GLFW_USE_RETINA "Use the full resolution of Retina displays" ON) +endif() + +if (UNIX AND NOT APPLE) + option(GLFW_USE_WAYLAND "Use Wayland for window creation" OFF) + option(GLFW_USE_MIR "Use Mir for window creation" OFF) +endif() + +if (MSVC) + option(USE_MSVC_RUNTIME_LIBRARY_DLL "Use MSVC runtime library DLL" ON) +endif() + +if (BUILD_SHARED_LIBS) + set(_GLFW_BUILD_DLL 1) +endif() + +if (BUILD_SHARED_LIBS AND UNIX) + # On Unix-like systems, shared libraries can use the soname system. + set(GLFW_LIB_NAME glfw) +else() + set(GLFW_LIB_NAME glfw3) +endif() + +if (GLFW_VULKAN_STATIC) + set(_GLFW_VULKAN_STATIC 1) +endif() + +list(APPEND CMAKE_MODULE_PATH "${GLFW_SOURCE_DIR}/CMake/modules") + +find_package(Threads REQUIRED) +find_package(Vulkan) + +if (GLFW_BUILD_DOCS) + set(DOXYGEN_SKIP_DOT TRUE) + find_package(Doxygen) +endif() + +#-------------------------------------------------------------------- +# Set compiler specific flags +#-------------------------------------------------------------------- +if (MSVC) + if (NOT USE_MSVC_RUNTIME_LIBRARY_DLL) + foreach (flag CMAKE_C_FLAGS + CMAKE_C_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL + CMAKE_C_FLAGS_RELWITHDEBINFO) + + if (${flag} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}") + endif() + if (${flag} MATCHES "/MDd") + string(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}") + endif() + + endforeach() + endif() +endif() + +if (MINGW) + # Workaround for legacy MinGW not providing XInput and DirectInput + include(CheckIncludeFile) + + check_include_file(dinput.h DINPUT_H_FOUND) + check_include_file(xinput.h XINPUT_H_FOUND) + if (NOT DINPUT_H_FOUND OR NOT XINPUT_H_FOUND) + list(APPEND glfw_INCLUDE_DIRS "${GLFW_SOURCE_DIR}/deps/mingw") + endif() + + # Enable link-time exploit mitigation features enabled by default on MSVC + include(CheckCCompilerFlag) + + # Compatibility with data execution prevention (DEP) + set(CMAKE_REQUIRED_FLAGS "-Wl,--nxcompat") + check_c_compiler_flag("" _GLFW_HAS_DEP) + if (_GLFW_HAS_DEP) + set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--nxcompat ${CMAKE_SHARED_LINKER_FLAGS}") + endif() + + # Compatibility with address space layout randomization (ASLR) + set(CMAKE_REQUIRED_FLAGS "-Wl,--dynamicbase") + check_c_compiler_flag("" _GLFW_HAS_ASLR) + if (_GLFW_HAS_ASLR) + set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--dynamicbase ${CMAKE_SHARED_LINKER_FLAGS}") + endif() + + # Compatibility with 64-bit address space layout randomization (ASLR) + set(CMAKE_REQUIRED_FLAGS "-Wl,--high-entropy-va") + check_c_compiler_flag("" _GLFW_HAS_64ASLR) + if (_GLFW_HAS_64ASLR) + set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--high-entropy-va ${CMAKE_SHARED_LINKER_FLAGS}") + endif() +endif() + +#-------------------------------------------------------------------- +# Detect and select backend APIs +#-------------------------------------------------------------------- +if (WIN32) + set(_GLFW_WIN32 1) + message(STATUS "Using Win32 for window creation") +elseif (APPLE) + set(_GLFW_COCOA 1) + message(STATUS "Using Cocoa for window creation") +elseif (UNIX) + if (GLFW_USE_WAYLAND) + set(_GLFW_WAYLAND 1) + message(STATUS "Using Wayland for window creation") + elseif (GLFW_USE_MIR) + set(_GLFW_MIR 1) + message(STATUS "Using Mir for window creation") + else() + set(_GLFW_X11 1) + message(STATUS "Using X11 for window creation") + endif() +else() + message(FATAL_ERROR "No supported platform was detected") +endif() + +#-------------------------------------------------------------------- +# Add Vulkan static library if requested +#-------------------------------------------------------------------- +if (GLFW_VULKAN_STATIC) + if (VULKAN_FOUND AND VULKAN_STATIC_LIBRARY) + list(APPEND glfw_LIBRARIES ${VULKAN_STATIC_LIBRARY}) + else() + if (BUILD_SHARED_LIBS OR GLFW_BUILD_EXAMPLES OR GLFW_BUILD_TESTS) + message(FATAL_ERROR "Vulkan loader static library not found") + else() + message(WARNING "Vulkan loader static library not found") + endif() + endif() +endif() + +#-------------------------------------------------------------------- +# Find and add Unix math and time libraries +#-------------------------------------------------------------------- +if (UNIX AND NOT APPLE) + find_library(RT_LIBRARY rt) + mark_as_advanced(RT_LIBRARY) + if (RT_LIBRARY) + list(APPEND glfw_LIBRARIES "${RT_LIBRARY}") + list(APPEND glfw_PKG_LIBS "-lrt") + endif() + + find_library(MATH_LIBRARY m) + mark_as_advanced(MATH_LIBRARY) + if (MATH_LIBRARY) + list(APPEND glfw_LIBRARIES "${MATH_LIBRARY}") + list(APPEND glfw_PKG_LIBS "-lm") + endif() + + if (CMAKE_DL_LIBS) + list(APPEND glfw_LIBRARIES "${CMAKE_DL_LIBS}") + list(APPEND glfw_PKG_LIBS "-l${CMAKE_DL_LIBS}") + endif() +endif() + +#-------------------------------------------------------------------- +# Use Win32 for window creation +#-------------------------------------------------------------------- +if (_GLFW_WIN32) + + list(APPEND glfw_PKG_LIBS "-lgdi32") + + if (GLFW_USE_HYBRID_HPG) + set(_GLFW_USE_HYBRID_HPG 1) + endif() +endif() + +#-------------------------------------------------------------------- +# Use X11 for window creation +#-------------------------------------------------------------------- +if (_GLFW_X11) + + find_package(X11 REQUIRED) + + list(APPEND glfw_PKG_DEPS "x11") + + # Set up library and include paths + list(APPEND glfw_INCLUDE_DIRS "${X11_X11_INCLUDE_PATH}") + list(APPEND glfw_LIBRARIES "${X11_X11_LIB}" "${CMAKE_THREAD_LIBS_INIT}") + + # Check for XRandR (modern resolution switching and gamma control) + if (NOT X11_Xrandr_FOUND) + message(FATAL_ERROR "The RandR library and headers were not found") + endif() + + list(APPEND glfw_INCLUDE_DIRS "${X11_Xrandr_INCLUDE_PATH}") + list(APPEND glfw_LIBRARIES "${X11_Xrandr_LIB}") + list(APPEND glfw_PKG_DEPS "xrandr") + + # Check for Xinerama (legacy multi-monitor support) + if (NOT X11_Xinerama_FOUND) + message(FATAL_ERROR "The Xinerama library and headers were not found") + endif() + + list(APPEND glfw_INCLUDE_DIRS "${X11_Xinerama_INCLUDE_PATH}") + list(APPEND glfw_LIBRARIES "${X11_Xinerama_LIB}") + list(APPEND glfw_PKG_DEPS "xinerama") + + # Check for Xf86VidMode (fallback gamma control) + if (X11_xf86vmode_FOUND) + list(APPEND glfw_INCLUDE_DIRS "${X11_xf86vmode_INCLUDE_PATH}") + list(APPEND glfw_PKG_DEPS "xxf86vm") + + if (X11_Xxf86vm_LIB) + list(APPEND glfw_LIBRARIES "${X11_Xxf86vm_LIB}") + else() + # Backwards compatibility (see CMake bug 0006976) + list(APPEND glfw_LIBRARIES Xxf86vm) + endif() + + set(_GLFW_HAS_XF86VM TRUE) + endif() + + # Check for Xkb (X keyboard extension) + if (NOT X11_Xkb_FOUND) + message(FATAL_ERROR "The X keyboard extension headers were not found") + endif() + + list(APPEND glfw_INCLUDE_DIR "${X11_Xkb_INCLUDE_PATH}") + + # Check for Xcursor + if (NOT X11_Xcursor_FOUND) + message(FATAL_ERROR "The Xcursor libraries and headers were not found") + endif() + + list(APPEND glfw_INCLUDE_DIR "${X11_Xcursor_INCLUDE_PATH}") + list(APPEND glfw_LIBRARIES "${X11_Xcursor_LIB}") + list(APPEND glfw_PKG_DEPS "xcursor") + +endif() + +#-------------------------------------------------------------------- +# Use Wayland for window creation +#-------------------------------------------------------------------- +if (_GLFW_WAYLAND) + find_package(ECM REQUIRED NO_MODULE) + list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) + + find_package(Wayland REQUIRED) + find_package(WaylandScanner REQUIRED) + find_package(WaylandProtocols 1.1 REQUIRED) + + list(APPEND glfw_PKG_DEPS "wayland-egl") + + list(APPEND glfw_INCLUDE_DIRS "${Wayland_INCLUDE_DIR}") + list(APPEND glfw_LIBRARIES "${Wayland_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") + + find_package(XKBCommon REQUIRED) + list(APPEND glfw_PKG_DEPS "xkbcommon") + list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}") + list(APPEND glfw_LIBRARIES "${XKBCOMMON_LIBRARY}") +endif() + +#-------------------------------------------------------------------- +# Use Mir for window creation +#-------------------------------------------------------------------- +if (_GLFW_MIR) + find_package(Mir REQUIRED) + list(APPEND glfw_PKG_DEPS "mirclient") + + list(APPEND glfw_INCLUDE_DIRS "${MIR_INCLUDE_DIR}") + list(APPEND glfw_LIBRARIES "${MIR_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") + + find_package(XKBCommon REQUIRED) + list(APPEND glfw_PKG_DEPS "xkbcommon") + list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}") + list(APPEND glfw_LIBRARIES "${XKBCOMMON_LIBRARY}") +endif() + +#-------------------------------------------------------------------- +# Use Cocoa for window creation and NSOpenGL for context creation +#-------------------------------------------------------------------- +if (_GLFW_COCOA) + + if (GLFW_USE_MENUBAR) + set(_GLFW_USE_MENUBAR 1) + endif() + + if (GLFW_USE_CHDIR) + set(_GLFW_USE_CHDIR 1) + endif() + + if (GLFW_USE_RETINA) + set(_GLFW_USE_RETINA 1) + endif() + + # Set up library and include paths + find_library(COCOA_FRAMEWORK Cocoa) + find_library(IOKIT_FRAMEWORK IOKit) + find_library(CORE_FOUNDATION_FRAMEWORK CoreFoundation) + find_library(CORE_VIDEO_FRAMEWORK CoreVideo) + mark_as_advanced(COCOA_FRAMEWORK + IOKIT_FRAMEWORK + CORE_FOUNDATION_FRAMEWORK + CORE_VIDEO_FRAMEWORK) + list(APPEND glfw_LIBRARIES "${COCOA_FRAMEWORK}" + "${IOKIT_FRAMEWORK}" + "${CORE_FOUNDATION_FRAMEWORK}" + "${CORE_VIDEO_FRAMEWORK}") + + set(glfw_PKG_DEPS "") + set(glfw_PKG_LIBS "-framework Cocoa -framework IOKit -framework CoreFoundation -framework CoreVideo") +endif() + +#-------------------------------------------------------------------- +# Export GLFW library dependencies +#-------------------------------------------------------------------- +foreach(arg ${glfw_PKG_DEPS}) + set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} ${arg}") +endforeach() +foreach(arg ${glfw_PKG_LIBS}) + set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} ${arg}") +endforeach() + +#-------------------------------------------------------------------- +# Create generated files +#-------------------------------------------------------------------- +include(CMakePackageConfigHelpers) + +set(GLFW_CONFIG_PATH "lib${LIB_SUFFIX}/cmake/glfw3") + +configure_package_config_file(src/glfw3Config.cmake.in + src/glfw3Config.cmake + INSTALL_DESTINATION "${GLFW_CONFIG_PATH}" + NO_CHECK_REQUIRED_COMPONENTS_MACRO) + +write_basic_package_version_file(src/glfw3ConfigVersion.cmake + VERSION ${GLFW_VERSION_FULL} + COMPATIBILITY SameMajorVersion) + +configure_file(src/glfw_config.h.in src/glfw_config.h @ONLY) + +configure_file(src/glfw3.pc.in src/glfw3.pc @ONLY) + +#-------------------------------------------------------------------- +# Add subdirectories +#-------------------------------------------------------------------- +add_subdirectory(src) + +if (GLFW_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() + +if (GLFW_BUILD_TESTS) + add_subdirectory(tests) +endif() + +if (DOXYGEN_FOUND AND GLFW_BUILD_DOCS) + add_subdirectory(docs) +endif() + +#-------------------------------------------------------------------- +# Install files other than the library +# The library is installed by src/CMakeLists.txt +#-------------------------------------------------------------------- +if (GLFW_INSTALL) + install(DIRECTORY include/GLFW DESTINATION include + FILES_MATCHING PATTERN glfw3.h PATTERN glfw3native.h) + + install(FILES "${GLFW_BINARY_DIR}/src/glfw3Config.cmake" + "${GLFW_BINARY_DIR}/src/glfw3ConfigVersion.cmake" + DESTINATION "${GLFW_CONFIG_PATH}") + + install(EXPORT glfwTargets FILE glfw3Targets.cmake + EXPORT_LINK_INTERFACE_LIBRARIES + DESTINATION "${GLFW_CONFIG_PATH}") + install(FILES "${GLFW_BINARY_DIR}/src/glfw3.pc" + DESTINATION "lib${LIB_SUFFIX}/pkgconfig") + + # Only generate this target if no higher-level project already has + if (NOT TARGET uninstall) + configure_file(cmake_uninstall.cmake.in + cmake_uninstall.cmake IMMEDIATE @ONLY) + + add_custom_target(uninstall + "${CMAKE_COMMAND}" -P + "${GLFW_BINARY_DIR}/cmake_uninstall.cmake") + endif() +endif() + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/COPYING.txt b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/COPYING.txt new file mode 100644 index 00000000..ad16462a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/COPYING.txt @@ -0,0 +1,22 @@ +Copyright (c) 2002-2006 Marcus Geelnard +Copyright (c) 2006-2016 Camilla Berglund + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would + be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source + distribution. + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/README.md b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/README.md new file mode 100644 index 00000000..44e85fe4 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/README.md @@ -0,0 +1,274 @@ +# GLFW + +[![Build status](https://travis-ci.org/glfw/glfw.svg?branch=master)](https://travis-ci.org/glfw/glfw) +[![Build status](https://ci.appveyor.com/api/projects/status/0kf0ct9831i5l6sp/branch/master?svg=true)](https://ci.appveyor.com/project/elmindreda/glfw) +[![Coverity Scan](https://scan.coverity.com/projects/4884/badge.svg)](https://scan.coverity.com/projects/glfw-glfw) + +## Introduction + +GLFW is an Open Source, multi-platform library for OpenGL, OpenGL ES and Vulkan +application development. It provides a simple, platform-independent API for +creating windows, contexts and surfaces, reading input, handling events, etc. + +GLFW is licensed under the [zlib/libpng +license](https://opensource.org/licenses/Zlib). + +This is version 3.2.1, which adds support for statically linking the Vulkan +loader and fixes for a number of bugs that together affect all supported +platforms. + +See the [downloads](http://www.glfw.org/download.html) page for details and +files, or fetch the `latest` branch, which always points to the latest stable +release. Each release starting with 3.0 also has a corresponding [annotated +tag](/~https://github.com/glfw/glfw/releases) with source and binary archives. + +If you are new to GLFW, you may find the +[tutorial](http://www.glfw.org/docs/latest/quick.html) for GLFW +3 useful. If you have used GLFW 2 in the past, there is a +[transition guide](http://www.glfw.org/docs/latest/moving.html) for moving to +the GLFW 3 API. + + +## Compiling GLFW + +GLFW itself requires only the headers and libraries for your window system. It +does not need the headers for any context creation API (WGL, GLX, EGL, NSGL) or +rendering API (OpenGL, OpenGL ES, Vulkan) to enable support for them. + +GLFW supports compilation on Windows with Visual C++ 2010 and later, MinGW and +MinGW-w64, on OS X with Clang and on Linux and other Unix-like systems with GCC +and Clang. It will likely compile in other environments as well, but this is +not regularly tested. + +There are also [pre-compiled Windows +binaries](http://www.glfw.org/download.html) available for all compilers +supported on that platform. + +See the [compilation guide](http://www.glfw.org/docs/latest/compile.html) in the +documentation for more information. + + +## Using GLFW + +See the [building application guide](http://www.glfw.org/docs/latest/build.html) +guide in the documentation for more information. + + +## System requirements + +GLFW supports Windows XP and later, OS X 10.7 Lion and later, and Linux and +other Unix-like systems with the X Window System. Experimental implementations +for the Wayland protocol and the Mir display server are available but not yet +officially supported. + +See the [compatibility guide](http://www.glfw.org/docs/latest/compat.html) +in the documentation for more information. + + +## Dependencies + +GLFW itself depends only on the headers and libraries for your window system. + +The examples and test programs depend on a number of tiny libraries. These are +located in the `deps/` directory. + + - [getopt\_port](/~https://github.com/kimgr/getopt_port/) for examples + with command-line options + - [TinyCThread](/~https://github.com/tinycthread/tinycthread) for threaded + examples + - An OpenGL 3.2 core loader generated by + [glad](/~https://github.com/Dav1dde/glad) for examples using modern OpenGL + - [linmath.h](/~https://github.com/datenwolf/linmath.h) for linear algebra in + examples + - [Vulkan headers](https://www.khronos.org/registry/vulkan/) for Vulkan tests + +The Vulkan example additionally requires the Vulkan SDK to be installed, or it +will not be included in the build. + +The documentation is generated with [Doxygen](http://doxygen.org/). If CMake +does not find Doxygen, the documentation will not be generated when you build. + + +## Reporting bugs + +Bugs are reported to our [issue tracker](/~https://github.com/glfw/glfw/issues). +Please check the [contribution +guide](/~https://github.com/glfw/glfw/blob/master/.github/CONTRIBUTING.md) for +information on what to include when reporting a bug. + + +## Changelog + + - Added on-demand loading of Vulkan and context creation API libraries + - Added `_GLFW_VULKAN_STATIC` build macro to make the library use the Vulkan + loader linked statically into the application (#820) + - Bugfix: Single compilation unit builds failed due to naming conflicts (#783) + - Bugfix: The range checks for `glfwSetCursorPos` used the wrong minimum (#773) + - Bugfix: Defining `GLFW_INCLUDE_VULKAN` when compiling the library did not + fail with the expected error message (#823) + - Bugfix: Inherited value of `CMAKE_MODULE_PATH` was clobbered (#822) + - [Win32] Bugfix: `glfwSetClipboardString` created an unnecessary intermediate + copy of the string + - [Win32] Bugfix: Examples failed to build on Visual C++ 2010 due to C99 in + `linmath.h` (#785) + - [Win32] Bugfix: The first shown window ignored the `GLFW_MAXIMIZED` hint + when the process was provided a `STARTUPINFO` (#780) + - [Cocoa] Bugfix: Event processing would segfault on some machines due to + a previous distributed notification listener not being fully + removed (#817,#826) + - [Cocoa] Bugfix: Some include statements were duplicated (#838) + - [X11] Bugfix: Window size limits were ignored if the minimum or maximum size + was set to `GLFW_DONT_CARE` (#805) + - [X11] Bugfix: Input focus was set before window was visible, causing + `BadMatch` on some non-reparenting WMs (#789,#798) + - [X11] Bugfix: `glfwGetWindowPos` and `glfwSetWindowPos` operated on the + window frame instead of the client area (#800) + - [WGL] Added reporting of errors from `WGL_ARB_create_context` extension + - [GLX] Bugfix: Dynamically loaded entry points were not verified + - [EGL] Added `lib` prefix matching between EGL and OpenGL ES library binaries + - [EGL] Bugfix: Dynamically loaded entry points were not verified + + +## Contact + +On [glfw.org](http://www.glfw.org/) you can find the latest version of GLFW, as +well as news, documentation and other information about the project. + +If you have questions related to the use of GLFW, we have a +[forum](http://discourse.glfw.org/), and the `#glfw` IRC channel on +[Freenode](http://freenode.net/). + +If you have a bug to report, a patch to submit or a feature you'd like to +request, please file it in the +[issue tracker](/~https://github.com/glfw/glfw/issues) on GitHub. + +Finally, if you're interested in helping out with the development of GLFW or +porting it to your favorite platform, join us on the forum, GitHub or IRC. + + +## Acknowledgements + +GLFW exists because people around the world donated their time and lent their +skills. + + - Bobyshev Alexander + - artblanc + - arturo + - Matt Arsenault + - Keith Bauer + - John Bartholomew + - Niklas Behrens + - Niklas Bergström + - Doug Binks + - blanco + - Martin Capitanio + - Chi-kwan Chan + - Lambert Clara + - Andrew Corrigan + - Noel Cower + - Jarrod Davis + - Olivier Delannoy + - Paul R. Deppe + - Michael Dickens + - Роман Донченко + - Mario Dorn + - Jonathan Dummer + - Ralph Eastwood + - Siavash Eliasi + - Michael Fogleman + - Gerald Franz + - GeO4d + - Marcus Geelnard + - Eloi Marín Gratacós + - Stefan Gustavson + - Sylvain Hellegouarch + - Matthew Henry + - heromyth + - Lucas Hinderberger + - Paul Holden + - Warren Hu + - IntellectualKitty + - Aaron Jacobs + - Erik S. V. Jansson + - Toni Jovanoski + - Arseny Kapoulkine + - Osman Keskin + - Cameron King + - Peter Knut + - Christoph Kubisch + - Eric Larson + - Robin Leffmann + - Glenn Lewis + - Shane Liesegang + - Eyal Lotem + - Дмитри Малышев + - Martins Mozeiko + - Tristam MacDonald + - Hans Mackowiak + - Zbigniew Mandziejewicz + - Kyle McDonald + - David Medlock + - Bryce Mehring + - Jonathan Mercier + - Marcel Metz + - Jonathan Miller + - Kenneth Miller + - Bruce Mitchener + - Jack Moffitt + - Jeff Molofee + - Jon Morton + - Pierre Moulon + - Julian Møller + - Kamil Nowakowski + - Ozzy + - Andri Pálsson + - Peoro + - Braden Pellett + - Arturo J. Pérez + - Orson Peters + - Emmanuel Gil Peyrot + - Cyril Pichard + - Pieroman + - Philip Rideout + - Jorge Rodriguez + - Ed Ropple + - Aleksey Rybalkin + - Riku Salminen + - Brandon Schaefer + - Sebastian Schuberth + - Matt Sealey + - SephiRok + - Steve Sexton + - Systemcluster + - Yoshiki Shibukawa + - Dmitri Shuralyov + - Daniel Skorupski + - Bradley Smith + - Patrick Snape + - Julian Squires + - Johannes Stein + - Justin Stoecker + - Elviss Strazdins + - Nathan Sweet + - TTK-Bandit + - Sergey Tikhomirov + - Arthur Tombs + - Ioannis Tsakpinis + - Samuli Tuomola + - urraka + - Jari Vetoniemi + - Ricardo Vieira + - Nicholas Vitovitch + - Simon Voordouw + - Torsten Walluhn + - Patrick Walton + - Xo Wang + - Jay Weisskopf + - Frank Wille + - yuriks + - Santi Zupancic + - Jonas Ã…dahl + - Lasse Öörni + - All the unmentioned and anonymous contributors in the GLFW community, for bug + reports, patches, feedback, testing and encouragement + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/cmake_uninstall.cmake.in b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/cmake_uninstall.cmake.in new file mode 100644 index 00000000..4ea57b1c --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/cmake_uninstall.cmake.in @@ -0,0 +1,29 @@ + +if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +endif() + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") + +foreach (file ${files}) + message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if (EXISTS "$ENV{DESTDIR}${file}") + exec_program("@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval) + if (NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + endif() + elseif (IS_SYMLINK "$ENV{DESTDIR}${file}") + EXEC_PROGRAM("@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval) + if (NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing symlink \"$ENV{DESTDIR}${file}\"") + endif() + else() + message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif() +endforeach() + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/KHR/khrplatform.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/KHR/khrplatform.h new file mode 100644 index 00000000..c9e6f17d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/KHR/khrplatform.h @@ -0,0 +1,282 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2009 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $ + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by sending them to the public Khronos Bugzilla + * (http://khronos.org/bugzilla) by filing a bug against product + * "Khronos (general)" component "Registry". + * + * A predefined template which fills in some of the bug fields can be + * reached using http://tinyurl.com/khrplatform-h-bugreport, but you + * must create a Bugzilla login first. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(_WIN32) && !defined(__SCITECH_SNAP__) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef _WIN64 +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/getopt.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/getopt.c new file mode 100644 index 00000000..9743046f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/getopt.c @@ -0,0 +1,230 @@ +/* Copyright (c) 2012, Kim Gräsman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Kim Gräsman nor the names of contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "getopt.h" + +#include +#include + +const int no_argument = 0; +const int required_argument = 1; +const int optional_argument = 2; + +char* optarg; +int optopt; +/* The variable optind [...] shall be initialized to 1 by the system. */ +int optind = 1; +int opterr; + +static char* optcursor = NULL; + +/* Implemented based on [1] and [2] for optional arguments. + optopt is handled FreeBSD-style, per [3]. + Other GNU and FreeBSD extensions are purely accidental. + +[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html +[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html +[3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE +*/ +int getopt(int argc, char* const argv[], const char* optstring) { + int optchar = -1; + const char* optdecl = NULL; + + optarg = NULL; + opterr = 0; + optopt = 0; + + /* Unspecified, but we need it to avoid overrunning the argv bounds. */ + if (optind >= argc) + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] is a null pointer, getopt() + shall return -1 without changing optind. */ + if (argv[optind] == NULL) + goto no_more_optchars; + + /* If, when getopt() is called *argv[optind] is not the character '-', + getopt() shall return -1 without changing optind. */ + if (*argv[optind] != '-') + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "-", + getopt() shall return -1 without changing optind. */ + if (strcmp(argv[optind], "-") == 0) + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "--", + getopt() shall return -1 after incrementing optind. */ + if (strcmp(argv[optind], "--") == 0) { + ++optind; + goto no_more_optchars; + } + + if (optcursor == NULL || *optcursor == '\0') + optcursor = argv[optind] + 1; + + optchar = *optcursor; + + /* FreeBSD: The variable optopt saves the last known option character + returned by getopt(). */ + optopt = optchar; + + /* The getopt() function shall return the next option character (if one is + found) from argv that matches a character in optstring, if there is + one that matches. */ + optdecl = strchr(optstring, optchar); + if (optdecl) { + /* [I]f a character is followed by a colon, the option takes an + argument. */ + if (optdecl[1] == ':') { + optarg = ++optcursor; + if (*optarg == '\0') { + /* GNU extension: Two colons mean an option takes an + optional arg; if there is text in the current argv-element + (i.e., in the same word as the option name itself, for example, + "-oarg"), then it is returned in optarg, otherwise optarg is set + to zero. */ + if (optdecl[2] != ':') { + /* If the option was the last character in the string pointed to by + an element of argv, then optarg shall contain the next element + of argv, and optind shall be incremented by 2. If the resulting + value of optind is greater than argc, this indicates a missing + option-argument, and getopt() shall return an error indication. + + Otherwise, optarg shall point to the string following the + option character in that element of argv, and optind shall be + incremented by 1. + */ + if (++optind < argc) { + optarg = argv[optind]; + } else { + /* If it detects a missing option-argument, it shall return the + colon character ( ':' ) if the first character of optstring + was a colon, or a question-mark character ( '?' ) otherwise. + */ + optarg = NULL; + optchar = (optstring[0] == ':') ? ':' : '?'; + } + } else { + optarg = NULL; + } + } + + optcursor = NULL; + } + } else { + /* If getopt() encounters an option character that is not contained in + optstring, it shall return the question-mark ( '?' ) character. */ + optchar = '?'; + } + + if (optcursor == NULL || *++optcursor == '\0') + ++optind; + + return optchar; + +no_more_optchars: + optcursor = NULL; + return -1; +} + +/* Implementation based on [1]. + +[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html +*/ +int getopt_long(int argc, char* const argv[], const char* optstring, + const struct option* longopts, int* longindex) { + const struct option* o = longopts; + const struct option* match = NULL; + int num_matches = 0; + size_t argument_name_length = 0; + const char* current_argument = NULL; + int retval = -1; + + optarg = NULL; + optopt = 0; + + if (optind >= argc) + return -1; + + if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) + return getopt(argc, argv, optstring); + + /* It's an option; starts with -- and is longer than two chars. */ + current_argument = argv[optind] + 2; + argument_name_length = strcspn(current_argument, "="); + for (; o->name; ++o) { + if (strncmp(o->name, current_argument, argument_name_length) == 0) { + match = o; + ++num_matches; + } + } + + if (num_matches == 1) { + /* If longindex is not NULL, it points to a variable which is set to the + index of the long option relative to longopts. */ + if (longindex) + *longindex = (int) (match - longopts); + + /* If flag is NULL, then getopt_long() shall return val. + Otherwise, getopt_long() returns 0, and flag shall point to a variable + which shall be set to val if the option is found, but left unchanged if + the option is not found. */ + if (match->flag) + *(match->flag) = match->val; + + retval = match->flag ? 0 : match->val; + + if (match->has_arg != no_argument) { + optarg = strchr(argv[optind], '='); + if (optarg != NULL) + ++optarg; + + if (match->has_arg == required_argument) { + /* Only scan the next argv for required arguments. Behavior is not + specified, but has been observed with Ubuntu and Mac OSX. */ + if (optarg == NULL && ++optind < argc) { + optarg = argv[optind]; + } + + if (optarg == NULL) + retval = ':'; + } + } else if (strchr(argv[optind], '=')) { + /* An argument was provided to a non-argument option. + I haven't seen this specified explicitly, but both GNU and BSD-based + implementations show this behavior. + */ + retval = '?'; + } + } else { + /* Unknown option or ambiguous match. */ + retval = '?'; + } + + ++optind; + return retval; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/getopt.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/getopt.h new file mode 100644 index 00000000..e1eb540f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/getopt.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2012, Kim Gräsman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Kim Gräsman nor the names of contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef INCLUDED_GETOPT_PORT_H +#define INCLUDED_GETOPT_PORT_H + +#if defined(__cplusplus) +extern "C" { +#endif + +extern const int no_argument; +extern const int required_argument; +extern const int optional_argument; + +extern char* optarg; +extern int optind, opterr, optopt; + +struct option { + const char* name; + int has_arg; + int* flag; + int val; +}; + +int getopt(int argc, char* const argv[], const char* optstring); + +int getopt_long(int argc, char* const argv[], + const char* optstring, const struct option* longopts, int* longindex); + +#if defined(__cplusplus) +} +#endif + +#endif // INCLUDED_GETOPT_PORT_H diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/glad.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/glad.c new file mode 100644 index 00000000..7886e606 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/glad.c @@ -0,0 +1,1555 @@ +#include +#include +#include +#include + +struct gladGLversionStruct GLVersion; + +static int has_ext(const char *ext) { +#if defined(GL_VERSION_3_0) || defined(GL_ES_VERSION_3_0) + if(GLVersion.major < 3 || glGetStringi == NULL) { +#endif + const char *extensions; + const char *loc; + const char *terminator; + extensions = (const char*) glGetString(GL_EXTENSIONS); + if(extensions == NULL || ext == NULL) { + return 0; + } + + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } +#if defined(GL_VERSION_3_0) || defined(GL_ES_VERSION_3_0) + } else { + GLint num_exts, index; + + glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts); + for(index = 0; index < num_exts; index++) { + if(strcmp((const char*) glGetStringi(GL_EXTENSIONS, index), ext) == 0) { + return 1; + } + } + } +#endif + + return 0; +} +int GLAD_GL_VERSION_1_0; +int GLAD_GL_VERSION_1_1; +int GLAD_GL_VERSION_1_2; +int GLAD_GL_VERSION_1_3; +int GLAD_GL_VERSION_1_4; +int GLAD_GL_VERSION_1_5; +int GLAD_GL_VERSION_2_0; +int GLAD_GL_VERSION_2_1; +int GLAD_GL_VERSION_3_0; +int GLAD_GL_VERSION_3_1; +int GLAD_GL_VERSION_3_2; +PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; +PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; +PFNGLWINDOWPOS2SPROC glad_glWindowPos2s; +PFNGLWINDOWPOS2IPROC glad_glWindowPos2i; +PFNGLWINDOWPOS2FPROC glad_glWindowPos2f; +PFNGLWINDOWPOS2DPROC glad_glWindowPos2d; +PFNGLVERTEX2FVPROC glad_glVertex2fv; +PFNGLINDEXIPROC glad_glIndexi; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +PFNGLRECTDVPROC glad_glRectdv; +PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; +PFNGLEVALCOORD2DPROC glad_glEvalCoord2d; +PFNGLEVALCOORD2FPROC glad_glEvalCoord2f; +PFNGLINDEXDPROC glad_glIndexd; +PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; +PFNGLINDEXFPROC glad_glIndexf; +PFNGLLINEWIDTHPROC glad_glLineWidth; +PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; +PFNGLGETMAPFVPROC glad_glGetMapfv; +PFNGLINDEXSPROC glad_glIndexs; +PFNGLCOMPILESHADERPROC glad_glCompileShader; +PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; +PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv; +PFNGLINDEXFVPROC glad_glIndexfv; +PFNGLFOGIVPROC glad_glFogiv; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv; +PFNGLLIGHTMODELIVPROC glad_glLightModeliv; +PFNGLCOLOR4UIPROC glad_glColor4ui; +PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv; +PFNGLFOGFVPROC glad_glFogfv; +PFNGLENABLEIPROC glad_glEnablei; +PFNGLVERTEX4IVPROC glad_glVertex4iv; +PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv; +PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv; +PFNGLCREATESHADERPROC glad_glCreateShader; +PFNGLISBUFFERPROC glad_glIsBuffer; +PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +PFNGLVERTEX4FVPROC glad_glVertex4fv; +PFNGLBINDTEXTUREPROC glad_glBindTexture; +PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; +PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv; +PFNGLSAMPLEMASKIPROC glad_glSampleMaski; +PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; +PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv; +PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; +PFNGLPOINTSIZEPROC glad_glPointSize; +PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +PFNGLCOLOR4BVPROC glad_glColor4bv; +PFNGLRASTERPOS2FPROC glad_glRasterPos2f; +PFNGLRASTERPOS2DPROC glad_glRasterPos2d; +PFNGLLOADIDENTITYPROC glad_glLoadIdentity; +PFNGLRASTERPOS2IPROC glad_glRasterPos2i; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; +PFNGLCOLOR3BPROC glad_glColor3b; +PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; +PFNGLEDGEFLAGPROC glad_glEdgeFlag; +PFNGLVERTEX3DPROC glad_glVertex3d; +PFNGLVERTEX3FPROC glad_glVertex3f; +PFNGLVERTEX3IPROC glad_glVertex3i; +PFNGLCOLOR3IPROC glad_glColor3i; +PFNGLUNIFORM3FPROC glad_glUniform3f; +PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; +PFNGLCOLOR3SPROC glad_glColor3s; +PFNGLVERTEX3SPROC glad_glVertex3s; +PFNGLCOLORMASKIPROC glad_glColorMaski; +PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; +PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv; +PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +PFNGLVERTEX2IVPROC glad_glVertex2iv; +PFNGLCOLOR3SVPROC glad_glColor3sv; +PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; +PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; +PFNGLNORMALPOINTERPROC glad_glNormalPointer; +PFNGLVERTEX4SVPROC glad_glVertex4sv; +PFNGLPASSTHROUGHPROC glad_glPassThrough; +PFNGLFOGIPROC glad_glFogi; +PFNGLBEGINPROC glad_glBegin; +PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv; +PFNGLCOLOR3UBVPROC glad_glColor3ubv; +PFNGLVERTEXPOINTERPROC glad_glVertexPointer; +PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +PFNGLDRAWARRAYSPROC glad_glDrawArrays; +PFNGLUNIFORM1UIPROC glad_glUniform1ui; +PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d; +PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f; +PFNGLLIGHTFVPROC glad_glLightfv; +PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; +PFNGLCLEARPROC glad_glClear; +PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i; +PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; +PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s; +PFNGLISENABLEDPROC glad_glIsEnabled; +PFNGLSTENCILOPPROC glad_glStencilOp; +PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +PFNGLTRANSLATEFPROC glad_glTranslatef; +PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; +PFNGLTRANSLATEDPROC glad_glTranslated; +PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv; +PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; +PFNGLTEXIMAGE1DPROC glad_glTexImage1D; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv; +PFNGLGETMATERIALFVPROC glad_glGetMaterialfv; +PFNGLGETTEXIMAGEPROC glad_glGetTexImage; +PFNGLFOGCOORDFVPROC glad_glFogCoordfv; +PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +PFNGLINDEXSVPROC glad_glIndexsv; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +PFNGLVERTEX3IVPROC glad_glVertex3iv; +PFNGLBITMAPPROC glad_glBitmap; +PFNGLMATERIALIPROC glad_glMateriali; +PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +PFNGLGETQUERYIVPROC glad_glGetQueryiv; +PFNGLTEXCOORD4FPROC glad_glTexCoord4f; +PFNGLTEXCOORD4DPROC glad_glTexCoord4d; +PFNGLTEXCOORD4IPROC glad_glTexCoord4i; +PFNGLMATERIALFPROC glad_glMaterialf; +PFNGLTEXCOORD4SPROC glad_glTexCoord4s; +PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; +PFNGLISSHADERPROC glad_glIsShader; +PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s; +PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; +PFNGLVERTEX3DVPROC glad_glVertex3dv; +PFNGLGETINTEGER64VPROC glad_glGetInteger64v; +PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; +PFNGLENABLEPROC glad_glEnable; +PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; +PFNGLCOLOR4FVPROC glad_glColor4fv; +PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv; +PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv; +PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; +PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv; +PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i; +PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv; +PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv; +PFNGLTEXGENFPROC glad_glTexGenf; +PFNGLGETPOINTERVPROC glad_glGetPointerv; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; +PFNGLNORMAL3FVPROC glad_glNormal3fv; +PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s; +PFNGLDEPTHRANGEPROC glad_glDepthRange; +PFNGLFRUSTUMPROC glad_glFrustum; +PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv; +PFNGLDRAWBUFFERPROC glad_glDrawBuffer; +PFNGLPUSHMATRIXPROC glad_glPushMatrix; +PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv; +PFNGLORTHOPROC glad_glOrtho; +PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; +PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv; +PFNGLCLEARINDEXPROC glad_glClearIndex; +PFNGLMAP1DPROC glad_glMap1d; +PFNGLMAP1FPROC glad_glMap1f; +PFNGLFLUSHPROC glad_glFlush; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +PFNGLINDEXIVPROC glad_glIndexiv; +PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +PFNGLPIXELZOOMPROC glad_glPixelZoom; +PFNGLFENCESYNCPROC glad_glFenceSync; +PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; +PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; +PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; +PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; +PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; +PFNGLLIGHTIPROC glad_glLighti; +PFNGLLIGHTFPROC glad_glLightf; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +PFNGLCLAMPCOLORPROC glad_glClampColor; +PFNGLUNIFORM4IVPROC glad_glUniform4iv; +PFNGLCLEARSTENCILPROC glad_glClearStencil; +PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv; +PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv; +PFNGLGENTEXTURESPROC glad_glGenTextures; +PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv; +PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; +PFNGLINDEXPOINTERPROC glad_glIndexPointer; +PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; +PFNGLISSYNCPROC glad_glIsSync; +PFNGLVERTEX2FPROC glad_glVertex2f; +PFNGLVERTEX2DPROC glad_glVertex2d; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +PFNGLUNIFORM2IPROC glad_glUniform2i; +PFNGLMAPGRID2DPROC glad_glMapGrid2d; +PFNGLMAPGRID2FPROC glad_glMapGrid2f; +PFNGLVERTEX2IPROC glad_glVertex2i; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; +PFNGLVERTEX2SPROC glad_glVertex2s; +PFNGLNORMAL3BVPROC glad_glNormal3bv; +PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; +PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; +PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv; +PFNGLVERTEX3SVPROC glad_glVertex3sv; +PFNGLGENQUERIESPROC glad_glGenQueries; +PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv; +PFNGLTEXENVFPROC glad_glTexEnvf; +PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; +PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; +PFNGLFOGCOORDDPROC glad_glFogCoordd; +PFNGLFOGCOORDFPROC glad_glFogCoordf; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +PFNGLTEXENVIPROC glad_glTexEnvi; +PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv; +PFNGLISENABLEDIPROC glad_glIsEnabledi; +PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; +PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv; +PFNGLUNIFORM2IVPROC glad_glUniform2iv; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; +PFNGLMATRIXMODEPROC glad_glMatrixMode; +PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer; +PFNGLGETMAPIVPROC glad_glGetMapiv; +PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; +PFNGLGETSHADERIVPROC glad_glGetShaderiv; +PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d; +PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f; +PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; +PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures; +PFNGLCALLLISTPROC glad_glCallList; +PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv; +PFNGLGETDOUBLEVPROC glad_glGetDoublev; +PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv; +PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; +PFNGLLIGHTMODELFPROC glad_glLightModelf; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +PFNGLVERTEX2SVPROC glad_glVertex2sv; +PFNGLLIGHTMODELIPROC glad_glLightModeli; +PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv; +PFNGLUNIFORM3FVPROC glad_glUniform3fv; +PFNGLPIXELSTOREIPROC glad_glPixelStorei; +PFNGLCALLLISTSPROC glad_glCallLists; +PFNGLMAPBUFFERPROC glad_glMapBuffer; +PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d; +PFNGLTEXCOORD3IPROC glad_glTexCoord3i; +PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv; +PFNGLRASTERPOS3IPROC glad_glRasterPos3i; +PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b; +PFNGLRASTERPOS3DPROC glad_glRasterPos3d; +PFNGLRASTERPOS3FPROC glad_glRasterPos3f; +PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; +PFNGLTEXCOORD3FPROC glad_glTexCoord3f; +PFNGLDELETESYNCPROC glad_glDeleteSync; +PFNGLTEXCOORD3DPROC glad_glTexCoord3d; +PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +PFNGLTEXCOORD3SPROC glad_glTexCoord3s; +PFNGLUNIFORM3IVPROC glad_glUniform3iv; +PFNGLRASTERPOS3SPROC glad_glRasterPos3s; +PFNGLPOLYGONMODEPROC glad_glPolygonMode; +PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; +PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; +PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident; +PFNGLISLISTPROC glad_glIsList; +PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv; +PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv; +PFNGLCOLOR4SPROC glad_glColor4s; +PFNGLUSEPROGRAMPROC glad_glUseProgram; +PFNGLLINESTIPPLEPROC glad_glLineStipple; +PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv; +PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; +PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; +PFNGLCOLOR4BPROC glad_glColor4b; +PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f; +PFNGLCOLOR4FPROC glad_glColor4f; +PFNGLCOLOR4DPROC glad_glColor4d; +PFNGLCOLOR4IPROC glad_glColor4i; +PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; +PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv; +PFNGLVERTEX2DVPROC glad_glVertex2dv; +PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv; +PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; +PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; +PFNGLFINISHPROC glad_glFinish; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +PFNGLDELETESHADERPROC glad_glDeleteShader; +PFNGLDRAWELEMENTSPROC glad_glDrawElements; +PFNGLRASTERPOS2SPROC glad_glRasterPos2s; +PFNGLGETMAPDVPROC glad_glGetMapdv; +PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; +PFNGLMATERIALFVPROC glad_glMaterialfv; +PFNGLVIEWPORTPROC glad_glViewport; +PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; +PFNGLINDEXDVPROC glad_glIndexdv; +PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; +PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv; +PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; +PFNGLCLEARDEPTHPROC glad_glClearDepth; +PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +PFNGLTEXBUFFERPROC glad_glTexBuffer; +PFNGLPOPNAMEPROC glad_glPopName; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +PFNGLPIXELSTOREFPROC glad_glPixelStoref; +PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; +PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv; +PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv; +PFNGLRECTIPROC glad_glRecti; +PFNGLCOLOR4UBPROC glad_glColor4ub; +PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf; +PFNGLRECTFPROC glad_glRectf; +PFNGLRECTDPROC glad_glRectd; +PFNGLNORMAL3SVPROC glad_glNormal3sv; +PFNGLNEWLISTPROC glad_glNewList; +PFNGLCOLOR4USPROC glad_glColor4us; +PFNGLLINKPROGRAMPROC glad_glLinkProgram; +PFNGLHINTPROC glad_glHint; +PFNGLRECTSPROC glad_glRects; +PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv; +PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv; +PFNGLGETSTRINGPROC glad_glGetString; +PFNGLEDGEFLAGVPROC glad_glEdgeFlagv; +PFNGLDETACHSHADERPROC glad_glDetachShader; +PFNGLSCALEFPROC glad_glScalef; +PFNGLENDQUERYPROC glad_glEndQuery; +PFNGLSCALEDPROC glad_glScaled; +PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer; +PFNGLCOPYPIXELSPROC glad_glCopyPixels; +PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; +PFNGLPOPATTRIBPROC glad_glPopAttrib; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +PFNGLDELETEQUERIESPROC glad_glDeleteQueries; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; +PFNGLINITNAMESPROC glad_glInitNames; +PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; +PFNGLCOLOR3DVPROC glad_glColor3dv; +PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +PFNGLWAITSYNCPROC glad_glWaitSync; +PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; +PFNGLCOLORMATERIALPROC glad_glColorMaterial; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +PFNGLUNIFORM1FPROC glad_glUniform1f; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +PFNGLRENDERMODEPROC glad_glRenderMode; +PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; +PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv; +PFNGLUNIFORM1IPROC glad_glUniform1i; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +PFNGLUNIFORM3IPROC glad_glUniform3i; +PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +PFNGLDISABLEPROC glad_glDisable; +PFNGLLOGICOPPROC glad_glLogicOp; +PFNGLEVALPOINT2PROC glad_glEvalPoint2; +PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf; +PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i; +PFNGLUNIFORM4UIPROC glad_glUniform4ui; +PFNGLCOLOR3FPROC glad_glColor3f; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv; +PFNGLRECTFVPROC glad_glRectfv; +PFNGLCULLFACEPROC glad_glCullFace; +PFNGLGETLIGHTFVPROC glad_glGetLightfv; +PFNGLCOLOR3DPROC glad_glColor3d; +PFNGLTEXGENDPROC glad_glTexGend; +PFNGLTEXGENIPROC glad_glTexGeni; +PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s; +PFNGLGETSTRINGIPROC glad_glGetStringi; +PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i; +PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f; +PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d; +PFNGLATTACHSHADERPROC glad_glAttachShader; +PFNGLFOGCOORDDVPROC glad_glFogCoorddv; +PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; +PFNGLGETTEXGENFVPROC glad_glGetTexGenfv; +PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer; +PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; +PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; +PFNGLTEXGENIVPROC glad_glTexGeniv; +PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv; +PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv; +PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture; +PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; +PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us; +PFNGLTEXENVFVPROC glad_glTexEnvfv; +PFNGLREADBUFFERPROC glad_glReadBuffer; +PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; +PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv; +PFNGLLIGHTMODELFVPROC glad_glLightModelfv; +PFNGLDELETELISTSPROC glad_glDeleteLists; +PFNGLGETCLIPPLANEPROC glad_glGetClipPlane; +PFNGLVERTEX4DVPROC glad_glVertex4dv; +PFNGLTEXCOORD2DPROC glad_glTexCoord2d; +PFNGLPOPMATRIXPROC glad_glPopMatrix; +PFNGLTEXCOORD2FPROC glad_glTexCoord2f; +PFNGLCOLOR4IVPROC glad_glColor4iv; +PFNGLINDEXUBVPROC glad_glIndexubv; +PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; +PFNGLTEXCOORD2IPROC glad_glTexCoord2i; +PFNGLRASTERPOS4DPROC glad_glRasterPos4d; +PFNGLRASTERPOS4FPROC glad_glRasterPos4f; +PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; +PFNGLTEXCOORD2SPROC glad_glTexCoord2s; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +PFNGLVERTEX3FVPROC glad_glVertex3fv; +PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv; +PFNGLMATERIALIVPROC glad_glMaterialiv; +PFNGLISPROGRAMPROC glad_glIsProgram; +PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; +PFNGLVERTEX4SPROC glad_glVertex4s; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +PFNGLNORMAL3DVPROC glad_glNormal3dv; +PFNGLUNIFORM4IPROC glad_glUniform4i; +PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +PFNGLROTATEDPROC glad_glRotated; +PFNGLROTATEFPROC glad_glRotatef; +PFNGLVERTEX4IPROC glad_glVertex4i; +PFNGLREADPIXELSPROC glad_glReadPixels; +PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; +PFNGLLOADNAMEPROC glad_glLoadName; +PFNGLUNIFORM4FPROC glad_glUniform4f; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; +PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; +PFNGLSHADEMODELPROC glad_glShadeModel; +PFNGLMAPGRID1DPROC glad_glMapGrid1d; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +PFNGLMAPGRID1FPROC glad_glMapGrid1f; +PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState; +PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; +PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer; +PFNGLALPHAFUNCPROC glad_glAlphaFunc; +PFNGLUNIFORM1IVPROC glad_glUniform1iv; +PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv; +PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; +PFNGLSTENCILFUNCPROC glad_glStencilFunc; +PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv; +PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; +PFNGLCOLOR4UIVPROC glad_glColor4uiv; +PFNGLRECTIVPROC glad_glRectiv; +PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv; +PFNGLEVALMESH2PROC glad_glEvalMesh2; +PFNGLEVALMESH1PROC glad_glEvalMesh1; +PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer; +PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; +PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; +PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv; +PFNGLCOLOR4UBVPROC glad_glColor4ubv; +PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd; +PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf; +PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; +PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv; +PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; +PFNGLTEXENVIVPROC glad_glTexEnviv; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; +PFNGLGENBUFFERSPROC glad_glGenBuffers; +PFNGLSELECTBUFFERPROC glad_glSelectBuffer; +PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; +PFNGLPUSHATTRIBPROC glad_glPushAttrib; +PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; +PFNGLBLENDFUNCPROC glad_glBlendFunc; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +PFNGLTEXIMAGE3DPROC glad_glTexImage3D; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +PFNGLLIGHTIVPROC glad_glLightiv; +PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; +PFNGLTEXGENFVPROC glad_glTexGenfv; +PFNGLENDPROC glad_glEnd; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +PFNGLSCISSORPROC glad_glScissor; +PFNGLCLIPPLANEPROC glad_glClipPlane; +PFNGLPUSHNAMEPROC glad_glPushName; +PFNGLTEXGENDVPROC glad_glTexGendv; +PFNGLINDEXUBPROC glad_glIndexub; +PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv; +PFNGLRASTERPOS4IPROC glad_glRasterPos4i; +PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd; +PFNGLCLEARCOLORPROC glad_glClearColor; +PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; +PFNGLNORMAL3SPROC glad_glNormal3s; +PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; +PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; +PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; +PFNGLBLENDCOLORPROC glad_glBlendColor; +PFNGLWINDOWPOS3DPROC glad_glWindowPos3d; +PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; +PFNGLUNIFORM3UIPROC glad_glUniform3ui; +PFNGLCOLOR4DVPROC glad_glColor4dv; +PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; +PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; +PFNGLUNIFORM2FVPROC glad_glUniform2fv; +PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub; +PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui; +PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv; +PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; +PFNGLNORMAL3IVPROC glad_glNormal3iv; +PFNGLWINDOWPOS3SPROC glad_glWindowPos3s; +PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; +PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; +PFNGLWINDOWPOS3IPROC glad_glWindowPos3i; +PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s; +PFNGLWINDOWPOS3FPROC glad_glWindowPos3f; +PFNGLCOLOR3USPROC glad_glColor3us; +PFNGLCOLOR3UIVPROC glad_glColor3uiv; +PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; +PFNGLGETLIGHTIVPROC glad_glGetLightiv; +PFNGLDEPTHFUNCPROC glad_glDepthFunc; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +PFNGLLISTBASEPROC glad_glListBase; +PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f; +PFNGLCOLOR3UBPROC glad_glColor3ub; +PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d; +PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +PFNGLCOLOR3UIPROC glad_glColor3ui; +PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i; +PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple; +PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; +PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; +PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv; +PFNGLCOLORMASKPROC glad_glColorMask; +PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +PFNGLRASTERPOS4SPROC glad_glRasterPos4s; +PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; +PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; +PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv; +PFNGLCOLOR4SVPROC glad_glColor4sv; +PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib; +PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; +PFNGLFOGFPROC glad_glFogf; +PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; +PFNGLCOLOR3IVPROC glad_glColor3iv; +PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; +PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; +PFNGLTEXCOORD1IPROC glad_glTexCoord1i; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +PFNGLTEXCOORD1DPROC glad_glTexCoord1d; +PFNGLTEXCOORD1FPROC glad_glTexCoord1f; +PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; +PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; +PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv; +PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; +PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; +PFNGLTEXCOORD1SPROC glad_glTexCoord1s; +PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; +PFNGLGENLISTSPROC glad_glGenLists; +PFNGLCOLOR3BVPROC glad_glColor3bv; +PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; +PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; +PFNGLGETTEXGENDVPROC glad_glGetTexGendv; +PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; +PFNGLENDLISTPROC glad_glEndList; +PFNGLUNIFORM2UIPROC glad_glUniform2ui; +PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; +PFNGLCOLOR3USVPROC glad_glColor3usv; +PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv; +PFNGLDISABLEIPROC glad_glDisablei; +PFNGLINDEXMASKPROC glad_glIndexMask; +PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib; +PFNGLSHADERSOURCEPROC glad_glShaderSource; +PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; +PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; +PFNGLCLEARACCUMPROC glad_glClearAccum; +PFNGLGETSYNCIVPROC glad_glGetSynciv; +PFNGLUNIFORM2FPROC glad_glUniform2f; +PFNGLBEGINQUERYPROC glad_glBeginQuery; +PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; +PFNGLBINDBUFFERPROC glad_glBindBuffer; +PFNGLMAP2DPROC glad_glMap2d; +PFNGLMAP2FPROC glad_glMap2f; +PFNGLVERTEX4DPROC glad_glVertex4d; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv; +PFNGLBUFFERDATAPROC glad_glBufferData; +PFNGLEVALPOINT1PROC glad_glEvalPoint1; +PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; +PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv; +PFNGLGETERRORPROC glad_glGetError; +PFNGLGETTEXENVIVPROC glad_glGetTexEnviv; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +PFNGLGETFLOATVPROC glad_glGetFloatv; +PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; +PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +PFNGLEVALCOORD1DPROC glad_glEvalCoord1d; +PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; +PFNGLEVALCOORD1FPROC glad_glEvalCoord1f; +PFNGLPIXELMAPFVPROC glad_glPixelMapfv; +PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv; +PFNGLGETINTEGERVPROC glad_glGetIntegerv; +PFNGLACCUMPROC glad_glAccum; +PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; +PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; +PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv; +PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv; +PFNGLISQUERYPROC glad_glIsQuery; +PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; +PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +PFNGLSTENCILMASKPROC glad_glStencilMask; +PFNGLDRAWPIXELSPROC glad_glDrawPixels; +PFNGLMULTMATRIXDPROC glad_glMultMatrixd; +PFNGLMULTMATRIXFPROC glad_glMultMatrixf; +PFNGLISTEXTUREPROC glad_glIsTexture; +PFNGLGETMATERIALIVPROC glad_glGetMaterialiv; +PFNGLUNIFORM1FVPROC glad_glUniform1fv; +PFNGLLOADMATRIXFPROC glad_glLoadMatrixf; +PFNGLLOADMATRIXDPROC glad_glLoadMatrixd; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +PFNGLVERTEX4FPROC glad_glVertex4f; +PFNGLRECTSVPROC glad_glRectsv; +PFNGLCOLOR4USVPROC glad_glColor4usv; +PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple; +PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays; +PFNGLNORMAL3IPROC glad_glNormal3i; +PFNGLNORMAL3FPROC glad_glNormal3f; +PFNGLNORMAL3DPROC glad_glNormal3d; +PFNGLNORMAL3BPROC glad_glNormal3b; +PFNGLPIXELMAPUSVPROC glad_glPixelMapusv; +PFNGLGETTEXGENIVPROC glad_glGetTexGeniv; +PFNGLARRAYELEMENTPROC glad_glArrayElement; +PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; +PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; +PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; +PFNGLDEPTHMASKPROC glad_glDepthMask; +PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; +PFNGLCOLOR3FVPROC glad_glColor3fv; +PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +PFNGLUNIFORM4FVPROC glad_glUniform4fv; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +PFNGLCOLORPOINTERPROC glad_glColorPointer; +PFNGLFRONTFACEPROC glad_glFrontFace; +PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; +PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; +int GLAD_GL_ARB_robustness; +int GLAD_GL_ARB_multisample; +int GLAD_GL_EXT_separate_specular_color; +PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB; +PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB; +PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB; +PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB; +PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC glad_glGetnCompressedTexImageARB; +PFNGLGETNUNIFORMFVARBPROC glad_glGetnUniformfvARB; +PFNGLGETNUNIFORMIVARBPROC glad_glGetnUniformivARB; +PFNGLGETNUNIFORMUIVARBPROC glad_glGetnUniformuivARB; +PFNGLGETNUNIFORMDVARBPROC glad_glGetnUniformdvARB; +PFNGLGETNMAPDVARBPROC glad_glGetnMapdvARB; +PFNGLGETNMAPFVARBPROC glad_glGetnMapfvARB; +PFNGLGETNMAPIVARBPROC glad_glGetnMapivARB; +PFNGLGETNPIXELMAPFVARBPROC glad_glGetnPixelMapfvARB; +PFNGLGETNPIXELMAPUIVARBPROC glad_glGetnPixelMapuivARB; +PFNGLGETNPIXELMAPUSVARBPROC glad_glGetnPixelMapusvARB; +PFNGLGETNPOLYGONSTIPPLEARBPROC glad_glGetnPolygonStippleARB; +PFNGLGETNCOLORTABLEARBPROC glad_glGetnColorTableARB; +PFNGLGETNCONVOLUTIONFILTERARBPROC glad_glGetnConvolutionFilterARB; +PFNGLGETNSEPARABLEFILTERARBPROC glad_glGetnSeparableFilterARB; +PFNGLGETNHISTOGRAMARBPROC glad_glGetnHistogramARB; +PFNGLGETNMINMAXARBPROC glad_glGetnMinmaxARB; +static void load_GL_VERSION_1_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_0) return; + glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); + glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); + glad_glHint = (PFNGLHINTPROC)load("glHint"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); + glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize"); + glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode"); + glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); + glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); + glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer"); + glad_glClear = (PFNGLCLEARPROC)load("glClear"); + glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); + glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); + glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); + glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); + glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); + glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); + glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); + glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); + glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); + glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); + glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer"); + glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); + glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev"); + glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); + glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); + glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv"); + glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv"); + glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); + glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange"); + glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); + glad_glNewList = (PFNGLNEWLISTPROC)load("glNewList"); + glad_glEndList = (PFNGLENDLISTPROC)load("glEndList"); + glad_glCallList = (PFNGLCALLLISTPROC)load("glCallList"); + glad_glCallLists = (PFNGLCALLLISTSPROC)load("glCallLists"); + glad_glDeleteLists = (PFNGLDELETELISTSPROC)load("glDeleteLists"); + glad_glGenLists = (PFNGLGENLISTSPROC)load("glGenLists"); + glad_glListBase = (PFNGLLISTBASEPROC)load("glListBase"); + glad_glBegin = (PFNGLBEGINPROC)load("glBegin"); + glad_glBitmap = (PFNGLBITMAPPROC)load("glBitmap"); + glad_glColor3b = (PFNGLCOLOR3BPROC)load("glColor3b"); + glad_glColor3bv = (PFNGLCOLOR3BVPROC)load("glColor3bv"); + glad_glColor3d = (PFNGLCOLOR3DPROC)load("glColor3d"); + glad_glColor3dv = (PFNGLCOLOR3DVPROC)load("glColor3dv"); + glad_glColor3f = (PFNGLCOLOR3FPROC)load("glColor3f"); + glad_glColor3fv = (PFNGLCOLOR3FVPROC)load("glColor3fv"); + glad_glColor3i = (PFNGLCOLOR3IPROC)load("glColor3i"); + glad_glColor3iv = (PFNGLCOLOR3IVPROC)load("glColor3iv"); + glad_glColor3s = (PFNGLCOLOR3SPROC)load("glColor3s"); + glad_glColor3sv = (PFNGLCOLOR3SVPROC)load("glColor3sv"); + glad_glColor3ub = (PFNGLCOLOR3UBPROC)load("glColor3ub"); + glad_glColor3ubv = (PFNGLCOLOR3UBVPROC)load("glColor3ubv"); + glad_glColor3ui = (PFNGLCOLOR3UIPROC)load("glColor3ui"); + glad_glColor3uiv = (PFNGLCOLOR3UIVPROC)load("glColor3uiv"); + glad_glColor3us = (PFNGLCOLOR3USPROC)load("glColor3us"); + glad_glColor3usv = (PFNGLCOLOR3USVPROC)load("glColor3usv"); + glad_glColor4b = (PFNGLCOLOR4BPROC)load("glColor4b"); + glad_glColor4bv = (PFNGLCOLOR4BVPROC)load("glColor4bv"); + glad_glColor4d = (PFNGLCOLOR4DPROC)load("glColor4d"); + glad_glColor4dv = (PFNGLCOLOR4DVPROC)load("glColor4dv"); + glad_glColor4f = (PFNGLCOLOR4FPROC)load("glColor4f"); + glad_glColor4fv = (PFNGLCOLOR4FVPROC)load("glColor4fv"); + glad_glColor4i = (PFNGLCOLOR4IPROC)load("glColor4i"); + glad_glColor4iv = (PFNGLCOLOR4IVPROC)load("glColor4iv"); + glad_glColor4s = (PFNGLCOLOR4SPROC)load("glColor4s"); + glad_glColor4sv = (PFNGLCOLOR4SVPROC)load("glColor4sv"); + glad_glColor4ub = (PFNGLCOLOR4UBPROC)load("glColor4ub"); + glad_glColor4ubv = (PFNGLCOLOR4UBVPROC)load("glColor4ubv"); + glad_glColor4ui = (PFNGLCOLOR4UIPROC)load("glColor4ui"); + glad_glColor4uiv = (PFNGLCOLOR4UIVPROC)load("glColor4uiv"); + glad_glColor4us = (PFNGLCOLOR4USPROC)load("glColor4us"); + glad_glColor4usv = (PFNGLCOLOR4USVPROC)load("glColor4usv"); + glad_glEdgeFlag = (PFNGLEDGEFLAGPROC)load("glEdgeFlag"); + glad_glEdgeFlagv = (PFNGLEDGEFLAGVPROC)load("glEdgeFlagv"); + glad_glEnd = (PFNGLENDPROC)load("glEnd"); + glad_glIndexd = (PFNGLINDEXDPROC)load("glIndexd"); + glad_glIndexdv = (PFNGLINDEXDVPROC)load("glIndexdv"); + glad_glIndexf = (PFNGLINDEXFPROC)load("glIndexf"); + glad_glIndexfv = (PFNGLINDEXFVPROC)load("glIndexfv"); + glad_glIndexi = (PFNGLINDEXIPROC)load("glIndexi"); + glad_glIndexiv = (PFNGLINDEXIVPROC)load("glIndexiv"); + glad_glIndexs = (PFNGLINDEXSPROC)load("glIndexs"); + glad_glIndexsv = (PFNGLINDEXSVPROC)load("glIndexsv"); + glad_glNormal3b = (PFNGLNORMAL3BPROC)load("glNormal3b"); + glad_glNormal3bv = (PFNGLNORMAL3BVPROC)load("glNormal3bv"); + glad_glNormal3d = (PFNGLNORMAL3DPROC)load("glNormal3d"); + glad_glNormal3dv = (PFNGLNORMAL3DVPROC)load("glNormal3dv"); + glad_glNormal3f = (PFNGLNORMAL3FPROC)load("glNormal3f"); + glad_glNormal3fv = (PFNGLNORMAL3FVPROC)load("glNormal3fv"); + glad_glNormal3i = (PFNGLNORMAL3IPROC)load("glNormal3i"); + glad_glNormal3iv = (PFNGLNORMAL3IVPROC)load("glNormal3iv"); + glad_glNormal3s = (PFNGLNORMAL3SPROC)load("glNormal3s"); + glad_glNormal3sv = (PFNGLNORMAL3SVPROC)load("glNormal3sv"); + glad_glRasterPos2d = (PFNGLRASTERPOS2DPROC)load("glRasterPos2d"); + glad_glRasterPos2dv = (PFNGLRASTERPOS2DVPROC)load("glRasterPos2dv"); + glad_glRasterPos2f = (PFNGLRASTERPOS2FPROC)load("glRasterPos2f"); + glad_glRasterPos2fv = (PFNGLRASTERPOS2FVPROC)load("glRasterPos2fv"); + glad_glRasterPos2i = (PFNGLRASTERPOS2IPROC)load("glRasterPos2i"); + glad_glRasterPos2iv = (PFNGLRASTERPOS2IVPROC)load("glRasterPos2iv"); + glad_glRasterPos2s = (PFNGLRASTERPOS2SPROC)load("glRasterPos2s"); + glad_glRasterPos2sv = (PFNGLRASTERPOS2SVPROC)load("glRasterPos2sv"); + glad_glRasterPos3d = (PFNGLRASTERPOS3DPROC)load("glRasterPos3d"); + glad_glRasterPos3dv = (PFNGLRASTERPOS3DVPROC)load("glRasterPos3dv"); + glad_glRasterPos3f = (PFNGLRASTERPOS3FPROC)load("glRasterPos3f"); + glad_glRasterPos3fv = (PFNGLRASTERPOS3FVPROC)load("glRasterPos3fv"); + glad_glRasterPos3i = (PFNGLRASTERPOS3IPROC)load("glRasterPos3i"); + glad_glRasterPos3iv = (PFNGLRASTERPOS3IVPROC)load("glRasterPos3iv"); + glad_glRasterPos3s = (PFNGLRASTERPOS3SPROC)load("glRasterPos3s"); + glad_glRasterPos3sv = (PFNGLRASTERPOS3SVPROC)load("glRasterPos3sv"); + glad_glRasterPos4d = (PFNGLRASTERPOS4DPROC)load("glRasterPos4d"); + glad_glRasterPos4dv = (PFNGLRASTERPOS4DVPROC)load("glRasterPos4dv"); + glad_glRasterPos4f = (PFNGLRASTERPOS4FPROC)load("glRasterPos4f"); + glad_glRasterPos4fv = (PFNGLRASTERPOS4FVPROC)load("glRasterPos4fv"); + glad_glRasterPos4i = (PFNGLRASTERPOS4IPROC)load("glRasterPos4i"); + glad_glRasterPos4iv = (PFNGLRASTERPOS4IVPROC)load("glRasterPos4iv"); + glad_glRasterPos4s = (PFNGLRASTERPOS4SPROC)load("glRasterPos4s"); + glad_glRasterPos4sv = (PFNGLRASTERPOS4SVPROC)load("glRasterPos4sv"); + glad_glRectd = (PFNGLRECTDPROC)load("glRectd"); + glad_glRectdv = (PFNGLRECTDVPROC)load("glRectdv"); + glad_glRectf = (PFNGLRECTFPROC)load("glRectf"); + glad_glRectfv = (PFNGLRECTFVPROC)load("glRectfv"); + glad_glRecti = (PFNGLRECTIPROC)load("glRecti"); + glad_glRectiv = (PFNGLRECTIVPROC)load("glRectiv"); + glad_glRects = (PFNGLRECTSPROC)load("glRects"); + glad_glRectsv = (PFNGLRECTSVPROC)load("glRectsv"); + glad_glTexCoord1d = (PFNGLTEXCOORD1DPROC)load("glTexCoord1d"); + glad_glTexCoord1dv = (PFNGLTEXCOORD1DVPROC)load("glTexCoord1dv"); + glad_glTexCoord1f = (PFNGLTEXCOORD1FPROC)load("glTexCoord1f"); + glad_glTexCoord1fv = (PFNGLTEXCOORD1FVPROC)load("glTexCoord1fv"); + glad_glTexCoord1i = (PFNGLTEXCOORD1IPROC)load("glTexCoord1i"); + glad_glTexCoord1iv = (PFNGLTEXCOORD1IVPROC)load("glTexCoord1iv"); + glad_glTexCoord1s = (PFNGLTEXCOORD1SPROC)load("glTexCoord1s"); + glad_glTexCoord1sv = (PFNGLTEXCOORD1SVPROC)load("glTexCoord1sv"); + glad_glTexCoord2d = (PFNGLTEXCOORD2DPROC)load("glTexCoord2d"); + glad_glTexCoord2dv = (PFNGLTEXCOORD2DVPROC)load("glTexCoord2dv"); + glad_glTexCoord2f = (PFNGLTEXCOORD2FPROC)load("glTexCoord2f"); + glad_glTexCoord2fv = (PFNGLTEXCOORD2FVPROC)load("glTexCoord2fv"); + glad_glTexCoord2i = (PFNGLTEXCOORD2IPROC)load("glTexCoord2i"); + glad_glTexCoord2iv = (PFNGLTEXCOORD2IVPROC)load("glTexCoord2iv"); + glad_glTexCoord2s = (PFNGLTEXCOORD2SPROC)load("glTexCoord2s"); + glad_glTexCoord2sv = (PFNGLTEXCOORD2SVPROC)load("glTexCoord2sv"); + glad_glTexCoord3d = (PFNGLTEXCOORD3DPROC)load("glTexCoord3d"); + glad_glTexCoord3dv = (PFNGLTEXCOORD3DVPROC)load("glTexCoord3dv"); + glad_glTexCoord3f = (PFNGLTEXCOORD3FPROC)load("glTexCoord3f"); + glad_glTexCoord3fv = (PFNGLTEXCOORD3FVPROC)load("glTexCoord3fv"); + glad_glTexCoord3i = (PFNGLTEXCOORD3IPROC)load("glTexCoord3i"); + glad_glTexCoord3iv = (PFNGLTEXCOORD3IVPROC)load("glTexCoord3iv"); + glad_glTexCoord3s = (PFNGLTEXCOORD3SPROC)load("glTexCoord3s"); + glad_glTexCoord3sv = (PFNGLTEXCOORD3SVPROC)load("glTexCoord3sv"); + glad_glTexCoord4d = (PFNGLTEXCOORD4DPROC)load("glTexCoord4d"); + glad_glTexCoord4dv = (PFNGLTEXCOORD4DVPROC)load("glTexCoord4dv"); + glad_glTexCoord4f = (PFNGLTEXCOORD4FPROC)load("glTexCoord4f"); + glad_glTexCoord4fv = (PFNGLTEXCOORD4FVPROC)load("glTexCoord4fv"); + glad_glTexCoord4i = (PFNGLTEXCOORD4IPROC)load("glTexCoord4i"); + glad_glTexCoord4iv = (PFNGLTEXCOORD4IVPROC)load("glTexCoord4iv"); + glad_glTexCoord4s = (PFNGLTEXCOORD4SPROC)load("glTexCoord4s"); + glad_glTexCoord4sv = (PFNGLTEXCOORD4SVPROC)load("glTexCoord4sv"); + glad_glVertex2d = (PFNGLVERTEX2DPROC)load("glVertex2d"); + glad_glVertex2dv = (PFNGLVERTEX2DVPROC)load("glVertex2dv"); + glad_glVertex2f = (PFNGLVERTEX2FPROC)load("glVertex2f"); + glad_glVertex2fv = (PFNGLVERTEX2FVPROC)load("glVertex2fv"); + glad_glVertex2i = (PFNGLVERTEX2IPROC)load("glVertex2i"); + glad_glVertex2iv = (PFNGLVERTEX2IVPROC)load("glVertex2iv"); + glad_glVertex2s = (PFNGLVERTEX2SPROC)load("glVertex2s"); + glad_glVertex2sv = (PFNGLVERTEX2SVPROC)load("glVertex2sv"); + glad_glVertex3d = (PFNGLVERTEX3DPROC)load("glVertex3d"); + glad_glVertex3dv = (PFNGLVERTEX3DVPROC)load("glVertex3dv"); + glad_glVertex3f = (PFNGLVERTEX3FPROC)load("glVertex3f"); + glad_glVertex3fv = (PFNGLVERTEX3FVPROC)load("glVertex3fv"); + glad_glVertex3i = (PFNGLVERTEX3IPROC)load("glVertex3i"); + glad_glVertex3iv = (PFNGLVERTEX3IVPROC)load("glVertex3iv"); + glad_glVertex3s = (PFNGLVERTEX3SPROC)load("glVertex3s"); + glad_glVertex3sv = (PFNGLVERTEX3SVPROC)load("glVertex3sv"); + glad_glVertex4d = (PFNGLVERTEX4DPROC)load("glVertex4d"); + glad_glVertex4dv = (PFNGLVERTEX4DVPROC)load("glVertex4dv"); + glad_glVertex4f = (PFNGLVERTEX4FPROC)load("glVertex4f"); + glad_glVertex4fv = (PFNGLVERTEX4FVPROC)load("glVertex4fv"); + glad_glVertex4i = (PFNGLVERTEX4IPROC)load("glVertex4i"); + glad_glVertex4iv = (PFNGLVERTEX4IVPROC)load("glVertex4iv"); + glad_glVertex4s = (PFNGLVERTEX4SPROC)load("glVertex4s"); + glad_glVertex4sv = (PFNGLVERTEX4SVPROC)load("glVertex4sv"); + glad_glClipPlane = (PFNGLCLIPPLANEPROC)load("glClipPlane"); + glad_glColorMaterial = (PFNGLCOLORMATERIALPROC)load("glColorMaterial"); + glad_glFogf = (PFNGLFOGFPROC)load("glFogf"); + glad_glFogfv = (PFNGLFOGFVPROC)load("glFogfv"); + glad_glFogi = (PFNGLFOGIPROC)load("glFogi"); + glad_glFogiv = (PFNGLFOGIVPROC)load("glFogiv"); + glad_glLightf = (PFNGLLIGHTFPROC)load("glLightf"); + glad_glLightfv = (PFNGLLIGHTFVPROC)load("glLightfv"); + glad_glLighti = (PFNGLLIGHTIPROC)load("glLighti"); + glad_glLightiv = (PFNGLLIGHTIVPROC)load("glLightiv"); + glad_glLightModelf = (PFNGLLIGHTMODELFPROC)load("glLightModelf"); + glad_glLightModelfv = (PFNGLLIGHTMODELFVPROC)load("glLightModelfv"); + glad_glLightModeli = (PFNGLLIGHTMODELIPROC)load("glLightModeli"); + glad_glLightModeliv = (PFNGLLIGHTMODELIVPROC)load("glLightModeliv"); + glad_glLineStipple = (PFNGLLINESTIPPLEPROC)load("glLineStipple"); + glad_glMaterialf = (PFNGLMATERIALFPROC)load("glMaterialf"); + glad_glMaterialfv = (PFNGLMATERIALFVPROC)load("glMaterialfv"); + glad_glMateriali = (PFNGLMATERIALIPROC)load("glMateriali"); + glad_glMaterialiv = (PFNGLMATERIALIVPROC)load("glMaterialiv"); + glad_glPolygonStipple = (PFNGLPOLYGONSTIPPLEPROC)load("glPolygonStipple"); + glad_glShadeModel = (PFNGLSHADEMODELPROC)load("glShadeModel"); + glad_glTexEnvf = (PFNGLTEXENVFPROC)load("glTexEnvf"); + glad_glTexEnvfv = (PFNGLTEXENVFVPROC)load("glTexEnvfv"); + glad_glTexEnvi = (PFNGLTEXENVIPROC)load("glTexEnvi"); + glad_glTexEnviv = (PFNGLTEXENVIVPROC)load("glTexEnviv"); + glad_glTexGend = (PFNGLTEXGENDPROC)load("glTexGend"); + glad_glTexGendv = (PFNGLTEXGENDVPROC)load("glTexGendv"); + glad_glTexGenf = (PFNGLTEXGENFPROC)load("glTexGenf"); + glad_glTexGenfv = (PFNGLTEXGENFVPROC)load("glTexGenfv"); + glad_glTexGeni = (PFNGLTEXGENIPROC)load("glTexGeni"); + glad_glTexGeniv = (PFNGLTEXGENIVPROC)load("glTexGeniv"); + glad_glFeedbackBuffer = (PFNGLFEEDBACKBUFFERPROC)load("glFeedbackBuffer"); + glad_glSelectBuffer = (PFNGLSELECTBUFFERPROC)load("glSelectBuffer"); + glad_glRenderMode = (PFNGLRENDERMODEPROC)load("glRenderMode"); + glad_glInitNames = (PFNGLINITNAMESPROC)load("glInitNames"); + glad_glLoadName = (PFNGLLOADNAMEPROC)load("glLoadName"); + glad_glPassThrough = (PFNGLPASSTHROUGHPROC)load("glPassThrough"); + glad_glPopName = (PFNGLPOPNAMEPROC)load("glPopName"); + glad_glPushName = (PFNGLPUSHNAMEPROC)load("glPushName"); + glad_glClearAccum = (PFNGLCLEARACCUMPROC)load("glClearAccum"); + glad_glClearIndex = (PFNGLCLEARINDEXPROC)load("glClearIndex"); + glad_glIndexMask = (PFNGLINDEXMASKPROC)load("glIndexMask"); + glad_glAccum = (PFNGLACCUMPROC)load("glAccum"); + glad_glPopAttrib = (PFNGLPOPATTRIBPROC)load("glPopAttrib"); + glad_glPushAttrib = (PFNGLPUSHATTRIBPROC)load("glPushAttrib"); + glad_glMap1d = (PFNGLMAP1DPROC)load("glMap1d"); + glad_glMap1f = (PFNGLMAP1FPROC)load("glMap1f"); + glad_glMap2d = (PFNGLMAP2DPROC)load("glMap2d"); + glad_glMap2f = (PFNGLMAP2FPROC)load("glMap2f"); + glad_glMapGrid1d = (PFNGLMAPGRID1DPROC)load("glMapGrid1d"); + glad_glMapGrid1f = (PFNGLMAPGRID1FPROC)load("glMapGrid1f"); + glad_glMapGrid2d = (PFNGLMAPGRID2DPROC)load("glMapGrid2d"); + glad_glMapGrid2f = (PFNGLMAPGRID2FPROC)load("glMapGrid2f"); + glad_glEvalCoord1d = (PFNGLEVALCOORD1DPROC)load("glEvalCoord1d"); + glad_glEvalCoord1dv = (PFNGLEVALCOORD1DVPROC)load("glEvalCoord1dv"); + glad_glEvalCoord1f = (PFNGLEVALCOORD1FPROC)load("glEvalCoord1f"); + glad_glEvalCoord1fv = (PFNGLEVALCOORD1FVPROC)load("glEvalCoord1fv"); + glad_glEvalCoord2d = (PFNGLEVALCOORD2DPROC)load("glEvalCoord2d"); + glad_glEvalCoord2dv = (PFNGLEVALCOORD2DVPROC)load("glEvalCoord2dv"); + glad_glEvalCoord2f = (PFNGLEVALCOORD2FPROC)load("glEvalCoord2f"); + glad_glEvalCoord2fv = (PFNGLEVALCOORD2FVPROC)load("glEvalCoord2fv"); + glad_glEvalMesh1 = (PFNGLEVALMESH1PROC)load("glEvalMesh1"); + glad_glEvalPoint1 = (PFNGLEVALPOINT1PROC)load("glEvalPoint1"); + glad_glEvalMesh2 = (PFNGLEVALMESH2PROC)load("glEvalMesh2"); + glad_glEvalPoint2 = (PFNGLEVALPOINT2PROC)load("glEvalPoint2"); + glad_glAlphaFunc = (PFNGLALPHAFUNCPROC)load("glAlphaFunc"); + glad_glPixelZoom = (PFNGLPIXELZOOMPROC)load("glPixelZoom"); + glad_glPixelTransferf = (PFNGLPIXELTRANSFERFPROC)load("glPixelTransferf"); + glad_glPixelTransferi = (PFNGLPIXELTRANSFERIPROC)load("glPixelTransferi"); + glad_glPixelMapfv = (PFNGLPIXELMAPFVPROC)load("glPixelMapfv"); + glad_glPixelMapuiv = (PFNGLPIXELMAPUIVPROC)load("glPixelMapuiv"); + glad_glPixelMapusv = (PFNGLPIXELMAPUSVPROC)load("glPixelMapusv"); + glad_glCopyPixels = (PFNGLCOPYPIXELSPROC)load("glCopyPixels"); + glad_glDrawPixels = (PFNGLDRAWPIXELSPROC)load("glDrawPixels"); + glad_glGetClipPlane = (PFNGLGETCLIPPLANEPROC)load("glGetClipPlane"); + glad_glGetLightfv = (PFNGLGETLIGHTFVPROC)load("glGetLightfv"); + glad_glGetLightiv = (PFNGLGETLIGHTIVPROC)load("glGetLightiv"); + glad_glGetMapdv = (PFNGLGETMAPDVPROC)load("glGetMapdv"); + glad_glGetMapfv = (PFNGLGETMAPFVPROC)load("glGetMapfv"); + glad_glGetMapiv = (PFNGLGETMAPIVPROC)load("glGetMapiv"); + glad_glGetMaterialfv = (PFNGLGETMATERIALFVPROC)load("glGetMaterialfv"); + glad_glGetMaterialiv = (PFNGLGETMATERIALIVPROC)load("glGetMaterialiv"); + glad_glGetPixelMapfv = (PFNGLGETPIXELMAPFVPROC)load("glGetPixelMapfv"); + glad_glGetPixelMapuiv = (PFNGLGETPIXELMAPUIVPROC)load("glGetPixelMapuiv"); + glad_glGetPixelMapusv = (PFNGLGETPIXELMAPUSVPROC)load("glGetPixelMapusv"); + glad_glGetPolygonStipple = (PFNGLGETPOLYGONSTIPPLEPROC)load("glGetPolygonStipple"); + glad_glGetTexEnvfv = (PFNGLGETTEXENVFVPROC)load("glGetTexEnvfv"); + glad_glGetTexEnviv = (PFNGLGETTEXENVIVPROC)load("glGetTexEnviv"); + glad_glGetTexGendv = (PFNGLGETTEXGENDVPROC)load("glGetTexGendv"); + glad_glGetTexGenfv = (PFNGLGETTEXGENFVPROC)load("glGetTexGenfv"); + glad_glGetTexGeniv = (PFNGLGETTEXGENIVPROC)load("glGetTexGeniv"); + glad_glIsList = (PFNGLISLISTPROC)load("glIsList"); + glad_glFrustum = (PFNGLFRUSTUMPROC)load("glFrustum"); + glad_glLoadIdentity = (PFNGLLOADIDENTITYPROC)load("glLoadIdentity"); + glad_glLoadMatrixf = (PFNGLLOADMATRIXFPROC)load("glLoadMatrixf"); + glad_glLoadMatrixd = (PFNGLLOADMATRIXDPROC)load("glLoadMatrixd"); + glad_glMatrixMode = (PFNGLMATRIXMODEPROC)load("glMatrixMode"); + glad_glMultMatrixf = (PFNGLMULTMATRIXFPROC)load("glMultMatrixf"); + glad_glMultMatrixd = (PFNGLMULTMATRIXDPROC)load("glMultMatrixd"); + glad_glOrtho = (PFNGLORTHOPROC)load("glOrtho"); + glad_glPopMatrix = (PFNGLPOPMATRIXPROC)load("glPopMatrix"); + glad_glPushMatrix = (PFNGLPUSHMATRIXPROC)load("glPushMatrix"); + glad_glRotated = (PFNGLROTATEDPROC)load("glRotated"); + glad_glRotatef = (PFNGLROTATEFPROC)load("glRotatef"); + glad_glScaled = (PFNGLSCALEDPROC)load("glScaled"); + glad_glScalef = (PFNGLSCALEFPROC)load("glScalef"); + glad_glTranslated = (PFNGLTRANSLATEDPROC)load("glTranslated"); + glad_glTranslatef = (PFNGLTRANSLATEFPROC)load("glTranslatef"); +} +static void load_GL_VERSION_1_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_1) return; + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); + glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); + glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); + glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); + glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); + glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); + glad_glArrayElement = (PFNGLARRAYELEMENTPROC)load("glArrayElement"); + glad_glColorPointer = (PFNGLCOLORPOINTERPROC)load("glColorPointer"); + glad_glDisableClientState = (PFNGLDISABLECLIENTSTATEPROC)load("glDisableClientState"); + glad_glEdgeFlagPointer = (PFNGLEDGEFLAGPOINTERPROC)load("glEdgeFlagPointer"); + glad_glEnableClientState = (PFNGLENABLECLIENTSTATEPROC)load("glEnableClientState"); + glad_glIndexPointer = (PFNGLINDEXPOINTERPROC)load("glIndexPointer"); + glad_glInterleavedArrays = (PFNGLINTERLEAVEDARRAYSPROC)load("glInterleavedArrays"); + glad_glNormalPointer = (PFNGLNORMALPOINTERPROC)load("glNormalPointer"); + glad_glTexCoordPointer = (PFNGLTEXCOORDPOINTERPROC)load("glTexCoordPointer"); + glad_glVertexPointer = (PFNGLVERTEXPOINTERPROC)load("glVertexPointer"); + glad_glAreTexturesResident = (PFNGLARETEXTURESRESIDENTPROC)load("glAreTexturesResident"); + glad_glPrioritizeTextures = (PFNGLPRIORITIZETEXTURESPROC)load("glPrioritizeTextures"); + glad_glIndexub = (PFNGLINDEXUBPROC)load("glIndexub"); + glad_glIndexubv = (PFNGLINDEXUBVPROC)load("glIndexubv"); + glad_glPopClientAttrib = (PFNGLPOPCLIENTATTRIBPROC)load("glPopClientAttrib"); + glad_glPushClientAttrib = (PFNGLPUSHCLIENTATTRIBPROC)load("glPushClientAttrib"); +} +static void load_GL_VERSION_1_2(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_2) return; + glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements"); + glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D"); + glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D"); + glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D"); +} +static void load_GL_VERSION_1_3(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_3) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); + glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); + glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D"); + glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); + glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D"); + glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage"); + glad_glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)load("glClientActiveTexture"); + glad_glMultiTexCoord1d = (PFNGLMULTITEXCOORD1DPROC)load("glMultiTexCoord1d"); + glad_glMultiTexCoord1dv = (PFNGLMULTITEXCOORD1DVPROC)load("glMultiTexCoord1dv"); + glad_glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC)load("glMultiTexCoord1f"); + glad_glMultiTexCoord1fv = (PFNGLMULTITEXCOORD1FVPROC)load("glMultiTexCoord1fv"); + glad_glMultiTexCoord1i = (PFNGLMULTITEXCOORD1IPROC)load("glMultiTexCoord1i"); + glad_glMultiTexCoord1iv = (PFNGLMULTITEXCOORD1IVPROC)load("glMultiTexCoord1iv"); + glad_glMultiTexCoord1s = (PFNGLMULTITEXCOORD1SPROC)load("glMultiTexCoord1s"); + glad_glMultiTexCoord1sv = (PFNGLMULTITEXCOORD1SVPROC)load("glMultiTexCoord1sv"); + glad_glMultiTexCoord2d = (PFNGLMULTITEXCOORD2DPROC)load("glMultiTexCoord2d"); + glad_glMultiTexCoord2dv = (PFNGLMULTITEXCOORD2DVPROC)load("glMultiTexCoord2dv"); + glad_glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC)load("glMultiTexCoord2f"); + glad_glMultiTexCoord2fv = (PFNGLMULTITEXCOORD2FVPROC)load("glMultiTexCoord2fv"); + glad_glMultiTexCoord2i = (PFNGLMULTITEXCOORD2IPROC)load("glMultiTexCoord2i"); + glad_glMultiTexCoord2iv = (PFNGLMULTITEXCOORD2IVPROC)load("glMultiTexCoord2iv"); + glad_glMultiTexCoord2s = (PFNGLMULTITEXCOORD2SPROC)load("glMultiTexCoord2s"); + glad_glMultiTexCoord2sv = (PFNGLMULTITEXCOORD2SVPROC)load("glMultiTexCoord2sv"); + glad_glMultiTexCoord3d = (PFNGLMULTITEXCOORD3DPROC)load("glMultiTexCoord3d"); + glad_glMultiTexCoord3dv = (PFNGLMULTITEXCOORD3DVPROC)load("glMultiTexCoord3dv"); + glad_glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC)load("glMultiTexCoord3f"); + glad_glMultiTexCoord3fv = (PFNGLMULTITEXCOORD3FVPROC)load("glMultiTexCoord3fv"); + glad_glMultiTexCoord3i = (PFNGLMULTITEXCOORD3IPROC)load("glMultiTexCoord3i"); + glad_glMultiTexCoord3iv = (PFNGLMULTITEXCOORD3IVPROC)load("glMultiTexCoord3iv"); + glad_glMultiTexCoord3s = (PFNGLMULTITEXCOORD3SPROC)load("glMultiTexCoord3s"); + glad_glMultiTexCoord3sv = (PFNGLMULTITEXCOORD3SVPROC)load("glMultiTexCoord3sv"); + glad_glMultiTexCoord4d = (PFNGLMULTITEXCOORD4DPROC)load("glMultiTexCoord4d"); + glad_glMultiTexCoord4dv = (PFNGLMULTITEXCOORD4DVPROC)load("glMultiTexCoord4dv"); + glad_glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC)load("glMultiTexCoord4f"); + glad_glMultiTexCoord4fv = (PFNGLMULTITEXCOORD4FVPROC)load("glMultiTexCoord4fv"); + glad_glMultiTexCoord4i = (PFNGLMULTITEXCOORD4IPROC)load("glMultiTexCoord4i"); + glad_glMultiTexCoord4iv = (PFNGLMULTITEXCOORD4IVPROC)load("glMultiTexCoord4iv"); + glad_glMultiTexCoord4s = (PFNGLMULTITEXCOORD4SPROC)load("glMultiTexCoord4s"); + glad_glMultiTexCoord4sv = (PFNGLMULTITEXCOORD4SVPROC)load("glMultiTexCoord4sv"); + glad_glLoadTransposeMatrixf = (PFNGLLOADTRANSPOSEMATRIXFPROC)load("glLoadTransposeMatrixf"); + glad_glLoadTransposeMatrixd = (PFNGLLOADTRANSPOSEMATRIXDPROC)load("glLoadTransposeMatrixd"); + glad_glMultTransposeMatrixf = (PFNGLMULTTRANSPOSEMATRIXFPROC)load("glMultTransposeMatrixf"); + glad_glMultTransposeMatrixd = (PFNGLMULTTRANSPOSEMATRIXDPROC)load("glMultTransposeMatrixd"); +} +static void load_GL_VERSION_1_4(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_4) return; + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); + glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays"); + glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements"); + glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf"); + glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv"); + glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri"); + glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv"); + glad_glFogCoordf = (PFNGLFOGCOORDFPROC)load("glFogCoordf"); + glad_glFogCoordfv = (PFNGLFOGCOORDFVPROC)load("glFogCoordfv"); + glad_glFogCoordd = (PFNGLFOGCOORDDPROC)load("glFogCoordd"); + glad_glFogCoorddv = (PFNGLFOGCOORDDVPROC)load("glFogCoorddv"); + glad_glFogCoordPointer = (PFNGLFOGCOORDPOINTERPROC)load("glFogCoordPointer"); + glad_glSecondaryColor3b = (PFNGLSECONDARYCOLOR3BPROC)load("glSecondaryColor3b"); + glad_glSecondaryColor3bv = (PFNGLSECONDARYCOLOR3BVPROC)load("glSecondaryColor3bv"); + glad_glSecondaryColor3d = (PFNGLSECONDARYCOLOR3DPROC)load("glSecondaryColor3d"); + glad_glSecondaryColor3dv = (PFNGLSECONDARYCOLOR3DVPROC)load("glSecondaryColor3dv"); + glad_glSecondaryColor3f = (PFNGLSECONDARYCOLOR3FPROC)load("glSecondaryColor3f"); + glad_glSecondaryColor3fv = (PFNGLSECONDARYCOLOR3FVPROC)load("glSecondaryColor3fv"); + glad_glSecondaryColor3i = (PFNGLSECONDARYCOLOR3IPROC)load("glSecondaryColor3i"); + glad_glSecondaryColor3iv = (PFNGLSECONDARYCOLOR3IVPROC)load("glSecondaryColor3iv"); + glad_glSecondaryColor3s = (PFNGLSECONDARYCOLOR3SPROC)load("glSecondaryColor3s"); + glad_glSecondaryColor3sv = (PFNGLSECONDARYCOLOR3SVPROC)load("glSecondaryColor3sv"); + glad_glSecondaryColor3ub = (PFNGLSECONDARYCOLOR3UBPROC)load("glSecondaryColor3ub"); + glad_glSecondaryColor3ubv = (PFNGLSECONDARYCOLOR3UBVPROC)load("glSecondaryColor3ubv"); + glad_glSecondaryColor3ui = (PFNGLSECONDARYCOLOR3UIPROC)load("glSecondaryColor3ui"); + glad_glSecondaryColor3uiv = (PFNGLSECONDARYCOLOR3UIVPROC)load("glSecondaryColor3uiv"); + glad_glSecondaryColor3us = (PFNGLSECONDARYCOLOR3USPROC)load("glSecondaryColor3us"); + glad_glSecondaryColor3usv = (PFNGLSECONDARYCOLOR3USVPROC)load("glSecondaryColor3usv"); + glad_glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)load("glSecondaryColorPointer"); + glad_glWindowPos2d = (PFNGLWINDOWPOS2DPROC)load("glWindowPos2d"); + glad_glWindowPos2dv = (PFNGLWINDOWPOS2DVPROC)load("glWindowPos2dv"); + glad_glWindowPos2f = (PFNGLWINDOWPOS2FPROC)load("glWindowPos2f"); + glad_glWindowPos2fv = (PFNGLWINDOWPOS2FVPROC)load("glWindowPos2fv"); + glad_glWindowPos2i = (PFNGLWINDOWPOS2IPROC)load("glWindowPos2i"); + glad_glWindowPos2iv = (PFNGLWINDOWPOS2IVPROC)load("glWindowPos2iv"); + glad_glWindowPos2s = (PFNGLWINDOWPOS2SPROC)load("glWindowPos2s"); + glad_glWindowPos2sv = (PFNGLWINDOWPOS2SVPROC)load("glWindowPos2sv"); + glad_glWindowPos3d = (PFNGLWINDOWPOS3DPROC)load("glWindowPos3d"); + glad_glWindowPos3dv = (PFNGLWINDOWPOS3DVPROC)load("glWindowPos3dv"); + glad_glWindowPos3f = (PFNGLWINDOWPOS3FPROC)load("glWindowPos3f"); + glad_glWindowPos3fv = (PFNGLWINDOWPOS3FVPROC)load("glWindowPos3fv"); + glad_glWindowPos3i = (PFNGLWINDOWPOS3IPROC)load("glWindowPos3i"); + glad_glWindowPos3iv = (PFNGLWINDOWPOS3IVPROC)load("glWindowPos3iv"); + glad_glWindowPos3s = (PFNGLWINDOWPOS3SPROC)load("glWindowPos3s"); + glad_glWindowPos3sv = (PFNGLWINDOWPOS3SVPROC)load("glWindowPos3sv"); + glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); +} +static void load_GL_VERSION_1_5(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_5) return; + glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries"); + glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries"); + glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery"); + glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery"); + glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery"); + glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv"); + glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv"); + glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); + glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); + glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); + glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData"); + glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer"); + glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); + glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); +} +static void load_GL_VERSION_2_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_0) return; + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); + glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); + glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); + glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); + glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); + glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); + glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d"); + glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); + glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s"); + glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv"); + glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d"); + glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); + glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s"); + glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv"); + glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d"); + glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); + glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s"); + glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv"); + glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv"); + glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv"); + glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv"); + glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub"); + glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv"); + glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv"); + glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv"); + glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv"); + glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d"); + glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); + glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv"); + glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s"); + glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv"); + glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv"); + glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv"); + glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); +} +static void load_GL_VERSION_2_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_1) return; + glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv"); + glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv"); + glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv"); + glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv"); + glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv"); + glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv"); +} +static void load_GL_VERSION_3_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_0) return; + glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski"); + glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); + glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei"); + glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei"); + glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi"); + glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback"); + glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings"); + glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying"); + glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor"); + glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender"); + glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender"); + glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer"); + glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv"); + glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv"); + glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i"); + glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i"); + glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i"); + glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i"); + glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui"); + glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui"); + glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui"); + glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui"); + glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv"); + glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv"); + glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv"); + glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv"); + glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv"); + glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv"); + glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv"); + glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv"); + glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv"); + glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv"); + glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv"); + glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv"); + glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv"); + glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation"); + glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation"); + glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui"); + glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui"); + glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui"); + glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui"); + glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv"); + glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv"); + glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv"); + glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv"); + glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv"); + glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv"); + glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv"); + glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv"); + glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv"); + glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv"); + glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv"); + glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi"); + glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); + glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); + glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); + glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); + glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); + glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); + glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange"); + glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange"); + glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); + glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); + glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); + glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); +} +static void load_GL_VERSION_3_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_1) return; + glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced"); + glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced"); + glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer"); + glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load("glPrimitiveRestartIndex"); + glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData"); + glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices"); + glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv"); + glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName"); + glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex"); + glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv"); + glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName"); + glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); +} +static void load_GL_VERSION_3_2(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_2) return; + glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex"); + glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex"); + glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex"); + glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load("glMultiDrawElementsBaseVertex"); + glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load("glProvokingVertex"); + glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync"); + glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync"); + glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync"); + glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync"); + glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync"); + glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v"); + glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv"); + glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v"); + glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v"); + glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture"); + glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample"); + glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample"); + glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv"); + glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski"); +} +static void load_GL_ARB_multisample(GLADloadproc load) { + if(!GLAD_GL_ARB_multisample) return; + glad_glSampleCoverageARB = (PFNGLSAMPLECOVERAGEARBPROC)load("glSampleCoverageARB"); +} +static void load_GL_ARB_robustness(GLADloadproc load) { + if(!GLAD_GL_ARB_robustness) return; + glad_glGetGraphicsResetStatusARB = (PFNGLGETGRAPHICSRESETSTATUSARBPROC)load("glGetGraphicsResetStatusARB"); + glad_glGetnTexImageARB = (PFNGLGETNTEXIMAGEARBPROC)load("glGetnTexImageARB"); + glad_glReadnPixelsARB = (PFNGLREADNPIXELSARBPROC)load("glReadnPixelsARB"); + glad_glGetnCompressedTexImageARB = (PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC)load("glGetnCompressedTexImageARB"); + glad_glGetnUniformfvARB = (PFNGLGETNUNIFORMFVARBPROC)load("glGetnUniformfvARB"); + glad_glGetnUniformivARB = (PFNGLGETNUNIFORMIVARBPROC)load("glGetnUniformivARB"); + glad_glGetnUniformuivARB = (PFNGLGETNUNIFORMUIVARBPROC)load("glGetnUniformuivARB"); + glad_glGetnUniformdvARB = (PFNGLGETNUNIFORMDVARBPROC)load("glGetnUniformdvARB"); + glad_glGetnMapdvARB = (PFNGLGETNMAPDVARBPROC)load("glGetnMapdvARB"); + glad_glGetnMapfvARB = (PFNGLGETNMAPFVARBPROC)load("glGetnMapfvARB"); + glad_glGetnMapivARB = (PFNGLGETNMAPIVARBPROC)load("glGetnMapivARB"); + glad_glGetnPixelMapfvARB = (PFNGLGETNPIXELMAPFVARBPROC)load("glGetnPixelMapfvARB"); + glad_glGetnPixelMapuivARB = (PFNGLGETNPIXELMAPUIVARBPROC)load("glGetnPixelMapuivARB"); + glad_glGetnPixelMapusvARB = (PFNGLGETNPIXELMAPUSVARBPROC)load("glGetnPixelMapusvARB"); + glad_glGetnPolygonStippleARB = (PFNGLGETNPOLYGONSTIPPLEARBPROC)load("glGetnPolygonStippleARB"); + glad_glGetnColorTableARB = (PFNGLGETNCOLORTABLEARBPROC)load("glGetnColorTableARB"); + glad_glGetnConvolutionFilterARB = (PFNGLGETNCONVOLUTIONFILTERARBPROC)load("glGetnConvolutionFilterARB"); + glad_glGetnSeparableFilterARB = (PFNGLGETNSEPARABLEFILTERARBPROC)load("glGetnSeparableFilterARB"); + glad_glGetnHistogramARB = (PFNGLGETNHISTOGRAMARBPROC)load("glGetnHistogramARB"); + glad_glGetnMinmaxARB = (PFNGLGETNMINMAXARBPROC)load("glGetnMinmaxARB"); +} +static void find_extensionsGL(void) { + GLAD_GL_EXT_separate_specular_color = has_ext("GL_EXT_separate_specular_color"); + GLAD_GL_ARB_multisample = has_ext("GL_ARB_multisample"); + GLAD_GL_ARB_robustness = has_ext("GL_ARB_robustness"); +} + +static void find_coreGL(void) { + + /* Thank you @elmindreda + * /~https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + * /~https://github.com/glfw/glfw/blob/master/src/context.c#L36 + */ + int i, major, minor; + + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + NULL + }; + + version = (const char*) glGetString(GL_VERSION); + if (!version) return; + + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + +/* PR #18 */ +#ifdef _MSC_VER + sscanf_s(version, "%d.%d", &major, &minor); +#else + sscanf(version, "%d.%d", &major, &minor); +#endif + + GLVersion.major = major; GLVersion.minor = minor; + GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; + GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; + GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; + GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; + GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; + GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; + GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; +} + +int gladLoadGLLoader(GLADloadproc load) { + GLVersion.major = 0; GLVersion.minor = 0; + glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + if(glGetString == NULL) return 0; + if(glGetString(GL_VERSION) == NULL) return 0; + find_coreGL(); + load_GL_VERSION_1_0(load); + load_GL_VERSION_1_1(load); + load_GL_VERSION_1_2(load); + load_GL_VERSION_1_3(load); + load_GL_VERSION_1_4(load); + load_GL_VERSION_1_5(load); + load_GL_VERSION_2_0(load); + load_GL_VERSION_2_1(load); + load_GL_VERSION_3_0(load); + load_GL_VERSION_3_1(load); + load_GL_VERSION_3_2(load); + + find_extensionsGL(); + load_GL_ARB_multisample(load); + load_GL_ARB_robustness(load); + return GLVersion.major != 0 || GLVersion.minor != 0; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/glad/glad.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/glad/glad.h new file mode 100644 index 00000000..ef965919 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/glad/glad.h @@ -0,0 +1,3520 @@ + +#ifndef __glad_h_ +#define __glad_h_ + +#ifdef __gl_h_ +#error OpenGL header already included, remove this include, glad already provides it +#endif +#define __gl_h_ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct gladGLversionStruct { + int major; + int minor; +}; + +extern struct gladGLversionStruct GLVersion; + +typedef void* (* GLADloadproc)(const char *name); + +#ifndef GLAPI +# if defined(GLAD_GLAPI_EXPORT) +# if defined(WIN32) || defined(__CYGWIN__) +# if defined(GLAD_GLAPI_EXPORT_BUILD) +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllexport)) extern +# else +# define GLAPI __declspec(dllexport) extern +# endif +# else +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllimport)) extern +# else +# define GLAPI __declspec(dllimport) extern +# endif +# endif +# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) +# define GLAPI __attribute__ ((visibility ("default"))) extern +# else +# define GLAPI extern +# endif +# else +# define GLAPI extern +# endif +#endif +GLAPI int gladLoadGLLoader(GLADloadproc); + +#include +#include +#ifndef GLEXT_64_TYPES_DEFINED +/* This code block is duplicated in glxext.h, so must be protected */ +#define GLEXT_64_TYPES_DEFINED +/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ +/* (as used in the GL_EXT_timer_query extension). */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(__sun__) || defined(__digital__) +#include +#if defined(__STDC__) +#if defined(__arch64__) || defined(_LP64) +typedef long int int64_t; +typedef unsigned long int uint64_t; +#else +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#endif /* __arch64__ */ +#endif /* __STDC__ */ +#elif defined( __VMS ) || defined(__sgi) +#include +#elif defined(__SCO__) || defined(__USLC__) +#include +#elif defined(__UNIXOS2__) || defined(__SOL64__) +typedef long int int32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif +#endif +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef signed char GLbyte; +typedef short GLshort; +typedef int GLint; +typedef int GLclampx; +typedef unsigned char GLubyte; +typedef unsigned short GLushort; +typedef unsigned int GLuint; +typedef int GLsizei; +typedef float GLfloat; +typedef float GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef unsigned short GLhalfARB; +typedef unsigned short GLhalf; +typedef GLint GLfixed; +typedef ptrdiff_t GLintptr; +typedef ptrdiff_t GLsizeiptr; +typedef int64_t GLint64; +typedef uint64_t GLuint64; +typedef ptrdiff_t GLintptrARB; +typedef ptrdiff_t GLsizeiptrARB; +typedef int64_t GLint64EXT; +typedef uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_QUADS 0x0007 +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_NONE 0 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_VIEWPORT 0x0BA2 +#define GL_DITHER 0x0BD0 +#define GL_BLEND_DST 0x0BE0 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND 0x0BE2 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_READ_BUFFER 0x0C02 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_STEREO 0x0C33 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_DOUBLE 0x140A +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_CLEAR 0x1500 +#define GL_AND 0x1501 +#define GL_AND_REVERSE 0x1502 +#define GL_COPY 0x1503 +#define GL_AND_INVERTED 0x1504 +#define GL_NOOP 0x1505 +#define GL_XOR 0x1506 +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_EQUIV 0x1509 +#define GL_INVERT 0x150A +#define GL_OR_REVERSE 0x150B +#define GL_COPY_INVERTED 0x150C +#define GL_OR_INVERTED 0x150D +#define GL_NAND 0x150E +#define GL_SET 0x150F +#define GL_TEXTURE 0x1702 +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_STENCIL_INDEX 0x1901 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_REPEAT 0x2901 +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_CURRENT_BIT 0x00000001 +#define GL_POINT_BIT 0x00000002 +#define GL_LINE_BIT 0x00000004 +#define GL_POLYGON_BIT 0x00000008 +#define GL_POLYGON_STIPPLE_BIT 0x00000010 +#define GL_PIXEL_MODE_BIT 0x00000020 +#define GL_LIGHTING_BIT 0x00000040 +#define GL_FOG_BIT 0x00000080 +#define GL_ACCUM_BUFFER_BIT 0x00000200 +#define GL_VIEWPORT_BIT 0x00000800 +#define GL_TRANSFORM_BIT 0x00001000 +#define GL_ENABLE_BIT 0x00002000 +#define GL_HINT_BIT 0x00008000 +#define GL_EVAL_BIT 0x00010000 +#define GL_LIST_BIT 0x00020000 +#define GL_TEXTURE_BIT 0x00040000 +#define GL_SCISSOR_BIT 0x00080000 +#define GL_ALL_ATTRIB_BITS 0xFFFFFFFF +#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 +#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 +#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF +#define GL_QUAD_STRIP 0x0008 +#define GL_POLYGON 0x0009 +#define GL_ACCUM 0x0100 +#define GL_LOAD 0x0101 +#define GL_RETURN 0x0102 +#define GL_MULT 0x0103 +#define GL_ADD 0x0104 +#define GL_AUX0 0x0409 +#define GL_AUX1 0x040A +#define GL_AUX2 0x040B +#define GL_AUX3 0x040C +#define GL_2D 0x0600 +#define GL_3D 0x0601 +#define GL_3D_COLOR 0x0602 +#define GL_3D_COLOR_TEXTURE 0x0603 +#define GL_4D_COLOR_TEXTURE 0x0604 +#define GL_PASS_THROUGH_TOKEN 0x0700 +#define GL_POINT_TOKEN 0x0701 +#define GL_LINE_TOKEN 0x0702 +#define GL_POLYGON_TOKEN 0x0703 +#define GL_BITMAP_TOKEN 0x0704 +#define GL_DRAW_PIXEL_TOKEN 0x0705 +#define GL_COPY_PIXEL_TOKEN 0x0706 +#define GL_LINE_RESET_TOKEN 0x0707 +#define GL_EXP 0x0800 +#define GL_EXP2 0x0801 +#define GL_COEFF 0x0A00 +#define GL_ORDER 0x0A01 +#define GL_DOMAIN 0x0A02 +#define GL_PIXEL_MAP_I_TO_I 0x0C70 +#define GL_PIXEL_MAP_S_TO_S 0x0C71 +#define GL_PIXEL_MAP_I_TO_R 0x0C72 +#define GL_PIXEL_MAP_I_TO_G 0x0C73 +#define GL_PIXEL_MAP_I_TO_B 0x0C74 +#define GL_PIXEL_MAP_I_TO_A 0x0C75 +#define GL_PIXEL_MAP_R_TO_R 0x0C76 +#define GL_PIXEL_MAP_G_TO_G 0x0C77 +#define GL_PIXEL_MAP_B_TO_B 0x0C78 +#define GL_PIXEL_MAP_A_TO_A 0x0C79 +#define GL_VERTEX_ARRAY_POINTER 0x808E +#define GL_NORMAL_ARRAY_POINTER 0x808F +#define GL_COLOR_ARRAY_POINTER 0x8090 +#define GL_INDEX_ARRAY_POINTER 0x8091 +#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 +#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093 +#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 +#define GL_SELECTION_BUFFER_POINTER 0x0DF3 +#define GL_CURRENT_COLOR 0x0B00 +#define GL_CURRENT_INDEX 0x0B01 +#define GL_CURRENT_NORMAL 0x0B02 +#define GL_CURRENT_TEXTURE_COORDS 0x0B03 +#define GL_CURRENT_RASTER_COLOR 0x0B04 +#define GL_CURRENT_RASTER_INDEX 0x0B05 +#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 +#define GL_CURRENT_RASTER_POSITION 0x0B07 +#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08 +#define GL_CURRENT_RASTER_DISTANCE 0x0B09 +#define GL_POINT_SMOOTH 0x0B10 +#define GL_LINE_STIPPLE 0x0B24 +#define GL_LINE_STIPPLE_PATTERN 0x0B25 +#define GL_LINE_STIPPLE_REPEAT 0x0B26 +#define GL_LIST_MODE 0x0B30 +#define GL_MAX_LIST_NESTING 0x0B31 +#define GL_LIST_BASE 0x0B32 +#define GL_LIST_INDEX 0x0B33 +#define GL_POLYGON_STIPPLE 0x0B42 +#define GL_EDGE_FLAG 0x0B43 +#define GL_LIGHTING 0x0B50 +#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 +#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 +#define GL_LIGHT_MODEL_AMBIENT 0x0B53 +#define GL_SHADE_MODEL 0x0B54 +#define GL_COLOR_MATERIAL_FACE 0x0B55 +#define GL_COLOR_MATERIAL_PARAMETER 0x0B56 +#define GL_COLOR_MATERIAL 0x0B57 +#define GL_FOG 0x0B60 +#define GL_FOG_INDEX 0x0B61 +#define GL_FOG_DENSITY 0x0B62 +#define GL_FOG_START 0x0B63 +#define GL_FOG_END 0x0B64 +#define GL_FOG_MODE 0x0B65 +#define GL_FOG_COLOR 0x0B66 +#define GL_ACCUM_CLEAR_VALUE 0x0B80 +#define GL_MATRIX_MODE 0x0BA0 +#define GL_NORMALIZE 0x0BA1 +#define GL_MODELVIEW_STACK_DEPTH 0x0BA3 +#define GL_PROJECTION_STACK_DEPTH 0x0BA4 +#define GL_TEXTURE_STACK_DEPTH 0x0BA5 +#define GL_MODELVIEW_MATRIX 0x0BA6 +#define GL_PROJECTION_MATRIX 0x0BA7 +#define GL_TEXTURE_MATRIX 0x0BA8 +#define GL_ATTRIB_STACK_DEPTH 0x0BB0 +#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 +#define GL_ALPHA_TEST 0x0BC0 +#define GL_ALPHA_TEST_FUNC 0x0BC1 +#define GL_ALPHA_TEST_REF 0x0BC2 +#define GL_INDEX_LOGIC_OP 0x0BF1 +#define GL_LOGIC_OP 0x0BF1 +#define GL_AUX_BUFFERS 0x0C00 +#define GL_INDEX_CLEAR_VALUE 0x0C20 +#define GL_INDEX_WRITEMASK 0x0C21 +#define GL_INDEX_MODE 0x0C30 +#define GL_RGBA_MODE 0x0C31 +#define GL_RENDER_MODE 0x0C40 +#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 +#define GL_POINT_SMOOTH_HINT 0x0C51 +#define GL_FOG_HINT 0x0C54 +#define GL_TEXTURE_GEN_S 0x0C60 +#define GL_TEXTURE_GEN_T 0x0C61 +#define GL_TEXTURE_GEN_R 0x0C62 +#define GL_TEXTURE_GEN_Q 0x0C63 +#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 +#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 +#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 +#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 +#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 +#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 +#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 +#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 +#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 +#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 +#define GL_MAP_COLOR 0x0D10 +#define GL_MAP_STENCIL 0x0D11 +#define GL_INDEX_SHIFT 0x0D12 +#define GL_INDEX_OFFSET 0x0D13 +#define GL_RED_SCALE 0x0D14 +#define GL_RED_BIAS 0x0D15 +#define GL_ZOOM_X 0x0D16 +#define GL_ZOOM_Y 0x0D17 +#define GL_GREEN_SCALE 0x0D18 +#define GL_GREEN_BIAS 0x0D19 +#define GL_BLUE_SCALE 0x0D1A +#define GL_BLUE_BIAS 0x0D1B +#define GL_ALPHA_SCALE 0x0D1C +#define GL_ALPHA_BIAS 0x0D1D +#define GL_DEPTH_SCALE 0x0D1E +#define GL_DEPTH_BIAS 0x0D1F +#define GL_MAX_EVAL_ORDER 0x0D30 +#define GL_MAX_LIGHTS 0x0D31 +#define GL_MAX_CLIP_PLANES 0x0D32 +#define GL_MAX_PIXEL_MAP_TABLE 0x0D34 +#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 +#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 +#define GL_MAX_NAME_STACK_DEPTH 0x0D37 +#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 +#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 +#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B +#define GL_INDEX_BITS 0x0D51 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_ALPHA_BITS 0x0D55 +#define GL_DEPTH_BITS 0x0D56 +#define GL_STENCIL_BITS 0x0D57 +#define GL_ACCUM_RED_BITS 0x0D58 +#define GL_ACCUM_GREEN_BITS 0x0D59 +#define GL_ACCUM_BLUE_BITS 0x0D5A +#define GL_ACCUM_ALPHA_BITS 0x0D5B +#define GL_NAME_STACK_DEPTH 0x0D70 +#define GL_AUTO_NORMAL 0x0D80 +#define GL_MAP1_COLOR_4 0x0D90 +#define GL_MAP1_INDEX 0x0D91 +#define GL_MAP1_NORMAL 0x0D92 +#define GL_MAP1_TEXTURE_COORD_1 0x0D93 +#define GL_MAP1_TEXTURE_COORD_2 0x0D94 +#define GL_MAP1_TEXTURE_COORD_3 0x0D95 +#define GL_MAP1_TEXTURE_COORD_4 0x0D96 +#define GL_MAP1_VERTEX_3 0x0D97 +#define GL_MAP1_VERTEX_4 0x0D98 +#define GL_MAP2_COLOR_4 0x0DB0 +#define GL_MAP2_INDEX 0x0DB1 +#define GL_MAP2_NORMAL 0x0DB2 +#define GL_MAP2_TEXTURE_COORD_1 0x0DB3 +#define GL_MAP2_TEXTURE_COORD_2 0x0DB4 +#define GL_MAP2_TEXTURE_COORD_3 0x0DB5 +#define GL_MAP2_TEXTURE_COORD_4 0x0DB6 +#define GL_MAP2_VERTEX_3 0x0DB7 +#define GL_MAP2_VERTEX_4 0x0DB8 +#define GL_MAP1_GRID_DOMAIN 0x0DD0 +#define GL_MAP1_GRID_SEGMENTS 0x0DD1 +#define GL_MAP2_GRID_DOMAIN 0x0DD2 +#define GL_MAP2_GRID_SEGMENTS 0x0DD3 +#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 +#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 +#define GL_SELECTION_BUFFER_SIZE 0x0DF4 +#define GL_VERTEX_ARRAY 0x8074 +#define GL_NORMAL_ARRAY 0x8075 +#define GL_COLOR_ARRAY 0x8076 +#define GL_INDEX_ARRAY 0x8077 +#define GL_TEXTURE_COORD_ARRAY 0x8078 +#define GL_EDGE_FLAG_ARRAY 0x8079 +#define GL_VERTEX_ARRAY_SIZE 0x807A +#define GL_VERTEX_ARRAY_TYPE 0x807B +#define GL_VERTEX_ARRAY_STRIDE 0x807C +#define GL_NORMAL_ARRAY_TYPE 0x807E +#define GL_NORMAL_ARRAY_STRIDE 0x807F +#define GL_COLOR_ARRAY_SIZE 0x8081 +#define GL_COLOR_ARRAY_TYPE 0x8082 +#define GL_COLOR_ARRAY_STRIDE 0x8083 +#define GL_INDEX_ARRAY_TYPE 0x8085 +#define GL_INDEX_ARRAY_STRIDE 0x8086 +#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 +#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 +#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A +#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C +#define GL_TEXTURE_COMPONENTS 0x1003 +#define GL_TEXTURE_BORDER 0x1005 +#define GL_TEXTURE_LUMINANCE_SIZE 0x8060 +#define GL_TEXTURE_INTENSITY_SIZE 0x8061 +#define GL_TEXTURE_PRIORITY 0x8066 +#define GL_TEXTURE_RESIDENT 0x8067 +#define GL_AMBIENT 0x1200 +#define GL_DIFFUSE 0x1201 +#define GL_SPECULAR 0x1202 +#define GL_POSITION 0x1203 +#define GL_SPOT_DIRECTION 0x1204 +#define GL_SPOT_EXPONENT 0x1205 +#define GL_SPOT_CUTOFF 0x1206 +#define GL_CONSTANT_ATTENUATION 0x1207 +#define GL_LINEAR_ATTENUATION 0x1208 +#define GL_QUADRATIC_ATTENUATION 0x1209 +#define GL_COMPILE 0x1300 +#define GL_COMPILE_AND_EXECUTE 0x1301 +#define GL_2_BYTES 0x1407 +#define GL_3_BYTES 0x1408 +#define GL_4_BYTES 0x1409 +#define GL_EMISSION 0x1600 +#define GL_SHININESS 0x1601 +#define GL_AMBIENT_AND_DIFFUSE 0x1602 +#define GL_COLOR_INDEXES 0x1603 +#define GL_MODELVIEW 0x1700 +#define GL_PROJECTION 0x1701 +#define GL_COLOR_INDEX 0x1900 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_BITMAP 0x1A00 +#define GL_RENDER 0x1C00 +#define GL_FEEDBACK 0x1C01 +#define GL_SELECT 0x1C02 +#define GL_FLAT 0x1D00 +#define GL_SMOOTH 0x1D01 +#define GL_S 0x2000 +#define GL_T 0x2001 +#define GL_R 0x2002 +#define GL_Q 0x2003 +#define GL_MODULATE 0x2100 +#define GL_DECAL 0x2101 +#define GL_TEXTURE_ENV_MODE 0x2200 +#define GL_TEXTURE_ENV_COLOR 0x2201 +#define GL_TEXTURE_ENV 0x2300 +#define GL_EYE_LINEAR 0x2400 +#define GL_OBJECT_LINEAR 0x2401 +#define GL_SPHERE_MAP 0x2402 +#define GL_TEXTURE_GEN_MODE 0x2500 +#define GL_OBJECT_PLANE 0x2501 +#define GL_EYE_PLANE 0x2502 +#define GL_CLAMP 0x2900 +#define GL_ALPHA4 0x803B +#define GL_ALPHA8 0x803C +#define GL_ALPHA12 0x803D +#define GL_ALPHA16 0x803E +#define GL_LUMINANCE4 0x803F +#define GL_LUMINANCE8 0x8040 +#define GL_LUMINANCE12 0x8041 +#define GL_LUMINANCE16 0x8042 +#define GL_LUMINANCE4_ALPHA4 0x8043 +#define GL_LUMINANCE6_ALPHA2 0x8044 +#define GL_LUMINANCE8_ALPHA8 0x8045 +#define GL_LUMINANCE12_ALPHA4 0x8046 +#define GL_LUMINANCE12_ALPHA12 0x8047 +#define GL_LUMINANCE16_ALPHA16 0x8048 +#define GL_INTENSITY 0x8049 +#define GL_INTENSITY4 0x804A +#define GL_INTENSITY8 0x804B +#define GL_INTENSITY12 0x804C +#define GL_INTENSITY16 0x804D +#define GL_V2F 0x2A20 +#define GL_V3F 0x2A21 +#define GL_C4UB_V2F 0x2A22 +#define GL_C4UB_V3F 0x2A23 +#define GL_C3F_V3F 0x2A24 +#define GL_N3F_V3F 0x2A25 +#define GL_C4F_N3F_V3F 0x2A26 +#define GL_T2F_V3F 0x2A27 +#define GL_T4F_V4F 0x2A28 +#define GL_T2F_C4UB_V3F 0x2A29 +#define GL_T2F_C3F_V3F 0x2A2A +#define GL_T2F_N3F_V3F 0x2A2B +#define GL_T2F_C4F_N3F_V3F 0x2A2C +#define GL_T4F_C4F_N3F_V4F 0x2A2D +#define GL_CLIP_PLANE0 0x3000 +#define GL_CLIP_PLANE1 0x3001 +#define GL_CLIP_PLANE2 0x3002 +#define GL_CLIP_PLANE3 0x3003 +#define GL_CLIP_PLANE4 0x3004 +#define GL_CLIP_PLANE5 0x3005 +#define GL_LIGHT0 0x4000 +#define GL_LIGHT1 0x4001 +#define GL_LIGHT2 0x4002 +#define GL_LIGHT3 0x4003 +#define GL_LIGHT4 0x4004 +#define GL_LIGHT5 0x4005 +#define GL_LIGHT6 0x4006 +#define GL_LIGHT7 0x4007 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_RESCALE_NORMAL 0x803A +#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 +#define GL_SINGLE_COLOR 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR 0x81FA +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 +#define GL_MAX_TEXTURE_UNITS 0x84E2 +#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 +#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 +#define GL_MULTISAMPLE_BIT 0x20000000 +#define GL_NORMAL_MAP 0x8511 +#define GL_REFLECTION_MAP 0x8512 +#define GL_COMPRESSED_ALPHA 0x84E9 +#define GL_COMPRESSED_LUMINANCE 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB +#define GL_COMPRESSED_INTENSITY 0x84EC +#define GL_COMBINE 0x8570 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_SOURCE0_RGB 0x8580 +#define GL_SOURCE1_RGB 0x8581 +#define GL_SOURCE2_RGB 0x8582 +#define GL_SOURCE0_ALPHA 0x8588 +#define GL_SOURCE1_ALPHA 0x8589 +#define GL_SOURCE2_ALPHA 0x858A +#define GL_OPERAND0_RGB 0x8590 +#define GL_OPERAND1_RGB 0x8591 +#define GL_OPERAND2_RGB 0x8592 +#define GL_OPERAND0_ALPHA 0x8598 +#define GL_OPERAND1_ALPHA 0x8599 +#define GL_OPERAND2_ALPHA 0x859A +#define GL_RGB_SCALE 0x8573 +#define GL_ADD_SIGNED 0x8574 +#define GL_INTERPOLATE 0x8575 +#define GL_SUBTRACT 0x84E7 +#define GL_CONSTANT 0x8576 +#define GL_PRIMARY_COLOR 0x8577 +#define GL_PREVIOUS 0x8578 +#define GL_DOT3_RGB 0x86AE +#define GL_DOT3_RGBA 0x86AF +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_POINT_SIZE_MIN 0x8126 +#define GL_POINT_SIZE_MAX 0x8127 +#define GL_POINT_DISTANCE_ATTENUATION 0x8129 +#define GL_GENERATE_MIPMAP 0x8191 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_FOG_COORDINATE_SOURCE 0x8450 +#define GL_FOG_COORDINATE 0x8451 +#define GL_FRAGMENT_DEPTH 0x8452 +#define GL_CURRENT_FOG_COORDINATE 0x8453 +#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 +#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 +#define GL_FOG_COORDINATE_ARRAY 0x8457 +#define GL_COLOR_SUM 0x8458 +#define GL_CURRENT_SECONDARY_COLOR 0x8459 +#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A +#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B +#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C +#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D +#define GL_SECONDARY_COLOR_ARRAY 0x845E +#define GL_TEXTURE_FILTER_CONTROL 0x8500 +#define GL_DEPTH_TEXTURE_MODE 0x884B +#define GL_COMPARE_R_TO_TEXTURE 0x884E +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E +#define GL_FOG_COORD_SRC 0x8450 +#define GL_FOG_COORD 0x8451 +#define GL_CURRENT_FOG_COORD 0x8453 +#define GL_FOG_COORD_ARRAY_TYPE 0x8454 +#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORD_ARRAY_POINTER 0x8456 +#define GL_FOG_COORD_ARRAY 0x8457 +#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D +#define GL_SRC0_RGB 0x8580 +#define GL_SRC1_RGB 0x8581 +#define GL_SRC2_RGB 0x8582 +#define GL_SRC0_ALPHA 0x8588 +#define GL_SRC2_ALPHA 0x858A +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define GL_POINT_SPRITE 0x8861 +#define GL_COORD_REPLACE 0x8862 +#define GL_MAX_TEXTURE_COORDS 0x8871 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F +#define GL_SLUMINANCE_ALPHA 0x8C44 +#define GL_SLUMINANCE8_ALPHA8 0x8C45 +#define GL_SLUMINANCE 0x8C46 +#define GL_SLUMINANCE8 0x8C47 +#define GL_COMPRESSED_SLUMINANCE 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_COLOR_ATTACHMENT16 0x8CF0 +#define GL_COLOR_ATTACHMENT17 0x8CF1 +#define GL_COLOR_ATTACHMENT18 0x8CF2 +#define GL_COLOR_ATTACHMENT19 0x8CF3 +#define GL_COLOR_ATTACHMENT20 0x8CF4 +#define GL_COLOR_ATTACHMENT21 0x8CF5 +#define GL_COLOR_ATTACHMENT22 0x8CF6 +#define GL_COLOR_ATTACHMENT23 0x8CF7 +#define GL_COLOR_ATTACHMENT24 0x8CF8 +#define GL_COLOR_ATTACHMENT25 0x8CF9 +#define GL_COLOR_ATTACHMENT26 0x8CFA +#define GL_COLOR_ATTACHMENT27 0x8CFB +#define GL_COLOR_ATTACHMENT28 0x8CFC +#define GL_COLOR_ATTACHMENT29 0x8CFD +#define GL_COLOR_ATTACHMENT30 0x8CFE +#define GL_COLOR_ATTACHMENT31 0x8CFF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_INDEX 0x8222 +#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 +#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_HALF_FLOAT 0x140B +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#define GL_CLAMP_VERTEX_COLOR 0x891A +#define GL_CLAMP_FRAGMENT_COLOR 0x891B +#define GL_ALPHA_INTEGER 0x8D97 +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_INVALID_INDEX 0xFFFFFFFF +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_DEPTH_CLAMP 0x864F +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 +#ifndef GL_VERSION_1_0 +#define GL_VERSION_1_0 1 +GLAPI int GLAD_GL_VERSION_1_0; +typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode); +GLAPI PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode); +GLAPI PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode); +GLAPI PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width); +GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size); +GLAPI PFNGLPOINTSIZEPROC glad_glPointSize; +#define glPointSize glad_glPointSize +typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); +GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode; +#define glPolygonMode glad_glPolygonMode +typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat* params); +GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint* params); +GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void* pixels); +GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D; +#define glTexImage1D glad_glTexImage1D +typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels); +GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf); +GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer; +#define glDrawBuffer glad_glDrawBuffer +typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask); +GLAPI PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s); +GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth); +GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth; +#define glClearDepth glad_glClearDepth +typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask); +GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GLAPI PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag); +GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap); +GLAPI PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap); +GLAPI PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +typedef void (APIENTRYP PFNGLFINISHPROC)(); +GLAPI PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +typedef void (APIENTRYP PFNGLFLUSHPROC)(); +GLAPI PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode); +GLAPI PFNGLLOGICOPPROC glad_glLogicOp; +#define glLogicOp glad_glLogicOp +typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +GLAPI PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func); +GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref; +#define glPixelStoref glad_glPixelStoref +typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src); +GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer; +#define glReadBuffer glad_glReadBuffer +typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); +GLAPI PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean* data); +GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble* data); +GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev; +#define glGetDoublev glad_glGetDoublev +typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(); +GLAPI PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat* data); +GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint* data); +GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +typedef const GLubyte* (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name); +GLAPI PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void* pixels); +GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage; +#define glGetTexImage glad_glGetTexImage +typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat* params); +GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat* params); +GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; +#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint* params); +GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; +#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv +typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap); +GLAPI PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble near, GLdouble far); +GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange; +#define glDepthRange glad_glDepthRange +typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport +typedef void (APIENTRYP PFNGLNEWLISTPROC)(GLuint list, GLenum mode); +GLAPI PFNGLNEWLISTPROC glad_glNewList; +#define glNewList glad_glNewList +typedef void (APIENTRYP PFNGLENDLISTPROC)(); +GLAPI PFNGLENDLISTPROC glad_glEndList; +#define glEndList glad_glEndList +typedef void (APIENTRYP PFNGLCALLLISTPROC)(GLuint list); +GLAPI PFNGLCALLLISTPROC glad_glCallList; +#define glCallList glad_glCallList +typedef void (APIENTRYP PFNGLCALLLISTSPROC)(GLsizei n, GLenum type, const void* lists); +GLAPI PFNGLCALLLISTSPROC glad_glCallLists; +#define glCallLists glad_glCallLists +typedef void (APIENTRYP PFNGLDELETELISTSPROC)(GLuint list, GLsizei range); +GLAPI PFNGLDELETELISTSPROC glad_glDeleteLists; +#define glDeleteLists glad_glDeleteLists +typedef GLuint (APIENTRYP PFNGLGENLISTSPROC)(GLsizei range); +GLAPI PFNGLGENLISTSPROC glad_glGenLists; +#define glGenLists glad_glGenLists +typedef void (APIENTRYP PFNGLLISTBASEPROC)(GLuint base); +GLAPI PFNGLLISTBASEPROC glad_glListBase; +#define glListBase glad_glListBase +typedef void (APIENTRYP PFNGLBEGINPROC)(GLenum mode); +GLAPI PFNGLBEGINPROC glad_glBegin; +#define glBegin glad_glBegin +typedef void (APIENTRYP PFNGLBITMAPPROC)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte* bitmap); +GLAPI PFNGLBITMAPPROC glad_glBitmap; +#define glBitmap glad_glBitmap +typedef void (APIENTRYP PFNGLCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); +GLAPI PFNGLCOLOR3BPROC glad_glColor3b; +#define glColor3b glad_glColor3b +typedef void (APIENTRYP PFNGLCOLOR3BVPROC)(const GLbyte* v); +GLAPI PFNGLCOLOR3BVPROC glad_glColor3bv; +#define glColor3bv glad_glColor3bv +typedef void (APIENTRYP PFNGLCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); +GLAPI PFNGLCOLOR3DPROC glad_glColor3d; +#define glColor3d glad_glColor3d +typedef void (APIENTRYP PFNGLCOLOR3DVPROC)(const GLdouble* v); +GLAPI PFNGLCOLOR3DVPROC glad_glColor3dv; +#define glColor3dv glad_glColor3dv +typedef void (APIENTRYP PFNGLCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); +GLAPI PFNGLCOLOR3FPROC glad_glColor3f; +#define glColor3f glad_glColor3f +typedef void (APIENTRYP PFNGLCOLOR3FVPROC)(const GLfloat* v); +GLAPI PFNGLCOLOR3FVPROC glad_glColor3fv; +#define glColor3fv glad_glColor3fv +typedef void (APIENTRYP PFNGLCOLOR3IPROC)(GLint red, GLint green, GLint blue); +GLAPI PFNGLCOLOR3IPROC glad_glColor3i; +#define glColor3i glad_glColor3i +typedef void (APIENTRYP PFNGLCOLOR3IVPROC)(const GLint* v); +GLAPI PFNGLCOLOR3IVPROC glad_glColor3iv; +#define glColor3iv glad_glColor3iv +typedef void (APIENTRYP PFNGLCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); +GLAPI PFNGLCOLOR3SPROC glad_glColor3s; +#define glColor3s glad_glColor3s +typedef void (APIENTRYP PFNGLCOLOR3SVPROC)(const GLshort* v); +GLAPI PFNGLCOLOR3SVPROC glad_glColor3sv; +#define glColor3sv glad_glColor3sv +typedef void (APIENTRYP PFNGLCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); +GLAPI PFNGLCOLOR3UBPROC glad_glColor3ub; +#define glColor3ub glad_glColor3ub +typedef void (APIENTRYP PFNGLCOLOR3UBVPROC)(const GLubyte* v); +GLAPI PFNGLCOLOR3UBVPROC glad_glColor3ubv; +#define glColor3ubv glad_glColor3ubv +typedef void (APIENTRYP PFNGLCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); +GLAPI PFNGLCOLOR3UIPROC glad_glColor3ui; +#define glColor3ui glad_glColor3ui +typedef void (APIENTRYP PFNGLCOLOR3UIVPROC)(const GLuint* v); +GLAPI PFNGLCOLOR3UIVPROC glad_glColor3uiv; +#define glColor3uiv glad_glColor3uiv +typedef void (APIENTRYP PFNGLCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); +GLAPI PFNGLCOLOR3USPROC glad_glColor3us; +#define glColor3us glad_glColor3us +typedef void (APIENTRYP PFNGLCOLOR3USVPROC)(const GLushort* v); +GLAPI PFNGLCOLOR3USVPROC glad_glColor3usv; +#define glColor3usv glad_glColor3usv +typedef void (APIENTRYP PFNGLCOLOR4BPROC)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +GLAPI PFNGLCOLOR4BPROC glad_glColor4b; +#define glColor4b glad_glColor4b +typedef void (APIENTRYP PFNGLCOLOR4BVPROC)(const GLbyte* v); +GLAPI PFNGLCOLOR4BVPROC glad_glColor4bv; +#define glColor4bv glad_glColor4bv +typedef void (APIENTRYP PFNGLCOLOR4DPROC)(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +GLAPI PFNGLCOLOR4DPROC glad_glColor4d; +#define glColor4d glad_glColor4d +typedef void (APIENTRYP PFNGLCOLOR4DVPROC)(const GLdouble* v); +GLAPI PFNGLCOLOR4DVPROC glad_glColor4dv; +#define glColor4dv glad_glColor4dv +typedef void (APIENTRYP PFNGLCOLOR4FPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCOLOR4FPROC glad_glColor4f; +#define glColor4f glad_glColor4f +typedef void (APIENTRYP PFNGLCOLOR4FVPROC)(const GLfloat* v); +GLAPI PFNGLCOLOR4FVPROC glad_glColor4fv; +#define glColor4fv glad_glColor4fv +typedef void (APIENTRYP PFNGLCOLOR4IPROC)(GLint red, GLint green, GLint blue, GLint alpha); +GLAPI PFNGLCOLOR4IPROC glad_glColor4i; +#define glColor4i glad_glColor4i +typedef void (APIENTRYP PFNGLCOLOR4IVPROC)(const GLint* v); +GLAPI PFNGLCOLOR4IVPROC glad_glColor4iv; +#define glColor4iv glad_glColor4iv +typedef void (APIENTRYP PFNGLCOLOR4SPROC)(GLshort red, GLshort green, GLshort blue, GLshort alpha); +GLAPI PFNGLCOLOR4SPROC glad_glColor4s; +#define glColor4s glad_glColor4s +typedef void (APIENTRYP PFNGLCOLOR4SVPROC)(const GLshort* v); +GLAPI PFNGLCOLOR4SVPROC glad_glColor4sv; +#define glColor4sv glad_glColor4sv +typedef void (APIENTRYP PFNGLCOLOR4UBPROC)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +GLAPI PFNGLCOLOR4UBPROC glad_glColor4ub; +#define glColor4ub glad_glColor4ub +typedef void (APIENTRYP PFNGLCOLOR4UBVPROC)(const GLubyte* v); +GLAPI PFNGLCOLOR4UBVPROC glad_glColor4ubv; +#define glColor4ubv glad_glColor4ubv +typedef void (APIENTRYP PFNGLCOLOR4UIPROC)(GLuint red, GLuint green, GLuint blue, GLuint alpha); +GLAPI PFNGLCOLOR4UIPROC glad_glColor4ui; +#define glColor4ui glad_glColor4ui +typedef void (APIENTRYP PFNGLCOLOR4UIVPROC)(const GLuint* v); +GLAPI PFNGLCOLOR4UIVPROC glad_glColor4uiv; +#define glColor4uiv glad_glColor4uiv +typedef void (APIENTRYP PFNGLCOLOR4USPROC)(GLushort red, GLushort green, GLushort blue, GLushort alpha); +GLAPI PFNGLCOLOR4USPROC glad_glColor4us; +#define glColor4us glad_glColor4us +typedef void (APIENTRYP PFNGLCOLOR4USVPROC)(const GLushort* v); +GLAPI PFNGLCOLOR4USVPROC glad_glColor4usv; +#define glColor4usv glad_glColor4usv +typedef void (APIENTRYP PFNGLEDGEFLAGPROC)(GLboolean flag); +GLAPI PFNGLEDGEFLAGPROC glad_glEdgeFlag; +#define glEdgeFlag glad_glEdgeFlag +typedef void (APIENTRYP PFNGLEDGEFLAGVPROC)(const GLboolean* flag); +GLAPI PFNGLEDGEFLAGVPROC glad_glEdgeFlagv; +#define glEdgeFlagv glad_glEdgeFlagv +typedef void (APIENTRYP PFNGLENDPROC)(); +GLAPI PFNGLENDPROC glad_glEnd; +#define glEnd glad_glEnd +typedef void (APIENTRYP PFNGLINDEXDPROC)(GLdouble c); +GLAPI PFNGLINDEXDPROC glad_glIndexd; +#define glIndexd glad_glIndexd +typedef void (APIENTRYP PFNGLINDEXDVPROC)(const GLdouble* c); +GLAPI PFNGLINDEXDVPROC glad_glIndexdv; +#define glIndexdv glad_glIndexdv +typedef void (APIENTRYP PFNGLINDEXFPROC)(GLfloat c); +GLAPI PFNGLINDEXFPROC glad_glIndexf; +#define glIndexf glad_glIndexf +typedef void (APIENTRYP PFNGLINDEXFVPROC)(const GLfloat* c); +GLAPI PFNGLINDEXFVPROC glad_glIndexfv; +#define glIndexfv glad_glIndexfv +typedef void (APIENTRYP PFNGLINDEXIPROC)(GLint c); +GLAPI PFNGLINDEXIPROC glad_glIndexi; +#define glIndexi glad_glIndexi +typedef void (APIENTRYP PFNGLINDEXIVPROC)(const GLint* c); +GLAPI PFNGLINDEXIVPROC glad_glIndexiv; +#define glIndexiv glad_glIndexiv +typedef void (APIENTRYP PFNGLINDEXSPROC)(GLshort c); +GLAPI PFNGLINDEXSPROC glad_glIndexs; +#define glIndexs glad_glIndexs +typedef void (APIENTRYP PFNGLINDEXSVPROC)(const GLshort* c); +GLAPI PFNGLINDEXSVPROC glad_glIndexsv; +#define glIndexsv glad_glIndexsv +typedef void (APIENTRYP PFNGLNORMAL3BPROC)(GLbyte nx, GLbyte ny, GLbyte nz); +GLAPI PFNGLNORMAL3BPROC glad_glNormal3b; +#define glNormal3b glad_glNormal3b +typedef void (APIENTRYP PFNGLNORMAL3BVPROC)(const GLbyte* v); +GLAPI PFNGLNORMAL3BVPROC glad_glNormal3bv; +#define glNormal3bv glad_glNormal3bv +typedef void (APIENTRYP PFNGLNORMAL3DPROC)(GLdouble nx, GLdouble ny, GLdouble nz); +GLAPI PFNGLNORMAL3DPROC glad_glNormal3d; +#define glNormal3d glad_glNormal3d +typedef void (APIENTRYP PFNGLNORMAL3DVPROC)(const GLdouble* v); +GLAPI PFNGLNORMAL3DVPROC glad_glNormal3dv; +#define glNormal3dv glad_glNormal3dv +typedef void (APIENTRYP PFNGLNORMAL3FPROC)(GLfloat nx, GLfloat ny, GLfloat nz); +GLAPI PFNGLNORMAL3FPROC glad_glNormal3f; +#define glNormal3f glad_glNormal3f +typedef void (APIENTRYP PFNGLNORMAL3FVPROC)(const GLfloat* v); +GLAPI PFNGLNORMAL3FVPROC glad_glNormal3fv; +#define glNormal3fv glad_glNormal3fv +typedef void (APIENTRYP PFNGLNORMAL3IPROC)(GLint nx, GLint ny, GLint nz); +GLAPI PFNGLNORMAL3IPROC glad_glNormal3i; +#define glNormal3i glad_glNormal3i +typedef void (APIENTRYP PFNGLNORMAL3IVPROC)(const GLint* v); +GLAPI PFNGLNORMAL3IVPROC glad_glNormal3iv; +#define glNormal3iv glad_glNormal3iv +typedef void (APIENTRYP PFNGLNORMAL3SPROC)(GLshort nx, GLshort ny, GLshort nz); +GLAPI PFNGLNORMAL3SPROC glad_glNormal3s; +#define glNormal3s glad_glNormal3s +typedef void (APIENTRYP PFNGLNORMAL3SVPROC)(const GLshort* v); +GLAPI PFNGLNORMAL3SVPROC glad_glNormal3sv; +#define glNormal3sv glad_glNormal3sv +typedef void (APIENTRYP PFNGLRASTERPOS2DPROC)(GLdouble x, GLdouble y); +GLAPI PFNGLRASTERPOS2DPROC glad_glRasterPos2d; +#define glRasterPos2d glad_glRasterPos2d +typedef void (APIENTRYP PFNGLRASTERPOS2DVPROC)(const GLdouble* v); +GLAPI PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv; +#define glRasterPos2dv glad_glRasterPos2dv +typedef void (APIENTRYP PFNGLRASTERPOS2FPROC)(GLfloat x, GLfloat y); +GLAPI PFNGLRASTERPOS2FPROC glad_glRasterPos2f; +#define glRasterPos2f glad_glRasterPos2f +typedef void (APIENTRYP PFNGLRASTERPOS2FVPROC)(const GLfloat* v); +GLAPI PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv; +#define glRasterPos2fv glad_glRasterPos2fv +typedef void (APIENTRYP PFNGLRASTERPOS2IPROC)(GLint x, GLint y); +GLAPI PFNGLRASTERPOS2IPROC glad_glRasterPos2i; +#define glRasterPos2i glad_glRasterPos2i +typedef void (APIENTRYP PFNGLRASTERPOS2IVPROC)(const GLint* v); +GLAPI PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv; +#define glRasterPos2iv glad_glRasterPos2iv +typedef void (APIENTRYP PFNGLRASTERPOS2SPROC)(GLshort x, GLshort y); +GLAPI PFNGLRASTERPOS2SPROC glad_glRasterPos2s; +#define glRasterPos2s glad_glRasterPos2s +typedef void (APIENTRYP PFNGLRASTERPOS2SVPROC)(const GLshort* v); +GLAPI PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv; +#define glRasterPos2sv glad_glRasterPos2sv +typedef void (APIENTRYP PFNGLRASTERPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLRASTERPOS3DPROC glad_glRasterPos3d; +#define glRasterPos3d glad_glRasterPos3d +typedef void (APIENTRYP PFNGLRASTERPOS3DVPROC)(const GLdouble* v); +GLAPI PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv; +#define glRasterPos3dv glad_glRasterPos3dv +typedef void (APIENTRYP PFNGLRASTERPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLRASTERPOS3FPROC glad_glRasterPos3f; +#define glRasterPos3f glad_glRasterPos3f +typedef void (APIENTRYP PFNGLRASTERPOS3FVPROC)(const GLfloat* v); +GLAPI PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv; +#define glRasterPos3fv glad_glRasterPos3fv +typedef void (APIENTRYP PFNGLRASTERPOS3IPROC)(GLint x, GLint y, GLint z); +GLAPI PFNGLRASTERPOS3IPROC glad_glRasterPos3i; +#define glRasterPos3i glad_glRasterPos3i +typedef void (APIENTRYP PFNGLRASTERPOS3IVPROC)(const GLint* v); +GLAPI PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv; +#define glRasterPos3iv glad_glRasterPos3iv +typedef void (APIENTRYP PFNGLRASTERPOS3SPROC)(GLshort x, GLshort y, GLshort z); +GLAPI PFNGLRASTERPOS3SPROC glad_glRasterPos3s; +#define glRasterPos3s glad_glRasterPos3s +typedef void (APIENTRYP PFNGLRASTERPOS3SVPROC)(const GLshort* v); +GLAPI PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv; +#define glRasterPos3sv glad_glRasterPos3sv +typedef void (APIENTRYP PFNGLRASTERPOS4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLRASTERPOS4DPROC glad_glRasterPos4d; +#define glRasterPos4d glad_glRasterPos4d +typedef void (APIENTRYP PFNGLRASTERPOS4DVPROC)(const GLdouble* v); +GLAPI PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv; +#define glRasterPos4dv glad_glRasterPos4dv +typedef void (APIENTRYP PFNGLRASTERPOS4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLRASTERPOS4FPROC glad_glRasterPos4f; +#define glRasterPos4f glad_glRasterPos4f +typedef void (APIENTRYP PFNGLRASTERPOS4FVPROC)(const GLfloat* v); +GLAPI PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv; +#define glRasterPos4fv glad_glRasterPos4fv +typedef void (APIENTRYP PFNGLRASTERPOS4IPROC)(GLint x, GLint y, GLint z, GLint w); +GLAPI PFNGLRASTERPOS4IPROC glad_glRasterPos4i; +#define glRasterPos4i glad_glRasterPos4i +typedef void (APIENTRYP PFNGLRASTERPOS4IVPROC)(const GLint* v); +GLAPI PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv; +#define glRasterPos4iv glad_glRasterPos4iv +typedef void (APIENTRYP PFNGLRASTERPOS4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI PFNGLRASTERPOS4SPROC glad_glRasterPos4s; +#define glRasterPos4s glad_glRasterPos4s +typedef void (APIENTRYP PFNGLRASTERPOS4SVPROC)(const GLshort* v); +GLAPI PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv; +#define glRasterPos4sv glad_glRasterPos4sv +typedef void (APIENTRYP PFNGLRECTDPROC)(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +GLAPI PFNGLRECTDPROC glad_glRectd; +#define glRectd glad_glRectd +typedef void (APIENTRYP PFNGLRECTDVPROC)(const GLdouble* v1, const GLdouble* v2); +GLAPI PFNGLRECTDVPROC glad_glRectdv; +#define glRectdv glad_glRectdv +typedef void (APIENTRYP PFNGLRECTFPROC)(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +GLAPI PFNGLRECTFPROC glad_glRectf; +#define glRectf glad_glRectf +typedef void (APIENTRYP PFNGLRECTFVPROC)(const GLfloat* v1, const GLfloat* v2); +GLAPI PFNGLRECTFVPROC glad_glRectfv; +#define glRectfv glad_glRectfv +typedef void (APIENTRYP PFNGLRECTIPROC)(GLint x1, GLint y1, GLint x2, GLint y2); +GLAPI PFNGLRECTIPROC glad_glRecti; +#define glRecti glad_glRecti +typedef void (APIENTRYP PFNGLRECTIVPROC)(const GLint* v1, const GLint* v2); +GLAPI PFNGLRECTIVPROC glad_glRectiv; +#define glRectiv glad_glRectiv +typedef void (APIENTRYP PFNGLRECTSPROC)(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +GLAPI PFNGLRECTSPROC glad_glRects; +#define glRects glad_glRects +typedef void (APIENTRYP PFNGLRECTSVPROC)(const GLshort* v1, const GLshort* v2); +GLAPI PFNGLRECTSVPROC glad_glRectsv; +#define glRectsv glad_glRectsv +typedef void (APIENTRYP PFNGLTEXCOORD1DPROC)(GLdouble s); +GLAPI PFNGLTEXCOORD1DPROC glad_glTexCoord1d; +#define glTexCoord1d glad_glTexCoord1d +typedef void (APIENTRYP PFNGLTEXCOORD1DVPROC)(const GLdouble* v); +GLAPI PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv; +#define glTexCoord1dv glad_glTexCoord1dv +typedef void (APIENTRYP PFNGLTEXCOORD1FPROC)(GLfloat s); +GLAPI PFNGLTEXCOORD1FPROC glad_glTexCoord1f; +#define glTexCoord1f glad_glTexCoord1f +typedef void (APIENTRYP PFNGLTEXCOORD1FVPROC)(const GLfloat* v); +GLAPI PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv; +#define glTexCoord1fv glad_glTexCoord1fv +typedef void (APIENTRYP PFNGLTEXCOORD1IPROC)(GLint s); +GLAPI PFNGLTEXCOORD1IPROC glad_glTexCoord1i; +#define glTexCoord1i glad_glTexCoord1i +typedef void (APIENTRYP PFNGLTEXCOORD1IVPROC)(const GLint* v); +GLAPI PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv; +#define glTexCoord1iv glad_glTexCoord1iv +typedef void (APIENTRYP PFNGLTEXCOORD1SPROC)(GLshort s); +GLAPI PFNGLTEXCOORD1SPROC glad_glTexCoord1s; +#define glTexCoord1s glad_glTexCoord1s +typedef void (APIENTRYP PFNGLTEXCOORD1SVPROC)(const GLshort* v); +GLAPI PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv; +#define glTexCoord1sv glad_glTexCoord1sv +typedef void (APIENTRYP PFNGLTEXCOORD2DPROC)(GLdouble s, GLdouble t); +GLAPI PFNGLTEXCOORD2DPROC glad_glTexCoord2d; +#define glTexCoord2d glad_glTexCoord2d +typedef void (APIENTRYP PFNGLTEXCOORD2DVPROC)(const GLdouble* v); +GLAPI PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv; +#define glTexCoord2dv glad_glTexCoord2dv +typedef void (APIENTRYP PFNGLTEXCOORD2FPROC)(GLfloat s, GLfloat t); +GLAPI PFNGLTEXCOORD2FPROC glad_glTexCoord2f; +#define glTexCoord2f glad_glTexCoord2f +typedef void (APIENTRYP PFNGLTEXCOORD2FVPROC)(const GLfloat* v); +GLAPI PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv; +#define glTexCoord2fv glad_glTexCoord2fv +typedef void (APIENTRYP PFNGLTEXCOORD2IPROC)(GLint s, GLint t); +GLAPI PFNGLTEXCOORD2IPROC glad_glTexCoord2i; +#define glTexCoord2i glad_glTexCoord2i +typedef void (APIENTRYP PFNGLTEXCOORD2IVPROC)(const GLint* v); +GLAPI PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv; +#define glTexCoord2iv glad_glTexCoord2iv +typedef void (APIENTRYP PFNGLTEXCOORD2SPROC)(GLshort s, GLshort t); +GLAPI PFNGLTEXCOORD2SPROC glad_glTexCoord2s; +#define glTexCoord2s glad_glTexCoord2s +typedef void (APIENTRYP PFNGLTEXCOORD2SVPROC)(const GLshort* v); +GLAPI PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv; +#define glTexCoord2sv glad_glTexCoord2sv +typedef void (APIENTRYP PFNGLTEXCOORD3DPROC)(GLdouble s, GLdouble t, GLdouble r); +GLAPI PFNGLTEXCOORD3DPROC glad_glTexCoord3d; +#define glTexCoord3d glad_glTexCoord3d +typedef void (APIENTRYP PFNGLTEXCOORD3DVPROC)(const GLdouble* v); +GLAPI PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv; +#define glTexCoord3dv glad_glTexCoord3dv +typedef void (APIENTRYP PFNGLTEXCOORD3FPROC)(GLfloat s, GLfloat t, GLfloat r); +GLAPI PFNGLTEXCOORD3FPROC glad_glTexCoord3f; +#define glTexCoord3f glad_glTexCoord3f +typedef void (APIENTRYP PFNGLTEXCOORD3FVPROC)(const GLfloat* v); +GLAPI PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv; +#define glTexCoord3fv glad_glTexCoord3fv +typedef void (APIENTRYP PFNGLTEXCOORD3IPROC)(GLint s, GLint t, GLint r); +GLAPI PFNGLTEXCOORD3IPROC glad_glTexCoord3i; +#define glTexCoord3i glad_glTexCoord3i +typedef void (APIENTRYP PFNGLTEXCOORD3IVPROC)(const GLint* v); +GLAPI PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv; +#define glTexCoord3iv glad_glTexCoord3iv +typedef void (APIENTRYP PFNGLTEXCOORD3SPROC)(GLshort s, GLshort t, GLshort r); +GLAPI PFNGLTEXCOORD3SPROC glad_glTexCoord3s; +#define glTexCoord3s glad_glTexCoord3s +typedef void (APIENTRYP PFNGLTEXCOORD3SVPROC)(const GLshort* v); +GLAPI PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv; +#define glTexCoord3sv glad_glTexCoord3sv +typedef void (APIENTRYP PFNGLTEXCOORD4DPROC)(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +GLAPI PFNGLTEXCOORD4DPROC glad_glTexCoord4d; +#define glTexCoord4d glad_glTexCoord4d +typedef void (APIENTRYP PFNGLTEXCOORD4DVPROC)(const GLdouble* v); +GLAPI PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv; +#define glTexCoord4dv glad_glTexCoord4dv +typedef void (APIENTRYP PFNGLTEXCOORD4FPROC)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +GLAPI PFNGLTEXCOORD4FPROC glad_glTexCoord4f; +#define glTexCoord4f glad_glTexCoord4f +typedef void (APIENTRYP PFNGLTEXCOORD4FVPROC)(const GLfloat* v); +GLAPI PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv; +#define glTexCoord4fv glad_glTexCoord4fv +typedef void (APIENTRYP PFNGLTEXCOORD4IPROC)(GLint s, GLint t, GLint r, GLint q); +GLAPI PFNGLTEXCOORD4IPROC glad_glTexCoord4i; +#define glTexCoord4i glad_glTexCoord4i +typedef void (APIENTRYP PFNGLTEXCOORD4IVPROC)(const GLint* v); +GLAPI PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv; +#define glTexCoord4iv glad_glTexCoord4iv +typedef void (APIENTRYP PFNGLTEXCOORD4SPROC)(GLshort s, GLshort t, GLshort r, GLshort q); +GLAPI PFNGLTEXCOORD4SPROC glad_glTexCoord4s; +#define glTexCoord4s glad_glTexCoord4s +typedef void (APIENTRYP PFNGLTEXCOORD4SVPROC)(const GLshort* v); +GLAPI PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv; +#define glTexCoord4sv glad_glTexCoord4sv +typedef void (APIENTRYP PFNGLVERTEX2DPROC)(GLdouble x, GLdouble y); +GLAPI PFNGLVERTEX2DPROC glad_glVertex2d; +#define glVertex2d glad_glVertex2d +typedef void (APIENTRYP PFNGLVERTEX2DVPROC)(const GLdouble* v); +GLAPI PFNGLVERTEX2DVPROC glad_glVertex2dv; +#define glVertex2dv glad_glVertex2dv +typedef void (APIENTRYP PFNGLVERTEX2FPROC)(GLfloat x, GLfloat y); +GLAPI PFNGLVERTEX2FPROC glad_glVertex2f; +#define glVertex2f glad_glVertex2f +typedef void (APIENTRYP PFNGLVERTEX2FVPROC)(const GLfloat* v); +GLAPI PFNGLVERTEX2FVPROC glad_glVertex2fv; +#define glVertex2fv glad_glVertex2fv +typedef void (APIENTRYP PFNGLVERTEX2IPROC)(GLint x, GLint y); +GLAPI PFNGLVERTEX2IPROC glad_glVertex2i; +#define glVertex2i glad_glVertex2i +typedef void (APIENTRYP PFNGLVERTEX2IVPROC)(const GLint* v); +GLAPI PFNGLVERTEX2IVPROC glad_glVertex2iv; +#define glVertex2iv glad_glVertex2iv +typedef void (APIENTRYP PFNGLVERTEX2SPROC)(GLshort x, GLshort y); +GLAPI PFNGLVERTEX2SPROC glad_glVertex2s; +#define glVertex2s glad_glVertex2s +typedef void (APIENTRYP PFNGLVERTEX2SVPROC)(const GLshort* v); +GLAPI PFNGLVERTEX2SVPROC glad_glVertex2sv; +#define glVertex2sv glad_glVertex2sv +typedef void (APIENTRYP PFNGLVERTEX3DPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLVERTEX3DPROC glad_glVertex3d; +#define glVertex3d glad_glVertex3d +typedef void (APIENTRYP PFNGLVERTEX3DVPROC)(const GLdouble* v); +GLAPI PFNGLVERTEX3DVPROC glad_glVertex3dv; +#define glVertex3dv glad_glVertex3dv +typedef void (APIENTRYP PFNGLVERTEX3FPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLVERTEX3FPROC glad_glVertex3f; +#define glVertex3f glad_glVertex3f +typedef void (APIENTRYP PFNGLVERTEX3FVPROC)(const GLfloat* v); +GLAPI PFNGLVERTEX3FVPROC glad_glVertex3fv; +#define glVertex3fv glad_glVertex3fv +typedef void (APIENTRYP PFNGLVERTEX3IPROC)(GLint x, GLint y, GLint z); +GLAPI PFNGLVERTEX3IPROC glad_glVertex3i; +#define glVertex3i glad_glVertex3i +typedef void (APIENTRYP PFNGLVERTEX3IVPROC)(const GLint* v); +GLAPI PFNGLVERTEX3IVPROC glad_glVertex3iv; +#define glVertex3iv glad_glVertex3iv +typedef void (APIENTRYP PFNGLVERTEX3SPROC)(GLshort x, GLshort y, GLshort z); +GLAPI PFNGLVERTEX3SPROC glad_glVertex3s; +#define glVertex3s glad_glVertex3s +typedef void (APIENTRYP PFNGLVERTEX3SVPROC)(const GLshort* v); +GLAPI PFNGLVERTEX3SVPROC glad_glVertex3sv; +#define glVertex3sv glad_glVertex3sv +typedef void (APIENTRYP PFNGLVERTEX4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLVERTEX4DPROC glad_glVertex4d; +#define glVertex4d glad_glVertex4d +typedef void (APIENTRYP PFNGLVERTEX4DVPROC)(const GLdouble* v); +GLAPI PFNGLVERTEX4DVPROC glad_glVertex4dv; +#define glVertex4dv glad_glVertex4dv +typedef void (APIENTRYP PFNGLVERTEX4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLVERTEX4FPROC glad_glVertex4f; +#define glVertex4f glad_glVertex4f +typedef void (APIENTRYP PFNGLVERTEX4FVPROC)(const GLfloat* v); +GLAPI PFNGLVERTEX4FVPROC glad_glVertex4fv; +#define glVertex4fv glad_glVertex4fv +typedef void (APIENTRYP PFNGLVERTEX4IPROC)(GLint x, GLint y, GLint z, GLint w); +GLAPI PFNGLVERTEX4IPROC glad_glVertex4i; +#define glVertex4i glad_glVertex4i +typedef void (APIENTRYP PFNGLVERTEX4IVPROC)(const GLint* v); +GLAPI PFNGLVERTEX4IVPROC glad_glVertex4iv; +#define glVertex4iv glad_glVertex4iv +typedef void (APIENTRYP PFNGLVERTEX4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI PFNGLVERTEX4SPROC glad_glVertex4s; +#define glVertex4s glad_glVertex4s +typedef void (APIENTRYP PFNGLVERTEX4SVPROC)(const GLshort* v); +GLAPI PFNGLVERTEX4SVPROC glad_glVertex4sv; +#define glVertex4sv glad_glVertex4sv +typedef void (APIENTRYP PFNGLCLIPPLANEPROC)(GLenum plane, const GLdouble* equation); +GLAPI PFNGLCLIPPLANEPROC glad_glClipPlane; +#define glClipPlane glad_glClipPlane +typedef void (APIENTRYP PFNGLCOLORMATERIALPROC)(GLenum face, GLenum mode); +GLAPI PFNGLCOLORMATERIALPROC glad_glColorMaterial; +#define glColorMaterial glad_glColorMaterial +typedef void (APIENTRYP PFNGLFOGFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLFOGFPROC glad_glFogf; +#define glFogf glad_glFogf +typedef void (APIENTRYP PFNGLFOGFVPROC)(GLenum pname, const GLfloat* params); +GLAPI PFNGLFOGFVPROC glad_glFogfv; +#define glFogfv glad_glFogfv +typedef void (APIENTRYP PFNGLFOGIPROC)(GLenum pname, GLint param); +GLAPI PFNGLFOGIPROC glad_glFogi; +#define glFogi glad_glFogi +typedef void (APIENTRYP PFNGLFOGIVPROC)(GLenum pname, const GLint* params); +GLAPI PFNGLFOGIVPROC glad_glFogiv; +#define glFogiv glad_glFogiv +typedef void (APIENTRYP PFNGLLIGHTFPROC)(GLenum light, GLenum pname, GLfloat param); +GLAPI PFNGLLIGHTFPROC glad_glLightf; +#define glLightf glad_glLightf +typedef void (APIENTRYP PFNGLLIGHTFVPROC)(GLenum light, GLenum pname, const GLfloat* params); +GLAPI PFNGLLIGHTFVPROC glad_glLightfv; +#define glLightfv glad_glLightfv +typedef void (APIENTRYP PFNGLLIGHTIPROC)(GLenum light, GLenum pname, GLint param); +GLAPI PFNGLLIGHTIPROC glad_glLighti; +#define glLighti glad_glLighti +typedef void (APIENTRYP PFNGLLIGHTIVPROC)(GLenum light, GLenum pname, const GLint* params); +GLAPI PFNGLLIGHTIVPROC glad_glLightiv; +#define glLightiv glad_glLightiv +typedef void (APIENTRYP PFNGLLIGHTMODELFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLLIGHTMODELFPROC glad_glLightModelf; +#define glLightModelf glad_glLightModelf +typedef void (APIENTRYP PFNGLLIGHTMODELFVPROC)(GLenum pname, const GLfloat* params); +GLAPI PFNGLLIGHTMODELFVPROC glad_glLightModelfv; +#define glLightModelfv glad_glLightModelfv +typedef void (APIENTRYP PFNGLLIGHTMODELIPROC)(GLenum pname, GLint param); +GLAPI PFNGLLIGHTMODELIPROC glad_glLightModeli; +#define glLightModeli glad_glLightModeli +typedef void (APIENTRYP PFNGLLIGHTMODELIVPROC)(GLenum pname, const GLint* params); +GLAPI PFNGLLIGHTMODELIVPROC glad_glLightModeliv; +#define glLightModeliv glad_glLightModeliv +typedef void (APIENTRYP PFNGLLINESTIPPLEPROC)(GLint factor, GLushort pattern); +GLAPI PFNGLLINESTIPPLEPROC glad_glLineStipple; +#define glLineStipple glad_glLineStipple +typedef void (APIENTRYP PFNGLMATERIALFPROC)(GLenum face, GLenum pname, GLfloat param); +GLAPI PFNGLMATERIALFPROC glad_glMaterialf; +#define glMaterialf glad_glMaterialf +typedef void (APIENTRYP PFNGLMATERIALFVPROC)(GLenum face, GLenum pname, const GLfloat* params); +GLAPI PFNGLMATERIALFVPROC glad_glMaterialfv; +#define glMaterialfv glad_glMaterialfv +typedef void (APIENTRYP PFNGLMATERIALIPROC)(GLenum face, GLenum pname, GLint param); +GLAPI PFNGLMATERIALIPROC glad_glMateriali; +#define glMateriali glad_glMateriali +typedef void (APIENTRYP PFNGLMATERIALIVPROC)(GLenum face, GLenum pname, const GLint* params); +GLAPI PFNGLMATERIALIVPROC glad_glMaterialiv; +#define glMaterialiv glad_glMaterialiv +typedef void (APIENTRYP PFNGLPOLYGONSTIPPLEPROC)(const GLubyte* mask); +GLAPI PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple; +#define glPolygonStipple glad_glPolygonStipple +typedef void (APIENTRYP PFNGLSHADEMODELPROC)(GLenum mode); +GLAPI PFNGLSHADEMODELPROC glad_glShadeModel; +#define glShadeModel glad_glShadeModel +typedef void (APIENTRYP PFNGLTEXENVFPROC)(GLenum target, GLenum pname, GLfloat param); +GLAPI PFNGLTEXENVFPROC glad_glTexEnvf; +#define glTexEnvf glad_glTexEnvf +typedef void (APIENTRYP PFNGLTEXENVFVPROC)(GLenum target, GLenum pname, const GLfloat* params); +GLAPI PFNGLTEXENVFVPROC glad_glTexEnvfv; +#define glTexEnvfv glad_glTexEnvfv +typedef void (APIENTRYP PFNGLTEXENVIPROC)(GLenum target, GLenum pname, GLint param); +GLAPI PFNGLTEXENVIPROC glad_glTexEnvi; +#define glTexEnvi glad_glTexEnvi +typedef void (APIENTRYP PFNGLTEXENVIVPROC)(GLenum target, GLenum pname, const GLint* params); +GLAPI PFNGLTEXENVIVPROC glad_glTexEnviv; +#define glTexEnviv glad_glTexEnviv +typedef void (APIENTRYP PFNGLTEXGENDPROC)(GLenum coord, GLenum pname, GLdouble param); +GLAPI PFNGLTEXGENDPROC glad_glTexGend; +#define glTexGend glad_glTexGend +typedef void (APIENTRYP PFNGLTEXGENDVPROC)(GLenum coord, GLenum pname, const GLdouble* params); +GLAPI PFNGLTEXGENDVPROC glad_glTexGendv; +#define glTexGendv glad_glTexGendv +typedef void (APIENTRYP PFNGLTEXGENFPROC)(GLenum coord, GLenum pname, GLfloat param); +GLAPI PFNGLTEXGENFPROC glad_glTexGenf; +#define glTexGenf glad_glTexGenf +typedef void (APIENTRYP PFNGLTEXGENFVPROC)(GLenum coord, GLenum pname, const GLfloat* params); +GLAPI PFNGLTEXGENFVPROC glad_glTexGenfv; +#define glTexGenfv glad_glTexGenfv +typedef void (APIENTRYP PFNGLTEXGENIPROC)(GLenum coord, GLenum pname, GLint param); +GLAPI PFNGLTEXGENIPROC glad_glTexGeni; +#define glTexGeni glad_glTexGeni +typedef void (APIENTRYP PFNGLTEXGENIVPROC)(GLenum coord, GLenum pname, const GLint* params); +GLAPI PFNGLTEXGENIVPROC glad_glTexGeniv; +#define glTexGeniv glad_glTexGeniv +typedef void (APIENTRYP PFNGLFEEDBACKBUFFERPROC)(GLsizei size, GLenum type, GLfloat* buffer); +GLAPI PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer; +#define glFeedbackBuffer glad_glFeedbackBuffer +typedef void (APIENTRYP PFNGLSELECTBUFFERPROC)(GLsizei size, GLuint* buffer); +GLAPI PFNGLSELECTBUFFERPROC glad_glSelectBuffer; +#define glSelectBuffer glad_glSelectBuffer +typedef GLint (APIENTRYP PFNGLRENDERMODEPROC)(GLenum mode); +GLAPI PFNGLRENDERMODEPROC glad_glRenderMode; +#define glRenderMode glad_glRenderMode +typedef void (APIENTRYP PFNGLINITNAMESPROC)(); +GLAPI PFNGLINITNAMESPROC glad_glInitNames; +#define glInitNames glad_glInitNames +typedef void (APIENTRYP PFNGLLOADNAMEPROC)(GLuint name); +GLAPI PFNGLLOADNAMEPROC glad_glLoadName; +#define glLoadName glad_glLoadName +typedef void (APIENTRYP PFNGLPASSTHROUGHPROC)(GLfloat token); +GLAPI PFNGLPASSTHROUGHPROC glad_glPassThrough; +#define glPassThrough glad_glPassThrough +typedef void (APIENTRYP PFNGLPOPNAMEPROC)(); +GLAPI PFNGLPOPNAMEPROC glad_glPopName; +#define glPopName glad_glPopName +typedef void (APIENTRYP PFNGLPUSHNAMEPROC)(GLuint name); +GLAPI PFNGLPUSHNAMEPROC glad_glPushName; +#define glPushName glad_glPushName +typedef void (APIENTRYP PFNGLCLEARACCUMPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCLEARACCUMPROC glad_glClearAccum; +#define glClearAccum glad_glClearAccum +typedef void (APIENTRYP PFNGLCLEARINDEXPROC)(GLfloat c); +GLAPI PFNGLCLEARINDEXPROC glad_glClearIndex; +#define glClearIndex glad_glClearIndex +typedef void (APIENTRYP PFNGLINDEXMASKPROC)(GLuint mask); +GLAPI PFNGLINDEXMASKPROC glad_glIndexMask; +#define glIndexMask glad_glIndexMask +typedef void (APIENTRYP PFNGLACCUMPROC)(GLenum op, GLfloat value); +GLAPI PFNGLACCUMPROC glad_glAccum; +#define glAccum glad_glAccum +typedef void (APIENTRYP PFNGLPOPATTRIBPROC)(); +GLAPI PFNGLPOPATTRIBPROC glad_glPopAttrib; +#define glPopAttrib glad_glPopAttrib +typedef void (APIENTRYP PFNGLPUSHATTRIBPROC)(GLbitfield mask); +GLAPI PFNGLPUSHATTRIBPROC glad_glPushAttrib; +#define glPushAttrib glad_glPushAttrib +typedef void (APIENTRYP PFNGLMAP1DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble* points); +GLAPI PFNGLMAP1DPROC glad_glMap1d; +#define glMap1d glad_glMap1d +typedef void (APIENTRYP PFNGLMAP1FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat* points); +GLAPI PFNGLMAP1FPROC glad_glMap1f; +#define glMap1f glad_glMap1f +typedef void (APIENTRYP PFNGLMAP2DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble* points); +GLAPI PFNGLMAP2DPROC glad_glMap2d; +#define glMap2d glad_glMap2d +typedef void (APIENTRYP PFNGLMAP2FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat* points); +GLAPI PFNGLMAP2FPROC glad_glMap2f; +#define glMap2f glad_glMap2f +typedef void (APIENTRYP PFNGLMAPGRID1DPROC)(GLint un, GLdouble u1, GLdouble u2); +GLAPI PFNGLMAPGRID1DPROC glad_glMapGrid1d; +#define glMapGrid1d glad_glMapGrid1d +typedef void (APIENTRYP PFNGLMAPGRID1FPROC)(GLint un, GLfloat u1, GLfloat u2); +GLAPI PFNGLMAPGRID1FPROC glad_glMapGrid1f; +#define glMapGrid1f glad_glMapGrid1f +typedef void (APIENTRYP PFNGLMAPGRID2DPROC)(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +GLAPI PFNGLMAPGRID2DPROC glad_glMapGrid2d; +#define glMapGrid2d glad_glMapGrid2d +typedef void (APIENTRYP PFNGLMAPGRID2FPROC)(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +GLAPI PFNGLMAPGRID2FPROC glad_glMapGrid2f; +#define glMapGrid2f glad_glMapGrid2f +typedef void (APIENTRYP PFNGLEVALCOORD1DPROC)(GLdouble u); +GLAPI PFNGLEVALCOORD1DPROC glad_glEvalCoord1d; +#define glEvalCoord1d glad_glEvalCoord1d +typedef void (APIENTRYP PFNGLEVALCOORD1DVPROC)(const GLdouble* u); +GLAPI PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv; +#define glEvalCoord1dv glad_glEvalCoord1dv +typedef void (APIENTRYP PFNGLEVALCOORD1FPROC)(GLfloat u); +GLAPI PFNGLEVALCOORD1FPROC glad_glEvalCoord1f; +#define glEvalCoord1f glad_glEvalCoord1f +typedef void (APIENTRYP PFNGLEVALCOORD1FVPROC)(const GLfloat* u); +GLAPI PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv; +#define glEvalCoord1fv glad_glEvalCoord1fv +typedef void (APIENTRYP PFNGLEVALCOORD2DPROC)(GLdouble u, GLdouble v); +GLAPI PFNGLEVALCOORD2DPROC glad_glEvalCoord2d; +#define glEvalCoord2d glad_glEvalCoord2d +typedef void (APIENTRYP PFNGLEVALCOORD2DVPROC)(const GLdouble* u); +GLAPI PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv; +#define glEvalCoord2dv glad_glEvalCoord2dv +typedef void (APIENTRYP PFNGLEVALCOORD2FPROC)(GLfloat u, GLfloat v); +GLAPI PFNGLEVALCOORD2FPROC glad_glEvalCoord2f; +#define glEvalCoord2f glad_glEvalCoord2f +typedef void (APIENTRYP PFNGLEVALCOORD2FVPROC)(const GLfloat* u); +GLAPI PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv; +#define glEvalCoord2fv glad_glEvalCoord2fv +typedef void (APIENTRYP PFNGLEVALMESH1PROC)(GLenum mode, GLint i1, GLint i2); +GLAPI PFNGLEVALMESH1PROC glad_glEvalMesh1; +#define glEvalMesh1 glad_glEvalMesh1 +typedef void (APIENTRYP PFNGLEVALPOINT1PROC)(GLint i); +GLAPI PFNGLEVALPOINT1PROC glad_glEvalPoint1; +#define glEvalPoint1 glad_glEvalPoint1 +typedef void (APIENTRYP PFNGLEVALMESH2PROC)(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +GLAPI PFNGLEVALMESH2PROC glad_glEvalMesh2; +#define glEvalMesh2 glad_glEvalMesh2 +typedef void (APIENTRYP PFNGLEVALPOINT2PROC)(GLint i, GLint j); +GLAPI PFNGLEVALPOINT2PROC glad_glEvalPoint2; +#define glEvalPoint2 glad_glEvalPoint2 +typedef void (APIENTRYP PFNGLALPHAFUNCPROC)(GLenum func, GLfloat ref); +GLAPI PFNGLALPHAFUNCPROC glad_glAlphaFunc; +#define glAlphaFunc glad_glAlphaFunc +typedef void (APIENTRYP PFNGLPIXELZOOMPROC)(GLfloat xfactor, GLfloat yfactor); +GLAPI PFNGLPIXELZOOMPROC glad_glPixelZoom; +#define glPixelZoom glad_glPixelZoom +typedef void (APIENTRYP PFNGLPIXELTRANSFERFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf; +#define glPixelTransferf glad_glPixelTransferf +typedef void (APIENTRYP PFNGLPIXELTRANSFERIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi; +#define glPixelTransferi glad_glPixelTransferi +typedef void (APIENTRYP PFNGLPIXELMAPFVPROC)(GLenum map, GLsizei mapsize, const GLfloat* values); +GLAPI PFNGLPIXELMAPFVPROC glad_glPixelMapfv; +#define glPixelMapfv glad_glPixelMapfv +typedef void (APIENTRYP PFNGLPIXELMAPUIVPROC)(GLenum map, GLsizei mapsize, const GLuint* values); +GLAPI PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv; +#define glPixelMapuiv glad_glPixelMapuiv +typedef void (APIENTRYP PFNGLPIXELMAPUSVPROC)(GLenum map, GLsizei mapsize, const GLushort* values); +GLAPI PFNGLPIXELMAPUSVPROC glad_glPixelMapusv; +#define glPixelMapusv glad_glPixelMapusv +typedef void (APIENTRYP PFNGLCOPYPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +GLAPI PFNGLCOPYPIXELSPROC glad_glCopyPixels; +#define glCopyPixels glad_glCopyPixels +typedef void (APIENTRYP PFNGLDRAWPIXELSPROC)(GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); +GLAPI PFNGLDRAWPIXELSPROC glad_glDrawPixels; +#define glDrawPixels glad_glDrawPixels +typedef void (APIENTRYP PFNGLGETCLIPPLANEPROC)(GLenum plane, GLdouble* equation); +GLAPI PFNGLGETCLIPPLANEPROC glad_glGetClipPlane; +#define glGetClipPlane glad_glGetClipPlane +typedef void (APIENTRYP PFNGLGETLIGHTFVPROC)(GLenum light, GLenum pname, GLfloat* params); +GLAPI PFNGLGETLIGHTFVPROC glad_glGetLightfv; +#define glGetLightfv glad_glGetLightfv +typedef void (APIENTRYP PFNGLGETLIGHTIVPROC)(GLenum light, GLenum pname, GLint* params); +GLAPI PFNGLGETLIGHTIVPROC glad_glGetLightiv; +#define glGetLightiv glad_glGetLightiv +typedef void (APIENTRYP PFNGLGETMAPDVPROC)(GLenum target, GLenum query, GLdouble* v); +GLAPI PFNGLGETMAPDVPROC glad_glGetMapdv; +#define glGetMapdv glad_glGetMapdv +typedef void (APIENTRYP PFNGLGETMAPFVPROC)(GLenum target, GLenum query, GLfloat* v); +GLAPI PFNGLGETMAPFVPROC glad_glGetMapfv; +#define glGetMapfv glad_glGetMapfv +typedef void (APIENTRYP PFNGLGETMAPIVPROC)(GLenum target, GLenum query, GLint* v); +GLAPI PFNGLGETMAPIVPROC glad_glGetMapiv; +#define glGetMapiv glad_glGetMapiv +typedef void (APIENTRYP PFNGLGETMATERIALFVPROC)(GLenum face, GLenum pname, GLfloat* params); +GLAPI PFNGLGETMATERIALFVPROC glad_glGetMaterialfv; +#define glGetMaterialfv glad_glGetMaterialfv +typedef void (APIENTRYP PFNGLGETMATERIALIVPROC)(GLenum face, GLenum pname, GLint* params); +GLAPI PFNGLGETMATERIALIVPROC glad_glGetMaterialiv; +#define glGetMaterialiv glad_glGetMaterialiv +typedef void (APIENTRYP PFNGLGETPIXELMAPFVPROC)(GLenum map, GLfloat* values); +GLAPI PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv; +#define glGetPixelMapfv glad_glGetPixelMapfv +typedef void (APIENTRYP PFNGLGETPIXELMAPUIVPROC)(GLenum map, GLuint* values); +GLAPI PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv; +#define glGetPixelMapuiv glad_glGetPixelMapuiv +typedef void (APIENTRYP PFNGLGETPIXELMAPUSVPROC)(GLenum map, GLushort* values); +GLAPI PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv; +#define glGetPixelMapusv glad_glGetPixelMapusv +typedef void (APIENTRYP PFNGLGETPOLYGONSTIPPLEPROC)(GLubyte* mask); +GLAPI PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple; +#define glGetPolygonStipple glad_glGetPolygonStipple +typedef void (APIENTRYP PFNGLGETTEXENVFVPROC)(GLenum target, GLenum pname, GLfloat* params); +GLAPI PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv; +#define glGetTexEnvfv glad_glGetTexEnvfv +typedef void (APIENTRYP PFNGLGETTEXENVIVPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETTEXENVIVPROC glad_glGetTexEnviv; +#define glGetTexEnviv glad_glGetTexEnviv +typedef void (APIENTRYP PFNGLGETTEXGENDVPROC)(GLenum coord, GLenum pname, GLdouble* params); +GLAPI PFNGLGETTEXGENDVPROC glad_glGetTexGendv; +#define glGetTexGendv glad_glGetTexGendv +typedef void (APIENTRYP PFNGLGETTEXGENFVPROC)(GLenum coord, GLenum pname, GLfloat* params); +GLAPI PFNGLGETTEXGENFVPROC glad_glGetTexGenfv; +#define glGetTexGenfv glad_glGetTexGenfv +typedef void (APIENTRYP PFNGLGETTEXGENIVPROC)(GLenum coord, GLenum pname, GLint* params); +GLAPI PFNGLGETTEXGENIVPROC glad_glGetTexGeniv; +#define glGetTexGeniv glad_glGetTexGeniv +typedef GLboolean (APIENTRYP PFNGLISLISTPROC)(GLuint list); +GLAPI PFNGLISLISTPROC glad_glIsList; +#define glIsList glad_glIsList +typedef void (APIENTRYP PFNGLFRUSTUMPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI PFNGLFRUSTUMPROC glad_glFrustum; +#define glFrustum glad_glFrustum +typedef void (APIENTRYP PFNGLLOADIDENTITYPROC)(); +GLAPI PFNGLLOADIDENTITYPROC glad_glLoadIdentity; +#define glLoadIdentity glad_glLoadIdentity +typedef void (APIENTRYP PFNGLLOADMATRIXFPROC)(const GLfloat* m); +GLAPI PFNGLLOADMATRIXFPROC glad_glLoadMatrixf; +#define glLoadMatrixf glad_glLoadMatrixf +typedef void (APIENTRYP PFNGLLOADMATRIXDPROC)(const GLdouble* m); +GLAPI PFNGLLOADMATRIXDPROC glad_glLoadMatrixd; +#define glLoadMatrixd glad_glLoadMatrixd +typedef void (APIENTRYP PFNGLMATRIXMODEPROC)(GLenum mode); +GLAPI PFNGLMATRIXMODEPROC glad_glMatrixMode; +#define glMatrixMode glad_glMatrixMode +typedef void (APIENTRYP PFNGLMULTMATRIXFPROC)(const GLfloat* m); +GLAPI PFNGLMULTMATRIXFPROC glad_glMultMatrixf; +#define glMultMatrixf glad_glMultMatrixf +typedef void (APIENTRYP PFNGLMULTMATRIXDPROC)(const GLdouble* m); +GLAPI PFNGLMULTMATRIXDPROC glad_glMultMatrixd; +#define glMultMatrixd glad_glMultMatrixd +typedef void (APIENTRYP PFNGLORTHOPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI PFNGLORTHOPROC glad_glOrtho; +#define glOrtho glad_glOrtho +typedef void (APIENTRYP PFNGLPOPMATRIXPROC)(); +GLAPI PFNGLPOPMATRIXPROC glad_glPopMatrix; +#define glPopMatrix glad_glPopMatrix +typedef void (APIENTRYP PFNGLPUSHMATRIXPROC)(); +GLAPI PFNGLPUSHMATRIXPROC glad_glPushMatrix; +#define glPushMatrix glad_glPushMatrix +typedef void (APIENTRYP PFNGLROTATEDPROC)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLROTATEDPROC glad_glRotated; +#define glRotated glad_glRotated +typedef void (APIENTRYP PFNGLROTATEFPROC)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLROTATEFPROC glad_glRotatef; +#define glRotatef glad_glRotatef +typedef void (APIENTRYP PFNGLSCALEDPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLSCALEDPROC glad_glScaled; +#define glScaled glad_glScaled +typedef void (APIENTRYP PFNGLSCALEFPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLSCALEFPROC glad_glScalef; +#define glScalef glad_glScalef +typedef void (APIENTRYP PFNGLTRANSLATEDPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLTRANSLATEDPROC glad_glTranslated; +#define glTranslated glad_glTranslated +typedef void (APIENTRYP PFNGLTRANSLATEFPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLTRANSLATEFPROC glad_glTranslatef; +#define glTranslatef glad_glTranslatef +#endif +#ifndef GL_VERSION_1_1 +#define GL_VERSION_1_1 1 +GLAPI int GLAD_GL_VERSION_1_1; +typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices); +GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +typedef void (APIENTRYP PFNGLGETPOINTERVPROC)(GLenum pname, void** params); +GLAPI PFNGLGETPOINTERVPROC glad_glGetPointerv; +#define glGetPointerv glad_glGetPointerv +typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; +#define glCopyTexImage1D glad_glCopyTexImage1D +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; +#define glCopyTexSubImage1D glad_glCopyTexSubImage1D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels); +GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; +#define glTexSubImage1D glad_glTexSubImage1D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); +GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint* textures); +GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint* textures); +GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture); +GLAPI PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +typedef void (APIENTRYP PFNGLARRAYELEMENTPROC)(GLint i); +GLAPI PFNGLARRAYELEMENTPROC glad_glArrayElement; +#define glArrayElement glad_glArrayElement +typedef void (APIENTRYP PFNGLCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void* pointer); +GLAPI PFNGLCOLORPOINTERPROC glad_glColorPointer; +#define glColorPointer glad_glColorPointer +typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEPROC)(GLenum array); +GLAPI PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState; +#define glDisableClientState glad_glDisableClientState +typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERPROC)(GLsizei stride, const void* pointer); +GLAPI PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer; +#define glEdgeFlagPointer glad_glEdgeFlagPointer +typedef void (APIENTRYP PFNGLENABLECLIENTSTATEPROC)(GLenum array); +GLAPI PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState; +#define glEnableClientState glad_glEnableClientState +typedef void (APIENTRYP PFNGLINDEXPOINTERPROC)(GLenum type, GLsizei stride, const void* pointer); +GLAPI PFNGLINDEXPOINTERPROC glad_glIndexPointer; +#define glIndexPointer glad_glIndexPointer +typedef void (APIENTRYP PFNGLINTERLEAVEDARRAYSPROC)(GLenum format, GLsizei stride, const void* pointer); +GLAPI PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays; +#define glInterleavedArrays glad_glInterleavedArrays +typedef void (APIENTRYP PFNGLNORMALPOINTERPROC)(GLenum type, GLsizei stride, const void* pointer); +GLAPI PFNGLNORMALPOINTERPROC glad_glNormalPointer; +#define glNormalPointer glad_glNormalPointer +typedef void (APIENTRYP PFNGLTEXCOORDPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void* pointer); +GLAPI PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer; +#define glTexCoordPointer glad_glTexCoordPointer +typedef void (APIENTRYP PFNGLVERTEXPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void* pointer); +GLAPI PFNGLVERTEXPOINTERPROC glad_glVertexPointer; +#define glVertexPointer glad_glVertexPointer +typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTPROC)(GLsizei n, const GLuint* textures, GLboolean* residences); +GLAPI PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident; +#define glAreTexturesResident glad_glAreTexturesResident +typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESPROC)(GLsizei n, const GLuint* textures, const GLfloat* priorities); +GLAPI PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures; +#define glPrioritizeTextures glad_glPrioritizeTextures +typedef void (APIENTRYP PFNGLINDEXUBPROC)(GLubyte c); +GLAPI PFNGLINDEXUBPROC glad_glIndexub; +#define glIndexub glad_glIndexub +typedef void (APIENTRYP PFNGLINDEXUBVPROC)(const GLubyte* c); +GLAPI PFNGLINDEXUBVPROC glad_glIndexubv; +#define glIndexubv glad_glIndexubv +typedef void (APIENTRYP PFNGLPOPCLIENTATTRIBPROC)(); +GLAPI PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib; +#define glPopClientAttrib glad_glPopClientAttrib +typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBPROC)(GLbitfield mask); +GLAPI PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib; +#define glPushClientAttrib glad_glPushClientAttrib +#endif +#ifndef GL_VERSION_1_2 +#define GL_VERSION_1_2 1 +GLAPI int GLAD_GL_VERSION_1_2; +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices); +GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; +#define glDrawRangeElements glad_glDrawRangeElements +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels); +GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D; +#define glTexImage3D glad_glTexImage3D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); +GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; +#define glTexSubImage3D glad_glTexSubImage3D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; +#define glCopyTexSubImage3D glad_glCopyTexSubImage3D +#endif +#ifndef GL_VERSION_1_3 +#define GL_VERSION_1_3 1 +GLAPI int GLAD_GL_VERSION_1_3; +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture); +GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; +#define glCompressedTexImage3D glad_glCompressedTexImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; +#define glCompressedTexImage1D glad_glCompressedTexImage1D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; +#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; +#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void* img); +GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; +#define glGetCompressedTexImage glad_glGetCompressedTexImage +typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC)(GLenum texture); +GLAPI PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture; +#define glClientActiveTexture glad_glClientActiveTexture +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC)(GLenum target, GLdouble s); +GLAPI PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d; +#define glMultiTexCoord1d glad_glMultiTexCoord1d +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC)(GLenum target, const GLdouble* v); +GLAPI PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv; +#define glMultiTexCoord1dv glad_glMultiTexCoord1dv +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC)(GLenum target, GLfloat s); +GLAPI PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f; +#define glMultiTexCoord1f glad_glMultiTexCoord1f +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC)(GLenum target, const GLfloat* v); +GLAPI PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv; +#define glMultiTexCoord1fv glad_glMultiTexCoord1fv +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC)(GLenum target, GLint s); +GLAPI PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i; +#define glMultiTexCoord1i glad_glMultiTexCoord1i +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC)(GLenum target, const GLint* v); +GLAPI PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv; +#define glMultiTexCoord1iv glad_glMultiTexCoord1iv +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC)(GLenum target, GLshort s); +GLAPI PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s; +#define glMultiTexCoord1s glad_glMultiTexCoord1s +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC)(GLenum target, const GLshort* v); +GLAPI PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv; +#define glMultiTexCoord1sv glad_glMultiTexCoord1sv +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC)(GLenum target, GLdouble s, GLdouble t); +GLAPI PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d; +#define glMultiTexCoord2d glad_glMultiTexCoord2d +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC)(GLenum target, const GLdouble* v); +GLAPI PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv; +#define glMultiTexCoord2dv glad_glMultiTexCoord2dv +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC)(GLenum target, GLfloat s, GLfloat t); +GLAPI PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f; +#define glMultiTexCoord2f glad_glMultiTexCoord2f +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC)(GLenum target, const GLfloat* v); +GLAPI PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv; +#define glMultiTexCoord2fv glad_glMultiTexCoord2fv +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC)(GLenum target, GLint s, GLint t); +GLAPI PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i; +#define glMultiTexCoord2i glad_glMultiTexCoord2i +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC)(GLenum target, const GLint* v); +GLAPI PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv; +#define glMultiTexCoord2iv glad_glMultiTexCoord2iv +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC)(GLenum target, GLshort s, GLshort t); +GLAPI PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s; +#define glMultiTexCoord2s glad_glMultiTexCoord2s +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC)(GLenum target, const GLshort* v); +GLAPI PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv; +#define glMultiTexCoord2sv glad_glMultiTexCoord2sv +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r); +GLAPI PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d; +#define glMultiTexCoord3d glad_glMultiTexCoord3d +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC)(GLenum target, const GLdouble* v); +GLAPI PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv; +#define glMultiTexCoord3dv glad_glMultiTexCoord3dv +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r); +GLAPI PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f; +#define glMultiTexCoord3f glad_glMultiTexCoord3f +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC)(GLenum target, const GLfloat* v); +GLAPI PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv; +#define glMultiTexCoord3fv glad_glMultiTexCoord3fv +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC)(GLenum target, GLint s, GLint t, GLint r); +GLAPI PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i; +#define glMultiTexCoord3i glad_glMultiTexCoord3i +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC)(GLenum target, const GLint* v); +GLAPI PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv; +#define glMultiTexCoord3iv glad_glMultiTexCoord3iv +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC)(GLenum target, GLshort s, GLshort t, GLshort r); +GLAPI PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s; +#define glMultiTexCoord3s glad_glMultiTexCoord3s +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC)(GLenum target, const GLshort* v); +GLAPI PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv; +#define glMultiTexCoord3sv glad_glMultiTexCoord3sv +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +GLAPI PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d; +#define glMultiTexCoord4d glad_glMultiTexCoord4d +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC)(GLenum target, const GLdouble* v); +GLAPI PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv; +#define glMultiTexCoord4dv glad_glMultiTexCoord4dv +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +GLAPI PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f; +#define glMultiTexCoord4f glad_glMultiTexCoord4f +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC)(GLenum target, const GLfloat* v); +GLAPI PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv; +#define glMultiTexCoord4fv glad_glMultiTexCoord4fv +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC)(GLenum target, GLint s, GLint t, GLint r, GLint q); +GLAPI PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i; +#define glMultiTexCoord4i glad_glMultiTexCoord4i +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC)(GLenum target, const GLint* v); +GLAPI PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv; +#define glMultiTexCoord4iv glad_glMultiTexCoord4iv +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC)(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +GLAPI PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s; +#define glMultiTexCoord4s glad_glMultiTexCoord4s +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC)(GLenum target, const GLshort* v); +GLAPI PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv; +#define glMultiTexCoord4sv glad_glMultiTexCoord4sv +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC)(const GLfloat* m); +GLAPI PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf; +#define glLoadTransposeMatrixf glad_glLoadTransposeMatrixf +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC)(const GLdouble* m); +GLAPI PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd; +#define glLoadTransposeMatrixd glad_glLoadTransposeMatrixd +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC)(const GLfloat* m); +GLAPI PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf; +#define glMultTransposeMatrixf glad_glMultTransposeMatrixf +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC)(const GLdouble* m); +GLAPI PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd; +#define glMultTransposeMatrixd glad_glMultTransposeMatrixd +#endif +#ifndef GL_VERSION_1_4 +#define GL_VERSION_1_4 1 +GLAPI int GLAD_GL_VERSION_1_4; +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount); +GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; +#define glMultiDrawArrays glad_glMultiDrawArrays +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei* count, GLenum type, const void** indices, GLsizei drawcount); +GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; +#define glMultiDrawElements glad_glMultiDrawElements +typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; +#define glPointParameterf glad_glPointParameterf +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat* params); +GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; +#define glPointParameterfv glad_glPointParameterfv +typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; +#define glPointParameteri glad_glPointParameteri +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint* params); +GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; +#define glPointParameteriv glad_glPointParameteriv +typedef void (APIENTRYP PFNGLFOGCOORDFPROC)(GLfloat coord); +GLAPI PFNGLFOGCOORDFPROC glad_glFogCoordf; +#define glFogCoordf glad_glFogCoordf +typedef void (APIENTRYP PFNGLFOGCOORDFVPROC)(const GLfloat* coord); +GLAPI PFNGLFOGCOORDFVPROC glad_glFogCoordfv; +#define glFogCoordfv glad_glFogCoordfv +typedef void (APIENTRYP PFNGLFOGCOORDDPROC)(GLdouble coord); +GLAPI PFNGLFOGCOORDDPROC glad_glFogCoordd; +#define glFogCoordd glad_glFogCoordd +typedef void (APIENTRYP PFNGLFOGCOORDDVPROC)(const GLdouble* coord); +GLAPI PFNGLFOGCOORDDVPROC glad_glFogCoorddv; +#define glFogCoorddv glad_glFogCoorddv +typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC)(GLenum type, GLsizei stride, const void* pointer); +GLAPI PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer; +#define glFogCoordPointer glad_glFogCoordPointer +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); +GLAPI PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b; +#define glSecondaryColor3b glad_glSecondaryColor3b +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC)(const GLbyte* v); +GLAPI PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv; +#define glSecondaryColor3bv glad_glSecondaryColor3bv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); +GLAPI PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d; +#define glSecondaryColor3d glad_glSecondaryColor3d +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC)(const GLdouble* v); +GLAPI PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv; +#define glSecondaryColor3dv glad_glSecondaryColor3dv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); +GLAPI PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f; +#define glSecondaryColor3f glad_glSecondaryColor3f +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC)(const GLfloat* v); +GLAPI PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv; +#define glSecondaryColor3fv glad_glSecondaryColor3fv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC)(GLint red, GLint green, GLint blue); +GLAPI PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i; +#define glSecondaryColor3i glad_glSecondaryColor3i +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC)(const GLint* v); +GLAPI PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv; +#define glSecondaryColor3iv glad_glSecondaryColor3iv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); +GLAPI PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s; +#define glSecondaryColor3s glad_glSecondaryColor3s +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC)(const GLshort* v); +GLAPI PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv; +#define glSecondaryColor3sv glad_glSecondaryColor3sv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); +GLAPI PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub; +#define glSecondaryColor3ub glad_glSecondaryColor3ub +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC)(const GLubyte* v); +GLAPI PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv; +#define glSecondaryColor3ubv glad_glSecondaryColor3ubv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); +GLAPI PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui; +#define glSecondaryColor3ui glad_glSecondaryColor3ui +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC)(const GLuint* v); +GLAPI PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv; +#define glSecondaryColor3uiv glad_glSecondaryColor3uiv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); +GLAPI PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us; +#define glSecondaryColor3us glad_glSecondaryColor3us +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC)(const GLushort* v); +GLAPI PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv; +#define glSecondaryColor3usv glad_glSecondaryColor3usv +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void* pointer); +GLAPI PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer; +#define glSecondaryColorPointer glad_glSecondaryColorPointer +typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC)(GLdouble x, GLdouble y); +GLAPI PFNGLWINDOWPOS2DPROC glad_glWindowPos2d; +#define glWindowPos2d glad_glWindowPos2d +typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC)(const GLdouble* v); +GLAPI PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv; +#define glWindowPos2dv glad_glWindowPos2dv +typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC)(GLfloat x, GLfloat y); +GLAPI PFNGLWINDOWPOS2FPROC glad_glWindowPos2f; +#define glWindowPos2f glad_glWindowPos2f +typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC)(const GLfloat* v); +GLAPI PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv; +#define glWindowPos2fv glad_glWindowPos2fv +typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC)(GLint x, GLint y); +GLAPI PFNGLWINDOWPOS2IPROC glad_glWindowPos2i; +#define glWindowPos2i glad_glWindowPos2i +typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC)(const GLint* v); +GLAPI PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv; +#define glWindowPos2iv glad_glWindowPos2iv +typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC)(GLshort x, GLshort y); +GLAPI PFNGLWINDOWPOS2SPROC glad_glWindowPos2s; +#define glWindowPos2s glad_glWindowPos2s +typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC)(const GLshort* v); +GLAPI PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv; +#define glWindowPos2sv glad_glWindowPos2sv +typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLWINDOWPOS3DPROC glad_glWindowPos3d; +#define glWindowPos3d glad_glWindowPos3d +typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC)(const GLdouble* v); +GLAPI PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv; +#define glWindowPos3dv glad_glWindowPos3dv +typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLWINDOWPOS3FPROC glad_glWindowPos3f; +#define glWindowPos3f glad_glWindowPos3f +typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC)(const GLfloat* v); +GLAPI PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv; +#define glWindowPos3fv glad_glWindowPos3fv +typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC)(GLint x, GLint y, GLint z); +GLAPI PFNGLWINDOWPOS3IPROC glad_glWindowPos3i; +#define glWindowPos3i glad_glWindowPos3i +typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC)(const GLint* v); +GLAPI PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv; +#define glWindowPos3iv glad_glWindowPos3iv +typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC)(GLshort x, GLshort y, GLshort z); +GLAPI PFNGLWINDOWPOS3SPROC glad_glWindowPos3s; +#define glWindowPos3s glad_glWindowPos3s +typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC)(const GLshort* v); +GLAPI PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv; +#define glWindowPos3sv glad_glWindowPos3sv +typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode); +GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +#endif +#ifndef GL_VERSION_1_5 +#define GL_VERSION_1_5 1 +GLAPI int GLAD_GL_VERSION_1_5; +typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint* ids); +GLAPI PFNGLGENQUERIESPROC glad_glGenQueries; +#define glGenQueries glad_glGenQueries +typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint* ids); +GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries; +#define glDeleteQueries glad_glDeleteQueries +typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id); +GLAPI PFNGLISQUERYPROC glad_glIsQuery; +#define glIsQuery glad_glIsQuery +typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); +GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery; +#define glBeginQuery glad_glBeginQuery +typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target); +GLAPI PFNGLENDQUERYPROC glad_glEndQuery; +#define glEndQuery glad_glEndQuery +typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv; +#define glGetQueryiv glad_glGetQueryiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint* params); +GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; +#define glGetQueryObjectiv glad_glGetQueryObjectiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint* params); +GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; +#define glGetQueryObjectuiv glad_glGetQueryObjectuiv +typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint* buffers); +GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint* buffers); +GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer); +GLAPI PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void* data, GLenum usage); +GLAPI PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void* data); +GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void* data); +GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; +#define glGetBufferSubData glad_glGetBufferSubData +typedef void* (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); +GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer; +#define glMapBuffer glad_glMapBuffer +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target); +GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; +#define glUnmapBuffer glad_glUnmapBuffer +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void** params); +GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; +#define glGetBufferPointerv glad_glGetBufferPointerv +#endif +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +GLAPI int GLAD_GL_VERSION_2_0; +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum* bufs); +GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; +#define glDrawBuffers glad_glDrawBuffers +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar* name); +GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader); +GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(); +GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type); +GLAPI PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program); +GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader); +GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); +GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); +GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders); +GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar* name); +GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint* params); +GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog); +GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint* params); +GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); +GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source); +GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar* name); +GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat* params); +GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint* params); +GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble* params); +GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; +#define glGetVertexAttribdv glad_glGetVertexAttribdv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat* params); +GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint* params); +GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void** pointer); +GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program); +GLAPI PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader); +GLAPI PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program); +GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar** string, const GLint* length); +GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program); +GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat* value); +GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat* value); +GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat* value); +GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat* value); +GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint* value); +GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint* value); +GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint* value); +GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint* value); +GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program); +GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); +GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; +#define glVertexAttrib1d glad_glVertexAttrib1d +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble* v); +GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; +#define glVertexAttrib1dv glad_glVertexAttrib1dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat* v); +GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); +GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; +#define glVertexAttrib1s glad_glVertexAttrib1s +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; +#define glVertexAttrib1sv glad_glVertexAttrib1sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); +GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; +#define glVertexAttrib2d glad_glVertexAttrib2d +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble* v); +GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; +#define glVertexAttrib2dv glad_glVertexAttrib2dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat* v); +GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); +GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; +#define glVertexAttrib2s glad_glVertexAttrib2s +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; +#define glVertexAttrib2sv glad_glVertexAttrib2sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; +#define glVertexAttrib3d glad_glVertexAttrib3d +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble* v); +GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; +#define glVertexAttrib3dv glad_glVertexAttrib3dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat* v); +GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; +#define glVertexAttrib3s glad_glVertexAttrib3s +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; +#define glVertexAttrib3sv glad_glVertexAttrib3sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte* v); +GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; +#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; +#define glVertexAttrib4Niv glad_glVertexAttrib4Niv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; +#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; +#define glVertexAttrib4Nub glad_glVertexAttrib4Nub +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte* v); +GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; +#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; +#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort* v); +GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; +#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte* v); +GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; +#define glVertexAttrib4bv glad_glVertexAttrib4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; +#define glVertexAttrib4d glad_glVertexAttrib4d +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble* v); +GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; +#define glVertexAttrib4dv glad_glVertexAttrib4dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat* v); +GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; +#define glVertexAttrib4iv glad_glVertexAttrib4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; +#define glVertexAttrib4s glad_glVertexAttrib4s +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; +#define glVertexAttrib4sv glad_glVertexAttrib4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte* v); +GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; +#define glVertexAttrib4ubv glad_glVertexAttrib4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; +#define glVertexAttrib4uiv glad_glVertexAttrib4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort* v); +GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; +#define glVertexAttrib4usv glad_glVertexAttrib4usv +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); +GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +#endif +#ifndef GL_VERSION_2_1 +#define GL_VERSION_2_1 1 +GLAPI int GLAD_GL_VERSION_2_1; +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; +#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; +#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; +#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; +#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; +#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; +#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv +#endif +#ifndef GL_VERSION_3_0 +#define GL_VERSION_3_0 1 +GLAPI int GLAD_GL_VERSION_3_0; +typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski; +#define glColorMaski glad_glColorMaski +typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean* data); +GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; +#define glGetBooleani_v glad_glGetBooleani_v +typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint* data); +GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; +#define glGetIntegeri_v glad_glGetIntegeri_v +typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index); +GLAPI PFNGLENABLEIPROC glad_glEnablei; +#define glEnablei glad_glEnablei +typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index); +GLAPI PFNGLDISABLEIPROC glad_glDisablei; +#define glDisablei glad_glDisablei +typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index); +GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi; +#define glIsEnabledi glad_glIsEnabledi +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); +GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; +#define glBeginTransformFeedback glad_glBeginTransformFeedback +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(); +GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; +#define glEndTransformFeedback glad_glEndTransformFeedback +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; +#define glBindBufferRange glad_glBindBufferRange +typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); +GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; +#define glBindBufferBase glad_glBindBufferBase +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar** varyings, GLenum bufferMode); +GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; +#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name); +GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; +#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying +typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); +GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor; +#define glClampColor glad_glClampColor +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); +GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; +#define glBeginConditionalRender glad_glBeginConditionalRender +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(); +GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; +#define glEndConditionalRender glad_glEndConditionalRender +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer); +GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; +#define glVertexAttribIPointer glad_glVertexAttribIPointer +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint* params); +GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; +#define glGetVertexAttribIiv glad_glGetVertexAttribIiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint* params); +GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; +#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); +GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; +#define glVertexAttribI1i glad_glVertexAttribI1i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); +GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; +#define glVertexAttribI2i glad_glVertexAttribI2i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); +GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; +#define glVertexAttribI3i glad_glVertexAttribI3i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; +#define glVertexAttribI4i glad_glVertexAttribI4i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); +GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; +#define glVertexAttribI1ui glad_glVertexAttribI1ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); +GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; +#define glVertexAttribI2ui glad_glVertexAttribI2ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; +#define glVertexAttribI3ui glad_glVertexAttribI3ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; +#define glVertexAttribI4ui glad_glVertexAttribI4ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; +#define glVertexAttribI1iv glad_glVertexAttribI1iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; +#define glVertexAttribI2iv glad_glVertexAttribI2iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; +#define glVertexAttribI3iv glad_glVertexAttribI3iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint* v); +GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; +#define glVertexAttribI4iv glad_glVertexAttribI4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; +#define glVertexAttribI1uiv glad_glVertexAttribI1uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; +#define glVertexAttribI2uiv glad_glVertexAttribI2uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; +#define glVertexAttribI3uiv glad_glVertexAttribI3uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint* v); +GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; +#define glVertexAttribI4uiv glad_glVertexAttribI4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte* v); +GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; +#define glVertexAttribI4bv glad_glVertexAttribI4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort* v); +GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; +#define glVertexAttribI4sv glad_glVertexAttribI4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte* v); +GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; +#define glVertexAttribI4ubv glad_glVertexAttribI4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort* v); +GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; +#define glVertexAttribI4usv glad_glVertexAttribI4usv +typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint* params); +GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; +#define glGetUniformuiv glad_glGetUniformuiv +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar* name); +GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; +#define glBindFragDataLocation glad_glBindFragDataLocation +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar* name); +GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; +#define glGetFragDataLocation glad_glGetFragDataLocation +typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); +GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui; +#define glUniform1ui glad_glUniform1ui +typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); +GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui; +#define glUniform2ui glad_glUniform2ui +typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui; +#define glUniform3ui glad_glUniform3ui +typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui; +#define glUniform4ui glad_glUniform4ui +typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint* value); +GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; +#define glUniform1uiv glad_glUniform1uiv +typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint* value); +GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; +#define glUniform2uiv glad_glUniform2uiv +typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint* value); +GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; +#define glUniform3uiv glad_glUniform3uiv +typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint* value); +GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; +#define glUniform4uiv glad_glUniform4uiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint* params); +GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; +#define glTexParameterIiv glad_glTexParameterIiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint* params); +GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; +#define glTexParameterIuiv glad_glTexParameterIuiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; +#define glGetTexParameterIiv glad_glGetTexParameterIiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint* params); +GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; +#define glGetTexParameterIuiv glad_glGetTexParameterIuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint* value); +GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; +#define glClearBufferiv glad_glClearBufferiv +typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint* value); +GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; +#define glClearBufferuiv glad_glClearBufferuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat* value); +GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; +#define glClearBufferfv glad_glClearBufferfv +typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; +#define glClearBufferfi glad_glClearBufferfi +typedef const GLubyte* (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); +GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi; +#define glGetStringi glad_glGetStringi +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint* renderbuffers); +GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint* renderbuffers); +GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params); +GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint* framebuffers); +GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint* framebuffers); +GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; +#define glFramebufferTexture1D glad_glFramebufferTexture1D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; +#define glFramebufferTexture3D glad_glFramebufferTexture3D +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint* params); +GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target); +GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; +#define glBlitFramebuffer glad_glBlitFramebuffer +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; +#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; +#define glFramebufferTextureLayer glad_glFramebufferTextureLayer +typedef void* (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; +#define glMapBufferRange glad_glMapBufferRange +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); +GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; +#define glFlushMappedBufferRange glad_glFlushMappedBufferRange +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array); +GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; +#define glBindVertexArray glad_glBindVertexArray +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint* arrays); +GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; +#define glDeleteVertexArrays glad_glDeleteVertexArrays +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint* arrays); +GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; +#define glGenVertexArrays glad_glGenVertexArrays +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array); +GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; +#define glIsVertexArray glad_glIsVertexArray +#endif +#ifndef GL_VERSION_3_1 +#define GL_VERSION_3_1 1 +GLAPI int GLAD_GL_VERSION_3_1; +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +GLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; +#define glDrawArraysInstanced glad_glDrawArraysInstanced +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount); +GLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; +#define glDrawElementsInstanced glad_glDrawElementsInstanced +typedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); +GLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer; +#define glTexBuffer glad_glTexBuffer +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); +GLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; +#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex +typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; +#define glCopyBufferSubData glad_glCopyBufferSubData +typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar** uniformNames, GLuint* uniformIndices); +GLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; +#define glGetUniformIndices glad_glGetUniformIndices +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params); +GLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; +#define glGetActiveUniformsiv glad_glGetActiveUniformsiv +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName); +GLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; +#define glGetActiveUniformName glad_glGetActiveUniformName +typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar* uniformBlockName); +GLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; +#define glGetUniformBlockIndex glad_glGetUniformBlockIndex +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params); +GLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; +#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName); +GLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; +#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName +typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +GLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; +#define glUniformBlockBinding glad_glUniformBlockBinding +#endif +#ifndef GL_VERSION_3_2 +#define GL_VERSION_3_2 1 +GLAPI int GLAD_GL_VERSION_3_2; +typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex); +GLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; +#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices, GLint basevertex); +GLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; +#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount, GLint basevertex); +GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; +#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei* count, GLenum type, const void** indices, GLsizei drawcount, const GLint* basevertex); +GLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; +#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode); +GLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; +#define glProvokingVertex glad_glProvokingVertex +typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); +GLAPI PFNGLFENCESYNCPROC glad_glFenceSync; +#define glFenceSync glad_glFenceSync +typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync); +GLAPI PFNGLISSYNCPROC glad_glIsSync; +#define glIsSync glad_glIsSync +typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync); +GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync; +#define glDeleteSync glad_glDeleteSync +typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; +#define glClientWaitSync glad_glClientWaitSync +typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI PFNGLWAITSYNCPROC glad_glWaitSync; +#define glWaitSync glad_glWaitSync +typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64* data); +GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v; +#define glGetInteger64v glad_glGetInteger64v +typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values); +GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv; +#define glGetSynciv glad_glGetSynciv +typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64* data); +GLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; +#define glGetInteger64i_v glad_glGetInteger64i_v +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64* params); +GLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; +#define glGetBufferParameteri64v glad_glGetBufferParameteri64v +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; +#define glFramebufferTexture glad_glFramebufferTexture +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; +#define glTexImage2DMultisample glad_glTexImage2DMultisample +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; +#define glTexImage3DMultisample glad_glTexImage3DMultisample +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat* val); +GLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; +#define glGetMultisamplefv glad_glGetMultisamplefv +typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); +GLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski; +#define glSampleMaski glad_glSampleMaski +#endif +#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 +#define GL_SINGLE_COLOR_EXT 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA +#define GL_MULTISAMPLE_ARB 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F +#define GL_SAMPLE_COVERAGE_ARB 0x80A0 +#define GL_SAMPLE_BUFFERS_ARB 0x80A8 +#define GL_SAMPLES_ARB 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB +#define GL_MULTISAMPLE_BIT_ARB 0x20000000 +#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 +#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 +#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 +#ifndef GL_EXT_separate_specular_color +#define GL_EXT_separate_specular_color 1 +GLAPI int GLAD_GL_EXT_separate_specular_color; +#endif +#ifndef GL_ARB_multisample +#define GL_ARB_multisample 1 +GLAPI int GLAD_GL_ARB_multisample; +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC)(GLfloat value, GLboolean invert); +GLAPI PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB; +#define glSampleCoverageARB glad_glSampleCoverageARB +#endif +#ifndef GL_ARB_robustness +#define GL_ARB_robustness 1 +GLAPI int GLAD_GL_ARB_robustness; +typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC)(); +GLAPI PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB; +#define glGetGraphicsResetStatusARB glad_glGetGraphicsResetStatusARB +typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC)(GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* img); +GLAPI PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB; +#define glGetnTexImageARB glad_glGetnTexImageARB +typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void* data); +GLAPI PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB; +#define glReadnPixelsARB glad_glReadnPixelsARB +typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC)(GLenum target, GLint lod, GLsizei bufSize, void* img); +GLAPI PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC glad_glGetnCompressedTexImageARB; +#define glGetnCompressedTexImageARB glad_glGetnCompressedTexImageARB +typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat* params); +GLAPI PFNGLGETNUNIFORMFVARBPROC glad_glGetnUniformfvARB; +#define glGetnUniformfvARB glad_glGetnUniformfvARB +typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLint* params); +GLAPI PFNGLGETNUNIFORMIVARBPROC glad_glGetnUniformivARB; +#define glGetnUniformivARB glad_glGetnUniformivARB +typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint* params); +GLAPI PFNGLGETNUNIFORMUIVARBPROC glad_glGetnUniformuivARB; +#define glGetnUniformuivARB glad_glGetnUniformuivARB +typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLdouble* params); +GLAPI PFNGLGETNUNIFORMDVARBPROC glad_glGetnUniformdvARB; +#define glGetnUniformdvARB glad_glGetnUniformdvARB +typedef void (APIENTRYP PFNGLGETNMAPDVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLdouble* v); +GLAPI PFNGLGETNMAPDVARBPROC glad_glGetnMapdvARB; +#define glGetnMapdvARB glad_glGetnMapdvARB +typedef void (APIENTRYP PFNGLGETNMAPFVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLfloat* v); +GLAPI PFNGLGETNMAPFVARBPROC glad_glGetnMapfvARB; +#define glGetnMapfvARB glad_glGetnMapfvARB +typedef void (APIENTRYP PFNGLGETNMAPIVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLint* v); +GLAPI PFNGLGETNMAPIVARBPROC glad_glGetnMapivARB; +#define glGetnMapivARB glad_glGetnMapivARB +typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC)(GLenum map, GLsizei bufSize, GLfloat* values); +GLAPI PFNGLGETNPIXELMAPFVARBPROC glad_glGetnPixelMapfvARB; +#define glGetnPixelMapfvARB glad_glGetnPixelMapfvARB +typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC)(GLenum map, GLsizei bufSize, GLuint* values); +GLAPI PFNGLGETNPIXELMAPUIVARBPROC glad_glGetnPixelMapuivARB; +#define glGetnPixelMapuivARB glad_glGetnPixelMapuivARB +typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC)(GLenum map, GLsizei bufSize, GLushort* values); +GLAPI PFNGLGETNPIXELMAPUSVARBPROC glad_glGetnPixelMapusvARB; +#define glGetnPixelMapusvARB glad_glGetnPixelMapusvARB +typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC)(GLsizei bufSize, GLubyte* pattern); +GLAPI PFNGLGETNPOLYGONSTIPPLEARBPROC glad_glGetnPolygonStippleARB; +#define glGetnPolygonStippleARB glad_glGetnPolygonStippleARB +typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void* table); +GLAPI PFNGLGETNCOLORTABLEARBPROC glad_glGetnColorTableARB; +#define glGetnColorTableARB glad_glGetnColorTableARB +typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void* image); +GLAPI PFNGLGETNCONVOLUTIONFILTERARBPROC glad_glGetnConvolutionFilterARB; +#define glGetnConvolutionFilterARB glad_glGetnConvolutionFilterARB +typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void* row, GLsizei columnBufSize, void* column, void* span); +GLAPI PFNGLGETNSEPARABLEFILTERARBPROC glad_glGetnSeparableFilterARB; +#define glGetnSeparableFilterARB glad_glGetnSeparableFilterARB +typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void* values); +GLAPI PFNGLGETNHISTOGRAMARBPROC glad_glGetnHistogramARB; +#define glGetnHistogramARB glad_glGetnHistogramARB +typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void* values); +GLAPI PFNGLGETNMINMAXARBPROC glad_glGetnMinmaxARB; +#define glGetnMinmaxARB glad_glGetnMinmaxARB +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/linmath.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/linmath.h new file mode 100644 index 00000000..5732a76a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/linmath.h @@ -0,0 +1,574 @@ +#ifndef LINMATH_H +#define LINMATH_H + +#include + +#ifdef _MSC_VER +#define inline __inline +#endif + +#define LINMATH_H_DEFINE_VEC(n) \ +typedef float vec##n[n]; \ +static inline void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \ +{ \ + int i; \ + for(i=0; i 1e-4) { + mat4x4 T, C, S; + + vec3_norm(u, u); + mat4x4_from_vec3_mul_outer(T, u, u); + + S[1][2] = u[0]; + S[2][1] = -u[0]; + S[2][0] = u[1]; + S[0][2] = -u[1]; + S[0][1] = u[2]; + S[1][0] = -u[2]; + + mat4x4_scale(S, S, s); + + mat4x4_identity(C); + mat4x4_sub(C, C, T); + + mat4x4_scale(C, C, c); + + mat4x4_add(T, T, C); + mat4x4_add(T, T, S); + + T[3][3] = 1.; + mat4x4_mul(R, M, T); + } else { + mat4x4_dup(R, M); + } +} +static inline void mat4x4_rotate_X(mat4x4 Q, mat4x4 M, float angle) +{ + float s = sinf(angle); + float c = cosf(angle); + mat4x4 R = { + {1.f, 0.f, 0.f, 0.f}, + {0.f, c, s, 0.f}, + {0.f, -s, c, 0.f}, + {0.f, 0.f, 0.f, 1.f} + }; + mat4x4_mul(Q, M, R); +} +static inline void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle) +{ + float s = sinf(angle); + float c = cosf(angle); + mat4x4 R = { + { c, 0.f, s, 0.f}, + { 0.f, 1.f, 0.f, 0.f}, + { -s, 0.f, c, 0.f}, + { 0.f, 0.f, 0.f, 1.f} + }; + mat4x4_mul(Q, M, R); +} +static inline void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle) +{ + float s = sinf(angle); + float c = cosf(angle); + mat4x4 R = { + { c, s, 0.f, 0.f}, + { -s, c, 0.f, 0.f}, + { 0.f, 0.f, 1.f, 0.f}, + { 0.f, 0.f, 0.f, 1.f} + }; + mat4x4_mul(Q, M, R); +} +static inline void mat4x4_invert(mat4x4 T, mat4x4 M) +{ + float idet; + float s[6]; + float c[6]; + s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1]; + s[1] = M[0][0]*M[1][2] - M[1][0]*M[0][2]; + s[2] = M[0][0]*M[1][3] - M[1][0]*M[0][3]; + s[3] = M[0][1]*M[1][2] - M[1][1]*M[0][2]; + s[4] = M[0][1]*M[1][3] - M[1][1]*M[0][3]; + s[5] = M[0][2]*M[1][3] - M[1][2]*M[0][3]; + + c[0] = M[2][0]*M[3][1] - M[3][0]*M[2][1]; + c[1] = M[2][0]*M[3][2] - M[3][0]*M[2][2]; + c[2] = M[2][0]*M[3][3] - M[3][0]*M[2][3]; + c[3] = M[2][1]*M[3][2] - M[3][1]*M[2][2]; + c[4] = M[2][1]*M[3][3] - M[3][1]*M[2][3]; + c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3]; + + /* Assumes it is invertible */ + idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] ); + + T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet; + T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet; + T[0][2] = ( M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet; + T[0][3] = (-M[2][1] * s[5] + M[2][2] * s[4] - M[2][3] * s[3]) * idet; + + T[1][0] = (-M[1][0] * c[5] + M[1][2] * c[2] - M[1][3] * c[1]) * idet; + T[1][1] = ( M[0][0] * c[5] - M[0][2] * c[2] + M[0][3] * c[1]) * idet; + T[1][2] = (-M[3][0] * s[5] + M[3][2] * s[2] - M[3][3] * s[1]) * idet; + T[1][3] = ( M[2][0] * s[5] - M[2][2] * s[2] + M[2][3] * s[1]) * idet; + + T[2][0] = ( M[1][0] * c[4] - M[1][1] * c[2] + M[1][3] * c[0]) * idet; + T[2][1] = (-M[0][0] * c[4] + M[0][1] * c[2] - M[0][3] * c[0]) * idet; + T[2][2] = ( M[3][0] * s[4] - M[3][1] * s[2] + M[3][3] * s[0]) * idet; + T[2][3] = (-M[2][0] * s[4] + M[2][1] * s[2] - M[2][3] * s[0]) * idet; + + T[3][0] = (-M[1][0] * c[3] + M[1][1] * c[1] - M[1][2] * c[0]) * idet; + T[3][1] = ( M[0][0] * c[3] - M[0][1] * c[1] + M[0][2] * c[0]) * idet; + T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet; + T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet; +} +static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M) +{ + float s = 1.; + vec3 h; + + mat4x4_dup(R, M); + vec3_norm(R[2], R[2]); + + s = vec3_mul_inner(R[1], R[2]); + vec3_scale(h, R[2], s); + vec3_sub(R[1], R[1], h); + vec3_norm(R[2], R[2]); + + s = vec3_mul_inner(R[1], R[2]); + vec3_scale(h, R[2], s); + vec3_sub(R[1], R[1], h); + vec3_norm(R[1], R[1]); + + s = vec3_mul_inner(R[0], R[1]); + vec3_scale(h, R[1], s); + vec3_sub(R[0], R[0], h); + vec3_norm(R[0], R[0]); +} + +static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f) +{ + M[0][0] = 2.f*n/(r-l); + M[0][1] = M[0][2] = M[0][3] = 0.f; + + M[1][1] = 2.f*n/(t-b); + M[1][0] = M[1][2] = M[1][3] = 0.f; + + M[2][0] = (r+l)/(r-l); + M[2][1] = (t+b)/(t-b); + M[2][2] = -(f+n)/(f-n); + M[2][3] = -1.f; + + M[3][2] = -2.f*(f*n)/(f-n); + M[3][0] = M[3][1] = M[3][3] = 0.f; +} +static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f) +{ + M[0][0] = 2.f/(r-l); + M[0][1] = M[0][2] = M[0][3] = 0.f; + + M[1][1] = 2.f/(t-b); + M[1][0] = M[1][2] = M[1][3] = 0.f; + + M[2][2] = -2.f/(f-n); + M[2][0] = M[2][1] = M[2][3] = 0.f; + + M[3][0] = -(r+l)/(r-l); + M[3][1] = -(t+b)/(t-b); + M[3][2] = -(f+n)/(f-n); + M[3][3] = 1.f; +} +static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f) +{ + /* NOTE: Degrees are an unhandy unit to work with. + * linmath.h uses radians for everything! */ + float const a = 1.f / (float) tan(y_fov / 2.f); + + m[0][0] = a / aspect; + m[0][1] = 0.f; + m[0][2] = 0.f; + m[0][3] = 0.f; + + m[1][0] = 0.f; + m[1][1] = a; + m[1][2] = 0.f; + m[1][3] = 0.f; + + m[2][0] = 0.f; + m[2][1] = 0.f; + m[2][2] = -((f + n) / (f - n)); + m[2][3] = -1.f; + + m[3][0] = 0.f; + m[3][1] = 0.f; + m[3][2] = -((2.f * f * n) / (f - n)); + m[3][3] = 0.f; +} +static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up) +{ + /* Adapted from Android's OpenGL Matrix.java. */ + /* See the OpenGL GLUT documentation for gluLookAt for a description */ + /* of the algorithm. We implement it in a straightforward way: */ + + /* TODO: The negation of of can be spared by swapping the order of + * operands in the following cross products in the right way. */ + vec3 f; + vec3 s; + vec3 t; + + vec3_sub(f, center, eye); + vec3_norm(f, f); + + vec3_mul_cross(s, f, up); + vec3_norm(s, s); + + vec3_mul_cross(t, s, f); + + m[0][0] = s[0]; + m[0][1] = t[0]; + m[0][2] = -f[0]; + m[0][3] = 0.f; + + m[1][0] = s[1]; + m[1][1] = t[1]; + m[1][2] = -f[1]; + m[1][3] = 0.f; + + m[2][0] = s[2]; + m[2][1] = t[2]; + m[2][2] = -f[2]; + m[2][3] = 0.f; + + m[3][0] = 0.f; + m[3][1] = 0.f; + m[3][2] = 0.f; + m[3][3] = 1.f; + + mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]); +} + +typedef float quat[4]; +static inline void quat_identity(quat q) +{ + q[0] = q[1] = q[2] = 0.f; + q[3] = 1.f; +} +static inline void quat_add(quat r, quat a, quat b) +{ + int i; + for(i=0; i<4; ++i) + r[i] = a[i] + b[i]; +} +static inline void quat_sub(quat r, quat a, quat b) +{ + int i; + for(i=0; i<4; ++i) + r[i] = a[i] - b[i]; +} +static inline void quat_mul(quat r, quat p, quat q) +{ + vec3 w; + vec3_mul_cross(r, p, q); + vec3_scale(w, p, q[3]); + vec3_add(r, r, w); + vec3_scale(w, q, p[3]); + vec3_add(r, r, w); + r[3] = p[3]*q[3] - vec3_mul_inner(p, q); +} +static inline void quat_scale(quat r, quat v, float s) +{ + int i; + for(i=0; i<4; ++i) + r[i] = v[i] * s; +} +static inline float quat_inner_product(quat a, quat b) +{ + float p = 0.f; + int i; + for(i=0; i<4; ++i) + p += b[i]*a[i]; + return p; +} +static inline void quat_conj(quat r, quat q) +{ + int i; + for(i=0; i<3; ++i) + r[i] = -q[i]; + r[3] = q[3]; +} +static inline void quat_rotate(quat r, float angle, vec3 axis) { + int i; + vec3 v; + vec3_scale(v, axis, sinf(angle / 2)); + for(i=0; i<3; ++i) + r[i] = v[i]; + r[3] = cosf(angle / 2); +} +#define quat_norm vec4_norm +static inline void quat_mul_vec3(vec3 r, quat q, vec3 v) +{ +/* + * Method by Fabian 'ryg' Giessen (of Farbrausch) +t = 2 * cross(q.xyz, v) +v' = v + q.w * t + cross(q.xyz, t) + */ + vec3 t = {q[0], q[1], q[2]}; + vec3 u = {q[0], q[1], q[2]}; + + vec3_mul_cross(t, t, v); + vec3_scale(t, t, 2); + + vec3_mul_cross(u, u, t); + vec3_scale(t, t, q[3]); + + vec3_add(r, v, t); + vec3_add(r, r, u); +} +static inline void mat4x4_from_quat(mat4x4 M, quat q) +{ + float a = q[3]; + float b = q[0]; + float c = q[1]; + float d = q[2]; + float a2 = a*a; + float b2 = b*b; + float c2 = c*c; + float d2 = d*d; + + M[0][0] = a2 + b2 - c2 - d2; + M[0][1] = 2.f*(b*c + a*d); + M[0][2] = 2.f*(b*d - a*c); + M[0][3] = 0.f; + + M[1][0] = 2*(b*c - a*d); + M[1][1] = a2 - b2 + c2 - d2; + M[1][2] = 2.f*(c*d + a*b); + M[1][3] = 0.f; + + M[2][0] = 2.f*(b*d + a*c); + M[2][1] = 2.f*(c*d - a*b); + M[2][2] = a2 - b2 - c2 + d2; + M[2][3] = 0.f; + + M[3][0] = M[3][1] = M[3][2] = 0.f; + M[3][3] = 1.f; +} + +static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q) +{ +/* XXX: The way this is written only works for othogonal matrices. */ +/* TODO: Take care of non-orthogonal case. */ + quat_mul_vec3(R[0], q, M[0]); + quat_mul_vec3(R[1], q, M[1]); + quat_mul_vec3(R[2], q, M[2]); + + R[3][0] = R[3][1] = R[3][2] = 0.f; + R[3][3] = 1.f; +} +static inline void quat_from_mat4x4(quat q, mat4x4 M) +{ + float r=0.f; + int i; + + int perm[] = { 0, 1, 2, 0, 1 }; + int *p = perm; + + for(i = 0; i<3; i++) { + float m = M[i][i]; + if( m < r ) + continue; + m = r; + p = &perm[i]; + } + + r = (float) sqrt(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]] ); + + if(r < 1e-6) { + q[0] = 1.f; + q[1] = q[2] = q[3] = 0.f; + return; + } + + q[0] = r/2.f; + q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]])/(2.f*r); + q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]])/(2.f*r); + q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]])/(2.f*r); +} + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/mingw/_mingw_dxhelper.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/mingw/_mingw_dxhelper.h new file mode 100644 index 00000000..849e2914 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/mingw/_mingw_dxhelper.h @@ -0,0 +1,117 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#if defined(_MSC_VER) && !defined(_MSC_EXTENSIONS) +#define NONAMELESSUNION 1 +#endif +#if defined(NONAMELESSSTRUCT) && \ + !defined(NONAMELESSUNION) +#define NONAMELESSUNION 1 +#endif +#if defined(NONAMELESSUNION) && \ + !defined(NONAMELESSSTRUCT) +#define NONAMELESSSTRUCT 1 +#endif +#if !defined(__GNU_EXTENSION) +#if defined(__GNUC__) || defined(__GNUG__) +#define __GNU_EXTENSION __extension__ +#else +#define __GNU_EXTENSION +#endif +#endif /* __extension__ */ + +#ifndef __ANONYMOUS_DEFINED +#define __ANONYMOUS_DEFINED +#if defined(__GNUC__) || defined(__GNUG__) +#define _ANONYMOUS_UNION __extension__ +#define _ANONYMOUS_STRUCT __extension__ +#else +#define _ANONYMOUS_UNION +#define _ANONYMOUS_STRUCT +#endif +#ifndef NONAMELESSUNION +#define _UNION_NAME(x) +#define _STRUCT_NAME(x) +#else /* NONAMELESSUNION */ +#define _UNION_NAME(x) x +#define _STRUCT_NAME(x) x +#endif +#endif /* __ANONYMOUS_DEFINED */ + +#ifndef DUMMYUNIONNAME +# ifdef NONAMELESSUNION +# define DUMMYUNIONNAME u +# define DUMMYUNIONNAME1 u1 /* Wine uses this variant */ +# define DUMMYUNIONNAME2 u2 +# define DUMMYUNIONNAME3 u3 +# define DUMMYUNIONNAME4 u4 +# define DUMMYUNIONNAME5 u5 +# define DUMMYUNIONNAME6 u6 +# define DUMMYUNIONNAME7 u7 +# define DUMMYUNIONNAME8 u8 +# define DUMMYUNIONNAME9 u9 +# else /* NONAMELESSUNION */ +# define DUMMYUNIONNAME +# define DUMMYUNIONNAME1 /* Wine uses this variant */ +# define DUMMYUNIONNAME2 +# define DUMMYUNIONNAME3 +# define DUMMYUNIONNAME4 +# define DUMMYUNIONNAME5 +# define DUMMYUNIONNAME6 +# define DUMMYUNIONNAME7 +# define DUMMYUNIONNAME8 +# define DUMMYUNIONNAME9 +# endif +#endif /* DUMMYUNIONNAME */ + +#if !defined(DUMMYUNIONNAME1) /* MinGW does not define this one */ +# ifdef NONAMELESSUNION +# define DUMMYUNIONNAME1 u1 /* Wine uses this variant */ +# else +# define DUMMYUNIONNAME1 /* Wine uses this variant */ +# endif +#endif /* DUMMYUNIONNAME1 */ + +#ifndef DUMMYSTRUCTNAME +# ifdef NONAMELESSUNION +# define DUMMYSTRUCTNAME s +# define DUMMYSTRUCTNAME1 s1 /* Wine uses this variant */ +# define DUMMYSTRUCTNAME2 s2 +# define DUMMYSTRUCTNAME3 s3 +# define DUMMYSTRUCTNAME4 s4 +# define DUMMYSTRUCTNAME5 s5 +# else +# define DUMMYSTRUCTNAME +# define DUMMYSTRUCTNAME1 /* Wine uses this variant */ +# define DUMMYSTRUCTNAME2 +# define DUMMYSTRUCTNAME3 +# define DUMMYSTRUCTNAME4 +# define DUMMYSTRUCTNAME5 +# endif +#endif /* DUMMYSTRUCTNAME */ + +/* These are for compatibility with the Wine source tree */ + +#ifndef WINELIB_NAME_AW +# ifdef __MINGW_NAME_AW +# define WINELIB_NAME_AW __MINGW_NAME_AW +# else +# ifdef UNICODE +# define WINELIB_NAME_AW(func) func##W +# else +# define WINELIB_NAME_AW(func) func##A +# endif +# endif +#endif /* WINELIB_NAME_AW */ + +#ifndef DECL_WINELIB_TYPE_AW +# ifdef __MINGW_TYPEDEF_AW +# define DECL_WINELIB_TYPE_AW __MINGW_TYPEDEF_AW +# else +# define DECL_WINELIB_TYPE_AW(type) typedef WINELIB_NAME_AW(type) type; +# endif +#endif /* DECL_WINELIB_TYPE_AW */ + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/mingw/dinput.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/mingw/dinput.h new file mode 100644 index 00000000..b5754802 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/mingw/dinput.h @@ -0,0 +1,2467 @@ +/* + * Copyright (C) the Wine project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __DINPUT_INCLUDED__ +#define __DINPUT_INCLUDED__ + +#define COM_NO_WINDOWS_H +#include +#include <_mingw_dxhelper.h> + +#ifndef DIRECTINPUT_VERSION +#define DIRECTINPUT_VERSION 0x0800 +#endif + +/* Classes */ +DEFINE_GUID(CLSID_DirectInput, 0x25E609E0,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(CLSID_DirectInputDevice, 0x25E609E1,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +DEFINE_GUID(CLSID_DirectInput8, 0x25E609E4,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(CLSID_DirectInputDevice8, 0x25E609E5,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +/* Interfaces */ +DEFINE_GUID(IID_IDirectInputA, 0x89521360,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputW, 0x89521361,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInput2A, 0x5944E662,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInput2W, 0x5944E663,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInput7A, 0x9A4CB684,0x236D,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE); +DEFINE_GUID(IID_IDirectInput7W, 0x9A4CB685,0x236D,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE); +DEFINE_GUID(IID_IDirectInput8A, 0xBF798030,0x483A,0x4DA2,0xAA,0x99,0x5D,0x64,0xED,0x36,0x97,0x00); +DEFINE_GUID(IID_IDirectInput8W, 0xBF798031,0x483A,0x4DA2,0xAA,0x99,0x5D,0x64,0xED,0x36,0x97,0x00); +DEFINE_GUID(IID_IDirectInputDeviceA, 0x5944E680,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDeviceW, 0x5944E681,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDevice2A, 0x5944E682,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDevice2W, 0x5944E683,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDevice7A, 0x57D7C6BC,0x2356,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE); +DEFINE_GUID(IID_IDirectInputDevice7W, 0x57D7C6BD,0x2356,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE); +DEFINE_GUID(IID_IDirectInputDevice8A, 0x54D41080,0xDC15,0x4833,0xA4,0x1B,0x74,0x8F,0x73,0xA3,0x81,0x79); +DEFINE_GUID(IID_IDirectInputDevice8W, 0x54D41081,0xDC15,0x4833,0xA4,0x1B,0x74,0x8F,0x73,0xA3,0x81,0x79); +DEFINE_GUID(IID_IDirectInputEffect, 0xE7E1F7C0,0x88D2,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); + +/* Predefined object types */ +DEFINE_GUID(GUID_XAxis, 0xA36D02E0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_YAxis, 0xA36D02E1,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_ZAxis, 0xA36D02E2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RxAxis,0xA36D02F4,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RyAxis,0xA36D02F5,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RzAxis,0xA36D02E3,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Slider,0xA36D02E4,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Button,0xA36D02F0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Key, 0x55728220,0xD33C,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_POV, 0xA36D02F2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Unknown,0xA36D02F3,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +/* Predefined product GUIDs */ +DEFINE_GUID(GUID_SysMouse, 0x6F1D2B60,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysKeyboard, 0x6F1D2B61,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Joystick, 0x6F1D2B70,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysMouseEm, 0x6F1D2B80,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysMouseEm2, 0x6F1D2B81,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysKeyboardEm, 0x6F1D2B82,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysKeyboardEm2,0x6F1D2B83,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +/* predefined forcefeedback effects */ +DEFINE_GUID(GUID_ConstantForce, 0x13541C20,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_RampForce, 0x13541C21,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Square, 0x13541C22,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Sine, 0x13541C23,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Triangle, 0x13541C24,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_SawtoothUp, 0x13541C25,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_SawtoothDown, 0x13541C26,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Spring, 0x13541C27,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Damper, 0x13541C28,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Inertia, 0x13541C29,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Friction, 0x13541C2A,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_CustomForce, 0x13541C2B,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); + +typedef struct IDirectInputA *LPDIRECTINPUTA; +typedef struct IDirectInputW *LPDIRECTINPUTW; +typedef struct IDirectInput2A *LPDIRECTINPUT2A; +typedef struct IDirectInput2W *LPDIRECTINPUT2W; +typedef struct IDirectInput7A *LPDIRECTINPUT7A; +typedef struct IDirectInput7W *LPDIRECTINPUT7W; +#if DIRECTINPUT_VERSION >= 0x0800 +typedef struct IDirectInput8A *LPDIRECTINPUT8A; +typedef struct IDirectInput8W *LPDIRECTINPUT8W; +#endif /* DI8 */ +typedef struct IDirectInputDeviceA *LPDIRECTINPUTDEVICEA; +typedef struct IDirectInputDeviceW *LPDIRECTINPUTDEVICEW; +#if DIRECTINPUT_VERSION >= 0x0500 +typedef struct IDirectInputDevice2A *LPDIRECTINPUTDEVICE2A; +typedef struct IDirectInputDevice2W *LPDIRECTINPUTDEVICE2W; +#endif /* DI5 */ +#if DIRECTINPUT_VERSION >= 0x0700 +typedef struct IDirectInputDevice7A *LPDIRECTINPUTDEVICE7A; +typedef struct IDirectInputDevice7W *LPDIRECTINPUTDEVICE7W; +#endif /* DI7 */ +#if DIRECTINPUT_VERSION >= 0x0800 +typedef struct IDirectInputDevice8A *LPDIRECTINPUTDEVICE8A; +typedef struct IDirectInputDevice8W *LPDIRECTINPUTDEVICE8W; +#endif /* DI8 */ +#if DIRECTINPUT_VERSION >= 0x0500 +typedef struct IDirectInputEffect *LPDIRECTINPUTEFFECT; +#endif /* DI5 */ +typedef struct SysKeyboardA *LPSYSKEYBOARDA; +typedef struct SysMouseA *LPSYSMOUSEA; + +#define IID_IDirectInput WINELIB_NAME_AW(IID_IDirectInput) +#define IDirectInput WINELIB_NAME_AW(IDirectInput) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUT) +#define IID_IDirectInput2 WINELIB_NAME_AW(IID_IDirectInput2) +#define IDirectInput2 WINELIB_NAME_AW(IDirectInput2) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUT2) +#define IID_IDirectInput7 WINELIB_NAME_AW(IID_IDirectInput7) +#define IDirectInput7 WINELIB_NAME_AW(IDirectInput7) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUT7) +#if DIRECTINPUT_VERSION >= 0x0800 +#define IID_IDirectInput8 WINELIB_NAME_AW(IID_IDirectInput8) +#define IDirectInput8 WINELIB_NAME_AW(IDirectInput8) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUT8) +#endif /* DI8 */ +#define IID_IDirectInputDevice WINELIB_NAME_AW(IID_IDirectInputDevice) +#define IDirectInputDevice WINELIB_NAME_AW(IDirectInputDevice) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE) +#if DIRECTINPUT_VERSION >= 0x0500 +#define IID_IDirectInputDevice2 WINELIB_NAME_AW(IID_IDirectInputDevice2) +#define IDirectInputDevice2 WINELIB_NAME_AW(IDirectInputDevice2) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE2) +#endif /* DI5 */ +#if DIRECTINPUT_VERSION >= 0x0700 +#define IID_IDirectInputDevice7 WINELIB_NAME_AW(IID_IDirectInputDevice7) +#define IDirectInputDevice7 WINELIB_NAME_AW(IDirectInputDevice7) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE7) +#endif /* DI7 */ +#if DIRECTINPUT_VERSION >= 0x0800 +#define IID_IDirectInputDevice8 WINELIB_NAME_AW(IID_IDirectInputDevice8) +#define IDirectInputDevice8 WINELIB_NAME_AW(IDirectInputDevice8) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE8) +#endif /* DI8 */ + +#define DI_OK S_OK +#define DI_NOTATTACHED S_FALSE +#define DI_BUFFEROVERFLOW S_FALSE +#define DI_PROPNOEFFECT S_FALSE +#define DI_NOEFFECT S_FALSE +#define DI_POLLEDDEVICE ((HRESULT)0x00000002L) +#define DI_DOWNLOADSKIPPED ((HRESULT)0x00000003L) +#define DI_EFFECTRESTARTED ((HRESULT)0x00000004L) +#define DI_TRUNCATED ((HRESULT)0x00000008L) +#define DI_SETTINGSNOTSAVED ((HRESULT)0x0000000BL) +#define DI_TRUNCATEDANDRESTARTED ((HRESULT)0x0000000CL) +#define DI_WRITEPROTECT ((HRESULT)0x00000013L) + +#define DIERR_OLDDIRECTINPUTVERSION \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_OLD_WIN_VERSION) +#define DIERR_BETADIRECTINPUTVERSION \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_RMODE_APP) +#define DIERR_BADDRIVERVER \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BAD_DRIVER_LEVEL) +#define DIERR_DEVICENOTREG REGDB_E_CLASSNOTREG +#define DIERR_NOTFOUND \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND) +#define DIERR_OBJECTNOTFOUND \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND) +#define DIERR_INVALIDPARAM E_INVALIDARG +#define DIERR_NOINTERFACE E_NOINTERFACE +#define DIERR_GENERIC E_FAIL +#define DIERR_OUTOFMEMORY E_OUTOFMEMORY +#define DIERR_UNSUPPORTED E_NOTIMPL +#define DIERR_NOTINITIALIZED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_READY) +#define DIERR_ALREADYINITIALIZED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_ALREADY_INITIALIZED) +#define DIERR_NOAGGREGATION CLASS_E_NOAGGREGATION +#define DIERR_OTHERAPPHASPRIO E_ACCESSDENIED +#define DIERR_INPUTLOST \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_READ_FAULT) +#define DIERR_ACQUIRED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BUSY) +#define DIERR_NOTACQUIRED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INVALID_ACCESS) +#define DIERR_READONLY E_ACCESSDENIED +#define DIERR_HANDLEEXISTS E_ACCESSDENIED +#ifndef E_PENDING +#define E_PENDING 0x8000000AL +#endif +#define DIERR_INSUFFICIENTPRIVS 0x80040200L +#define DIERR_DEVICEFULL 0x80040201L +#define DIERR_MOREDATA 0x80040202L +#define DIERR_NOTDOWNLOADED 0x80040203L +#define DIERR_HASEFFECTS 0x80040204L +#define DIERR_NOTEXCLUSIVEACQUIRED 0x80040205L +#define DIERR_INCOMPLETEEFFECT 0x80040206L +#define DIERR_NOTBUFFERED 0x80040207L +#define DIERR_EFFECTPLAYING 0x80040208L +#define DIERR_UNPLUGGED 0x80040209L +#define DIERR_REPORTFULL 0x8004020AL +#define DIERR_MAPFILEFAIL 0x8004020BL + +#define DIENUM_STOP 0 +#define DIENUM_CONTINUE 1 + +#define DIEDFL_ALLDEVICES 0x00000000 +#define DIEDFL_ATTACHEDONLY 0x00000001 +#define DIEDFL_FORCEFEEDBACK 0x00000100 +#define DIEDFL_INCLUDEALIASES 0x00010000 +#define DIEDFL_INCLUDEPHANTOMS 0x00020000 +#define DIEDFL_INCLUDEHIDDEN 0x00040000 + +#define DIDEVTYPE_DEVICE 1 +#define DIDEVTYPE_MOUSE 2 +#define DIDEVTYPE_KEYBOARD 3 +#define DIDEVTYPE_JOYSTICK 4 +#define DIDEVTYPE_HID 0x00010000 + +#define DI8DEVCLASS_ALL 0 +#define DI8DEVCLASS_DEVICE 1 +#define DI8DEVCLASS_POINTER 2 +#define DI8DEVCLASS_KEYBOARD 3 +#define DI8DEVCLASS_GAMECTRL 4 + +#define DI8DEVTYPE_DEVICE 0x11 +#define DI8DEVTYPE_MOUSE 0x12 +#define DI8DEVTYPE_KEYBOARD 0x13 +#define DI8DEVTYPE_JOYSTICK 0x14 +#define DI8DEVTYPE_GAMEPAD 0x15 +#define DI8DEVTYPE_DRIVING 0x16 +#define DI8DEVTYPE_FLIGHT 0x17 +#define DI8DEVTYPE_1STPERSON 0x18 +#define DI8DEVTYPE_DEVICECTRL 0x19 +#define DI8DEVTYPE_SCREENPOINTER 0x1A +#define DI8DEVTYPE_REMOTE 0x1B +#define DI8DEVTYPE_SUPPLEMENTAL 0x1C + +#define DIDEVTYPEMOUSE_UNKNOWN 1 +#define DIDEVTYPEMOUSE_TRADITIONAL 2 +#define DIDEVTYPEMOUSE_FINGERSTICK 3 +#define DIDEVTYPEMOUSE_TOUCHPAD 4 +#define DIDEVTYPEMOUSE_TRACKBALL 5 + +#define DIDEVTYPEKEYBOARD_UNKNOWN 0 +#define DIDEVTYPEKEYBOARD_PCXT 1 +#define DIDEVTYPEKEYBOARD_OLIVETTI 2 +#define DIDEVTYPEKEYBOARD_PCAT 3 +#define DIDEVTYPEKEYBOARD_PCENH 4 +#define DIDEVTYPEKEYBOARD_NOKIA1050 5 +#define DIDEVTYPEKEYBOARD_NOKIA9140 6 +#define DIDEVTYPEKEYBOARD_NEC98 7 +#define DIDEVTYPEKEYBOARD_NEC98LAPTOP 8 +#define DIDEVTYPEKEYBOARD_NEC98106 9 +#define DIDEVTYPEKEYBOARD_JAPAN106 10 +#define DIDEVTYPEKEYBOARD_JAPANAX 11 +#define DIDEVTYPEKEYBOARD_J3100 12 + +#define DIDEVTYPEJOYSTICK_UNKNOWN 1 +#define DIDEVTYPEJOYSTICK_TRADITIONAL 2 +#define DIDEVTYPEJOYSTICK_FLIGHTSTICK 3 +#define DIDEVTYPEJOYSTICK_GAMEPAD 4 +#define DIDEVTYPEJOYSTICK_RUDDER 5 +#define DIDEVTYPEJOYSTICK_WHEEL 6 +#define DIDEVTYPEJOYSTICK_HEADTRACKER 7 + +#define DI8DEVTYPEMOUSE_UNKNOWN 1 +#define DI8DEVTYPEMOUSE_TRADITIONAL 2 +#define DI8DEVTYPEMOUSE_FINGERSTICK 3 +#define DI8DEVTYPEMOUSE_TOUCHPAD 4 +#define DI8DEVTYPEMOUSE_TRACKBALL 5 +#define DI8DEVTYPEMOUSE_ABSOLUTE 6 + +#define DI8DEVTYPEKEYBOARD_UNKNOWN 0 +#define DI8DEVTYPEKEYBOARD_PCXT 1 +#define DI8DEVTYPEKEYBOARD_OLIVETTI 2 +#define DI8DEVTYPEKEYBOARD_PCAT 3 +#define DI8DEVTYPEKEYBOARD_PCENH 4 +#define DI8DEVTYPEKEYBOARD_NOKIA1050 5 +#define DI8DEVTYPEKEYBOARD_NOKIA9140 6 +#define DI8DEVTYPEKEYBOARD_NEC98 7 +#define DI8DEVTYPEKEYBOARD_NEC98LAPTOP 8 +#define DI8DEVTYPEKEYBOARD_NEC98106 9 +#define DI8DEVTYPEKEYBOARD_JAPAN106 10 +#define DI8DEVTYPEKEYBOARD_JAPANAX 11 +#define DI8DEVTYPEKEYBOARD_J3100 12 + +#define DI8DEVTYPE_LIMITEDGAMESUBTYPE 1 + +#define DI8DEVTYPEJOYSTICK_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPEJOYSTICK_STANDARD 2 + +#define DI8DEVTYPEGAMEPAD_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPEGAMEPAD_STANDARD 2 +#define DI8DEVTYPEGAMEPAD_TILT 3 + +#define DI8DEVTYPEDRIVING_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPEDRIVING_COMBINEDPEDALS 2 +#define DI8DEVTYPEDRIVING_DUALPEDALS 3 +#define DI8DEVTYPEDRIVING_THREEPEDALS 4 +#define DI8DEVTYPEDRIVING_HANDHELD 5 + +#define DI8DEVTYPEFLIGHT_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPEFLIGHT_STICK 2 +#define DI8DEVTYPEFLIGHT_YOKE 3 +#define DI8DEVTYPEFLIGHT_RC 4 + +#define DI8DEVTYPE1STPERSON_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPE1STPERSON_UNKNOWN 2 +#define DI8DEVTYPE1STPERSON_SIXDOF 3 +#define DI8DEVTYPE1STPERSON_SHOOTER 4 + +#define DI8DEVTYPESCREENPTR_UNKNOWN 2 +#define DI8DEVTYPESCREENPTR_LIGHTGUN 3 +#define DI8DEVTYPESCREENPTR_LIGHTPEN 4 +#define DI8DEVTYPESCREENPTR_TOUCH 5 + +#define DI8DEVTYPEREMOTE_UNKNOWN 2 + +#define DI8DEVTYPEDEVICECTRL_UNKNOWN 2 +#define DI8DEVTYPEDEVICECTRL_COMMSSELECTION 3 +#define DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED 4 + +#define DI8DEVTYPESUPPLEMENTAL_UNKNOWN 2 +#define DI8DEVTYPESUPPLEMENTAL_2NDHANDCONTROLLER 3 +#define DI8DEVTYPESUPPLEMENTAL_HEADTRACKER 4 +#define DI8DEVTYPESUPPLEMENTAL_HANDTRACKER 5 +#define DI8DEVTYPESUPPLEMENTAL_SHIFTSTICKGATE 6 +#define DI8DEVTYPESUPPLEMENTAL_SHIFTER 7 +#define DI8DEVTYPESUPPLEMENTAL_THROTTLE 8 +#define DI8DEVTYPESUPPLEMENTAL_SPLITTHROTTLE 9 +#define DI8DEVTYPESUPPLEMENTAL_COMBINEDPEDALS 10 +#define DI8DEVTYPESUPPLEMENTAL_DUALPEDALS 11 +#define DI8DEVTYPESUPPLEMENTAL_THREEPEDALS 12 +#define DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS 13 + +#define GET_DIDEVICE_TYPE(dwDevType) LOBYTE(dwDevType) +#define GET_DIDEVICE_SUBTYPE(dwDevType) HIBYTE(dwDevType) + +typedef struct DIDEVICEOBJECTINSTANCE_DX3A { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + CHAR tszName[MAX_PATH]; +} DIDEVICEOBJECTINSTANCE_DX3A, *LPDIDEVICEOBJECTINSTANCE_DX3A; +typedef const DIDEVICEOBJECTINSTANCE_DX3A *LPCDIDEVICEOBJECTINSTANCE_DX3A; +typedef struct DIDEVICEOBJECTINSTANCE_DX3W { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + WCHAR tszName[MAX_PATH]; +} DIDEVICEOBJECTINSTANCE_DX3W, *LPDIDEVICEOBJECTINSTANCE_DX3W; +typedef const DIDEVICEOBJECTINSTANCE_DX3W *LPCDIDEVICEOBJECTINSTANCE_DX3W; + +DECL_WINELIB_TYPE_AW(DIDEVICEOBJECTINSTANCE_DX3) +DECL_WINELIB_TYPE_AW(LPDIDEVICEOBJECTINSTANCE_DX3) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEOBJECTINSTANCE_DX3) + +typedef struct DIDEVICEOBJECTINSTANCEA { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + CHAR tszName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + DWORD dwFFMaxForce; + DWORD dwFFForceResolution; + WORD wCollectionNumber; + WORD wDesignatorIndex; + WORD wUsagePage; + WORD wUsage; + DWORD dwDimension; + WORD wExponent; + WORD wReserved; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEOBJECTINSTANCEA, *LPDIDEVICEOBJECTINSTANCEA; +typedef const DIDEVICEOBJECTINSTANCEA *LPCDIDEVICEOBJECTINSTANCEA; + +typedef struct DIDEVICEOBJECTINSTANCEW { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + WCHAR tszName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + DWORD dwFFMaxForce; + DWORD dwFFForceResolution; + WORD wCollectionNumber; + WORD wDesignatorIndex; + WORD wUsagePage; + WORD wUsage; + DWORD dwDimension; + WORD wExponent; + WORD wReserved; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEOBJECTINSTANCEW, *LPDIDEVICEOBJECTINSTANCEW; +typedef const DIDEVICEOBJECTINSTANCEW *LPCDIDEVICEOBJECTINSTANCEW; + +DECL_WINELIB_TYPE_AW(DIDEVICEOBJECTINSTANCE) +DECL_WINELIB_TYPE_AW(LPDIDEVICEOBJECTINSTANCE) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEOBJECTINSTANCE) + +typedef struct DIDEVICEINSTANCE_DX3A { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + CHAR tszInstanceName[MAX_PATH]; + CHAR tszProductName[MAX_PATH]; +} DIDEVICEINSTANCE_DX3A, *LPDIDEVICEINSTANCE_DX3A; +typedef const DIDEVICEINSTANCE_DX3A *LPCDIDEVICEINSTANCE_DX3A; +typedef struct DIDEVICEINSTANCE_DX3W { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + WCHAR tszInstanceName[MAX_PATH]; + WCHAR tszProductName[MAX_PATH]; +} DIDEVICEINSTANCE_DX3W, *LPDIDEVICEINSTANCE_DX3W; +typedef const DIDEVICEINSTANCE_DX3W *LPCDIDEVICEINSTANCE_DX3W; + +DECL_WINELIB_TYPE_AW(DIDEVICEINSTANCE_DX3) +DECL_WINELIB_TYPE_AW(LPDIDEVICEINSTANCE_DX3) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEINSTANCE_DX3) + +typedef struct DIDEVICEINSTANCEA { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + CHAR tszInstanceName[MAX_PATH]; + CHAR tszProductName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + GUID guidFFDriver; + WORD wUsagePage; + WORD wUsage; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEINSTANCEA, *LPDIDEVICEINSTANCEA; +typedef const DIDEVICEINSTANCEA *LPCDIDEVICEINSTANCEA; + +typedef struct DIDEVICEINSTANCEW { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + WCHAR tszInstanceName[MAX_PATH]; + WCHAR tszProductName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + GUID guidFFDriver; + WORD wUsagePage; + WORD wUsage; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEINSTANCEW, *LPDIDEVICEINSTANCEW; +typedef const DIDEVICEINSTANCEW *LPCDIDEVICEINSTANCEW; + +DECL_WINELIB_TYPE_AW(DIDEVICEINSTANCE) +DECL_WINELIB_TYPE_AW(LPDIDEVICEINSTANCE) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEINSTANCE) + +typedef BOOL (CALLBACK *LPDIENUMDEVICESCALLBACKA)(LPCDIDEVICEINSTANCEA,LPVOID); +typedef BOOL (CALLBACK *LPDIENUMDEVICESCALLBACKW)(LPCDIDEVICEINSTANCEW,LPVOID); +DECL_WINELIB_TYPE_AW(LPDIENUMDEVICESCALLBACK) + +#define DIEDBS_MAPPEDPRI1 0x00000001 +#define DIEDBS_MAPPEDPRI2 0x00000002 +#define DIEDBS_RECENTDEVICE 0x00000010 +#define DIEDBS_NEWDEVICE 0x00000020 + +#define DIEDBSFL_ATTACHEDONLY 0x00000000 +#define DIEDBSFL_THISUSER 0x00000010 +#define DIEDBSFL_FORCEFEEDBACK DIEDFL_FORCEFEEDBACK +#define DIEDBSFL_AVAILABLEDEVICES 0x00001000 +#define DIEDBSFL_MULTIMICEKEYBOARDS 0x00002000 +#define DIEDBSFL_NONGAMINGDEVICES 0x00004000 +#define DIEDBSFL_VALID 0x00007110 + +#if DIRECTINPUT_VERSION >= 0x0800 +typedef BOOL (CALLBACK *LPDIENUMDEVICESBYSEMANTICSCBA)(LPCDIDEVICEINSTANCEA,LPDIRECTINPUTDEVICE8A,DWORD,DWORD,LPVOID); +typedef BOOL (CALLBACK *LPDIENUMDEVICESBYSEMANTICSCBW)(LPCDIDEVICEINSTANCEW,LPDIRECTINPUTDEVICE8W,DWORD,DWORD,LPVOID); +DECL_WINELIB_TYPE_AW(LPDIENUMDEVICESBYSEMANTICSCB) +#endif + +typedef BOOL (CALLBACK *LPDICONFIGUREDEVICESCALLBACK)(LPUNKNOWN,LPVOID); + +typedef BOOL (CALLBACK *LPDIENUMDEVICEOBJECTSCALLBACKA)(LPCDIDEVICEOBJECTINSTANCEA,LPVOID); +typedef BOOL (CALLBACK *LPDIENUMDEVICEOBJECTSCALLBACKW)(LPCDIDEVICEOBJECTINSTANCEW,LPVOID); +DECL_WINELIB_TYPE_AW(LPDIENUMDEVICEOBJECTSCALLBACK) + +#if DIRECTINPUT_VERSION >= 0x0500 +typedef BOOL (CALLBACK *LPDIENUMCREATEDEFFECTOBJECTSCALLBACK)(LPDIRECTINPUTEFFECT, LPVOID); +#endif + +#define DIK_ESCAPE 0x01 +#define DIK_1 0x02 +#define DIK_2 0x03 +#define DIK_3 0x04 +#define DIK_4 0x05 +#define DIK_5 0x06 +#define DIK_6 0x07 +#define DIK_7 0x08 +#define DIK_8 0x09 +#define DIK_9 0x0A +#define DIK_0 0x0B +#define DIK_MINUS 0x0C /* - on main keyboard */ +#define DIK_EQUALS 0x0D +#define DIK_BACK 0x0E /* backspace */ +#define DIK_TAB 0x0F +#define DIK_Q 0x10 +#define DIK_W 0x11 +#define DIK_E 0x12 +#define DIK_R 0x13 +#define DIK_T 0x14 +#define DIK_Y 0x15 +#define DIK_U 0x16 +#define DIK_I 0x17 +#define DIK_O 0x18 +#define DIK_P 0x19 +#define DIK_LBRACKET 0x1A +#define DIK_RBRACKET 0x1B +#define DIK_RETURN 0x1C /* Enter on main keyboard */ +#define DIK_LCONTROL 0x1D +#define DIK_A 0x1E +#define DIK_S 0x1F +#define DIK_D 0x20 +#define DIK_F 0x21 +#define DIK_G 0x22 +#define DIK_H 0x23 +#define DIK_J 0x24 +#define DIK_K 0x25 +#define DIK_L 0x26 +#define DIK_SEMICOLON 0x27 +#define DIK_APOSTROPHE 0x28 +#define DIK_GRAVE 0x29 /* accent grave */ +#define DIK_LSHIFT 0x2A +#define DIK_BACKSLASH 0x2B +#define DIK_Z 0x2C +#define DIK_X 0x2D +#define DIK_C 0x2E +#define DIK_V 0x2F +#define DIK_B 0x30 +#define DIK_N 0x31 +#define DIK_M 0x32 +#define DIK_COMMA 0x33 +#define DIK_PERIOD 0x34 /* . on main keyboard */ +#define DIK_SLASH 0x35 /* / on main keyboard */ +#define DIK_RSHIFT 0x36 +#define DIK_MULTIPLY 0x37 /* * on numeric keypad */ +#define DIK_LMENU 0x38 /* left Alt */ +#define DIK_SPACE 0x39 +#define DIK_CAPITAL 0x3A +#define DIK_F1 0x3B +#define DIK_F2 0x3C +#define DIK_F3 0x3D +#define DIK_F4 0x3E +#define DIK_F5 0x3F +#define DIK_F6 0x40 +#define DIK_F7 0x41 +#define DIK_F8 0x42 +#define DIK_F9 0x43 +#define DIK_F10 0x44 +#define DIK_NUMLOCK 0x45 +#define DIK_SCROLL 0x46 /* Scroll Lock */ +#define DIK_NUMPAD7 0x47 +#define DIK_NUMPAD8 0x48 +#define DIK_NUMPAD9 0x49 +#define DIK_SUBTRACT 0x4A /* - on numeric keypad */ +#define DIK_NUMPAD4 0x4B +#define DIK_NUMPAD5 0x4C +#define DIK_NUMPAD6 0x4D +#define DIK_ADD 0x4E /* + on numeric keypad */ +#define DIK_NUMPAD1 0x4F +#define DIK_NUMPAD2 0x50 +#define DIK_NUMPAD3 0x51 +#define DIK_NUMPAD0 0x52 +#define DIK_DECIMAL 0x53 /* . on numeric keypad */ +#define DIK_OEM_102 0x56 /* < > | on UK/Germany keyboards */ +#define DIK_F11 0x57 +#define DIK_F12 0x58 +#define DIK_F13 0x64 /* (NEC PC98) */ +#define DIK_F14 0x65 /* (NEC PC98) */ +#define DIK_F15 0x66 /* (NEC PC98) */ +#define DIK_KANA 0x70 /* (Japanese keyboard) */ +#define DIK_ABNT_C1 0x73 /* / ? on Portugese (Brazilian) keyboards */ +#define DIK_CONVERT 0x79 /* (Japanese keyboard) */ +#define DIK_NOCONVERT 0x7B /* (Japanese keyboard) */ +#define DIK_YEN 0x7D /* (Japanese keyboard) */ +#define DIK_ABNT_C2 0x7E /* Numpad . on Portugese (Brazilian) keyboards */ +#define DIK_NUMPADEQUALS 0x8D /* = on numeric keypad (NEC PC98) */ +#define DIK_CIRCUMFLEX 0x90 /* (Japanese keyboard) */ +#define DIK_AT 0x91 /* (NEC PC98) */ +#define DIK_COLON 0x92 /* (NEC PC98) */ +#define DIK_UNDERLINE 0x93 /* (NEC PC98) */ +#define DIK_KANJI 0x94 /* (Japanese keyboard) */ +#define DIK_STOP 0x95 /* (NEC PC98) */ +#define DIK_AX 0x96 /* (Japan AX) */ +#define DIK_UNLABELED 0x97 /* (J3100) */ +#define DIK_NEXTTRACK 0x99 /* Next Track */ +#define DIK_NUMPADENTER 0x9C /* Enter on numeric keypad */ +#define DIK_RCONTROL 0x9D +#define DIK_MUTE 0xA0 /* Mute */ +#define DIK_CALCULATOR 0xA1 /* Calculator */ +#define DIK_PLAYPAUSE 0xA2 /* Play / Pause */ +#define DIK_MEDIASTOP 0xA4 /* Media Stop */ +#define DIK_VOLUMEDOWN 0xAE /* Volume - */ +#define DIK_VOLUMEUP 0xB0 /* Volume + */ +#define DIK_WEBHOME 0xB2 /* Web home */ +#define DIK_NUMPADCOMMA 0xB3 /* , on numeric keypad (NEC PC98) */ +#define DIK_DIVIDE 0xB5 /* / on numeric keypad */ +#define DIK_SYSRQ 0xB7 +#define DIK_RMENU 0xB8 /* right Alt */ +#define DIK_PAUSE 0xC5 /* Pause */ +#define DIK_HOME 0xC7 /* Home on arrow keypad */ +#define DIK_UP 0xC8 /* UpArrow on arrow keypad */ +#define DIK_PRIOR 0xC9 /* PgUp on arrow keypad */ +#define DIK_LEFT 0xCB /* LeftArrow on arrow keypad */ +#define DIK_RIGHT 0xCD /* RightArrow on arrow keypad */ +#define DIK_END 0xCF /* End on arrow keypad */ +#define DIK_DOWN 0xD0 /* DownArrow on arrow keypad */ +#define DIK_NEXT 0xD1 /* PgDn on arrow keypad */ +#define DIK_INSERT 0xD2 /* Insert on arrow keypad */ +#define DIK_DELETE 0xD3 /* Delete on arrow keypad */ +#define DIK_LWIN 0xDB /* Left Windows key */ +#define DIK_RWIN 0xDC /* Right Windows key */ +#define DIK_APPS 0xDD /* AppMenu key */ +#define DIK_POWER 0xDE +#define DIK_SLEEP 0xDF +#define DIK_WAKE 0xE3 /* System Wake */ +#define DIK_WEBSEARCH 0xE5 /* Web Search */ +#define DIK_WEBFAVORITES 0xE6 /* Web Favorites */ +#define DIK_WEBREFRESH 0xE7 /* Web Refresh */ +#define DIK_WEBSTOP 0xE8 /* Web Stop */ +#define DIK_WEBFORWARD 0xE9 /* Web Forward */ +#define DIK_WEBBACK 0xEA /* Web Back */ +#define DIK_MYCOMPUTER 0xEB /* My Computer */ +#define DIK_MAIL 0xEC /* Mail */ +#define DIK_MEDIASELECT 0xED /* Media Select */ + +#define DIK_BACKSPACE DIK_BACK /* backspace */ +#define DIK_NUMPADSTAR DIK_MULTIPLY /* * on numeric keypad */ +#define DIK_LALT DIK_LMENU /* left Alt */ +#define DIK_CAPSLOCK DIK_CAPITAL /* CapsLock */ +#define DIK_NUMPADMINUS DIK_SUBTRACT /* - on numeric keypad */ +#define DIK_NUMPADPLUS DIK_ADD /* + on numeric keypad */ +#define DIK_NUMPADPERIOD DIK_DECIMAL /* . on numeric keypad */ +#define DIK_NUMPADSLASH DIK_DIVIDE /* / on numeric keypad */ +#define DIK_RALT DIK_RMENU /* right Alt */ +#define DIK_UPARROW DIK_UP /* UpArrow on arrow keypad */ +#define DIK_PGUP DIK_PRIOR /* PgUp on arrow keypad */ +#define DIK_LEFTARROW DIK_LEFT /* LeftArrow on arrow keypad */ +#define DIK_RIGHTARROW DIK_RIGHT /* RightArrow on arrow keypad */ +#define DIK_DOWNARROW DIK_DOWN /* DownArrow on arrow keypad */ +#define DIK_PGDN DIK_NEXT /* PgDn on arrow keypad */ + +#define DIDFT_ALL 0x00000000 +#define DIDFT_RELAXIS 0x00000001 +#define DIDFT_ABSAXIS 0x00000002 +#define DIDFT_AXIS 0x00000003 +#define DIDFT_PSHBUTTON 0x00000004 +#define DIDFT_TGLBUTTON 0x00000008 +#define DIDFT_BUTTON 0x0000000C +#define DIDFT_POV 0x00000010 +#define DIDFT_COLLECTION 0x00000040 +#define DIDFT_NODATA 0x00000080 +#define DIDFT_ANYINSTANCE 0x00FFFF00 +#define DIDFT_INSTANCEMASK DIDFT_ANYINSTANCE +#define DIDFT_MAKEINSTANCE(n) ((WORD)(n) << 8) +#define DIDFT_GETTYPE(n) LOBYTE(n) +#define DIDFT_GETINSTANCE(n) LOWORD((n) >> 8) +#define DIDFT_FFACTUATOR 0x01000000 +#define DIDFT_FFEFFECTTRIGGER 0x02000000 +#if DIRECTINPUT_VERSION >= 0x050a +#define DIDFT_OUTPUT 0x10000000 +#define DIDFT_VENDORDEFINED 0x04000000 +#define DIDFT_ALIAS 0x08000000 +#endif /* DI5a */ +#ifndef DIDFT_OPTIONAL +#define DIDFT_OPTIONAL 0x80000000 +#endif +#define DIDFT_ENUMCOLLECTION(n) ((WORD)(n) << 8) +#define DIDFT_NOCOLLECTION 0x00FFFF00 + +#define DIDF_ABSAXIS 0x00000001 +#define DIDF_RELAXIS 0x00000002 + +#define DIGDD_PEEK 0x00000001 + +#define DISEQUENCE_COMPARE(dwSq1,cmp,dwSq2) ((int)((dwSq1) - (dwSq2)) cmp 0) + +typedef struct DIDEVICEOBJECTDATA_DX3 { + DWORD dwOfs; + DWORD dwData; + DWORD dwTimeStamp; + DWORD dwSequence; +} DIDEVICEOBJECTDATA_DX3,*LPDIDEVICEOBJECTDATA_DX3; +typedef const DIDEVICEOBJECTDATA_DX3 *LPCDIDEVICEOBJECTDATA_DX3; + +typedef struct DIDEVICEOBJECTDATA { + DWORD dwOfs; + DWORD dwData; + DWORD dwTimeStamp; + DWORD dwSequence; +#if(DIRECTINPUT_VERSION >= 0x0800) + UINT_PTR uAppData; +#endif /* DIRECTINPUT_VERSION >= 0x0800 */ +} DIDEVICEOBJECTDATA, *LPDIDEVICEOBJECTDATA; +typedef const DIDEVICEOBJECTDATA *LPCDIDEVICEOBJECTDATA; + +typedef struct _DIOBJECTDATAFORMAT { + const GUID *pguid; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; +} DIOBJECTDATAFORMAT, *LPDIOBJECTDATAFORMAT; +typedef const DIOBJECTDATAFORMAT *LPCDIOBJECTDATAFORMAT; + +typedef struct _DIDATAFORMAT { + DWORD dwSize; + DWORD dwObjSize; + DWORD dwFlags; + DWORD dwDataSize; + DWORD dwNumObjs; + LPDIOBJECTDATAFORMAT rgodf; +} DIDATAFORMAT, *LPDIDATAFORMAT; +typedef const DIDATAFORMAT *LPCDIDATAFORMAT; + +#if DIRECTINPUT_VERSION >= 0x0500 +#define DIDOI_FFACTUATOR 0x00000001 +#define DIDOI_FFEFFECTTRIGGER 0x00000002 +#define DIDOI_POLLED 0x00008000 +#define DIDOI_ASPECTPOSITION 0x00000100 +#define DIDOI_ASPECTVELOCITY 0x00000200 +#define DIDOI_ASPECTACCEL 0x00000300 +#define DIDOI_ASPECTFORCE 0x00000400 +#define DIDOI_ASPECTMASK 0x00000F00 +#endif /* DI5 */ +#if DIRECTINPUT_VERSION >= 0x050a +#define DIDOI_GUIDISUSAGE 0x00010000 +#endif /* DI5a */ + +typedef struct DIPROPHEADER { + DWORD dwSize; + DWORD dwHeaderSize; + DWORD dwObj; + DWORD dwHow; +} DIPROPHEADER,*LPDIPROPHEADER; +typedef const DIPROPHEADER *LPCDIPROPHEADER; + +#define DIPH_DEVICE 0 +#define DIPH_BYOFFSET 1 +#define DIPH_BYID 2 +#if DIRECTINPUT_VERSION >= 0x050a +#define DIPH_BYUSAGE 3 + +#define DIMAKEUSAGEDWORD(UsagePage, Usage) (DWORD)MAKELONG(Usage, UsagePage) +#endif /* DI5a */ + +typedef struct DIPROPDWORD { + DIPROPHEADER diph; + DWORD dwData; +} DIPROPDWORD, *LPDIPROPDWORD; +typedef const DIPROPDWORD *LPCDIPROPDWORD; + +typedef struct DIPROPRANGE { + DIPROPHEADER diph; + LONG lMin; + LONG lMax; +} DIPROPRANGE, *LPDIPROPRANGE; +typedef const DIPROPRANGE *LPCDIPROPRANGE; + +#define DIPROPRANGE_NOMIN ((LONG)0x80000000) +#define DIPROPRANGE_NOMAX ((LONG)0x7FFFFFFF) + +#if DIRECTINPUT_VERSION >= 0x050a +typedef struct DIPROPCAL { + DIPROPHEADER diph; + LONG lMin; + LONG lCenter; + LONG lMax; +} DIPROPCAL, *LPDIPROPCAL; +typedef const DIPROPCAL *LPCDIPROPCAL; + +typedef struct DIPROPCALPOV { + DIPROPHEADER diph; + LONG lMin[5]; + LONG lMax[5]; +} DIPROPCALPOV, *LPDIPROPCALPOV; +typedef const DIPROPCALPOV *LPCDIPROPCALPOV; + +typedef struct DIPROPGUIDANDPATH { + DIPROPHEADER diph; + GUID guidClass; + WCHAR wszPath[MAX_PATH]; +} DIPROPGUIDANDPATH, *LPDIPROPGUIDANDPATH; +typedef const DIPROPGUIDANDPATH *LPCDIPROPGUIDANDPATH; + +typedef struct DIPROPSTRING { + DIPROPHEADER diph; + WCHAR wsz[MAX_PATH]; +} DIPROPSTRING, *LPDIPROPSTRING; +typedef const DIPROPSTRING *LPCDIPROPSTRING; +#endif /* DI5a */ + +#if DIRECTINPUT_VERSION >= 0x0800 +typedef struct DIPROPPOINTER { + DIPROPHEADER diph; + UINT_PTR uData; +} DIPROPPOINTER, *LPDIPROPPOINTER; +typedef const DIPROPPOINTER *LPCDIPROPPOINTER; +#endif /* DI8 */ + +/* special property GUIDs */ +#ifdef __cplusplus +#define MAKEDIPROP(prop) (*(const GUID *)(prop)) +#else +#define MAKEDIPROP(prop) ((REFGUID)(prop)) +#endif +#define DIPROP_BUFFERSIZE MAKEDIPROP(1) +#define DIPROP_AXISMODE MAKEDIPROP(2) + +#define DIPROPAXISMODE_ABS 0 +#define DIPROPAXISMODE_REL 1 + +#define DIPROP_GRANULARITY MAKEDIPROP(3) +#define DIPROP_RANGE MAKEDIPROP(4) +#define DIPROP_DEADZONE MAKEDIPROP(5) +#define DIPROP_SATURATION MAKEDIPROP(6) +#define DIPROP_FFGAIN MAKEDIPROP(7) +#define DIPROP_FFLOAD MAKEDIPROP(8) +#define DIPROP_AUTOCENTER MAKEDIPROP(9) + +#define DIPROPAUTOCENTER_OFF 0 +#define DIPROPAUTOCENTER_ON 1 + +#define DIPROP_CALIBRATIONMODE MAKEDIPROP(10) + +#define DIPROPCALIBRATIONMODE_COOKED 0 +#define DIPROPCALIBRATIONMODE_RAW 1 + +#if DIRECTINPUT_VERSION >= 0x050a +#define DIPROP_CALIBRATION MAKEDIPROP(11) +#define DIPROP_GUIDANDPATH MAKEDIPROP(12) +#define DIPROP_INSTANCENAME MAKEDIPROP(13) +#define DIPROP_PRODUCTNAME MAKEDIPROP(14) +#endif + +#if DIRECTINPUT_VERSION >= 0x5B2 +#define DIPROP_JOYSTICKID MAKEDIPROP(15) +#define DIPROP_GETPORTDISPLAYNAME MAKEDIPROP(16) +#endif + +#if DIRECTINPUT_VERSION >= 0x0700 +#define DIPROP_PHYSICALRANGE MAKEDIPROP(18) +#define DIPROP_LOGICALRANGE MAKEDIPROP(19) +#endif + +#if(DIRECTINPUT_VERSION >= 0x0800) +#define DIPROP_KEYNAME MAKEDIPROP(20) +#define DIPROP_CPOINTS MAKEDIPROP(21) +#define DIPROP_APPDATA MAKEDIPROP(22) +#define DIPROP_SCANCODE MAKEDIPROP(23) +#define DIPROP_VIDPID MAKEDIPROP(24) +#define DIPROP_USERNAME MAKEDIPROP(25) +#define DIPROP_TYPENAME MAKEDIPROP(26) + +#define MAXCPOINTSNUM 8 + +typedef struct _CPOINT { + LONG lP; + DWORD dwLog; +} CPOINT, *PCPOINT; + +typedef struct DIPROPCPOINTS { + DIPROPHEADER diph; + DWORD dwCPointsNum; + CPOINT cp[MAXCPOINTSNUM]; +} DIPROPCPOINTS, *LPDIPROPCPOINTS; +typedef const DIPROPCPOINTS *LPCDIPROPCPOINTS; +#endif /* DI8 */ + + +typedef struct DIDEVCAPS_DX3 { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDevType; + DWORD dwAxes; + DWORD dwButtons; + DWORD dwPOVs; +} DIDEVCAPS_DX3, *LPDIDEVCAPS_DX3; + +typedef struct DIDEVCAPS { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDevType; + DWORD dwAxes; + DWORD dwButtons; + DWORD dwPOVs; +#if(DIRECTINPUT_VERSION >= 0x0500) + DWORD dwFFSamplePeriod; + DWORD dwFFMinTimeResolution; + DWORD dwFirmwareRevision; + DWORD dwHardwareRevision; + DWORD dwFFDriverVersion; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVCAPS,*LPDIDEVCAPS; + +#define DIDC_ATTACHED 0x00000001 +#define DIDC_POLLEDDEVICE 0x00000002 +#define DIDC_EMULATED 0x00000004 +#define DIDC_POLLEDDATAFORMAT 0x00000008 +#define DIDC_FORCEFEEDBACK 0x00000100 +#define DIDC_FFATTACK 0x00000200 +#define DIDC_FFFADE 0x00000400 +#define DIDC_SATURATION 0x00000800 +#define DIDC_POSNEGCOEFFICIENTS 0x00001000 +#define DIDC_POSNEGSATURATION 0x00002000 +#define DIDC_DEADBAND 0x00004000 +#define DIDC_STARTDELAY 0x00008000 +#define DIDC_ALIAS 0x00010000 +#define DIDC_PHANTOM 0x00020000 +#define DIDC_HIDDEN 0x00040000 + + +/* SetCooperativeLevel dwFlags */ +#define DISCL_EXCLUSIVE 0x00000001 +#define DISCL_NONEXCLUSIVE 0x00000002 +#define DISCL_FOREGROUND 0x00000004 +#define DISCL_BACKGROUND 0x00000008 +#define DISCL_NOWINKEY 0x00000010 + +#if (DIRECTINPUT_VERSION >= 0x0500) +/* Device FF flags */ +#define DISFFC_RESET 0x00000001 +#define DISFFC_STOPALL 0x00000002 +#define DISFFC_PAUSE 0x00000004 +#define DISFFC_CONTINUE 0x00000008 +#define DISFFC_SETACTUATORSON 0x00000010 +#define DISFFC_SETACTUATORSOFF 0x00000020 + +#define DIGFFS_EMPTY 0x00000001 +#define DIGFFS_STOPPED 0x00000002 +#define DIGFFS_PAUSED 0x00000004 +#define DIGFFS_ACTUATORSON 0x00000010 +#define DIGFFS_ACTUATORSOFF 0x00000020 +#define DIGFFS_POWERON 0x00000040 +#define DIGFFS_POWEROFF 0x00000080 +#define DIGFFS_SAFETYSWITCHON 0x00000100 +#define DIGFFS_SAFETYSWITCHOFF 0x00000200 +#define DIGFFS_USERFFSWITCHON 0x00000400 +#define DIGFFS_USERFFSWITCHOFF 0x00000800 +#define DIGFFS_DEVICELOST 0x80000000 + +/* Effect flags */ +#define DIEFT_ALL 0x00000000 + +#define DIEFT_CONSTANTFORCE 0x00000001 +#define DIEFT_RAMPFORCE 0x00000002 +#define DIEFT_PERIODIC 0x00000003 +#define DIEFT_CONDITION 0x00000004 +#define DIEFT_CUSTOMFORCE 0x00000005 +#define DIEFT_HARDWARE 0x000000FF +#define DIEFT_FFATTACK 0x00000200 +#define DIEFT_FFFADE 0x00000400 +#define DIEFT_SATURATION 0x00000800 +#define DIEFT_POSNEGCOEFFICIENTS 0x00001000 +#define DIEFT_POSNEGSATURATION 0x00002000 +#define DIEFT_DEADBAND 0x00004000 +#define DIEFT_STARTDELAY 0x00008000 +#define DIEFT_GETTYPE(n) LOBYTE(n) + +#define DIEFF_OBJECTIDS 0x00000001 +#define DIEFF_OBJECTOFFSETS 0x00000002 +#define DIEFF_CARTESIAN 0x00000010 +#define DIEFF_POLAR 0x00000020 +#define DIEFF_SPHERICAL 0x00000040 + +#define DIEP_DURATION 0x00000001 +#define DIEP_SAMPLEPERIOD 0x00000002 +#define DIEP_GAIN 0x00000004 +#define DIEP_TRIGGERBUTTON 0x00000008 +#define DIEP_TRIGGERREPEATINTERVAL 0x00000010 +#define DIEP_AXES 0x00000020 +#define DIEP_DIRECTION 0x00000040 +#define DIEP_ENVELOPE 0x00000080 +#define DIEP_TYPESPECIFICPARAMS 0x00000100 +#if(DIRECTINPUT_VERSION >= 0x0600) +#define DIEP_STARTDELAY 0x00000200 +#define DIEP_ALLPARAMS_DX5 0x000001FF +#define DIEP_ALLPARAMS 0x000003FF +#else +#define DIEP_ALLPARAMS 0x000001FF +#endif /* DIRECTINPUT_VERSION >= 0x0600 */ +#define DIEP_START 0x20000000 +#define DIEP_NORESTART 0x40000000 +#define DIEP_NODOWNLOAD 0x80000000 +#define DIEB_NOTRIGGER 0xFFFFFFFF + +#define DIES_SOLO 0x00000001 +#define DIES_NODOWNLOAD 0x80000000 + +#define DIEGES_PLAYING 0x00000001 +#define DIEGES_EMULATED 0x00000002 + +#define DI_DEGREES 100 +#define DI_FFNOMINALMAX 10000 +#define DI_SECONDS 1000000 + +typedef struct DICONSTANTFORCE { + LONG lMagnitude; +} DICONSTANTFORCE, *LPDICONSTANTFORCE; +typedef const DICONSTANTFORCE *LPCDICONSTANTFORCE; + +typedef struct DIRAMPFORCE { + LONG lStart; + LONG lEnd; +} DIRAMPFORCE, *LPDIRAMPFORCE; +typedef const DIRAMPFORCE *LPCDIRAMPFORCE; + +typedef struct DIPERIODIC { + DWORD dwMagnitude; + LONG lOffset; + DWORD dwPhase; + DWORD dwPeriod; +} DIPERIODIC, *LPDIPERIODIC; +typedef const DIPERIODIC *LPCDIPERIODIC; + +typedef struct DICONDITION { + LONG lOffset; + LONG lPositiveCoefficient; + LONG lNegativeCoefficient; + DWORD dwPositiveSaturation; + DWORD dwNegativeSaturation; + LONG lDeadBand; +} DICONDITION, *LPDICONDITION; +typedef const DICONDITION *LPCDICONDITION; + +typedef struct DICUSTOMFORCE { + DWORD cChannels; + DWORD dwSamplePeriod; + DWORD cSamples; + LPLONG rglForceData; +} DICUSTOMFORCE, *LPDICUSTOMFORCE; +typedef const DICUSTOMFORCE *LPCDICUSTOMFORCE; + +typedef struct DIENVELOPE { + DWORD dwSize; + DWORD dwAttackLevel; + DWORD dwAttackTime; + DWORD dwFadeLevel; + DWORD dwFadeTime; +} DIENVELOPE, *LPDIENVELOPE; +typedef const DIENVELOPE *LPCDIENVELOPE; + +typedef struct DIEFFECT_DX5 { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDuration; + DWORD dwSamplePeriod; + DWORD dwGain; + DWORD dwTriggerButton; + DWORD dwTriggerRepeatInterval; + DWORD cAxes; + LPDWORD rgdwAxes; + LPLONG rglDirection; + LPDIENVELOPE lpEnvelope; + DWORD cbTypeSpecificParams; + LPVOID lpvTypeSpecificParams; +} DIEFFECT_DX5, *LPDIEFFECT_DX5; +typedef const DIEFFECT_DX5 *LPCDIEFFECT_DX5; + +typedef struct DIEFFECT { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDuration; + DWORD dwSamplePeriod; + DWORD dwGain; + DWORD dwTriggerButton; + DWORD dwTriggerRepeatInterval; + DWORD cAxes; + LPDWORD rgdwAxes; + LPLONG rglDirection; + LPDIENVELOPE lpEnvelope; + DWORD cbTypeSpecificParams; + LPVOID lpvTypeSpecificParams; +#if(DIRECTINPUT_VERSION >= 0x0600) + DWORD dwStartDelay; +#endif /* DIRECTINPUT_VERSION >= 0x0600 */ +} DIEFFECT, *LPDIEFFECT; +typedef const DIEFFECT *LPCDIEFFECT; +typedef DIEFFECT DIEFFECT_DX6; +typedef LPDIEFFECT LPDIEFFECT_DX6; + +typedef struct DIEFFECTINFOA { + DWORD dwSize; + GUID guid; + DWORD dwEffType; + DWORD dwStaticParams; + DWORD dwDynamicParams; + CHAR tszName[MAX_PATH]; +} DIEFFECTINFOA, *LPDIEFFECTINFOA; +typedef const DIEFFECTINFOA *LPCDIEFFECTINFOA; + +typedef struct DIEFFECTINFOW { + DWORD dwSize; + GUID guid; + DWORD dwEffType; + DWORD dwStaticParams; + DWORD dwDynamicParams; + WCHAR tszName[MAX_PATH]; +} DIEFFECTINFOW, *LPDIEFFECTINFOW; +typedef const DIEFFECTINFOW *LPCDIEFFECTINFOW; + +DECL_WINELIB_TYPE_AW(DIEFFECTINFO) +DECL_WINELIB_TYPE_AW(LPDIEFFECTINFO) +DECL_WINELIB_TYPE_AW(LPCDIEFFECTINFO) + +typedef BOOL (CALLBACK *LPDIENUMEFFECTSCALLBACKA)(LPCDIEFFECTINFOA, LPVOID); +typedef BOOL (CALLBACK *LPDIENUMEFFECTSCALLBACKW)(LPCDIEFFECTINFOW, LPVOID); + +typedef struct DIEFFESCAPE { + DWORD dwSize; + DWORD dwCommand; + LPVOID lpvInBuffer; + DWORD cbInBuffer; + LPVOID lpvOutBuffer; + DWORD cbOutBuffer; +} DIEFFESCAPE, *LPDIEFFESCAPE; + +typedef struct DIJOYSTATE { + LONG lX; + LONG lY; + LONG lZ; + LONG lRx; + LONG lRy; + LONG lRz; + LONG rglSlider[2]; + DWORD rgdwPOV[4]; + BYTE rgbButtons[32]; +} DIJOYSTATE, *LPDIJOYSTATE; + +typedef struct DIJOYSTATE2 { + LONG lX; + LONG lY; + LONG lZ; + LONG lRx; + LONG lRy; + LONG lRz; + LONG rglSlider[2]; + DWORD rgdwPOV[4]; + BYTE rgbButtons[128]; + LONG lVX; /* 'v' as in velocity */ + LONG lVY; + LONG lVZ; + LONG lVRx; + LONG lVRy; + LONG lVRz; + LONG rglVSlider[2]; + LONG lAX; /* 'a' as in acceleration */ + LONG lAY; + LONG lAZ; + LONG lARx; + LONG lARy; + LONG lARz; + LONG rglASlider[2]; + LONG lFX; /* 'f' as in force */ + LONG lFY; + LONG lFZ; + LONG lFRx; /* 'fr' as in rotational force aka torque */ + LONG lFRy; + LONG lFRz; + LONG rglFSlider[2]; +} DIJOYSTATE2, *LPDIJOYSTATE2; + +#define DIJOFS_X FIELD_OFFSET(DIJOYSTATE, lX) +#define DIJOFS_Y FIELD_OFFSET(DIJOYSTATE, lY) +#define DIJOFS_Z FIELD_OFFSET(DIJOYSTATE, lZ) +#define DIJOFS_RX FIELD_OFFSET(DIJOYSTATE, lRx) +#define DIJOFS_RY FIELD_OFFSET(DIJOYSTATE, lRy) +#define DIJOFS_RZ FIELD_OFFSET(DIJOYSTATE, lRz) +#define DIJOFS_SLIDER(n) (FIELD_OFFSET(DIJOYSTATE, rglSlider) + \ + (n) * sizeof(LONG)) +#define DIJOFS_POV(n) (FIELD_OFFSET(DIJOYSTATE, rgdwPOV) + \ + (n) * sizeof(DWORD)) +#define DIJOFS_BUTTON(n) (FIELD_OFFSET(DIJOYSTATE, rgbButtons) + (n)) +#define DIJOFS_BUTTON0 DIJOFS_BUTTON(0) +#define DIJOFS_BUTTON1 DIJOFS_BUTTON(1) +#define DIJOFS_BUTTON2 DIJOFS_BUTTON(2) +#define DIJOFS_BUTTON3 DIJOFS_BUTTON(3) +#define DIJOFS_BUTTON4 DIJOFS_BUTTON(4) +#define DIJOFS_BUTTON5 DIJOFS_BUTTON(5) +#define DIJOFS_BUTTON6 DIJOFS_BUTTON(6) +#define DIJOFS_BUTTON7 DIJOFS_BUTTON(7) +#define DIJOFS_BUTTON8 DIJOFS_BUTTON(8) +#define DIJOFS_BUTTON9 DIJOFS_BUTTON(9) +#define DIJOFS_BUTTON10 DIJOFS_BUTTON(10) +#define DIJOFS_BUTTON11 DIJOFS_BUTTON(11) +#define DIJOFS_BUTTON12 DIJOFS_BUTTON(12) +#define DIJOFS_BUTTON13 DIJOFS_BUTTON(13) +#define DIJOFS_BUTTON14 DIJOFS_BUTTON(14) +#define DIJOFS_BUTTON15 DIJOFS_BUTTON(15) +#define DIJOFS_BUTTON16 DIJOFS_BUTTON(16) +#define DIJOFS_BUTTON17 DIJOFS_BUTTON(17) +#define DIJOFS_BUTTON18 DIJOFS_BUTTON(18) +#define DIJOFS_BUTTON19 DIJOFS_BUTTON(19) +#define DIJOFS_BUTTON20 DIJOFS_BUTTON(20) +#define DIJOFS_BUTTON21 DIJOFS_BUTTON(21) +#define DIJOFS_BUTTON22 DIJOFS_BUTTON(22) +#define DIJOFS_BUTTON23 DIJOFS_BUTTON(23) +#define DIJOFS_BUTTON24 DIJOFS_BUTTON(24) +#define DIJOFS_BUTTON25 DIJOFS_BUTTON(25) +#define DIJOFS_BUTTON26 DIJOFS_BUTTON(26) +#define DIJOFS_BUTTON27 DIJOFS_BUTTON(27) +#define DIJOFS_BUTTON28 DIJOFS_BUTTON(28) +#define DIJOFS_BUTTON29 DIJOFS_BUTTON(29) +#define DIJOFS_BUTTON30 DIJOFS_BUTTON(30) +#define DIJOFS_BUTTON31 DIJOFS_BUTTON(31) +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ + +/* DInput 7 structures, types */ +#if(DIRECTINPUT_VERSION >= 0x0700) +typedef struct DIFILEEFFECT { + DWORD dwSize; + GUID GuidEffect; + LPCDIEFFECT lpDiEffect; + CHAR szFriendlyName[MAX_PATH]; +} DIFILEEFFECT, *LPDIFILEEFFECT; + +typedef const DIFILEEFFECT *LPCDIFILEEFFECT; +typedef BOOL (CALLBACK *LPDIENUMEFFECTSINFILECALLBACK)(LPCDIFILEEFFECT , LPVOID); +#endif /* DIRECTINPUT_VERSION >= 0x0700 */ + +/* DInput 8 structures and types */ +#if DIRECTINPUT_VERSION >= 0x0800 +typedef struct _DIACTIONA { + UINT_PTR uAppData; + DWORD dwSemantic; + DWORD dwFlags; + __GNU_EXTENSION union { + LPCSTR lptszActionName; + UINT uResIdString; + } DUMMYUNIONNAME; + GUID guidInstance; + DWORD dwObjID; + DWORD dwHow; +} DIACTIONA, *LPDIACTIONA; +typedef const DIACTIONA *LPCDIACTIONA; + +typedef struct _DIACTIONW { + UINT_PTR uAppData; + DWORD dwSemantic; + DWORD dwFlags; + __GNU_EXTENSION union { + LPCWSTR lptszActionName; + UINT uResIdString; + } DUMMYUNIONNAME; + GUID guidInstance; + DWORD dwObjID; + DWORD dwHow; +} DIACTIONW, *LPDIACTIONW; +typedef const DIACTIONW *LPCDIACTIONW; + +DECL_WINELIB_TYPE_AW(DIACTION) +DECL_WINELIB_TYPE_AW(LPDIACTION) +DECL_WINELIB_TYPE_AW(LPCDIACTION) + +#define DIA_FORCEFEEDBACK 0x00000001 +#define DIA_APPMAPPED 0x00000002 +#define DIA_APPNOMAP 0x00000004 +#define DIA_NORANGE 0x00000008 +#define DIA_APPFIXED 0x00000010 + +#define DIAH_UNMAPPED 0x00000000 +#define DIAH_USERCONFIG 0x00000001 +#define DIAH_APPREQUESTED 0x00000002 +#define DIAH_HWAPP 0x00000004 +#define DIAH_HWDEFAULT 0x00000008 +#define DIAH_DEFAULT 0x00000020 +#define DIAH_ERROR 0x80000000 + +typedef struct _DIACTIONFORMATA { + DWORD dwSize; + DWORD dwActionSize; + DWORD dwDataSize; + DWORD dwNumActions; + LPDIACTIONA rgoAction; + GUID guidActionMap; + DWORD dwGenre; + DWORD dwBufferSize; + LONG lAxisMin; + LONG lAxisMax; + HINSTANCE hInstString; + FILETIME ftTimeStamp; + DWORD dwCRC; + CHAR tszActionMap[MAX_PATH]; +} DIACTIONFORMATA, *LPDIACTIONFORMATA; +typedef const DIACTIONFORMATA *LPCDIACTIONFORMATA; + +typedef struct _DIACTIONFORMATW { + DWORD dwSize; + DWORD dwActionSize; + DWORD dwDataSize; + DWORD dwNumActions; + LPDIACTIONW rgoAction; + GUID guidActionMap; + DWORD dwGenre; + DWORD dwBufferSize; + LONG lAxisMin; + LONG lAxisMax; + HINSTANCE hInstString; + FILETIME ftTimeStamp; + DWORD dwCRC; + WCHAR tszActionMap[MAX_PATH]; +} DIACTIONFORMATW, *LPDIACTIONFORMATW; +typedef const DIACTIONFORMATW *LPCDIACTIONFORMATW; + +DECL_WINELIB_TYPE_AW(DIACTIONFORMAT) +DECL_WINELIB_TYPE_AW(LPDIACTIONFORMAT) +DECL_WINELIB_TYPE_AW(LPCDIACTIONFORMAT) + +#define DIAFTS_NEWDEVICELOW 0xFFFFFFFF +#define DIAFTS_NEWDEVICEHIGH 0xFFFFFFFF +#define DIAFTS_UNUSEDDEVICELOW 0x00000000 +#define DIAFTS_UNUSEDDEVICEHIGH 0x00000000 + +#define DIDBAM_DEFAULT 0x00000000 +#define DIDBAM_PRESERVE 0x00000001 +#define DIDBAM_INITIALIZE 0x00000002 +#define DIDBAM_HWDEFAULTS 0x00000004 + +#define DIDSAM_DEFAULT 0x00000000 +#define DIDSAM_NOUSER 0x00000001 +#define DIDSAM_FORCESAVE 0x00000002 + +#define DICD_DEFAULT 0x00000000 +#define DICD_EDIT 0x00000001 + +#ifndef D3DCOLOR_DEFINED +typedef DWORD D3DCOLOR; +#define D3DCOLOR_DEFINED +#endif + +typedef struct _DICOLORSET { + DWORD dwSize; + D3DCOLOR cTextFore; + D3DCOLOR cTextHighlight; + D3DCOLOR cCalloutLine; + D3DCOLOR cCalloutHighlight; + D3DCOLOR cBorder; + D3DCOLOR cControlFill; + D3DCOLOR cHighlightFill; + D3DCOLOR cAreaFill; +} DICOLORSET, *LPDICOLORSET; +typedef const DICOLORSET *LPCDICOLORSET; + +typedef struct _DICONFIGUREDEVICESPARAMSA { + DWORD dwSize; + DWORD dwcUsers; + LPSTR lptszUserNames; + DWORD dwcFormats; + LPDIACTIONFORMATA lprgFormats; + HWND hwnd; + DICOLORSET dics; + LPUNKNOWN lpUnkDDSTarget; +} DICONFIGUREDEVICESPARAMSA, *LPDICONFIGUREDEVICESPARAMSA; +typedef const DICONFIGUREDEVICESPARAMSA *LPCDICONFIGUREDEVICESPARAMSA; + +typedef struct _DICONFIGUREDEVICESPARAMSW { + DWORD dwSize; + DWORD dwcUsers; + LPWSTR lptszUserNames; + DWORD dwcFormats; + LPDIACTIONFORMATW lprgFormats; + HWND hwnd; + DICOLORSET dics; + LPUNKNOWN lpUnkDDSTarget; +} DICONFIGUREDEVICESPARAMSW, *LPDICONFIGUREDEVICESPARAMSW; +typedef const DICONFIGUREDEVICESPARAMSW *LPCDICONFIGUREDEVICESPARAMSW; + +DECL_WINELIB_TYPE_AW(DICONFIGUREDEVICESPARAMS) +DECL_WINELIB_TYPE_AW(LPDICONFIGUREDEVICESPARAMS) +DECL_WINELIB_TYPE_AW(LPCDICONFIGUREDEVICESPARAMS) + +#define DIDIFT_CONFIGURATION 0x00000001 +#define DIDIFT_OVERLAY 0x00000002 + +#define DIDAL_CENTERED 0x00000000 +#define DIDAL_LEFTALIGNED 0x00000001 +#define DIDAL_RIGHTALIGNED 0x00000002 +#define DIDAL_MIDDLE 0x00000000 +#define DIDAL_TOPALIGNED 0x00000004 +#define DIDAL_BOTTOMALIGNED 0x00000008 + +typedef struct _DIDEVICEIMAGEINFOA { + CHAR tszImagePath[MAX_PATH]; + DWORD dwFlags; + DWORD dwViewID; + RECT rcOverlay; + DWORD dwObjID; + DWORD dwcValidPts; + POINT rgptCalloutLine[5]; + RECT rcCalloutRect; + DWORD dwTextAlign; +} DIDEVICEIMAGEINFOA, *LPDIDEVICEIMAGEINFOA; +typedef const DIDEVICEIMAGEINFOA *LPCDIDEVICEIMAGEINFOA; + +typedef struct _DIDEVICEIMAGEINFOW { + WCHAR tszImagePath[MAX_PATH]; + DWORD dwFlags; + DWORD dwViewID; + RECT rcOverlay; + DWORD dwObjID; + DWORD dwcValidPts; + POINT rgptCalloutLine[5]; + RECT rcCalloutRect; + DWORD dwTextAlign; +} DIDEVICEIMAGEINFOW, *LPDIDEVICEIMAGEINFOW; +typedef const DIDEVICEIMAGEINFOW *LPCDIDEVICEIMAGEINFOW; + +DECL_WINELIB_TYPE_AW(DIDEVICEIMAGEINFO) +DECL_WINELIB_TYPE_AW(LPDIDEVICEIMAGEINFO) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEIMAGEINFO) + +typedef struct _DIDEVICEIMAGEINFOHEADERA { + DWORD dwSize; + DWORD dwSizeImageInfo; + DWORD dwcViews; + DWORD dwcButtons; + DWORD dwcAxes; + DWORD dwcPOVs; + DWORD dwBufferSize; + DWORD dwBufferUsed; + LPDIDEVICEIMAGEINFOA lprgImageInfoArray; +} DIDEVICEIMAGEINFOHEADERA, *LPDIDEVICEIMAGEINFOHEADERA; +typedef const DIDEVICEIMAGEINFOHEADERA *LPCDIDEVICEIMAGEINFOHEADERA; + +typedef struct _DIDEVICEIMAGEINFOHEADERW { + DWORD dwSize; + DWORD dwSizeImageInfo; + DWORD dwcViews; + DWORD dwcButtons; + DWORD dwcAxes; + DWORD dwcPOVs; + DWORD dwBufferSize; + DWORD dwBufferUsed; + LPDIDEVICEIMAGEINFOW lprgImageInfoArray; +} DIDEVICEIMAGEINFOHEADERW, *LPDIDEVICEIMAGEINFOHEADERW; +typedef const DIDEVICEIMAGEINFOHEADERW *LPCDIDEVICEIMAGEINFOHEADERW; + +DECL_WINELIB_TYPE_AW(DIDEVICEIMAGEINFOHEADER) +DECL_WINELIB_TYPE_AW(LPDIDEVICEIMAGEINFOHEADER) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEIMAGEINFOHEADER) + +#endif /* DI8 */ + + +/***************************************************************************** + * IDirectInputEffect interface + */ +#if (DIRECTINPUT_VERSION >= 0x0500) +#undef INTERFACE +#define INTERFACE IDirectInputEffect +DECLARE_INTERFACE_(IDirectInputEffect,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputEffect methods ***/ + STDMETHOD(Initialize)(THIS_ HINSTANCE, DWORD, REFGUID) PURE; + STDMETHOD(GetEffectGuid)(THIS_ LPGUID) PURE; + STDMETHOD(GetParameters)(THIS_ LPDIEFFECT, DWORD) PURE; + STDMETHOD(SetParameters)(THIS_ LPCDIEFFECT, DWORD) PURE; + STDMETHOD(Start)(THIS_ DWORD, DWORD) PURE; + STDMETHOD(Stop)(THIS) PURE; + STDMETHOD(GetEffectStatus)(THIS_ LPDWORD) PURE; + STDMETHOD(Download)(THIS) PURE; + STDMETHOD(Unload)(THIS) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputEffect_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputEffect_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputEffect_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputEffect methods ***/ +#define IDirectInputEffect_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +#define IDirectInputEffect_GetEffectGuid(p,a) (p)->lpVtbl->GetEffectGuid(p,a) +#define IDirectInputEffect_GetParameters(p,a,b) (p)->lpVtbl->GetParameters(p,a,b) +#define IDirectInputEffect_SetParameters(p,a,b) (p)->lpVtbl->SetParameters(p,a,b) +#define IDirectInputEffect_Start(p,a,b) (p)->lpVtbl->Start(p,a,b) +#define IDirectInputEffect_Stop(p) (p)->lpVtbl->Stop(p) +#define IDirectInputEffect_GetEffectStatus(p,a) (p)->lpVtbl->GetEffectStatus(p,a) +#define IDirectInputEffect_Download(p) (p)->lpVtbl->Download(p) +#define IDirectInputEffect_Unload(p) (p)->lpVtbl->Unload(p) +#define IDirectInputEffect_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#else +/*** IUnknown methods ***/ +#define IDirectInputEffect_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputEffect_AddRef(p) (p)->AddRef() +#define IDirectInputEffect_Release(p) (p)->Release() +/*** IDirectInputEffect methods ***/ +#define IDirectInputEffect_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +#define IDirectInputEffect_GetEffectGuid(p,a) (p)->GetEffectGuid(a) +#define IDirectInputEffect_GetParameters(p,a,b) (p)->GetParameters(a,b) +#define IDirectInputEffect_SetParameters(p,a,b) (p)->SetParameters(a,b) +#define IDirectInputEffect_Start(p,a,b) (p)->Start(a,b) +#define IDirectInputEffect_Stop(p) (p)->Stop() +#define IDirectInputEffect_GetEffectStatus(p,a) (p)->GetEffectStatus(a) +#define IDirectInputEffect_Download(p) (p)->Download() +#define IDirectInputEffect_Unload(p) (p)->Unload() +#define IDirectInputEffect_Escape(p,a) (p)->Escape(a) +#endif + +#endif /* DI5 */ + + +/***************************************************************************** + * IDirectInputDeviceA interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDeviceA +DECLARE_INTERFACE_(IDirectInputDeviceA,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; +}; + +/***************************************************************************** + * IDirectInputDeviceW interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDeviceW +DECLARE_INTERFACE_(IDirectInputDeviceW,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputDevice_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +#else +/*** IUnknown methods ***/ +#define IDirectInputDevice_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice_AddRef(p) (p)->AddRef() +#define IDirectInputDevice_Release(p) (p)->Release() +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice_Acquire(p) (p)->Acquire() +#define IDirectInputDevice_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +#endif + + +#if (DIRECTINPUT_VERSION >= 0x0500) +/***************************************************************************** + * IDirectInputDevice2A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice2A +DECLARE_INTERFACE_(IDirectInputDevice2A,IDirectInputDeviceA) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2A methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; +}; + +/***************************************************************************** + * IDirectInputDevice2W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice2W +DECLARE_INTERFACE_(IDirectInputDevice2W,IDirectInputDeviceW) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2W methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputDevice2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice2_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice2_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice2_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice2_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice2_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice2_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice2_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice2_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice2_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice2_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice2_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice2_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice2_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice2_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice2_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice2_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice2_CreateEffect(p,a,b,c,d) (p)->lpVtbl->CreateEffect(p,a,b,c,d) +#define IDirectInputDevice2_EnumEffects(p,a,b,c) (p)->lpVtbl->EnumEffects(p,a,b,c) +#define IDirectInputDevice2_GetEffectInfo(p,a,b) (p)->lpVtbl->GetEffectInfo(p,a,b) +#define IDirectInputDevice2_GetForceFeedbackState(p,a) (p)->lpVtbl->GetForceFeedbackState(p,a) +#define IDirectInputDevice2_SendForceFeedbackCommand(p,a) (p)->lpVtbl->SendForceFeedbackCommand(p,a) +#define IDirectInputDevice2_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c) +#define IDirectInputDevice2_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#define IDirectInputDevice2_Poll(p) (p)->lpVtbl->Poll(p) +#define IDirectInputDevice2_SendDeviceData(p,a,b,c,d) (p)->lpVtbl->SendDeviceData(p,a,b,c,d) +#else +/*** IUnknown methods ***/ +#define IDirectInputDevice2_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice2_AddRef(p) (p)->AddRef() +#define IDirectInputDevice2_Release(p) (p)->Release() +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice2_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice2_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice2_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice2_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice2_Acquire(p) (p)->Acquire() +#define IDirectInputDevice2_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice2_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice2_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice2_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice2_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice2_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice2_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice2_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice2_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice2_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice2_CreateEffect(p,a,b,c,d) (p)->CreateEffect(a,b,c,d) +#define IDirectInputDevice2_EnumEffects(p,a,b,c) (p)->EnumEffects(a,b,c) +#define IDirectInputDevice2_GetEffectInfo(p,a,b) (p)->GetEffectInfo(a,b) +#define IDirectInputDevice2_GetForceFeedbackState(p,a) (p)->GetForceFeedbackState(a) +#define IDirectInputDevice2_SendForceFeedbackCommand(p,a) (p)->SendForceFeedbackCommand(a) +#define IDirectInputDevice2_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c) +#define IDirectInputDevice2_Escape(p,a) (p)->Escape(a) +#define IDirectInputDevice2_Poll(p) (p)->Poll() +#define IDirectInputDevice2_SendDeviceData(p,a,b,c,d) (p)->SendDeviceData(a,b,c,d) +#endif +#endif /* DI5 */ + +#if DIRECTINPUT_VERSION >= 0x0700 +/***************************************************************************** + * IDirectInputDevice7A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice7A +DECLARE_INTERFACE_(IDirectInputDevice7A,IDirectInputDevice2A) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2A methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; + /*** IDirectInputDevice7A methods ***/ + STDMETHOD(EnumEffectsInFile)(THIS_ LPCSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE; + STDMETHOD(WriteEffectToFile)(THIS_ LPCSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE; +}; + +/***************************************************************************** + * IDirectInputDevice7W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice7W +DECLARE_INTERFACE_(IDirectInputDevice7W,IDirectInputDevice2W) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2W methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; + /*** IDirectInputDevice7W methods ***/ + STDMETHOD(EnumEffectsInFile)(THIS_ LPCWSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE; + STDMETHOD(WriteEffectToFile)(THIS_ LPCWSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputDevice7_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice7_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice7_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice7_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice7_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice7_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice7_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice7_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice7_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice7_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice7_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice7_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice7_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice7_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice7_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice7_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice7_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice7_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice7_CreateEffect(p,a,b,c,d) (p)->lpVtbl->CreateEffect(p,a,b,c,d) +#define IDirectInputDevice7_EnumEffects(p,a,b,c) (p)->lpVtbl->EnumEffects(p,a,b,c) +#define IDirectInputDevice7_GetEffectInfo(p,a,b) (p)->lpVtbl->GetEffectInfo(p,a,b) +#define IDirectInputDevice7_GetForceFeedbackState(p,a) (p)->lpVtbl->GetForceFeedbackState(p,a) +#define IDirectInputDevice7_SendForceFeedbackCommand(p,a) (p)->lpVtbl->SendForceFeedbackCommand(p,a) +#define IDirectInputDevice7_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c) +#define IDirectInputDevice7_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#define IDirectInputDevice7_Poll(p) (p)->lpVtbl->Poll(p) +#define IDirectInputDevice7_SendDeviceData(p,a,b,c,d) (p)->lpVtbl->SendDeviceData(p,a,b,c,d) +/*** IDirectInputDevice7 methods ***/ +#define IDirectInputDevice7_EnumEffectsInFile(p,a,b,c,d) (p)->lpVtbl->EnumEffectsInFile(p,a,b,c,d) +#define IDirectInputDevice7_WriteEffectToFile(p,a,b,c,d) (p)->lpVtbl->WriteEffectToFile(p,a,b,c,d) +#else +/*** IUnknown methods ***/ +#define IDirectInputDevice7_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice7_AddRef(p) (p)->AddRef() +#define IDirectInputDevice7_Release(p) (p)->Release() +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice7_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice7_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice7_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice7_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice7_Acquire(p) (p)->Acquire() +#define IDirectInputDevice7_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice7_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice7_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice7_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice7_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice7_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice7_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice7_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice7_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice7_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice7_CreateEffect(p,a,b,c,d) (p)->CreateEffect(a,b,c,d) +#define IDirectInputDevice7_EnumEffects(p,a,b,c) (p)->EnumEffects(a,b,c) +#define IDirectInputDevice7_GetEffectInfo(p,a,b) (p)->GetEffectInfo(a,b) +#define IDirectInputDevice7_GetForceFeedbackState(p,a) (p)->GetForceFeedbackState(a) +#define IDirectInputDevice7_SendForceFeedbackCommand(p,a) (p)->SendForceFeedbackCommand(a) +#define IDirectInputDevice7_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c) +#define IDirectInputDevice7_Escape(p,a) (p)->Escape(a) +#define IDirectInputDevice7_Poll(p) (p)->Poll() +#define IDirectInputDevice7_SendDeviceData(p,a,b,c,d) (p)->SendDeviceData(a,b,c,d) +/*** IDirectInputDevice7 methods ***/ +#define IDirectInputDevice7_EnumEffectsInFile(p,a,b,c,d) (p)->EnumEffectsInFile(a,b,c,d) +#define IDirectInputDevice7_WriteEffectToFile(p,a,b,c,d) (p)->WriteEffectToFile(a,b,c,d) +#endif + +#endif /* DI7 */ + +#if DIRECTINPUT_VERSION >= 0x0800 +/***************************************************************************** + * IDirectInputDevice8A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice8A +DECLARE_INTERFACE_(IDirectInputDevice8A,IDirectInputDevice7A) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2A methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; + /*** IDirectInputDevice7A methods ***/ + STDMETHOD(EnumEffectsInFile)(THIS_ LPCSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE; + STDMETHOD(WriteEffectToFile)(THIS_ LPCSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE; + /*** IDirectInputDevice8A methods ***/ + STDMETHOD(BuildActionMap)(THIS_ LPDIACTIONFORMATA lpdiaf, LPCSTR lpszUserName, DWORD dwFlags) PURE; + STDMETHOD(SetActionMap)(THIS_ LPDIACTIONFORMATA lpdiaf, LPCSTR lpszUserName, DWORD dwFlags) PURE; + STDMETHOD(GetImageInfo)(THIS_ LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader) PURE; +}; + +/***************************************************************************** + * IDirectInputDevice8W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice8W +DECLARE_INTERFACE_(IDirectInputDevice8W,IDirectInputDevice7W) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2W methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; + /*** IDirectInputDevice7W methods ***/ + STDMETHOD(EnumEffectsInFile)(THIS_ LPCWSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE; + STDMETHOD(WriteEffectToFile)(THIS_ LPCWSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE; + /*** IDirectInputDevice8W methods ***/ + STDMETHOD(BuildActionMap)(THIS_ LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) PURE; + STDMETHOD(SetActionMap)(THIS_ LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) PURE; + STDMETHOD(GetImageInfo)(THIS_ LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputDevice8_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice8_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice8_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice8_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice8_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice8_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice8_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice8_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice8_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice8_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice8_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice8_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice8_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice8_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice8_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice8_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice8_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice8_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice8_CreateEffect(p,a,b,c,d) (p)->lpVtbl->CreateEffect(p,a,b,c,d) +#define IDirectInputDevice8_EnumEffects(p,a,b,c) (p)->lpVtbl->EnumEffects(p,a,b,c) +#define IDirectInputDevice8_GetEffectInfo(p,a,b) (p)->lpVtbl->GetEffectInfo(p,a,b) +#define IDirectInputDevice8_GetForceFeedbackState(p,a) (p)->lpVtbl->GetForceFeedbackState(p,a) +#define IDirectInputDevice8_SendForceFeedbackCommand(p,a) (p)->lpVtbl->SendForceFeedbackCommand(p,a) +#define IDirectInputDevice8_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c) +#define IDirectInputDevice8_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#define IDirectInputDevice8_Poll(p) (p)->lpVtbl->Poll(p) +#define IDirectInputDevice8_SendDeviceData(p,a,b,c,d) (p)->lpVtbl->SendDeviceData(p,a,b,c,d) +/*** IDirectInputDevice7 methods ***/ +#define IDirectInputDevice8_EnumEffectsInFile(p,a,b,c,d) (p)->lpVtbl->EnumEffectsInFile(p,a,b,c,d) +#define IDirectInputDevice8_WriteEffectToFile(p,a,b,c,d) (p)->lpVtbl->WriteEffectToFile(p,a,b,c,d) +/*** IDirectInputDevice8 methods ***/ +#define IDirectInputDevice8_BuildActionMap(p,a,b,c) (p)->lpVtbl->BuildActionMap(p,a,b,c) +#define IDirectInputDevice8_SetActionMap(p,a,b,c) (p)->lpVtbl->SetActionMap(p,a,b,c) +#define IDirectInputDevice8_GetImageInfo(p,a) (p)->lpVtbl->GetImageInfo(p,a) +#else +/*** IUnknown methods ***/ +#define IDirectInputDevice8_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice8_AddRef(p) (p)->AddRef() +#define IDirectInputDevice8_Release(p) (p)->Release() +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice8_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice8_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice8_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice8_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice8_Acquire(p) (p)->Acquire() +#define IDirectInputDevice8_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice8_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice8_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice8_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice8_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice8_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice8_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice8_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice8_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice8_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice8_CreateEffect(p,a,b,c,d) (p)->CreateEffect(a,b,c,d) +#define IDirectInputDevice8_EnumEffects(p,a,b,c) (p)->EnumEffects(a,b,c) +#define IDirectInputDevice8_GetEffectInfo(p,a,b) (p)->GetEffectInfo(a,b) +#define IDirectInputDevice8_GetForceFeedbackState(p,a) (p)->GetForceFeedbackState(a) +#define IDirectInputDevice8_SendForceFeedbackCommand(p,a) (p)->SendForceFeedbackCommand(a) +#define IDirectInputDevice8_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c) +#define IDirectInputDevice8_Escape(p,a) (p)->Escape(a) +#define IDirectInputDevice8_Poll(p) (p)->Poll() +#define IDirectInputDevice8_SendDeviceData(p,a,b,c,d) (p)->SendDeviceData(a,b,c,d) +/*** IDirectInputDevice7 methods ***/ +#define IDirectInputDevice8_EnumEffectsInFile(p,a,b,c,d) (p)->EnumEffectsInFile(a,b,c,d) +#define IDirectInputDevice8_WriteEffectToFile(p,a,b,c,d) (p)->WriteEffectToFile(a,b,c,d) +/*** IDirectInputDevice8 methods ***/ +#define IDirectInputDevice8_BuildActionMap(p,a,b,c) (p)->BuildActionMap(a,b,c) +#define IDirectInputDevice8_SetActionMap(p,a,b,c) (p)->SetActionMap(a,b,c) +#define IDirectInputDevice8_GetImageInfo(p,a) (p)->GetImageInfo(a) +#endif + +#endif /* DI8 */ + +/* "Standard" Mouse report... */ +typedef struct DIMOUSESTATE { + LONG lX; + LONG lY; + LONG lZ; + BYTE rgbButtons[4]; +} DIMOUSESTATE; + +#if DIRECTINPUT_VERSION >= 0x0700 +/* "Standard" Mouse report for DInput 7... */ +typedef struct DIMOUSESTATE2 { + LONG lX; + LONG lY; + LONG lZ; + BYTE rgbButtons[8]; +} DIMOUSESTATE2; +#endif /* DI7 */ + +#define DIMOFS_X FIELD_OFFSET(DIMOUSESTATE, lX) +#define DIMOFS_Y FIELD_OFFSET(DIMOUSESTATE, lY) +#define DIMOFS_Z FIELD_OFFSET(DIMOUSESTATE, lZ) +#define DIMOFS_BUTTON0 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 0) +#define DIMOFS_BUTTON1 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 1) +#define DIMOFS_BUTTON2 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 2) +#define DIMOFS_BUTTON3 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 3) +#if DIRECTINPUT_VERSION >= 0x0700 +#define DIMOFS_BUTTON4 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 4) +#define DIMOFS_BUTTON5 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 5) +#define DIMOFS_BUTTON6 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 6) +#define DIMOFS_BUTTON7 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 7) +#endif /* DI7 */ + +#ifdef __cplusplus +extern "C" { +#endif +extern const DIDATAFORMAT c_dfDIMouse; +#if DIRECTINPUT_VERSION >= 0x0700 +extern const DIDATAFORMAT c_dfDIMouse2; /* DX 7 */ +#endif /* DI7 */ +extern const DIDATAFORMAT c_dfDIKeyboard; +#if DIRECTINPUT_VERSION >= 0x0500 +extern const DIDATAFORMAT c_dfDIJoystick; +extern const DIDATAFORMAT c_dfDIJoystick2; +#endif /* DI5 */ +#ifdef __cplusplus +}; +#endif + +/***************************************************************************** + * IDirectInputA interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputA +DECLARE_INTERFACE_(IDirectInputA,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputA methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEA *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; +}; + +/***************************************************************************** + * IDirectInputW interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputW +DECLARE_INTERFACE_(IDirectInputW,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputW methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEW *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInput_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInput methods ***/ +#define IDirectInput_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#else +/*** IUnknown methods ***/ +#define IDirectInput_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput_AddRef(p) (p)->AddRef() +#define IDirectInput_Release(p) (p)->Release() +/*** IDirectInput methods ***/ +#define IDirectInput_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput_Initialize(p,a,b) (p)->Initialize(a,b) +#endif + +/***************************************************************************** + * IDirectInput2A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput2A +DECLARE_INTERFACE_(IDirectInput2A,IDirectInputA) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputA methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEA *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + /*** IDirectInput2A methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) PURE; +}; + +/***************************************************************************** + * IDirectInput2W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput2W +DECLARE_INTERFACE_(IDirectInput2W,IDirectInputW) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputW methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEW *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + /*** IDirectInput2W methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInput2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput2_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInput methods ***/ +#define IDirectInput2_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput2_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput2_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput2_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput2_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +/*** IDirectInput2 methods ***/ +#define IDirectInput2_FindDevice(p,a,b,c) (p)->lpVtbl->FindDevice(p,a,b,c) +#else +/*** IUnknown methods ***/ +#define IDirectInput2_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput2_AddRef(p) (p)->AddRef() +#define IDirectInput2_Release(p) (p)->Release() +/*** IDirectInput methods ***/ +#define IDirectInput2_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput2_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput2_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput2_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput2_Initialize(p,a,b) (p)->Initialize(a,b) +/*** IDirectInput2 methods ***/ +#define IDirectInput2_FindDevice(p,a,b,c) (p)->FindDevice(a,b,c) +#endif + +/***************************************************************************** + * IDirectInput7A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput7A +DECLARE_INTERFACE_(IDirectInput7A,IDirectInput2A) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputA methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEA *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + /*** IDirectInput2A methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) PURE; + /*** IDirectInput7A methods ***/ + STDMETHOD(CreateDeviceEx)(THIS_ REFGUID rguid, REFIID riid, LPVOID *pvOut, LPUNKNOWN lpUnknownOuter) PURE; +}; + +/***************************************************************************** + * IDirectInput7W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput7W +DECLARE_INTERFACE_(IDirectInput7W,IDirectInput2W) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputW methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEW *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + /*** IDirectInput2W methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) PURE; + /*** IDirectInput7W methods ***/ + STDMETHOD(CreateDeviceEx)(THIS_ REFGUID rguid, REFIID riid, LPVOID *pvOut, LPUNKNOWN lpUnknownOuter) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInput7_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput7_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput7_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInput methods ***/ +#define IDirectInput7_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput7_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput7_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput7_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput7_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +/*** IDirectInput2 methods ***/ +#define IDirectInput7_FindDevice(p,a,b,c) (p)->lpVtbl->FindDevice(p,a,b,c) +/*** IDirectInput7 methods ***/ +#define IDirectInput7_CreateDeviceEx(p,a,b,c,d) (p)->lpVtbl->CreateDeviceEx(p,a,b,c,d) +#else +/*** IUnknown methods ***/ +#define IDirectInput7_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput7_AddRef(p) (p)->AddRef() +#define IDirectInput7_Release(p) (p)->Release() +/*** IDirectInput methods ***/ +#define IDirectInput7_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput7_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput7_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput7_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput7_Initialize(p,a,b) (p)->Initialize(a,b) +/*** IDirectInput2 methods ***/ +#define IDirectInput7_FindDevice(p,a,b,c) (p)->FindDevice(a,b,c) +/*** IDirectInput7 methods ***/ +#define IDirectInput7_CreateDeviceEx(p,a,b,c,d) (p)->CreateDeviceEx(a,b,c,d) +#endif + + +#if DIRECTINPUT_VERSION >= 0x0800 +/***************************************************************************** + * IDirectInput8A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput8A +DECLARE_INTERFACE_(IDirectInput8A,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInput8A methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICE8A *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) PURE; + STDMETHOD(EnumDevicesBySemantics)(THIS_ LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat, LPDIENUMDEVICESBYSEMANTICSCBA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(ConfigureDevices)(THIS_ LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) PURE; +}; + +/***************************************************************************** + * IDirectInput8W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput8W +DECLARE_INTERFACE_(IDirectInput8W,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInput8W methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICE8W *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) PURE; + STDMETHOD(EnumDevicesBySemantics)(THIS_ LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat, LPDIENUMDEVICESBYSEMANTICSCBW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(ConfigureDevices)(THIS_ LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) PURE; +}; +#undef INTERFACE + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInput8_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput8_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput8_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInput8 methods ***/ +#define IDirectInput8_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput8_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput8_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput8_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput8_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IDirectInput8_FindDevice(p,a,b,c) (p)->lpVtbl->FindDevice(p,a,b,c) +#define IDirectInput8_EnumDevicesBySemantics(p,a,b,c,d,e) (p)->lpVtbl->EnumDevicesBySemantics(p,a,b,c,d,e) +#define IDirectInput8_ConfigureDevices(p,a,b,c,d) (p)->lpVtbl->ConfigureDevices(p,a,b,c,d) +#else +/*** IUnknown methods ***/ +#define IDirectInput8_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput8_AddRef(p) (p)->AddRef() +#define IDirectInput8_Release(p) (p)->Release() +/*** IDirectInput8 methods ***/ +#define IDirectInput8_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput8_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput8_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput8_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput8_Initialize(p,a,b) (p)->Initialize(a,b) +#define IDirectInput8_FindDevice(p,a,b,c) (p)->FindDevice(a,b,c) +#define IDirectInput8_EnumDevicesBySemantics(p,a,b,c,d,e) (p)->EnumDevicesBySemantics(a,b,c,d,e) +#define IDirectInput8_ConfigureDevices(p,a,b,c,d) (p)->ConfigureDevices(a,b,c,d) +#endif + +#endif /* DI8 */ + +/* Export functions */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if DIRECTINPUT_VERSION >= 0x0800 +HRESULT WINAPI DirectInput8Create(HINSTANCE,DWORD,REFIID,LPVOID *,LPUNKNOWN); +#else /* DI < 8 */ +HRESULT WINAPI DirectInputCreateA(HINSTANCE,DWORD,LPDIRECTINPUTA *,LPUNKNOWN); +HRESULT WINAPI DirectInputCreateW(HINSTANCE,DWORD,LPDIRECTINPUTW *,LPUNKNOWN); +#define DirectInputCreate WINELIB_NAME_AW(DirectInputCreate) + +HRESULT WINAPI DirectInputCreateEx(HINSTANCE,DWORD,REFIID,LPVOID *,LPUNKNOWN); +#endif /* DI8 */ + +#ifdef __cplusplus +}; +#endif + +#endif /* __DINPUT_INCLUDED__ */ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/mingw/xinput.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/mingw/xinput.h new file mode 100644 index 00000000..d3ca726c --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/mingw/xinput.h @@ -0,0 +1,239 @@ +/* + * The Wine project - Xinput Joystick Library + * Copyright 2008 Andrew Fenn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_XINPUT_H +#define __WINE_XINPUT_H + +#include + +/* + * Bitmasks for the joysticks buttons, determines what has + * been pressed on the joystick, these need to be mapped + * to whatever device you're using instead of an xbox 360 + * joystick + */ + +#define XINPUT_GAMEPAD_DPAD_UP 0x0001 +#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002 +#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004 +#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008 +#define XINPUT_GAMEPAD_START 0x0010 +#define XINPUT_GAMEPAD_BACK 0x0020 +#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040 +#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080 +#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 +#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 +#define XINPUT_GAMEPAD_A 0x1000 +#define XINPUT_GAMEPAD_B 0x2000 +#define XINPUT_GAMEPAD_X 0x4000 +#define XINPUT_GAMEPAD_Y 0x8000 + +/* + * Defines the flags used to determine if the user is pushing + * down on a button, not holding a button, etc + */ + +#define XINPUT_KEYSTROKE_KEYDOWN 0x0001 +#define XINPUT_KEYSTROKE_KEYUP 0x0002 +#define XINPUT_KEYSTROKE_REPEAT 0x0004 + +/* + * Defines the codes which are returned by XInputGetKeystroke + */ + +#define VK_PAD_A 0x5800 +#define VK_PAD_B 0x5801 +#define VK_PAD_X 0x5802 +#define VK_PAD_Y 0x5803 +#define VK_PAD_RSHOULDER 0x5804 +#define VK_PAD_LSHOULDER 0x5805 +#define VK_PAD_LTRIGGER 0x5806 +#define VK_PAD_RTRIGGER 0x5807 +#define VK_PAD_DPAD_UP 0x5810 +#define VK_PAD_DPAD_DOWN 0x5811 +#define VK_PAD_DPAD_LEFT 0x5812 +#define VK_PAD_DPAD_RIGHT 0x5813 +#define VK_PAD_START 0x5814 +#define VK_PAD_BACK 0x5815 +#define VK_PAD_LTHUMB_PRESS 0x5816 +#define VK_PAD_RTHUMB_PRESS 0x5817 +#define VK_PAD_LTHUMB_UP 0x5820 +#define VK_PAD_LTHUMB_DOWN 0x5821 +#define VK_PAD_LTHUMB_RIGHT 0x5822 +#define VK_PAD_LTHUMB_LEFT 0x5823 +#define VK_PAD_LTHUMB_UPLEFT 0x5824 +#define VK_PAD_LTHUMB_UPRIGHT 0x5825 +#define VK_PAD_LTHUMB_DOWNRIGHT 0x5826 +#define VK_PAD_LTHUMB_DOWNLEFT 0x5827 +#define VK_PAD_RTHUMB_UP 0x5830 +#define VK_PAD_RTHUMB_DOWN 0x5831 +#define VK_PAD_RTHUMB_RIGHT 0x5832 +#define VK_PAD_RTHUMB_LEFT 0x5833 +#define VK_PAD_RTHUMB_UPLEFT 0x5834 +#define VK_PAD_RTHUMB_UPRIGHT 0x5835 +#define VK_PAD_RTHUMB_DOWNRIGHT 0x5836 +#define VK_PAD_RTHUMB_DOWNLEFT 0x5837 + +/* + * Deadzones are for analogue joystick controls on the joypad + * which determine when input should be assumed to be in the + * middle of the pad. This is a threshold to stop a joypad + * controlling the game when the player isn't touching the + * controls. + */ + +#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849 +#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689 +#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30 + + +/* + * Defines what type of abilities the type of joystick has + * DEVTYPE_GAMEPAD is available for all joysticks, however + * there may be more specific identifiers for other joysticks + * which are being used. + */ + +#define XINPUT_DEVTYPE_GAMEPAD 0x01 +#define XINPUT_DEVSUBTYPE_GAMEPAD 0x01 +#define XINPUT_DEVSUBTYPE_WHEEL 0x02 +#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03 +#define XINPUT_DEVSUBTYPE_FLIGHT_SICK 0x04 +#define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05 +#define XINPUT_DEVSUBTYPE_GUITAR 0x06 +#define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08 + +/* + * These are used with the XInputGetCapabilities function to + * determine the abilities to the joystick which has been + * plugged in. + */ + +#define XINPUT_CAPS_VOICE_SUPPORTED 0x0004 +#define XINPUT_FLAG_GAMEPAD 0x00000001 + +/* + * Defines the status of the battery if one is used in the + * attached joystick. The first two define if the joystick + * supports a battery. Disconnected means that the joystick + * isn't connected. Wired shows that the joystick is a wired + * joystick. + */ + +#define BATTERY_DEVTYPE_GAMEPAD 0x00 +#define BATTERY_DEVTYPE_HEADSET 0x01 +#define BATTERY_TYPE_DISCONNECTED 0x00 +#define BATTERY_TYPE_WIRED 0x01 +#define BATTERY_TYPE_ALKALINE 0x02 +#define BATTERY_TYPE_NIMH 0x03 +#define BATTERY_TYPE_UNKNOWN 0xFF +#define BATTERY_LEVEL_EMPTY 0x00 +#define BATTERY_LEVEL_LOW 0x01 +#define BATTERY_LEVEL_MEDIUM 0x02 +#define BATTERY_LEVEL_FULL 0x03 + +/* + * How many joysticks can be used with this library. Games that + * use the xinput library will not go over this number. + */ + +#define XUSER_MAX_COUNT 4 +#define XUSER_INDEX_ANY 0x000000FF + +/* + * Defines the structure of an xbox 360 joystick. + */ + +typedef struct _XINPUT_GAMEPAD { + WORD wButtons; + BYTE bLeftTrigger; + BYTE bRightTrigger; + SHORT sThumbLX; + SHORT sThumbLY; + SHORT sThumbRX; + SHORT sThumbRY; +} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD; + +typedef struct _XINPUT_STATE { + DWORD dwPacketNumber; + XINPUT_GAMEPAD Gamepad; +} XINPUT_STATE, *PXINPUT_STATE; + +/* + * Defines the structure of how much vibration is set on both the + * right and left motors in a joystick. If you're not using a 360 + * joystick you will have to map these to your device. + */ + +typedef struct _XINPUT_VIBRATION { + WORD wLeftMotorSpeed; + WORD wRightMotorSpeed; +} XINPUT_VIBRATION, *PXINPUT_VIBRATION; + +/* + * Defines the structure for what kind of abilities the joystick has + * such abilities are things such as if the joystick has the ability + * to send and receive audio, if the joystick is in fact a driving + * wheel or perhaps if the joystick is some kind of dance pad or + * guitar. + */ + +typedef struct _XINPUT_CAPABILITIES { + BYTE Type; + BYTE SubType; + WORD Flags; + XINPUT_GAMEPAD Gamepad; + XINPUT_VIBRATION Vibration; +} XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES; + +/* + * Defines the structure for a joystick input event which is + * retrieved using the function XInputGetKeystroke + */ +typedef struct _XINPUT_KEYSTROKE { + WORD VirtualKey; + WCHAR Unicode; + WORD Flags; + BYTE UserIndex; + BYTE HidCode; +} XINPUT_KEYSTROKE, *PXINPUT_KEYSTROKE; + +typedef struct _XINPUT_BATTERY_INFORMATION +{ + BYTE BatteryType; + BYTE BatteryLevel; +} XINPUT_BATTERY_INFORMATION, *PXINPUT_BATTERY_INFORMATION; + +#ifdef __cplusplus +extern "C" { +#endif + +void WINAPI XInputEnable(WINBOOL); +DWORD WINAPI XInputSetState(DWORD, XINPUT_VIBRATION*); +DWORD WINAPI XInputGetState(DWORD, XINPUT_STATE*); +DWORD WINAPI XInputGetKeystroke(DWORD, DWORD, PXINPUT_KEYSTROKE); +DWORD WINAPI XInputGetCapabilities(DWORD, DWORD, XINPUT_CAPABILITIES*); +DWORD WINAPI XInputGetDSoundAudioDeviceGuids(DWORD, GUID*, GUID*); +DWORD WINAPI XInputGetBatteryInformation(DWORD, BYTE, XINPUT_BATTERY_INFORMATION*); + +#ifdef __cplusplus +} +#endif + +#endif /* __WINE_XINPUT_H */ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/tinycthread.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/tinycthread.c new file mode 100644 index 00000000..ddb86d99 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/tinycthread.c @@ -0,0 +1,594 @@ +/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- +Copyright (c) 2012 Marcus Geelnard + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +/* 2013-01-06 Camilla Berglund + * + * Added casts from time_t to DWORD to avoid warnings on VC++. + * Fixed time retrieval on POSIX systems. + */ + +#include "tinycthread.h" +#include + +/* Platform specific includes */ +#if defined(_TTHREAD_POSIX_) + #include + #include + #include + #include + #include +#elif defined(_TTHREAD_WIN32_) + #include + #include +#endif + +/* Standard, good-to-have defines */ +#ifndef NULL + #define NULL (void*)0 +#endif +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + +int mtx_init(mtx_t *mtx, int type) +{ +#if defined(_TTHREAD_WIN32_) + mtx->mAlreadyLocked = FALSE; + mtx->mRecursive = type & mtx_recursive; + InitializeCriticalSection(&mtx->mHandle); + return thrd_success; +#else + int ret; + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + if (type & mtx_recursive) + { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + } + ret = pthread_mutex_init(mtx, &attr); + pthread_mutexattr_destroy(&attr); + return ret == 0 ? thrd_success : thrd_error; +#endif +} + +void mtx_destroy(mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + DeleteCriticalSection(&mtx->mHandle); +#else + pthread_mutex_destroy(mtx); +#endif +} + +int mtx_lock(mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + EnterCriticalSection(&mtx->mHandle); + if (!mtx->mRecursive) + { + while(mtx->mAlreadyLocked) Sleep(1000); /* Simulate deadlock... */ + mtx->mAlreadyLocked = TRUE; + } + return thrd_success; +#else + return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; +#endif +} + +int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + /* FIXME! */ + (void)mtx; + (void)ts; + return thrd_error; +} + +int mtx_trylock(mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy; + if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked) + { + LeaveCriticalSection(&mtx->mHandle); + ret = thrd_busy; + } + return ret; +#else + return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; +#endif +} + +int mtx_unlock(mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + mtx->mAlreadyLocked = FALSE; + LeaveCriticalSection(&mtx->mHandle); + return thrd_success; +#else + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;; +#endif +} + +#if defined(_TTHREAD_WIN32_) +#define _CONDITION_EVENT_ONE 0 +#define _CONDITION_EVENT_ALL 1 +#endif + +int cnd_init(cnd_t *cond) +{ +#if defined(_TTHREAD_WIN32_) + cond->mWaitersCount = 0; + + /* Init critical section */ + InitializeCriticalSection(&cond->mWaitersCountLock); + + /* Init events */ + cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); + if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL) + { + cond->mEvents[_CONDITION_EVENT_ALL] = NULL; + return thrd_error; + } + cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); + if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL) + { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); + cond->mEvents[_CONDITION_EVENT_ONE] = NULL; + return thrd_error; + } + + return thrd_success; +#else + return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error; +#endif +} + +void cnd_destroy(cnd_t *cond) +{ +#if defined(_TTHREAD_WIN32_) + if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL) + { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); + } + if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL) + { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]); + } + DeleteCriticalSection(&cond->mWaitersCountLock); +#else + pthread_cond_destroy(cond); +#endif +} + +int cnd_signal(cnd_t *cond) +{ +#if defined(_TTHREAD_WIN32_) + int haveWaiters; + + /* Are there any waiters? */ + EnterCriticalSection(&cond->mWaitersCountLock); + haveWaiters = (cond->mWaitersCount > 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we have any waiting threads, send them a signal */ + if(haveWaiters) + { + if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0) + { + return thrd_error; + } + } + + return thrd_success; +#else + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; +#endif +} + +int cnd_broadcast(cnd_t *cond) +{ +#if defined(_TTHREAD_WIN32_) + int haveWaiters; + + /* Are there any waiters? */ + EnterCriticalSection(&cond->mWaitersCountLock); + haveWaiters = (cond->mWaitersCount > 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we have any waiting threads, send them a signal */ + if(haveWaiters) + { + if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) + { + return thrd_error; + } + } + + return thrd_success; +#else + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; +#endif +} + +#if defined(_TTHREAD_WIN32_) +static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) +{ + int result, lastWaiter; + + /* Increment number of waiters */ + EnterCriticalSection(&cond->mWaitersCountLock); + ++ cond->mWaitersCount; + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* Release the mutex while waiting for the condition (will decrease + the number of waiters when done)... */ + mtx_unlock(mtx); + + /* Wait for either event to become signaled due to cnd_signal() or + cnd_broadcast() being called */ + result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout); + if (result == WAIT_TIMEOUT) + { + return thrd_timeout; + } + else if (result == (int)WAIT_FAILED) + { + return thrd_error; + } + + /* Check if we are the last waiter */ + EnterCriticalSection(&cond->mWaitersCountLock); + -- cond->mWaitersCount; + lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && + (cond->mWaitersCount == 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we are the last waiter to be notified to stop waiting, reset the event */ + if (lastWaiter) + { + if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) + { + return thrd_error; + } + } + + /* Re-acquire the mutex */ + mtx_lock(mtx); + + return thrd_success; +} +#endif + +int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + return _cnd_timedwait_win32(cond, mtx, INFINITE); +#else + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; +#endif +} + +int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ +#if defined(_TTHREAD_WIN32_) + struct timespec now; + if (clock_gettime(CLOCK_REALTIME, &now) == 0) + { + DWORD delta = (DWORD) ((ts->tv_sec - now.tv_sec) * 1000 + + (ts->tv_nsec - now.tv_nsec + 500000) / 1000000); + return _cnd_timedwait_win32(cond, mtx, delta); + } + else + return thrd_error; +#else + int ret; + ret = pthread_cond_timedwait(cond, mtx, ts); + if (ret == ETIMEDOUT) + { + return thrd_timeout; + } + return ret == 0 ? thrd_success : thrd_error; +#endif +} + + +/** Information to pass to the new thread (what to run). */ +typedef struct { + thrd_start_t mFunction; /**< Pointer to the function to be executed. */ + void * mArg; /**< Function argument for the thread function. */ +} _thread_start_info; + +/* Thread wrapper function. */ +#if defined(_TTHREAD_WIN32_) +static unsigned WINAPI _thrd_wrapper_function(void * aArg) +#elif defined(_TTHREAD_POSIX_) +static void * _thrd_wrapper_function(void * aArg) +#endif +{ + thrd_start_t fun; + void *arg; + int res; +#if defined(_TTHREAD_POSIX_) + void *pres; +#endif + + /* Get thread startup information */ + _thread_start_info *ti = (_thread_start_info *) aArg; + fun = ti->mFunction; + arg = ti->mArg; + + /* The thread is responsible for freeing the startup information */ + free((void *)ti); + + /* Call the actual client thread function */ + res = fun(arg); + +#if defined(_TTHREAD_WIN32_) + return res; +#else + pres = malloc(sizeof(int)); + if (pres != NULL) + { + *(int*)pres = res; + } + return pres; +#endif +} + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + /* Fill out the thread startup information (passed to the thread wrapper, + which will eventually free it) */ + _thread_start_info* ti = (_thread_start_info*)malloc(sizeof(_thread_start_info)); + if (ti == NULL) + { + return thrd_nomem; + } + ti->mFunction = func; + ti->mArg = arg; + + /* Create the thread */ +#if defined(_TTHREAD_WIN32_) + *thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL); +#elif defined(_TTHREAD_POSIX_) + if(pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0) + { + *thr = 0; + } +#endif + + /* Did we fail to create the thread? */ + if(!*thr) + { + free(ti); + return thrd_error; + } + + return thrd_success; +} + +thrd_t thrd_current(void) +{ +#if defined(_TTHREAD_WIN32_) + return GetCurrentThread(); +#else + return pthread_self(); +#endif +} + +int thrd_detach(thrd_t thr) +{ + /* FIXME! */ + (void)thr; + return thrd_error; +} + +int thrd_equal(thrd_t thr0, thrd_t thr1) +{ +#if defined(_TTHREAD_WIN32_) + return thr0 == thr1; +#else + return pthread_equal(thr0, thr1); +#endif +} + +void thrd_exit(int res) +{ +#if defined(_TTHREAD_WIN32_) + ExitThread(res); +#else + void *pres = malloc(sizeof(int)); + if (pres != NULL) + { + *(int*)pres = res; + } + pthread_exit(pres); +#endif +} + +int thrd_join(thrd_t thr, int *res) +{ +#if defined(_TTHREAD_WIN32_) + if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED) + { + return thrd_error; + } + if (res != NULL) + { + DWORD dwRes; + GetExitCodeThread(thr, &dwRes); + *res = dwRes; + } +#elif defined(_TTHREAD_POSIX_) + void *pres; + int ires = 0; + if (pthread_join(thr, &pres) != 0) + { + return thrd_error; + } + if (pres != NULL) + { + ires = *(int*)pres; + free(pres); + } + if (res != NULL) + { + *res = ires; + } +#endif + return thrd_success; +} + +int thrd_sleep(const struct timespec *time_point, struct timespec *remaining) +{ + struct timespec now; +#if defined(_TTHREAD_WIN32_) + DWORD delta; +#else + long delta; +#endif + + /* Get the current time */ + if (clock_gettime(CLOCK_REALTIME, &now) != 0) + return -2; // FIXME: Some specific error code? + +#if defined(_TTHREAD_WIN32_) + /* Delta in milliseconds */ + delta = (DWORD) ((time_point->tv_sec - now.tv_sec) * 1000 + + (time_point->tv_nsec - now.tv_nsec + 500000) / 1000000); + if (delta > 0) + { + Sleep(delta); + } +#else + /* Delta in microseconds */ + delta = (time_point->tv_sec - now.tv_sec) * 1000000L + + (time_point->tv_nsec - now.tv_nsec + 500L) / 1000L; + + /* On some systems, the usleep argument must be < 1000000 */ + while (delta > 999999L) + { + usleep(999999); + delta -= 999999L; + } + if (delta > 0L) + { + usleep((useconds_t)delta); + } +#endif + + /* We don't support waking up prematurely (yet) */ + if (remaining) + { + remaining->tv_sec = 0; + remaining->tv_nsec = 0; + } + return 0; +} + +void thrd_yield(void) +{ +#if defined(_TTHREAD_WIN32_) + Sleep(0); +#else + sched_yield(); +#endif +} + +int tss_create(tss_t *key, tss_dtor_t dtor) +{ +#if defined(_TTHREAD_WIN32_) + /* FIXME: The destructor function is not supported yet... */ + if (dtor != NULL) + { + return thrd_error; + } + *key = TlsAlloc(); + if (*key == TLS_OUT_OF_INDEXES) + { + return thrd_error; + } +#else + if (pthread_key_create(key, dtor) != 0) + { + return thrd_error; + } +#endif + return thrd_success; +} + +void tss_delete(tss_t key) +{ +#if defined(_TTHREAD_WIN32_) + TlsFree(key); +#else + pthread_key_delete(key); +#endif +} + +void *tss_get(tss_t key) +{ +#if defined(_TTHREAD_WIN32_) + return TlsGetValue(key); +#else + return pthread_getspecific(key); +#endif +} + +int tss_set(tss_t key, void *val) +{ +#if defined(_TTHREAD_WIN32_) + if (TlsSetValue(key, val) == 0) + { + return thrd_error; + } +#else + if (pthread_setspecific(key, val) != 0) + { + return thrd_error; + } +#endif + return thrd_success; +} + +#if defined(_TTHREAD_EMULATE_CLOCK_GETTIME_) +int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts) +{ +#if defined(_TTHREAD_WIN32_) + struct _timeb tb; + _ftime(&tb); + ts->tv_sec = (time_t)tb.time; + ts->tv_nsec = 1000000L * (long)tb.millitm; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + ts->tv_sec = (time_t)tv.tv_sec; + ts->tv_nsec = 1000L * (long)tv.tv_usec; +#endif + return 0; +} +#endif // _TTHREAD_EMULATE_CLOCK_GETTIME_ + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/tinycthread.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/tinycthread.h new file mode 100644 index 00000000..6da30d70 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/tinycthread.h @@ -0,0 +1,441 @@ +/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- +Copyright (c) 2012 Marcus Geelnard + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef _TINYCTHREAD_H_ +#define _TINYCTHREAD_H_ + +/** +* @file +* @mainpage TinyCThread API Reference +* +* @section intro_sec Introduction +* TinyCThread is a minimal, portable implementation of basic threading +* classes for C. +* +* They closely mimic the functionality and naming of the C11 standard, and +* should be easily replaceable with the corresponding standard variants. +* +* @section port_sec Portability +* The Win32 variant uses the native Win32 API for implementing the thread +* classes, while for other systems, the POSIX threads API (pthread) is used. +* +* @section misc_sec Miscellaneous +* The following special keywords are available: #_Thread_local. +* +* For more detailed information, browse the different sections of this +* documentation. A good place to start is: +* tinycthread.h. +*/ + +/* Which platform are we on? */ +#if !defined(_TTHREAD_PLATFORM_DEFINED_) + #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) + #define _TTHREAD_WIN32_ + #else + #define _TTHREAD_POSIX_ + #endif + #define _TTHREAD_PLATFORM_DEFINED_ +#endif + +/* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */ +#if defined(_TTHREAD_POSIX_) + #undef _FEATURES_H + #if !defined(_GNU_SOURCE) + #define _GNU_SOURCE + #endif + #if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) + #undef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309L + #endif + #if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) + #undef _XOPEN_SOURCE + #define _XOPEN_SOURCE 500 + #endif +#endif + +/* Generic includes */ +#include + +/* Platform specific includes */ +#if defined(_TTHREAD_POSIX_) + #include + #include +#elif defined(_TTHREAD_WIN32_) + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #define __UNDEF_LEAN_AND_MEAN + #endif + #include + #ifdef __UNDEF_LEAN_AND_MEAN + #undef WIN32_LEAN_AND_MEAN + #undef __UNDEF_LEAN_AND_MEAN + #endif +#endif + +/* Workaround for missing TIME_UTC: If time.h doesn't provide TIME_UTC, + it's quite likely that libc does not support it either. Hence, fall back to + the only other supported time specifier: CLOCK_REALTIME (and if that fails, + we're probably emulating clock_gettime anyway, so anything goes). */ +#ifndef TIME_UTC + #ifdef CLOCK_REALTIME + #define TIME_UTC CLOCK_REALTIME + #else + #define TIME_UTC 0 + #endif +#endif + +/* Workaround for missing clock_gettime (most Windows compilers, afaik) */ +#if defined(_TTHREAD_WIN32_) || defined(__APPLE_CC__) +#define _TTHREAD_EMULATE_CLOCK_GETTIME_ +/* Emulate struct timespec */ +#if defined(_TTHREAD_WIN32_) +struct _ttherad_timespec { + time_t tv_sec; + long tv_nsec; +}; +#define timespec _ttherad_timespec +#endif + +/* Emulate clockid_t */ +typedef int _tthread_clockid_t; +#define clockid_t _tthread_clockid_t + +/* Emulate clock_gettime */ +int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); +#define clock_gettime _tthread_clock_gettime +#define CLOCK_REALTIME 0 +#endif + + +/** TinyCThread version (major number). */ +#define TINYCTHREAD_VERSION_MAJOR 1 +/** TinyCThread version (minor number). */ +#define TINYCTHREAD_VERSION_MINOR 1 +/** TinyCThread version (full version). */ +#define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR) + +/** +* @def _Thread_local +* Thread local storage keyword. +* A variable that is declared with the @c _Thread_local keyword makes the +* value of the variable local to each thread (known as thread-local storage, +* or TLS). Example usage: +* @code +* // This variable is local to each thread. +* _Thread_local int variable; +* @endcode +* @note The @c _Thread_local keyword is a macro that maps to the corresponding +* compiler directive (e.g. @c __declspec(thread)). +* @note This directive is currently not supported on Mac OS X (it will give +* a compiler error), since compile-time TLS is not supported in the Mac OS X +* executable format. Also, some older versions of MinGW (before GCC 4.x) do +* not support this directive. +* @hideinitializer +*/ + +/* FIXME: Check for a PROPER value of __STDC_VERSION__ to know if we have C11 */ +#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local) + #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) + #define _Thread_local __thread + #else + #define _Thread_local __declspec(thread) + #endif +#endif + +/* Macros */ +#define TSS_DTOR_ITERATIONS 0 + +/* Function return values */ +#define thrd_error 0 /**< The requested operation failed */ +#define thrd_success 1 /**< The requested operation succeeded */ +#define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ +#define thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ +#define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ + +/* Mutex types */ +#define mtx_plain 1 +#define mtx_timed 2 +#define mtx_try 4 +#define mtx_recursive 8 + +/* Mutex */ +#if defined(_TTHREAD_WIN32_) +typedef struct { + CRITICAL_SECTION mHandle; /* Critical section handle */ + int mAlreadyLocked; /* TRUE if the mutex is already locked */ + int mRecursive; /* TRUE if the mutex is recursive */ +} mtx_t; +#else +typedef pthread_mutex_t mtx_t; +#endif + +/** Create a mutex object. +* @param mtx A mutex object. +* @param type Bit-mask that must have one of the following six values: +* @li @c mtx_plain for a simple non-recursive mutex +* @li @c mtx_timed for a non-recursive mutex that supports timeout +* @li @c mtx_try for a non-recursive mutex that supports test and return +* @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) +* @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) +* @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int mtx_init(mtx_t *mtx, int type); + +/** Release any resources used by the given mutex. +* @param mtx A mutex object. +*/ +void mtx_destroy(mtx_t *mtx); + +/** Lock the given mutex. +* Blocks until the given mutex can be locked. If the mutex is non-recursive, and +* the calling thread already has a lock on the mutex, this call will block +* forever. +* @param mtx A mutex object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int mtx_lock(mtx_t *mtx); + +/** NOT YET IMPLEMENTED. +*/ +int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); + +/** Try to lock the given mutex. +* The specified mutex shall support either test and return or timeout. If the +* mutex is already locked, the function returns without blocking. +* @param mtx A mutex object. +* @return @ref thrd_success on success, or @ref thrd_busy if the resource +* requested is already in use, or @ref thrd_error if the request could not be +* honored. +*/ +int mtx_trylock(mtx_t *mtx); + +/** Unlock the given mutex. +* @param mtx A mutex object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int mtx_unlock(mtx_t *mtx); + +/* Condition variable */ +#if defined(_TTHREAD_WIN32_) +typedef struct { + HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ + unsigned int mWaitersCount; /* Count of the number of waiters. */ + CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ +} cnd_t; +#else +typedef pthread_cond_t cnd_t; +#endif + +/** Create a condition variable object. +* @param cond A condition variable object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int cnd_init(cnd_t *cond); + +/** Release any resources used by the given condition variable. +* @param cond A condition variable object. +*/ +void cnd_destroy(cnd_t *cond); + +/** Signal a condition variable. +* Unblocks one of the threads that are blocked on the given condition variable +* at the time of the call. If no threads are blocked on the condition variable +* at the time of the call, the function does nothing and return success. +* @param cond A condition variable object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int cnd_signal(cnd_t *cond); + +/** Broadcast a condition variable. +* Unblocks all of the threads that are blocked on the given condition variable +* at the time of the call. If no threads are blocked on the condition variable +* at the time of the call, the function does nothing and return success. +* @param cond A condition variable object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int cnd_broadcast(cnd_t *cond); + +/** Wait for a condition variable to become signaled. +* The function atomically unlocks the given mutex and endeavors to block until +* the given condition variable is signaled by a call to cnd_signal or to +* cnd_broadcast. When the calling thread becomes unblocked it locks the mutex +* before it returns. +* @param cond A condition variable object. +* @param mtx A mutex object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int cnd_wait(cnd_t *cond, mtx_t *mtx); + +/** Wait for a condition variable to become signaled. +* The function atomically unlocks the given mutex and endeavors to block until +* the given condition variable is signaled by a call to cnd_signal or to +* cnd_broadcast, or until after the specified time. When the calling thread +* becomes unblocked it locks the mutex before it returns. +* @param cond A condition variable object. +* @param mtx A mutex object. +* @param xt A point in time at which the request will time out (absolute time). +* @return @ref thrd_success upon success, or @ref thrd_timeout if the time +* specified in the call was reached without acquiring the requested resource, or +* @ref thrd_error if the request could not be honored. +*/ +int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); + +/* Thread */ +#if defined(_TTHREAD_WIN32_) +typedef HANDLE thrd_t; +#else +typedef pthread_t thrd_t; +#endif + +/** Thread start function. +* Any thread that is started with the @ref thrd_create() function must be +* started through a function of this type. +* @param arg The thread argument (the @c arg argument of the corresponding +* @ref thrd_create() call). +* @return The thread return value, which can be obtained by another thread +* by using the @ref thrd_join() function. +*/ +typedef int (*thrd_start_t)(void *arg); + +/** Create a new thread. +* @param thr Identifier of the newly created thread. +* @param func A function pointer to the function that will be executed in +* the new thread. +* @param arg An argument to the thread function. +* @return @ref thrd_success on success, or @ref thrd_nomem if no memory could +* be allocated for the thread requested, or @ref thrd_error if the request +* could not be honored. +* @note A thread’s identifier may be reused for a different thread once the +* original thread has exited and either been detached or joined to another +* thread. +*/ +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); + +/** Identify the calling thread. +* @return The identifier of the calling thread. +*/ +thrd_t thrd_current(void); + +/** NOT YET IMPLEMENTED. +*/ +int thrd_detach(thrd_t thr); + +/** Compare two thread identifiers. +* The function determines if two thread identifiers refer to the same thread. +* @return Zero if the two thread identifiers refer to different threads. +* Otherwise a nonzero value is returned. +*/ +int thrd_equal(thrd_t thr0, thrd_t thr1); + +/** Terminate execution of the calling thread. +* @param res Result code of the calling thread. +*/ +void thrd_exit(int res); + +/** Wait for a thread to terminate. +* The function joins the given thread with the current thread by blocking +* until the other thread has terminated. +* @param thr The thread to join with. +* @param res If this pointer is not NULL, the function will store the result +* code of the given thread in the integer pointed to by @c res. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int thrd_join(thrd_t thr, int *res); + +/** Put the calling thread to sleep. +* Suspend execution of the calling thread. +* @param time_point A point in time at which the thread will resume (absolute time). +* @param remaining If non-NULL, this parameter will hold the remaining time until +* time_point upon return. This will typically be zero, but if +* the thread was woken up by a signal that is not ignored before +* time_point was reached @c remaining will hold a positive +* time. +* @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. +*/ +int thrd_sleep(const struct timespec *time_point, struct timespec *remaining); + +/** Yield execution to another thread. +* Permit other threads to run, even if the current thread would ordinarily +* continue to run. +*/ +void thrd_yield(void); + +/* Thread local storage */ +#if defined(_TTHREAD_WIN32_) +typedef DWORD tss_t; +#else +typedef pthread_key_t tss_t; +#endif + +/** Destructor function for a thread-specific storage. +* @param val The value of the destructed thread-specific storage. +*/ +typedef void (*tss_dtor_t)(void *val); + +/** Create a thread-specific storage. +* @param key The unique key identifier that will be set if the function is +* successful. +* @param dtor Destructor function. This can be NULL. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +* @note The destructor function is not supported under Windows. If @c dtor is +* not NULL when calling this function under Windows, the function will fail +* and return @ref thrd_error. +*/ +int tss_create(tss_t *key, tss_dtor_t dtor); + +/** Delete a thread-specific storage. +* The function releases any resources used by the given thread-specific +* storage. +* @param key The key that shall be deleted. +*/ +void tss_delete(tss_t key); + +/** Get the value for a thread-specific storage. +* @param key The thread-specific storage identifier. +* @return The value for the current thread held in the given thread-specific +* storage. +*/ +void *tss_get(tss_t key); + +/** Set the value for a thread-specific storage. +* @param key The thread-specific storage identifier. +* @param val The value of the thread-specific storage to set for the current +* thread. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int tss_set(tss_t key, void *val); + + +#endif /* _TINYTHREAD_H_ */ + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/vulkan/vk_platform.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/vulkan/vk_platform.h new file mode 100644 index 00000000..5d0fc766 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/vulkan/vk_platform.h @@ -0,0 +1,120 @@ +// +// File: vk_platform.h +// +/* +** Copyright (c) 2014-2015 The Khronos Group Inc. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + + +#ifndef VK_PLATFORM_H_ +#define VK_PLATFORM_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/* +*************************************************************************************************** +* Platform-specific directives and type declarations +*************************************************************************************************** +*/ + +/* Platform-specific calling convention macros. + * + * Platforms should define these so that Vulkan clients call Vulkan commands + * with the same calling conventions that the Vulkan implementation expects. + * + * VKAPI_ATTR - Placed before the return type in function declarations. + * Useful for C++11 and GCC/Clang-style function attribute syntax. + * VKAPI_CALL - Placed after the return type in function declarations. + * Useful for MSVC-style calling convention syntax. + * VKAPI_PTR - Placed between the '(' and '*' in function pointer types. + * + * Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); + * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); + */ +#if defined(_WIN32) + // On Windows, Vulkan commands use the stdcall convention + #define VKAPI_ATTR + #define VKAPI_CALL __stdcall + #define VKAPI_PTR VKAPI_CALL +#elif defined(__ANDROID__) && defined(__ARM_EABI__) && !defined(__ARM_ARCH_7A__) + // Android does not support Vulkan in native code using the "armeabi" ABI. + #error "Vulkan requires the 'armeabi-v7a' or 'armeabi-v7a-hard' ABI on 32-bit ARM CPUs" +#elif defined(__ANDROID__) && defined(__ARM_ARCH_7A__) + // On Android/ARMv7a, Vulkan functions use the armeabi-v7a-hard calling + // convention, even if the application's native code is compiled with the + // armeabi-v7a calling convention. + #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) + #define VKAPI_CALL + #define VKAPI_PTR VKAPI_ATTR +#else + // On other platforms, use the default calling convention + #define VKAPI_ATTR + #define VKAPI_CALL + #define VKAPI_PTR +#endif + +#include + +#if !defined(VK_NO_STDINT_H) + #if defined(_MSC_VER) && (_MSC_VER < 1600) + typedef signed __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef signed __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef signed __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef signed __int64 int64_t; + typedef unsigned __int64 uint64_t; + #else + #include + #endif +#endif // !defined(VK_NO_STDINT_H) + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +// Platform-specific headers required by platform window system extensions. +// These are enabled prior to #including "vulkan.h". The same enable then +// controls inclusion of the extension interfaces in vulkan.h. + +#ifdef VK_USE_PLATFORM_ANDROID_KHR +#include +#endif + +#ifdef VK_USE_PLATFORM_MIR_KHR +#include +#endif + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +#include +#endif + +#ifdef VK_USE_PLATFORM_WIN32_KHR +#include +#endif + +#ifdef VK_USE_PLATFORM_XLIB_KHR +#include +#endif + +#ifdef VK_USE_PLATFORM_XCB_KHR +#include +#endif + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/vulkan/vulkan.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/vulkan/vulkan.h new file mode 100644 index 00000000..eb8343e2 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/deps/vulkan/vulkan.h @@ -0,0 +1,3835 @@ +#ifndef VULKAN_H_ +#define VULKAN_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2015-2016 The Khronos Group Inc. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#define VK_VERSION_1_0 1 +#include "vk_platform.h" + +#define VK_MAKE_VERSION(major, minor, patch) \ + (((major) << 22) | ((minor) << 12) | (patch)) + +// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. +//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) + +// Vulkan 1.0 version number +#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0) + +#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) +#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) +#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) +// Version of this file +#define VK_HEADER_VERSION 11 + + +#define VK_NULL_HANDLE 0 + + + +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; + + +#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; +#else + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; +#endif + + + +typedef uint32_t VkFlags; +typedef uint32_t VkBool32; +typedef uint64_t VkDeviceSize; +typedef uint32_t VkSampleMask; + +VK_DEFINE_HANDLE(VkInstance) +VK_DEFINE_HANDLE(VkPhysicalDevice) +VK_DEFINE_HANDLE(VkDevice) +VK_DEFINE_HANDLE(VkQueue) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) +VK_DEFINE_HANDLE(VkCommandBuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) + +#define VK_LOD_CLAMP_NONE 1000.0f +#define VK_REMAINING_MIP_LEVELS (~0U) +#define VK_REMAINING_ARRAY_LAYERS (~0U) +#define VK_WHOLE_SIZE (~0ULL) +#define VK_ATTACHMENT_UNUSED (~0U) +#define VK_TRUE 1 +#define VK_FALSE 0 +#define VK_QUEUE_FAMILY_IGNORED (~0U) +#define VK_SUBPASS_EXTERNAL (~0U) +#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 +#define VK_UUID_SIZE 16 +#define VK_MAX_MEMORY_TYPES 32 +#define VK_MAX_MEMORY_HEAPS 16 +#define VK_MAX_EXTENSION_NAME_SIZE 256 +#define VK_MAX_DESCRIPTION_SIZE 256 + + +typedef enum VkPipelineCacheHeaderVersion { + VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, + VK_PIPELINE_CACHE_HEADER_VERSION_BEGIN_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, + VK_PIPELINE_CACHE_HEADER_VERSION_END_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, + VK_PIPELINE_CACHE_HEADER_VERSION_RANGE_SIZE = (VK_PIPELINE_CACHE_HEADER_VERSION_ONE - VK_PIPELINE_CACHE_HEADER_VERSION_ONE + 1), + VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCacheHeaderVersion; + +typedef enum VkResult { + VK_SUCCESS = 0, + VK_NOT_READY = 1, + VK_TIMEOUT = 2, + VK_EVENT_SET = 3, + VK_EVENT_RESET = 4, + VK_INCOMPLETE = 5, + VK_ERROR_OUT_OF_HOST_MEMORY = -1, + VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, + VK_ERROR_INITIALIZATION_FAILED = -3, + VK_ERROR_DEVICE_LOST = -4, + VK_ERROR_MEMORY_MAP_FAILED = -5, + VK_ERROR_LAYER_NOT_PRESENT = -6, + VK_ERROR_EXTENSION_NOT_PRESENT = -7, + VK_ERROR_FEATURE_NOT_PRESENT = -8, + VK_ERROR_INCOMPATIBLE_DRIVER = -9, + VK_ERROR_TOO_MANY_OBJECTS = -10, + VK_ERROR_FORMAT_NOT_SUPPORTED = -11, + VK_ERROR_SURFACE_LOST_KHR = -1000000000, + VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, + VK_SUBOPTIMAL_KHR = 1000001003, + VK_ERROR_OUT_OF_DATE_KHR = -1000001004, + VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, + VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, + VK_ERROR_INVALID_SHADER_NV = -1000012000, + VK_RESULT_BEGIN_RANGE = VK_ERROR_FORMAT_NOT_SUPPORTED, + VK_RESULT_END_RANGE = VK_INCOMPLETE, + VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FORMAT_NOT_SUPPORTED + 1), + VK_RESULT_MAX_ENUM = 0x7FFFFFFF +} VkResult; + +typedef enum VkStructureType { + VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2, + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3, + VK_STRUCTURE_TYPE_SUBMIT_INFO = 4, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5, + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6, + VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7, + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8, + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9, + VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10, + VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11, + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12, + VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13, + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14, + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15, + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16, + VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28, + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29, + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30, + VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35, + VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36, + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38, + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42, + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45, + VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46, + VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, + VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, + VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, + VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, + VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000, + VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, + VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, + VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, + VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000, + VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, + VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, + VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, + VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO, + VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO, + VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1), + VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkStructureType; + +typedef enum VkSystemAllocationScope { + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1, + VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2, + VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3, + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4, + VK_SYSTEM_ALLOCATION_SCOPE_BEGIN_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_COMMAND, + VK_SYSTEM_ALLOCATION_SCOPE_END_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE, + VK_SYSTEM_ALLOCATION_SCOPE_RANGE_SIZE = (VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND + 1), + VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF +} VkSystemAllocationScope; + +typedef enum VkInternalAllocationType { + VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0, + VK_INTERNAL_ALLOCATION_TYPE_BEGIN_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, + VK_INTERNAL_ALLOCATION_TYPE_END_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, + VK_INTERNAL_ALLOCATION_TYPE_RANGE_SIZE = (VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE + 1), + VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkInternalAllocationType; + +typedef enum VkFormat { + VK_FORMAT_UNDEFINED = 0, + VK_FORMAT_R4G4_UNORM_PACK8 = 1, + VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2, + VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3, + VK_FORMAT_R5G6B5_UNORM_PACK16 = 4, + VK_FORMAT_B5G6R5_UNORM_PACK16 = 5, + VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6, + VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7, + VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8, + VK_FORMAT_R8_UNORM = 9, + VK_FORMAT_R8_SNORM = 10, + VK_FORMAT_R8_USCALED = 11, + VK_FORMAT_R8_SSCALED = 12, + VK_FORMAT_R8_UINT = 13, + VK_FORMAT_R8_SINT = 14, + VK_FORMAT_R8_SRGB = 15, + VK_FORMAT_R8G8_UNORM = 16, + VK_FORMAT_R8G8_SNORM = 17, + VK_FORMAT_R8G8_USCALED = 18, + VK_FORMAT_R8G8_SSCALED = 19, + VK_FORMAT_R8G8_UINT = 20, + VK_FORMAT_R8G8_SINT = 21, + VK_FORMAT_R8G8_SRGB = 22, + VK_FORMAT_R8G8B8_UNORM = 23, + VK_FORMAT_R8G8B8_SNORM = 24, + VK_FORMAT_R8G8B8_USCALED = 25, + VK_FORMAT_R8G8B8_SSCALED = 26, + VK_FORMAT_R8G8B8_UINT = 27, + VK_FORMAT_R8G8B8_SINT = 28, + VK_FORMAT_R8G8B8_SRGB = 29, + VK_FORMAT_B8G8R8_UNORM = 30, + VK_FORMAT_B8G8R8_SNORM = 31, + VK_FORMAT_B8G8R8_USCALED = 32, + VK_FORMAT_B8G8R8_SSCALED = 33, + VK_FORMAT_B8G8R8_UINT = 34, + VK_FORMAT_B8G8R8_SINT = 35, + VK_FORMAT_B8G8R8_SRGB = 36, + VK_FORMAT_R8G8B8A8_UNORM = 37, + VK_FORMAT_R8G8B8A8_SNORM = 38, + VK_FORMAT_R8G8B8A8_USCALED = 39, + VK_FORMAT_R8G8B8A8_SSCALED = 40, + VK_FORMAT_R8G8B8A8_UINT = 41, + VK_FORMAT_R8G8B8A8_SINT = 42, + VK_FORMAT_R8G8B8A8_SRGB = 43, + VK_FORMAT_B8G8R8A8_UNORM = 44, + VK_FORMAT_B8G8R8A8_SNORM = 45, + VK_FORMAT_B8G8R8A8_USCALED = 46, + VK_FORMAT_B8G8R8A8_SSCALED = 47, + VK_FORMAT_B8G8R8A8_UINT = 48, + VK_FORMAT_B8G8R8A8_SINT = 49, + VK_FORMAT_B8G8R8A8_SRGB = 50, + VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51, + VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52, + VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53, + VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54, + VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55, + VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56, + VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57, + VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58, + VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59, + VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60, + VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61, + VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62, + VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63, + VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64, + VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65, + VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66, + VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67, + VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68, + VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69, + VK_FORMAT_R16_UNORM = 70, + VK_FORMAT_R16_SNORM = 71, + VK_FORMAT_R16_USCALED = 72, + VK_FORMAT_R16_SSCALED = 73, + VK_FORMAT_R16_UINT = 74, + VK_FORMAT_R16_SINT = 75, + VK_FORMAT_R16_SFLOAT = 76, + VK_FORMAT_R16G16_UNORM = 77, + VK_FORMAT_R16G16_SNORM = 78, + VK_FORMAT_R16G16_USCALED = 79, + VK_FORMAT_R16G16_SSCALED = 80, + VK_FORMAT_R16G16_UINT = 81, + VK_FORMAT_R16G16_SINT = 82, + VK_FORMAT_R16G16_SFLOAT = 83, + VK_FORMAT_R16G16B16_UNORM = 84, + VK_FORMAT_R16G16B16_SNORM = 85, + VK_FORMAT_R16G16B16_USCALED = 86, + VK_FORMAT_R16G16B16_SSCALED = 87, + VK_FORMAT_R16G16B16_UINT = 88, + VK_FORMAT_R16G16B16_SINT = 89, + VK_FORMAT_R16G16B16_SFLOAT = 90, + VK_FORMAT_R16G16B16A16_UNORM = 91, + VK_FORMAT_R16G16B16A16_SNORM = 92, + VK_FORMAT_R16G16B16A16_USCALED = 93, + VK_FORMAT_R16G16B16A16_SSCALED = 94, + VK_FORMAT_R16G16B16A16_UINT = 95, + VK_FORMAT_R16G16B16A16_SINT = 96, + VK_FORMAT_R16G16B16A16_SFLOAT = 97, + VK_FORMAT_R32_UINT = 98, + VK_FORMAT_R32_SINT = 99, + VK_FORMAT_R32_SFLOAT = 100, + VK_FORMAT_R32G32_UINT = 101, + VK_FORMAT_R32G32_SINT = 102, + VK_FORMAT_R32G32_SFLOAT = 103, + VK_FORMAT_R32G32B32_UINT = 104, + VK_FORMAT_R32G32B32_SINT = 105, + VK_FORMAT_R32G32B32_SFLOAT = 106, + VK_FORMAT_R32G32B32A32_UINT = 107, + VK_FORMAT_R32G32B32A32_SINT = 108, + VK_FORMAT_R32G32B32A32_SFLOAT = 109, + VK_FORMAT_R64_UINT = 110, + VK_FORMAT_R64_SINT = 111, + VK_FORMAT_R64_SFLOAT = 112, + VK_FORMAT_R64G64_UINT = 113, + VK_FORMAT_R64G64_SINT = 114, + VK_FORMAT_R64G64_SFLOAT = 115, + VK_FORMAT_R64G64B64_UINT = 116, + VK_FORMAT_R64G64B64_SINT = 117, + VK_FORMAT_R64G64B64_SFLOAT = 118, + VK_FORMAT_R64G64B64A64_UINT = 119, + VK_FORMAT_R64G64B64A64_SINT = 120, + VK_FORMAT_R64G64B64A64_SFLOAT = 121, + VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122, + VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123, + VK_FORMAT_D16_UNORM = 124, + VK_FORMAT_X8_D24_UNORM_PACK32 = 125, + VK_FORMAT_D32_SFLOAT = 126, + VK_FORMAT_S8_UINT = 127, + VK_FORMAT_D16_UNORM_S8_UINT = 128, + VK_FORMAT_D24_UNORM_S8_UINT = 129, + VK_FORMAT_D32_SFLOAT_S8_UINT = 130, + VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131, + VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132, + VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133, + VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134, + VK_FORMAT_BC2_UNORM_BLOCK = 135, + VK_FORMAT_BC2_SRGB_BLOCK = 136, + VK_FORMAT_BC3_UNORM_BLOCK = 137, + VK_FORMAT_BC3_SRGB_BLOCK = 138, + VK_FORMAT_BC4_UNORM_BLOCK = 139, + VK_FORMAT_BC4_SNORM_BLOCK = 140, + VK_FORMAT_BC5_UNORM_BLOCK = 141, + VK_FORMAT_BC5_SNORM_BLOCK = 142, + VK_FORMAT_BC6H_UFLOAT_BLOCK = 143, + VK_FORMAT_BC6H_SFLOAT_BLOCK = 144, + VK_FORMAT_BC7_UNORM_BLOCK = 145, + VK_FORMAT_BC7_SRGB_BLOCK = 146, + VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147, + VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148, + VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149, + VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150, + VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151, + VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152, + VK_FORMAT_EAC_R11_UNORM_BLOCK = 153, + VK_FORMAT_EAC_R11_SNORM_BLOCK = 154, + VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155, + VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156, + VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157, + VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158, + VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159, + VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160, + VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161, + VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162, + VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163, + VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164, + VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165, + VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166, + VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167, + VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168, + VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169, + VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170, + VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171, + VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172, + VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173, + VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174, + VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175, + VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176, + VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177, + VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178, + VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179, + VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180, + VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181, + VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, + VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, + VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, + VK_FORMAT_BEGIN_RANGE = VK_FORMAT_UNDEFINED, + VK_FORMAT_END_RANGE = VK_FORMAT_ASTC_12x12_SRGB_BLOCK, + VK_FORMAT_RANGE_SIZE = (VK_FORMAT_ASTC_12x12_SRGB_BLOCK - VK_FORMAT_UNDEFINED + 1), + VK_FORMAT_MAX_ENUM = 0x7FFFFFFF +} VkFormat; + +typedef enum VkImageType { + VK_IMAGE_TYPE_1D = 0, + VK_IMAGE_TYPE_2D = 1, + VK_IMAGE_TYPE_3D = 2, + VK_IMAGE_TYPE_BEGIN_RANGE = VK_IMAGE_TYPE_1D, + VK_IMAGE_TYPE_END_RANGE = VK_IMAGE_TYPE_3D, + VK_IMAGE_TYPE_RANGE_SIZE = (VK_IMAGE_TYPE_3D - VK_IMAGE_TYPE_1D + 1), + VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkImageType; + +typedef enum VkImageTiling { + VK_IMAGE_TILING_OPTIMAL = 0, + VK_IMAGE_TILING_LINEAR = 1, + VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR, + VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1), + VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF +} VkImageTiling; + +typedef enum VkPhysicalDeviceType { + VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, + VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, + VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, + VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, + VK_PHYSICAL_DEVICE_TYPE_CPU = 4, + VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE = VK_PHYSICAL_DEVICE_TYPE_OTHER, + VK_PHYSICAL_DEVICE_TYPE_END_RANGE = VK_PHYSICAL_DEVICE_TYPE_CPU, + VK_PHYSICAL_DEVICE_TYPE_RANGE_SIZE = (VK_PHYSICAL_DEVICE_TYPE_CPU - VK_PHYSICAL_DEVICE_TYPE_OTHER + 1), + VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkPhysicalDeviceType; + +typedef enum VkQueryType { + VK_QUERY_TYPE_OCCLUSION = 0, + VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, + VK_QUERY_TYPE_TIMESTAMP = 2, + VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION, + VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP, + VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1), + VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkQueryType; + +typedef enum VkSharingMode { + VK_SHARING_MODE_EXCLUSIVE = 0, + VK_SHARING_MODE_CONCURRENT = 1, + VK_SHARING_MODE_BEGIN_RANGE = VK_SHARING_MODE_EXCLUSIVE, + VK_SHARING_MODE_END_RANGE = VK_SHARING_MODE_CONCURRENT, + VK_SHARING_MODE_RANGE_SIZE = (VK_SHARING_MODE_CONCURRENT - VK_SHARING_MODE_EXCLUSIVE + 1), + VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSharingMode; + +typedef enum VkImageLayout { + VK_IMAGE_LAYOUT_UNDEFINED = 0, + VK_IMAGE_LAYOUT_GENERAL = 1, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7, + VK_IMAGE_LAYOUT_PREINITIALIZED = 8, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, + VK_IMAGE_LAYOUT_BEGIN_RANGE = VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_END_RANGE = VK_IMAGE_LAYOUT_PREINITIALIZED, + VK_IMAGE_LAYOUT_RANGE_SIZE = (VK_IMAGE_LAYOUT_PREINITIALIZED - VK_IMAGE_LAYOUT_UNDEFINED + 1), + VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF +} VkImageLayout; + +typedef enum VkImageViewType { + VK_IMAGE_VIEW_TYPE_1D = 0, + VK_IMAGE_VIEW_TYPE_2D = 1, + VK_IMAGE_VIEW_TYPE_3D = 2, + VK_IMAGE_VIEW_TYPE_CUBE = 3, + VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4, + VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5, + VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6, + VK_IMAGE_VIEW_TYPE_BEGIN_RANGE = VK_IMAGE_VIEW_TYPE_1D, + VK_IMAGE_VIEW_TYPE_END_RANGE = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, + VK_IMAGE_VIEW_TYPE_RANGE_SIZE = (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY - VK_IMAGE_VIEW_TYPE_1D + 1), + VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkImageViewType; + +typedef enum VkComponentSwizzle { + VK_COMPONENT_SWIZZLE_IDENTITY = 0, + VK_COMPONENT_SWIZZLE_ZERO = 1, + VK_COMPONENT_SWIZZLE_ONE = 2, + VK_COMPONENT_SWIZZLE_R = 3, + VK_COMPONENT_SWIZZLE_G = 4, + VK_COMPONENT_SWIZZLE_B = 5, + VK_COMPONENT_SWIZZLE_A = 6, + VK_COMPONENT_SWIZZLE_BEGIN_RANGE = VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_END_RANGE = VK_COMPONENT_SWIZZLE_A, + VK_COMPONENT_SWIZZLE_RANGE_SIZE = (VK_COMPONENT_SWIZZLE_A - VK_COMPONENT_SWIZZLE_IDENTITY + 1), + VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF +} VkComponentSwizzle; + +typedef enum VkVertexInputRate { + VK_VERTEX_INPUT_RATE_VERTEX = 0, + VK_VERTEX_INPUT_RATE_INSTANCE = 1, + VK_VERTEX_INPUT_RATE_BEGIN_RANGE = VK_VERTEX_INPUT_RATE_VERTEX, + VK_VERTEX_INPUT_RATE_END_RANGE = VK_VERTEX_INPUT_RATE_INSTANCE, + VK_VERTEX_INPUT_RATE_RANGE_SIZE = (VK_VERTEX_INPUT_RATE_INSTANCE - VK_VERTEX_INPUT_RATE_VERTEX + 1), + VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF +} VkVertexInputRate; + +typedef enum VkPrimitiveTopology { + VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9, + VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10, + VK_PRIMITIVE_TOPOLOGY_BEGIN_RANGE = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, + VK_PRIMITIVE_TOPOLOGY_END_RANGE = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, + VK_PRIMITIVE_TOPOLOGY_RANGE_SIZE = (VK_PRIMITIVE_TOPOLOGY_PATCH_LIST - VK_PRIMITIVE_TOPOLOGY_POINT_LIST + 1), + VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF +} VkPrimitiveTopology; + +typedef enum VkPolygonMode { + VK_POLYGON_MODE_FILL = 0, + VK_POLYGON_MODE_LINE = 1, + VK_POLYGON_MODE_POINT = 2, + VK_POLYGON_MODE_BEGIN_RANGE = VK_POLYGON_MODE_FILL, + VK_POLYGON_MODE_END_RANGE = VK_POLYGON_MODE_POINT, + VK_POLYGON_MODE_RANGE_SIZE = (VK_POLYGON_MODE_POINT - VK_POLYGON_MODE_FILL + 1), + VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF +} VkPolygonMode; + +typedef enum VkFrontFace { + VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, + VK_FRONT_FACE_CLOCKWISE = 1, + VK_FRONT_FACE_BEGIN_RANGE = VK_FRONT_FACE_COUNTER_CLOCKWISE, + VK_FRONT_FACE_END_RANGE = VK_FRONT_FACE_CLOCKWISE, + VK_FRONT_FACE_RANGE_SIZE = (VK_FRONT_FACE_CLOCKWISE - VK_FRONT_FACE_COUNTER_CLOCKWISE + 1), + VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF +} VkFrontFace; + +typedef enum VkCompareOp { + VK_COMPARE_OP_NEVER = 0, + VK_COMPARE_OP_LESS = 1, + VK_COMPARE_OP_EQUAL = 2, + VK_COMPARE_OP_LESS_OR_EQUAL = 3, + VK_COMPARE_OP_GREATER = 4, + VK_COMPARE_OP_NOT_EQUAL = 5, + VK_COMPARE_OP_GREATER_OR_EQUAL = 6, + VK_COMPARE_OP_ALWAYS = 7, + VK_COMPARE_OP_BEGIN_RANGE = VK_COMPARE_OP_NEVER, + VK_COMPARE_OP_END_RANGE = VK_COMPARE_OP_ALWAYS, + VK_COMPARE_OP_RANGE_SIZE = (VK_COMPARE_OP_ALWAYS - VK_COMPARE_OP_NEVER + 1), + VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF +} VkCompareOp; + +typedef enum VkStencilOp { + VK_STENCIL_OP_KEEP = 0, + VK_STENCIL_OP_ZERO = 1, + VK_STENCIL_OP_REPLACE = 2, + VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3, + VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4, + VK_STENCIL_OP_INVERT = 5, + VK_STENCIL_OP_INCREMENT_AND_WRAP = 6, + VK_STENCIL_OP_DECREMENT_AND_WRAP = 7, + VK_STENCIL_OP_BEGIN_RANGE = VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_END_RANGE = VK_STENCIL_OP_DECREMENT_AND_WRAP, + VK_STENCIL_OP_RANGE_SIZE = (VK_STENCIL_OP_DECREMENT_AND_WRAP - VK_STENCIL_OP_KEEP + 1), + VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF +} VkStencilOp; + +typedef enum VkLogicOp { + VK_LOGIC_OP_CLEAR = 0, + VK_LOGIC_OP_AND = 1, + VK_LOGIC_OP_AND_REVERSE = 2, + VK_LOGIC_OP_COPY = 3, + VK_LOGIC_OP_AND_INVERTED = 4, + VK_LOGIC_OP_NO_OP = 5, + VK_LOGIC_OP_XOR = 6, + VK_LOGIC_OP_OR = 7, + VK_LOGIC_OP_NOR = 8, + VK_LOGIC_OP_EQUIVALENT = 9, + VK_LOGIC_OP_INVERT = 10, + VK_LOGIC_OP_OR_REVERSE = 11, + VK_LOGIC_OP_COPY_INVERTED = 12, + VK_LOGIC_OP_OR_INVERTED = 13, + VK_LOGIC_OP_NAND = 14, + VK_LOGIC_OP_SET = 15, + VK_LOGIC_OP_BEGIN_RANGE = VK_LOGIC_OP_CLEAR, + VK_LOGIC_OP_END_RANGE = VK_LOGIC_OP_SET, + VK_LOGIC_OP_RANGE_SIZE = (VK_LOGIC_OP_SET - VK_LOGIC_OP_CLEAR + 1), + VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF +} VkLogicOp; + +typedef enum VkBlendFactor { + VK_BLEND_FACTOR_ZERO = 0, + VK_BLEND_FACTOR_ONE = 1, + VK_BLEND_FACTOR_SRC_COLOR = 2, + VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3, + VK_BLEND_FACTOR_DST_COLOR = 4, + VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5, + VK_BLEND_FACTOR_SRC_ALPHA = 6, + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7, + VK_BLEND_FACTOR_DST_ALPHA = 8, + VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9, + VK_BLEND_FACTOR_CONSTANT_COLOR = 10, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11, + VK_BLEND_FACTOR_CONSTANT_ALPHA = 12, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13, + VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14, + VK_BLEND_FACTOR_SRC1_COLOR = 15, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16, + VK_BLEND_FACTOR_SRC1_ALPHA = 17, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18, + VK_BLEND_FACTOR_BEGIN_RANGE = VK_BLEND_FACTOR_ZERO, + VK_BLEND_FACTOR_END_RANGE = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, + VK_BLEND_FACTOR_RANGE_SIZE = (VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA - VK_BLEND_FACTOR_ZERO + 1), + VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF +} VkBlendFactor; + +typedef enum VkBlendOp { + VK_BLEND_OP_ADD = 0, + VK_BLEND_OP_SUBTRACT = 1, + VK_BLEND_OP_REVERSE_SUBTRACT = 2, + VK_BLEND_OP_MIN = 3, + VK_BLEND_OP_MAX = 4, + VK_BLEND_OP_BEGIN_RANGE = VK_BLEND_OP_ADD, + VK_BLEND_OP_END_RANGE = VK_BLEND_OP_MAX, + VK_BLEND_OP_RANGE_SIZE = (VK_BLEND_OP_MAX - VK_BLEND_OP_ADD + 1), + VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF +} VkBlendOp; + +typedef enum VkDynamicState { + VK_DYNAMIC_STATE_VIEWPORT = 0, + VK_DYNAMIC_STATE_SCISSOR = 1, + VK_DYNAMIC_STATE_LINE_WIDTH = 2, + VK_DYNAMIC_STATE_DEPTH_BIAS = 3, + VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4, + VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5, + VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7, + VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8, + VK_DYNAMIC_STATE_BEGIN_RANGE = VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_END_RANGE = VK_DYNAMIC_STATE_STENCIL_REFERENCE, + VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1), + VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF +} VkDynamicState; + +typedef enum VkFilter { + VK_FILTER_NEAREST = 0, + VK_FILTER_LINEAR = 1, + VK_FILTER_CUBIC_IMG = 1000015000, + VK_FILTER_BEGIN_RANGE = VK_FILTER_NEAREST, + VK_FILTER_END_RANGE = VK_FILTER_LINEAR, + VK_FILTER_RANGE_SIZE = (VK_FILTER_LINEAR - VK_FILTER_NEAREST + 1), + VK_FILTER_MAX_ENUM = 0x7FFFFFFF +} VkFilter; + +typedef enum VkSamplerMipmapMode { + VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, + VK_SAMPLER_MIPMAP_MODE_LINEAR = 1, + VK_SAMPLER_MIPMAP_MODE_BEGIN_RANGE = VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_MIPMAP_MODE_END_RANGE = VK_SAMPLER_MIPMAP_MODE_LINEAR, + VK_SAMPLER_MIPMAP_MODE_RANGE_SIZE = (VK_SAMPLER_MIPMAP_MODE_LINEAR - VK_SAMPLER_MIPMAP_MODE_NEAREST + 1), + VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerMipmapMode; + +typedef enum VkSamplerAddressMode { + VK_SAMPLER_ADDRESS_MODE_REPEAT = 0, + VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3, + VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, + VK_SAMPLER_ADDRESS_MODE_BEGIN_RANGE = VK_SAMPLER_ADDRESS_MODE_REPEAT, + VK_SAMPLER_ADDRESS_MODE_END_RANGE = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + VK_SAMPLER_ADDRESS_MODE_RANGE_SIZE = (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER - VK_SAMPLER_ADDRESS_MODE_REPEAT + 1), + VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerAddressMode; + +typedef enum VkBorderColor { + VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0, + VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1, + VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2, + VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3, + VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4, + VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5, + VK_BORDER_COLOR_BEGIN_RANGE = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, + VK_BORDER_COLOR_END_RANGE = VK_BORDER_COLOR_INT_OPAQUE_WHITE, + VK_BORDER_COLOR_RANGE_SIZE = (VK_BORDER_COLOR_INT_OPAQUE_WHITE - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK + 1), + VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF +} VkBorderColor; + +typedef enum VkDescriptorType { + VK_DESCRIPTOR_TYPE_SAMPLER = 0, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1, + VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2, + VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3, + VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4, + VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, + VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, + VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER, + VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1), + VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorType; + +typedef enum VkAttachmentLoadOp { + VK_ATTACHMENT_LOAD_OP_LOAD = 0, + VK_ATTACHMENT_LOAD_OP_CLEAR = 1, + VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, + VK_ATTACHMENT_LOAD_OP_BEGIN_RANGE = VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_LOAD_OP_END_RANGE = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_RANGE_SIZE = (VK_ATTACHMENT_LOAD_OP_DONT_CARE - VK_ATTACHMENT_LOAD_OP_LOAD + 1), + VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentLoadOp; + +typedef enum VkAttachmentStoreOp { + VK_ATTACHMENT_STORE_OP_STORE = 0, + VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, + VK_ATTACHMENT_STORE_OP_BEGIN_RANGE = VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_STORE_OP_END_RANGE = VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_RANGE_SIZE = (VK_ATTACHMENT_STORE_OP_DONT_CARE - VK_ATTACHMENT_STORE_OP_STORE + 1), + VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentStoreOp; + +typedef enum VkPipelineBindPoint { + VK_PIPELINE_BIND_POINT_GRAPHICS = 0, + VK_PIPELINE_BIND_POINT_COMPUTE = 1, + VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS, + VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE, + VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1), + VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF +} VkPipelineBindPoint; + +typedef enum VkCommandBufferLevel { + VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, + VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1, + VK_COMMAND_BUFFER_LEVEL_BEGIN_RANGE = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + VK_COMMAND_BUFFER_LEVEL_END_RANGE = VK_COMMAND_BUFFER_LEVEL_SECONDARY, + VK_COMMAND_BUFFER_LEVEL_RANGE_SIZE = (VK_COMMAND_BUFFER_LEVEL_SECONDARY - VK_COMMAND_BUFFER_LEVEL_PRIMARY + 1), + VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferLevel; + +typedef enum VkIndexType { + VK_INDEX_TYPE_UINT16 = 0, + VK_INDEX_TYPE_UINT32 = 1, + VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16, + VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32, + VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1), + VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkIndexType; + +typedef enum VkSubpassContents { + VK_SUBPASS_CONTENTS_INLINE = 0, + VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, + VK_SUBPASS_CONTENTS_BEGIN_RANGE = VK_SUBPASS_CONTENTS_INLINE, + VK_SUBPASS_CONTENTS_END_RANGE = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, + VK_SUBPASS_CONTENTS_RANGE_SIZE = (VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS - VK_SUBPASS_CONTENTS_INLINE + 1), + VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF +} VkSubpassContents; + +typedef VkFlags VkInstanceCreateFlags; + +typedef enum VkFormatFeatureFlagBits { + VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001, + VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002, + VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004, + VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008, + VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010, + VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020, + VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040, + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080, + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200, + VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, + VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, + VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFormatFeatureFlagBits; +typedef VkFlags VkFormatFeatureFlags; + +typedef enum VkImageUsageFlagBits { + VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001, + VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, + VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, + VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, + VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageUsageFlagBits; +typedef VkFlags VkImageUsageFlags; + +typedef enum VkImageCreateFlagBits { + VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001, + VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, + VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, + VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, + VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, + VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageCreateFlagBits; +typedef VkFlags VkImageCreateFlags; + +typedef enum VkSampleCountFlagBits { + VK_SAMPLE_COUNT_1_BIT = 0x00000001, + VK_SAMPLE_COUNT_2_BIT = 0x00000002, + VK_SAMPLE_COUNT_4_BIT = 0x00000004, + VK_SAMPLE_COUNT_8_BIT = 0x00000008, + VK_SAMPLE_COUNT_16_BIT = 0x00000010, + VK_SAMPLE_COUNT_32_BIT = 0x00000020, + VK_SAMPLE_COUNT_64_BIT = 0x00000040, + VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSampleCountFlagBits; +typedef VkFlags VkSampleCountFlags; + +typedef enum VkQueueFlagBits { + VK_QUEUE_GRAPHICS_BIT = 0x00000001, + VK_QUEUE_COMPUTE_BIT = 0x00000002, + VK_QUEUE_TRANSFER_BIT = 0x00000004, + VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, + VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueueFlagBits; +typedef VkFlags VkQueueFlags; + +typedef enum VkMemoryPropertyFlagBits { + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002, + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, + VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, + VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryPropertyFlagBits; +typedef VkFlags VkMemoryPropertyFlags; + +typedef enum VkMemoryHeapFlagBits { + VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, + VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryHeapFlagBits; +typedef VkFlags VkMemoryHeapFlags; +typedef VkFlags VkDeviceCreateFlags; +typedef VkFlags VkDeviceQueueCreateFlags; + +typedef enum VkPipelineStageFlagBits { + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001, + VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004, + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008, + VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010, + VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020, + VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800, + VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000, + VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, + VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineStageFlagBits; +typedef VkFlags VkPipelineStageFlags; +typedef VkFlags VkMemoryMapFlags; + +typedef enum VkImageAspectFlagBits { + VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001, + VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, + VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, + VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, + VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageAspectFlagBits; +typedef VkFlags VkImageAspectFlags; + +typedef enum VkSparseImageFormatFlagBits { + VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, + VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, + VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, + VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSparseImageFormatFlagBits; +typedef VkFlags VkSparseImageFormatFlags; + +typedef enum VkSparseMemoryBindFlagBits { + VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001, + VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSparseMemoryBindFlagBits; +typedef VkFlags VkSparseMemoryBindFlags; + +typedef enum VkFenceCreateFlagBits { + VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, + VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFenceCreateFlagBits; +typedef VkFlags VkFenceCreateFlags; +typedef VkFlags VkSemaphoreCreateFlags; +typedef VkFlags VkEventCreateFlags; +typedef VkFlags VkQueryPoolCreateFlags; + +typedef enum VkQueryPipelineStatisticFlagBits { + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001, + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002, + VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004, + VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008, + VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010, + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020, + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040, + VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080, + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, + VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, + VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryPipelineStatisticFlagBits; +typedef VkFlags VkQueryPipelineStatisticFlags; + +typedef enum VkQueryResultFlagBits { + VK_QUERY_RESULT_64_BIT = 0x00000001, + VK_QUERY_RESULT_WAIT_BIT = 0x00000002, + VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, + VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, + VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryResultFlagBits; +typedef VkFlags VkQueryResultFlags; + +typedef enum VkBufferCreateFlagBits { + VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, + VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, + VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, + VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkBufferCreateFlagBits; +typedef VkFlags VkBufferCreateFlags; + +typedef enum VkBufferUsageFlagBits { + VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001, + VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002, + VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004, + VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, + VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, + VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkBufferUsageFlagBits; +typedef VkFlags VkBufferUsageFlags; +typedef VkFlags VkBufferViewCreateFlags; +typedef VkFlags VkImageViewCreateFlags; +typedef VkFlags VkShaderModuleCreateFlags; +typedef VkFlags VkPipelineCacheCreateFlags; + +typedef enum VkPipelineCreateFlagBits { + VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, + VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, + VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, + VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCreateFlagBits; +typedef VkFlags VkPipelineCreateFlags; +typedef VkFlags VkPipelineShaderStageCreateFlags; + +typedef enum VkShaderStageFlagBits { + VK_SHADER_STAGE_VERTEX_BIT = 0x00000001, + VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002, + VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004, + VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, + VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, + VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, + VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, + VK_SHADER_STAGE_ALL = 0x7FFFFFFF, + VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkShaderStageFlagBits; +typedef VkFlags VkPipelineVertexInputStateCreateFlags; +typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; +typedef VkFlags VkPipelineTessellationStateCreateFlags; +typedef VkFlags VkPipelineViewportStateCreateFlags; +typedef VkFlags VkPipelineRasterizationStateCreateFlags; + +typedef enum VkCullModeFlagBits { + VK_CULL_MODE_NONE = 0, + VK_CULL_MODE_FRONT_BIT = 0x00000001, + VK_CULL_MODE_BACK_BIT = 0x00000002, + VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, + VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCullModeFlagBits; +typedef VkFlags VkCullModeFlags; +typedef VkFlags VkPipelineMultisampleStateCreateFlags; +typedef VkFlags VkPipelineDepthStencilStateCreateFlags; +typedef VkFlags VkPipelineColorBlendStateCreateFlags; + +typedef enum VkColorComponentFlagBits { + VK_COLOR_COMPONENT_R_BIT = 0x00000001, + VK_COLOR_COMPONENT_G_BIT = 0x00000002, + VK_COLOR_COMPONENT_B_BIT = 0x00000004, + VK_COLOR_COMPONENT_A_BIT = 0x00000008, + VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkColorComponentFlagBits; +typedef VkFlags VkColorComponentFlags; +typedef VkFlags VkPipelineDynamicStateCreateFlags; +typedef VkFlags VkPipelineLayoutCreateFlags; +typedef VkFlags VkShaderStageFlags; +typedef VkFlags VkSamplerCreateFlags; +typedef VkFlags VkDescriptorSetLayoutCreateFlags; + +typedef enum VkDescriptorPoolCreateFlagBits { + VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, + VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorPoolCreateFlagBits; +typedef VkFlags VkDescriptorPoolCreateFlags; +typedef VkFlags VkDescriptorPoolResetFlags; +typedef VkFlags VkFramebufferCreateFlags; +typedef VkFlags VkRenderPassCreateFlags; + +typedef enum VkAttachmentDescriptionFlagBits { + VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, + VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentDescriptionFlagBits; +typedef VkFlags VkAttachmentDescriptionFlags; +typedef VkFlags VkSubpassDescriptionFlags; + +typedef enum VkAccessFlagBits { + VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001, + VK_ACCESS_INDEX_READ_BIT = 0x00000002, + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004, + VK_ACCESS_UNIFORM_READ_BIT = 0x00000008, + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010, + VK_ACCESS_SHADER_READ_BIT = 0x00000020, + VK_ACCESS_SHADER_WRITE_BIT = 0x00000040, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400, + VK_ACCESS_TRANSFER_READ_BIT = 0x00000800, + VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000, + VK_ACCESS_HOST_READ_BIT = 0x00002000, + VK_ACCESS_HOST_WRITE_BIT = 0x00004000, + VK_ACCESS_MEMORY_READ_BIT = 0x00008000, + VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, + VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkAccessFlagBits; +typedef VkFlags VkAccessFlags; + +typedef enum VkDependencyFlagBits { + VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, + VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDependencyFlagBits; +typedef VkFlags VkDependencyFlags; + +typedef enum VkCommandPoolCreateFlagBits { + VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, + VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, + VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandPoolCreateFlagBits; +typedef VkFlags VkCommandPoolCreateFlags; + +typedef enum VkCommandPoolResetFlagBits { + VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, + VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandPoolResetFlagBits; +typedef VkFlags VkCommandPoolResetFlags; + +typedef enum VkCommandBufferUsageFlagBits { + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001, + VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002, + VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004, + VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferUsageFlagBits; +typedef VkFlags VkCommandBufferUsageFlags; + +typedef enum VkQueryControlFlagBits { + VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001, + VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryControlFlagBits; +typedef VkFlags VkQueryControlFlags; + +typedef enum VkCommandBufferResetFlagBits { + VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, + VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferResetFlagBits; +typedef VkFlags VkCommandBufferResetFlags; + +typedef enum VkStencilFaceFlagBits { + VK_STENCIL_FACE_FRONT_BIT = 0x00000001, + VK_STENCIL_FACE_BACK_BIT = 0x00000002, + VK_STENCIL_FRONT_AND_BACK = 0x00000003, + VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkStencilFaceFlagBits; +typedef VkFlags VkStencilFaceFlags; + +typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)( + void* pUserData, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + +typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)( + void* pUserData, + void* pOriginal, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkFreeFunction)( + void* pUserData, + void* pMemory); + +typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); + +typedef struct VkApplicationInfo { + VkStructureType sType; + const void* pNext; + const char* pApplicationName; + uint32_t applicationVersion; + const char* pEngineName; + uint32_t engineVersion; + uint32_t apiVersion; +} VkApplicationInfo; + +typedef struct VkInstanceCreateInfo { + VkStructureType sType; + const void* pNext; + VkInstanceCreateFlags flags; + const VkApplicationInfo* pApplicationInfo; + uint32_t enabledLayerCount; + const char* const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char* const* ppEnabledExtensionNames; +} VkInstanceCreateInfo; + +typedef struct VkAllocationCallbacks { + void* pUserData; + PFN_vkAllocationFunction pfnAllocation; + PFN_vkReallocationFunction pfnReallocation; + PFN_vkFreeFunction pfnFree; + PFN_vkInternalAllocationNotification pfnInternalAllocation; + PFN_vkInternalFreeNotification pfnInternalFree; +} VkAllocationCallbacks; + +typedef struct VkPhysicalDeviceFeatures { + VkBool32 robustBufferAccess; + VkBool32 fullDrawIndexUint32; + VkBool32 imageCubeArray; + VkBool32 independentBlend; + VkBool32 geometryShader; + VkBool32 tessellationShader; + VkBool32 sampleRateShading; + VkBool32 dualSrcBlend; + VkBool32 logicOp; + VkBool32 multiDrawIndirect; + VkBool32 drawIndirectFirstInstance; + VkBool32 depthClamp; + VkBool32 depthBiasClamp; + VkBool32 fillModeNonSolid; + VkBool32 depthBounds; + VkBool32 wideLines; + VkBool32 largePoints; + VkBool32 alphaToOne; + VkBool32 multiViewport; + VkBool32 samplerAnisotropy; + VkBool32 textureCompressionETC2; + VkBool32 textureCompressionASTC_LDR; + VkBool32 textureCompressionBC; + VkBool32 occlusionQueryPrecise; + VkBool32 pipelineStatisticsQuery; + VkBool32 vertexPipelineStoresAndAtomics; + VkBool32 fragmentStoresAndAtomics; + VkBool32 shaderTessellationAndGeometryPointSize; + VkBool32 shaderImageGatherExtended; + VkBool32 shaderStorageImageExtendedFormats; + VkBool32 shaderStorageImageMultisample; + VkBool32 shaderStorageImageReadWithoutFormat; + VkBool32 shaderStorageImageWriteWithoutFormat; + VkBool32 shaderUniformBufferArrayDynamicIndexing; + VkBool32 shaderSampledImageArrayDynamicIndexing; + VkBool32 shaderStorageBufferArrayDynamicIndexing; + VkBool32 shaderStorageImageArrayDynamicIndexing; + VkBool32 shaderClipDistance; + VkBool32 shaderCullDistance; + VkBool32 shaderFloat64; + VkBool32 shaderInt64; + VkBool32 shaderInt16; + VkBool32 shaderResourceResidency; + VkBool32 shaderResourceMinLod; + VkBool32 sparseBinding; + VkBool32 sparseResidencyBuffer; + VkBool32 sparseResidencyImage2D; + VkBool32 sparseResidencyImage3D; + VkBool32 sparseResidency2Samples; + VkBool32 sparseResidency4Samples; + VkBool32 sparseResidency8Samples; + VkBool32 sparseResidency16Samples; + VkBool32 sparseResidencyAliased; + VkBool32 variableMultisampleRate; + VkBool32 inheritedQueries; +} VkPhysicalDeviceFeatures; + +typedef struct VkFormatProperties { + VkFormatFeatureFlags linearTilingFeatures; + VkFormatFeatureFlags optimalTilingFeatures; + VkFormatFeatureFlags bufferFeatures; +} VkFormatProperties; + +typedef struct VkExtent3D { + uint32_t width; + uint32_t height; + uint32_t depth; +} VkExtent3D; + +typedef struct VkImageFormatProperties { + VkExtent3D maxExtent; + uint32_t maxMipLevels; + uint32_t maxArrayLayers; + VkSampleCountFlags sampleCounts; + VkDeviceSize maxResourceSize; +} VkImageFormatProperties; + +typedef struct VkPhysicalDeviceLimits { + uint32_t maxImageDimension1D; + uint32_t maxImageDimension2D; + uint32_t maxImageDimension3D; + uint32_t maxImageDimensionCube; + uint32_t maxImageArrayLayers; + uint32_t maxTexelBufferElements; + uint32_t maxUniformBufferRange; + uint32_t maxStorageBufferRange; + uint32_t maxPushConstantsSize; + uint32_t maxMemoryAllocationCount; + uint32_t maxSamplerAllocationCount; + VkDeviceSize bufferImageGranularity; + VkDeviceSize sparseAddressSpaceSize; + uint32_t maxBoundDescriptorSets; + uint32_t maxPerStageDescriptorSamplers; + uint32_t maxPerStageDescriptorUniformBuffers; + uint32_t maxPerStageDescriptorStorageBuffers; + uint32_t maxPerStageDescriptorSampledImages; + uint32_t maxPerStageDescriptorStorageImages; + uint32_t maxPerStageDescriptorInputAttachments; + uint32_t maxPerStageResources; + uint32_t maxDescriptorSetSamplers; + uint32_t maxDescriptorSetUniformBuffers; + uint32_t maxDescriptorSetUniformBuffersDynamic; + uint32_t maxDescriptorSetStorageBuffers; + uint32_t maxDescriptorSetStorageBuffersDynamic; + uint32_t maxDescriptorSetSampledImages; + uint32_t maxDescriptorSetStorageImages; + uint32_t maxDescriptorSetInputAttachments; + uint32_t maxVertexInputAttributes; + uint32_t maxVertexInputBindings; + uint32_t maxVertexInputAttributeOffset; + uint32_t maxVertexInputBindingStride; + uint32_t maxVertexOutputComponents; + uint32_t maxTessellationGenerationLevel; + uint32_t maxTessellationPatchSize; + uint32_t maxTessellationControlPerVertexInputComponents; + uint32_t maxTessellationControlPerVertexOutputComponents; + uint32_t maxTessellationControlPerPatchOutputComponents; + uint32_t maxTessellationControlTotalOutputComponents; + uint32_t maxTessellationEvaluationInputComponents; + uint32_t maxTessellationEvaluationOutputComponents; + uint32_t maxGeometryShaderInvocations; + uint32_t maxGeometryInputComponents; + uint32_t maxGeometryOutputComponents; + uint32_t maxGeometryOutputVertices; + uint32_t maxGeometryTotalOutputComponents; + uint32_t maxFragmentInputComponents; + uint32_t maxFragmentOutputAttachments; + uint32_t maxFragmentDualSrcAttachments; + uint32_t maxFragmentCombinedOutputResources; + uint32_t maxComputeSharedMemorySize; + uint32_t maxComputeWorkGroupCount[3]; + uint32_t maxComputeWorkGroupInvocations; + uint32_t maxComputeWorkGroupSize[3]; + uint32_t subPixelPrecisionBits; + uint32_t subTexelPrecisionBits; + uint32_t mipmapPrecisionBits; + uint32_t maxDrawIndexedIndexValue; + uint32_t maxDrawIndirectCount; + float maxSamplerLodBias; + float maxSamplerAnisotropy; + uint32_t maxViewports; + uint32_t maxViewportDimensions[2]; + float viewportBoundsRange[2]; + uint32_t viewportSubPixelBits; + size_t minMemoryMapAlignment; + VkDeviceSize minTexelBufferOffsetAlignment; + VkDeviceSize minUniformBufferOffsetAlignment; + VkDeviceSize minStorageBufferOffsetAlignment; + int32_t minTexelOffset; + uint32_t maxTexelOffset; + int32_t minTexelGatherOffset; + uint32_t maxTexelGatherOffset; + float minInterpolationOffset; + float maxInterpolationOffset; + uint32_t subPixelInterpolationOffsetBits; + uint32_t maxFramebufferWidth; + uint32_t maxFramebufferHeight; + uint32_t maxFramebufferLayers; + VkSampleCountFlags framebufferColorSampleCounts; + VkSampleCountFlags framebufferDepthSampleCounts; + VkSampleCountFlags framebufferStencilSampleCounts; + VkSampleCountFlags framebufferNoAttachmentsSampleCounts; + uint32_t maxColorAttachments; + VkSampleCountFlags sampledImageColorSampleCounts; + VkSampleCountFlags sampledImageIntegerSampleCounts; + VkSampleCountFlags sampledImageDepthSampleCounts; + VkSampleCountFlags sampledImageStencilSampleCounts; + VkSampleCountFlags storageImageSampleCounts; + uint32_t maxSampleMaskWords; + VkBool32 timestampComputeAndGraphics; + float timestampPeriod; + uint32_t maxClipDistances; + uint32_t maxCullDistances; + uint32_t maxCombinedClipAndCullDistances; + uint32_t discreteQueuePriorities; + float pointSizeRange[2]; + float lineWidthRange[2]; + float pointSizeGranularity; + float lineWidthGranularity; + VkBool32 strictLines; + VkBool32 standardSampleLocations; + VkDeviceSize optimalBufferCopyOffsetAlignment; + VkDeviceSize optimalBufferCopyRowPitchAlignment; + VkDeviceSize nonCoherentAtomSize; +} VkPhysicalDeviceLimits; + +typedef struct VkPhysicalDeviceSparseProperties { + VkBool32 residencyStandard2DBlockShape; + VkBool32 residencyStandard2DMultisampleBlockShape; + VkBool32 residencyStandard3DBlockShape; + VkBool32 residencyAlignedMipSize; + VkBool32 residencyNonResidentStrict; +} VkPhysicalDeviceSparseProperties; + +typedef struct VkPhysicalDeviceProperties { + uint32_t apiVersion; + uint32_t driverVersion; + uint32_t vendorID; + uint32_t deviceID; + VkPhysicalDeviceType deviceType; + char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; + uint8_t pipelineCacheUUID[VK_UUID_SIZE]; + VkPhysicalDeviceLimits limits; + VkPhysicalDeviceSparseProperties sparseProperties; +} VkPhysicalDeviceProperties; + +typedef struct VkQueueFamilyProperties { + VkQueueFlags queueFlags; + uint32_t queueCount; + uint32_t timestampValidBits; + VkExtent3D minImageTransferGranularity; +} VkQueueFamilyProperties; + +typedef struct VkMemoryType { + VkMemoryPropertyFlags propertyFlags; + uint32_t heapIndex; +} VkMemoryType; + +typedef struct VkMemoryHeap { + VkDeviceSize size; + VkMemoryHeapFlags flags; +} VkMemoryHeap; + +typedef struct VkPhysicalDeviceMemoryProperties { + uint32_t memoryTypeCount; + VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]; + uint32_t memoryHeapCount; + VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryProperties; + +typedef struct VkDeviceQueueCreateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueCount; + const float* pQueuePriorities; +} VkDeviceQueueCreateInfo; + +typedef struct VkDeviceCreateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceCreateFlags flags; + uint32_t queueCreateInfoCount; + const VkDeviceQueueCreateInfo* pQueueCreateInfos; + uint32_t enabledLayerCount; + const char* const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char* const* ppEnabledExtensionNames; + const VkPhysicalDeviceFeatures* pEnabledFeatures; +} VkDeviceCreateInfo; + +typedef struct VkExtensionProperties { + char extensionName[VK_MAX_EXTENSION_NAME_SIZE]; + uint32_t specVersion; +} VkExtensionProperties; + +typedef struct VkLayerProperties { + char layerName[VK_MAX_EXTENSION_NAME_SIZE]; + uint32_t specVersion; + uint32_t implementationVersion; + char description[VK_MAX_DESCRIPTION_SIZE]; +} VkLayerProperties; + +typedef struct VkSubmitInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + const VkPipelineStageFlags* pWaitDstStageMask; + uint32_t commandBufferCount; + const VkCommandBuffer* pCommandBuffers; + uint32_t signalSemaphoreCount; + const VkSemaphore* pSignalSemaphores; +} VkSubmitInfo; + +typedef struct VkMemoryAllocateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeIndex; +} VkMemoryAllocateInfo; + +typedef struct VkMappedMemoryRange { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; +} VkMappedMemoryRange; + +typedef struct VkMemoryRequirements { + VkDeviceSize size; + VkDeviceSize alignment; + uint32_t memoryTypeBits; +} VkMemoryRequirements; + +typedef struct VkSparseImageFormatProperties { + VkImageAspectFlags aspectMask; + VkExtent3D imageGranularity; + VkSparseImageFormatFlags flags; +} VkSparseImageFormatProperties; + +typedef struct VkSparseImageMemoryRequirements { + VkSparseImageFormatProperties formatProperties; + uint32_t imageMipTailFirstLod; + VkDeviceSize imageMipTailSize; + VkDeviceSize imageMipTailOffset; + VkDeviceSize imageMipTailStride; +} VkSparseImageMemoryRequirements; + +typedef struct VkSparseMemoryBind { + VkDeviceSize resourceOffset; + VkDeviceSize size; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseMemoryBind; + +typedef struct VkSparseBufferMemoryBindInfo { + VkBuffer buffer; + uint32_t bindCount; + const VkSparseMemoryBind* pBinds; +} VkSparseBufferMemoryBindInfo; + +typedef struct VkSparseImageOpaqueMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseMemoryBind* pBinds; +} VkSparseImageOpaqueMemoryBindInfo; + +typedef struct VkImageSubresource { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t arrayLayer; +} VkImageSubresource; + +typedef struct VkOffset3D { + int32_t x; + int32_t y; + int32_t z; +} VkOffset3D; + +typedef struct VkSparseImageMemoryBind { + VkImageSubresource subresource; + VkOffset3D offset; + VkExtent3D extent; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseImageMemoryBind; + +typedef struct VkSparseImageMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseImageMemoryBind* pBinds; +} VkSparseImageMemoryBindInfo; + +typedef struct VkBindSparseInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + uint32_t bufferBindCount; + const VkSparseBufferMemoryBindInfo* pBufferBinds; + uint32_t imageOpaqueBindCount; + const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; + uint32_t imageBindCount; + const VkSparseImageMemoryBindInfo* pImageBinds; + uint32_t signalSemaphoreCount; + const VkSemaphore* pSignalSemaphores; +} VkBindSparseInfo; + +typedef struct VkFenceCreateInfo { + VkStructureType sType; + const void* pNext; + VkFenceCreateFlags flags; +} VkFenceCreateInfo; + +typedef struct VkSemaphoreCreateInfo { + VkStructureType sType; + const void* pNext; + VkSemaphoreCreateFlags flags; +} VkSemaphoreCreateInfo; + +typedef struct VkEventCreateInfo { + VkStructureType sType; + const void* pNext; + VkEventCreateFlags flags; +} VkEventCreateInfo; + +typedef struct VkQueryPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkQueryPoolCreateFlags flags; + VkQueryType queryType; + uint32_t queryCount; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkQueryPoolCreateInfo; + +typedef struct VkBufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkBufferCreateFlags flags; + VkDeviceSize size; + VkBufferUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; +} VkBufferCreateInfo; + +typedef struct VkBufferViewCreateInfo { + VkStructureType sType; + const void* pNext; + VkBufferViewCreateFlags flags; + VkBuffer buffer; + VkFormat format; + VkDeviceSize offset; + VkDeviceSize range; +} VkBufferViewCreateInfo; + +typedef struct VkImageCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageCreateFlags flags; + VkImageType imageType; + VkFormat format; + VkExtent3D extent; + uint32_t mipLevels; + uint32_t arrayLayers; + VkSampleCountFlagBits samples; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; + VkImageLayout initialLayout; +} VkImageCreateInfo; + +typedef struct VkSubresourceLayout { + VkDeviceSize offset; + VkDeviceSize size; + VkDeviceSize rowPitch; + VkDeviceSize arrayPitch; + VkDeviceSize depthPitch; +} VkSubresourceLayout; + +typedef struct VkComponentMapping { + VkComponentSwizzle r; + VkComponentSwizzle g; + VkComponentSwizzle b; + VkComponentSwizzle a; +} VkComponentMapping; + +typedef struct VkImageSubresourceRange { + VkImageAspectFlags aspectMask; + uint32_t baseMipLevel; + uint32_t levelCount; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceRange; + +typedef struct VkImageViewCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageViewCreateFlags flags; + VkImage image; + VkImageViewType viewType; + VkFormat format; + VkComponentMapping components; + VkImageSubresourceRange subresourceRange; +} VkImageViewCreateInfo; + +typedef struct VkShaderModuleCreateInfo { + VkStructureType sType; + const void* pNext; + VkShaderModuleCreateFlags flags; + size_t codeSize; + const uint32_t* pCode; +} VkShaderModuleCreateInfo; + +typedef struct VkPipelineCacheCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCacheCreateFlags flags; + size_t initialDataSize; + const void* pInitialData; +} VkPipelineCacheCreateInfo; + +typedef struct VkSpecializationMapEntry { + uint32_t constantID; + uint32_t offset; + size_t size; +} VkSpecializationMapEntry; + +typedef struct VkSpecializationInfo { + uint32_t mapEntryCount; + const VkSpecializationMapEntry* pMapEntries; + size_t dataSize; + const void* pData; +} VkSpecializationInfo; + +typedef struct VkPipelineShaderStageCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineShaderStageCreateFlags flags; + VkShaderStageFlagBits stage; + VkShaderModule module; + const char* pName; + const VkSpecializationInfo* pSpecializationInfo; +} VkPipelineShaderStageCreateInfo; + +typedef struct VkVertexInputBindingDescription { + uint32_t binding; + uint32_t stride; + VkVertexInputRate inputRate; +} VkVertexInputBindingDescription; + +typedef struct VkVertexInputAttributeDescription { + uint32_t location; + uint32_t binding; + VkFormat format; + uint32_t offset; +} VkVertexInputAttributeDescription; + +typedef struct VkPipelineVertexInputStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineVertexInputStateCreateFlags flags; + uint32_t vertexBindingDescriptionCount; + const VkVertexInputBindingDescription* pVertexBindingDescriptions; + uint32_t vertexAttributeDescriptionCount; + const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; +} VkPipelineVertexInputStateCreateInfo; + +typedef struct VkPipelineInputAssemblyStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineInputAssemblyStateCreateFlags flags; + VkPrimitiveTopology topology; + VkBool32 primitiveRestartEnable; +} VkPipelineInputAssemblyStateCreateInfo; + +typedef struct VkPipelineTessellationStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineTessellationStateCreateFlags flags; + uint32_t patchControlPoints; +} VkPipelineTessellationStateCreateInfo; + +typedef struct VkViewport { + float x; + float y; + float width; + float height; + float minDepth; + float maxDepth; +} VkViewport; + +typedef struct VkOffset2D { + int32_t x; + int32_t y; +} VkOffset2D; + +typedef struct VkExtent2D { + uint32_t width; + uint32_t height; +} VkExtent2D; + +typedef struct VkRect2D { + VkOffset2D offset; + VkExtent2D extent; +} VkRect2D; + +typedef struct VkPipelineViewportStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineViewportStateCreateFlags flags; + uint32_t viewportCount; + const VkViewport* pViewports; + uint32_t scissorCount; + const VkRect2D* pScissors; +} VkPipelineViewportStateCreateInfo; + +typedef struct VkPipelineRasterizationStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationStateCreateFlags flags; + VkBool32 depthClampEnable; + VkBool32 rasterizerDiscardEnable; + VkPolygonMode polygonMode; + VkCullModeFlags cullMode; + VkFrontFace frontFace; + VkBool32 depthBiasEnable; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; + float lineWidth; +} VkPipelineRasterizationStateCreateInfo; + +typedef struct VkPipelineMultisampleStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineMultisampleStateCreateFlags flags; + VkSampleCountFlagBits rasterizationSamples; + VkBool32 sampleShadingEnable; + float minSampleShading; + const VkSampleMask* pSampleMask; + VkBool32 alphaToCoverageEnable; + VkBool32 alphaToOneEnable; +} VkPipelineMultisampleStateCreateInfo; + +typedef struct VkStencilOpState { + VkStencilOp failOp; + VkStencilOp passOp; + VkStencilOp depthFailOp; + VkCompareOp compareOp; + uint32_t compareMask; + uint32_t writeMask; + uint32_t reference; +} VkStencilOpState; + +typedef struct VkPipelineDepthStencilStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineDepthStencilStateCreateFlags flags; + VkBool32 depthTestEnable; + VkBool32 depthWriteEnable; + VkCompareOp depthCompareOp; + VkBool32 depthBoundsTestEnable; + VkBool32 stencilTestEnable; + VkStencilOpState front; + VkStencilOpState back; + float minDepthBounds; + float maxDepthBounds; +} VkPipelineDepthStencilStateCreateInfo; + +typedef struct VkPipelineColorBlendAttachmentState { + VkBool32 blendEnable; + VkBlendFactor srcColorBlendFactor; + VkBlendFactor dstColorBlendFactor; + VkBlendOp colorBlendOp; + VkBlendFactor srcAlphaBlendFactor; + VkBlendFactor dstAlphaBlendFactor; + VkBlendOp alphaBlendOp; + VkColorComponentFlags colorWriteMask; +} VkPipelineColorBlendAttachmentState; + +typedef struct VkPipelineColorBlendStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineColorBlendStateCreateFlags flags; + VkBool32 logicOpEnable; + VkLogicOp logicOp; + uint32_t attachmentCount; + const VkPipelineColorBlendAttachmentState* pAttachments; + float blendConstants[4]; +} VkPipelineColorBlendStateCreateInfo; + +typedef struct VkPipelineDynamicStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineDynamicStateCreateFlags flags; + uint32_t dynamicStateCount; + const VkDynamicState* pDynamicStates; +} VkPipelineDynamicStateCreateInfo; + +typedef struct VkGraphicsPipelineCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + const VkPipelineVertexInputStateCreateInfo* pVertexInputState; + const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; + const VkPipelineTessellationStateCreateInfo* pTessellationState; + const VkPipelineViewportStateCreateInfo* pViewportState; + const VkPipelineRasterizationStateCreateInfo* pRasterizationState; + const VkPipelineMultisampleStateCreateInfo* pMultisampleState; + const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; + const VkPipelineColorBlendStateCreateInfo* pColorBlendState; + const VkPipelineDynamicStateCreateInfo* pDynamicState; + VkPipelineLayout layout; + VkRenderPass renderPass; + uint32_t subpass; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkGraphicsPipelineCreateInfo; + +typedef struct VkComputePipelineCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + VkPipelineShaderStageCreateInfo stage; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkComputePipelineCreateInfo; + +typedef struct VkPushConstantRange { + VkShaderStageFlags stageFlags; + uint32_t offset; + uint32_t size; +} VkPushConstantRange; + +typedef struct VkPipelineLayoutCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineLayoutCreateFlags flags; + uint32_t setLayoutCount; + const VkDescriptorSetLayout* pSetLayouts; + uint32_t pushConstantRangeCount; + const VkPushConstantRange* pPushConstantRanges; +} VkPipelineLayoutCreateInfo; + +typedef struct VkSamplerCreateInfo { + VkStructureType sType; + const void* pNext; + VkSamplerCreateFlags flags; + VkFilter magFilter; + VkFilter minFilter; + VkSamplerMipmapMode mipmapMode; + VkSamplerAddressMode addressModeU; + VkSamplerAddressMode addressModeV; + VkSamplerAddressMode addressModeW; + float mipLodBias; + VkBool32 anisotropyEnable; + float maxAnisotropy; + VkBool32 compareEnable; + VkCompareOp compareOp; + float minLod; + float maxLod; + VkBorderColor borderColor; + VkBool32 unnormalizedCoordinates; +} VkSamplerCreateInfo; + +typedef struct VkDescriptorSetLayoutBinding { + uint32_t binding; + VkDescriptorType descriptorType; + uint32_t descriptorCount; + VkShaderStageFlags stageFlags; + const VkSampler* pImmutableSamplers; +} VkDescriptorSetLayoutBinding; + +typedef struct VkDescriptorSetLayoutCreateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorSetLayoutCreateFlags flags; + uint32_t bindingCount; + const VkDescriptorSetLayoutBinding* pBindings; +} VkDescriptorSetLayoutCreateInfo; + +typedef struct VkDescriptorPoolSize { + VkDescriptorType type; + uint32_t descriptorCount; +} VkDescriptorPoolSize; + +typedef struct VkDescriptorPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorPoolCreateFlags flags; + uint32_t maxSets; + uint32_t poolSizeCount; + const VkDescriptorPoolSize* pPoolSizes; +} VkDescriptorPoolCreateInfo; + +typedef struct VkDescriptorSetAllocateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorPool descriptorPool; + uint32_t descriptorSetCount; + const VkDescriptorSetLayout* pSetLayouts; +} VkDescriptorSetAllocateInfo; + +typedef struct VkDescriptorImageInfo { + VkSampler sampler; + VkImageView imageView; + VkImageLayout imageLayout; +} VkDescriptorImageInfo; + +typedef struct VkDescriptorBufferInfo { + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize range; +} VkDescriptorBufferInfo; + +typedef struct VkWriteDescriptorSet { + VkStructureType sType; + const void* pNext; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; + VkDescriptorType descriptorType; + const VkDescriptorImageInfo* pImageInfo; + const VkDescriptorBufferInfo* pBufferInfo; + const VkBufferView* pTexelBufferView; +} VkWriteDescriptorSet; + +typedef struct VkCopyDescriptorSet { + VkStructureType sType; + const void* pNext; + VkDescriptorSet srcSet; + uint32_t srcBinding; + uint32_t srcArrayElement; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; +} VkCopyDescriptorSet; + +typedef struct VkFramebufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkFramebufferCreateFlags flags; + VkRenderPass renderPass; + uint32_t attachmentCount; + const VkImageView* pAttachments; + uint32_t width; + uint32_t height; + uint32_t layers; +} VkFramebufferCreateInfo; + +typedef struct VkAttachmentDescription { + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription; + +typedef struct VkAttachmentReference { + uint32_t attachment; + VkImageLayout layout; +} VkAttachmentReference; + +typedef struct VkSubpassDescription { + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t inputAttachmentCount; + const VkAttachmentReference* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference* pColorAttachments; + const VkAttachmentReference* pResolveAttachments; + const VkAttachmentReference* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription; + +typedef struct VkSubpassDependency { + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; +} VkSubpassDependency; + +typedef struct VkRenderPassCreateInfo { + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency* pDependencies; +} VkRenderPassCreateInfo; + +typedef struct VkCommandPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkCommandPoolCreateFlags flags; + uint32_t queueFamilyIndex; +} VkCommandPoolCreateInfo; + +typedef struct VkCommandBufferAllocateInfo { + VkStructureType sType; + const void* pNext; + VkCommandPool commandPool; + VkCommandBufferLevel level; + uint32_t commandBufferCount; +} VkCommandBufferAllocateInfo; + +typedef struct VkCommandBufferInheritanceInfo { + VkStructureType sType; + const void* pNext; + VkRenderPass renderPass; + uint32_t subpass; + VkFramebuffer framebuffer; + VkBool32 occlusionQueryEnable; + VkQueryControlFlags queryFlags; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkCommandBufferInheritanceInfo; + +typedef struct VkCommandBufferBeginInfo { + VkStructureType sType; + const void* pNext; + VkCommandBufferUsageFlags flags; + const VkCommandBufferInheritanceInfo* pInheritanceInfo; +} VkCommandBufferBeginInfo; + +typedef struct VkBufferCopy { + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy; + +typedef struct VkImageSubresourceLayers { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceLayers; + +typedef struct VkImageCopy { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy; + +typedef struct VkImageBlit { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets[2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets[2]; +} VkImageBlit; + +typedef struct VkBufferImageCopy { + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy; + +typedef union VkClearColorValue { + float float32[4]; + int32_t int32[4]; + uint32_t uint32[4]; +} VkClearColorValue; + +typedef struct VkClearDepthStencilValue { + float depth; + uint32_t stencil; +} VkClearDepthStencilValue; + +typedef union VkClearValue { + VkClearColorValue color; + VkClearDepthStencilValue depthStencil; +} VkClearValue; + +typedef struct VkClearAttachment { + VkImageAspectFlags aspectMask; + uint32_t colorAttachment; + VkClearValue clearValue; +} VkClearAttachment; + +typedef struct VkClearRect { + VkRect2D rect; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkClearRect; + +typedef struct VkImageResolve { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve; + +typedef struct VkMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; +} VkMemoryBarrier; + +typedef struct VkBufferMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier; + +typedef struct VkImageMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier; + +typedef struct VkRenderPassBeginInfo { + VkStructureType sType; + const void* pNext; + VkRenderPass renderPass; + VkFramebuffer framebuffer; + VkRect2D renderArea; + uint32_t clearValueCount; + const VkClearValue* pClearValues; +} VkRenderPassBeginInfo; + +typedef struct VkDispatchIndirectCommand { + uint32_t x; + uint32_t y; + uint32_t z; +} VkDispatchIndirectCommand; + +typedef struct VkDrawIndexedIndirectCommand { + uint32_t indexCount; + uint32_t instanceCount; + uint32_t firstIndex; + int32_t vertexOffset; + uint32_t firstInstance; +} VkDrawIndexedIndirectCommand; + +typedef struct VkDrawIndirectCommand { + uint32_t vertexCount; + uint32_t instanceCount; + uint32_t firstVertex; + uint32_t firstInstance; +} VkDrawIndirectCommand; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); +typedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char* pName); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); +typedef void (VKAPI_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t* pPropertyCount, VkLayerProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue queue); +typedef VkResult (VKAPI_PTR *PFN_vkDeviceWaitIdle)(VkDevice device); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory); +typedef void (VKAPI_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData); +typedef void (VKAPI_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory); +typedef VkResult (VKAPI_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); +typedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); +typedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes); +typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); +typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); +typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); +typedef void (VKAPI_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences); +typedef VkResult (VKAPI_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore); +typedef void (VKAPI_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent); +typedef void (VKAPI_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool); +typedef void (VKAPI_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer); +typedef void (VKAPI_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView); +typedef void (VKAPI_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage); +typedef void (VKAPI_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout); +typedef VkResult (VKAPI_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView); +typedef void (VKAPI_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule); +typedef void (VKAPI_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache); +typedef void (VKAPI_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches); +typedef VkResult (VKAPI_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef void (VKAPI_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler); +typedef void (VKAPI_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets); +typedef VkResult (VKAPI_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets); +typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies); +typedef VkResult (VKAPI_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer); +typedef void (VKAPI_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity); +typedef VkResult (VKAPI_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool); +typedef void (VKAPI_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); +typedef void (VKAPI_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); +typedef VkResult (VKAPI_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo); +typedef VkResult (VKAPI_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer); +typedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); +typedef void (VKAPI_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); +typedef void (VKAPI_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); +typedef void (VKAPI_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants[4]); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); +typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData); +typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); +typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); +typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); +typedef void (VKAPI_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); +typedef void (VKAPI_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); +typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); +typedef void (VKAPI_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); +typedef void (VKAPI_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); +typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); +typedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance( + const VkInstanceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkInstance* pInstance); + +VKAPI_ATTR void VKAPI_CALL vkDestroyInstance( + VkInstance instance, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices( + VkInstance instance, + uint32_t* pPhysicalDeviceCount, + VkPhysicalDevice* pPhysicalDevices); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures* pFeatures); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties* pFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags, + VkImageFormatProperties* pImageFormatProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties* pQueueFamilyProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties* pMemoryProperties); + +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr( + VkInstance instance, + const char* pName); + +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr( + VkDevice device, + const char* pName); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice( + VkPhysicalDevice physicalDevice, + const VkDeviceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDevice* pDevice); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDevice( + VkDevice device, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties( + const char* pLayerName, + uint32_t* pPropertyCount, + VkExtensionProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties( + VkPhysicalDevice physicalDevice, + const char* pLayerName, + uint32_t* pPropertyCount, + VkExtensionProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties( + uint32_t* pPropertyCount, + VkLayerProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkLayerProperties* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue( + VkDevice device, + uint32_t queueFamilyIndex, + uint32_t queueIndex, + VkQueue* pQueue); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit( + VkQueue queue, + uint32_t submitCount, + const VkSubmitInfo* pSubmits, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle( + VkQueue queue); + +VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle( + VkDevice device); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory( + VkDevice device, + const VkMemoryAllocateInfo* pAllocateInfo, + const VkAllocationCallbacks* pAllocator, + VkDeviceMemory* pMemory); + +VKAPI_ATTR void VKAPI_CALL vkFreeMemory( + VkDevice device, + VkDeviceMemory memory, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory( + VkDevice device, + VkDeviceMemory memory, + VkDeviceSize offset, + VkDeviceSize size, + VkMemoryMapFlags flags, + void** ppData); + +VKAPI_ATTR void VKAPI_CALL vkUnmapMemory( + VkDevice device, + VkDeviceMemory memory); + +VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges( + VkDevice device, + uint32_t memoryRangeCount, + const VkMappedMemoryRange* pMemoryRanges); + +VKAPI_ATTR VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges( + VkDevice device, + uint32_t memoryRangeCount, + const VkMappedMemoryRange* pMemoryRanges); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment( + VkDevice device, + VkDeviceMemory memory, + VkDeviceSize* pCommittedMemoryInBytes); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory( + VkDevice device, + VkBuffer buffer, + VkDeviceMemory memory, + VkDeviceSize memoryOffset); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory( + VkDevice device, + VkImage image, + VkDeviceMemory memory, + VkDeviceSize memoryOffset); + +VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements( + VkDevice device, + VkBuffer buffer, + VkMemoryRequirements* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements( + VkDevice device, + VkImage image, + VkMemoryRequirements* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements( + VkDevice device, + VkImage image, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements* pSparseMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkSampleCountFlagBits samples, + VkImageUsageFlags usage, + VkImageTiling tiling, + uint32_t* pPropertyCount, + VkSparseImageFormatProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueBindSparse( + VkQueue queue, + uint32_t bindInfoCount, + const VkBindSparseInfo* pBindInfo, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateFence( + VkDevice device, + const VkFenceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence); + +VKAPI_ATTR void VKAPI_CALL vkDestroyFence( + VkDevice device, + VkFence fence, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetFences( + VkDevice device, + uint32_t fenceCount, + const VkFence* pFences); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus( + VkDevice device, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences( + VkDevice device, + uint32_t fenceCount, + const VkFence* pFences, + VkBool32 waitAll, + uint64_t timeout); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore( + VkDevice device, + const VkSemaphoreCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSemaphore* pSemaphore); + +VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore( + VkDevice device, + VkSemaphore semaphore, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent( + VkDevice device, + const VkEventCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkEvent* pEvent); + +VKAPI_ATTR void VKAPI_CALL vkDestroyEvent( + VkDevice device, + VkEvent event, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetEventStatus( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetEvent( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool( + VkDevice device, + const VkQueryPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkQueryPool* pQueryPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyQueryPool( + VkDevice device, + VkQueryPool queryPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults( + VkDevice device, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + size_t dataSize, + void* pData, + VkDeviceSize stride, + VkQueryResultFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer( + VkDevice device, + const VkBufferCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkBuffer* pBuffer); + +VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer( + VkDevice device, + VkBuffer buffer, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView( + VkDevice device, + const VkBufferViewCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkBufferView* pView); + +VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView( + VkDevice device, + VkBufferView bufferView, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage( + VkDevice device, + const VkImageCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkImage* pImage); + +VKAPI_ATTR void VKAPI_CALL vkDestroyImage( + VkDevice device, + VkImage image, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout( + VkDevice device, + VkImage image, + const VkImageSubresource* pSubresource, + VkSubresourceLayout* pLayout); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView( + VkDevice device, + const VkImageViewCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkImageView* pView); + +VKAPI_ATTR void VKAPI_CALL vkDestroyImageView( + VkDevice device, + VkImageView imageView, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule( + VkDevice device, + const VkShaderModuleCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkShaderModule* pShaderModule); + +VKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule( + VkDevice device, + VkShaderModule shaderModule, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache( + VkDevice device, + const VkPipelineCacheCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPipelineCache* pPipelineCache); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineCache( + VkDevice device, + VkPipelineCache pipelineCache, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData( + VkDevice device, + VkPipelineCache pipelineCache, + size_t* pDataSize, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches( + VkDevice device, + VkPipelineCache dstCache, + uint32_t srcCacheCount, + const VkPipelineCache* pSrcCaches); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkGraphicsPipelineCreateInfo* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkComputePipelineCreateInfo* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline( + VkDevice device, + VkPipeline pipeline, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout( + VkDevice device, + const VkPipelineLayoutCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPipelineLayout* pPipelineLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineLayout( + VkDevice device, + VkPipelineLayout pipelineLayout, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler( + VkDevice device, + const VkSamplerCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSampler* pSampler); + +VKAPI_ATTR void VKAPI_CALL vkDestroySampler( + VkDevice device, + VkSampler sampler, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorSetLayout* pSetLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorSetLayout( + VkDevice device, + VkDescriptorSetLayout descriptorSetLayout, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorPool( + VkDevice device, + const VkDescriptorPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorPool* pDescriptorPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorPool( + VkDevice device, + VkDescriptorPool descriptorPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetDescriptorPool( + VkDevice device, + VkDescriptorPool descriptorPool, + VkDescriptorPoolResetFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateDescriptorSets( + VkDevice device, + const VkDescriptorSetAllocateInfo* pAllocateInfo, + VkDescriptorSet* pDescriptorSets); + +VKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets( + VkDevice device, + VkDescriptorPool descriptorPool, + uint32_t descriptorSetCount, + const VkDescriptorSet* pDescriptorSets); + +VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets( + VkDevice device, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet* pDescriptorWrites, + uint32_t descriptorCopyCount, + const VkCopyDescriptorSet* pDescriptorCopies); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer( + VkDevice device, + const VkFramebufferCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkFramebuffer* pFramebuffer); + +VKAPI_ATTR void VKAPI_CALL vkDestroyFramebuffer( + VkDevice device, + VkFramebuffer framebuffer, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass( + VkDevice device, + const VkRenderPassCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkRenderPass* pRenderPass); + +VKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass( + VkDevice device, + VkRenderPass renderPass, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkGetRenderAreaGranularity( + VkDevice device, + VkRenderPass renderPass, + VkExtent2D* pGranularity); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool( + VkDevice device, + const VkCommandPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCommandPool* pCommandPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool( + VkDevice device, + VkCommandPool commandPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolResetFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers( + VkDevice device, + const VkCommandBufferAllocateInfo* pAllocateInfo, + VkCommandBuffer* pCommandBuffers); + +VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers( + VkDevice device, + VkCommandPool commandPool, + uint32_t commandBufferCount, + const VkCommandBuffer* pCommandBuffers); + +VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer( + VkCommandBuffer commandBuffer, + const VkCommandBufferBeginInfo* pBeginInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer( + VkCommandBuffer commandBuffer, + VkCommandBufferResetFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipeline pipeline); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewport( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkViewport* pViewports); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetScissor( + VkCommandBuffer commandBuffer, + uint32_t firstScissor, + uint32_t scissorCount, + const VkRect2D* pScissors); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth( + VkCommandBuffer commandBuffer, + float lineWidth); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias( + VkCommandBuffer commandBuffer, + float depthBiasConstantFactor, + float depthBiasClamp, + float depthBiasSlopeFactor); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants( + VkCommandBuffer commandBuffer, + const float blendConstants[4]); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBounds( + VkCommandBuffer commandBuffer, + float minDepthBounds, + float maxDepthBounds); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilCompareMask( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t compareMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilWriteMask( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t writeMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilReference( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t reference); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t firstSet, + uint32_t descriptorSetCount, + const VkDescriptorSet* pDescriptorSets, + uint32_t dynamicOffsetCount, + const uint32_t* pDynamicOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkIndexType indexType); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdDraw( + VkCommandBuffer commandBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed( + VkCommandBuffer commandBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatch( + VkCommandBuffer commandBuffer, + uint32_t x, + uint32_t y, + uint32_t z); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer( + VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageBlit* pRegions, + VkFilter filter); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage( + VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkBufferImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer( + VkCommandBuffer commandBuffer, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize dataSize, + const uint32_t* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer( + VkCommandBuffer commandBuffer, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize size, + uint32_t data); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage( + VkCommandBuffer commandBuffer, + VkImage image, + VkImageLayout imageLayout, + const VkClearColorValue* pColor, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearDepthStencilImage( + VkCommandBuffer commandBuffer, + VkImage image, + VkImageLayout imageLayout, + const VkClearDepthStencilValue* pDepthStencil, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments( + VkCommandBuffer commandBuffer, + uint32_t attachmentCount, + const VkClearAttachment* pAttachments, + uint32_t rectCount, + const VkClearRect* pRects); + +VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageResolve* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents( + VkCommandBuffer commandBuffer, + uint32_t eventCount, + const VkEvent* pEvents, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers); + +VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetQueryPool( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp( + VkCommandBuffer commandBuffer, + VkPipelineStageFlagBits pipelineStage, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize stride, + VkQueryResultFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants( + VkCommandBuffer commandBuffer, + VkPipelineLayout layout, + VkShaderStageFlags stageFlags, + uint32_t offset, + uint32_t size, + const void* pValues); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass( + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + VkSubpassContents contents); + +VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass( + VkCommandBuffer commandBuffer, + VkSubpassContents contents); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR void VKAPI_CALL vkCmdExecuteCommands( + VkCommandBuffer commandBuffer, + uint32_t commandBufferCount, + const VkCommandBuffer* pCommandBuffers); +#endif + +#define VK_KHR_surface 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) + +#define VK_KHR_SURFACE_SPEC_VERSION 25 +#define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" + + +typedef enum VkColorSpaceKHR { + VK_COLORSPACE_SRGB_NONLINEAR_KHR = 0, + VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLORSPACE_SRGB_NONLINEAR_KHR, + VK_COLOR_SPACE_END_RANGE_KHR = VK_COLORSPACE_SRGB_NONLINEAR_KHR, + VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLORSPACE_SRGB_NONLINEAR_KHR - VK_COLORSPACE_SRGB_NONLINEAR_KHR + 1), + VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkColorSpaceKHR; + +typedef enum VkPresentModeKHR { + VK_PRESENT_MODE_IMMEDIATE_KHR = 0, + VK_PRESENT_MODE_MAILBOX_KHR = 1, + VK_PRESENT_MODE_FIFO_KHR = 2, + VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, + VK_PRESENT_MODE_BEGIN_RANGE_KHR = VK_PRESENT_MODE_IMMEDIATE_KHR, + VK_PRESENT_MODE_END_RANGE_KHR = VK_PRESENT_MODE_FIFO_RELAXED_KHR, + VK_PRESENT_MODE_RANGE_SIZE_KHR = (VK_PRESENT_MODE_FIFO_RELAXED_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1), + VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPresentModeKHR; + + +typedef enum VkSurfaceTransformFlagBitsKHR { + VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001, + VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, + VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004, + VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080, + VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, + VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkSurfaceTransformFlagBitsKHR; +typedef VkFlags VkSurfaceTransformFlagsKHR; + +typedef enum VkCompositeAlphaFlagBitsKHR { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, + VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkCompositeAlphaFlagBitsKHR; +typedef VkFlags VkCompositeAlphaFlagsKHR; + +typedef struct VkSurfaceCapabilitiesKHR { + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; +} VkSurfaceCapabilitiesKHR; + +typedef struct VkSurfaceFormatKHR { + VkFormat format; + VkColorSpaceKHR colorSpace; +} VkSurfaceFormatKHR; + + +typedef void (VKAPI_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR( + VkInstance instance, + VkSurfaceKHR surface, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + VkSurfaceKHR surface, + VkBool32* pSupported); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pSurfaceFormatCount, + VkSurfaceFormatKHR* pSurfaceFormats); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pPresentModeCount, + VkPresentModeKHR* pPresentModes); +#endif + +#define VK_KHR_swapchain 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) + +#define VK_KHR_SWAPCHAIN_SPEC_VERSION 68 +#define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" + +typedef VkFlags VkSwapchainCreateFlagsKHR; + +typedef struct VkSwapchainCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainCreateFlagsKHR flags; + VkSurfaceKHR surface; + uint32_t minImageCount; + VkFormat imageFormat; + VkColorSpaceKHR imageColorSpace; + VkExtent2D imageExtent; + uint32_t imageArrayLayers; + VkImageUsageFlags imageUsage; + VkSharingMode imageSharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; + VkSurfaceTransformFlagBitsKHR preTransform; + VkCompositeAlphaFlagBitsKHR compositeAlpha; + VkPresentModeKHR presentMode; + VkBool32 clipped; + VkSwapchainKHR oldSwapchain; +} VkSwapchainCreateInfoKHR; + +typedef struct VkPresentInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + uint32_t swapchainCount; + const VkSwapchainKHR* pSwapchains; + const uint32_t* pImageIndices; + VkResult* pResults; +} VkPresentInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); +typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); +typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR( + VkDevice device, + const VkSwapchainCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSwapchainKHR* pSwapchain); + +VKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR( + VkDevice device, + VkSwapchainKHR swapchain, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t* pSwapchainImageCount, + VkImage* pSwapchainImages); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint64_t timeout, + VkSemaphore semaphore, + VkFence fence, + uint32_t* pImageIndex); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR( + VkQueue queue, + const VkPresentInfoKHR* pPresentInfo); +#endif + +#define VK_KHR_display 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) + +#define VK_KHR_DISPLAY_SPEC_VERSION 21 +#define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display" + + +typedef enum VkDisplayPlaneAlphaFlagBitsKHR { + VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, + VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002, + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004, + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008, + VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDisplayPlaneAlphaFlagBitsKHR; +typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; +typedef VkFlags VkDisplayModeCreateFlagsKHR; +typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; + +typedef struct VkDisplayPropertiesKHR { + VkDisplayKHR display; + const char* displayName; + VkExtent2D physicalDimensions; + VkExtent2D physicalResolution; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkBool32 planeReorderPossible; + VkBool32 persistentContent; +} VkDisplayPropertiesKHR; + +typedef struct VkDisplayModeParametersKHR { + VkExtent2D visibleRegion; + uint32_t refreshRate; +} VkDisplayModeParametersKHR; + +typedef struct VkDisplayModePropertiesKHR { + VkDisplayModeKHR displayMode; + VkDisplayModeParametersKHR parameters; +} VkDisplayModePropertiesKHR; + +typedef struct VkDisplayModeCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDisplayModeCreateFlagsKHR flags; + VkDisplayModeParametersKHR parameters; +} VkDisplayModeCreateInfoKHR; + +typedef struct VkDisplayPlaneCapabilitiesKHR { + VkDisplayPlaneAlphaFlagsKHR supportedAlpha; + VkOffset2D minSrcPosition; + VkOffset2D maxSrcPosition; + VkExtent2D minSrcExtent; + VkExtent2D maxSrcExtent; + VkOffset2D minDstPosition; + VkOffset2D maxDstPosition; + VkExtent2D minDstExtent; + VkExtent2D maxDstExtent; +} VkDisplayPlaneCapabilitiesKHR; + +typedef struct VkDisplayPlanePropertiesKHR { + VkDisplayKHR currentDisplay; + uint32_t currentStackIndex; +} VkDisplayPlanePropertiesKHR; + +typedef struct VkDisplaySurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDisplaySurfaceCreateFlagsKHR flags; + VkDisplayModeKHR displayMode; + uint32_t planeIndex; + uint32_t planeStackIndex; + VkSurfaceTransformFlagBitsKHR transform; + float globalAlpha; + VkDisplayPlaneAlphaFlagBitsKHR alphaMode; + VkExtent2D imageExtent; +} VkDisplaySurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPropertiesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlanePropertiesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPlanePropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneSupportedDisplaysKHR( + VkPhysicalDevice physicalDevice, + uint32_t planeIndex, + uint32_t* pDisplayCount, + VkDisplayKHR* pDisplays); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModePropertiesKHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t* pPropertyCount, + VkDisplayModePropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayModeKHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + const VkDisplayModeCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDisplayModeKHR* pMode); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilitiesKHR( + VkPhysicalDevice physicalDevice, + VkDisplayModeKHR mode, + uint32_t planeIndex, + VkDisplayPlaneCapabilitiesKHR* pCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayPlaneSurfaceKHR( + VkInstance instance, + const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#define VK_KHR_display_swapchain 1 +#define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9 +#define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain" + +typedef struct VkDisplayPresentInfoKHR { + VkStructureType sType; + const void* pNext; + VkRect2D srcRect; + VkRect2D dstRect; + VkBool32 persistent; +} VkDisplayPresentInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR( + VkDevice device, + uint32_t swapchainCount, + const VkSwapchainCreateInfoKHR* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkSwapchainKHR* pSwapchains); +#endif + +#ifdef VK_USE_PLATFORM_XLIB_KHR +#define VK_KHR_xlib_surface 1 +#include + +#define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6 +#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface" + +typedef VkFlags VkXlibSurfaceCreateFlagsKHR; + +typedef struct VkXlibSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display* dpy; + Window window; +} VkXlibSurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR( + VkInstance instance, + const VkXlibSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + Display* dpy, + VisualID visualID); +#endif +#endif /* VK_USE_PLATFORM_XLIB_KHR */ + +#ifdef VK_USE_PLATFORM_XCB_KHR +#define VK_KHR_xcb_surface 1 +#include + +#define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 +#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface" + +typedef VkFlags VkXcbSurfaceCreateFlagsKHR; + +typedef struct VkXcbSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t* connection; + xcb_window_t window; +} VkXcbSurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR( + VkInstance instance, + const VkXcbSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + xcb_connection_t* connection, + xcb_visualid_t visual_id); +#endif +#endif /* VK_USE_PLATFORM_XCB_KHR */ + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +#define VK_KHR_wayland_surface 1 +#include + +#define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 5 +#define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface" + +typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; + +typedef struct VkWaylandSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + struct wl_display* display; + struct wl_surface* surface; +} VkWaylandSurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display* display); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateWaylandSurfaceKHR( + VkInstance instance, + const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWaylandPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + struct wl_display* display); +#endif +#endif /* VK_USE_PLATFORM_WAYLAND_KHR */ + +#ifdef VK_USE_PLATFORM_MIR_KHR +#define VK_KHR_mir_surface 1 +#include + +#define VK_KHR_MIR_SURFACE_SPEC_VERSION 4 +#define VK_KHR_MIR_SURFACE_EXTENSION_NAME "VK_KHR_mir_surface" + +typedef VkFlags VkMirSurfaceCreateFlagsKHR; + +typedef struct VkMirSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkMirSurfaceCreateFlagsKHR flags; + MirConnection* connection; + MirSurface* mirSurface; +} VkMirSurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateMirSurfaceKHR)(VkInstance instance, const VkMirSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, MirConnection* connection); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateMirSurfaceKHR( + VkInstance instance, + const VkMirSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceMirPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + MirConnection* connection); +#endif +#endif /* VK_USE_PLATFORM_MIR_KHR */ + +#ifdef VK_USE_PLATFORM_ANDROID_KHR +#define VK_KHR_android_surface 1 +#include + +#define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 +#define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface" + +typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; + +typedef struct VkAndroidSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkAndroidSurfaceCreateFlagsKHR flags; + ANativeWindow* window; +} VkAndroidSurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR( + VkInstance instance, + const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif +#endif /* VK_USE_PLATFORM_ANDROID_KHR */ + +#ifdef VK_USE_PLATFORM_WIN32_KHR +#define VK_KHR_win32_surface 1 +#include + +#define VK_KHR_WIN32_SURFACE_SPEC_VERSION 5 +#define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface" + +typedef VkFlags VkWin32SurfaceCreateFlagsKHR; + +typedef struct VkWin32SurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkWin32SurfaceCreateFlagsKHR flags; + HINSTANCE hinstance; + HWND hwnd; +} VkWin32SurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateWin32SurfaceKHR)(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR( + VkInstance instance, + const VkWin32SurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex); +#endif +#endif /* VK_USE_PLATFORM_WIN32_KHR */ + +#define VK_KHR_sampler_mirror_clamp_to_edge 1 +#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1 +#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" + + +#define VK_EXT_debug_report 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) + +#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 2 +#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" +#define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT + + +typedef enum VkDebugReportObjectTypeEXT { + VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, + VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, + VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2, + VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3, + VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4, + VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5, + VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6, + VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7, + VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9, + VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10, + VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11, + VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13, + VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14, + VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17, + VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23, + VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24, + VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25, + VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26, + VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27, + VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28, + VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1), + VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugReportObjectTypeEXT; + +typedef enum VkDebugReportErrorEXT { + VK_DEBUG_REPORT_ERROR_NONE_EXT = 0, + VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1, + VK_DEBUG_REPORT_ERROR_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_ERROR_NONE_EXT, + VK_DEBUG_REPORT_ERROR_END_RANGE_EXT = VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, + VK_DEBUG_REPORT_ERROR_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT - VK_DEBUG_REPORT_ERROR_NONE_EXT + 1), + VK_DEBUG_REPORT_ERROR_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugReportErrorEXT; + + +typedef enum VkDebugReportFlagBitsEXT { + VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001, + VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002, + VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004, + VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008, + VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, + VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugReportFlagBitsEXT; +typedef VkFlags VkDebugReportFlagsEXT; + +typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* pUserData); + + +typedef struct VkDebugReportCallbackCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugReportFlagsEXT flags; + PFN_vkDebugReportCallbackEXT pfnCallback; + void* pUserData; +} VkDebugReportCallbackCreateInfoEXT; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); +typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT( + VkInstance instance, + const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDebugReportCallbackEXT* pCallback); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT( + VkInstance instance, + VkDebugReportCallbackEXT callback, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT( + VkInstance instance, + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage); +#endif + +#define VK_NV_glsl_shader 1 +#define VK_NV_GLSL_SHADER_SPEC_VERSION 1 +#define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader" + + +#define VK_IMG_filter_cubic 1 +#define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 +#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic" + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/include/GLFW/glfw3.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/include/GLFW/glfw3.h new file mode 100644 index 00000000..95caa955 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/include/GLFW/glfw3.h @@ -0,0 +1,4248 @@ +/************************************************************************* + * GLFW 3.2 - www.glfw.org + * A library for OpenGL, window and input + *------------------------------------------------------------------------ + * Copyright (c) 2002-2006 Marcus Geelnard + * Copyright (c) 2006-2016 Camilla Berglund + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + *************************************************************************/ + +#ifndef _glfw3_h_ +#define _glfw3_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************* + * Doxygen documentation + *************************************************************************/ + +/*! @file glfw3.h + * @brief The header of the GLFW 3 API. + * + * This is the header file of the GLFW 3 API. It defines all its types and + * declares all its functions. + * + * For more information about how to use this file, see @ref build_include. + */ +/*! @defgroup context Context reference + * + * This is the reference documentation for OpenGL and OpenGL ES context related + * functions. For more task-oriented information, see the @ref context_guide. + */ +/*! @defgroup vulkan Vulkan reference + * + * This is the reference documentation for Vulkan related functions and types. + * For more task-oriented information, see the @ref vulkan_guide. + */ +/*! @defgroup init Initialization, version and error reference + * + * This is the reference documentation for initialization and termination of + * the library, version management and error handling. For more task-oriented + * information, see the @ref intro_guide. + */ +/*! @defgroup input Input reference + * + * This is the reference documentation for input related functions and types. + * For more task-oriented information, see the @ref input_guide. + */ +/*! @defgroup monitor Monitor reference + * + * This is the reference documentation for monitor related functions and types. + * For more task-oriented information, see the @ref monitor_guide. + */ +/*! @defgroup window Window reference + * + * This is the reference documentation for window related functions and types, + * including creation, deletion and event polling. For more task-oriented + * information, see the @ref window_guide. + */ + + +/************************************************************************* + * Compiler- and platform-specific preprocessor work + *************************************************************************/ + +/* If we are we on Windows, we want a single define for it. + */ +#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)) + #define _WIN32 +#endif /* _WIN32 */ + +/* It is customary to use APIENTRY for OpenGL function pointer declarations on + * all platforms. Additionally, the Windows OpenGL header needs APIENTRY. + */ +#ifndef APIENTRY + #ifdef _WIN32 + #define APIENTRY __stdcall + #else + #define APIENTRY + #endif +#endif /* APIENTRY */ + +/* Some Windows OpenGL headers need this. + */ +#if !defined(WINGDIAPI) && defined(_WIN32) + #define WINGDIAPI __declspec(dllimport) + #define GLFW_WINGDIAPI_DEFINED +#endif /* WINGDIAPI */ + +/* Some Windows GLU headers need this. + */ +#if !defined(CALLBACK) && defined(_WIN32) + #define CALLBACK __stdcall + #define GLFW_CALLBACK_DEFINED +#endif /* CALLBACK */ + +/* Include because most Windows GLU headers need wchar_t and + * the OS X OpenGL header blocks the definition of ptrdiff_t by glext.h. + * Include it unconditionally to avoid surprising side-effects. + */ +#include + +/* Include because it is needed by Vulkan and related functions. + */ +#include + +/* Include the chosen client API headers. + */ +#if defined(__APPLE__) + #if defined(GLFW_INCLUDE_GLCOREARB) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + #elif !defined(GLFW_INCLUDE_NONE) + #if !defined(GLFW_INCLUDE_GLEXT) + #define GL_GLEXT_LEGACY + #endif + #include + #endif + #if defined(GLFW_INCLUDE_GLU) + #include + #endif +#else + #if defined(GLFW_INCLUDE_GLCOREARB) + #include + #elif defined(GLFW_INCLUDE_ES1) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + #elif defined(GLFW_INCLUDE_ES2) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + #elif defined(GLFW_INCLUDE_ES3) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + #elif defined(GLFW_INCLUDE_ES31) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + #elif defined(GLFW_INCLUDE_VULKAN) + #include + #elif !defined(GLFW_INCLUDE_NONE) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + #endif + #if defined(GLFW_INCLUDE_GLU) + #include + #endif +#endif + +#if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) + /* GLFW_DLL must be defined by applications that are linking against the DLL + * version of the GLFW library. _GLFW_BUILD_DLL is defined by the GLFW + * configuration header when compiling the DLL version of the library. + */ + #error "You must not have both GLFW_DLL and _GLFW_BUILD_DLL defined" +#endif + +/* GLFWAPI is used to declare public API functions for export + * from the DLL / shared library / dynamic library. + */ +#if defined(_WIN32) && defined(_GLFW_BUILD_DLL) + /* We are building GLFW as a Win32 DLL */ + #define GLFWAPI __declspec(dllexport) +#elif defined(_WIN32) && defined(GLFW_DLL) + /* We are calling GLFW as a Win32 DLL */ + #define GLFWAPI __declspec(dllimport) +#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) + /* We are building GLFW as a shared / dynamic library */ + #define GLFWAPI __attribute__((visibility("default"))) +#else + /* We are building or calling GLFW as a static library */ + #define GLFWAPI +#endif + + +/************************************************************************* + * GLFW API tokens + *************************************************************************/ + +/*! @name GLFW version macros + * @{ */ +/*! @brief The major version number of the GLFW library. + * + * This is incremented when the API is changed in non-compatible ways. + * @ingroup init + */ +#define GLFW_VERSION_MAJOR 3 +/*! @brief The minor version number of the GLFW library. + * + * This is incremented when features are added to the API but it remains + * backward-compatible. + * @ingroup init + */ +#define GLFW_VERSION_MINOR 2 +/*! @brief The revision number of the GLFW library. + * + * This is incremented when a bug fix release is made that does not contain any + * API changes. + * @ingroup init + */ +#define GLFW_VERSION_REVISION 1 +/*! @} */ + +/*! @name Boolean values + * @{ */ +/*! @brief One. + * + * One. Seriously. You don't _need_ to use this symbol in your code. It's + * just semantic sugar for the number 1. You can use `1` or `true` or `_True` + * or `GL_TRUE` or whatever you want. + */ +#define GLFW_TRUE 1 +/*! @brief Zero. + * + * Zero. Seriously. You don't _need_ to use this symbol in your code. It's + * just just semantic sugar for the number 0. You can use `0` or `false` or + * `_False` or `GL_FALSE` or whatever you want. + */ +#define GLFW_FALSE 0 +/*! @} */ + +/*! @name Key and button actions + * @{ */ +/*! @brief The key or mouse button was released. + * + * The key or mouse button was released. + * + * @ingroup input + */ +#define GLFW_RELEASE 0 +/*! @brief The key or mouse button was pressed. + * + * The key or mouse button was pressed. + * + * @ingroup input + */ +#define GLFW_PRESS 1 +/*! @brief The key was held down until it repeated. + * + * The key was held down until it repeated. + * + * @ingroup input + */ +#define GLFW_REPEAT 2 +/*! @} */ + +/*! @defgroup keys Keyboard keys + * + * See [key input](@ref input_key) for how these are used. + * + * These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60), + * but re-arranged to map to 7-bit ASCII for printable keys (function keys are + * put in the 256+ range). + * + * The naming of the key codes follow these rules: + * - The US keyboard layout is used + * - Names of printable alpha-numeric characters are used (e.g. "A", "R", + * "3", etc.) + * - For non-alphanumeric characters, Unicode:ish names are used (e.g. + * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not + * correspond to the Unicode standard (usually for brevity) + * - Keys that lack a clear US mapping are named "WORLD_x" + * - For non-printable keys, custom names are used (e.g. "F4", + * "BACKSPACE", etc.) + * + * @ingroup input + * @{ + */ + +/* The unknown key */ +#define GLFW_KEY_UNKNOWN -1 + +/* Printable keys */ +#define GLFW_KEY_SPACE 32 +#define GLFW_KEY_APOSTROPHE 39 /* ' */ +#define GLFW_KEY_COMMA 44 /* , */ +#define GLFW_KEY_MINUS 45 /* - */ +#define GLFW_KEY_PERIOD 46 /* . */ +#define GLFW_KEY_SLASH 47 /* / */ +#define GLFW_KEY_0 48 +#define GLFW_KEY_1 49 +#define GLFW_KEY_2 50 +#define GLFW_KEY_3 51 +#define GLFW_KEY_4 52 +#define GLFW_KEY_5 53 +#define GLFW_KEY_6 54 +#define GLFW_KEY_7 55 +#define GLFW_KEY_8 56 +#define GLFW_KEY_9 57 +#define GLFW_KEY_SEMICOLON 59 /* ; */ +#define GLFW_KEY_EQUAL 61 /* = */ +#define GLFW_KEY_A 65 +#define GLFW_KEY_B 66 +#define GLFW_KEY_C 67 +#define GLFW_KEY_D 68 +#define GLFW_KEY_E 69 +#define GLFW_KEY_F 70 +#define GLFW_KEY_G 71 +#define GLFW_KEY_H 72 +#define GLFW_KEY_I 73 +#define GLFW_KEY_J 74 +#define GLFW_KEY_K 75 +#define GLFW_KEY_L 76 +#define GLFW_KEY_M 77 +#define GLFW_KEY_N 78 +#define GLFW_KEY_O 79 +#define GLFW_KEY_P 80 +#define GLFW_KEY_Q 81 +#define GLFW_KEY_R 82 +#define GLFW_KEY_S 83 +#define GLFW_KEY_T 84 +#define GLFW_KEY_U 85 +#define GLFW_KEY_V 86 +#define GLFW_KEY_W 87 +#define GLFW_KEY_X 88 +#define GLFW_KEY_Y 89 +#define GLFW_KEY_Z 90 +#define GLFW_KEY_LEFT_BRACKET 91 /* [ */ +#define GLFW_KEY_BACKSLASH 92 /* \ */ +#define GLFW_KEY_RIGHT_BRACKET 93 /* ] */ +#define GLFW_KEY_GRAVE_ACCENT 96 /* ` */ +#define GLFW_KEY_WORLD_1 161 /* non-US #1 */ +#define GLFW_KEY_WORLD_2 162 /* non-US #2 */ + +/* Function keys */ +#define GLFW_KEY_ESCAPE 256 +#define GLFW_KEY_ENTER 257 +#define GLFW_KEY_TAB 258 +#define GLFW_KEY_BACKSPACE 259 +#define GLFW_KEY_INSERT 260 +#define GLFW_KEY_DELETE 261 +#define GLFW_KEY_RIGHT 262 +#define GLFW_KEY_LEFT 263 +#define GLFW_KEY_DOWN 264 +#define GLFW_KEY_UP 265 +#define GLFW_KEY_PAGE_UP 266 +#define GLFW_KEY_PAGE_DOWN 267 +#define GLFW_KEY_HOME 268 +#define GLFW_KEY_END 269 +#define GLFW_KEY_CAPS_LOCK 280 +#define GLFW_KEY_SCROLL_LOCK 281 +#define GLFW_KEY_NUM_LOCK 282 +#define GLFW_KEY_PRINT_SCREEN 283 +#define GLFW_KEY_PAUSE 284 +#define GLFW_KEY_F1 290 +#define GLFW_KEY_F2 291 +#define GLFW_KEY_F3 292 +#define GLFW_KEY_F4 293 +#define GLFW_KEY_F5 294 +#define GLFW_KEY_F6 295 +#define GLFW_KEY_F7 296 +#define GLFW_KEY_F8 297 +#define GLFW_KEY_F9 298 +#define GLFW_KEY_F10 299 +#define GLFW_KEY_F11 300 +#define GLFW_KEY_F12 301 +#define GLFW_KEY_F13 302 +#define GLFW_KEY_F14 303 +#define GLFW_KEY_F15 304 +#define GLFW_KEY_F16 305 +#define GLFW_KEY_F17 306 +#define GLFW_KEY_F18 307 +#define GLFW_KEY_F19 308 +#define GLFW_KEY_F20 309 +#define GLFW_KEY_F21 310 +#define GLFW_KEY_F22 311 +#define GLFW_KEY_F23 312 +#define GLFW_KEY_F24 313 +#define GLFW_KEY_F25 314 +#define GLFW_KEY_KP_0 320 +#define GLFW_KEY_KP_1 321 +#define GLFW_KEY_KP_2 322 +#define GLFW_KEY_KP_3 323 +#define GLFW_KEY_KP_4 324 +#define GLFW_KEY_KP_5 325 +#define GLFW_KEY_KP_6 326 +#define GLFW_KEY_KP_7 327 +#define GLFW_KEY_KP_8 328 +#define GLFW_KEY_KP_9 329 +#define GLFW_KEY_KP_DECIMAL 330 +#define GLFW_KEY_KP_DIVIDE 331 +#define GLFW_KEY_KP_MULTIPLY 332 +#define GLFW_KEY_KP_SUBTRACT 333 +#define GLFW_KEY_KP_ADD 334 +#define GLFW_KEY_KP_ENTER 335 +#define GLFW_KEY_KP_EQUAL 336 +#define GLFW_KEY_LEFT_SHIFT 340 +#define GLFW_KEY_LEFT_CONTROL 341 +#define GLFW_KEY_LEFT_ALT 342 +#define GLFW_KEY_LEFT_SUPER 343 +#define GLFW_KEY_RIGHT_SHIFT 344 +#define GLFW_KEY_RIGHT_CONTROL 345 +#define GLFW_KEY_RIGHT_ALT 346 +#define GLFW_KEY_RIGHT_SUPER 347 +#define GLFW_KEY_MENU 348 + +#define GLFW_KEY_LAST GLFW_KEY_MENU + +/*! @} */ + +/*! @defgroup mods Modifier key flags + * + * See [key input](@ref input_key) for how these are used. + * + * @ingroup input + * @{ */ + +/*! @brief If this bit is set one or more Shift keys were held down. + */ +#define GLFW_MOD_SHIFT 0x0001 +/*! @brief If this bit is set one or more Control keys were held down. + */ +#define GLFW_MOD_CONTROL 0x0002 +/*! @brief If this bit is set one or more Alt keys were held down. + */ +#define GLFW_MOD_ALT 0x0004 +/*! @brief If this bit is set one or more Super keys were held down. + */ +#define GLFW_MOD_SUPER 0x0008 + +/*! @} */ + +/*! @defgroup buttons Mouse buttons + * + * See [mouse button input](@ref input_mouse_button) for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_MOUSE_BUTTON_1 0 +#define GLFW_MOUSE_BUTTON_2 1 +#define GLFW_MOUSE_BUTTON_3 2 +#define GLFW_MOUSE_BUTTON_4 3 +#define GLFW_MOUSE_BUTTON_5 4 +#define GLFW_MOUSE_BUTTON_6 5 +#define GLFW_MOUSE_BUTTON_7 6 +#define GLFW_MOUSE_BUTTON_8 7 +#define GLFW_MOUSE_BUTTON_LAST GLFW_MOUSE_BUTTON_8 +#define GLFW_MOUSE_BUTTON_LEFT GLFW_MOUSE_BUTTON_1 +#define GLFW_MOUSE_BUTTON_RIGHT GLFW_MOUSE_BUTTON_2 +#define GLFW_MOUSE_BUTTON_MIDDLE GLFW_MOUSE_BUTTON_3 +/*! @} */ + +/*! @defgroup joysticks Joysticks + * + * See [joystick input](@ref joystick) for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_JOYSTICK_1 0 +#define GLFW_JOYSTICK_2 1 +#define GLFW_JOYSTICK_3 2 +#define GLFW_JOYSTICK_4 3 +#define GLFW_JOYSTICK_5 4 +#define GLFW_JOYSTICK_6 5 +#define GLFW_JOYSTICK_7 6 +#define GLFW_JOYSTICK_8 7 +#define GLFW_JOYSTICK_9 8 +#define GLFW_JOYSTICK_10 9 +#define GLFW_JOYSTICK_11 10 +#define GLFW_JOYSTICK_12 11 +#define GLFW_JOYSTICK_13 12 +#define GLFW_JOYSTICK_14 13 +#define GLFW_JOYSTICK_15 14 +#define GLFW_JOYSTICK_16 15 +#define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16 +/*! @} */ + +/*! @defgroup errors Error codes + * + * See [error handling](@ref error_handling) for how these are used. + * + * @ingroup init + * @{ */ +/*! @brief GLFW has not been initialized. + * + * This occurs if a GLFW function was called that must not be called unless the + * library is [initialized](@ref intro_init). + * + * @analysis Application programmer error. Initialize GLFW before calling any + * function that requires initialization. + */ +#define GLFW_NOT_INITIALIZED 0x00010001 +/*! @brief No context is current for this thread. + * + * This occurs if a GLFW function was called that needs and operates on the + * current OpenGL or OpenGL ES context but no context is current on the calling + * thread. One such function is @ref glfwSwapInterval. + * + * @analysis Application programmer error. Ensure a context is current before + * calling functions that require a current context. + */ +#define GLFW_NO_CURRENT_CONTEXT 0x00010002 +/*! @brief One of the arguments to the function was an invalid enum value. + * + * One of the arguments to the function was an invalid enum value, for example + * requesting [GLFW_RED_BITS](@ref window_hints_fb) with @ref + * glfwGetWindowAttrib. + * + * @analysis Application programmer error. Fix the offending call. + */ +#define GLFW_INVALID_ENUM 0x00010003 +/*! @brief One of the arguments to the function was an invalid value. + * + * One of the arguments to the function was an invalid value, for example + * requesting a non-existent OpenGL or OpenGL ES version like 2.7. + * + * Requesting a valid but unavailable OpenGL or OpenGL ES version will instead + * result in a @ref GLFW_VERSION_UNAVAILABLE error. + * + * @analysis Application programmer error. Fix the offending call. + */ +#define GLFW_INVALID_VALUE 0x00010004 +/*! @brief A memory allocation failed. + * + * A memory allocation failed. + * + * @analysis A bug in GLFW or the underlying operating system. Report the bug + * to our [issue tracker](/~https://github.com/glfw/glfw/issues). + */ +#define GLFW_OUT_OF_MEMORY 0x00010005 +/*! @brief GLFW could not find support for the requested API on the system. + * + * GLFW could not find support for the requested API on the system. + * + * @analysis The installed graphics driver does not support the requested + * API, or does not support it via the chosen context creation backend. + * Below are a few examples. + * + * @par + * Some pre-installed Windows graphics drivers do not support OpenGL. AMD only + * supports OpenGL ES via EGL, while Nvidia and Intel only support it via + * a WGL or GLX extension. OS X does not provide OpenGL ES at all. The Mesa + * EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary + * driver. Older graphics drivers do not support Vulkan. + */ +#define GLFW_API_UNAVAILABLE 0x00010006 +/*! @brief The requested OpenGL or OpenGL ES version is not available. + * + * The requested OpenGL or OpenGL ES version (including any requested context + * or framebuffer hints) is not available on this machine. + * + * @analysis The machine does not support your requirements. If your + * application is sufficiently flexible, downgrade your requirements and try + * again. Otherwise, inform the user that their machine does not match your + * requirements. + * + * @par + * Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 + * comes out before the 4.x series gets that far, also fail with this error and + * not @ref GLFW_INVALID_VALUE, because GLFW cannot know what future versions + * will exist. + */ +#define GLFW_VERSION_UNAVAILABLE 0x00010007 +/*! @brief A platform-specific error occurred that does not match any of the + * more specific categories. + * + * A platform-specific error occurred that does not match any of the more + * specific categories. + * + * @analysis A bug or configuration error in GLFW, the underlying operating + * system or its drivers, or a lack of required resources. Report the issue to + * our [issue tracker](/~https://github.com/glfw/glfw/issues). + */ +#define GLFW_PLATFORM_ERROR 0x00010008 +/*! @brief The requested format is not supported or available. + * + * If emitted during window creation, the requested pixel format is not + * supported. + * + * If emitted when querying the clipboard, the contents of the clipboard could + * not be converted to the requested format. + * + * @analysis If emitted during window creation, one or more + * [hard constraints](@ref window_hints_hard) did not match any of the + * available pixel formats. If your application is sufficiently flexible, + * downgrade your requirements and try again. Otherwise, inform the user that + * their machine does not match your requirements. + * + * @par + * If emitted when querying the clipboard, ignore the error or report it to + * the user, as appropriate. + */ +#define GLFW_FORMAT_UNAVAILABLE 0x00010009 +/*! @brief The specified window does not have an OpenGL or OpenGL ES context. + * + * A window that does not have an OpenGL or OpenGL ES context was passed to + * a function that requires it to have one. + * + * @analysis Application programmer error. Fix the offending call. + */ +#define GLFW_NO_WINDOW_CONTEXT 0x0001000A +/*! @} */ + +#define GLFW_FOCUSED 0x00020001 +#define GLFW_ICONIFIED 0x00020002 +#define GLFW_RESIZABLE 0x00020003 +#define GLFW_VISIBLE 0x00020004 +#define GLFW_DECORATED 0x00020005 +#define GLFW_AUTO_ICONIFY 0x00020006 +#define GLFW_FLOATING 0x00020007 +#define GLFW_MAXIMIZED 0x00020008 + +#define GLFW_RED_BITS 0x00021001 +#define GLFW_GREEN_BITS 0x00021002 +#define GLFW_BLUE_BITS 0x00021003 +#define GLFW_ALPHA_BITS 0x00021004 +#define GLFW_DEPTH_BITS 0x00021005 +#define GLFW_STENCIL_BITS 0x00021006 +#define GLFW_ACCUM_RED_BITS 0x00021007 +#define GLFW_ACCUM_GREEN_BITS 0x00021008 +#define GLFW_ACCUM_BLUE_BITS 0x00021009 +#define GLFW_ACCUM_ALPHA_BITS 0x0002100A +#define GLFW_AUX_BUFFERS 0x0002100B +#define GLFW_STEREO 0x0002100C +#define GLFW_SAMPLES 0x0002100D +#define GLFW_SRGB_CAPABLE 0x0002100E +#define GLFW_REFRESH_RATE 0x0002100F +#define GLFW_DOUBLEBUFFER 0x00021010 + +#define GLFW_CLIENT_API 0x00022001 +#define GLFW_CONTEXT_VERSION_MAJOR 0x00022002 +#define GLFW_CONTEXT_VERSION_MINOR 0x00022003 +#define GLFW_CONTEXT_REVISION 0x00022004 +#define GLFW_CONTEXT_ROBUSTNESS 0x00022005 +#define GLFW_OPENGL_FORWARD_COMPAT 0x00022006 +#define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 +#define GLFW_OPENGL_PROFILE 0x00022008 +#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 +#define GLFW_CONTEXT_NO_ERROR 0x0002200A +#define GLFW_CONTEXT_CREATION_API 0x0002200B + +#define GLFW_NO_API 0 +#define GLFW_OPENGL_API 0x00030001 +#define GLFW_OPENGL_ES_API 0x00030002 + +#define GLFW_NO_ROBUSTNESS 0 +#define GLFW_NO_RESET_NOTIFICATION 0x00031001 +#define GLFW_LOSE_CONTEXT_ON_RESET 0x00031002 + +#define GLFW_OPENGL_ANY_PROFILE 0 +#define GLFW_OPENGL_CORE_PROFILE 0x00032001 +#define GLFW_OPENGL_COMPAT_PROFILE 0x00032002 + +#define GLFW_CURSOR 0x00033001 +#define GLFW_STICKY_KEYS 0x00033002 +#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 + +#define GLFW_CURSOR_NORMAL 0x00034001 +#define GLFW_CURSOR_HIDDEN 0x00034002 +#define GLFW_CURSOR_DISABLED 0x00034003 + +#define GLFW_ANY_RELEASE_BEHAVIOR 0 +#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 +#define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002 + +#define GLFW_NATIVE_CONTEXT_API 0x00036001 +#define GLFW_EGL_CONTEXT_API 0x00036002 + +/*! @defgroup shapes Standard cursor shapes + * + * See [standard cursor creation](@ref cursor_standard) for how these are used. + * + * @ingroup input + * @{ */ + +/*! @brief The regular arrow cursor shape. + * + * The regular arrow cursor. + */ +#define GLFW_ARROW_CURSOR 0x00036001 +/*! @brief The text input I-beam cursor shape. + * + * The text input I-beam cursor shape. + */ +#define GLFW_IBEAM_CURSOR 0x00036002 +/*! @brief The crosshair shape. + * + * The crosshair shape. + */ +#define GLFW_CROSSHAIR_CURSOR 0x00036003 +/*! @brief The hand shape. + * + * The hand shape. + */ +#define GLFW_HAND_CURSOR 0x00036004 +/*! @brief The horizontal resize arrow shape. + * + * The horizontal resize arrow shape. + */ +#define GLFW_HRESIZE_CURSOR 0x00036005 +/*! @brief The vertical resize arrow shape. + * + * The vertical resize arrow shape. + */ +#define GLFW_VRESIZE_CURSOR 0x00036006 +/*! @} */ + +#define GLFW_CONNECTED 0x00040001 +#define GLFW_DISCONNECTED 0x00040002 + +#define GLFW_DONT_CARE -1 + + +/************************************************************************* + * GLFW API types + *************************************************************************/ + +/*! @brief Client API function pointer type. + * + * Generic function pointer used for returning client API function pointers + * without forcing a cast from a regular pointer. + * + * @sa @ref context_glext + * @sa glfwGetProcAddress + * + * @since Added in version 3.0. + + * @ingroup context + */ +typedef void (*GLFWglproc)(void); + +/*! @brief Vulkan API function pointer type. + * + * Generic function pointer used for returning Vulkan API function pointers + * without forcing a cast from a regular pointer. + * + * @sa @ref vulkan_proc + * @sa glfwGetInstanceProcAddress + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +typedef void (*GLFWvkproc)(void); + +/*! @brief Opaque monitor object. + * + * Opaque monitor object. + * + * @see @ref monitor_object + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +typedef struct GLFWmonitor GLFWmonitor; + +/*! @brief Opaque window object. + * + * Opaque window object. + * + * @see @ref window_object + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef struct GLFWwindow GLFWwindow; + +/*! @brief Opaque cursor object. + * + * Opaque cursor object. + * + * @see @ref cursor_object + * + * @since Added in version 3.1. + * + * @ingroup cursor + */ +typedef struct GLFWcursor GLFWcursor; + +/*! @brief The function signature for error callbacks. + * + * This is the function signature for error callback functions. + * + * @param[in] error An [error code](@ref errors). + * @param[in] description A UTF-8 encoded string describing the error. + * + * @sa @ref error_handling + * @sa glfwSetErrorCallback + * + * @since Added in version 3.0. + * + * @ingroup init + */ +typedef void (* GLFWerrorfun)(int,const char*); + +/*! @brief The function signature for window position callbacks. + * + * This is the function signature for window position callback functions. + * + * @param[in] window The window that was moved. + * @param[in] xpos The new x-coordinate, in screen coordinates, of the + * upper-left corner of the client area of the window. + * @param[in] ypos The new y-coordinate, in screen coordinates, of the + * upper-left corner of the client area of the window. + * + * @sa @ref window_pos + * @sa glfwSetWindowPosCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); + +/*! @brief The function signature for window resize callbacks. + * + * This is the function signature for window size callback functions. + * + * @param[in] window The window that was resized. + * @param[in] width The new width, in screen coordinates, of the window. + * @param[in] height The new height, in screen coordinates, of the window. + * + * @sa @ref window_size + * @sa glfwSetWindowSizeCallback + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); + +/*! @brief The function signature for window close callbacks. + * + * This is the function signature for window close callback functions. + * + * @param[in] window The window that the user attempted to close. + * + * @sa @ref window_close + * @sa glfwSetWindowCloseCallback + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +typedef void (* GLFWwindowclosefun)(GLFWwindow*); + +/*! @brief The function signature for window content refresh callbacks. + * + * This is the function signature for window refresh callback functions. + * + * @param[in] window The window whose content needs to be refreshed. + * + * @sa @ref window_refresh + * @sa glfwSetWindowRefreshCallback + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); + +/*! @brief The function signature for window focus/defocus callbacks. + * + * This is the function signature for window focus callback functions. + * + * @param[in] window The window that gained or lost input focus. + * @param[in] focused `GLFW_TRUE` if the window was given input focus, or + * `GLFW_FALSE` if it lost it. + * + * @sa @ref window_focus + * @sa glfwSetWindowFocusCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); + +/*! @brief The function signature for window iconify/restore callbacks. + * + * This is the function signature for window iconify/restore callback + * functions. + * + * @param[in] window The window that was iconified or restored. + * @param[in] iconified `GLFW_TRUE` if the window was iconified, or + * `GLFW_FALSE` if it was restored. + * + * @sa @ref window_iconify + * @sa glfwSetWindowIconifyCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); + +/*! @brief The function signature for framebuffer resize callbacks. + * + * This is the function signature for framebuffer resize callback + * functions. + * + * @param[in] window The window whose framebuffer was resized. + * @param[in] width The new width, in pixels, of the framebuffer. + * @param[in] height The new height, in pixels, of the framebuffer. + * + * @sa @ref window_fbsize + * @sa glfwSetFramebufferSizeCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); + +/*! @brief The function signature for mouse button callbacks. + * + * This is the function signature for mouse button callback functions. + * + * @param[in] window The window that received the event. + * @param[in] button The [mouse button](@ref buttons) that was pressed or + * released. + * @param[in] action One of `GLFW_PRESS` or `GLFW_RELEASE`. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa @ref input_mouse_button + * @sa glfwSetMouseButtonCallback + * + * @since Added in version 1.0. + * @glfw3 Added window handle and modifier mask parameters. + * + * @ingroup input + */ +typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); + +/*! @brief The function signature for cursor position callbacks. + * + * This is the function signature for cursor position callback functions. + * + * @param[in] window The window that received the event. + * @param[in] xpos The new cursor x-coordinate, relative to the left edge of + * the client area. + * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the + * client area. + * + * @sa @ref cursor_pos + * @sa glfwSetCursorPosCallback + * + * @since Added in version 3.0. Replaces `GLFWmouseposfun`. + * + * @ingroup input + */ +typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); + +/*! @brief The function signature for cursor enter/leave callbacks. + * + * This is the function signature for cursor enter/leave callback functions. + * + * @param[in] window The window that received the event. + * @param[in] entered `GLFW_TRUE` if the cursor entered the window's client + * area, or `GLFW_FALSE` if it left it. + * + * @sa @ref cursor_enter + * @sa glfwSetCursorEnterCallback + * + * @since Added in version 3.0. + * + * @ingroup input + */ +typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); + +/*! @brief The function signature for scroll callbacks. + * + * This is the function signature for scroll callback functions. + * + * @param[in] window The window that received the event. + * @param[in] xoffset The scroll offset along the x-axis. + * @param[in] yoffset The scroll offset along the y-axis. + * + * @sa @ref scrolling + * @sa glfwSetScrollCallback + * + * @since Added in version 3.0. Replaces `GLFWmousewheelfun`. + * + * @ingroup input + */ +typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); + +/*! @brief The function signature for keyboard key callbacks. + * + * This is the function signature for keyboard key callback functions. + * + * @param[in] window The window that received the event. + * @param[in] key The [keyboard key](@ref keys) that was pressed or released. + * @param[in] scancode The system-specific scancode of the key. + * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa @ref input_key + * @sa glfwSetKeyCallback + * + * @since Added in version 1.0. + * @glfw3 Added window handle, scancode and modifier mask parameters. + * + * @ingroup input + */ +typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); + +/*! @brief The function signature for Unicode character callbacks. + * + * This is the function signature for Unicode character callback functions. + * + * @param[in] window The window that received the event. + * @param[in] codepoint The Unicode code point of the character. + * + * @sa @ref input_char + * @sa glfwSetCharCallback + * + * @since Added in version 2.4. + * @glfw3 Added window handle parameter. + * + * @ingroup input + */ +typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); + +/*! @brief The function signature for Unicode character with modifiers + * callbacks. + * + * This is the function signature for Unicode character with modifiers callback + * functions. It is called for each input character, regardless of what + * modifier keys are held down. + * + * @param[in] window The window that received the event. + * @param[in] codepoint The Unicode code point of the character. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa @ref input_char + * @sa glfwSetCharModsCallback + * + * @since Added in version 3.1. + * + * @ingroup input + */ +typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); + +/*! @brief The function signature for file drop callbacks. + * + * This is the function signature for file drop callbacks. + * + * @param[in] window The window that received the event. + * @param[in] count The number of dropped files. + * @param[in] paths The UTF-8 encoded file and/or directory path names. + * + * @sa @ref path_drop + * @sa glfwSetDropCallback + * + * @since Added in version 3.1. + * + * @ingroup input + */ +typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); + +/*! @brief The function signature for monitor configuration callbacks. + * + * This is the function signature for monitor configuration callback functions. + * + * @param[in] monitor The monitor that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + * + * @sa @ref monitor_event + * @sa glfwSetMonitorCallback + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +typedef void (* GLFWmonitorfun)(GLFWmonitor*,int); + +/*! @brief The function signature for joystick configuration callbacks. + * + * This is the function signature for joystick configuration callback + * functions. + * + * @param[in] joy The joystick that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + * + * @sa @ref joystick_event + * @sa glfwSetJoystickCallback + * + * @since Added in version 3.2. + * + * @ingroup input + */ +typedef void (* GLFWjoystickfun)(int,int); + +/*! @brief Video mode type. + * + * This describes a single video mode. + * + * @sa @ref monitor_modes + * @sa glfwGetVideoMode glfwGetVideoModes + * + * @since Added in version 1.0. + * @glfw3 Added refresh rate member. + * + * @ingroup monitor + */ +typedef struct GLFWvidmode +{ + /*! The width, in screen coordinates, of the video mode. + */ + int width; + /*! The height, in screen coordinates, of the video mode. + */ + int height; + /*! The bit depth of the red channel of the video mode. + */ + int redBits; + /*! The bit depth of the green channel of the video mode. + */ + int greenBits; + /*! The bit depth of the blue channel of the video mode. + */ + int blueBits; + /*! The refresh rate, in Hz, of the video mode. + */ + int refreshRate; +} GLFWvidmode; + +/*! @brief Gamma ramp. + * + * This describes the gamma ramp for a monitor. + * + * @sa @ref monitor_gamma + * @sa glfwGetGammaRamp glfwSetGammaRamp + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +typedef struct GLFWgammaramp +{ + /*! An array of value describing the response of the red channel. + */ + unsigned short* red; + /*! An array of value describing the response of the green channel. + */ + unsigned short* green; + /*! An array of value describing the response of the blue channel. + */ + unsigned short* blue; + /*! The number of elements in each array. + */ + unsigned int size; +} GLFWgammaramp; + +/*! @brief Image data. + * + * @sa @ref cursor_custom + * @sa @ref window_icon + * + * @since Added in version 2.1. + * @glfw3 Removed format and bytes-per-pixel members. + */ +typedef struct GLFWimage +{ + /*! The width, in pixels, of this image. + */ + int width; + /*! The height, in pixels, of this image. + */ + int height; + /*! The pixel data of this image, arranged left-to-right, top-to-bottom. + */ + unsigned char* pixels; +} GLFWimage; + + +/************************************************************************* + * GLFW API functions + *************************************************************************/ + +/*! @brief Initializes the GLFW library. + * + * This function initializes the GLFW library. Before most GLFW functions can + * be used, GLFW must be initialized, and before an application terminates GLFW + * should be terminated in order to free any resources allocated during or + * after initialization. + * + * If this function fails, it calls @ref glfwTerminate before returning. If it + * succeeds, you should call @ref glfwTerminate before the application exits. + * + * Additional calls to this function after successful initialization but before + * termination will return `GLFW_TRUE` immediately. + * + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. + * + * @remark @osx This function will change the current directory of the + * application to the `Contents/Resources` subdirectory of the application's + * bundle, if present. This can be disabled with a + * [compile-time option](@ref compile_options_osx). + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref intro_init + * @sa glfwTerminate + * + * @since Added in version 1.0. + * + * @ingroup init + */ +GLFWAPI int glfwInit(void); + +/*! @brief Terminates the GLFW library. + * + * This function destroys all remaining windows and cursors, restores any + * modified gamma ramps and frees any other allocated resources. Once this + * function is called, you must again call @ref glfwInit successfully before + * you will be able to use most GLFW functions. + * + * If GLFW has been successfully initialized, this function should be called + * before the application exits. If initialization fails, there is no need to + * call this function, as it is called by @ref glfwInit before it returns + * failure. + * + * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. + * + * @remark This function may be called before @ref glfwInit. + * + * @warning The contexts of any remaining windows must not be current on any + * other thread when this function is called. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref intro_init + * @sa glfwInit + * + * @since Added in version 1.0. + * + * @ingroup init + */ +GLFWAPI void glfwTerminate(void); + +/*! @brief Retrieves the version of the GLFW library. + * + * This function retrieves the major, minor and revision numbers of the GLFW + * library. It is intended for when you are using GLFW as a shared library and + * want to ensure that you are using the minimum required version. + * + * Any or all of the version arguments may be `NULL`. + * + * @param[out] major Where to store the major version number, or `NULL`. + * @param[out] minor Where to store the minor version number, or `NULL`. + * @param[out] rev Where to store the revision number, or `NULL`. + * + * @errors None. + * + * @remark This function may be called before @ref glfwInit. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref intro_version + * @sa glfwGetVersionString + * + * @since Added in version 1.0. + * + * @ingroup init + */ +GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); + +/*! @brief Returns a string describing the compile-time configuration. + * + * This function returns the compile-time generated + * [version string](@ref intro_version_string) of the GLFW library binary. It + * describes the version, platform, compiler and any platform-specific + * compile-time options. It should not be confused with the OpenGL or OpenGL + * ES version string, queried with `glGetString`. + * + * __Do not use the version string__ to parse the GLFW library version. The + * @ref glfwGetVersion function provides the version of the running library + * binary in numerical format. + * + * @return The ASCII encoded GLFW version string. + * + * @errors None. + * + * @remark This function may be called before @ref glfwInit. + * + * @pointer_lifetime The returned string is static and compile-time generated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref intro_version + * @sa glfwGetVersion + * + * @since Added in version 3.0. + * + * @ingroup init + */ +GLFWAPI const char* glfwGetVersionString(void); + +/*! @brief Sets the error callback. + * + * This function sets the error callback, which is called with an error code + * and a human-readable description each time a GLFW error occurs. + * + * The error callback is called on the thread where the error occurred. If you + * are using GLFW from multiple threads, your error callback needs to be + * written accordingly. + * + * Because the description string may have been generated specifically for that + * error, it is not guaranteed to be valid after the callback has returned. If + * you wish to use it after the callback returns, you need to make a copy. + * + * Once set, the error callback remains set even after the library has been + * terminated. + * + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set. + * + * @errors None. + * + * @remark This function may be called before @ref glfwInit. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref error_handling + * + * @since Added in version 3.0. + * + * @ingroup init + */ +GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun); + +/*! @brief Returns the currently connected monitors. + * + * This function returns an array of handles for all currently connected + * monitors. The primary monitor is always first in the returned array. If no + * monitors were found, this function returns `NULL`. + * + * @param[out] count Where to store the number of monitors in the returned + * array. This is set to zero if an error occurred. + * @return An array of monitor handles, or `NULL` if no monitors were found or + * if an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * monitor configuration changes or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_monitors + * @sa @ref monitor_event + * @sa glfwGetPrimaryMonitor + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); + +/*! @brief Returns the primary monitor. + * + * This function returns the primary monitor. This is usually the monitor + * where elements like the task bar or global menu bar are located. + * + * @return The primary monitor, or `NULL` if no monitors were found or if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @remark The primary monitor is always first in the array returned by @ref + * glfwGetMonitors. + * + * @sa @ref monitor_monitors + * @sa glfwGetMonitors + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); + +/*! @brief Returns the position of the monitor's viewport on the virtual screen. + * + * This function returns the position, in screen coordinates, of the upper-left + * corner of the specified monitor. + * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * + * @param[in] monitor The monitor to query. + * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. + * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); + +/*! @brief Returns the physical size of the monitor. + * + * This function returns the size, in millimetres, of the display area of the + * specified monitor. + * + * Some systems do not provide accurate monitor size information, either + * because the monitor + * [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data) + * data is incorrect or because the driver does not report it accurately. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] monitor The monitor to query. + * @param[out] widthMM Where to store the width, in millimetres, of the + * monitor's display area, or `NULL`. + * @param[out] heightMM Where to store the height, in millimetres, of the + * monitor's display area, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @win32 calculates the returned physical size from the + * current resolution and system DPI instead of querying the monitor EDID data. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM); + +/*! @brief Returns the name of the specified monitor. + * + * This function returns a human-readable name, encoded as UTF-8, of the + * specified monitor. The name typically reflects the make and model of the + * monitor and is not guaranteed to be unique among the connected monitors. + * + * @param[in] monitor The monitor to query. + * @return The UTF-8 encoded name of the monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); + +/*! @brief Sets the monitor configuration callback. + * + * This function sets the monitor configuration callback, or removes the + * currently set callback. This is called when a monitor is connected to or + * disconnected from the system. + * + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_event + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun); + +/*! @brief Returns the available video modes for the specified monitor. + * + * This function returns an array of all video modes supported by the specified + * monitor. The returned array is sorted in ascending order, first by color + * bit depth (the sum of all channel depths) and then by resolution area (the + * product of width and height). + * + * @param[in] monitor The monitor to query. + * @param[out] count Where to store the number of video modes in the returned + * array. This is set to zero if an error occurred. + * @return An array of video modes, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected, this function is called again for that monitor or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_modes + * @sa glfwGetVideoMode + * + * @since Added in version 1.0. + * @glfw3 Changed to return an array of modes for a specific monitor. + * + * @ingroup monitor + */ +GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); + +/*! @brief Returns the current mode of the specified monitor. + * + * This function returns the current video mode of the specified monitor. If + * you have created a full screen window for that monitor, the return value + * will depend on whether that window is iconified. + * + * @param[in] monitor The monitor to query. + * @return The current mode of the monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_modes + * @sa glfwGetVideoModes + * + * @since Added in version 3.0. Replaces `glfwGetDesktopMode`. + * + * @ingroup monitor + */ +GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); + +/*! @brief Generates a gamma ramp and sets it for the specified monitor. + * + * This function generates a 256-element gamma ramp from the specified exponent + * and then calls @ref glfwSetGammaRamp with it. The value must be a finite + * number greater than zero. + * + * @param[in] monitor The monitor whose gamma ramp to set. + * @param[in] gamma The desired exponent. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); + +/*! @brief Returns the current gamma ramp for the specified monitor. + * + * This function returns the current gamma ramp of the specified monitor. + * + * @param[in] monitor The monitor to query. + * @return The current gamma ramp, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned structure and its arrays are allocated and + * freed by GLFW. You should not free them yourself. They are valid until the + * specified monitor is disconnected, this function is called again for that + * monitor or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); + +/*! @brief Sets the current gamma ramp for the specified monitor. + * + * This function sets the current gamma ramp for the specified monitor. The + * original gamma ramp for that monitor is saved by GLFW the first time this + * function is called and is restored by @ref glfwTerminate. + * + * @param[in] monitor The monitor whose gamma ramp to set. + * @param[in] ramp The gamma ramp to use. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark Gamma ramp sizes other than 256 are not supported by all platforms + * or graphics hardware. + * + * @remark @win32 The gamma ramp size must be 256. + * + * @pointer_lifetime The specified gamma ramp is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); + +/*! @brief Resets all window hints to their default values. + * + * This function resets all window hints to their + * [default values](@ref window_hints_values). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hints + * @sa glfwWindowHint + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwDefaultWindowHints(void); + +/*! @brief Sets the specified window hint to the desired value. + * + * This function sets hints for the next call to @ref glfwCreateWindow. The + * hints, once set, retain their values until changed by a call to @ref + * glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is + * terminated. + * + * This function does not check whether the specified hint values are valid. + * If you set hints to invalid values this will instead be reported by the next + * call to @ref glfwCreateWindow. + * + * @param[in] hint The [window hint](@ref window_hints) to set. + * @param[in] value The new value of the window hint. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hints + * @sa glfwDefaultWindowHints + * + * @since Added in version 3.0. Replaces `glfwOpenWindowHint`. + * + * @ingroup window + */ +GLFWAPI void glfwWindowHint(int hint, int value); + +/*! @brief Creates a window and its associated context. + * + * This function creates a window and its associated OpenGL or OpenGL ES + * context. Most of the options controlling how the window and its context + * should be created are specified with [window hints](@ref window_hints). + * + * Successful creation does not change which context is current. Before you + * can use the newly created context, you need to + * [make it current](@ref context_current). For information about the `share` + * parameter, see @ref context_sharing. + * + * The created window, framebuffer and context may differ from what you + * requested, as not all parameters and hints are + * [hard constraints](@ref window_hints_hard). This includes the size of the + * window, especially for full screen windows. To query the actual attributes + * of the created window, framebuffer and context, see @ref + * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize. + * + * To create a full screen window, you need to specify the monitor the window + * will cover. If no monitor is specified, the window will be windowed mode. + * Unless you have a way for the user to choose a specific monitor, it is + * recommended that you pick the primary monitor. For more information on how + * to query connected monitors, see @ref monitor_monitors. + * + * For full screen windows, the specified size becomes the resolution of the + * window's _desired video mode_. As long as a full screen window is not + * iconified, the supported video mode most closely matching the desired video + * mode is set for the specified monitor. For more information about full + * screen windows, including the creation of so called _windowed full screen_ + * or _borderless full screen_ windows, see @ref window_windowed_full_screen. + * + * Once you have created the window, you can switch it between windowed and + * full screen mode with @ref glfwSetWindowMonitor. If the window has an + * OpenGL or OpenGL ES context, it will be unaffected. + * + * By default, newly created windows use the placement recommended by the + * window system. To create the window at a specific position, make it + * initially invisible using the [GLFW_VISIBLE](@ref window_hints_wnd) window + * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) + * it. + * + * As long as at least one full screen window is not iconified, the screensaver + * is prohibited from starting. + * + * Window systems put limits on window sizes. Very large or very small window + * dimensions may be overridden by the window system on creation. Check the + * actual [size](@ref window_size) after creation. + * + * The [swap interval](@ref buffer_swap) is not set during window creation and + * the initial value may vary depending on driver settings and defaults. + * + * @param[in] width The desired width, in screen coordinates, of the window. + * This must be greater than zero. + * @param[in] height The desired height, in screen coordinates, of the window. + * This must be greater than zero. + * @param[in] title The initial, UTF-8 encoded window title. + * @param[in] monitor The monitor to use for full screen mode, or `NULL` for + * windowed mode. + * @param[in] share The window whose context to share resources with, or `NULL` + * to not share resources. + * @return The handle of the created window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref + * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @win32 Window creation will fail if the Microsoft GDI software + * OpenGL implementation is the only one available. + * + * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it + * will be set as the initial icon for the window. If no such icon is present, + * the `IDI_WINLOGO` icon will be used instead. To set a different icon, see + * @ref glfwSetWindowIcon. + * + * @remark @win32 The context to share resources with must not be current on + * any other thread. + * + * @remark @osx The GLFW window has no icon, as it is not a document + * window, but the dock icon will be the same as the application bundle's icon. + * For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @remark @osx The first time a window is created the menu bar is populated + * with common commands like Hide, Quit and About. The About entry opens + * a minimal about dialog with information from the application's bundle. The + * menu bar can be disabled with a + * [compile-time option](@ref compile_options_osx). + * + * @remark @osx On OS X 10.10 and later the window frame will not be rendered + * at full resolution on Retina displays unless the `NSHighResolutionCapable` + * key is enabled in the application bundle's `Info.plist`. For more + * information, see + * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) + * in the Mac Developer Library. The GLFW test and example programs use + * a custom `Info.plist` template for this, which can be found as + * `CMake/MacOSXBundleInfo.plist.in` in the source tree. + * + * @remark @x11 Some window managers will not respect the placement of + * initially hidden windows. + * + * @remark @x11 Due to the asynchronous nature of X11, it may take a moment for + * a window to reach its requested state. This means you may not be able to + * query the final size, position or other attributes directly after window + * creation. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_creation + * @sa glfwDestroyWindow + * + * @since Added in version 3.0. Replaces `glfwOpenWindow`. + * + * @ingroup window + */ +GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share); + +/*! @brief Destroys the specified window and its context. + * + * This function destroys the specified window and its context. On calling + * this function, no further callbacks will be called for that window. + * + * If the context of the specified window is current on the main thread, it is + * detached before being destroyed. + * + * @param[in] window The window to destroy. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @note The context of the specified window must not be current on any other + * thread when this function is called. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_creation + * @sa glfwCreateWindow + * + * @since Added in version 3.0. Replaces `glfwCloseWindow`. + * + * @ingroup window + */ +GLFWAPI void glfwDestroyWindow(GLFWwindow* window); + +/*! @brief Checks the close flag of the specified window. + * + * This function returns the value of the close flag of the specified window. + * + * @param[in] window The window to query. + * @return The value of the close flag. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_close + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI int glfwWindowShouldClose(GLFWwindow* window); + +/*! @brief Sets the close flag of the specified window. + * + * This function sets the value of the close flag of the specified window. + * This can be used to override the user's attempt to close the window, or + * to signal that it should be closed. + * + * @param[in] window The window whose flag to change. + * @param[in] value The new value. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_close + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); + +/*! @brief Sets the title of the specified window. + * + * This function sets the window title, encoded as UTF-8, of the specified + * window. + * + * @param[in] window The window whose title to change. + * @param[in] title The UTF-8 encoded window title. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @osx The window title will not be updated until the next time you + * process events. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_title + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); + +/*! @brief Sets the icon for the specified window. + * + * This function sets the icon of the specified window. If passed an array of + * candidate images, those of or closest to the sizes desired by the system are + * selected. If no images are specified, the window reverts to its default + * icon. + * + * The desired image sizes varies depending on platform and system settings. + * The selected images will be rescaled as needed. Good sizes include 16x16, + * 32x32 and 48x48. + * + * @param[in] window The window whose icon to set. + * @param[in] count The number of images in the specified array, or zero to + * revert to the default window icon. + * @param[in] images The images to create the icon from. This is ignored if + * count is zero. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified image data is copied before this function + * returns. + * + * @remark @osx The GLFW window has no icon, as it is not a document + * window, so this function does nothing. The dock icon will be the same as + * the application bundle's icon. For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_icon + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images); + +/*! @brief Retrieves the position of the client area of the specified window. + * + * This function retrieves the position, in screen coordinates, of the + * upper-left corner of the client area of the specified window. + * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * + * @param[in] window The window to query. + * @param[out] xpos Where to store the x-coordinate of the upper-left corner of + * the client area, or `NULL`. + * @param[out] ypos Where to store the y-coordinate of the upper-left corner of + * the client area, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_pos + * @sa glfwSetWindowPos + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); + +/*! @brief Sets the position of the client area of the specified window. + * + * This function sets the position, in screen coordinates, of the upper-left + * corner of the client area of the specified windowed mode window. If the + * window is a full screen window, this function does nothing. + * + * __Do not use this function__ to move an already visible window unless you + * have very good reasons for doing so, as it will confuse and annoy the user. + * + * The window manager may put limits on what positions are allowed. GLFW + * cannot and should not override these limits. + * + * @param[in] window The window to query. + * @param[in] xpos The x-coordinate of the upper-left corner of the client area. + * @param[in] ypos The y-coordinate of the upper-left corner of the client area. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_pos + * @sa glfwGetWindowPos + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); + +/*! @brief Retrieves the size of the client area of the specified window. + * + * This function retrieves the size, in screen coordinates, of the client area + * of the specified window. If you wish to retrieve the size of the + * framebuffer of the window in pixels, see @ref glfwGetFramebufferSize. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] window The window whose size to retrieve. + * @param[out] width Where to store the width, in screen coordinates, of the + * client area, or `NULL`. + * @param[out] height Where to store the height, in screen coordinates, of the + * client area, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * @sa glfwSetWindowSize + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); + +/*! @brief Sets the size limits of the specified window. + * + * This function sets the size limits of the client area of the specified + * window. If the window is full screen, the size limits only take effect + * once it is made windowed. If the window is not resizable, this function + * does nothing. + * + * The size limits are applied immediately to a windowed mode window and may + * cause it to be resized. + * + * The maximum dimensions must be greater than or equal to the minimum + * dimensions and all must be greater than or equal to zero. + * + * @param[in] window The window to set limits for. + * @param[in] minwidth The minimum width, in screen coordinates, of the client + * area, or `GLFW_DONT_CARE`. + * @param[in] minheight The minimum height, in screen coordinates, of the + * client area, or `GLFW_DONT_CARE`. + * @param[in] maxwidth The maximum width, in screen coordinates, of the client + * area, or `GLFW_DONT_CARE`. + * @param[in] maxheight The maximum height, in screen coordinates, of the + * client area, or `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa glfwSetWindowAspectRatio + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); + +/*! @brief Sets the aspect ratio of the specified window. + * + * This function sets the required aspect ratio of the client area of the + * specified window. If the window is full screen, the aspect ratio only takes + * effect once it is made windowed. If the window is not resizable, this + * function does nothing. + * + * The aspect ratio is specified as a numerator and a denominator and both + * values must be greater than zero. For example, the common 16:9 aspect ratio + * is specified as 16 and 9, respectively. + * + * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect + * ratio limit is disabled. + * + * The aspect ratio is applied immediately to a windowed mode window and may + * cause it to be resized. + * + * @param[in] window The window to set limits for. + * @param[in] numer The numerator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * @param[in] denom The denominator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa glfwSetWindowSizeLimits + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); + +/*! @brief Sets the size of the client area of the specified window. + * + * This function sets the size, in screen coordinates, of the client area of + * the specified window. + * + * For full screen windows, this function updates the resolution of its desired + * video mode and switches to the video mode closest to it, without affecting + * the window's context. As the context is unaffected, the bit depths of the + * framebuffer remain unchanged. + * + * If you wish to update the refresh rate of the desired video mode in addition + * to its resolution, see @ref glfwSetWindowMonitor. + * + * The window manager may put limits on what sizes are allowed. GLFW cannot + * and should not override these limits. + * + * @param[in] window The window to resize. + * @param[in] width The desired width, in screen coordinates, of the window + * client area. + * @param[in] height The desired height, in screen coordinates, of the window + * client area. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * @sa glfwGetWindowSize + * @sa glfwSetWindowMonitor + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); + +/*! @brief Retrieves the size of the framebuffer of the specified window. + * + * This function retrieves the size, in pixels, of the framebuffer of the + * specified window. If you wish to retrieve the size of the window in screen + * coordinates, see @ref glfwGetWindowSize. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] window The window whose framebuffer to query. + * @param[out] width Where to store the width, in pixels, of the framebuffer, + * or `NULL`. + * @param[out] height Where to store the height, in pixels, of the framebuffer, + * or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_fbsize + * @sa glfwSetFramebufferSizeCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height); + +/*! @brief Retrieves the size of the frame of the window. + * + * This function retrieves the size, in screen coordinates, of each edge of the + * frame of the specified window. This size includes the title bar, if the + * window has one. The size of the frame may vary depending on the + * [window-related hints](@ref window_hints_wnd) used to create it. + * + * Because this function retrieves the size of each window frame edge and not + * the offset along a particular coordinate axis, the retrieved values will + * always be zero or positive. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] window The window whose frame size to query. + * @param[out] left Where to store the size, in screen coordinates, of the left + * edge of the window frame, or `NULL`. + * @param[out] top Where to store the size, in screen coordinates, of the top + * edge of the window frame, or `NULL`. + * @param[out] right Where to store the size, in screen coordinates, of the + * right edge of the window frame, or `NULL`. + * @param[out] bottom Where to store the size, in screen coordinates, of the + * bottom edge of the window frame, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * + * @since Added in version 3.1. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom); + +/*! @brief Iconifies the specified window. + * + * This function iconifies (minimizes) the specified window if it was + * previously restored. If the window is already iconified, this function does + * nothing. + * + * If the specified window is a full screen window, the original monitor + * resolution is restored until the window is restored. + * + * @param[in] window The window to iconify. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_iconify + * @sa glfwRestoreWindow + * @sa glfwMaximizeWindow + * + * @since Added in version 2.1. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwIconifyWindow(GLFWwindow* window); + +/*! @brief Restores the specified window. + * + * This function restores the specified window if it was previously iconified + * (minimized) or maximized. If the window is already restored, this function + * does nothing. + * + * If the specified window is a full screen window, the resolution chosen for + * the window is restored on the selected monitor. + * + * @param[in] window The window to restore. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_iconify + * @sa glfwIconifyWindow + * @sa glfwMaximizeWindow + * + * @since Added in version 2.1. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwRestoreWindow(GLFWwindow* window); + +/*! @brief Maximizes the specified window. + * + * This function maximizes the specified window if it was previously not + * maximized. If the window is already maximized, this function does nothing. + * + * If the specified window is a full screen window, this function does nothing. + * + * @param[in] window The window to maximize. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_iconify + * @sa glfwIconifyWindow + * @sa glfwRestoreWindow + * + * @since Added in GLFW 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwMaximizeWindow(GLFWwindow* window); + +/*! @brief Makes the specified window visible. + * + * This function makes the specified window visible if it was previously + * hidden. If the window is already visible or is in full screen mode, this + * function does nothing. + * + * @param[in] window The window to make visible. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hide + * @sa glfwHideWindow + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwShowWindow(GLFWwindow* window); + +/*! @brief Hides the specified window. + * + * This function hides the specified window if it was previously visible. If + * the window is already hidden or is in full screen mode, this function does + * nothing. + * + * @param[in] window The window to hide. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hide + * @sa glfwShowWindow + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwHideWindow(GLFWwindow* window); + +/*! @brief Brings the specified window to front and sets input focus. + * + * This function brings the specified window to front and sets input focus. + * The window should already be visible and not iconified. + * + * By default, both windowed and full screen mode windows are focused when + * initially created. Set the [GLFW_FOCUSED](@ref window_hints_wnd) to disable + * this behavior. + * + * __Do not use this function__ to steal focus from other applications unless + * you are certain that is what the user wants. Focus stealing can be + * extremely disruptive. + * + * @param[in] window The window to give input focus. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_focus + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwFocusWindow(GLFWwindow* window); + +/*! @brief Returns the monitor that the window uses for full screen mode. + * + * This function returns the handle of the monitor that the specified window is + * in full screen on. + * + * @param[in] window The window to query. + * @return The monitor, or `NULL` if the window is in windowed mode or an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_monitor + * @sa glfwSetWindowMonitor + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); + +/*! @brief Sets the mode, monitor, video mode and placement of a window. + * + * This function sets the monitor that the window uses for full screen mode or, + * if the monitor is `NULL`, makes it windowed mode. + * + * When setting a monitor, this function updates the width, height and refresh + * rate of the desired video mode and switches to the video mode closest to it. + * The window position is ignored when setting a monitor. + * + * When the monitor is `NULL`, the position, width and height are used to + * place the window client area. The refresh rate is ignored when no monitor + * is specified. + * + * If you only wish to update the resolution of a full screen window or the + * size of a windowed mode window, see @ref glfwSetWindowSize. + * + * When a window transitions from full screen to windowed mode, this function + * restores any previous window settings such as whether it is decorated, + * floating, resizable, has size or aspect ratio limits, etc.. + * + * @param[in] window The window whose monitor, size or video mode to set. + * @param[in] monitor The desired monitor, or `NULL` to set windowed mode. + * @param[in] xpos The desired x-coordinate of the upper-left corner of the + * client area. + * @param[in] ypos The desired y-coordinate of the upper-left corner of the + * client area. + * @param[in] width The desired with, in screen coordinates, of the client area + * or video mode. + * @param[in] height The desired height, in screen coordinates, of the client + * area or video mode. + * @param[in] refreshRate The desired refresh rate, in Hz, of the video mode, + * or `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_monitor + * @sa @ref window_full_screen + * @sa glfwGetWindowMonitor + * @sa glfwSetWindowSize + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); + +/*! @brief Returns an attribute of the specified window. + * + * This function returns the value of an attribute of the specified window or + * its OpenGL or OpenGL ES context. + * + * @param[in] window The window to query. + * @param[in] attrib The [window attribute](@ref window_attribs) whose value to + * return. + * @return The value of the attribute, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @remark Framebuffer related hints are not window attributes. See @ref + * window_attribs_fb for more information. + * + * @remark Zero is a valid value for many window and context related + * attributes so you cannot use a return value of zero as an indication of + * errors. However, this function should not fail as long as it is passed + * valid arguments and the library has been [initialized](@ref intro_init). + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_attribs + * + * @since Added in version 3.0. Replaces `glfwGetWindowParam` and + * `glfwGetGLVersion`. + * + * @ingroup window + */ +GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); + +/*! @brief Sets the user pointer of the specified window. + * + * This function sets the user-defined pointer of the specified window. The + * current value is retained until the window is destroyed. The initial value + * is `NULL`. + * + * @param[in] window The window whose pointer to set. + * @param[in] pointer The new value. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_userptr + * @sa glfwGetWindowUserPointer + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); + +/*! @brief Returns the user pointer of the specified window. + * + * This function returns the current value of the user-defined pointer of the + * specified window. The initial value is `NULL`. + * + * @param[in] window The window whose pointer to return. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_userptr + * @sa glfwSetWindowUserPointer + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); + +/*! @brief Sets the position callback for the specified window. + * + * This function sets the position callback of the specified window, which is + * called when the window is moved. The callback is provided with the screen + * position of the upper-left corner of the client area of the window. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_pos + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun cbfun); + +/*! @brief Sets the size callback for the specified window. + * + * This function sets the size callback of the specified window, which is + * called when the window is resized. The callback is provided with the size, + * in screen coordinates, of the client area of the window. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup window + */ +GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun cbfun); + +/*! @brief Sets the close callback for the specified window. + * + * This function sets the close callback of the specified window, which is + * called when the user attempts to close the window, for example by clicking + * the close widget in the title bar. + * + * The close flag is set before this callback is called, but you can modify it + * at any time with @ref glfwSetWindowShouldClose. + * + * The close callback is not triggered by @ref glfwDestroyWindow. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @osx Selecting Quit from the application menu will trigger the close + * callback for all windows. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_close + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup window + */ +GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun cbfun); + +/*! @brief Sets the refresh callback for the specified window. + * + * This function sets the refresh callback of the specified window, which is + * called when the client area of the window needs to be redrawn, for example + * if the window has been exposed after having been covered by another window. + * + * On compositing window systems such as Aero, Compiz or Aqua, where the window + * contents are saved off-screen, this callback may be called only very + * infrequently or never at all. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_refresh + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup window + */ +GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun cbfun); + +/*! @brief Sets the focus callback for the specified window. + * + * This function sets the focus callback of the specified window, which is + * called when the window gains or loses input focus. + * + * After the focus callback is called for a window that lost input focus, + * synthetic key and mouse button release events will be generated for all such + * that had been pressed. For more information, see @ref glfwSetKeyCallback + * and @ref glfwSetMouseButtonCallback. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_focus + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun cbfun); + +/*! @brief Sets the iconify callback for the specified window. + * + * This function sets the iconification callback of the specified window, which + * is called when the window is iconified or restored. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_iconify + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun cbfun); + +/*! @brief Sets the framebuffer resize callback for the specified window. + * + * This function sets the framebuffer resize callback of the specified window, + * which is called when the framebuffer of the specified window is resized. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_fbsize + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun cbfun); + +/*! @brief Processes all pending events. + * + * This function processes only those events that are already in the event + * queue and then returns immediately. Processing events will cause the window + * and input callbacks associated with those events to be called. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * On some platforms, certain events are sent directly to the application + * without going through the event queue, causing callbacks to be called + * outside of a call to one of the event processing functions. + * + * Event processing is not required for joystick input to work. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events + * @sa glfwWaitEvents + * @sa glfwWaitEventsTimeout + * + * @since Added in version 1.0. + * + * @ingroup window + */ +GLFWAPI void glfwPollEvents(void); + +/*! @brief Waits until events are queued and processes them. + * + * This function puts the calling thread to sleep until at least one event is + * available in the event queue. Once one or more events are available, + * it behaves exactly like @ref glfwPollEvents, i.e. the events in the queue + * are processed and the function then returns immediately. Processing events + * will cause the window and input callbacks associated with those events to be + * called. + * + * Since not all events are associated with callbacks, this function may return + * without a callback having been called even if you are monitoring all + * callbacks. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * On some platforms, certain callbacks may be called outside of a call to one + * of the event processing functions. + * + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. + * + * Event processing is not required for joystick input to work. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events + * @sa glfwPollEvents + * @sa glfwWaitEventsTimeout + * + * @since Added in version 2.5. + * + * @ingroup window + */ +GLFWAPI void glfwWaitEvents(void); + +/*! @brief Waits with timeout until events are queued and processes them. + * + * This function puts the calling thread to sleep until at least one event is + * available in the event queue, or until the specified timeout is reached. If + * one or more events are available, it behaves exactly like @ref + * glfwPollEvents, i.e. the events in the queue are processed and the function + * then returns immediately. Processing events will cause the window and input + * callbacks associated with those events to be called. + * + * The timeout value must be a positive finite number. + * + * Since not all events are associated with callbacks, this function may return + * without a callback having been called even if you are monitoring all + * callbacks. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * On some platforms, certain callbacks may be called outside of a call to one + * of the event processing functions. + * + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. + * + * Event processing is not required for joystick input to work. + * + * @param[in] timeout The maximum amount of time, in seconds, to wait. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events + * @sa glfwPollEvents + * @sa glfwWaitEvents + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwWaitEventsTimeout(double timeout); + +/*! @brief Posts an empty event to the event queue. + * + * This function posts an empty event from the current thread to the event + * queue, causing @ref glfwWaitEvents or @ref glfwWaitEventsTimeout to return. + * + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref events + * @sa glfwWaitEvents + * @sa glfwWaitEventsTimeout + * + * @since Added in version 3.1. + * + * @ingroup window + */ +GLFWAPI void glfwPostEmptyEvent(void); + +/*! @brief Returns the value of an input option for the specified window. + * + * This function returns the value of an input option for the specified window. + * The mode must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * + * @param[in] window The window to query. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa glfwSetInputMode + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); + +/*! @brief Sets an input option for the specified window. + * + * This function sets an input mode option for the specified window. The mode + * must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * + * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor + * modes: + * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. + * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client + * area of the window but does not restrict the cursor from leaving. + * - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual + * and unlimited cursor movement. This is useful for implementing for + * example 3D camera controls. + * + * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to + * enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are + * enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS` + * the next time it is called even if the key had been released before the + * call. This is useful when you are only interested in whether keys have been + * pressed but not when or in which order. + * + * If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either + * `GLFW_TRUE` to enable sticky mouse buttons, or `GLFW_FALSE` to disable it. + * If sticky mouse buttons are enabled, a mouse button press will ensure that + * @ref glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even + * if the mouse button had been released before the call. This is useful when + * you are only interested in whether mouse buttons have been pressed but not + * when or in which order. + * + * @param[in] window The window whose input mode to set. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * @param[in] value The new value of the specified input mode. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa glfwGetInputMode + * + * @since Added in version 3.0. Replaces `glfwEnable` and `glfwDisable`. + * + * @ingroup input + */ +GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); + +/*! @brief Returns the localized name of the specified printable key. + * + * This function returns the localized name of the specified printable key. + * This is intended for displaying key bindings to the user. + * + * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used instead, otherwise + * the scancode is ignored. If a non-printable key or (if the key is + * `GLFW_KEY_UNKNOWN`) a scancode that maps to a non-printable key is + * specified, this function returns `NULL`. + * + * This behavior allows you to pass in the arguments passed to the + * [key callback](@ref input_key) without modification. + * + * The printable keys are: + * - `GLFW_KEY_APOSTROPHE` + * - `GLFW_KEY_COMMA` + * - `GLFW_KEY_MINUS` + * - `GLFW_KEY_PERIOD` + * - `GLFW_KEY_SLASH` + * - `GLFW_KEY_SEMICOLON` + * - `GLFW_KEY_EQUAL` + * - `GLFW_KEY_LEFT_BRACKET` + * - `GLFW_KEY_RIGHT_BRACKET` + * - `GLFW_KEY_BACKSLASH` + * - `GLFW_KEY_WORLD_1` + * - `GLFW_KEY_WORLD_2` + * - `GLFW_KEY_0` to `GLFW_KEY_9` + * - `GLFW_KEY_A` to `GLFW_KEY_Z` + * - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9` + * - `GLFW_KEY_KP_DECIMAL` + * - `GLFW_KEY_KP_DIVIDE` + * - `GLFW_KEY_KP_MULTIPLY` + * - `GLFW_KEY_KP_SUBTRACT` + * - `GLFW_KEY_KP_ADD` + * - `GLFW_KEY_KP_EQUAL` + * + * @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`. + * @param[in] scancode The scancode of the key to query. + * @return The localized name of the key, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref + * glfwGetKeyName, or until the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key_name + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetKeyName(int key, int scancode); + +/*! @brief Returns the last reported state of a keyboard key for the specified + * window. + * + * This function returns the last state reported for the specified key to the + * specified window. The returned state is one of `GLFW_PRESS` or + * `GLFW_RELEASE`. The higher-level action `GLFW_REPEAT` is only reported to + * the key callback. + * + * If the `GLFW_STICKY_KEYS` input mode is enabled, this function returns + * `GLFW_PRESS` the first time you call it for a key that was pressed, even if + * that key has already been released. + * + * The key functions deal with physical keys, with [key tokens](@ref keys) + * named after their use on the standard US keyboard layout. If you want to + * input text, use the Unicode character callback instead. + * + * The [modifier key bit masks](@ref mods) are not key tokens and cannot be + * used with this function. + * + * __Do not use this function__ to implement [text input](@ref input_char). + * + * @param[in] window The desired window. + * @param[in] key The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is + * not a valid key for this function. + * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup input + */ +GLFWAPI int glfwGetKey(GLFWwindow* window, int key); + +/*! @brief Returns the last reported state of a mouse button for the specified + * window. + * + * This function returns the last state reported for the specified mouse button + * to the specified window. The returned state is one of `GLFW_PRESS` or + * `GLFW_RELEASE`. + * + * If the `GLFW_STICKY_MOUSE_BUTTONS` input mode is enabled, this function + * `GLFW_PRESS` the first time you call it for a mouse button that was pressed, + * even if that mouse button has already been released. + * + * @param[in] window The desired window. + * @param[in] button The desired [mouse button](@ref buttons). + * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup input + */ +GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); + +/*! @brief Retrieves the position of the cursor relative to the client area of + * the window. + * + * This function returns the position of the cursor, in screen coordinates, + * relative to the upper-left corner of the client area of the specified + * window. + * + * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor + * position is unbounded and limited only by the minimum and maximum values of + * a `double`. + * + * The coordinate can be converted to their integer equivalents with the + * `floor` function. Casting directly to an integer type works for positive + * coordinates, but fails for negative ones. + * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * + * @param[in] window The desired window. + * @param[out] xpos Where to store the cursor x-coordinate, relative to the + * left edge of the client area, or `NULL`. + * @param[out] ypos Where to store the cursor y-coordinate, relative to the to + * top edge of the client area, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_pos + * @sa glfwSetCursorPos + * + * @since Added in version 3.0. Replaces `glfwGetMousePos`. + * + * @ingroup input + */ +GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); + +/*! @brief Sets the position of the cursor, relative to the client area of the + * window. + * + * This function sets the position, in screen coordinates, of the cursor + * relative to the upper-left corner of the client area of the specified + * window. The window must have input focus. If the window does not have + * input focus when this function is called, it fails silently. + * + * __Do not use this function__ to implement things like camera controls. GLFW + * already provides the `GLFW_CURSOR_DISABLED` cursor mode that hides the + * cursor, transparently re-centers it and provides unconstrained cursor + * motion. See @ref glfwSetInputMode for more information. + * + * If the cursor mode is `GLFW_CURSOR_DISABLED` then the cursor position is + * unconstrained and limited only by the minimum and maximum values of + * a `double`. + * + * @param[in] window The desired window. + * @param[in] xpos The desired x-coordinate, relative to the left edge of the + * client area. + * @param[in] ypos The desired y-coordinate, relative to the top edge of the + * client area. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_pos + * @sa glfwGetCursorPos + * + * @since Added in version 3.0. Replaces `glfwSetMousePos`. + * + * @ingroup input + */ +GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); + +/*! @brief Creates a custom cursor. + * + * Creates a new custom cursor image that can be set for a window with @ref + * glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor. + * Any remaining cursors are destroyed by @ref glfwTerminate. + * + * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight + * bits per channel. They are arranged canonically as packed sequential rows, + * starting from the top-left corner. + * + * The cursor hotspot is specified in pixels, relative to the upper-left corner + * of the cursor image. Like all other coordinate systems in GLFW, the X-axis + * points to the right and the Y-axis points down. + * + * @param[in] image The desired cursor image. + * @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot. + * @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot. + * @return The handle of the created cursor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified image data is copied before this function + * returns. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa glfwDestroyCursor + * @sa glfwCreateStandardCursor + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot); + +/*! @brief Creates a cursor with a standard shape. + * + * Returns a cursor with a [standard shape](@ref shapes), that can be set for + * a window with @ref glfwSetCursor. + * + * @param[in] shape One of the [standard shapes](@ref shapes). + * @return A new cursor ready to use or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa glfwCreateCursor + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape); + +/*! @brief Destroys a cursor. + * + * This function destroys a cursor previously created with @ref + * glfwCreateCursor. Any remaining cursors will be destroyed by @ref + * glfwTerminate. + * + * @param[in] cursor The cursor object to destroy. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa glfwCreateCursor + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor); + +/*! @brief Sets the cursor for the window. + * + * This function sets the cursor image to be used when the cursor is over the + * client area of the specified window. The set cursor will only be visible + * when the [cursor mode](@ref cursor_mode) of the window is + * `GLFW_CURSOR_NORMAL`. + * + * On some platforms, the set cursor may not be visible unless the window also + * has input focus. + * + * @param[in] window The window to set the cursor for. + * @param[in] cursor The cursor to set, or `NULL` to switch back to the default + * arrow cursor. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); + +/*! @brief Sets the key callback. + * + * This function sets the key callback of the specified window, which is called + * when a key is pressed, repeated or released. + * + * The key functions deal with physical keys, with layout independent + * [key tokens](@ref keys) named after their values in the standard US keyboard + * layout. If you want to input text, use the + * [character callback](@ref glfwSetCharCallback) instead. + * + * When a window loses input focus, it will generate synthetic key release + * events for all pressed keys. You can tell these events from user-generated + * events by the fact that the synthetic ones are generated after the focus + * loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. + * + * The scancode of a key is specific to that platform or sometimes even to that + * machine. Scancodes are intended to allow users to bind keys that don't have + * a GLFW key token. Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their + * state is not saved and so it cannot be queried with @ref glfwGetKey. + * + * Sometimes GLFW needs to generate synthetic key events, in which case the + * scancode may be zero. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new key callback, or `NULL` to remove the currently + * set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup input + */ +GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); + +/*! @brief Sets the Unicode character callback. + * + * This function sets the character callback of the specified window, which is + * called when a Unicode character is input. + * + * The character callback is intended for Unicode text input. As it deals with + * characters, it is keyboard layout dependent, whereas the + * [key callback](@ref glfwSetKeyCallback) is not. Characters do not map 1:1 + * to physical keys, as a key may produce zero, one or more characters. If you + * want to know whether a specific physical key was pressed or released, see + * the key callback instead. + * + * The character callback behaves as system text input normally does and will + * not be called if modifier keys are held down that would prevent normal text + * input on that platform, for example a Super (Command) key on OS X or Alt key + * on Windows. There is a + * [character with modifiers callback](@ref glfwSetCharModsCallback) that + * receives these events. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_char + * + * @since Added in version 2.4. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup input + */ +GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); + +/*! @brief Sets the Unicode character with modifiers callback. + * + * This function sets the character with modifiers callback of the specified + * window, which is called when a Unicode character is input regardless of what + * modifier keys are used. + * + * The character with modifiers callback is intended for implementing custom + * Unicode character input. For regular Unicode text input, see the + * [character callback](@ref glfwSetCharCallback). Like the character + * callback, the character with modifiers callback deals with characters and is + * keyboard layout dependent. Characters do not map 1:1 to physical keys, as + * a key may produce zero, one or more characters. If you want to know whether + * a specific physical key was pressed or released, see the + * [key callback](@ref glfwSetKeyCallback) instead. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_char + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun cbfun); + +/*! @brief Sets the mouse button callback. + * + * This function sets the mouse button callback of the specified window, which + * is called when a mouse button is pressed or released. + * + * When a window loses input focus, it will generate synthetic mouse button + * release events for all pressed mouse buttons. You can tell these events + * from user-generated events by the fact that the synthetic ones are generated + * after the focus loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup input + */ +GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun cbfun); + +/*! @brief Sets the cursor position callback. + * + * This function sets the cursor position callback of the specified window, + * which is called when the cursor is moved. The callback is provided with the + * position, in screen coordinates, relative to the upper-left corner of the + * client area of the window. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_pos + * + * @since Added in version 3.0. Replaces `glfwSetMousePosCallback`. + * + * @ingroup input + */ +GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun cbfun); + +/*! @brief Sets the cursor enter/exit callback. + * + * This function sets the cursor boundary crossing callback of the specified + * window, which is called when the cursor enters or leaves the client area of + * the window. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_enter + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcursorenterfun cbfun); + +/*! @brief Sets the scroll callback. + * + * This function sets the scroll callback of the specified window, which is + * called when a scrolling device is used, such as a mouse wheel or scrolling + * area of a touchpad. + * + * The scroll callback receives all scrolling input, like that from a mouse + * wheel or a touchpad scrolling area. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new scroll callback, or `NULL` to remove the currently + * set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref scrolling + * + * @since Added in version 3.0. Replaces `glfwSetMouseWheelCallback`. + * + * @ingroup input + */ +GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun); + +/*! @brief Sets the file drop callback. + * + * This function sets the file drop callback of the specified window, which is + * called when one or more dragged files are dropped on the window. + * + * Because the path array and its strings may have been generated specifically + * for that event, they are not guaranteed to be valid after the callback has + * returned. If you wish to use them after the callback returns, you need to + * make a deep copy. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new file drop callback, or `NULL` to remove the + * currently set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref path_drop + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun); + +/*! @brief Returns whether the specified joystick is present. + * + * This function returns whether the specified joystick is present. + * + * @param[in] joy The [joystick](@ref joysticks) to query. + * @return `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick + * + * @since Added in version 3.0. Replaces `glfwGetJoystickParam`. + * + * @ingroup input + */ +GLFWAPI int glfwJoystickPresent(int joy); + +/*! @brief Returns the values of all axes of the specified joystick. + * + * This function returns the values of all axes of the specified joystick. + * Each element in the array is a value between -1.0 and 1.0. + * + * Querying a joystick slot with no device present is not an error, but will + * cause this function to return `NULL`. Call @ref glfwJoystickPresent to + * check device presence. + * + * @param[in] joy The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of axis values in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * @return An array of axis values, or `NULL` if the joystick is not present or + * an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_axis + * + * @since Added in version 3.0. Replaces `glfwGetJoystickPos`. + * + * @ingroup input + */ +GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count); + +/*! @brief Returns the state of all buttons of the specified joystick. + * + * This function returns the state of all buttons of the specified joystick. + * Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`. + * + * Querying a joystick slot with no device present is not an error, but will + * cause this function to return `NULL`. Call @ref glfwJoystickPresent to + * check device presence. + * + * @param[in] joy The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of button states in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * @return An array of button states, or `NULL` if the joystick is not present + * or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_button + * + * @since Added in version 2.2. + * @glfw3 Changed to return a dynamic array. + * + * @ingroup input + */ +GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count); + +/*! @brief Returns the name of the specified joystick. + * + * This function returns the name, encoded as UTF-8, of the specified joystick. + * The returned string is allocated and freed by GLFW. You should not free it + * yourself. + * + * Querying a joystick slot with no device present is not an error, but will + * cause this function to return `NULL`. Call @ref glfwJoystickPresent to + * check device presence. + * + * @param[in] joy The [joystick](@ref joysticks) to query. + * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick + * is not present or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_name + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetJoystickName(int joy); + +/*! @brief Sets the joystick configuration callback. + * + * This function sets the joystick configuration callback, or removes the + * currently set callback. This is called when a joystick is connected to or + * disconnected from the system. + * + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_event + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun); + +/*! @brief Sets the clipboard to the specified string. + * + * This function sets the system clipboard to the specified, UTF-8 encoded + * string. + * + * @param[in] window The window that will own the clipboard contents. + * @param[in] string A UTF-8 encoded string. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified string is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref clipboard + * @sa glfwGetClipboardString + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); + +/*! @brief Returns the contents of the clipboard as a string. + * + * This function returns the contents of the system clipboard, if it contains + * or is convertible to a UTF-8 encoded string. If the clipboard is empty or + * if its contents cannot be converted, `NULL` is returned and a @ref + * GLFW_FORMAT_UNAVAILABLE error is generated. + * + * @param[in] window The window that will request the clipboard contents. + * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` + * if an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref + * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref clipboard + * @sa glfwSetClipboardString + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); + +/*! @brief Returns the value of the GLFW timer. + * + * This function returns the value of the GLFW timer. Unless the timer has + * been set using @ref glfwSetTime, the timer measures time elapsed since GLFW + * was initialized. + * + * The resolution of the timer is system dependent, but is usually on the order + * of a few micro- or nanoseconds. It uses the highest-resolution monotonic + * time source on each supported platform. + * + * @return The current value, in seconds, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Reading and + * writing of the internal timer offset is not atomic, so it needs to be + * externally synchronized with calls to @ref glfwSetTime. + * + * @sa @ref time + * + * @since Added in version 1.0. + * + * @ingroup input + */ +GLFWAPI double glfwGetTime(void); + +/*! @brief Sets the GLFW timer. + * + * This function sets the value of the GLFW timer. It then continues to count + * up from that value. The value must be a positive finite number less than + * or equal to 18446744073.0, which is approximately 584.5 years. + * + * @param[in] time The new value, in seconds. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @remark The upper limit of the timer is calculated as + * floor((264 - 1) / 109) and is due to implementations + * storing nanoseconds in 64 bits. The limit may be increased in the future. + * + * @thread_safety This function may be called from any thread. Reading and + * writing of the internal timer offset is not atomic, so it needs to be + * externally synchronized with calls to @ref glfwGetTime. + * + * @sa @ref time + * + * @since Added in version 2.2. + * + * @ingroup input + */ +GLFWAPI void glfwSetTime(double time); + +/*! @brief Returns the current value of the raw timer. + * + * This function returns the current value of the raw timer, measured in + * 1 / frequency seconds. To get the frequency, call @ref + * glfwGetTimerFrequency. + * + * @return The value of the timer, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa glfwGetTimerFrequency + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI uint64_t glfwGetTimerValue(void); + +/*! @brief Returns the frequency, in Hz, of the raw timer. + * + * This function returns the frequency, in Hz, of the raw timer. + * + * @return The frequency of the timer, in Hz, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa glfwGetTimerValue + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI uint64_t glfwGetTimerFrequency(void); + +/*! @brief Makes the context of the specified window current for the calling + * thread. + * + * This function makes the OpenGL or OpenGL ES context of the specified window + * current on the calling thread. A context can only be made current on + * a single thread at a time and each thread can have only a single current + * context at a time. + * + * By default, making a context non-current implicitly forces a pipeline flush. + * On machines that support `GL_KHR_context_flush_control`, you can control + * whether a context performs this flush by setting the + * [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref window_hints_ctx) window hint. + * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. + * + * @param[in] window The window whose context to make current, or `NULL` to + * detach the current context. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_current + * @sa glfwGetCurrentContext + * + * @since Added in version 3.0. + * + * @ingroup context + */ +GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window); + +/*! @brief Returns the window whose context is current on the calling thread. + * + * This function returns the window whose OpenGL or OpenGL ES context is + * current on the calling thread. + * + * @return The window whose context is current, or `NULL` if no window's + * context is current. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_current + * @sa glfwMakeContextCurrent + * + * @since Added in version 3.0. + * + * @ingroup context + */ +GLFWAPI GLFWwindow* glfwGetCurrentContext(void); + +/*! @brief Swaps the front and back buffers of the specified window. + * + * This function swaps the front and back buffers of the specified window when + * rendering with OpenGL or OpenGL ES. If the swap interval is greater than + * zero, the GPU driver waits the specified number of screen updates before + * swapping the buffers. + * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see `vkQueuePresentKHR` instead. + * + * @param[in] window The window whose buffers to swap. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark __EGL:__ The context of the specified window must be current on the + * calling thread. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref buffer_swap + * @sa glfwSwapInterval + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwSwapBuffers(GLFWwindow* window); + +/*! @brief Sets the swap interval for the current context. + * + * This function sets the swap interval for the current OpenGL or OpenGL ES + * context, i.e. the number of screen updates to wait from the time @ref + * glfwSwapBuffers was called before swapping the buffers and returning. This + * is sometimes called _vertical synchronization_, _vertical retrace + * synchronization_ or just _vsync_. + * + * Contexts that support either of the `WGL_EXT_swap_control_tear` and + * `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals, + * which allow the driver to swap even if a frame arrives a little bit late. + * You can check for the presence of these extensions using @ref + * glfwExtensionSupported. For more information about swap tearing, see the + * extension specifications. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see the present mode of your swapchain instead. + * + * @param[in] interval The minimum number of screen updates to wait for + * until the buffers are swapped by @ref glfwSwapBuffers. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark This function is not called during context creation, leaving the + * swap interval set to whatever is the default on that platform. This is done + * because some swap interval extensions used by GLFW do not allow the swap + * interval to be reset to zero once it has been set to a non-zero value. + * + * @remark Some GPU drivers do not honor the requested swap interval, either + * because of a user setting that overrides the application's request or due to + * bugs in the driver. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref buffer_swap + * @sa glfwSwapBuffers + * + * @since Added in version 1.0. + * + * @ingroup context + */ +GLFWAPI void glfwSwapInterval(int interval); + +/*! @brief Returns whether the specified extension is available. + * + * This function returns whether the specified + * [API extension](@ref context_glext) is supported by the current OpenGL or + * OpenGL ES context. It searches both for client API extension and context + * creation API extensions. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * As this functions retrieves and searches one or more extension strings each + * call, it is recommended that you cache its results if it is going to be used + * frequently. The extension strings will not change during the lifetime of + * a context, so there is no danger in doing this. + * + * This function does not apply to Vulkan. If you are using Vulkan, see @ref + * glfwGetRequiredInstanceExtensions, `vkEnumerateInstanceExtensionProperties` + * and `vkEnumerateDeviceExtensionProperties` instead. + * + * @param[in] extension The ASCII encoded name of the extension. + * @return `GLFW_TRUE` if the extension is available, or `GLFW_FALSE` + * otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT, @ref GLFW_INVALID_VALUE and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_glext + * @sa glfwGetProcAddress + * + * @since Added in version 1.0. + * + * @ingroup context + */ +GLFWAPI int glfwExtensionSupported(const char* extension); + +/*! @brief Returns the address of the specified function for the current + * context. + * + * This function returns the address of the specified OpenGL or OpenGL ES + * [core or extension function](@ref context_glext), if it is supported + * by the current context. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see @ref glfwGetInstanceProcAddress, `vkGetInstanceProcAddr` and + * `vkGetDeviceProcAddr` instead. + * + * @param[in] procname The ASCII encoded name of the function. + * @return The address of the function, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark The address of a given function is not guaranteed to be the same + * between contexts. + * + * @remark This function may return a non-`NULL` address despite the + * associated version or extension not being available. Always check the + * context version or extension string first. + * + * @pointer_lifetime The returned function pointer is valid until the context + * is destroyed or the library is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_glext + * @sa glfwExtensionSupported + * + * @since Added in version 1.0. + * + * @ingroup context + */ +GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname); + +/*! @brief Returns whether the Vulkan loader has been found. + * + * This function returns whether the Vulkan loader has been found. This check + * is performed by @ref glfwInit. + * + * The availability of a Vulkan loader does not by itself guarantee that window + * surface creation or even device creation is possible. Call @ref + * glfwGetRequiredInstanceExtensions to check whether the extensions necessary + * for Vulkan surface creation are available and @ref + * glfwGetPhysicalDevicePresentationSupport to check whether a queue family of + * a physical device supports image presentation. + * + * @return `GLFW_TRUE` if Vulkan is available, or `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_support + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI int glfwVulkanSupported(void); + +/*! @brief Returns the Vulkan instance extensions required by GLFW. + * + * This function returns an array of names of Vulkan instance extensions required + * by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the + * list will always contains `VK_KHR_surface`, so if you don't require any + * additional extensions you can pass this list directly to the + * `VkInstanceCreateInfo` struct. + * + * If Vulkan is not available on the machine, this function returns `NULL` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is available. + * + * If Vulkan is available but no set of extensions allowing window surface + * creation was found, this function returns `NULL`. You may still use Vulkan + * for off-screen rendering and compute work. + * + * @param[out] count Where to store the number of extensions in the returned + * array. This is set to zero if an error occurred. + * @return An array of ASCII encoded extension names, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * @remarks Additional extensions may be required by future versions of GLFW. + * You should check if any extensions you wish to enable are already in the + * returned array, as it is an error to specify an extension more than once in + * the `VkInstanceCreateInfo` struct. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * library is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_ext + * @sa glfwCreateWindowSurface + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count); + +#if defined(VK_VERSION_1_0) + +/*! @brief Returns the address of the specified Vulkan instance function. + * + * This function returns the address of the specified Vulkan core or extension + * function for the specified instance. If instance is set to `NULL` it can + * return any function exported from the Vulkan loader, including at least the + * following functions: + * + * - `vkEnumerateInstanceExtensionProperties` + * - `vkEnumerateInstanceLayerProperties` + * - `vkCreateInstance` + * - `vkGetInstanceProcAddr` + * + * If Vulkan is not available on the machine, this function returns `NULL` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is available. + * + * This function is equivalent to calling `vkGetInstanceProcAddr` with + * a platform-specific query of the Vulkan loader as a fallback. + * + * @param[in] instance The Vulkan instance to query, or `NULL` to retrieve + * functions related to instance creation. + * @param[in] procname The ASCII encoded name of the function. + * @return The address of the function, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * @pointer_lifetime The returned function pointer is valid until the library + * is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_proc + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* procname); + +/*! @brief Returns whether the specified queue family can present images. + * + * This function returns whether the specified queue family of the specified + * physical device supports presentation to the platform GLFW was built for. + * + * If Vulkan or the required window surface creation instance extensions are + * not available on the machine, or if the specified instance was not created + * with the required extensions, this function returns `GLFW_FALSE` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is available and @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * @param[in] instance The instance that the physical device belongs to. + * @param[in] device The physical device that the queue family belongs to. + * @param[in] queuefamily The index of the queue family to query. + * @return `GLFW_TRUE` if the queue family supports presentation, or + * `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_present + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); + +/*! @brief Creates a Vulkan surface for the specified window. + * + * This function creates a Vulkan surface for the specified window. + * + * If the Vulkan loader was not found at initialization, this function returns + * `VK_ERROR_INITIALIZATION_FAILED` and generates a @ref GLFW_API_UNAVAILABLE + * error. Call @ref glfwVulkanSupported to check whether the Vulkan loader was + * found. + * + * If the required window surface creation instance extensions are not + * available or if the specified instance was not created with these extensions + * enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * The window surface must be destroyed before the specified Vulkan instance. + * It is the responsibility of the caller to destroy the window surface. GLFW + * does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the + * surface. + * + * @param[in] instance The Vulkan instance to create the surface in. + * @param[in] window The window to create the surface for. + * @param[in] allocator The allocator to use, or `NULL` to use the default + * allocator. + * @param[out] surface Where to store the handle of the surface. This is set + * to `VK_NULL_HANDLE` if an error occurred. + * @return `VK_SUCCESS` if successful, or a Vulkan error code if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * + * @remarks If an error occurs before the creation call is made, GLFW returns + * the Vulkan error code most appropriate for the error. Appropriate use of + * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should + * eliminate almost all occurrences of these errors. + * + * @thread_safety This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_surface + * @sa glfwGetRequiredInstanceExtensions + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); + +#endif /*VK_VERSION_1_0*/ + + +/************************************************************************* + * Global definition cleanup + *************************************************************************/ + +/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ + +#ifdef GLFW_WINGDIAPI_DEFINED + #undef WINGDIAPI + #undef GLFW_WINGDIAPI_DEFINED +#endif + +#ifdef GLFW_CALLBACK_DEFINED + #undef CALLBACK + #undef GLFW_CALLBACK_DEFINED +#endif + +/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ + + +#ifdef __cplusplus +} +#endif + +#endif /* _glfw3_h_ */ + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/include/GLFW/glfw3native.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/include/GLFW/glfw3native.h new file mode 100644 index 00000000..30e1a570 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/include/GLFW/glfw3native.h @@ -0,0 +1,456 @@ +/************************************************************************* + * GLFW 3.2 - www.glfw.org + * A library for OpenGL, window and input + *------------------------------------------------------------------------ + * Copyright (c) 2002-2006 Marcus Geelnard + * Copyright (c) 2006-2016 Camilla Berglund + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + *************************************************************************/ + +#ifndef _glfw3_native_h_ +#define _glfw3_native_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************* + * Doxygen documentation + *************************************************************************/ + +/*! @file glfw3native.h + * @brief The header of the native access functions. + * + * This is the header file of the native access functions. See @ref native for + * more information. + */ +/*! @defgroup native Native access + * + * **By using the native access functions you assert that you know what you're + * doing and how to fix problems caused by using them. If you don't, you + * shouldn't be using them.** + * + * Before the inclusion of @ref glfw3native.h, you may define exactly one + * window system API macro and zero or more context creation API macros. + * + * The chosen backends must match those the library was compiled for. Failure + * to do this will cause a link-time error. + * + * The available window API macros are: + * * `GLFW_EXPOSE_NATIVE_WIN32` + * * `GLFW_EXPOSE_NATIVE_COCOA` + * * `GLFW_EXPOSE_NATIVE_X11` + * * `GLFW_EXPOSE_NATIVE_WAYLAND` + * * `GLFW_EXPOSE_NATIVE_MIR` + * + * The available context API macros are: + * * `GLFW_EXPOSE_NATIVE_WGL` + * * `GLFW_EXPOSE_NATIVE_NSGL` + * * `GLFW_EXPOSE_NATIVE_GLX` + * * `GLFW_EXPOSE_NATIVE_EGL` + * + * These macros select which of the native access functions that are declared + * and which platform-specific headers to include. It is then up your (by + * definition platform-specific) code to handle which of these should be + * defined. + */ + + +/************************************************************************* + * System headers and types + *************************************************************************/ + +#if defined(GLFW_EXPOSE_NATIVE_WIN32) + // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for + // example to allow applications to correctly declare a GL_ARB_debug_output + // callback) but windows.h assumes no one will define APIENTRY before it does + #undef APIENTRY + #include +#elif defined(GLFW_EXPOSE_NATIVE_COCOA) + #include + #if defined(__OBJC__) + #import + #else + typedef void* id; + #endif +#elif defined(GLFW_EXPOSE_NATIVE_X11) + #include + #include +#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) + #include +#elif defined(GLFW_EXPOSE_NATIVE_MIR) + #include +#endif + +#if defined(GLFW_EXPOSE_NATIVE_WGL) + /* WGL is declared by windows.h */ +#endif +#if defined(GLFW_EXPOSE_NATIVE_NSGL) + /* NSGL is declared by Cocoa.h */ +#endif +#if defined(GLFW_EXPOSE_NATIVE_GLX) + #include +#endif +#if defined(GLFW_EXPOSE_NATIVE_EGL) + #include +#endif + + +/************************************************************************* + * Functions + *************************************************************************/ + +#if defined(GLFW_EXPOSE_NATIVE_WIN32) +/*! @brief Returns the adapter device name of the specified monitor. + * + * @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) + * of the specified monitor, or `NULL` if an [error](@ref error_handling) + * occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.1. + * + * @ingroup native + */ +GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); + +/*! @brief Returns the display device name of the specified monitor. + * + * @return The UTF-8 encoded display device name (for example + * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.1. + * + * @ingroup native + */ +GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); + +/*! @brief Returns the `HWND` of the specified window. + * + * @return The `HWND` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_WGL) +/*! @brief Returns the `HGLRC` of the specified window. + * + * @return The `HGLRC` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_COCOA) +/*! @brief Returns the `CGDirectDisplayID` of the specified monitor. + * + * @return The `CGDirectDisplayID` of the specified monitor, or + * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.1. + * + * @ingroup native + */ +GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); + +/*! @brief Returns the `NSWindow` of the specified window. + * + * @return The `NSWindow` of the specified window, or `nil` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_NSGL) +/*! @brief Returns the `NSOpenGLContext` of the specified window. + * + * @return The `NSOpenGLContext` of the specified window, or `nil` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_X11) +/*! @brief Returns the `Display` used by GLFW. + * + * @return The `Display` used by GLFW, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI Display* glfwGetX11Display(void); + +/*! @brief Returns the `RRCrtc` of the specified monitor. + * + * @return The `RRCrtc` of the specified monitor, or `None` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.1. + * + * @ingroup native + */ +GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); + +/*! @brief Returns the `RROutput` of the specified monitor. + * + * @return The `RROutput` of the specified monitor, or `None` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.1. + * + * @ingroup native + */ +GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); + +/*! @brief Returns the `Window` of the specified window. + * + * @return The `Window` of the specified window, or `None` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI Window glfwGetX11Window(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_GLX) +/*! @brief Returns the `GLXContext` of the specified window. + * + * @return The `GLXContext` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); + +/*! @brief Returns the `GLXWindow` of the specified window. + * + * @return The `GLXWindow` of the specified window, or `None` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_WAYLAND) +/*! @brief Returns the `struct wl_display*` used by GLFW. + * + * @return The `struct wl_display*` used by GLFW, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI struct wl_display* glfwGetWaylandDisplay(void); + +/*! @brief Returns the `struct wl_output*` of the specified monitor. + * + * @return The `struct wl_output*` of the specified monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); + +/*! @brief Returns the main `struct wl_surface*` of the specified window. + * + * @return The main `struct wl_surface*` of the specified window, or `NULL` if + * an [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_MIR) +/*! @brief Returns the `MirConnection*` used by GLFW. + * + * @return The `MirConnection*` used by GLFW, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI MirConnection* glfwGetMirDisplay(void); + +/*! @brief Returns the Mir output ID of the specified monitor. + * + * @return The Mir output ID of the specified monitor, or zero if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor); + +/*! @brief Returns the `MirSurface*` of the specified window. + * + * @return The `MirSurface*` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_EGL) +/*! @brief Returns the `EGLDisplay` used by GLFW. + * + * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI EGLDisplay glfwGetEGLDisplay(void); + +/*! @brief Returns the `EGLContext` of the specified window. + * + * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); + +/*! @brief Returns the `EGLSurface` of the specified window. + * + * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _glfw3_native_h_ */ + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/CMakeLists.txt new file mode 100644 index 00000000..5042aba3 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/CMakeLists.txt @@ -0,0 +1,120 @@ + +set(common_HEADERS internal.h + "${GLFW_BINARY_DIR}/src/glfw_config.h" + "${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h" + "${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h") +set(common_SOURCES context.c init.c input.c monitor.c vulkan.c window.c) + +if (_GLFW_COCOA) + set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h cocoa_joystick.h + posix_tls.h nsgl_context.h) + set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_joystick.m + cocoa_monitor.m cocoa_window.m cocoa_time.c posix_tls.c + nsgl_context.m) +elseif (_GLFW_WIN32) + set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h + wgl_context.h egl_context.h) + set(glfw_SOURCES ${common_SOURCES} win32_init.c win32_joystick.c + win32_monitor.c win32_time.c win32_tls.c win32_window.c + wgl_context.c egl_context.c) +elseif (_GLFW_X11) + set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h + linux_joystick.h posix_time.h posix_tls.h glx_context.h + egl_context.h) + set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c + xkb_unicode.c linux_joystick.c posix_time.c posix_tls.c + glx_context.c egl_context.c) +elseif (_GLFW_WAYLAND) + set(glfw_HEADERS ${common_HEADERS} wl_platform.h linux_joystick.h + posix_time.h posix_tls.h xkb_unicode.h egl_context.h) + set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c + linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c + egl_context.c) + + ecm_add_wayland_client_protocol(glfw_SOURCES + PROTOCOL + ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml + BASENAME relative-pointer-unstable-v1) + ecm_add_wayland_client_protocol(glfw_SOURCES + PROTOCOL + ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml + BASENAME pointer-constraints-unstable-v1) +elseif (_GLFW_MIR) + set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h + posix_time.h posix_tls.h xkb_unicode.h egl_context.h) + set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c + linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c + egl_context.c) +endif() + +if (APPLE) + # For some reason, CMake doesn't know about .m + set_source_files_properties(${glfw_SOURCES} PROPERTIES LANGUAGE C) +endif() + +add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS}) +set_target_properties(glfw PROPERTIES + OUTPUT_NAME ${GLFW_LIB_NAME} + VERSION ${GLFW_VERSION} + SOVERSION ${GLFW_VERSION_MAJOR} + POSITION_INDEPENDENT_CODE ON + FOLDER "GLFW3") + +target_compile_definitions(glfw PRIVATE -D_GLFW_USE_CONFIG_H) +target_include_directories(glfw PUBLIC + $ + $/include>) +target_include_directories(glfw PRIVATE + "${GLFW_SOURCE_DIR}/src" + "${GLFW_BINARY_DIR}/src" + ${glfw_INCLUDE_DIRS}) + +# HACK: When building on MinGW, WINVER and UNICODE need to be defined before +# the inclusion of stddef.h (by glfw3.h), which is itself included before +# win32_platform.h. We define them here until a saner solution can be found +# NOTE: MinGW-w64 and Visual C++ do /not/ need this hack. +target_compile_definitions(glfw PRIVATE + "$<$:UNICODE;WINVER=0x0501>") + +# Enable a reasonable set of warnings (no, -Wextra is not reasonable) +target_compile_options(glfw PRIVATE + "$<$:-Wall>" + "$<$:-Wall>") + +if (BUILD_SHARED_LIBS) + if (WIN32) + if (MINGW) + # Remove the lib prefix on the DLL (but not the import library + set_target_properties(glfw PROPERTIES PREFIX "") + + # Add a suffix to the import library to avoid naming conflicts + set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.a") + else() + # Add a suffix to the import library to avoid naming conflicts + set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.lib") + endif() + elseif (APPLE) + # Add -fno-common to work around a bug in Apple's GCC + target_compile_options(glfw PRIVATE "-fno-common") + + set_target_properties(glfw PROPERTIES + INSTALL_NAME_DIR "lib${LIB_SUFFIX}") + elseif (UNIX) + # Hide symbols not explicitly tagged for export from the shared library + target_compile_options(glfw PRIVATE "-fvisibility=hidden") + endif() + + target_compile_definitions(glfw INTERFACE -DGLFW_DLL) + target_link_libraries(glfw PRIVATE ${glfw_LIBRARIES}) +else() + target_link_libraries(glfw INTERFACE ${glfw_LIBRARIES}) +endif() + +if (MSVC) + target_compile_definitions(glfw PRIVATE _CRT_SECURE_NO_WARNINGS) +endif() + +if (GLFW_INSTALL) + install(TARGETS glfw EXPORT glfwTargets DESTINATION lib${LIB_SUFFIX}) +endif() + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_init.m b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_init.m new file mode 100644 index 00000000..f10d638d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_init.m @@ -0,0 +1,398 @@ +//======================================================================== +// GLFW 3.2 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" +#include // For MAXPATHLEN + + +#if defined(_GLFW_USE_CHDIR) + +// Change to our application bundle's resources directory, if present +// +static void changeToResourcesDirectory(void) +{ + char resourcesPath[MAXPATHLEN]; + + CFBundleRef bundle = CFBundleGetMainBundle(); + if (!bundle) + return; + + CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle); + + CFStringRef last = CFURLCopyLastPathComponent(resourcesURL); + if (CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo) + { + CFRelease(last); + CFRelease(resourcesURL); + return; + } + + CFRelease(last); + + if (!CFURLGetFileSystemRepresentation(resourcesURL, + true, + (UInt8*) resourcesPath, + MAXPATHLEN)) + { + CFRelease(resourcesURL); + return; + } + + CFRelease(resourcesURL); + + chdir(resourcesPath); +} + +#endif /* _GLFW_USE_CHDIR */ + +// Create key code translation tables +// +static void createKeyTables(void) +{ + int scancode; + + memset(_glfw.ns.publicKeys, -1, sizeof(_glfw.ns.publicKeys)); + memset(_glfw.ns.nativeKeys, -1, sizeof(_glfw.ns.nativeKeys)); + + _glfw.ns.publicKeys[0x1D] = GLFW_KEY_0; + _glfw.ns.publicKeys[0x12] = GLFW_KEY_1; + _glfw.ns.publicKeys[0x13] = GLFW_KEY_2; + _glfw.ns.publicKeys[0x14] = GLFW_KEY_3; + _glfw.ns.publicKeys[0x15] = GLFW_KEY_4; + _glfw.ns.publicKeys[0x17] = GLFW_KEY_5; + _glfw.ns.publicKeys[0x16] = GLFW_KEY_6; + _glfw.ns.publicKeys[0x1A] = GLFW_KEY_7; + _glfw.ns.publicKeys[0x1C] = GLFW_KEY_8; + _glfw.ns.publicKeys[0x19] = GLFW_KEY_9; + _glfw.ns.publicKeys[0x00] = GLFW_KEY_A; + _glfw.ns.publicKeys[0x0B] = GLFW_KEY_B; + _glfw.ns.publicKeys[0x08] = GLFW_KEY_C; + _glfw.ns.publicKeys[0x02] = GLFW_KEY_D; + _glfw.ns.publicKeys[0x0E] = GLFW_KEY_E; + _glfw.ns.publicKeys[0x03] = GLFW_KEY_F; + _glfw.ns.publicKeys[0x05] = GLFW_KEY_G; + _glfw.ns.publicKeys[0x04] = GLFW_KEY_H; + _glfw.ns.publicKeys[0x22] = GLFW_KEY_I; + _glfw.ns.publicKeys[0x26] = GLFW_KEY_J; + _glfw.ns.publicKeys[0x28] = GLFW_KEY_K; + _glfw.ns.publicKeys[0x25] = GLFW_KEY_L; + _glfw.ns.publicKeys[0x2E] = GLFW_KEY_M; + _glfw.ns.publicKeys[0x2D] = GLFW_KEY_N; + _glfw.ns.publicKeys[0x1F] = GLFW_KEY_O; + _glfw.ns.publicKeys[0x23] = GLFW_KEY_P; + _glfw.ns.publicKeys[0x0C] = GLFW_KEY_Q; + _glfw.ns.publicKeys[0x0F] = GLFW_KEY_R; + _glfw.ns.publicKeys[0x01] = GLFW_KEY_S; + _glfw.ns.publicKeys[0x11] = GLFW_KEY_T; + _glfw.ns.publicKeys[0x20] = GLFW_KEY_U; + _glfw.ns.publicKeys[0x09] = GLFW_KEY_V; + _glfw.ns.publicKeys[0x0D] = GLFW_KEY_W; + _glfw.ns.publicKeys[0x07] = GLFW_KEY_X; + _glfw.ns.publicKeys[0x10] = GLFW_KEY_Y; + _glfw.ns.publicKeys[0x06] = GLFW_KEY_Z; + + _glfw.ns.publicKeys[0x27] = GLFW_KEY_APOSTROPHE; + _glfw.ns.publicKeys[0x2A] = GLFW_KEY_BACKSLASH; + _glfw.ns.publicKeys[0x2B] = GLFW_KEY_COMMA; + _glfw.ns.publicKeys[0x18] = GLFW_KEY_EQUAL; + _glfw.ns.publicKeys[0x32] = GLFW_KEY_GRAVE_ACCENT; + _glfw.ns.publicKeys[0x21] = GLFW_KEY_LEFT_BRACKET; + _glfw.ns.publicKeys[0x1B] = GLFW_KEY_MINUS; + _glfw.ns.publicKeys[0x2F] = GLFW_KEY_PERIOD; + _glfw.ns.publicKeys[0x1E] = GLFW_KEY_RIGHT_BRACKET; + _glfw.ns.publicKeys[0x29] = GLFW_KEY_SEMICOLON; + _glfw.ns.publicKeys[0x2C] = GLFW_KEY_SLASH; + _glfw.ns.publicKeys[0x0A] = GLFW_KEY_WORLD_1; + + _glfw.ns.publicKeys[0x33] = GLFW_KEY_BACKSPACE; + _glfw.ns.publicKeys[0x39] = GLFW_KEY_CAPS_LOCK; + _glfw.ns.publicKeys[0x75] = GLFW_KEY_DELETE; + _glfw.ns.publicKeys[0x7D] = GLFW_KEY_DOWN; + _glfw.ns.publicKeys[0x77] = GLFW_KEY_END; + _glfw.ns.publicKeys[0x24] = GLFW_KEY_ENTER; + _glfw.ns.publicKeys[0x35] = GLFW_KEY_ESCAPE; + _glfw.ns.publicKeys[0x7A] = GLFW_KEY_F1; + _glfw.ns.publicKeys[0x78] = GLFW_KEY_F2; + _glfw.ns.publicKeys[0x63] = GLFW_KEY_F3; + _glfw.ns.publicKeys[0x76] = GLFW_KEY_F4; + _glfw.ns.publicKeys[0x60] = GLFW_KEY_F5; + _glfw.ns.publicKeys[0x61] = GLFW_KEY_F6; + _glfw.ns.publicKeys[0x62] = GLFW_KEY_F7; + _glfw.ns.publicKeys[0x64] = GLFW_KEY_F8; + _glfw.ns.publicKeys[0x65] = GLFW_KEY_F9; + _glfw.ns.publicKeys[0x6D] = GLFW_KEY_F10; + _glfw.ns.publicKeys[0x67] = GLFW_KEY_F11; + _glfw.ns.publicKeys[0x6F] = GLFW_KEY_F12; + _glfw.ns.publicKeys[0x69] = GLFW_KEY_F13; + _glfw.ns.publicKeys[0x6B] = GLFW_KEY_F14; + _glfw.ns.publicKeys[0x71] = GLFW_KEY_F15; + _glfw.ns.publicKeys[0x6A] = GLFW_KEY_F16; + _glfw.ns.publicKeys[0x40] = GLFW_KEY_F17; + _glfw.ns.publicKeys[0x4F] = GLFW_KEY_F18; + _glfw.ns.publicKeys[0x50] = GLFW_KEY_F19; + _glfw.ns.publicKeys[0x5A] = GLFW_KEY_F20; + _glfw.ns.publicKeys[0x73] = GLFW_KEY_HOME; + _glfw.ns.publicKeys[0x72] = GLFW_KEY_INSERT; + _glfw.ns.publicKeys[0x7B] = GLFW_KEY_LEFT; + _glfw.ns.publicKeys[0x3A] = GLFW_KEY_LEFT_ALT; + _glfw.ns.publicKeys[0x3B] = GLFW_KEY_LEFT_CONTROL; + _glfw.ns.publicKeys[0x38] = GLFW_KEY_LEFT_SHIFT; + _glfw.ns.publicKeys[0x37] = GLFW_KEY_LEFT_SUPER; + _glfw.ns.publicKeys[0x6E] = GLFW_KEY_MENU; + _glfw.ns.publicKeys[0x47] = GLFW_KEY_NUM_LOCK; + _glfw.ns.publicKeys[0x79] = GLFW_KEY_PAGE_DOWN; + _glfw.ns.publicKeys[0x74] = GLFW_KEY_PAGE_UP; + _glfw.ns.publicKeys[0x7C] = GLFW_KEY_RIGHT; + _glfw.ns.publicKeys[0x3D] = GLFW_KEY_RIGHT_ALT; + _glfw.ns.publicKeys[0x3E] = GLFW_KEY_RIGHT_CONTROL; + _glfw.ns.publicKeys[0x3C] = GLFW_KEY_RIGHT_SHIFT; + _glfw.ns.publicKeys[0x36] = GLFW_KEY_RIGHT_SUPER; + _glfw.ns.publicKeys[0x31] = GLFW_KEY_SPACE; + _glfw.ns.publicKeys[0x30] = GLFW_KEY_TAB; + _glfw.ns.publicKeys[0x7E] = GLFW_KEY_UP; + + _glfw.ns.publicKeys[0x52] = GLFW_KEY_KP_0; + _glfw.ns.publicKeys[0x53] = GLFW_KEY_KP_1; + _glfw.ns.publicKeys[0x54] = GLFW_KEY_KP_2; + _glfw.ns.publicKeys[0x55] = GLFW_KEY_KP_3; + _glfw.ns.publicKeys[0x56] = GLFW_KEY_KP_4; + _glfw.ns.publicKeys[0x57] = GLFW_KEY_KP_5; + _glfw.ns.publicKeys[0x58] = GLFW_KEY_KP_6; + _glfw.ns.publicKeys[0x59] = GLFW_KEY_KP_7; + _glfw.ns.publicKeys[0x5B] = GLFW_KEY_KP_8; + _glfw.ns.publicKeys[0x5C] = GLFW_KEY_KP_9; + _glfw.ns.publicKeys[0x45] = GLFW_KEY_KP_ADD; + _glfw.ns.publicKeys[0x41] = GLFW_KEY_KP_DECIMAL; + _glfw.ns.publicKeys[0x4B] = GLFW_KEY_KP_DIVIDE; + _glfw.ns.publicKeys[0x4C] = GLFW_KEY_KP_ENTER; + _glfw.ns.publicKeys[0x51] = GLFW_KEY_KP_EQUAL; + _glfw.ns.publicKeys[0x43] = GLFW_KEY_KP_MULTIPLY; + _glfw.ns.publicKeys[0x4E] = GLFW_KEY_KP_SUBTRACT; + + for (scancode = 0; scancode < 256; scancode++) + { + // Store the reverse translation for faster key name lookup + if (_glfw.ns.publicKeys[scancode] >= 0) + _glfw.ns.nativeKeys[_glfw.ns.publicKeys[scancode]] = scancode; + } +} + +// Retrieve Unicode data for the current keyboard layout +// +static GLFWbool updateUnicodeDataNS(void) +{ + if (_glfw.ns.inputSource) + { + CFRelease(_glfw.ns.inputSource); + _glfw.ns.inputSource = NULL; + _glfw.ns.unicodeData = nil; + } + + _glfw.ns.inputSource = TISCopyCurrentKeyboardLayoutInputSource(); + if (!_glfw.ns.inputSource) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to retrieve keyboard layout input source"); + return GLFW_FALSE; + } + + _glfw.ns.unicodeData = TISGetInputSourceProperty(_glfw.ns.inputSource, + kTISPropertyUnicodeKeyLayoutData); + if (!_glfw.ns.unicodeData) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to retrieve keyboard layout Unicode data"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +// Load HIToolbox.framework and the TIS symbols we need from it +// +static GLFWbool initializeTIS(void) +{ + // This works only because Cocoa has already loaded it properly + _glfw.ns.tis.bundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox")); + if (!_glfw.ns.tis.bundle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to load HIToolbox.framework"); + return GLFW_FALSE; + } + + CFStringRef* kPropertyUnicodeKeyLayoutData = + CFBundleGetDataPointerForName(_glfw.ns.tis.bundle, + CFSTR("kTISPropertyUnicodeKeyLayoutData")); + CFStringRef* kNotifySelectedKeyboardInputSourceChanged = + CFBundleGetDataPointerForName(_glfw.ns.tis.bundle, + CFSTR("kTISNotifySelectedKeyboardInputSourceChanged")); + _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource = + CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, + CFSTR("TISCopyCurrentKeyboardLayoutInputSource")); + _glfw.ns.tis.GetInputSourceProperty = + CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, + CFSTR("TISGetInputSourceProperty")); + _glfw.ns.tis.GetKbdType = + CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, + CFSTR("LMGetKbdType")); + + if (!kPropertyUnicodeKeyLayoutData || + !kNotifySelectedKeyboardInputSourceChanged || + !TISCopyCurrentKeyboardLayoutInputSource || + !TISGetInputSourceProperty || + !LMGetKbdType) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to load TIS API symbols"); + return GLFW_FALSE; + } + + _glfw.ns.tis.kPropertyUnicodeKeyLayoutData = + *kPropertyUnicodeKeyLayoutData; + _glfw.ns.tis.kNotifySelectedKeyboardInputSourceChanged = + *kNotifySelectedKeyboardInputSourceChanged; + + return updateUnicodeDataNS(); +} + +@interface GLFWLayoutListener : NSObject +@end + +@implementation GLFWLayoutListener + +- (void)selectedKeyboardInputSourceChanged:(NSObject* )object +{ + updateUnicodeDataNS(); +} + +@end + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; + + _glfw.ns.listener = [[GLFWLayoutListener alloc] init]; + [[NSDistributedNotificationCenter defaultCenter] + addObserver:_glfw.ns.listener + selector:@selector(selectedKeyboardInputSourceChanged:) + name:(__bridge NSString*)kTISNotifySelectedKeyboardInputSourceChanged + object:nil]; + +#if defined(_GLFW_USE_CHDIR) + changeToResourcesDirectory(); +#endif + + createKeyTables(); + + _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); + if (!_glfw.ns.eventSource) + return GLFW_FALSE; + + CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0); + + if (!initializeTIS()) + return GLFW_FALSE; + + if (!_glfwInitThreadLocalStoragePOSIX()) + return GLFW_FALSE; + + _glfwInitTimerNS(); + _glfwInitJoysticksNS(); + + return GLFW_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + if (_glfw.ns.inputSource) + { + CFRelease(_glfw.ns.inputSource); + _glfw.ns.inputSource = NULL; + _glfw.ns.unicodeData = nil; + } + + if (_glfw.ns.eventSource) + { + CFRelease(_glfw.ns.eventSource); + _glfw.ns.eventSource = NULL; + } + + if (_glfw.ns.delegate) + { + [NSApp setDelegate:nil]; + [_glfw.ns.delegate release]; + _glfw.ns.delegate = nil; + } + + if (_glfw.ns.listener) + { + [[NSDistributedNotificationCenter defaultCenter] + removeObserver:_glfw.ns.listener + name:(__bridge NSString*)kTISNotifySelectedKeyboardInputSourceChanged + object:nil]; + [[NSDistributedNotificationCenter defaultCenter] + removeObserver:_glfw.ns.listener]; + [_glfw.ns.listener release]; + _glfw.ns.listener = nil; + } + + [_glfw.ns.cursor release]; + _glfw.ns.cursor = nil; + + free(_glfw.ns.clipboardString); + + _glfwTerminateNSGL(); + _glfwTerminateJoysticksNS(); + _glfwTerminateThreadLocalStoragePOSIX(); + + [_glfw.ns.autoreleasePool release]; + _glfw.ns.autoreleasePool = nil; +} + +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " Cocoa NSGL" +#if defined(_GLFW_USE_CHDIR) + " chdir" +#endif +#if defined(_GLFW_USE_MENUBAR) + " menubar" +#endif +#if defined(_GLFW_USE_RETINA) + " retina" +#endif +#if defined(_GLFW_BUILD_DLL) + " dynamic" +#endif + ; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_joystick.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_joystick.h new file mode 100644 index 00000000..3b806344 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_joystick.h @@ -0,0 +1,60 @@ +//======================================================================== +// GLFW 3.2 Cocoa - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_cocoa_joystick_h_ +#define _glfw3_cocoa_joystick_h_ + +#include +#include +#include +#include + +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \ + _GLFWjoystickNS ns_js[GLFW_JOYSTICK_LAST + 1] + + +// Cocoa-specific per-joystick data +// +typedef struct _GLFWjoystickNS +{ + GLFWbool present; + char name[256]; + + IOHIDDeviceRef deviceRef; + + CFMutableArrayRef axisElements; + CFMutableArrayRef buttonElements; + CFMutableArrayRef hatElements; + + float* axes; + unsigned char* buttons; +} _GLFWjoystickNS; + + +void _glfwInitJoysticksNS(void); +void _glfwTerminateJoysticksNS(void); + +#endif // _glfw3_cocoa_joystick_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_joystick.m b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_joystick.m new file mode 100644 index 00000000..7423e3d7 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_joystick.m @@ -0,0 +1,511 @@ +//======================================================================== +// GLFW 3.2 Cocoa - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Berglund +// Copyright (c) 2012 Torsten Walluhn +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + +#include +#include + +#include +#include + + +// Joystick element information +// +typedef struct _GLFWjoyelementNS +{ + IOHIDElementRef elementRef; + + long min; + long max; + + long minReport; + long maxReport; + +} _GLFWjoyelementNS; + + +static void getElementsCFArrayHandler(const void* value, void* parameter); + +// Adds an element to the specified joystick +// +static void addJoystickElement(_GLFWjoystickNS* js, + IOHIDElementRef elementRef) +{ + IOHIDElementType elementType; + long usagePage, usage; + CFMutableArrayRef elementsArray = NULL; + + elementType = IOHIDElementGetType(elementRef); + usagePage = IOHIDElementGetUsagePage(elementRef); + usage = IOHIDElementGetUsage(elementRef); + + if ((elementType != kIOHIDElementTypeInput_Axis) && + (elementType != kIOHIDElementTypeInput_Button) && + (elementType != kIOHIDElementTypeInput_Misc)) + { + return; + } + + switch (usagePage) + { + case kHIDPage_GenericDesktop: + { + switch (usage) + { + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + case kHIDUsage_GD_Slider: + case kHIDUsage_GD_Dial: + case kHIDUsage_GD_Wheel: + elementsArray = js->axisElements; + break; + case kHIDUsage_GD_Hatswitch: + elementsArray = js->hatElements; + break; + } + + break; + } + + case kHIDPage_Button: + elementsArray = js->buttonElements; + break; + default: + break; + } + + if (elementsArray) + { + _GLFWjoyelementNS* element = calloc(1, sizeof(_GLFWjoyelementNS)); + + CFArrayAppendValue(elementsArray, element); + + element->elementRef = elementRef; + + element->minReport = IOHIDElementGetLogicalMin(elementRef); + element->maxReport = IOHIDElementGetLogicalMax(elementRef); + } +} + +// Adds an element to the specified joystick +// +static void getElementsCFArrayHandler(const void* value, void* parameter) +{ + if (CFGetTypeID(value) == IOHIDElementGetTypeID()) + { + addJoystickElement((_GLFWjoystickNS*) parameter, + (IOHIDElementRef) value); + } +} + +// Returns the value of the specified element of the specified joystick +// +static long getElementValue(_GLFWjoystickNS* js, _GLFWjoyelementNS* element) +{ + IOReturn result = kIOReturnSuccess; + IOHIDValueRef valueRef; + long value = 0; + + if (js && element && js->deviceRef) + { + result = IOHIDDeviceGetValue(js->deviceRef, + element->elementRef, + &valueRef); + + if (kIOReturnSuccess == result) + { + value = IOHIDValueGetIntegerValue(valueRef); + + // Record min and max for auto calibration + if (value < element->minReport) + element->minReport = value; + if (value > element->maxReport) + element->maxReport = value; + } + } + + // Auto user scale + return value; +} + +// Removes the specified joystick +// +static void removeJoystick(_GLFWjoystickNS* js) +{ + int i; + + if (!js->present) + return; + + for (i = 0; i < CFArrayGetCount(js->axisElements); i++) + free((void*) CFArrayGetValueAtIndex(js->axisElements, i)); + CFArrayRemoveAllValues(js->axisElements); + CFRelease(js->axisElements); + + for (i = 0; i < CFArrayGetCount(js->buttonElements); i++) + free((void*) CFArrayGetValueAtIndex(js->buttonElements, i)); + CFArrayRemoveAllValues(js->buttonElements); + CFRelease(js->buttonElements); + + for (i = 0; i < CFArrayGetCount(js->hatElements); i++) + free((void*) CFArrayGetValueAtIndex(js->hatElements, i)); + CFArrayRemoveAllValues(js->hatElements); + CFRelease(js->hatElements); + + free(js->axes); + free(js->buttons); + + memset(js, 0, sizeof(_GLFWjoystickNS)); + + _glfwInputJoystickChange(js - _glfw.ns_js, GLFW_DISCONNECTED); +} + +// Polls for joystick axis events and updates GLFW state +// +static GLFWbool pollJoystickAxisEvents(_GLFWjoystickNS* js) +{ + CFIndex i; + + if (!js->present) + return GLFW_FALSE; + + for (i = 0; i < CFArrayGetCount(js->axisElements); i++) + { + _GLFWjoyelementNS* axis = (_GLFWjoyelementNS*) + CFArrayGetValueAtIndex(js->axisElements, i); + + long value = getElementValue(js, axis); + long readScale = axis->maxReport - axis->minReport; + + if (readScale == 0) + js->axes[i] = value; + else + js->axes[i] = (2.f * (value - axis->minReport) / readScale) - 1.f; + } + + return GLFW_TRUE; +} + +// Polls for joystick button events and updates GLFW state +// +static GLFWbool pollJoystickButtonEvents(_GLFWjoystickNS* js) +{ + CFIndex i; + int buttonIndex = 0; + + if (!js->present) + return GLFW_FALSE; + + for (i = 0; i < CFArrayGetCount(js->buttonElements); i++) + { + _GLFWjoyelementNS* button = (_GLFWjoyelementNS*) + CFArrayGetValueAtIndex(js->buttonElements, i); + + if (getElementValue(js, button)) + js->buttons[buttonIndex++] = GLFW_PRESS; + else + js->buttons[buttonIndex++] = GLFW_RELEASE; + } + + for (i = 0; i < CFArrayGetCount(js->hatElements); i++) + { + _GLFWjoyelementNS* hat = (_GLFWjoyelementNS*) + CFArrayGetValueAtIndex(js->hatElements, i); + + // Bit fields of button presses for each direction, including nil + const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; + + long j, value = getElementValue(js, hat); + if (value < 0 || value > 8) + value = 8; + + for (j = 0; j < 4; j++) + { + if (directions[value] & (1 << j)) + js->buttons[buttonIndex++] = GLFW_PRESS; + else + js->buttons[buttonIndex++] = GLFW_RELEASE; + } + } + + return GLFW_TRUE; +} + +// Callback for user-initiated joystick addition +// +static void matchCallback(void* context, + IOReturn result, + void* sender, + IOHIDDeviceRef deviceRef) +{ + _GLFWjoystickNS* js; + int joy; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (_glfw.ns_js[joy].present && _glfw.ns_js[joy].deviceRef == deviceRef) + return; + } + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (!_glfw.ns_js[joy].present) + break; + } + + if (joy > GLFW_JOYSTICK_LAST) + return; + + js = _glfw.ns_js + joy; + js->present = GLFW_TRUE; + js->deviceRef = deviceRef; + + CFStringRef name = IOHIDDeviceGetProperty(deviceRef, + CFSTR(kIOHIDProductKey)); + if (name) + { + CFStringGetCString(name, + js->name, + sizeof(js->name), + kCFStringEncodingUTF8); + } + else + strncpy(js->name, "Unknown", sizeof(js->name)); + + js->axisElements = CFArrayCreateMutable(NULL, 0, NULL); + js->buttonElements = CFArrayCreateMutable(NULL, 0, NULL); + js->hatElements = CFArrayCreateMutable(NULL, 0, NULL); + + CFArrayRef arrayRef = IOHIDDeviceCopyMatchingElements(deviceRef, + NULL, + kIOHIDOptionsTypeNone); + CFRange range = { 0, CFArrayGetCount(arrayRef) }; + CFArrayApplyFunction(arrayRef, + range, + getElementsCFArrayHandler, + (void*) js); + + CFRelease(arrayRef); + + js->axes = calloc(CFArrayGetCount(js->axisElements), sizeof(float)); + js->buttons = calloc(CFArrayGetCount(js->buttonElements) + + CFArrayGetCount(js->hatElements) * 4, 1); + + _glfwInputJoystickChange(joy, GLFW_CONNECTED); +} + +// Callback for user-initiated joystick removal +// +static void removeCallback(void* context, + IOReturn result, + void* sender, + IOHIDDeviceRef deviceRef) +{ + int joy; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (_glfw.ns_js[joy].deviceRef == deviceRef) + { + removeJoystick(_glfw.ns_js + joy); + break; + } + } +} + +// Creates a dictionary to match against devices with the specified usage page +// and usage +// +static CFMutableDictionaryRef createMatchingDictionary(long usagePage, + long usage) +{ + CFMutableDictionaryRef result = + CFDictionaryCreateMutable(kCFAllocatorDefault, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + if (result) + { + CFNumberRef pageRef = CFNumberCreate(kCFAllocatorDefault, + kCFNumberLongType, + &usagePage); + if (pageRef) + { + CFDictionarySetValue(result, + CFSTR(kIOHIDDeviceUsagePageKey), + pageRef); + CFRelease(pageRef); + + CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault, + kCFNumberLongType, + &usage); + if (usageRef) + { + CFDictionarySetValue(result, + CFSTR(kIOHIDDeviceUsageKey), + usageRef); + CFRelease(usageRef); + } + } + } + + return result; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize joystick interface +// +void _glfwInitJoysticksNS(void) +{ + CFMutableArrayRef matchingCFArrayRef; + + _glfw.ns.hidManager = IOHIDManagerCreate(kCFAllocatorDefault, + kIOHIDOptionsTypeNone); + + matchingCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, + 0, + &kCFTypeArrayCallBacks); + if (matchingCFArrayRef) + { + CFDictionaryRef matchingCFDictRef = + createMatchingDictionary(kHIDPage_GenericDesktop, + kHIDUsage_GD_Joystick); + if (matchingCFDictRef) + { + CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef); + CFRelease(matchingCFDictRef); + } + + matchingCFDictRef = createMatchingDictionary(kHIDPage_GenericDesktop, + kHIDUsage_GD_GamePad); + if (matchingCFDictRef) + { + CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef); + CFRelease(matchingCFDictRef); + } + + matchingCFDictRef = + createMatchingDictionary(kHIDPage_GenericDesktop, + kHIDUsage_GD_MultiAxisController); + if (matchingCFDictRef) + { + CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef); + CFRelease(matchingCFDictRef); + } + + IOHIDManagerSetDeviceMatchingMultiple(_glfw.ns.hidManager, + matchingCFArrayRef); + CFRelease(matchingCFArrayRef); + } + + IOHIDManagerRegisterDeviceMatchingCallback(_glfw.ns.hidManager, + &matchCallback, NULL); + IOHIDManagerRegisterDeviceRemovalCallback(_glfw.ns.hidManager, + &removeCallback, NULL); + + IOHIDManagerScheduleWithRunLoop(_glfw.ns.hidManager, + CFRunLoopGetMain(), + kCFRunLoopDefaultMode); + + IOHIDManagerOpen(_glfw.ns.hidManager, kIOHIDOptionsTypeNone); + + // Execute the run loop once in order to register any initially-attached + // joysticks + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false); +} + +// Close all opened joystick handles +// +void _glfwTerminateJoysticksNS(void) +{ + int joy; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + _GLFWjoystickNS* js = _glfw.ns_js + joy; + removeJoystick(js); + } + + CFRelease(_glfw.ns.hidManager); + _glfw.ns.hidManager = NULL; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformJoystickPresent(int joy) +{ + _GLFWjoystickNS* js = _glfw.ns_js + joy; + return js->present; +} + +const float* _glfwPlatformGetJoystickAxes(int joy, int* count) +{ + _GLFWjoystickNS* js = _glfw.ns_js + joy; + if (!pollJoystickAxisEvents(js)) + return NULL; + + *count = (int) CFArrayGetCount(js->axisElements); + return js->axes; +} + +const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) +{ + _GLFWjoystickNS* js = _glfw.ns_js + joy; + if (!pollJoystickButtonEvents(js)) + return NULL; + + *count = (int) CFArrayGetCount(js->buttonElements) + + (int) CFArrayGetCount(js->hatElements) * 4; + return js->buttons; +} + +const char* _glfwPlatformGetJoystickName(int joy) +{ + _GLFWjoystickNS* js = _glfw.ns_js + joy; + if (!js->present) + return NULL; + + return js->name; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_monitor.m b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_monitor.m new file mode 100644 index 00000000..9ac0a832 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_monitor.m @@ -0,0 +1,413 @@ +//======================================================================== +// GLFW 3.2 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + +#include +#include +#include +#include + + +// Get the name of the specified display +// +static char* getDisplayName(CGDirectDisplayID displayID) +{ + char* name; + CFDictionaryRef info, names; + CFStringRef value; + CFIndex size; + + // NOTE: This uses a deprecated function because Apple has + // (as of January 2015) not provided any alternative + info = IODisplayCreateInfoDictionary(CGDisplayIOServicePort(displayID), + kIODisplayOnlyPreferredName); + names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName)); + + if (!names || !CFDictionaryGetValueIfPresent(names, CFSTR("en_US"), + (const void**) &value)) + { + // This may happen if a desktop Mac is running headless + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to retrieve display name"); + + CFRelease(info); + return strdup("Unknown"); + } + + size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), + kCFStringEncodingUTF8); + name = calloc(size + 1, 1); + CFStringGetCString(value, name, size, kCFStringEncodingUTF8); + + CFRelease(info); + + return name; +} + +// Check whether the display mode should be included in enumeration +// +static GLFWbool modeIsGood(CGDisplayModeRef mode) +{ + uint32_t flags = CGDisplayModeGetIOFlags(mode); + if (!(flags & kDisplayModeValidFlag) || !(flags & kDisplayModeSafeFlag)) + return GLFW_FALSE; + + if (flags & kDisplayModeInterlacedFlag) + return GLFW_FALSE; + + if (flags & kDisplayModeStretchedFlag) + return GLFW_FALSE; + + CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); + if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) && + CFStringCompare(format, CFSTR(IO32BitDirectPixels), 0)) + { + CFRelease(format); + return GLFW_FALSE; + } + + CFRelease(format); + return GLFW_TRUE; +} + +// Convert Core Graphics display mode to GLFW video mode +// +static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode, + CVDisplayLinkRef link) +{ + GLFWvidmode result; + result.width = (int) CGDisplayModeGetWidth(mode); + result.height = (int) CGDisplayModeGetHeight(mode); + result.refreshRate = (int) CGDisplayModeGetRefreshRate(mode); + + if (result.refreshRate == 0) + { + const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link); + if (!(time.flags & kCVTimeIsIndefinite)) + result.refreshRate = (int) (time.timeScale / (double) time.timeValue); + } + + CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); + + if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) == 0) + { + result.redBits = 5; + result.greenBits = 5; + result.blueBits = 5; + } + else + { + result.redBits = 8; + result.greenBits = 8; + result.blueBits = 8; + } + + CFRelease(format); + return result; +} + +// Starts reservation for display fading +// +static CGDisplayFadeReservationToken beginFadeReservation(void) +{ + CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken; + + if (CGAcquireDisplayFadeReservation(5, &token) == kCGErrorSuccess) + CGDisplayFade(token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE); + + return token; +} + +// Ends reservation for display fading +// +static void endFadeReservation(CGDisplayFadeReservationToken token) +{ + if (token != kCGDisplayFadeReservationInvalidToken) + { + CGDisplayFade(token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE); + CGReleaseDisplayFadeReservation(token); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Change the current video mode +// +GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired) +{ + CFArrayRef modes; + CFIndex count, i; + CVDisplayLinkRef link; + CGDisplayModeRef native = NULL; + GLFWvidmode current; + const GLFWvidmode* best; + + best = _glfwChooseVideoMode(monitor, desired); + _glfwPlatformGetVideoMode(monitor, ¤t); + if (_glfwCompareVideoModes(¤t, best) == 0) + return GLFW_TRUE; + + CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); + + modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); + count = CFArrayGetCount(modes); + + for (i = 0; i < count; i++) + { + CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); + if (!modeIsGood(dm)) + continue; + + const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link); + if (_glfwCompareVideoModes(best, &mode) == 0) + { + native = dm; + break; + } + } + + if (native) + { + if (monitor->ns.previousMode == NULL) + monitor->ns.previousMode = CGDisplayCopyDisplayMode(monitor->ns.displayID); + + CGDisplayFadeReservationToken token = beginFadeReservation(); + CGDisplaySetDisplayMode(monitor->ns.displayID, native, NULL); + endFadeReservation(token); + } + + CFRelease(modes); + CVDisplayLinkRelease(link); + + if (!native) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Monitor mode list changed"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +// Restore the previously saved (original) video mode +// +void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor) +{ + if (monitor->ns.previousMode) + { + CGDisplayFadeReservationToken token = beginFadeReservation(); + CGDisplaySetDisplayMode(monitor->ns.displayID, + monitor->ns.previousMode, NULL); + endFadeReservation(token); + + CGDisplayModeRelease(monitor->ns.previousMode); + monitor->ns.previousMode = NULL; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwPlatformGetMonitors(int* count) +{ + uint32_t i, found = 0, displayCount; + _GLFWmonitor** monitors; + CGDirectDisplayID* displays; + + *count = 0; + + CGGetOnlineDisplayList(0, NULL, &displayCount); + displays = calloc(displayCount, sizeof(CGDirectDisplayID)); + monitors = calloc(displayCount, sizeof(_GLFWmonitor*)); + + CGGetOnlineDisplayList(displayCount, displays, &displayCount); + + for (i = 0; i < displayCount; i++) + { + _GLFWmonitor* monitor; + + if (CGDisplayIsAsleep(displays[i])) + continue; + + const CGSize size = CGDisplayScreenSize(displays[i]); + char* name = getDisplayName(displays[i]); + + monitor = _glfwAllocMonitor(name, size.width, size.height); + monitor->ns.displayID = displays[i]; + monitor->ns.unitNumber = CGDisplayUnitNumber(displays[i]); + + free(name); + + found++; + monitors[found - 1] = monitor; + } + + free(displays); + + *count = found; + return monitors; +} + +GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) +{ + // HACK: Compare unit numbers instead of display IDs to work around display + // replacement on machines with automatic graphics switching + return first->ns.unitNumber == second->ns.unitNumber; +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + const CGRect bounds = CGDisplayBounds(monitor->ns.displayID); + + if (xpos) + *xpos = (int) bounds.origin.x; + if (ypos) + *ypos = (int) bounds.origin.y; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) +{ + CFArrayRef modes; + CFIndex found, i, j; + GLFWvidmode* result; + CVDisplayLinkRef link; + + *count = 0; + + CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); + + modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); + found = CFArrayGetCount(modes); + result = calloc(found, sizeof(GLFWvidmode)); + + for (i = 0; i < found; i++) + { + CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); + if (!modeIsGood(dm)) + continue; + + const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link); + + for (j = 0; j < *count; j++) + { + if (_glfwCompareVideoModes(result + j, &mode) == 0) + break; + } + + // Skip duplicate modes + if (i < *count) + continue; + + (*count)++; + result[*count - 1] = mode; + } + + CFRelease(modes); + CVDisplayLinkRelease(link); + return result; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode) +{ + CGDisplayModeRef displayMode; + CVDisplayLinkRef link; + + CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); + + displayMode = CGDisplayCopyDisplayMode(monitor->ns.displayID); + *mode = vidmodeFromCGDisplayMode(displayMode, link); + CGDisplayModeRelease(displayMode); + + CVDisplayLinkRelease(link); +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID); + CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue)); + + CGGetDisplayTransferByTable(monitor->ns.displayID, + size, + values, + values + size, + values + size * 2, + &size); + + _glfwAllocGammaArrays(ramp, size); + + for (i = 0; i < size; i++) + { + ramp->red[i] = (unsigned short) (values[i] * 65535); + ramp->green[i] = (unsigned short) (values[i + size] * 65535); + ramp->blue[i] = (unsigned short) (values[i + size * 2] * 65535); + } + + free(values); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + int i; + CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue)); + + for (i = 0; i < ramp->size; i++) + { + values[i] = ramp->red[i] / 65535.f; + values[i + ramp->size] = ramp->green[i] / 65535.f; + values[i + ramp->size * 2] = ramp->blue[i] / 65535.f; + } + + CGSetDisplayTransferByTable(monitor->ns.displayID, + ramp->size, + values, + values + ramp->size, + values + ramp->size * 2); + + free(values); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(kCGNullDirectDisplay); + return monitor->ns.displayID; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_platform.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_platform.h new file mode 100644 index 00000000..92214276 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_platform.h @@ -0,0 +1,150 @@ +//======================================================================== +// GLFW 3.2 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_cocoa_platform_h_ +#define _glfw3_cocoa_platform_h_ + +#include +#include + +#if defined(__OBJC__) +#import +#import +#else +#include +#include +typedef void* id; +#endif + +#include "posix_tls.h" +#include "cocoa_joystick.h" +#include "nsgl_context.h" + +#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) +#define _glfw_dlclose(handle) dlclose(handle) +#define _glfw_dlsym(handle, name) dlsym(handle, name) + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns +#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeNS ns_time +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorNS ns + +#define _GLFW_EGL_CONTEXT_STATE +#define _GLFW_EGL_LIBRARY_CONTEXT_STATE + +// HIToolbox.framework pointer typedefs +#define kTISPropertyUnicodeKeyLayoutData _glfw.ns.tis.kPropertyUnicodeKeyLayoutData +#define kTISNotifySelectedKeyboardInputSourceChanged _glfw.ns.tis.kNotifySelectedKeyboardInputSourceChanged +typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardLayoutInputSource)(void); +#define TISCopyCurrentKeyboardLayoutInputSource _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource +typedef void* (*PFN_TISGetInputSourceProperty)(TISInputSourceRef,CFStringRef); +#define TISGetInputSourceProperty _glfw.ns.tis.GetInputSourceProperty +typedef UInt8 (*PFN_LMGetKbdType)(void); +#define LMGetKbdType _glfw.ns.tis.GetKbdType + + +// Cocoa-specific per-window data +// +typedef struct _GLFWwindowNS +{ + id object; + id delegate; + id view; + + // The total sum of the distances the cursor has been warped + // since the last cursor motion event was processed + // This is kept to counteract Cocoa doing the same internally + double cursorWarpDeltaX, cursorWarpDeltaY; + +} _GLFWwindowNS; + +// Cocoa-specific global data +// +typedef struct _GLFWlibraryNS +{ + CGEventSourceRef eventSource; + id delegate; + id autoreleasePool; + id cursor; + TISInputSourceRef inputSource; + IOHIDManagerRef hidManager; + id unicodeData; + id listener; + + char keyName[64]; + short int publicKeys[256]; + short int nativeKeys[GLFW_KEY_LAST + 1]; + char* clipboardString; + // Where to place the cursor when re-enabled + double restoreCursorPosX, restoreCursorPosY; + // The window whose disabled cursor mode is active + _GLFWwindow* disabledCursorWindow; + + struct { + CFBundleRef bundle; + PFN_TISCopyCurrentKeyboardLayoutInputSource CopyCurrentKeyboardLayoutInputSource; + PFN_TISGetInputSourceProperty GetInputSourceProperty; + PFN_LMGetKbdType GetKbdType; + CFStringRef kPropertyUnicodeKeyLayoutData; + CFStringRef kNotifySelectedKeyboardInputSourceChanged; + } tis; + +} _GLFWlibraryNS; + +// Cocoa-specific per-monitor data +// +typedef struct _GLFWmonitorNS +{ + CGDirectDisplayID displayID; + CGDisplayModeRef previousMode; + uint32_t unitNumber; + +} _GLFWmonitorNS; + +// Cocoa-specific per-cursor data +// +typedef struct _GLFWcursorNS +{ + id object; + +} _GLFWcursorNS; + +// Cocoa-specific global timer data +// +typedef struct _GLFWtimeNS +{ + uint64_t frequency; + +} _GLFWtimeNS; + + +void _glfwInitTimerNS(void); + +GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired); +void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor); + +#endif // _glfw3_cocoa_platform_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_time.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_time.c new file mode 100644 index 00000000..dacfed01 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_time.c @@ -0,0 +1,60 @@ +//======================================================================== +// GLFW 3.2 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialise timer +// +void _glfwInitTimerNS(void) +{ + mach_timebase_info_data_t info; + mach_timebase_info(&info); + + _glfw.ns_time.frequency = (info.denom * 1e9) / info.numer; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +uint64_t _glfwPlatformGetTimerValue(void) +{ + return mach_absolute_time(); +} + +uint64_t _glfwPlatformGetTimerFrequency(void) +{ + return _glfw.ns_time.frequency; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_window.m b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_window.m new file mode 100644 index 00000000..b002e997 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/cocoa_window.m @@ -0,0 +1,1653 @@ +//======================================================================== +// GLFW 3.2 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + +// Needed for _NSGetProgname +#include + + +// Returns the specified standard cursor +// +static NSCursor* getStandardCursor(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return [NSCursor arrowCursor]; + case GLFW_IBEAM_CURSOR: + return [NSCursor IBeamCursor]; + case GLFW_CROSSHAIR_CURSOR: + return [NSCursor crosshairCursor]; + case GLFW_HAND_CURSOR: + return [NSCursor pointingHandCursor]; + case GLFW_HRESIZE_CURSOR: + return [NSCursor resizeLeftRightCursor]; + case GLFW_VRESIZE_CURSOR: + return [NSCursor resizeUpDownCursor]; + } + + return nil; +} + +// Returns the style mask corresponding to the window settings +// +static NSUInteger getStyleMask(_GLFWwindow* window) +{ + NSUInteger styleMask = 0; + + if (window->monitor || !window->decorated) + styleMask |= NSBorderlessWindowMask; + else + { + styleMask |= NSTitledWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask; + + if (window->resizable) + styleMask |= NSResizableWindowMask; + } + + return styleMask; +} + +// Center the cursor in the view of the window +// +static void centerCursor(_GLFWwindow *window) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); +} + +// Returns whether the cursor is in the client area of the specified window +// +static GLFWbool cursorInClientArea(_GLFWwindow* window) +{ + const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; + return [window->ns.view mouse:pos inRect:[window->ns.view frame]]; +} + +// Updates the cursor image according to its cursor mode +// +static void updateCursorImage(_GLFWwindow* window) +{ + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + if (window->cursor) + [(NSCursor*) window->cursor->ns.object set]; + else + [[NSCursor arrowCursor] set]; + } + else + [(NSCursor*) _glfw.ns.cursor set]; +} + +// Transforms the specified y-coordinate between the CG display and NS screen +// coordinate systems +// +static float transformY(float y) +{ + return CGDisplayBounds(CGMainDisplayID()).size.height - y; +} + +// Make the specified window and its video mode active on its monitor +// +static GLFWbool acquireMonitor(_GLFWwindow* window) +{ + const GLFWbool status = _glfwSetVideoModeNS(window->monitor, &window->videoMode); + const CGRect bounds = CGDisplayBounds(window->monitor->ns.displayID); + const NSRect frame = NSMakeRect(bounds.origin.x, + transformY(bounds.origin.y + bounds.size.height), + bounds.size.width, + bounds.size.height); + + [window->ns.object setFrame:frame display:YES]; + + _glfwInputMonitorWindowChange(window->monitor, window); + return status; +} + +// Remove the window and restore the original video mode +// +static void releaseMonitor(_GLFWwindow* window) +{ + if (window->monitor->window != window) + return; + + _glfwInputMonitorWindowChange(window->monitor, NULL); + _glfwRestoreVideoModeNS(window->monitor); +} + +// Translates OS X key modifiers into GLFW ones +// +static int translateFlags(NSUInteger flags) +{ + int mods = 0; + + if (flags & NSShiftKeyMask) + mods |= GLFW_MOD_SHIFT; + if (flags & NSControlKeyMask) + mods |= GLFW_MOD_CONTROL; + if (flags & NSAlternateKeyMask) + mods |= GLFW_MOD_ALT; + if (flags & NSCommandKeyMask) + mods |= GLFW_MOD_SUPER; + + return mods; +} + +// Translates a OS X keycode to a GLFW keycode +// +static int translateKey(unsigned int key) +{ + if (key >= sizeof(_glfw.ns.publicKeys) / sizeof(_glfw.ns.publicKeys[0])) + return GLFW_KEY_UNKNOWN; + + return _glfw.ns.publicKeys[key]; +} + +// Translate a GLFW keycode to a Cocoa modifier flag +// +static NSUInteger translateKeyToModifierFlag(int key) +{ + switch (key) + { + case GLFW_KEY_LEFT_SHIFT: + case GLFW_KEY_RIGHT_SHIFT: + return NSShiftKeyMask; + case GLFW_KEY_LEFT_CONTROL: + case GLFW_KEY_RIGHT_CONTROL: + return NSControlKeyMask; + case GLFW_KEY_LEFT_ALT: + case GLFW_KEY_RIGHT_ALT: + return NSAlternateKeyMask; + case GLFW_KEY_LEFT_SUPER: + case GLFW_KEY_RIGHT_SUPER: + return NSCommandKeyMask; + } + + return 0; +} + +// Defines a constant for empty ranges in NSTextInputClient +// +static const NSRange kEmptyRange = { NSNotFound, 0 }; + + +//------------------------------------------------------------------------ +// Delegate for window related notifications +//------------------------------------------------------------------------ + +@interface GLFWWindowDelegate : NSObject +{ + _GLFWwindow* window; +} + +- (id)initWithGlfwWindow:(_GLFWwindow *)initWindow; + +@end + +@implementation GLFWWindowDelegate + +- (id)initWithGlfwWindow:(_GLFWwindow *)initWindow +{ + self = [super init]; + if (self != nil) + window = initWindow; + + return self; +} + +- (BOOL)windowShouldClose:(id)sender +{ + _glfwInputWindowCloseRequest(window); + return NO; +} + +- (void)windowDidResize:(NSNotification *)notification +{ + if (window->context.client != GLFW_NO_API) + [window->context.nsgl.object update]; + + if (_glfw.ns.disabledCursorWindow == window) + centerCursor(window); + + const NSRect contentRect = [window->ns.view frame]; + const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; + + _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); + _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height); +} + +- (void)windowDidMove:(NSNotification *)notification +{ + if (window->context.client != GLFW_NO_API) + [window->context.nsgl.object update]; + + if (_glfw.ns.disabledCursorWindow == window) + centerCursor(window); + + int x, y; + _glfwPlatformGetWindowPos(window, &x, &y); + _glfwInputWindowPos(window, x, y); +} + +- (void)windowDidMiniaturize:(NSNotification *)notification +{ + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowIconify(window, GLFW_TRUE); +} + +- (void)windowDidDeminiaturize:(NSNotification *)notification +{ + if (window->monitor) + acquireMonitor(window); + + _glfwInputWindowIconify(window, GLFW_FALSE); +} + +- (void)windowDidBecomeKey:(NSNotification *)notification +{ + if (_glfw.ns.disabledCursorWindow == window) + centerCursor(window); + + _glfwInputWindowFocus(window, GLFW_TRUE); + _glfwPlatformSetCursorMode(window, window->cursorMode); +} + +- (void)windowDidResignKey:(NSNotification *)notification +{ + if (window->monitor && window->autoIconify) + _glfwPlatformIconifyWindow(window); + + _glfwInputWindowFocus(window, GLFW_FALSE); +} + +@end + + +//------------------------------------------------------------------------ +// Delegate for application related notifications +//------------------------------------------------------------------------ + +@interface GLFWApplicationDelegate : NSObject +@end + +@implementation GLFWApplicationDelegate + +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender +{ + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window->next) + _glfwInputWindowCloseRequest(window); + + return NSTerminateCancel; +} + +- (void)applicationDidChangeScreenParameters:(NSNotification *) notification +{ + _glfwInputMonitorChange(); +} + +- (void)applicationDidFinishLaunching:(NSNotification *)notification +{ + [NSApp stop:nil]; + + _glfwPlatformPostEmptyEvent(); +} + +- (void)applicationDidHide:(NSNotification *)notification +{ + int i; + + for (i = 0; i < _glfw.monitorCount; i++) + _glfwRestoreVideoModeNS(_glfw.monitors[i]); +} + +@end + + +//------------------------------------------------------------------------ +// Content view class for the GLFW window +//------------------------------------------------------------------------ + +@interface GLFWContentView : NSView +{ + _GLFWwindow* window; + NSTrackingArea* trackingArea; + NSMutableAttributedString* markedText; +} + +- (id)initWithGlfwWindow:(_GLFWwindow *)initWindow; + +@end + +@implementation GLFWContentView + ++ (void)initialize +{ + if (self == [GLFWContentView class]) + { + if (_glfw.ns.cursor == nil) + { + NSImage* data = [[NSImage alloc] initWithSize:NSMakeSize(16, 16)]; + _glfw.ns.cursor = [[NSCursor alloc] initWithImage:data + hotSpot:NSZeroPoint]; + [data release]; + } + } +} + +- (id)initWithGlfwWindow:(_GLFWwindow *)initWindow +{ + self = [super init]; + if (self != nil) + { + window = initWindow; + trackingArea = nil; + markedText = [[NSMutableAttributedString alloc] init]; + + [self updateTrackingAreas]; + [self registerForDraggedTypes:[NSArray arrayWithObjects: + NSFilenamesPboardType, nil]]; + } + + return self; +} + +- (void)dealloc +{ + [trackingArea release]; + [markedText release]; + [super dealloc]; +} + +- (BOOL)isOpaque +{ + return YES; +} + +- (BOOL)canBecomeKeyView +{ + return YES; +} + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (void)cursorUpdate:(NSEvent *)event +{ + updateCursorImage(window); +} + +- (void)mouseDown:(NSEvent *)event +{ + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_LEFT, + GLFW_PRESS, + translateFlags([event modifierFlags])); +} + +- (void)mouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)mouseUp:(NSEvent *)event +{ + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_LEFT, + GLFW_RELEASE, + translateFlags([event modifierFlags])); +} + +- (void)mouseMoved:(NSEvent *)event +{ + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + const double dx = [event deltaX] - window->ns.cursorWarpDeltaX; + const double dy = [event deltaY] - window->ns.cursorWarpDeltaY; + + _glfwInputCursorPos(window, + window->virtualCursorPosX + dx, + window->virtualCursorPosY + dy); + } + else + { + const NSRect contentRect = [window->ns.view frame]; + const NSPoint pos = [event locationInWindow]; + + _glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y); + } + + window->ns.cursorWarpDeltaX = 0; + window->ns.cursorWarpDeltaY = 0; +} + +- (void)rightMouseDown:(NSEvent *)event +{ + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_RIGHT, + GLFW_PRESS, + translateFlags([event modifierFlags])); +} + +- (void)rightMouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)rightMouseUp:(NSEvent *)event +{ + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_RIGHT, + GLFW_RELEASE, + translateFlags([event modifierFlags])); +} + +- (void)otherMouseDown:(NSEvent *)event +{ + _glfwInputMouseClick(window, + (int) [event buttonNumber], + GLFW_PRESS, + translateFlags([event modifierFlags])); +} + +- (void)otherMouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)otherMouseUp:(NSEvent *)event +{ + _glfwInputMouseClick(window, + (int) [event buttonNumber], + GLFW_RELEASE, + translateFlags([event modifierFlags])); +} + +- (void)mouseExited:(NSEvent *)event +{ + _glfwInputCursorEnter(window, GLFW_FALSE); +} + +- (void)mouseEntered:(NSEvent *)event +{ + _glfwInputCursorEnter(window, GLFW_TRUE); +} + +- (void)viewDidChangeBackingProperties +{ + const NSRect contentRect = [window->ns.view frame]; + const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; + + _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); +} + +- (void)drawRect:(NSRect)rect +{ + _glfwInputWindowDamage(window); +} + +- (void)updateTrackingAreas +{ + if (trackingArea != nil) + { + [self removeTrackingArea:trackingArea]; + [trackingArea release]; + } + + const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | + NSTrackingActiveInKeyWindow | + NSTrackingEnabledDuringMouseDrag | + NSTrackingCursorUpdate | + NSTrackingInVisibleRect | + NSTrackingAssumeInside; + + trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] + options:options + owner:self + userInfo:nil]; + + [self addTrackingArea:trackingArea]; + [super updateTrackingAreas]; +} + +- (void)keyDown:(NSEvent *)event +{ + const int key = translateKey([event keyCode]); + const int mods = translateFlags([event modifierFlags]); + + _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods); + + [self interpretKeyEvents:[NSArray arrayWithObject:event]]; +} + +- (void)flagsChanged:(NSEvent *)event +{ + int action; + const unsigned int modifierFlags = + [event modifierFlags] & NSDeviceIndependentModifierFlagsMask; + const int key = translateKey([event keyCode]); + const int mods = translateFlags(modifierFlags); + const NSUInteger keyFlag = translateKeyToModifierFlag(key); + + if (keyFlag & modifierFlags) + { + if (window->keys[key] == GLFW_PRESS) + action = GLFW_RELEASE; + else + action = GLFW_PRESS; + } + else + action = GLFW_RELEASE; + + _glfwInputKey(window, key, [event keyCode], action, mods); +} + +- (void)keyUp:(NSEvent *)event +{ + const int key = translateKey([event keyCode]); + const int mods = translateFlags([event modifierFlags]); + _glfwInputKey(window, key, [event keyCode], GLFW_RELEASE, mods); +} + +- (void)scrollWheel:(NSEvent *)event +{ + double deltaX, deltaY; + + deltaX = [event scrollingDeltaX]; + deltaY = [event scrollingDeltaY]; + + if ([event hasPreciseScrollingDeltas]) + { + deltaX *= 0.1; + deltaY *= 0.1; + } + + if (fabs(deltaX) > 0.0 || fabs(deltaY) > 0.0) + _glfwInputScroll(window, deltaX, deltaY); +} + +- (NSDragOperation)draggingEntered:(id )sender +{ + if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) + == NSDragOperationGeneric) + { + [self setNeedsDisplay:YES]; + return NSDragOperationGeneric; + } + + return NSDragOperationNone; +} + +- (BOOL)prepareForDragOperation:(id )sender +{ + [self setNeedsDisplay:YES]; + return YES; +} + +- (BOOL)performDragOperation:(id )sender +{ + NSPasteboard* pasteboard = [sender draggingPasteboard]; + NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType]; + + const NSRect contentRect = [window->ns.view frame]; + _glfwInputCursorPos(window, + [sender draggingLocation].x, + contentRect.size.height - [sender draggingLocation].y); + + const int count = [files count]; + if (count) + { + NSEnumerator* e = [files objectEnumerator]; + char** paths = calloc(count, sizeof(char*)); + int i; + + for (i = 0; i < count; i++) + paths[i] = strdup([[e nextObject] UTF8String]); + + _glfwInputDrop(window, count, (const char**) paths); + + for (i = 0; i < count; i++) + free(paths[i]); + free(paths); + } + + return YES; +} + +- (void)concludeDragOperation:(id )sender +{ + [self setNeedsDisplay:YES]; +} + +- (BOOL)hasMarkedText +{ + return [markedText length] > 0; +} + +- (NSRange)markedRange +{ + if ([markedText length] > 0) + return NSMakeRange(0, [markedText length] - 1); + else + return kEmptyRange; +} + +- (NSRange)selectedRange +{ + return kEmptyRange; +} + +- (void)setMarkedText:(id)string + selectedRange:(NSRange)selectedRange + replacementRange:(NSRange)replacementRange +{ + if ([string isKindOfClass:[NSAttributedString class]]) + [markedText initWithAttributedString:string]; + else + [markedText initWithString:string]; +} + +- (void)unmarkText +{ + [[markedText mutableString] setString:@""]; +} + +- (NSArray*)validAttributesForMarkedText +{ + return [NSArray array]; +} + +- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range + actualRange:(NSRangePointer)actualRange +{ + return nil; +} + +- (NSUInteger)characterIndexForPoint:(NSPoint)point +{ + return 0; +} + +- (NSRect)firstRectForCharacterRange:(NSRange)range + actualRange:(NSRangePointer)actualRange +{ + int xpos, ypos; + _glfwPlatformGetWindowPos(window, &xpos, &ypos); + const NSRect contentRect = [window->ns.view frame]; + return NSMakeRect(xpos, transformY(ypos + contentRect.size.height), 0.0, 0.0); +} + +- (void)insertText:(id)string replacementRange:(NSRange)replacementRange +{ + NSString* characters; + NSEvent* event = [NSApp currentEvent]; + const int mods = translateFlags([event modifierFlags]); + const int plain = !(mods & GLFW_MOD_SUPER); + + if ([string isKindOfClass:[NSAttributedString class]]) + characters = [string string]; + else + characters = (NSString*) string; + + NSUInteger i, length = [characters length]; + + for (i = 0; i < length; i++) + { + const unichar codepoint = [characters characterAtIndex:i]; + if ((codepoint & 0xff00) == 0xf700) + continue; + + _glfwInputChar(window, codepoint, mods, plain); + } +} + +- (void)doCommandBySelector:(SEL)selector +{ +} + +@end + + +//------------------------------------------------------------------------ +// GLFW window class +//------------------------------------------------------------------------ + +@interface GLFWWindow : NSWindow {} +@end + +@implementation GLFWWindow + +- (BOOL)canBecomeKeyWindow +{ + // Required for NSBorderlessWindowMask windows + return YES; +} + +@end + + +//------------------------------------------------------------------------ +// GLFW application class +//------------------------------------------------------------------------ + +@interface GLFWApplication : NSApplication +@end + +@implementation GLFWApplication + +// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost +// This works around an AppKit bug, where key up events while holding +// down the command key don't get sent to the key window. +- (void)sendEvent:(NSEvent *)event +{ + if ([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask)) + [[self keyWindow] sendEvent:event]; + else + [super sendEvent:event]; +} + + +// No-op thread entry point +// +- (void)doNothing:(id)object +{ +} +@end + +#if defined(_GLFW_USE_MENUBAR) + +// Try to figure out what the calling application is called +// +static NSString* findAppName(void) +{ + size_t i; + NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary]; + + // Keys to search for as potential application names + NSString* GLFWNameKeys[] = + { + @"CFBundleDisplayName", + @"CFBundleName", + @"CFBundleExecutable", + }; + + for (i = 0; i < sizeof(GLFWNameKeys) / sizeof(GLFWNameKeys[0]); i++) + { + id name = [infoDictionary objectForKey:GLFWNameKeys[i]]; + if (name && + [name isKindOfClass:[NSString class]] && + ![name isEqualToString:@""]) + { + return name; + } + } + + char** progname = _NSGetProgname(); + if (progname && *progname) + return [NSString stringWithUTF8String:*progname]; + + // Really shouldn't get here + return @"GLFW Application"; +} + +// Set up the menu bar (manually) +// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that +// could go away at any moment, lots of stuff that really should be +// localize(d|able), etc. Loading a nib would save us this horror, but that +// doesn't seem like a good thing to require of GLFW users. +// +static void createMenuBar(void) +{ + NSString* appName = findAppName(); + + NSMenu* bar = [[NSMenu alloc] init]; + [NSApp setMainMenu:bar]; + + NSMenuItem* appMenuItem = + [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; + NSMenu* appMenu = [[NSMenu alloc] init]; + [appMenuItem setSubmenu:appMenu]; + + [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] + action:@selector(orderFrontStandardAboutPanel:) + keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + NSMenu* servicesMenu = [[NSMenu alloc] init]; + [NSApp setServicesMenu:servicesMenu]; + [[appMenu addItemWithTitle:@"Services" + action:NULL + keyEquivalent:@""] setSubmenu:servicesMenu]; + [servicesMenu release]; + [appMenu addItem:[NSMenuItem separatorItem]]; + [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] + action:@selector(hide:) + keyEquivalent:@"h"]; + [[appMenu addItemWithTitle:@"Hide Others" + action:@selector(hideOtherApplications:) + keyEquivalent:@"h"] + setKeyEquivalentModifierMask:NSAlternateKeyMask | NSCommandKeyMask]; + [appMenu addItemWithTitle:@"Show All" + action:@selector(unhideAllApplications:) + keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] + action:@selector(terminate:) + keyEquivalent:@"q"]; + + NSMenuItem* windowMenuItem = + [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; + [bar release]; + NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + [NSApp setWindowsMenu:windowMenu]; + [windowMenuItem setSubmenu:windowMenu]; + + [windowMenu addItemWithTitle:@"Minimize" + action:@selector(performMiniaturize:) + keyEquivalent:@"m"]; + [windowMenu addItemWithTitle:@"Zoom" + action:@selector(performZoom:) + keyEquivalent:@""]; + [windowMenu addItem:[NSMenuItem separatorItem]]; + [windowMenu addItemWithTitle:@"Bring All to Front" + action:@selector(arrangeInFront:) + keyEquivalent:@""]; + + // TODO: Make this appear at the bottom of the menu (for consistency) + [windowMenu addItem:[NSMenuItem separatorItem]]; + [[windowMenu addItemWithTitle:@"Enter Full Screen" + action:@selector(toggleFullScreen:) + keyEquivalent:@"f"] + setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask]; + + // Prior to Snow Leopard, we need to use this oddly-named semi-private API + // to get the application menu working properly. + SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:"); + [NSApp performSelector:setAppleMenuSelector withObject:appMenu]; +} + +#endif /* _GLFW_USE_MENUBAR */ + +// Initialize the Cocoa Application Kit +// +static GLFWbool initializeAppKit(void) +{ + if (NSApp) + return GLFW_TRUE; + + // Implicitly create shared NSApplication instance + [GLFWApplication sharedApplication]; + + // Make Cocoa enter multi-threaded mode + [NSThread detachNewThreadSelector:@selector(doNothing:) + toTarget:NSApp + withObject:nil]; + + // In case we are unbundled, make us a proper UI application + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + +#if defined(_GLFW_USE_MENUBAR) + // Menu bar setup must go between sharedApplication above and + // finishLaunching below, in order to properly emulate the behavior + // of NSApplicationMain + createMenuBar(); +#endif + + // There can only be one application delegate, but we allocate it the + // first time a window is created to keep all window code in this file + _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; + if (_glfw.ns.delegate == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to create application delegate"); + return GLFW_FALSE; + } + + [NSApp setDelegate:_glfw.ns.delegate]; + [NSApp run]; + + return GLFW_TRUE; +} + +// Create the Cocoa window +// +static GLFWbool createNativeWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig) +{ + window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window]; + if (window->ns.delegate == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to create window delegate"); + return GLFW_FALSE; + } + + NSRect contentRect; + + if (window->monitor) + { + GLFWvidmode mode; + int xpos, ypos; + + _glfwPlatformGetVideoMode(window->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + + contentRect = NSMakeRect(xpos, ypos, mode.width, mode.height); + } + else + contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height); + + window->ns.object = [[GLFWWindow alloc] + initWithContentRect:contentRect + styleMask:getStyleMask(window) + backing:NSBackingStoreBuffered + defer:NO]; + + if (window->ns.object == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create window"); + return GLFW_FALSE; + } + + if (window->monitor) + [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; + else + { + [window->ns.object center]; + + if (wndconfig->resizable) + [window->ns.object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + + if (wndconfig->floating) + [window->ns.object setLevel:NSFloatingWindowLevel]; + + if (wndconfig->maximized) + [window->ns.object zoom:nil]; + } + + window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window]; + +#if defined(_GLFW_USE_RETINA) + [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; +#endif /*_GLFW_USE_RETINA*/ + + [window->ns.object makeFirstResponder:window->ns.view]; + [window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]]; + [window->ns.object setDelegate:window->ns.delegate]; + [window->ns.object setAcceptsMouseMovedEvents:YES]; + [window->ns.object setContentView:window->ns.view]; + [window->ns.object setRestorable:NO]; + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + if (!initializeAppKit()) + return GLFW_FALSE; + + if (!createNativeWindow(window, wndconfig)) + return GLFW_FALSE; + + if (ctxconfig->client != GLFW_NO_API) + { + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwInitNSGL()) + return GLFW_FALSE; + if (!_glfwCreateContextNSGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else + { + _glfwInputError(GLFW_API_UNAVAILABLE, "Cocoa: EGL not available"); + return GLFW_FALSE; + } + } + + if (window->monitor) + { + _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); + if (!acquireMonitor(window)) + return GLFW_FALSE; + + centerCursor(window); + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (_glfw.ns.disabledCursorWindow == window) + _glfw.ns.disabledCursorWindow = NULL; + + [window->ns.object orderOut:nil]; + + if (window->monitor) + releaseMonitor(window); + + if (window->context.destroy) + window->context.destroy(window); + + [window->ns.object setDelegate:nil]; + [window->ns.delegate release]; + window->ns.delegate = nil; + + [window->ns.view release]; + window->ns.view = nil; + + [window->ns.object close]; + window->ns.object = nil; + + [_glfw.ns.autoreleasePool drain]; + _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char *title) +{ + [window->ns.object setTitle:[NSString stringWithUTF8String:title]]; +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + // Regular windows do not have icons +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + const NSRect contentRect = + [window->ns.object contentRectForFrameRect:[window->ns.object frame]]; + + if (xpos) + *xpos = contentRect.origin.x; + if (ypos) + *ypos = transformY(contentRect.origin.y + contentRect.size.height); +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int x, int y) +{ + const NSRect contentRect = [window->ns.view frame]; + const NSRect dummyRect = NSMakeRect(x, transformY(y + contentRect.size.height), 0, 0); + const NSRect frameRect = [window->ns.object frameRectForContentRect:dummyRect]; + [window->ns.object setFrameOrigin:frameRect.origin]; +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + const NSRect contentRect = [window->ns.view frame]; + + if (width) + *width = contentRect.size.width; + if (height) + *height = contentRect.size.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + if (window->monitor) + { + if (window->monitor->window == window) + acquireMonitor(window); + } + else + [window->ns.object setContentSize:NSMakeSize(width, height)]; +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ + if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) + [window->ns.object setContentMinSize:NSMakeSize(0, 0)]; + else + [window->ns.object setContentMinSize:NSMakeSize(minwidth, minheight)]; + + if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE) + [window->ns.object setContentMaxSize:NSMakeSize(DBL_MAX, DBL_MAX)]; + else + [window->ns.object setContentMaxSize:NSMakeSize(maxwidth, maxheight)]; +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +{ + if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) + [window->ns.object setContentAspectRatio:NSMakeSize(0, 0)]; + else + [window->ns.object setContentAspectRatio:NSMakeSize(numer, denom)]; +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + const NSRect contentRect = [window->ns.view frame]; + const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; + + if (width) + *width = (int) fbRect.size.width; + if (height) + *height = (int) fbRect.size.height; +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + const NSRect contentRect = [window->ns.view frame]; + const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect]; + + if (left) + *left = contentRect.origin.x - frameRect.origin.x; + if (top) + *top = frameRect.origin.y + frameRect.size.height - + contentRect.origin.y - contentRect.size.height; + if (right) + *right = frameRect.origin.x + frameRect.size.width - + contentRect.origin.x - contentRect.size.width; + if (bottom) + *bottom = contentRect.origin.y - frameRect.origin.y; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + [window->ns.object miniaturize:nil]; +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + if ([window->ns.object isMiniaturized]) + [window->ns.object deminiaturize:nil]; + else if ([window->ns.object isZoomed]) + [window->ns.object zoom:nil]; +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + if (![window->ns.object isZoomed]) + [window->ns.object zoom:nil]; +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + [window->ns.object orderFront:nil]; +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + [window->ns.object orderOut:nil]; +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + // Make us the active application + // HACK: This has been moved here from initializeAppKit to prevent + // applications using only hidden windows from being activated, but + // should probably not be done every time any window is shown + [NSApp activateIgnoringOtherApps:YES]; + + [window->ns.object makeKeyAndOrderFront:nil]; +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (window->monitor == monitor) + { + if (monitor) + { + if (monitor->window == window) + acquireMonitor(window); + } + else + { + const NSRect contentRect = + NSMakeRect(xpos, transformY(ypos + height), width, height); + const NSRect frameRect = + [window->ns.object frameRectForContentRect:contentRect + styleMask:getStyleMask(window)]; + + [window->ns.object setFrame:frameRect display:YES]; + } + + return; + } + + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowMonitorChange(window, monitor); + + const NSUInteger styleMask = getStyleMask(window); + [window->ns.object setStyleMask:styleMask]; + [window->ns.object makeFirstResponder:window->ns.view]; + + NSRect contentRect; + + if (monitor) + { + GLFWvidmode mode; + + _glfwPlatformGetVideoMode(window->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + + contentRect = NSMakeRect(xpos, transformY(ypos + mode.height), + mode.width, mode.height); + } + else + { + contentRect = NSMakeRect(xpos, transformY(ypos + height), + width, height); + } + + NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect + styleMask:styleMask]; + [window->ns.object setFrame:frameRect display:YES]; + + if (monitor) + { + [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; + [window->ns.object setHasShadow:NO]; + + acquireMonitor(window); + } + else + { + if (window->numer != GLFW_DONT_CARE && + window->denom != GLFW_DONT_CARE) + { + [window->ns.object setContentAspectRatio:NSMakeSize(window->numer, + window->denom)]; + } + + if (window->minwidth != GLFW_DONT_CARE && + window->minheight != GLFW_DONT_CARE) + { + [window->ns.object setContentMinSize:NSMakeSize(window->minwidth, + window->minheight)]; + } + + if (window->maxwidth != GLFW_DONT_CARE && + window->maxheight != GLFW_DONT_CARE) + { + [window->ns.object setContentMaxSize:NSMakeSize(window->maxwidth, + window->maxheight)]; + } + + if (window->floating) + [window->ns.object setLevel:NSFloatingWindowLevel]; + else + [window->ns.object setLevel:NSNormalWindowLevel]; + + [window->ns.object setHasShadow:YES]; + } +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + return [window->ns.object isKeyWindow]; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + return [window->ns.object isMiniaturized]; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + return [window->ns.object isVisible]; +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + return [window->ns.object isZoomed]; +} + +void _glfwPlatformPollEvents(void) +{ + for (;;) + { + NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (event == nil) + break; + + [NSApp sendEvent:event]; + } + + [_glfw.ns.autoreleasePool drain]; + _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; +} + +void _glfwPlatformWaitEvents(void) +{ + // I wanted to pass NO to dequeue:, and rely on PollEvents to + // dequeue and send. For reasons not at all clear to me, passing + // NO to dequeue: causes this method never to return. + NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantFuture] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + [NSApp sendEvent:event]; + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + NSDate* date = [NSDate dateWithTimeIntervalSinceNow:timeout]; + NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:date + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (event) + [NSApp sendEvent:event]; + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformPostEmptyEvent(void) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined + location:NSMakePoint(0, 0) + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:nil + subtype:0 + data1:0 + data2:0]; + [NSApp postEvent:event atStart:YES]; + [pool drain]; +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + const NSRect contentRect = [window->ns.view frame]; + const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; + + if (xpos) + *xpos = pos.x; + if (ypos) + *ypos = contentRect.size.height - pos.y - 1; +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +{ + updateCursorImage(window); + + const NSRect contentRect = [window->ns.view frame]; + const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; + + window->ns.cursorWarpDeltaX += x - pos.x; + window->ns.cursorWarpDeltaY += y - contentRect.size.height + pos.y; + + if (window->monitor) + { + CGDisplayMoveCursorToPoint(window->monitor->ns.displayID, + CGPointMake(x, y)); + } + else + { + const NSRect localRect = NSMakeRect(x, contentRect.size.height - y - 1, 0, 0); + const NSRect globalRect = [window->ns.object convertRectToScreen:localRect]; + const NSPoint globalPoint = globalRect.origin; + + CGWarpMouseCursorPosition(CGPointMake(globalPoint.x, + transformY(globalPoint.y))); + } +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + if (mode == GLFW_CURSOR_DISABLED) + { + _glfw.ns.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.ns.restoreCursorPosX, + &_glfw.ns.restoreCursorPosY); + centerCursor(window); + CGAssociateMouseAndMouseCursorPosition(false); + } + else if (_glfw.ns.disabledCursorWindow == window) + { + _glfw.ns.disabledCursorWindow = NULL; + CGAssociateMouseAndMouseCursorPosition(true); + _glfwPlatformSetCursorPos(window, + _glfw.ns.restoreCursorPosX, + _glfw.ns.restoreCursorPosY); + } + + if (cursorInClientArea(window)) + updateCursorImage(window); +} + +const char* _glfwPlatformGetKeyName(int key, int scancode) +{ + if (key != GLFW_KEY_UNKNOWN) + scancode = _glfw.ns.nativeKeys[key]; + + if (!_glfwIsPrintable(_glfw.ns.publicKeys[scancode])) + return NULL; + + UInt32 deadKeyState = 0; + UniChar characters[8]; + UniCharCount characterCount = 0; + + if (UCKeyTranslate([(NSData*) _glfw.ns.unicodeData bytes], + scancode, + kUCKeyActionDisplay, + 0, + LMGetKbdType(), + kUCKeyTranslateNoDeadKeysBit, + &deadKeyState, + sizeof(characters) / sizeof(characters[0]), + &characterCount, + characters) != noErr) + { + return NULL; + } + + if (!characterCount) + return NULL; + + CFStringRef string = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, + characters, + characterCount, + kCFAllocatorNull); + CFStringGetCString(string, + _glfw.ns.keyName, + sizeof(_glfw.ns.keyName), + kCFStringEncodingUTF8); + CFRelease(string); + + return _glfw.ns.keyName; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + NSImage* native; + NSBitmapImageRep* rep; + + if (!initializeAppKit()) + return GLFW_FALSE; + + rep = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes:NULL + pixelsWide:image->width + pixelsHigh:image->height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSCalibratedRGBColorSpace + bitmapFormat:NSAlphaNonpremultipliedBitmapFormat + bytesPerRow:image->width * 4 + bitsPerPixel:32]; + + if (rep == nil) + return GLFW_FALSE; + + memcpy([rep bitmapData], image->pixels, image->width * image->height * 4); + + native = [[NSImage alloc] initWithSize:NSMakeSize(image->width, image->height)]; + [native addRepresentation:rep]; + + cursor->ns.object = [[NSCursor alloc] initWithImage:native + hotSpot:NSMakePoint(xhot, yhot)]; + + [native release]; + [rep release]; + + if (cursor->ns.object == nil) + return GLFW_FALSE; + + return GLFW_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + if (!initializeAppKit()) + return GLFW_FALSE; + + cursor->ns.object = getStandardCursor(shape); + if (!cursor->ns.object) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to retrieve standard cursor"); + return GLFW_FALSE; + } + + [cursor->ns.object retain]; + return GLFW_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + if (cursor->ns.object) + [(NSCursor*) cursor->ns.object release]; +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + if (cursorInClientArea(window)) + updateCursorImage(window); +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil]; + + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + [pasteboard declareTypes:types owner:nil]; + [pasteboard setString:[NSString stringWithUTF8String:string] + forType:NSStringPboardType]; +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + + if (![[pasteboard types] containsObject:NSStringPboardType]) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "Cocoa: Failed to retrieve string from pasteboard"); + return NULL; + } + + NSString* object = [pasteboard stringForType:NSStringPboardType]; + if (!object) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to retrieve object from pasteboard"); + return NULL; + } + + free(_glfw.ns.clipboardString); + _glfw.ns.clipboardString = strdup([object UTF8String]); + + return _glfw.ns.clipboardString; +} + +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count) +{ + *count = 0; + return NULL; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + return GLFW_FALSE; +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + return VK_ERROR_EXTENSION_NOT_PRESENT; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI id glfwGetCocoaWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(nil); + return window->ns.object; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/context.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/context.c new file mode 100644 index 00000000..85bce7fb --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/context.c @@ -0,0 +1,720 @@ +//======================================================================== +// GLFW 3.2 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) +{ + if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API && + ctxconfig->source != GLFW_EGL_CONTEXT_API) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid context creation API %i", + ctxconfig->source); + return GLFW_FALSE; + } + + if (ctxconfig->client != GLFW_NO_API && + ctxconfig->client != GLFW_OPENGL_API && + ctxconfig->client != GLFW_OPENGL_ES_API) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid client API %i", + ctxconfig->client); + return GLFW_FALSE; + } + + if (ctxconfig->client == GLFW_OPENGL_API) + { + if ((ctxconfig->major < 1 || ctxconfig->minor < 0) || + (ctxconfig->major == 1 && ctxconfig->minor > 5) || + (ctxconfig->major == 2 && ctxconfig->minor > 1) || + (ctxconfig->major == 3 && ctxconfig->minor > 3)) + { + // OpenGL 1.0 is the smallest valid version + // OpenGL 1.x series ended with version 1.5 + // OpenGL 2.x series ended with version 2.1 + // OpenGL 3.x series ended with version 3.3 + // For now, let everything else through + + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid OpenGL version %i.%i", + ctxconfig->major, ctxconfig->minor); + return GLFW_FALSE; + } + + if (ctxconfig->profile) + { + if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE && + ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid OpenGL profile %i", + ctxconfig->profile); + return GLFW_FALSE; + } + + if (ctxconfig->major <= 2 || + (ctxconfig->major == 3 && ctxconfig->minor < 2)) + { + // Desktop OpenGL context profiles are only defined for version 3.2 + // and above + + _glfwInputError(GLFW_INVALID_VALUE, + "Context profiles are only defined for OpenGL version 3.2 and above"); + return GLFW_FALSE; + } + } + + if (ctxconfig->forward && ctxconfig->major <= 2) + { + // Forward-compatible contexts are only defined for OpenGL version 3.0 and above + _glfwInputError(GLFW_INVALID_VALUE, + "Forward-compatibility is only defined for OpenGL version 3.0 and above"); + return GLFW_FALSE; + } + } + else if (ctxconfig->client == GLFW_OPENGL_ES_API) + { + if (ctxconfig->major < 1 || ctxconfig->minor < 0 || + (ctxconfig->major == 1 && ctxconfig->minor > 1) || + (ctxconfig->major == 2 && ctxconfig->minor > 0)) + { + // OpenGL ES 1.0 is the smallest valid version + // OpenGL ES 1.x series ended with version 1.1 + // OpenGL ES 2.x series ended with version 2.0 + // For now, let everything else through + + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid OpenGL ES version %i.%i", + ctxconfig->major, ctxconfig->minor); + return GLFW_FALSE; + } + } + + if (ctxconfig->robustness) + { + if (ctxconfig->robustness != GLFW_NO_RESET_NOTIFICATION && + ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid context robustness mode %i", + ctxconfig->robustness); + return GLFW_FALSE; + } + } + + if (ctxconfig->release) + { + if (ctxconfig->release != GLFW_RELEASE_BEHAVIOR_NONE && + ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid context release behavior %i", + ctxconfig->release); + return GLFW_FALSE; + } + } + + return GLFW_TRUE; +} + +const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, + const _GLFWfbconfig* alternatives, + unsigned int count) +{ + unsigned int i; + unsigned int missing, leastMissing = UINT_MAX; + unsigned int colorDiff, leastColorDiff = UINT_MAX; + unsigned int extraDiff, leastExtraDiff = UINT_MAX; + const _GLFWfbconfig* current; + const _GLFWfbconfig* closest = NULL; + + for (i = 0; i < count; i++) + { + current = alternatives + i; + + if (desired->stereo > 0 && current->stereo == 0) + { + // Stereo is a hard constraint + continue; + } + + if (desired->doublebuffer != current->doublebuffer) + { + // Double buffering is a hard constraint + continue; + } + + // Count number of missing buffers + { + missing = 0; + + if (desired->alphaBits > 0 && current->alphaBits == 0) + missing++; + + if (desired->depthBits > 0 && current->depthBits == 0) + missing++; + + if (desired->stencilBits > 0 && current->stencilBits == 0) + missing++; + + if (desired->auxBuffers > 0 && + current->auxBuffers < desired->auxBuffers) + { + missing += desired->auxBuffers - current->auxBuffers; + } + + if (desired->samples > 0 && current->samples == 0) + { + // Technically, several multisampling buffers could be + // involved, but that's a lower level implementation detail and + // not important to us here, so we count them as one + missing++; + } + } + + // These polynomials make many small channel size differences matter + // less than one large channel size difference + + // Calculate color channel size difference value + { + colorDiff = 0; + + if (desired->redBits != GLFW_DONT_CARE) + { + colorDiff += (desired->redBits - current->redBits) * + (desired->redBits - current->redBits); + } + + if (desired->greenBits != GLFW_DONT_CARE) + { + colorDiff += (desired->greenBits - current->greenBits) * + (desired->greenBits - current->greenBits); + } + + if (desired->blueBits != GLFW_DONT_CARE) + { + colorDiff += (desired->blueBits - current->blueBits) * + (desired->blueBits - current->blueBits); + } + } + + // Calculate non-color channel size difference value + { + extraDiff = 0; + + if (desired->alphaBits != GLFW_DONT_CARE) + { + extraDiff += (desired->alphaBits - current->alphaBits) * + (desired->alphaBits - current->alphaBits); + } + + if (desired->depthBits != GLFW_DONT_CARE) + { + extraDiff += (desired->depthBits - current->depthBits) * + (desired->depthBits - current->depthBits); + } + + if (desired->stencilBits != GLFW_DONT_CARE) + { + extraDiff += (desired->stencilBits - current->stencilBits) * + (desired->stencilBits - current->stencilBits); + } + + if (desired->accumRedBits != GLFW_DONT_CARE) + { + extraDiff += (desired->accumRedBits - current->accumRedBits) * + (desired->accumRedBits - current->accumRedBits); + } + + if (desired->accumGreenBits != GLFW_DONT_CARE) + { + extraDiff += (desired->accumGreenBits - current->accumGreenBits) * + (desired->accumGreenBits - current->accumGreenBits); + } + + if (desired->accumBlueBits != GLFW_DONT_CARE) + { + extraDiff += (desired->accumBlueBits - current->accumBlueBits) * + (desired->accumBlueBits - current->accumBlueBits); + } + + if (desired->accumAlphaBits != GLFW_DONT_CARE) + { + extraDiff += (desired->accumAlphaBits - current->accumAlphaBits) * + (desired->accumAlphaBits - current->accumAlphaBits); + } + + if (desired->samples != GLFW_DONT_CARE) + { + extraDiff += (desired->samples - current->samples) * + (desired->samples - current->samples); + } + + if (desired->sRGB && !current->sRGB) + extraDiff++; + } + + // Figure out if the current one is better than the best one found so far + // Least number of missing buffers is the most important heuristic, + // then color buffer size match and lastly size match for other buffers + + if (missing < leastMissing) + closest = current; + else if (missing == leastMissing) + { + if ((colorDiff < leastColorDiff) || + (colorDiff == leastColorDiff && extraDiff < leastExtraDiff)) + { + closest = current; + } + } + + if (current == closest) + { + leastMissing = missing; + leastColorDiff = colorDiff; + leastExtraDiff = extraDiff; + } + } + + return closest; +} + +GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) +{ + int i; + _GLFWwindow* window; + const char* version; + const char* prefixes[] = + { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + NULL + }; + + window = _glfwPlatformGetCurrentContext(); + + window->context.source = ctxconfig->source; + window->context.client = GLFW_OPENGL_API; + + window->context.GetIntegerv = (PFNGLGETINTEGERVPROC) + window->context.getProcAddress("glGetIntegerv"); + window->context.GetString = (PFNGLGETSTRINGPROC) + window->context.getProcAddress("glGetString"); + if (!window->context.GetIntegerv || !window->context.GetString) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken"); + return GLFW_FALSE; + } + + version = (const char*) window->context.GetString(GL_VERSION); + if (!version) + { + if (ctxconfig->client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OpenGL version string retrieval is broken"); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OpenGL ES version string retrieval is broken"); + } + + return GLFW_FALSE; + } + + for (i = 0; prefixes[i]; i++) + { + const size_t length = strlen(prefixes[i]); + + if (strncmp(version, prefixes[i], length) == 0) + { + version += length; + window->context.client = GLFW_OPENGL_ES_API; + break; + } + } + + if (!sscanf(version, "%d.%d.%d", + &window->context.major, + &window->context.minor, + &window->context.revision)) + { + if (window->context.client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "No version found in OpenGL version string"); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "No version found in OpenGL ES version string"); + } + + return GLFW_FALSE; + } + + if (window->context.major < ctxconfig->major || + (window->context.major == ctxconfig->major && + window->context.minor < ctxconfig->minor)) + { + // The desired OpenGL version is greater than the actual version + // This only happens if the machine lacks {GLX|WGL}_ARB_create_context + // /and/ the user has requested an OpenGL version greater than 1.0 + + // For API consistency, we emulate the behavior of the + // {GLX|WGL}_ARB_create_context extension and fail here + + if (window->context.client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "Requested OpenGL version %i.%i, got version %i.%i", + ctxconfig->major, ctxconfig->minor, + window->context.major, window->context.minor); + } + else + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "Requested OpenGL ES version %i.%i, got version %i.%i", + ctxconfig->major, ctxconfig->minor, + window->context.major, window->context.minor); + } + + return GLFW_FALSE; + } + + if (window->context.major >= 3) + { + // OpenGL 3.0+ uses a different function for extension string retrieval + // We cache it here instead of in glfwExtensionSupported mostly to alert + // users as early as possible that their build may be broken + + window->context.GetStringi = (PFNGLGETSTRINGIPROC) + window->context.getProcAddress("glGetStringi"); + if (!window->context.GetStringi) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Entry point retrieval is broken"); + return GLFW_FALSE; + } + } + + if (window->context.client == GLFW_OPENGL_API) + { + // Read back context flags (OpenGL 3.0 and above) + if (window->context.major >= 3) + { + GLint flags; + window->context.GetIntegerv(GL_CONTEXT_FLAGS, &flags); + + if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) + window->context.forward = GLFW_TRUE; + + if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) + window->context.debug = GLFW_TRUE; + else if (glfwExtensionSupported("GL_ARB_debug_output") && + ctxconfig->debug) + { + // HACK: This is a workaround for older drivers (pre KHR_debug) + // not setting the debug bit in the context flags for + // debug contexts + window->context.debug = GLFW_TRUE; + } + + if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR) + window->context.noerror = GLFW_TRUE; + } + + // Read back OpenGL context profile (OpenGL 3.2 and above) + if (window->context.major >= 4 || + (window->context.major == 3 && window->context.minor >= 2)) + { + GLint mask; + window->context.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); + + if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) + window->context.profile = GLFW_OPENGL_COMPAT_PROFILE; + else if (mask & GL_CONTEXT_CORE_PROFILE_BIT) + window->context.profile = GLFW_OPENGL_CORE_PROFILE; + else if (glfwExtensionSupported("GL_ARB_compatibility")) + { + // HACK: This is a workaround for the compatibility profile bit + // not being set in the context flags if an OpenGL 3.2+ + // context was created without having requested a specific + // version + window->context.profile = GLFW_OPENGL_COMPAT_PROFILE; + } + } + + // Read back robustness strategy + if (glfwExtensionSupported("GL_ARB_robustness")) + { + // NOTE: We avoid using the context flags for detection, as they are + // only present from 3.0 while the extension applies from 1.1 + + GLint strategy; + window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, + &strategy); + + if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) + window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; + else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) + window->context.robustness = GLFW_NO_RESET_NOTIFICATION; + } + } + else + { + // Read back robustness strategy + if (glfwExtensionSupported("GL_EXT_robustness")) + { + // NOTE: The values of these constants match those of the OpenGL ARB + // one, so we can reuse them here + + GLint strategy; + window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, + &strategy); + + if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) + window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; + else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) + window->context.robustness = GLFW_NO_RESET_NOTIFICATION; + } + } + + if (glfwExtensionSupported("GL_KHR_context_flush_control")) + { + GLint behavior; + window->context.GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior); + + if (behavior == GL_NONE) + window->context.release = GLFW_RELEASE_BEHAVIOR_NONE; + else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH) + window->context.release = GLFW_RELEASE_BEHAVIOR_FLUSH; + } + + // Clearing the front buffer to black to avoid garbage pixels left over from + // previous uses of our bit of VRAM + { + PFNGLCLEARPROC glClear = (PFNGLCLEARPROC) + window->context.getProcAddress("glClear"); + glClear(GL_COLOR_BUFFER_BIT); + window->context.swapBuffers(window); + } + + return GLFW_TRUE; +} + +GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions) +{ + const char* start = extensions; + + for (;;) + { + const char* where; + const char* terminator; + + where = strstr(start, string); + if (!where) + return GLFW_FALSE; + + terminator = where + strlen(string); + if (where == start || *(where - 1) == ' ') + { + if (*terminator == ' ' || *terminator == '\0') + break; + } + + start = terminator; + } + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFWwindow* previous = _glfwPlatformGetCurrentContext(); + + _GLFW_REQUIRE_INIT(); + + if (window && window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return; + } + + if (previous) + { + if (!window || window->context.source != previous->context.source) + previous->context.makeCurrent(NULL); + } + + if (window) + window->context.makeCurrent(window); +} + +GLFWAPI GLFWwindow* glfwGetCurrentContext(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return (GLFWwindow*) _glfwPlatformGetCurrentContext(); +} + +GLFWAPI void glfwSwapBuffers(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return; + } + + window->context.swapBuffers(window); +} + +GLFWAPI void glfwSwapInterval(int interval) +{ + _GLFWwindow* window; + + _GLFW_REQUIRE_INIT(); + + window = _glfwPlatformGetCurrentContext(); + if (!window) + { + _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); + return; + } + + window->context.swapInterval(interval); +} + +GLFWAPI int glfwExtensionSupported(const char* extension) +{ + _GLFWwindow* window; + + assert(extension != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + window = _glfwPlatformGetCurrentContext(); + if (!window) + { + _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); + return GLFW_FALSE; + } + + if (*extension == '\0') + { + _glfwInputError(GLFW_INVALID_VALUE, "Extension name is empty string"); + return GLFW_FALSE; + } + + if (window->context.major >= 3) + { + int i; + GLint count; + + // Check if extension is in the modern OpenGL extensions string list + + window->context.GetIntegerv(GL_NUM_EXTENSIONS, &count); + + for (i = 0; i < count; i++) + { + const char* en = (const char*) + window->context.GetStringi(GL_EXTENSIONS, i); + if (!en) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Extension string retrieval is broken"); + return GLFW_FALSE; + } + + if (strcmp(en, extension) == 0) + return GLFW_TRUE; + } + } + else + { + // Check if extension is in the old style OpenGL extensions string + + const char* extensions = (const char*) + window->context.GetString(GL_EXTENSIONS); + if (!extensions) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Extension string retrieval is broken"); + return GLFW_FALSE; + } + + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + + // Check if extension is in the platform-specific string + return window->context.extensionSupported(extension); +} + +GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname) +{ + _GLFWwindow* window; + assert(procname != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + window = _glfwPlatformGetCurrentContext(); + if (!window) + { + _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); + return NULL; + } + + return window->context.getProcAddress(procname); +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/egl_context.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/egl_context.c new file mode 100644 index 00000000..e3d6260a --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/egl_context.c @@ -0,0 +1,746 @@ +//======================================================================== +// GLFW 3.2 EGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include + + +// Return a description of the specified EGL error +// +static const char* getEGLErrorString(EGLint error) +{ + switch (error) + { + case EGL_SUCCESS: + return "Success"; + case EGL_NOT_INITIALIZED: + return "EGL is not or could not be initialized"; + case EGL_BAD_ACCESS: + return "EGL cannot access a requested resource"; + case EGL_BAD_ALLOC: + return "EGL failed to allocate resources for the requested operation"; + case EGL_BAD_ATTRIBUTE: + return "An unrecognized attribute or attribute value was passed in the attribute list"; + case EGL_BAD_CONTEXT: + return "An EGLContext argument does not name a valid EGL rendering context"; + case EGL_BAD_CONFIG: + return "An EGLConfig argument does not name a valid EGL frame buffer configuration"; + case EGL_BAD_CURRENT_SURFACE: + return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid"; + case EGL_BAD_DISPLAY: + return "An EGLDisplay argument does not name a valid EGL display connection"; + case EGL_BAD_SURFACE: + return "An EGLSurface argument does not name a valid surface configured for GL rendering"; + case EGL_BAD_MATCH: + return "Arguments are inconsistent"; + case EGL_BAD_PARAMETER: + return "One or more argument values are invalid"; + case EGL_BAD_NATIVE_PIXMAP: + return "A NativePixmapType argument does not refer to a valid native pixmap"; + case EGL_BAD_NATIVE_WINDOW: + return "A NativeWindowType argument does not refer to a valid native window"; + case EGL_CONTEXT_LOST: + return "The application must destroy all contexts and reinitialise"; + default: + return "ERROR: UNKNOWN EGL ERROR"; + } +} + +// Returns the specified attribute of the specified EGLConfig +// +static int getEGLConfigAttrib(EGLConfig config, int attrib) +{ + int value; + eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value); + return value; +} + +// Return the EGLConfig most closely matching the specified hints +// +static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* desired, + EGLConfig* result) +{ + EGLConfig* nativeConfigs; + _GLFWfbconfig* usableConfigs; + const _GLFWfbconfig* closest; + int i, nativeCount, usableCount; + + eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); + if (!nativeCount) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned"); + return GLFW_FALSE; + } + + nativeConfigs = calloc(nativeCount, sizeof(EGLConfig)); + eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount); + + usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableCount = 0; + + for (i = 0; i < nativeCount; i++) + { + const EGLConfig n = nativeConfigs[i]; + _GLFWfbconfig* u = usableConfigs + usableCount; + + // Only consider RGB(A) EGLConfigs + if (!(getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) & EGL_RGB_BUFFER)) + continue; + + // Only consider window EGLConfigs + if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT)) + continue; + +#if defined(_GLFW_X11) + // Only consider EGLConfigs with associated Visuals + if (!getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID)) + continue; +#endif // _GLFW_X11 + + if (ctxconfig->client == GLFW_OPENGL_ES_API) + { + if (ctxconfig->major == 1) + { + if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT)) + continue; + } + else + { + if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT)) + continue; + } + } + else if (ctxconfig->client == GLFW_OPENGL_API) + { + if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT)) + continue; + } + + u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE); + u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE); + u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE); + + u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE); + u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE); + u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE); + + u->samples = getEGLConfigAttrib(n, EGL_SAMPLES); + u->doublebuffer = GLFW_TRUE; + + u->handle = (uintptr_t) n; + usableCount++; + } + + closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); + if (closest) + *result = (EGLConfig) closest->handle; + + free(nativeConfigs); + free(usableConfigs); + + return closest != NULL; +} + +static void makeContextCurrentEGL(_GLFWwindow* window) +{ + if (window) + { + if (!eglMakeCurrent(_glfw.egl.display, + window->context.egl.surface, + window->context.egl.surface, + window->context.egl.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to make context current: %s", + getEGLErrorString(eglGetError())); + return; + } + } + else + { + if (!eglMakeCurrent(_glfw.egl.display, + EGL_NO_SURFACE, + EGL_NO_SURFACE, + EGL_NO_CONTEXT)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to clear current context: %s", + getEGLErrorString(eglGetError())); + return; + } + } + + _glfwPlatformSetCurrentContext(window); +} + +static void swapBuffersEGL(_GLFWwindow* window) +{ + if (window != _glfwPlatformGetCurrentContext()) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: The context must be current on the calling thread when swapping buffers"); + return; + } + + eglSwapBuffers(_glfw.egl.display, window->context.egl.surface); +} + +static void swapIntervalEGL(int interval) +{ + eglSwapInterval(_glfw.egl.display, interval); +} + +static int extensionSupportedEGL(const char* extension) +{ + const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddressEGL(const char* procname) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + if (window->context.egl.client) + { + GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client, + procname); + if (proc) + return proc; + } + + return eglGetProcAddress(procname); +} + +static void destroyContextEGL(_GLFWwindow* window) +{ +#if defined(_GLFW_X11) + // NOTE: Do not unload libGL.so.1 while the X11 display is still open, + // as it will make XCloseDisplay segfault + if (window->context.client != GLFW_OPENGL_API) +#endif // _GLFW_X11 + { + if (window->context.egl.client) + { + _glfw_dlclose(window->context.egl.client); + window->context.egl.client = NULL; + } + } + + if (window->context.egl.surface) + { + eglDestroySurface(_glfw.egl.display, window->context.egl.surface); + window->context.egl.surface = EGL_NO_SURFACE; + } + + if (window->context.egl.handle) + { + eglDestroyContext(_glfw.egl.display, window->context.egl.handle); + window->context.egl.handle = EGL_NO_CONTEXT; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize EGL +// +GLFWbool _glfwInitEGL(void) +{ + int i; + const char* sonames[] = + { +#if defined(_GLFW_WIN32) + "libEGL.dll", + "EGL.dll", +#elif defined(_GLFW_COCOA) + "libEGL.dylib", +#else + "libEGL.so.1", +#endif + NULL + }; + + if (_glfw.egl.handle) + return GLFW_TRUE; + + for (i = 0; sonames[i]; i++) + { + _glfw.egl.handle = _glfw_dlopen(sonames[i]); + if (_glfw.egl.handle) + break; + } + + if (!_glfw.egl.handle) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found"); + return GLFW_FALSE; + } + + _glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0); + + _glfw.egl.GetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) + _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib"); + _glfw.egl.GetConfigs = (PFNEGLGETCONFIGSPROC) + _glfw_dlsym(_glfw.egl.handle, "eglGetConfigs"); + _glfw.egl.GetDisplay = (PFNEGLGETDISPLAYPROC) + _glfw_dlsym(_glfw.egl.handle, "eglGetDisplay"); + _glfw.egl.GetError = (PFNEGLGETERRORPROC) + _glfw_dlsym(_glfw.egl.handle, "eglGetError"); + _glfw.egl.Initialize = (PFNEGLINITIALIZEPROC) + _glfw_dlsym(_glfw.egl.handle, "eglInitialize"); + _glfw.egl.Terminate = (PFNEGLTERMINATEPROC) + _glfw_dlsym(_glfw.egl.handle, "eglTerminate"); + _glfw.egl.BindAPI = (PFNEGLBINDAPIPROC) + _glfw_dlsym(_glfw.egl.handle, "eglBindAPI"); + _glfw.egl.CreateContext = (PFNEGLCREATECONTEXTPROC) + _glfw_dlsym(_glfw.egl.handle, "eglCreateContext"); + _glfw.egl.DestroySurface = (PFNEGLDESTROYSURFACEPROC) + _glfw_dlsym(_glfw.egl.handle, "eglDestroySurface"); + _glfw.egl.DestroyContext = (PFNEGLDESTROYCONTEXTPROC) + _glfw_dlsym(_glfw.egl.handle, "eglDestroyContext"); + _glfw.egl.CreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) + _glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface"); + _glfw.egl.MakeCurrent = (PFNEGLMAKECURRENTPROC) + _glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent"); + _glfw.egl.SwapBuffers = (PFNEGLSWAPBUFFERSPROC) + _glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers"); + _glfw.egl.SwapInterval = (PFNEGLSWAPINTERVALPROC) + _glfw_dlsym(_glfw.egl.handle, "eglSwapInterval"); + _glfw.egl.QueryString = (PFNEGLQUERYSTRINGPROC) + _glfw_dlsym(_glfw.egl.handle, "eglQueryString"); + _glfw.egl.GetProcAddress = (PFNEGLGETPROCADDRESSPROC) + _glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress"); + + if (!_glfw.egl.GetConfigAttrib || + !_glfw.egl.GetConfigs || + !_glfw.egl.GetDisplay || + !_glfw.egl.GetError || + !_glfw.egl.Initialize || + !_glfw.egl.Terminate || + !_glfw.egl.BindAPI || + !_glfw.egl.CreateContext || + !_glfw.egl.DestroySurface || + !_glfw.egl.DestroyContext || + !_glfw.egl.CreateWindowSurface || + !_glfw.egl.MakeCurrent || + !_glfw.egl.SwapBuffers || + !_glfw.egl.SwapInterval || + !_glfw.egl.QueryString || + !_glfw.egl.GetProcAddress) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to load required entry points"); + + _glfwTerminateEGL(); + return GLFW_FALSE; + } + + _glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY); + if (_glfw.egl.display == EGL_NO_DISPLAY) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to get EGL display: %s", + getEGLErrorString(eglGetError())); + + _glfwTerminateEGL(); + return GLFW_FALSE; + } + + if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to initialize EGL: %s", + getEGLErrorString(eglGetError())); + + _glfwTerminateEGL(); + return GLFW_FALSE; + } + + _glfw.egl.KHR_create_context = + extensionSupportedEGL("EGL_KHR_create_context"); + _glfw.egl.KHR_create_context_no_error = + extensionSupportedEGL("EGL_KHR_create_context_no_error"); + _glfw.egl.KHR_gl_colorspace = + extensionSupportedEGL("EGL_KHR_gl_colorspace"); + + return GLFW_TRUE; +} + +// Terminate EGL +// +void _glfwTerminateEGL(void) +{ + if (_glfw.egl.display) + { + eglTerminate(_glfw.egl.display); + _glfw.egl.display = EGL_NO_DISPLAY; + } + + if (_glfw.egl.handle) + { + _glfw_dlclose(_glfw.egl.handle); + _glfw.egl.handle = NULL; + } +} + +#define setEGLattrib(attribName, attribValue) \ +{ \ + attribs[index++] = attribName; \ + attribs[index++] = attribValue; \ + assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ +} + +// Create the OpenGL or OpenGL ES context +// +GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + EGLint attribs[40]; + EGLConfig config; + EGLContext share = NULL; + + if (!_glfw.egl.display) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available"); + return GLFW_FALSE; + } + + if (ctxconfig->share) + share = ctxconfig->share->context.egl.handle; + + if (!chooseEGLConfig(ctxconfig, fbconfig, &config)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "EGL: Failed to find a suitable EGLConfig"); + return GLFW_FALSE; + } + + if (ctxconfig->client == GLFW_OPENGL_ES_API) + { + if (!eglBindAPI(EGL_OPENGL_ES_API)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to bind OpenGL ES: %s", + getEGLErrorString(eglGetError())); + return GLFW_FALSE; + } + } + else + { + if (!eglBindAPI(EGL_OPENGL_API)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to bind OpenGL: %s", + getEGLErrorString(eglGetError())); + return GLFW_FALSE; + } + } + + if (_glfw.egl.KHR_create_context) + { + int index = 0, mask = 0, flags = 0; + + if (ctxconfig->client == GLFW_OPENGL_API) + { + if (ctxconfig->forward) + flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; + + if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) + mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; + else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) + mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; + + if (_glfw.egl.KHR_create_context_no_error) + { + if (ctxconfig->noerror) + flags |= EGL_CONTEXT_OPENGL_NO_ERROR_KHR; + } + } + + if (ctxconfig->debug) + flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; + + if (ctxconfig->robustness) + { + if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) + { + setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_NO_RESET_NOTIFICATION_KHR); + } + else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) + { + setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_LOSE_CONTEXT_ON_RESET_KHR); + } + + flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; + } + + if (ctxconfig->major != 1 || ctxconfig->minor != 0) + { + setEGLattrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); + setEGLattrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor); + } + + if (mask) + setEGLattrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); + + if (flags) + setEGLattrib(EGL_CONTEXT_FLAGS_KHR, flags); + + setEGLattrib(EGL_NONE, EGL_NONE); + } + else + { + int index = 0; + + if (ctxconfig->client == GLFW_OPENGL_ES_API) + setEGLattrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); + + setEGLattrib(EGL_NONE, EGL_NONE); + } + + // Context release behaviors (GL_KHR_context_flush_control) are not yet + // supported on EGL but are not a hard constraint, so ignore and continue + + window->context.egl.handle = eglCreateContext(_glfw.egl.display, + config, share, attribs); + + if (window->context.egl.handle == EGL_NO_CONTEXT) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "EGL: Failed to create context: %s", + getEGLErrorString(eglGetError())); + return GLFW_FALSE; + } + + // Set up attributes for surface creation + { + int index = 0; + + if (fbconfig->sRGB) + { + if (_glfw.egl.KHR_gl_colorspace) + { + setEGLattrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); + } + } + + setEGLattrib(EGL_NONE, EGL_NONE); + } + + window->context.egl.surface = + eglCreateWindowSurface(_glfw.egl.display, + config, + _GLFW_EGL_NATIVE_WINDOW, + attribs); + if (window->context.egl.surface == EGL_NO_SURFACE) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to create window surface: %s", + getEGLErrorString(eglGetError())); + return GLFW_FALSE; + } + + window->context.egl.config = config; + + // Load the appropriate client library + { + int i; + const char** sonames; + const char* es1sonames[] = + { +#if defined(_GLFW_WIN32) + "GLESv1_CM.dll", + "libGLES_CM.dll", +#elif defined(_GLFW_COCOA) + "libGLESv1_CM.dylib", +#else + "libGLESv1_CM.so.1", + "libGLES_CM.so.1", +#endif + NULL + }; + const char* es2sonames[] = + { +#if defined(_GLFW_WIN32) + "GLESv2.dll", + "libGLESv2.dll", +#elif defined(_GLFW_COCOA) + "libGLESv2.dylib", +#else + "libGLESv2.so.2", +#endif + NULL + }; + const char* glsonames[] = + { +#if defined(_GLFW_WIN32) +#elif defined(_GLFW_COCOA) +#else + "libGL.so.1", +#endif + NULL + }; + + if (ctxconfig->client == GLFW_OPENGL_ES_API) + { + if (ctxconfig->major == 1) + sonames = es1sonames; + else + sonames = es2sonames; + } + else + sonames = glsonames; + + for (i = 0; sonames[i]; i++) + { + // HACK: Match presence of lib prefix to increase chance of finding + // a matching pair in the jungle that is Win32 EGL/GLES + if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0)) + continue; + + window->context.egl.client = _glfw_dlopen(sonames[i]); + if (window->context.egl.client) + break; + } + + if (!window->context.egl.client) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to load client library"); + return GLFW_FALSE; + } + } + + window->context.makeCurrent = makeContextCurrentEGL; + window->context.swapBuffers = swapBuffersEGL; + window->context.swapInterval = swapIntervalEGL; + window->context.extensionSupported = extensionSupportedEGL; + window->context.getProcAddress = getProcAddressEGL; + window->context.destroy = destroyContextEGL; + + return GLFW_TRUE; +} + +#undef setEGLattrib + +// Returns the Visual and depth of the chosen EGLConfig +// +#if defined(_GLFW_X11) +GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig, + Visual** visual, int* depth) +{ + XVisualInfo* result; + XVisualInfo desired; + EGLConfig native; + EGLint visualID = 0, count = 0; + const long vimask = VisualScreenMask | VisualIDMask; + + if (!chooseEGLConfig(ctxconfig, fbconfig, &native)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "EGL: Failed to find a suitable EGLConfig"); + return GLFW_FALSE; + } + + eglGetConfigAttrib(_glfw.egl.display, native, + EGL_NATIVE_VISUAL_ID, &visualID); + + desired.screen = _glfw.x11.screen; + desired.visualid = visualID; + + result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count); + if (!result) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to retrieve Visual for EGLConfig"); + return GLFW_FALSE; + } + + *visual = result->visual; + *depth = result->depth; + + XFree(result); + return GLFW_TRUE; +} +#endif // _GLFW_X11 + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI EGLDisplay glfwGetEGLDisplay(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY); + return _glfw.egl.display; +} + +GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return EGL_NO_CONTEXT; + } + + return window->context.egl.handle; +} + +GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return EGL_NO_SURFACE; + } + + return window->context.egl.surface; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/egl_context.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/egl_context.h new file mode 100644 index 00000000..9bd8bb40 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/egl_context.h @@ -0,0 +1,213 @@ +//======================================================================== +// GLFW 3.2 EGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_egl_context_h_ +#define _glfw3_egl_context_h_ + +#if defined(_GLFW_USE_EGLPLATFORM_H) + #include +#elif defined(_GLFW_WIN32) + #define EGLAPIENTRY __stdcall +typedef HDC EGLNativeDisplayType; +typedef HWND EGLNativeWindowType; +#elif defined(_GLFW_X11) + #define EGLAPIENTRY +typedef Display* EGLNativeDisplayType; +typedef Window EGLNativeWindowType; +#elif defined(_GLFW_WAYLAND) + #define EGLAPIENTRY +typedef struct wl_display* EGLNativeDisplayType; +typedef struct wl_egl_window* EGLNativeWindowType; +#elif defined(_GLFW_MIR) + #define EGLAPIENTRY +typedef MirEGLNativeDisplayType EGLNativeDisplayType; +typedef MirEGLNativeWindowType EGLNativeWindowType; +#else + #error "No supported EGL platform selected" +#endif + +#define EGL_SUCCESS 0x3000 +#define EGL_NOT_INITIALIZED 0x3001 +#define EGL_BAD_ACCESS 0x3002 +#define EGL_BAD_ALLOC 0x3003 +#define EGL_BAD_ATTRIBUTE 0x3004 +#define EGL_BAD_CONFIG 0x3005 +#define EGL_BAD_CONTEXT 0x3006 +#define EGL_BAD_CURRENT_SURFACE 0x3007 +#define EGL_BAD_DISPLAY 0x3008 +#define EGL_BAD_MATCH 0x3009 +#define EGL_BAD_NATIVE_PIXMAP 0x300a +#define EGL_BAD_NATIVE_WINDOW 0x300b +#define EGL_BAD_PARAMETER 0x300c +#define EGL_BAD_SURFACE 0x300d +#define EGL_CONTEXT_LOST 0x300e +#define EGL_COLOR_BUFFER_TYPE 0x303f +#define EGL_RGB_BUFFER 0x308e +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_WINDOW_BIT 0x0004 +#define EGL_RENDERABLE_TYPE 0x3040 +#define EGL_OPENGL_ES_BIT 0x0001 +#define EGL_OPENGL_ES2_BIT 0x0004 +#define EGL_OPENGL_BIT 0x0008 +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_BLUE_SIZE 0x3022 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_RED_SIZE 0x3024 +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_STENCIL_SIZE 0x3026 +#define EGL_SAMPLES 0x3031 +#define EGL_OPENGL_ES_API 0x30a0 +#define EGL_OPENGL_API 0x30a2 +#define EGL_NONE 0x3038 +#define EGL_EXTENSIONS 0x3055 +#define EGL_CONTEXT_CLIENT_VERSION 0x3098 +#define EGL_NATIVE_VISUAL_ID 0x302e +#define EGL_NO_SURFACE ((EGLSurface) 0) +#define EGL_NO_DISPLAY ((EGLDisplay) 0) +#define EGL_NO_CONTEXT ((EGLContext) 0) +#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0) + +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 +#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31bd +#define EGL_NO_RESET_NOTIFICATION_KHR 0x31be +#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31bf +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 +#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 +#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30fb +#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30fd +#define EGL_CONTEXT_FLAGS_KHR 0x30fc +#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3 +#define EGL_GL_COLORSPACE_KHR 0x309d +#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 + +typedef int EGLint; +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; +typedef void* EGLConfig; +typedef void* EGLContext; +typedef void* EGLDisplay; +typedef void* EGLSurface; + +// EGL function pointer typedefs +typedef EGLBoolean (EGLAPIENTRY * PFNEGLGETCONFIGATTRIBPROC)(EGLDisplay,EGLConfig,EGLint,EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLGETCONFIGSPROC)(EGLDisplay,EGLConfig*,EGLint,EGLint*); +typedef EGLDisplay (EGLAPIENTRY * PFNEGLGETDISPLAYPROC)(EGLNativeDisplayType); +typedef EGLint (EGLAPIENTRY * PFNEGLGETERRORPROC)(void); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLINITIALIZEPROC)(EGLDisplay,EGLint*,EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLTERMINATEPROC)(EGLDisplay); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLBINDAPIPROC)(EGLenum); +typedef EGLContext (EGLAPIENTRY * PFNEGLCREATECONTEXTPROC)(EGLDisplay,EGLConfig,EGLContext,const EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLDESTROYSURFACEPROC)(EGLDisplay,EGLSurface); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLDESTROYCONTEXTPROC)(EGLDisplay,EGLContext); +typedef EGLSurface (EGLAPIENTRY * PFNEGLCREATEWINDOWSURFACEPROC)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLMAKECURRENTPROC)(EGLDisplay,EGLSurface,EGLSurface,EGLContext); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLSWAPBUFFERSPROC)(EGLDisplay,EGLSurface); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLSWAPINTERVALPROC)(EGLDisplay,EGLint); +typedef const char* (EGLAPIENTRY * PFNEGLQUERYSTRINGPROC)(EGLDisplay,EGLint); +typedef GLFWglproc (EGLAPIENTRY * PFNEGLGETPROCADDRESSPROC)(const char*); +#define eglGetConfigAttrib _glfw.egl.GetConfigAttrib +#define eglGetConfigs _glfw.egl.GetConfigs +#define eglGetDisplay _glfw.egl.GetDisplay +#define eglGetError _glfw.egl.GetError +#define eglInitialize _glfw.egl.Initialize +#define eglTerminate _glfw.egl.Terminate +#define eglBindAPI _glfw.egl.BindAPI +#define eglCreateContext _glfw.egl.CreateContext +#define eglDestroySurface _glfw.egl.DestroySurface +#define eglDestroyContext _glfw.egl.DestroyContext +#define eglCreateWindowSurface _glfw.egl.CreateWindowSurface +#define eglMakeCurrent _glfw.egl.MakeCurrent +#define eglSwapBuffers _glfw.egl.SwapBuffers +#define eglSwapInterval _glfw.egl.SwapInterval +#define eglQueryString _glfw.egl.QueryString +#define eglGetProcAddress _glfw.egl.GetProcAddress + +#define _GLFW_EGL_CONTEXT_STATE _GLFWcontextEGL egl +#define _GLFW_EGL_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl + + +// EGL-specific per-context data +// +typedef struct _GLFWcontextEGL +{ + EGLConfig config; + EGLContext handle; + EGLSurface surface; + + void* client; + +} _GLFWcontextEGL; + +// EGL-specific global data +// +typedef struct _GLFWlibraryEGL +{ + EGLDisplay display; + EGLint major, minor; + GLFWbool prefix; + + GLFWbool KHR_create_context; + GLFWbool KHR_create_context_no_error; + GLFWbool KHR_gl_colorspace; + + void* handle; + + PFNEGLGETCONFIGATTRIBPROC GetConfigAttrib; + PFNEGLGETCONFIGSPROC GetConfigs; + PFNEGLGETDISPLAYPROC GetDisplay; + PFNEGLGETERRORPROC GetError; + PFNEGLINITIALIZEPROC Initialize; + PFNEGLTERMINATEPROC Terminate; + PFNEGLBINDAPIPROC BindAPI; + PFNEGLCREATECONTEXTPROC CreateContext; + PFNEGLDESTROYSURFACEPROC DestroySurface; + PFNEGLDESTROYCONTEXTPROC DestroyContext; + PFNEGLCREATEWINDOWSURFACEPROC CreateWindowSurface; + PFNEGLMAKECURRENTPROC MakeCurrent; + PFNEGLSWAPBUFFERSPROC SwapBuffers; + PFNEGLSWAPINTERVALPROC SwapInterval; + PFNEGLQUERYSTRINGPROC QueryString; + PFNEGLGETPROCADDRESSPROC GetProcAddress; + +} _GLFWlibraryEGL; + + +GLFWbool _glfwInitEGL(void); +void _glfwTerminateEGL(void); +GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +#if defined(_GLFW_X11) +GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig, + Visual** visual, int* depth); +#endif /*_GLFW_X11*/ + +#endif // _glfw3_egl_context_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glfw3.pc.in b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glfw3.pc.in new file mode 100644 index 00000000..f2e4d976 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glfw3.pc.in @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +includedir=${prefix}/include +libdir=${exec_prefix}/lib@LIB_SUFFIX@ + +Name: GLFW +Description: A multi-platform library for OpenGL, window and input +Version: @GLFW_VERSION_FULL@ +URL: http://www.glfw.org/ +Requires.private: @GLFW_PKG_DEPS@ +Libs: -L${libdir} -l@GLFW_LIB_NAME@ +Libs.private: @GLFW_PKG_LIBS@ +Cflags: -I${includedir} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glfw3Config.cmake.in b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glfw3Config.cmake.in new file mode 100644 index 00000000..1fa200e2 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glfw3Config.cmake.in @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/glfw3Targets.cmake") diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glfw_config.h.in b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glfw_config.h.in new file mode 100644 index 00000000..cf253d36 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glfw_config.h.in @@ -0,0 +1,65 @@ +//======================================================================== +// GLFW 3.2 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2010-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// As glfw_config.h.in, this file is used by CMake to produce the +// glfw_config.h configuration header file. If you are adding a feature +// requiring conditional compilation, this is where to add the macro. +//======================================================================== +// As glfw_config.h, this file defines compile-time option macros for a +// specific platform and development environment. If you are using the +// GLFW CMake files, modify glfw_config.h.in instead of this file. If you +// are using your own build system, make this file define the appropriate +// macros in whatever way is suitable. +//======================================================================== + +// Define this to 1 if building GLFW for X11 +#cmakedefine _GLFW_X11 +// Define this to 1 if building GLFW for Win32 +#cmakedefine _GLFW_WIN32 +// Define this to 1 if building GLFW for Cocoa +#cmakedefine _GLFW_COCOA +// Define this to 1 if building GLFW for Wayland +#cmakedefine _GLFW_WAYLAND +// Define this to 1 if building GLFW for Mir +#cmakedefine _GLFW_MIR + +// Define this to 1 if building as a shared library / dynamic library / DLL +#cmakedefine _GLFW_BUILD_DLL +// Define this to 1 to use Vulkan loader linked statically into application +#cmakedefine _GLFW_VULKAN_STATIC + +// Define this to 1 to force use of high-performance GPU on hybrid systems +#cmakedefine _GLFW_USE_HYBRID_HPG + +// Define this to 1 if the Xxf86vm X11 extension is available +#cmakedefine _GLFW_HAS_XF86VM + +// Define this to 1 if glfwInit should change the current directory +#cmakedefine _GLFW_USE_CHDIR +// Define this to 1 if glfwCreateWindow should populate the menu bar +#cmakedefine _GLFW_USE_MENUBAR +// Define this to 1 if windows should use full resolution on Retina displays +#cmakedefine _GLFW_USE_RETINA + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glx_context.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glx_context.c new file mode 100644 index 00000000..251b7fc4 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glx_context.c @@ -0,0 +1,677 @@ +//======================================================================== +// GLFW 3.2 GLX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + +#ifndef GLXBadProfileARB + #define GLXBadProfileARB 13 +#endif + + +// Returns the specified attribute of the specified GLXFBConfig +// +static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib) +{ + int value; + glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value); + return value; +} + +// Return the GLXFBConfig most closely matching the specified hints +// +static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result) +{ + GLXFBConfig* nativeConfigs; + _GLFWfbconfig* usableConfigs; + const _GLFWfbconfig* closest; + int i, nativeCount, usableCount; + const char* vendor; + GLFWbool trustWindowBit = GLFW_TRUE; + + // HACK: This is a (hopefully temporary) workaround for Chromium + // (VirtualBox GL) not setting the window bit on any GLXFBConfigs + vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR); + if (strcmp(vendor, "Chromium") == 0) + trustWindowBit = GLFW_FALSE; + + nativeConfigs = + glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount); + if (!nativeCount) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned"); + return GLFW_FALSE; + } + + usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableCount = 0; + + for (i = 0; i < nativeCount; i++) + { + const GLXFBConfig n = nativeConfigs[i]; + _GLFWfbconfig* u = usableConfigs + usableCount; + + // Only consider RGBA GLXFBConfigs + if (!(getGLXFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT)) + continue; + + // Only consider window GLXFBConfigs + if (!(getGLXFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT)) + { + if (trustWindowBit) + continue; + } + + u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE); + u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE); + u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE); + + u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE); + u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE); + u->stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE); + + u->accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE); + u->accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE); + u->accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE); + u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE); + + u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS); + + if (getGLXFBConfigAttrib(n, GLX_STEREO)) + u->stereo = GLFW_TRUE; + if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER)) + u->doublebuffer = GLFW_TRUE; + + if (_glfw.glx.ARB_multisample) + u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES); + + if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB) + u->sRGB = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB); + + u->handle = (uintptr_t) n; + usableCount++; + } + + closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); + if (closest) + *result = (GLXFBConfig) closest->handle; + + XFree(nativeConfigs); + free(usableConfigs); + + return closest != NULL; +} + +// Create the OpenGL context using legacy API +// +static GLXContext createLegacyContextGLX(_GLFWwindow* window, + GLXFBConfig fbconfig, + GLXContext share) +{ + return glXCreateNewContext(_glfw.x11.display, + fbconfig, + GLX_RGBA_TYPE, + share, + True); +} + +static void makeContextCurrentGLX(_GLFWwindow* window) +{ + if (window) + { + if (!glXMakeCurrent(_glfw.x11.display, + window->context.glx.window, + window->context.glx.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to make context current"); + return; + } + } + else + { + if (!glXMakeCurrent(_glfw.x11.display, None, NULL)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to clear current context"); + return; + } + } + + _glfwPlatformSetCurrentContext(window); +} + +static void swapBuffersGLX(_GLFWwindow* window) +{ + glXSwapBuffers(_glfw.x11.display, window->context.glx.window); +} + +static void swapIntervalGLX(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + if (_glfw.glx.EXT_swap_control) + { + _glfw.glx.SwapIntervalEXT(_glfw.x11.display, + window->context.glx.window, + interval); + } + else if (_glfw.glx.MESA_swap_control) + _glfw.glx.SwapIntervalMESA(interval); + else if (_glfw.glx.SGI_swap_control) + { + if (interval > 0) + _glfw.glx.SwapIntervalSGI(interval); + } +} + +static int extensionSupportedGLX(const char* extension) +{ + const char* extensions = + glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddressGLX(const char* procname) +{ + if (_glfw.glx.GetProcAddress) + return _glfw.glx.GetProcAddress((const GLubyte*) procname); + else if (_glfw.glx.GetProcAddressARB) + return _glfw.glx.GetProcAddressARB((const GLubyte*) procname); + else + return dlsym(_glfw.glx.handle, procname); +} + +// Destroy the OpenGL context +// +static void destroyContextGLX(_GLFWwindow* window) +{ + if (window->context.glx.window) + { + glXDestroyWindow(_glfw.x11.display, window->context.glx.window); + window->context.glx.window = None; + } + + if (window->context.glx.handle) + { + glXDestroyContext(_glfw.x11.display, window->context.glx.handle); + window->context.glx.handle = NULL; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize GLX +// +GLFWbool _glfwInitGLX(void) +{ + int i; + const char* sonames[] = + { +#if defined(__CYGWIN__) + "libGL-1.so", +#else + "libGL.so.1", + "libGL.so", +#endif + NULL + }; + + if (_glfw.glx.handle) + return GLFW_TRUE; + + for (i = 0; sonames[i]; i++) + { + _glfw.glx.handle = dlopen(sonames[i], RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.glx.handle) + break; + } + + if (!_glfw.glx.handle) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX"); + return GLFW_FALSE; + } + + _glfw.glx.GetFBConfigs = + dlsym(_glfw.glx.handle, "glXGetFBConfigs"); + _glfw.glx.GetFBConfigAttrib = + dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib"); + _glfw.glx.GetClientString = + dlsym(_glfw.glx.handle, "glXGetClientString"); + _glfw.glx.QueryExtension = + dlsym(_glfw.glx.handle, "glXQueryExtension"); + _glfw.glx.QueryVersion = + dlsym(_glfw.glx.handle, "glXQueryVersion"); + _glfw.glx.DestroyContext = + dlsym(_glfw.glx.handle, "glXDestroyContext"); + _glfw.glx.MakeCurrent = + dlsym(_glfw.glx.handle, "glXMakeCurrent"); + _glfw.glx.SwapBuffers = + dlsym(_glfw.glx.handle, "glXSwapBuffers"); + _glfw.glx.QueryExtensionsString = + dlsym(_glfw.glx.handle, "glXQueryExtensionsString"); + _glfw.glx.CreateNewContext = + dlsym(_glfw.glx.handle, "glXCreateNewContext"); + _glfw.glx.CreateWindow = + dlsym(_glfw.glx.handle, "glXCreateWindow"); + _glfw.glx.DestroyWindow = + dlsym(_glfw.glx.handle, "glXDestroyWindow"); + _glfw.glx.GetProcAddress = + dlsym(_glfw.glx.handle, "glXGetProcAddress"); + _glfw.glx.GetProcAddressARB = + dlsym(_glfw.glx.handle, "glXGetProcAddressARB"); + _glfw.glx.GetVisualFromFBConfig = + dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig"); + + if (!_glfw.glx.GetFBConfigs || + !_glfw.glx.GetFBConfigAttrib || + !_glfw.glx.GetClientString || + !_glfw.glx.QueryExtension || + !_glfw.glx.QueryVersion || + !_glfw.glx.DestroyContext || + !_glfw.glx.MakeCurrent || + !_glfw.glx.SwapBuffers || + !_glfw.glx.QueryExtensionsString || + !_glfw.glx.CreateNewContext || + !_glfw.glx.CreateWindow || + !_glfw.glx.DestroyWindow || + !_glfw.glx.GetProcAddress || + !_glfw.glx.GetProcAddressARB || + !_glfw.glx.GetVisualFromFBConfig) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to load required entry points"); + return GLFW_FALSE; + } + + if (!glXQueryExtension(_glfw.x11.display, + &_glfw.glx.errorBase, + &_glfw.glx.eventBase)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found"); + return GLFW_FALSE; + } + + if (!glXQueryVersion(_glfw.x11.display, &_glfw.glx.major, &_glfw.glx.minor)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "GLX: Failed to query GLX version"); + return GLFW_FALSE; + } + + if (_glfw.glx.major == 1 && _glfw.glx.minor < 3) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "GLX: GLX version 1.3 is required"); + return GLFW_FALSE; + } + + if (extensionSupportedGLX("GLX_EXT_swap_control")) + { + _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) + getProcAddressGLX("glXSwapIntervalEXT"); + + if (_glfw.glx.SwapIntervalEXT) + _glfw.glx.EXT_swap_control = GLFW_TRUE; + } + + if (extensionSupportedGLX("GLX_SGI_swap_control")) + { + _glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) + getProcAddressGLX("glXSwapIntervalSGI"); + + if (_glfw.glx.SwapIntervalSGI) + _glfw.glx.SGI_swap_control = GLFW_TRUE; + } + + if (extensionSupportedGLX("GLX_MESA_swap_control")) + { + _glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC) + getProcAddressGLX("glXSwapIntervalMESA"); + + if (_glfw.glx.SwapIntervalMESA) + _glfw.glx.MESA_swap_control = GLFW_TRUE; + } + + if (extensionSupportedGLX("GLX_ARB_multisample")) + _glfw.glx.ARB_multisample = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_framebuffer_sRGB")) + _glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_EXT_framebuffer_sRGB")) + _glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_create_context")) + { + _glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) + getProcAddressGLX("glXCreateContextAttribsARB"); + + if (_glfw.glx.CreateContextAttribsARB) + _glfw.glx.ARB_create_context = GLFW_TRUE; + } + + if (extensionSupportedGLX("GLX_ARB_create_context_robustness")) + _glfw.glx.ARB_create_context_robustness = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_create_context_profile")) + _glfw.glx.ARB_create_context_profile = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_EXT_create_context_es2_profile")) + _glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_context_flush_control")) + _glfw.glx.ARB_context_flush_control = GLFW_TRUE; + + return GLFW_TRUE; +} + +// Terminate GLX +// +void _glfwTerminateGLX(void) +{ + // NOTE: This function must not call any X11 functions, as it is called + // after XCloseDisplay (see _glfwPlatformTerminate for details) + + if (_glfw.glx.handle) + { + dlclose(_glfw.glx.handle); + _glfw.glx.handle = NULL; + } +} + +#define setGLXattrib(attribName, attribValue) \ +{ \ + attribs[index++] = attribName; \ + attribs[index++] = attribValue; \ + assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ +} + +// Create the OpenGL or OpenGL ES context +// +GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + int attribs[40]; + GLXFBConfig native = NULL; + GLXContext share = NULL; + + if (ctxconfig->share) + share = ctxconfig->share->context.glx.handle; + + if (!chooseGLXFBConfig(fbconfig, &native)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "GLX: Failed to find a suitable GLXFBConfig"); + return GLFW_FALSE; + } + + if (ctxconfig->client == GLFW_OPENGL_ES_API) + { + if (!_glfw.glx.ARB_create_context || + !_glfw.glx.ARB_create_context_profile || + !_glfw.glx.EXT_create_context_es2_profile) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "GLX: OpenGL ES requested but GLX_EXT_create_context_es2_profile is unavailable"); + return GLFW_FALSE; + } + } + + if (ctxconfig->forward) + { + if (!_glfw.glx.ARB_create_context) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable"); + return GLFW_FALSE; + } + } + + if (ctxconfig->profile) + { + if (!_glfw.glx.ARB_create_context || + !_glfw.glx.ARB_create_context_profile) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "GLX: An OpenGL profile requested but GLX_ARB_create_context_profile is unavailable"); + return GLFW_FALSE; + } + } + + _glfwGrabErrorHandlerX11(); + + if (_glfw.glx.ARB_create_context) + { + int index = 0, mask = 0, flags = 0; + + if (ctxconfig->client == GLFW_OPENGL_API) + { + if (ctxconfig->forward) + flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) + mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) + mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + } + else + mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; + + if (ctxconfig->debug) + flags |= GLX_CONTEXT_DEBUG_BIT_ARB; + if (ctxconfig->noerror) + flags |= GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR; + + if (ctxconfig->robustness) + { + if (_glfw.glx.ARB_create_context_robustness) + { + if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) + { + setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_NO_RESET_NOTIFICATION_ARB); + } + else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) + { + setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_LOSE_CONTEXT_ON_RESET_ARB); + } + + flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; + } + } + + if (ctxconfig->release) + { + if (_glfw.glx.ARB_context_flush_control) + { + if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) + { + setGLXattrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + } + else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) + { + setGLXattrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + } + } + } + + // NOTE: Only request an explicitly versioned context when necessary, as + // explicitly requesting version 1.0 does not always return the + // highest version supported by the driver + if (ctxconfig->major != 1 || ctxconfig->minor != 0) + { + setGLXattrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + setGLXattrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); + } + + if (mask) + setGLXattrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); + + if (flags) + setGLXattrib(GLX_CONTEXT_FLAGS_ARB, flags); + + setGLXattrib(None, None); + + window->context.glx.handle = + _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, + native, + share, + True, + attribs); + + // HACK: This is a fallback for broken versions of the Mesa + // implementation of GLX_ARB_create_context_profile that fail + // default 1.0 context creation with a GLXBadProfileARB error in + // violation of the extension spec + if (!window->context.glx.handle) + { + if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && + ctxconfig->client == GLFW_OPENGL_API && + ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE && + ctxconfig->forward == GLFW_FALSE) + { + window->context.glx.handle = + createLegacyContextGLX(window, native, share); + } + } + } + else + { + window->context.glx.handle = + createLegacyContextGLX(window, native, share); + } + + _glfwReleaseErrorHandlerX11(); + + if (!window->context.glx.handle) + { + _glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context"); + return GLFW_FALSE; + } + + window->context.glx.window = + glXCreateWindow(_glfw.x11.display, native, window->x11.handle, NULL); + if (!window->context.glx.window) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window"); + return GLFW_FALSE; + } + + window->context.makeCurrent = makeContextCurrentGLX; + window->context.swapBuffers = swapBuffersGLX; + window->context.swapInterval = swapIntervalGLX; + window->context.extensionSupported = extensionSupportedGLX; + window->context.getProcAddress = getProcAddressGLX; + window->context.destroy = destroyContextGLX; + + return GLFW_TRUE; +} + +#undef setGLXattrib + +// Returns the Visual and depth of the chosen GLXFBConfig +// +GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig, + Visual** visual, int* depth) +{ + GLXFBConfig native; + XVisualInfo* result; + + if (!chooseGLXFBConfig(fbconfig, &native)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "GLX: Failed to find a suitable GLXFBConfig"); + return GLFW_FALSE; + } + + result = glXGetVisualFromFBConfig(_glfw.x11.display, native); + if (!result) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to retrieve Visual for GLXFBConfig"); + return GLFW_FALSE; + } + + *visual = result->visual; + *depth = result->depth; + + XFree(result); + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return NULL; + } + + return window->context.glx.handle; +} + +GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(None); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return None; + } + + return window->context.glx.window; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glx_context.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glx_context.h new file mode 100644 index 00000000..3abed0eb --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/glx_context.h @@ -0,0 +1,182 @@ +//======================================================================== +// GLFW 3.2 GLX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_glx_context_h_ +#define _glfw3_glx_context_h_ + +#define GLX_VENDOR 1 +#define GLX_RGBA_BIT 0x00000001 +#define GLX_WINDOW_BIT 0x00000001 +#define GLX_DRAWABLE_TYPE 0x8010 +#define GLX_RENDER_TYPE 0x8011 +#define GLX_RGBA_TYPE 0x8014 +#define GLX_DOUBLEBUFFER 5 +#define GLX_STEREO 6 +#define GLX_AUX_BUFFERS 7 +#define GLX_RED_SIZE 8 +#define GLX_GREEN_SIZE 9 +#define GLX_BLUE_SIZE 10 +#define GLX_ALPHA_SIZE 11 +#define GLX_DEPTH_SIZE 12 +#define GLX_STENCIL_SIZE 13 +#define GLX_ACCUM_RED_SIZE 14 +#define GLX_ACCUM_GREEN_SIZE 15 +#define GLX_ACCUM_BLUE_SIZE 16 +#define GLX_ACCUM_ALPHA_SIZE 17 +#define GLX_SAMPLES 0x186a1 +#define GLX_VISUAL_ID 0x800b + +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20b2 +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define GLX_CONTEXT_FLAGS_ARB 0x2094 +#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 + +typedef XID GLXWindow; +typedef XID GLXDrawable; +typedef struct __GLXFBConfig* GLXFBConfig; +typedef struct __GLXcontext* GLXContext; +typedef void (*__GLXextproc)(void); + +typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*); +typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int); +typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*); +typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*); +typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display*,GLXContext); +typedef Bool (*PFNGLXMAKECURRENTPROC)(Display*,GLXDrawable,GLXContext); +typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable); +typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int); +typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*); +typedef GLXContext (*PFNGLXCREATENEWCONTEXTPROC)(Display*,GLXFBConfig,int,GLXContext,Bool); +typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const GLubyte *procName); +typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int); +typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int); +typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int); +typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*); +typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig); +typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*); +typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow); + +// libGL.so function pointer typedefs +#define glXGetFBConfigs _glfw.glx.GetFBConfigs +#define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib +#define glXGetClientString _glfw.glx.GetClientString +#define glXQueryExtension _glfw.glx.QueryExtension +#define glXQueryVersion _glfw.glx.QueryVersion +#define glXDestroyContext _glfw.glx.DestroyContext +#define glXMakeCurrent _glfw.glx.MakeCurrent +#define glXSwapBuffers _glfw.glx.SwapBuffers +#define glXQueryExtensionsString _glfw.glx.QueryExtensionsString +#define glXCreateNewContext _glfw.glx.CreateNewContext +#define glXGetVisualFromFBConfig _glfw.glx.GetVisualFromFBConfig +#define glXCreateWindow _glfw.glx.CreateWindow +#define glXDestroyWindow _glfw.glx.DestroyWindow + +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx + + +// GLX-specific per-context data +// +typedef struct _GLFWcontextGLX +{ + GLXContext handle; + GLXWindow window; + +} _GLFWcontextGLX; + +// GLX-specific global data +// +typedef struct _GLFWlibraryGLX +{ + int major, minor; + int eventBase; + int errorBase; + + // dlopen handle for libGL.so.1 + void* handle; + + // GLX 1.3 functions + PFNGLXGETFBCONFIGSPROC GetFBConfigs; + PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib; + PFNGLXGETCLIENTSTRINGPROC GetClientString; + PFNGLXQUERYEXTENSIONPROC QueryExtension; + PFNGLXQUERYVERSIONPROC QueryVersion; + PFNGLXDESTROYCONTEXTPROC DestroyContext; + PFNGLXMAKECURRENTPROC MakeCurrent; + PFNGLXSWAPBUFFERSPROC SwapBuffers; + PFNGLXQUERYEXTENSIONSSTRINGPROC QueryExtensionsString; + PFNGLXCREATENEWCONTEXTPROC CreateNewContext; + PFNGLXGETVISUALFROMFBCONFIGPROC GetVisualFromFBConfig; + PFNGLXCREATEWINDOWPROC CreateWindow; + PFNGLXDESTROYWINDOWPROC DestroyWindow; + + // GLX 1.4 and extension functions + PFNGLXGETPROCADDRESSPROC GetProcAddress; + PFNGLXGETPROCADDRESSPROC GetProcAddressARB; + PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI; + PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT; + PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA; + PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + GLFWbool SGI_swap_control; + GLFWbool EXT_swap_control; + GLFWbool MESA_swap_control; + GLFWbool ARB_multisample; + GLFWbool ARB_framebuffer_sRGB; + GLFWbool EXT_framebuffer_sRGB; + GLFWbool ARB_create_context; + GLFWbool ARB_create_context_profile; + GLFWbool ARB_create_context_robustness; + GLFWbool EXT_create_context_es2_profile; + GLFWbool ARB_context_flush_control; + +} _GLFWlibraryGLX; + + +GLFWbool _glfwInitGLX(void); +void _glfwTerminateGLX(void); +GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContextGLX(_GLFWwindow* window); +GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig, + Visual** visual, int* depth); + +#endif // _glfw3_glx_context_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/init.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/init.c new file mode 100644 index 00000000..9d4a2b25 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/init.c @@ -0,0 +1,200 @@ +//======================================================================== +// GLFW 3.2 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include + + +// The three global variables below comprise all global data in GLFW. +// Any other global variable is a bug. + +// Global state shared between compilation units of GLFW +// These are documented in internal.h +// +GLFWbool _glfwInitialized = GLFW_FALSE; +_GLFWlibrary _glfw; + +// This is outside of _glfw so it can be initialized and usable before +// glfwInit is called, which lets that function report errors +// +static GLFWerrorfun _glfwErrorCallback = NULL; + + +// Returns a generic string representation of the specified error +// +static const char* getErrorString(int error) +{ + switch (error) + { + case GLFW_NOT_INITIALIZED: + return "The GLFW library is not initialized"; + case GLFW_NO_CURRENT_CONTEXT: + return "There is no current context"; + case GLFW_INVALID_ENUM: + return "Invalid argument for enum parameter"; + case GLFW_INVALID_VALUE: + return "Invalid value for parameter"; + case GLFW_OUT_OF_MEMORY: + return "Out of memory"; + case GLFW_API_UNAVAILABLE: + return "The requested API is unavailable"; + case GLFW_VERSION_UNAVAILABLE: + return "The requested API version is unavailable"; + case GLFW_PLATFORM_ERROR: + return "A platform-specific error occurred"; + case GLFW_FORMAT_UNAVAILABLE: + return "The requested format is unavailable"; + case GLFW_NO_WINDOW_CONTEXT: + return "The specified window has no context"; + default: + return "ERROR: UNKNOWN GLFW ERROR"; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInputError(int error, const char* format, ...) +{ + if (_glfwErrorCallback) + { + char buffer[8192]; + const char* description; + + if (format) + { + int count; + va_list vl; + + va_start(vl, format); + count = vsnprintf(buffer, sizeof(buffer), format, vl); + va_end(vl); + + if (count < 0) + buffer[sizeof(buffer) - 1] = '\0'; + + description = buffer; + } + else + description = getErrorString(error); + + _glfwErrorCallback(error, description); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI int glfwInit(void) +{ + if (_glfwInitialized) + return GLFW_TRUE; + + memset(&_glfw, 0, sizeof(_glfw)); + + if (!_glfwPlatformInit()) + { + _glfwPlatformTerminate(); + return GLFW_FALSE; + } + + _glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount); + _glfwInitialized = GLFW_TRUE; + + _glfw.timerOffset = _glfwPlatformGetTimerValue(); + + // Not all window hints have zero as their default value + glfwDefaultWindowHints(); + + return GLFW_TRUE; +} + +GLFWAPI void glfwTerminate(void) +{ + int i; + + if (!_glfwInitialized) + return; + + memset(&_glfw.callbacks, 0, sizeof(_glfw.callbacks)); + + while (_glfw.windowListHead) + glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead); + + while (_glfw.cursorListHead) + glfwDestroyCursor((GLFWcursor*) _glfw.cursorListHead); + + for (i = 0; i < _glfw.monitorCount; i++) + { + _GLFWmonitor* monitor = _glfw.monitors[i]; + if (monitor->originalRamp.size) + _glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp); + } + + _glfwTerminateVulkan(); + + _glfwFreeMonitors(_glfw.monitors, _glfw.monitorCount); + _glfw.monitors = NULL; + _glfw.monitorCount = 0; + + _glfwPlatformTerminate(); + + memset(&_glfw, 0, sizeof(_glfw)); + _glfwInitialized = GLFW_FALSE; +} + +GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev) +{ + if (major != NULL) + *major = GLFW_VERSION_MAJOR; + + if (minor != NULL) + *minor = GLFW_VERSION_MINOR; + + if (rev != NULL) + *rev = GLFW_VERSION_REVISION; +} + +GLFWAPI const char* glfwGetVersionString(void) +{ + return _glfwPlatformGetVersionString(); +} + +GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) +{ + _GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun); + return cbfun; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/input.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/input.c new file mode 100644 index 00000000..614c6ef3 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/input.c @@ -0,0 +1,659 @@ +//======================================================================== +// GLFW 3.2 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + +// Internal key state used for sticky keys +#define _GLFW_STICK 3 + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (key >= 0 && key <= GLFW_KEY_LAST) + { + GLFWbool repeated = GLFW_FALSE; + + if (action == GLFW_RELEASE && window->keys[key] == GLFW_RELEASE) + return; + + if (action == GLFW_PRESS && window->keys[key] == GLFW_PRESS) + repeated = GLFW_TRUE; + + if (action == GLFW_RELEASE && window->stickyKeys) + window->keys[key] = _GLFW_STICK; + else + window->keys[key] = (char) action; + + if (repeated) + action = GLFW_REPEAT; + } + + if (window->callbacks.key) + window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods); +} + +void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain) +{ + if (codepoint < 32 || (codepoint > 126 && codepoint < 160)) + return; + + if (window->callbacks.charmods) + window->callbacks.charmods((GLFWwindow*) window, codepoint, mods); + + if (plain) + { + if (window->callbacks.character) + window->callbacks.character((GLFWwindow*) window, codepoint); + } +} + +void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) +{ + if (window->callbacks.scroll) + window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset); +} + +void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) +{ + if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) + return; + + // Register mouse button action + if (action == GLFW_RELEASE && window->stickyMouseButtons) + window->mouseButtons[button] = _GLFW_STICK; + else + window->mouseButtons[button] = (char) action; + + if (window->callbacks.mouseButton) + window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods); +} + +void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos) +{ + if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos) + return; + + window->virtualCursorPosX = xpos; + window->virtualCursorPosY = ypos; + + if (window->callbacks.cursorPos) + window->callbacks.cursorPos((GLFWwindow*) window, xpos, ypos); +} + +void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered) +{ + if (window->callbacks.cursorEnter) + window->callbacks.cursorEnter((GLFWwindow*) window, entered); +} + +void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) +{ + if (window->callbacks.drop) + window->callbacks.drop((GLFWwindow*) window, count, paths); +} + +void _glfwInputJoystickChange(int joy, int event) +{ + if (_glfw.callbacks.joystick) + _glfw.callbacks.joystick(joy, event); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwIsPrintable(int key) +{ + return (key >= GLFW_KEY_APOSTROPHE && key <= GLFW_KEY_WORLD_2) || + (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD) || + key == GLFW_KEY_KP_EQUAL; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(0); + + switch (mode) + { + case GLFW_CURSOR: + return window->cursorMode; + case GLFW_STICKY_KEYS: + return window->stickyKeys; + case GLFW_STICKY_MOUSE_BUTTONS: + return window->stickyMouseButtons; + default: + _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode); + return 0; + } +} + +GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + switch (mode) + { + case GLFW_CURSOR: + { + if (value != GLFW_CURSOR_NORMAL && + value != GLFW_CURSOR_HIDDEN && + value != GLFW_CURSOR_DISABLED) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid cursor mode %i", + value); + return; + } + + if (window->cursorMode == value) + return; + + window->cursorMode = value; + + _glfwPlatformGetCursorPos(window, + &window->virtualCursorPosX, + &window->virtualCursorPosY); + + if (_glfwPlatformWindowFocused(window)) + _glfwPlatformSetCursorMode(window, value); + + return; + } + + case GLFW_STICKY_KEYS: + { + if (window->stickyKeys == value) + return; + + if (!value) + { + int i; + + // Release all sticky keys + for (i = 0; i <= GLFW_KEY_LAST; i++) + { + if (window->keys[i] == _GLFW_STICK) + window->keys[i] = GLFW_RELEASE; + } + } + + window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE; + return; + } + + case GLFW_STICKY_MOUSE_BUTTONS: + { + if (window->stickyMouseButtons == value) + return; + + if (!value) + { + int i; + + // Release all sticky mouse buttons + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window->mouseButtons[i] == _GLFW_STICK) + window->mouseButtons[i] = GLFW_RELEASE; + } + } + + window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE; + return; + } + } + + _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode); +} + +GLFWAPI const char* glfwGetKeyName(int key, int scancode) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfwPlatformGetKeyName(key, scancode); +} + +GLFWAPI int glfwGetKey(GLFWwindow* handle, int key) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE); + + if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); + return GLFW_RELEASE; + } + + if (window->keys[key] == _GLFW_STICK) + { + // Sticky mode: release key now + window->keys[key] = GLFW_RELEASE; + return GLFW_PRESS; + } + + return (int) window->keys[key]; +} + +GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE); + + if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button); + return GLFW_RELEASE; + } + + if (window->mouseButtons[button] == _GLFW_STICK) + { + // Sticky mode: release mouse button now + window->mouseButtons[button] = GLFW_RELEASE; + return GLFW_PRESS; + } + + return (int) window->mouseButtons[button]; +} + +GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + + _GLFW_REQUIRE_INIT(); + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + if (xpos) + *xpos = window->virtualCursorPosX; + if (ypos) + *ypos = window->virtualCursorPosY; + } + else + _glfwPlatformGetCursorPos(window, xpos, ypos); +} + +GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (xpos != xpos || xpos < -DBL_MAX || xpos > DBL_MAX || + ypos != ypos || ypos < -DBL_MAX || ypos > DBL_MAX) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid cursor position %f %f", + xpos, ypos); + return; + } + + if (!_glfwPlatformWindowFocused(window)) + return; + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + // Only update the accumulated position if the cursor is disabled + window->virtualCursorPosX = xpos; + window->virtualCursorPosY = ypos; + } + else + { + // Update system cursor position + _glfwPlatformSetCursorPos(window, xpos, ypos); + } +} + +GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) +{ + _GLFWcursor* cursor; + + assert(image != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + cursor = calloc(1, sizeof(_GLFWcursor)); + cursor->next = _glfw.cursorListHead; + _glfw.cursorListHead = cursor; + + if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot)) + { + glfwDestroyCursor((GLFWcursor*) cursor); + return NULL; + } + + return (GLFWcursor*) cursor; +} + +GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape) +{ + _GLFWcursor* cursor; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (shape != GLFW_ARROW_CURSOR && + shape != GLFW_IBEAM_CURSOR && + shape != GLFW_CROSSHAIR_CURSOR && + shape != GLFW_HAND_CURSOR && + shape != GLFW_HRESIZE_CURSOR && + shape != GLFW_VRESIZE_CURSOR) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor %i", shape); + return NULL; + } + + cursor = calloc(1, sizeof(_GLFWcursor)); + cursor->next = _glfw.cursorListHead; + _glfw.cursorListHead = cursor; + + if (!_glfwPlatformCreateStandardCursor(cursor, shape)) + { + glfwDestroyCursor((GLFWcursor*) cursor); + return NULL; + } + + return (GLFWcursor*) cursor; +} + +GLFWAPI void glfwDestroyCursor(GLFWcursor* handle) +{ + _GLFWcursor* cursor = (_GLFWcursor*) handle; + + _GLFW_REQUIRE_INIT(); + + if (cursor == NULL) + return; + + // Make sure the cursor is not being used by any window + { + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window->next) + { + if (window->cursor == cursor) + glfwSetCursor((GLFWwindow*) window, NULL); + } + } + + _glfwPlatformDestroyCursor(cursor); + + // Unlink cursor from global linked list + { + _GLFWcursor** prev = &_glfw.cursorListHead; + + while (*prev != cursor) + prev = &((*prev)->next); + + *prev = cursor->next; + } + + free(cursor); +} + +GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) +{ + _GLFWwindow* window = (_GLFWwindow*) windowHandle; + _GLFWcursor* cursor = (_GLFWcursor*) cursorHandle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + window->cursor = cursor; + + _glfwPlatformSetCursor(window, cursor); +} + +GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.key, cbfun); + return cbfun; +} + +GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.character, cbfun); + return cbfun; +} + +GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun); + return cbfun; +} + +GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle, + GLFWmousebuttonfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun); + return cbfun; +} + +GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle, + GLFWcursorposfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun); + return cbfun; +} + +GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle, + GLFWcursorenterfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun); + return cbfun; +} + +GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, + GLFWscrollfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun); + return cbfun; +} + +GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun); + return cbfun; +} + +GLFWAPI int glfwJoystickPresent(int joy) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0); + + if (joy < 0 || joy > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy); + return 0; + } + + return _glfwPlatformJoystickPresent(joy); +} + +GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count) +{ + assert(count != NULL); + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (joy < 0 || joy > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy); + return NULL; + } + + return _glfwPlatformGetJoystickAxes(joy, count); +} + +GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count) +{ + assert(count != NULL); + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (joy < 0 || joy > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy); + return NULL; + } + + return _glfwPlatformGetJoystickButtons(joy, count); +} + +GLFWAPI const char* glfwGetJoystickName(int joy) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (joy < 0 || joy > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy); + return NULL; + } + + return _glfwPlatformGetJoystickName(joy); +} + +GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun); + return cbfun; +} + +GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + assert(string != NULL); + + _GLFW_REQUIRE_INIT(); + _glfwPlatformSetClipboardString(window, string); +} + +GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfwPlatformGetClipboardString(window); +} + +GLFWAPI double glfwGetTime(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0.0); + return (double) (_glfwPlatformGetTimerValue() - _glfw.timerOffset) / + _glfwPlatformGetTimerFrequency(); +} + +GLFWAPI void glfwSetTime(double time) +{ + _GLFW_REQUIRE_INIT(); + + if (time != time || time < 0.0 || time > 18446744073.0) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time); + return; + } + + _glfw.timerOffset = _glfwPlatformGetTimerValue() - + (uint64_t) (time * _glfwPlatformGetTimerFrequency()); +} + +GLFWAPI uint64_t glfwGetTimerValue(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return _glfwPlatformGetTimerValue(); +} + +GLFWAPI uint64_t glfwGetTimerFrequency(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return _glfwPlatformGetTimerFrequency(); +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/internal.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/internal.h new file mode 100644 index 00000000..8e84efd2 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/internal.h @@ -0,0 +1,1055 @@ +//======================================================================== +// GLFW 3.2 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_internal_h_ +#define _glfw3_internal_h_ + + +#if defined(_GLFW_USE_CONFIG_H) + #include "glfw_config.h" +#endif + +#if defined(GLFW_INCLUDE_GLCOREARB) || \ + defined(GLFW_INCLUDE_ES1) || \ + defined(GLFW_INCLUDE_ES2) || \ + defined(GLFW_INCLUDE_ES3) || \ + defined(GLFW_INCLUDE_NONE) || \ + defined(GLFW_INCLUDE_GLEXT) || \ + defined(GLFW_INCLUDE_GLU) || \ + defined(GLFW_INCLUDE_VULKAN) || \ + defined(GLFW_DLL) + #error "You must not define any header option macros when compiling GLFW" +#endif + +#define GLFW_INCLUDE_NONE +#include "../include/GLFW/glfw3.h" + +typedef int GLFWbool; + +typedef struct _GLFWwndconfig _GLFWwndconfig; +typedef struct _GLFWctxconfig _GLFWctxconfig; +typedef struct _GLFWfbconfig _GLFWfbconfig; +typedef struct _GLFWcontext _GLFWcontext; +typedef struct _GLFWwindow _GLFWwindow; +typedef struct _GLFWlibrary _GLFWlibrary; +typedef struct _GLFWmonitor _GLFWmonitor; +typedef struct _GLFWcursor _GLFWcursor; + +typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*); +typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*); +typedef void (* _GLFWswapintervalfun)(int); +typedef int (* _GLFWextensionsupportedfun)(const char*); +typedef GLFWglproc (* _GLFWgetprocaddressfun)(const char*); +typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*); + +#define GL_VERSION 0x1f02 +#define GL_NONE 0 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_EXTENSIONS 0x1f03 +#define GL_NUM_EXTENSIONS 0x821d +#define GL_CONTEXT_FLAGS 0x821e +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82fb +#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82fc +#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 + +typedef int GLint; +typedef unsigned int GLuint; +typedef unsigned int GLenum; +typedef unsigned int GLbitfield; +typedef unsigned char GLubyte; + +typedef void (APIENTRY * PFNGLCLEARPROC)(GLbitfield); +typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGPROC)(GLenum); +typedef void (APIENTRY * PFNGLGETINTEGERVPROC)(GLenum,GLint*); +typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGIPROC)(GLenum,GLuint); + +#define VK_NULL_HANDLE 0 + +typedef void* VkInstance; +typedef void* VkPhysicalDevice; +typedef uint64_t VkSurfaceKHR; +typedef uint32_t VkFlags; +typedef uint32_t VkBool32; + +typedef enum VkStructureType +{ + VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, + VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, + VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, + VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000, + VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, + VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkStructureType; + +typedef enum VkResult +{ + VK_SUCCESS = 0, + VK_NOT_READY = 1, + VK_TIMEOUT = 2, + VK_EVENT_SET = 3, + VK_EVENT_RESET = 4, + VK_INCOMPLETE = 5, + VK_ERROR_OUT_OF_HOST_MEMORY = -1, + VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, + VK_ERROR_INITIALIZATION_FAILED = -3, + VK_ERROR_DEVICE_LOST = -4, + VK_ERROR_MEMORY_MAP_FAILED = -5, + VK_ERROR_LAYER_NOT_PRESENT = -6, + VK_ERROR_EXTENSION_NOT_PRESENT = -7, + VK_ERROR_FEATURE_NOT_PRESENT = -8, + VK_ERROR_INCOMPATIBLE_DRIVER = -9, + VK_ERROR_TOO_MANY_OBJECTS = -10, + VK_ERROR_FORMAT_NOT_SUPPORTED = -11, + VK_ERROR_SURFACE_LOST_KHR = -1000000000, + VK_SUBOPTIMAL_KHR = 1000001003, + VK_ERROR_OUT_OF_DATE_KHR = -1000001004, + VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, + VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, + VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, + VK_RESULT_MAX_ENUM = 0x7FFFFFFF +} VkResult; + +typedef struct VkAllocationCallbacks VkAllocationCallbacks; + +typedef struct VkExtensionProperties +{ + char extensionName[256]; + uint32_t specVersion; +} VkExtensionProperties; + +typedef void (APIENTRY * PFN_vkVoidFunction)(void); + +#if defined(_GLFW_VULKAN_STATIC) + PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance,const char*); + VkResult vkEnumerateInstanceExtensionProperties(const char*,uint32_t*,VkExtensionProperties*); +#else + typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*); + typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*); + #define vkEnumerateInstanceExtensionProperties _glfw.vk.EnumerateInstanceExtensionProperties + #define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr +#endif + +#if defined(_GLFW_COCOA) + #include "cocoa_platform.h" +#elif defined(_GLFW_WIN32) + #include "win32_platform.h" +#elif defined(_GLFW_X11) + #include "x11_platform.h" +#elif defined(_GLFW_WAYLAND) + #include "wl_platform.h" +#elif defined(_GLFW_MIR) + #include "mir_platform.h" +#else + #error "No supported window creation API selected" +#endif + + +//======================================================================== +// Doxygen group definitions +//======================================================================== + +/*! @defgroup platform Platform interface + * @brief The interface implemented by the platform-specific code. + * + * The platform API is the interface exposed by the platform-specific code for + * each platform and is called by the shared code of the public API It mirrors + * the public API except it uses objects instead of handles. + */ +/*! @defgroup event Event interface + * @brief The interface used by the platform-specific code to report events. + * + * The event API is used by the platform-specific code to notify the shared + * code of events that can be translated into state changes and/or callback + * calls. + */ +/*! @defgroup utility Utility functions + * @brief Various utility functions for internal use. + * + * These functions are shared code and may be used by any part of GLFW + * Each platform may add its own utility functions, but those must only be + * called by the platform-specific code + */ + + +//======================================================================== +// Helper macros +//======================================================================== + +// Constructs a version number string from the public header macros +#define _GLFW_CONCAT_VERSION(m, n, r) #m "." #n "." #r +#define _GLFW_MAKE_VERSION(m, n, r) _GLFW_CONCAT_VERSION(m, n, r) +#define _GLFW_VERSION_NUMBER _GLFW_MAKE_VERSION(GLFW_VERSION_MAJOR, \ + GLFW_VERSION_MINOR, \ + GLFW_VERSION_REVISION) + +// Checks for whether the library has been initialized +#define _GLFW_REQUIRE_INIT() \ + if (!_glfwInitialized) \ + { \ + _glfwInputError(GLFW_NOT_INITIALIZED, NULL); \ + return; \ + } +#define _GLFW_REQUIRE_INIT_OR_RETURN(x) \ + if (!_glfwInitialized) \ + { \ + _glfwInputError(GLFW_NOT_INITIALIZED, NULL); \ + return x; \ + } + +// Swaps the provided pointers +#define _GLFW_SWAP_POINTERS(x, y) \ + { \ + void* t; \ + t = x; \ + x = y; \ + y = t; \ + } + + +//======================================================================== +// Platform-independent structures +//======================================================================== + +/*! @brief Window configuration. + * + * Parameters relating to the creation of the window but not directly related + * to the framebuffer. This is used to pass window creation parameters from + * shared code to the platform API. + */ +struct _GLFWwndconfig +{ + int width; + int height; + const char* title; + GLFWbool resizable; + GLFWbool visible; + GLFWbool decorated; + GLFWbool focused; + GLFWbool autoIconify; + GLFWbool floating; + GLFWbool maximized; +}; + +/*! @brief Context configuration. + * + * Parameters relating to the creation of the context but not directly related + * to the framebuffer. This is used to pass context creation parameters from + * shared code to the platform API. + */ +struct _GLFWctxconfig +{ + int client; + int source; + int major; + int minor; + GLFWbool forward; + GLFWbool debug; + GLFWbool noerror; + int profile; + int robustness; + int release; + _GLFWwindow* share; +}; + +/*! @brief Framebuffer configuration. + * + * This describes buffers and their sizes. It also contains + * a platform-specific ID used to map back to the backend API object. + * + * It is used to pass framebuffer parameters from shared code to the platform + * API and also to enumerate and select available framebuffer configs. + */ +struct _GLFWfbconfig +{ + int redBits; + int greenBits; + int blueBits; + int alphaBits; + int depthBits; + int stencilBits; + int accumRedBits; + int accumGreenBits; + int accumBlueBits; + int accumAlphaBits; + int auxBuffers; + GLFWbool stereo; + int samples; + GLFWbool sRGB; + GLFWbool doublebuffer; + uintptr_t handle; +}; + +/*! @brief Context structure. + */ +struct _GLFWcontext +{ + int client; + int source; + int major, minor, revision; + GLFWbool forward, debug, noerror; + int profile; + int robustness; + int release; + + PFNGLGETSTRINGIPROC GetStringi; + PFNGLGETINTEGERVPROC GetIntegerv; + PFNGLGETSTRINGPROC GetString; + + _GLFWmakecontextcurrentfun makeCurrent; + _GLFWswapbuffersfun swapBuffers; + _GLFWswapintervalfun swapInterval; + _GLFWextensionsupportedfun extensionSupported; + _GLFWgetprocaddressfun getProcAddress; + _GLFWdestroycontextfun destroy; + + // This is defined in the context API's context.h + _GLFW_PLATFORM_CONTEXT_STATE; + // This is defined in egl_context.h + _GLFW_EGL_CONTEXT_STATE; +}; + +/*! @brief Window and context structure. + */ +struct _GLFWwindow +{ + struct _GLFWwindow* next; + + // Window settings and state + GLFWbool resizable; + GLFWbool decorated; + GLFWbool autoIconify; + GLFWbool floating; + GLFWbool closed; + void* userPointer; + GLFWvidmode videoMode; + _GLFWmonitor* monitor; + _GLFWcursor* cursor; + + int minwidth, minheight; + int maxwidth, maxheight; + int numer, denom; + + GLFWbool stickyKeys; + GLFWbool stickyMouseButtons; + int cursorMode; + char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1]; + char keys[GLFW_KEY_LAST + 1]; + // Virtual cursor position when cursor is disabled + double virtualCursorPosX, virtualCursorPosY; + + _GLFWcontext context; + + struct { + GLFWwindowposfun pos; + GLFWwindowsizefun size; + GLFWwindowclosefun close; + GLFWwindowrefreshfun refresh; + GLFWwindowfocusfun focus; + GLFWwindowiconifyfun iconify; + GLFWframebuffersizefun fbsize; + GLFWmousebuttonfun mouseButton; + GLFWcursorposfun cursorPos; + GLFWcursorenterfun cursorEnter; + GLFWscrollfun scroll; + GLFWkeyfun key; + GLFWcharfun character; + GLFWcharmodsfun charmods; + GLFWdropfun drop; + } callbacks; + + // This is defined in the window API's platform.h + _GLFW_PLATFORM_WINDOW_STATE; +}; + +/*! @brief Monitor structure. + */ +struct _GLFWmonitor +{ + char* name; + + // Physical dimensions in millimeters. + int widthMM, heightMM; + + // The window whose video mode is current on this monitor + _GLFWwindow* window; + + GLFWvidmode* modes; + int modeCount; + GLFWvidmode currentMode; + + GLFWgammaramp originalRamp; + GLFWgammaramp currentRamp; + + // This is defined in the window API's platform.h + _GLFW_PLATFORM_MONITOR_STATE; +}; + +/*! @brief Cursor structure + */ +struct _GLFWcursor +{ + _GLFWcursor* next; + + // This is defined in the window API's platform.h + _GLFW_PLATFORM_CURSOR_STATE; +}; + +/*! @brief Library global data. + */ +struct _GLFWlibrary +{ + struct { + _GLFWfbconfig framebuffer; + _GLFWwndconfig window; + _GLFWctxconfig context; + int refreshRate; + } hints; + + _GLFWcursor* cursorListHead; + + _GLFWwindow* windowListHead; + + _GLFWmonitor** monitors; + int monitorCount; + + uint64_t timerOffset; + + struct { + GLFWbool available; + void* handle; + char** extensions; + uint32_t extensionCount; +#if !defined(_GLFW_VULKAN_STATIC) + PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; + PFN_vkGetInstanceProcAddr GetInstanceProcAddr; +#endif + GLFWbool KHR_surface; + GLFWbool KHR_win32_surface; + GLFWbool KHR_xlib_surface; + GLFWbool KHR_xcb_surface; + GLFWbool KHR_wayland_surface; + GLFWbool KHR_mir_surface; + } vk; + + struct { + GLFWmonitorfun monitor; + GLFWjoystickfun joystick; + } callbacks; + + // This is defined in the window API's platform.h + _GLFW_PLATFORM_LIBRARY_WINDOW_STATE; + // This is defined in the context API's context.h + _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE; + // This is defined in the platform's time.h + _GLFW_PLATFORM_LIBRARY_TIME_STATE; + // This is defined in the platform's joystick.h + _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE; + // This is defined in the platform's tls.h + _GLFW_PLATFORM_LIBRARY_TLS_STATE; + // This is defined in egl_context.h + _GLFW_EGL_LIBRARY_CONTEXT_STATE; +}; + + +//======================================================================== +// Global state shared between compilation units of GLFW +//======================================================================== + +/*! @brief Flag indicating whether GLFW has been successfully initialized. + */ +extern GLFWbool _glfwInitialized; + +/*! @brief All global data protected by @ref _glfwInitialized. + * This should only be touched after a call to @ref glfwInit that has not been + * followed by a call to @ref glfwTerminate. + */ +extern _GLFWlibrary _glfw; + + +//======================================================================== +// Platform API functions +//======================================================================== + +/*! @brief Initializes the platform-specific part of the library. + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an error occurred. + * @ingroup platform + */ +int _glfwPlatformInit(void); + +/*! @brief Terminates the platform-specific part of the library. + * @ingroup platform + */ +void _glfwPlatformTerminate(void); + +/*! @copydoc glfwGetVersionString + * @ingroup platform + * + * @note The returned string must be available for the duration of the program. + * + * @note The returned string must not change for the duration of the program. + */ +const char* _glfwPlatformGetVersionString(void); + +/*! @copydoc glfwGetCursorPos + * @ingroup platform + */ +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos); + +/*! @copydoc glfwSetCursorPos + * @ingroup platform + */ +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos); + +/*! @brief Sets the specified cursor mode of the specified window. + * @param[in] window The window whose cursor mode to set. + * @ingroup platform + */ +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode); + +/*! @copydoc glfwGetKeyName + * @ingroup platform + */ +const char* _glfwPlatformGetKeyName(int key, int scancode); + +/*! @copydoc glfwGetMonitors + * @ingroup platform + */ +_GLFWmonitor** _glfwPlatformGetMonitors(int* count); + +/*! @brief Checks whether two monitor objects represent the same monitor. + * + * @param[in] first The first monitor. + * @param[in] second The second monitor. + * @return @c GLFW_TRUE if the monitor objects represent the same monitor, or + * @c GLFW_FALSE otherwise. + * @ingroup platform + */ +GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second); + +/*! @copydoc glfwGetMonitorPos + * @ingroup platform + */ +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos); + +/*! @copydoc glfwGetVideoModes + * @ingroup platform + */ +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count); + +/*! @ingroup platform + */ +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); + +/*! @copydoc glfwGetGammaRamp + * @ingroup platform + */ +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp); + +/*! @copydoc glfwSetGammaRamp + * @ingroup platform + */ +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); + +/*! @copydoc glfwSetClipboardString + * @ingroup platform + */ +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string); + +/*! @copydoc glfwGetClipboardString + * @ingroup platform + * + * @note The returned string must be valid until the next call to @ref + * _glfwPlatformGetClipboardString or @ref _glfwPlatformSetClipboardString. + */ +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window); + +/*! @copydoc glfwJoystickPresent + * @ingroup platform + */ +int _glfwPlatformJoystickPresent(int joy); + +/*! @copydoc glfwGetJoystickAxes + * @ingroup platform + */ +const float* _glfwPlatformGetJoystickAxes(int joy, int* count); + +/*! @copydoc glfwGetJoystickButtons + * @ingroup platform + */ +const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count); + +/*! @copydoc glfwGetJoystickName + * @ingroup platform + */ +const char* _glfwPlatformGetJoystickName(int joy); + +/*! @copydoc glfwGetTimerValue + * @ingroup platform + */ +uint64_t _glfwPlatformGetTimerValue(void); + +/*! @copydoc glfwGetTimerFrequency + * @ingroup platform + */ +uint64_t _glfwPlatformGetTimerFrequency(void); + +/*! @ingroup platform + */ +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); + +/*! @ingroup platform + */ +void _glfwPlatformDestroyWindow(_GLFWwindow* window); + +/*! @copydoc glfwSetWindowTitle + * @ingroup platform + */ +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title); + +/*! @copydoc glfwSetWindowIcon + * @ingroup platform + */ +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const GLFWimage* images); + +/*! @copydoc glfwGetWindowPos + * @ingroup platform + */ +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos); + +/*! @copydoc glfwSetWindowPos + * @ingroup platform + */ +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos); + +/*! @copydoc glfwGetWindowSize + * @ingroup platform + */ +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height); + +/*! @copydoc glfwSetWindowSize + * @ingroup platform + */ +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height); + +/*! @copydoc glfwSetWindowSizeLimits + * @ingroup platform + */ +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); + +/*! @copydoc glfwSetWindowAspectRatio + * @ingroup platform + */ +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom); + +/*! @copydoc glfwGetFramebufferSize + * @ingroup platform + */ +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height); + +/*! @copydoc glfwGetWindowFrameSize + * @ingroup platform + */ +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom); + +/*! @copydoc glfwIconifyWindow + * @ingroup platform + */ +void _glfwPlatformIconifyWindow(_GLFWwindow* window); + +/*! @copydoc glfwRestoreWindow + * @ingroup platform + */ +void _glfwPlatformRestoreWindow(_GLFWwindow* window); + +/*! @copydoc glfwMaximizeWindow + * @ingroup platform + */ +void _glfwPlatformMaximizeWindow(_GLFWwindow* window); + +/*! @copydoc glfwShowWindow + * @ingroup platform + */ +void _glfwPlatformShowWindow(_GLFWwindow* window); + +/*! @copydoc glfwHideWindow + * @ingroup platform + */ +void _glfwPlatformHideWindow(_GLFWwindow* window); + +/*! @copydoc glfwFocusWindow + * @ingroup platform + */ +void _glfwPlatformFocusWindow(_GLFWwindow* window); + +/*! @copydoc glfwSetWindowMonitor + * @ingroup platform + */ +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); + +/*! @brief Returns whether the window is focused. + * @ingroup platform + */ +int _glfwPlatformWindowFocused(_GLFWwindow* window); + +/*! @brief Returns whether the window is iconified. + * @ingroup platform + */ +int _glfwPlatformWindowIconified(_GLFWwindow* window); + +/*! @brief Returns whether the window is visible. + * @ingroup platform + */ +int _glfwPlatformWindowVisible(_GLFWwindow* window); + +/*! @brief Returns whether the window is maximized. + * @ingroup platform + */ +int _glfwPlatformWindowMaximized(_GLFWwindow* window); + +/*! @copydoc glfwPollEvents + * @ingroup platform + */ +void _glfwPlatformPollEvents(void); + +/*! @copydoc glfwWaitEvents + * @ingroup platform + */ +void _glfwPlatformWaitEvents(void); + +/*! @copydoc glfwWaitEventsTimeout + * @ingroup platform + */ +void _glfwPlatformWaitEventsTimeout(double timeout); + +/*! @copydoc glfwPostEmptyEvent + * @ingroup platform + */ +void _glfwPlatformPostEmptyEvent(void); + +/*! @ingroup platform + */ +void _glfwPlatformSetCurrentContext(_GLFWwindow* context); + +/*! @copydoc glfwGetCurrentContext + * @ingroup platform + */ +_GLFWwindow* _glfwPlatformGetCurrentContext(void); + +/*! @copydoc glfwCreateCursor + * @ingroup platform + */ +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot); + +/*! @copydoc glfwCreateStandardCursor + * @ingroup platform + */ +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape); + +/*! @copydoc glfwDestroyCursor + * @ingroup platform + */ +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor); + +/*! @copydoc glfwSetCursor + * @ingroup platform + */ +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor); + +/*! @ingroup platform + */ +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count); + +/*! @ingroup platform + */ +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); + +/*! @ingroup platform + */ +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); + + +//======================================================================== +// Event API functions +//======================================================================== + +/*! @brief Notifies shared code of a window focus event. + * @param[in] window The window that received the event. + * @param[in] focused `GLFW_TRUE` if the window received focus, or `GLFW_FALSE` + * if it lost focus. + * @ingroup event + */ +void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused); + +/*! @brief Notifies shared code of a window movement event. + * @param[in] window The window that received the event. + * @param[in] xpos The new x-coordinate of the client area of the window. + * @param[in] ypos The new y-coordinate of the client area of the window. + * @ingroup event + */ +void _glfwInputWindowPos(_GLFWwindow* window, int xpos, int ypos); + +/*! @brief Notifies shared code of a window resize event. + * @param[in] window The window that received the event. + * @param[in] width The new width of the client area of the window. + * @param[in] height The new height of the client area of the window. + * @ingroup event + */ +void _glfwInputWindowSize(_GLFWwindow* window, int width, int height); + +/*! @brief Notifies shared code of a framebuffer resize event. + * @param[in] window The window that received the event. + * @param[in] width The new width, in pixels, of the framebuffer. + * @param[in] height The new height, in pixels, of the framebuffer. + * @ingroup event + */ +void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height); + +/*! @brief Notifies shared code of a window iconification event. + * @param[in] window The window that received the event. + * @param[in] iconified `GLFW_TRUE` if the window was iconified, or + * `GLFW_FALSE` if it was restored. + * @ingroup event + */ +void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified); + +/*! @brief Notifies shared code of a window damage event. + * @param[in] window The window that received the event. + */ +void _glfwInputWindowDamage(_GLFWwindow* window); + +/*! @brief Notifies shared code of a window close request event + * @param[in] window The window that received the event. + * @ingroup event + */ +void _glfwInputWindowCloseRequest(_GLFWwindow* window); + +void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor); + +/*! @brief Notifies shared code of a physical key event. + * @param[in] window The window that received the event. + * @param[in] key The key that was pressed or released. + * @param[in] scancode The system-specific scan code of the key. + * @param[in] action @ref GLFW_PRESS or @ref GLFW_RELEASE. + * @param[in] mods The modifiers pressed when the event was generated. + * @ingroup event + */ +void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods); + +/*! @brief Notifies shared code of a Unicode character input event. + * @param[in] window The window that received the event. + * @param[in] codepoint The Unicode code point of the input character. + * @param[in] mods Bit field describing which modifier keys were held down. + * @param[in] plain `GLFW_TRUE` if the character is regular text input, or + * `GLFW_FALSE` otherwise. + * @ingroup event + */ +void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain); + +/*! @brief Notifies shared code of a scroll event. + * @param[in] window The window that received the event. + * @param[in] xoffset The scroll offset along the x-axis. + * @param[in] yoffset The scroll offset along the y-axis. + * @ingroup event + */ +void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset); + +/*! @brief Notifies shared code of a mouse button click event. + * @param[in] window The window that received the event. + * @param[in] button The button that was pressed or released. + * @param[in] action @ref GLFW_PRESS or @ref GLFW_RELEASE. + * @ingroup event + */ +void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods); + +/*! @brief Notifies shared code of a cursor motion event. + * @param[in] window The window that received the event. + * @param[in] xpos The new x-coordinate of the cursor, relative to the left + * edge of the client area of the window. + * @param[in] ypos The new y-coordinate of the cursor, relative to the top edge + * of the client area of the window. + * @ingroup event + */ +void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos); + +/*! @brief Notifies shared code of a cursor enter/leave event. + * @param[in] window The window that received the event. + * @param[in] entered `GLFW_TRUE` if the cursor entered the client area of the + * window, or `GLFW_FALSE` if it left it. + * @ingroup event + */ +void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered); + +/*! @ingroup event + */ +void _glfwInputMonitorChange(void); + +/*! @ingroup event + */ +void _glfwInputMonitorWindowChange(_GLFWmonitor* monitor, _GLFWwindow* window); + +/*! @brief Notifies shared code of an error. + * @param[in] error The error code most suitable for the error. + * @param[in] format The `printf` style format string of the error + * description. + * @ingroup event + */ +#if defined(__GNUC__) +void _glfwInputError(int error, const char* format, ...) __attribute__((format(printf, 2, 3))); +#else +void _glfwInputError(int error, const char* format, ...); +#endif + +/*! @brief Notifies dropped object over window. + * @param[in] window The window that received the event. + * @param[in] count The number of dropped objects. + * @param[in] names The names of the dropped objects. + * @ingroup event + */ +void _glfwInputDrop(_GLFWwindow* window, int count, const char** names); + +/*! @brief Notifies shared code of a joystick connection/disconnection event. + * @param[in] joy The joystick that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + * @ingroup event + */ +void _glfwInputJoystickChange(int joy, int event); + + +//======================================================================== +// Utility functions +//======================================================================== + +/*! @ingroup utility + */ +const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor, + const GLFWvidmode* desired); + +/*! @brief Performs lexical comparison between two @ref GLFWvidmode structures. + * @ingroup utility + */ +int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second); + +/*! @brief Splits a color depth into red, green and blue bit depths. + * @ingroup utility + */ +void _glfwSplitBPP(int bpp, int* red, int* green, int* blue); + +/*! @brief Searches an extension string for the specified extension. + * @param[in] string The extension string to search. + * @param[in] extensions The extension to search for. + * @return `GLFW_TRUE` if the extension was found, or `GLFW_FALSE` otherwise. + * @ingroup utility + */ +GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions); + +/*! @brief Chooses the framebuffer config that best matches the desired one. + * @param[in] desired The desired framebuffer config. + * @param[in] alternatives The framebuffer configs supported by the system. + * @param[in] count The number of entries in the alternatives array. + * @return The framebuffer config most closely matching the desired one, or @c + * NULL if none fulfilled the hard constraints of the desired values. + * @ingroup utility + */ +const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, + const _GLFWfbconfig* alternatives, + unsigned int count); + +/*! @brief Retrieves the attributes of the current context. + * @param[in] ctxconfig The desired context attributes. + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if the context is + * unusable. + * @ingroup utility + */ +GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig); + +/*! @brief Checks whether the desired context attributes are valid. + * @param[in] ctxconfig The context attributes to check. + * @return `GLFW_TRUE` if the context attributes are valid, or `GLFW_FALSE` + * otherwise. + * @ingroup utility + * + * This function checks things like whether the specified client API version + * exists and whether all relevant options have supported and non-conflicting + * values. + */ +GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig); + +/*! @ingroup utility + */ +void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size); + +/*! @ingroup utility + */ +void _glfwFreeGammaArrays(GLFWgammaramp* ramp); + +/*! @brief Allocates and returns a monitor object with the specified name + * and dimensions. + * @param[in] name The name of the monitor. + * @param[in] widthMM The width, in mm, of the monitor's display area. + * @param[in] heightMM The height, in mm, of the monitor's display area. + * @return The newly created object. + * @ingroup utility + */ +_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM); + +/*! @brief Frees a monitor object and any data associated with it. + * @ingroup utility + */ +void _glfwFreeMonitor(_GLFWmonitor* monitor); + +/*! @ingroup utility + */ +void _glfwFreeMonitors(_GLFWmonitor** monitors, int count); + +/*! @ingroup utility + */ +GLFWbool _glfwIsPrintable(int key); + +/*! @ingroup utility + */ +GLFWbool _glfwInitVulkan(void); + +/*! @ingroup utility + */ +void _glfwTerminateVulkan(void); + +/*! @ingroup utility + */ +const char* _glfwGetVulkanResultString(VkResult result); + +#endif // _glfw3_internal_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/linux_joystick.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/linux_joystick.c new file mode 100644 index 00000000..4a456767 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/linux_joystick.c @@ -0,0 +1,352 @@ +//======================================================================== +// GLFW 3.2 Linux - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define _GNU_SOURCE // for asprintf() + +#include "internal.h" + +#if defined(__linux__) +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // __linux__ + + +// Attempt to open the specified joystick device +// +#if defined(__linux__) +static GLFWbool openJoystickDevice(const char* path) +{ + char axisCount, buttonCount; + char name[256] = ""; + int joy, fd, version; + _GLFWjoystickLinux* js; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (!_glfw.linux_js.js[joy].present) + continue; + + if (strcmp(_glfw.linux_js.js[joy].path, path) == 0) + return GLFW_FALSE; + } + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (!_glfw.linux_js.js[joy].present) + break; + } + + if (joy > GLFW_JOYSTICK_LAST) + return GLFW_FALSE; + + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd == -1) + return GLFW_FALSE; + + // Verify that the joystick driver version is at least 1.0 + ioctl(fd, JSIOCGVERSION, &version); + if (version < 0x010000) + { + // It's an old 0.x interface (we don't support it) + close(fd); + return GLFW_FALSE; + } + + if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0) + strncpy(name, "Unknown", sizeof(name)); + + js = _glfw.linux_js.js + joy; + js->present = GLFW_TRUE; + js->name = strdup(name); + js->path = strdup(path); + js->fd = fd; + + ioctl(fd, JSIOCGAXES, &axisCount); + js->axisCount = (int) axisCount; + js->axes = calloc(axisCount, sizeof(float)); + + ioctl(fd, JSIOCGBUTTONS, &buttonCount); + js->buttonCount = (int) buttonCount; + js->buttons = calloc(buttonCount, 1); + + _glfwInputJoystickChange(joy, GLFW_CONNECTED); + return GLFW_TRUE; +} +#endif // __linux__ + +// Polls for and processes events the specified joystick +// +static GLFWbool pollJoystickEvents(_GLFWjoystickLinux* js) +{ +#if defined(__linux__) + _glfwPollJoystickEvents(); + + if (!js->present) + return GLFW_FALSE; + + // Read all queued events (non-blocking) + for (;;) + { + struct js_event e; + + errno = 0; + if (read(js->fd, &e, sizeof(e)) < 0) + { + // Reset the joystick slot if the device was disconnected + if (errno == ENODEV) + { + free(js->axes); + free(js->buttons); + free(js->name); + free(js->path); + + memset(js, 0, sizeof(_GLFWjoystickLinux)); + + _glfwInputJoystickChange(js - _glfw.linux_js.js, + GLFW_DISCONNECTED); + } + + break; + } + + // Clear the initial-state bit + e.type &= ~JS_EVENT_INIT; + + if (e.type == JS_EVENT_AXIS) + js->axes[e.number] = (float) e.value / 32767.0f; + else if (e.type == JS_EVENT_BUTTON) + js->buttons[e.number] = e.value ? GLFW_PRESS : GLFW_RELEASE; + } +#endif // __linux__ + return js->present; +} + +// Lexically compare joysticks by name; used by qsort +// +#if defined(__linux__) +static int compareJoysticks(const void* fp, const void* sp) +{ + const _GLFWjoystickLinux* fj = fp; + const _GLFWjoystickLinux* sj = sp; + return strcmp(fj->path, sj->path); +} +#endif // __linux__ + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize joystick interface +// +GLFWbool _glfwInitJoysticksLinux(void) +{ +#if defined(__linux__) + DIR* dir; + int count = 0; + const char* dirname = "/dev/input"; + + _glfw.linux_js.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (_glfw.linux_js.inotify == -1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to initialize inotify: %s", + strerror(errno)); + return GLFW_FALSE; + } + + // HACK: Register for IN_ATTRIB as well to get notified when udev is done + // This works well in practice but the true way is libudev + + _glfw.linux_js.watch = inotify_add_watch(_glfw.linux_js.inotify, + dirname, + IN_CREATE | IN_ATTRIB); + if (_glfw.linux_js.watch == -1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to watch for joystick connections in %s: %s", + dirname, + strerror(errno)); + // Continue without device connection notifications + } + + if (regcomp(&_glfw.linux_js.regex, "^js[0-9]\\+$", 0) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex"); + return GLFW_FALSE; + } + + dir = opendir(dirname); + if (dir) + { + struct dirent* entry; + + while ((entry = readdir(dir))) + { + regmatch_t match; + char* path = NULL; + + if (regexec(&_glfw.linux_js.regex, entry->d_name, 1, &match, 0) != 0) + continue; + + if (asprintf(&path, "%s/%s", dirname, entry->d_name) < 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to construct device path: %s", + strerror(errno)); + continue; + } + + if (openJoystickDevice(path)) + count++; + + free(path); + } + + closedir(dir); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to open joystick device directory %s: %s", + dirname, + strerror(errno)); + // Continue with no joysticks detected + } + + qsort(_glfw.linux_js.js, count, sizeof(_GLFWjoystickLinux), compareJoysticks); +#endif // __linux__ + + return GLFW_TRUE; +} + +// Close all opened joystick handles +// +void _glfwTerminateJoysticksLinux(void) +{ +#if defined(__linux__) + int i; + + for (i = 0; i <= GLFW_JOYSTICK_LAST; i++) + { + if (_glfw.linux_js.js[i].present) + { + close(_glfw.linux_js.js[i].fd); + free(_glfw.linux_js.js[i].axes); + free(_glfw.linux_js.js[i].buttons); + free(_glfw.linux_js.js[i].name); + free(_glfw.linux_js.js[i].path); + } + } + + regfree(&_glfw.linux_js.regex); + + if (_glfw.linux_js.inotify > 0) + { + if (_glfw.linux_js.watch > 0) + inotify_rm_watch(_glfw.linux_js.inotify, _glfw.linux_js.watch); + + close(_glfw.linux_js.inotify); + } +#endif // __linux__ +} + +void _glfwPollJoystickEvents(void) +{ +#if defined(__linux__) + ssize_t offset = 0; + char buffer[16384]; + + const ssize_t size = read(_glfw.linux_js.inotify, buffer, sizeof(buffer)); + + while (size > offset) + { + regmatch_t match; + const struct inotify_event* e = (struct inotify_event*) (buffer + offset); + + if (regexec(&_glfw.linux_js.regex, e->name, 1, &match, 0) == 0) + { + char path[20]; + snprintf(path, sizeof(path), "/dev/input/%s", e->name); + openJoystickDevice(path); + } + + offset += sizeof(struct inotify_event) + e->len; + } +#endif +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformJoystickPresent(int joy) +{ + _GLFWjoystickLinux* js = _glfw.linux_js.js + joy; + return pollJoystickEvents(js); +} + +const float* _glfwPlatformGetJoystickAxes(int joy, int* count) +{ + _GLFWjoystickLinux* js = _glfw.linux_js.js + joy; + if (!pollJoystickEvents(js)) + return NULL; + + *count = js->axisCount; + return js->axes; +} + +const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) +{ + _GLFWjoystickLinux* js = _glfw.linux_js.js + joy; + if (!pollJoystickEvents(js)) + return NULL; + + *count = js->buttonCount; + return js->buttons; +} + +const char* _glfwPlatformGetJoystickName(int joy) +{ + _GLFWjoystickLinux* js = _glfw.linux_js.js + joy; + if (!pollJoystickEvents(js)) + return NULL; + + return js->name; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/linux_joystick.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/linux_joystick.h new file mode 100644 index 00000000..e9d1f2ba --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/linux_joystick.h @@ -0,0 +1,68 @@ +//======================================================================== +// GLFW 3.2 Linux - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ã…dahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_linux_joystick_h_ +#define _glfw3_linux_joystick_h_ + +#include + +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWjoylistLinux linux_js + + +// Linux-specific joystick data +// +typedef struct _GLFWjoystickLinux +{ + GLFWbool present; + int fd; + float* axes; + int axisCount; + unsigned char* buttons; + int buttonCount; + char* name; + char* path; +} _GLFWjoystickLinux; + +// Linux-specific joystick API data +// +typedef struct _GLFWjoylistLinux +{ + _GLFWjoystickLinux js[GLFW_JOYSTICK_LAST + 1]; + +#if defined(__linux__) + int inotify; + int watch; + regex_t regex; +#endif /*__linux__*/ +} _GLFWjoylistLinux; + + +GLFWbool _glfwInitJoysticksLinux(void); +void _glfwTerminateJoysticksLinux(void); + +void _glfwPollJoystickEvents(void); + +#endif // _glfw3_linux_joystick_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/mir_init.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/mir_init.c new file mode 100644 index 00000000..3076f5f3 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/mir_init.c @@ -0,0 +1,238 @@ +//======================================================================== +// GLFW 3.2 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014-2015 Brandon Schaefer +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + + +// Create key code translation tables +// +static void createKeyTables(void) +{ + memset(_glfw.mir.publicKeys, -1, sizeof(_glfw.mir.publicKeys)); + + _glfw.mir.publicKeys[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT; + _glfw.mir.publicKeys[KEY_1] = GLFW_KEY_1; + _glfw.mir.publicKeys[KEY_2] = GLFW_KEY_2; + _glfw.mir.publicKeys[KEY_3] = GLFW_KEY_3; + _glfw.mir.publicKeys[KEY_4] = GLFW_KEY_4; + _glfw.mir.publicKeys[KEY_5] = GLFW_KEY_5; + _glfw.mir.publicKeys[KEY_6] = GLFW_KEY_6; + _glfw.mir.publicKeys[KEY_7] = GLFW_KEY_7; + _glfw.mir.publicKeys[KEY_8] = GLFW_KEY_8; + _glfw.mir.publicKeys[KEY_9] = GLFW_KEY_9; + _glfw.mir.publicKeys[KEY_0] = GLFW_KEY_0; + _glfw.mir.publicKeys[KEY_MINUS] = GLFW_KEY_MINUS; + _glfw.mir.publicKeys[KEY_EQUAL] = GLFW_KEY_EQUAL; + _glfw.mir.publicKeys[KEY_Q] = GLFW_KEY_Q; + _glfw.mir.publicKeys[KEY_W] = GLFW_KEY_W; + _glfw.mir.publicKeys[KEY_E] = GLFW_KEY_E; + _glfw.mir.publicKeys[KEY_R] = GLFW_KEY_R; + _glfw.mir.publicKeys[KEY_T] = GLFW_KEY_T; + _glfw.mir.publicKeys[KEY_Y] = GLFW_KEY_Y; + _glfw.mir.publicKeys[KEY_U] = GLFW_KEY_U; + _glfw.mir.publicKeys[KEY_I] = GLFW_KEY_I; + _glfw.mir.publicKeys[KEY_O] = GLFW_KEY_O; + _glfw.mir.publicKeys[KEY_P] = GLFW_KEY_P; + _glfw.mir.publicKeys[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET; + _glfw.mir.publicKeys[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET; + _glfw.mir.publicKeys[KEY_A] = GLFW_KEY_A; + _glfw.mir.publicKeys[KEY_S] = GLFW_KEY_S; + _glfw.mir.publicKeys[KEY_D] = GLFW_KEY_D; + _glfw.mir.publicKeys[KEY_F] = GLFW_KEY_F; + _glfw.mir.publicKeys[KEY_G] = GLFW_KEY_G; + _glfw.mir.publicKeys[KEY_H] = GLFW_KEY_H; + _glfw.mir.publicKeys[KEY_J] = GLFW_KEY_J; + _glfw.mir.publicKeys[KEY_K] = GLFW_KEY_K; + _glfw.mir.publicKeys[KEY_L] = GLFW_KEY_L; + _glfw.mir.publicKeys[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON; + _glfw.mir.publicKeys[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE; + _glfw.mir.publicKeys[KEY_Z] = GLFW_KEY_Z; + _glfw.mir.publicKeys[KEY_X] = GLFW_KEY_X; + _glfw.mir.publicKeys[KEY_C] = GLFW_KEY_C; + _glfw.mir.publicKeys[KEY_V] = GLFW_KEY_V; + _glfw.mir.publicKeys[KEY_B] = GLFW_KEY_B; + _glfw.mir.publicKeys[KEY_N] = GLFW_KEY_N; + _glfw.mir.publicKeys[KEY_M] = GLFW_KEY_M; + _glfw.mir.publicKeys[KEY_COMMA] = GLFW_KEY_COMMA; + _glfw.mir.publicKeys[KEY_DOT] = GLFW_KEY_PERIOD; + _glfw.mir.publicKeys[KEY_SLASH] = GLFW_KEY_SLASH; + _glfw.mir.publicKeys[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH; + _glfw.mir.publicKeys[KEY_ESC] = GLFW_KEY_ESCAPE; + _glfw.mir.publicKeys[KEY_TAB] = GLFW_KEY_TAB; + _glfw.mir.publicKeys[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT; + _glfw.mir.publicKeys[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT; + _glfw.mir.publicKeys[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL; + _glfw.mir.publicKeys[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL; + _glfw.mir.publicKeys[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT; + _glfw.mir.publicKeys[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT; + _glfw.mir.publicKeys[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER; + _glfw.mir.publicKeys[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER; + _glfw.mir.publicKeys[KEY_MENU] = GLFW_KEY_MENU; + _glfw.mir.publicKeys[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK; + _glfw.mir.publicKeys[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK; + _glfw.mir.publicKeys[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN; + _glfw.mir.publicKeys[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK; + _glfw.mir.publicKeys[KEY_PAUSE] = GLFW_KEY_PAUSE; + _glfw.mir.publicKeys[KEY_DELETE] = GLFW_KEY_DELETE; + _glfw.mir.publicKeys[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE; + _glfw.mir.publicKeys[KEY_ENTER] = GLFW_KEY_ENTER; + _glfw.mir.publicKeys[KEY_HOME] = GLFW_KEY_HOME; + _glfw.mir.publicKeys[KEY_END] = GLFW_KEY_END; + _glfw.mir.publicKeys[KEY_PAGEUP] = GLFW_KEY_PAGE_UP; + _glfw.mir.publicKeys[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN; + _glfw.mir.publicKeys[KEY_INSERT] = GLFW_KEY_INSERT; + _glfw.mir.publicKeys[KEY_LEFT] = GLFW_KEY_LEFT; + _glfw.mir.publicKeys[KEY_RIGHT] = GLFW_KEY_RIGHT; + _glfw.mir.publicKeys[KEY_DOWN] = GLFW_KEY_DOWN; + _glfw.mir.publicKeys[KEY_UP] = GLFW_KEY_UP; + _glfw.mir.publicKeys[KEY_F1] = GLFW_KEY_F1; + _glfw.mir.publicKeys[KEY_F2] = GLFW_KEY_F2; + _glfw.mir.publicKeys[KEY_F3] = GLFW_KEY_F3; + _glfw.mir.publicKeys[KEY_F4] = GLFW_KEY_F4; + _glfw.mir.publicKeys[KEY_F5] = GLFW_KEY_F5; + _glfw.mir.publicKeys[KEY_F6] = GLFW_KEY_F6; + _glfw.mir.publicKeys[KEY_F7] = GLFW_KEY_F7; + _glfw.mir.publicKeys[KEY_F8] = GLFW_KEY_F8; + _glfw.mir.publicKeys[KEY_F9] = GLFW_KEY_F9; + _glfw.mir.publicKeys[KEY_F10] = GLFW_KEY_F10; + _glfw.mir.publicKeys[KEY_F11] = GLFW_KEY_F11; + _glfw.mir.publicKeys[KEY_F12] = GLFW_KEY_F12; + _glfw.mir.publicKeys[KEY_F13] = GLFW_KEY_F13; + _glfw.mir.publicKeys[KEY_F14] = GLFW_KEY_F14; + _glfw.mir.publicKeys[KEY_F15] = GLFW_KEY_F15; + _glfw.mir.publicKeys[KEY_F16] = GLFW_KEY_F16; + _glfw.mir.publicKeys[KEY_F17] = GLFW_KEY_F17; + _glfw.mir.publicKeys[KEY_F18] = GLFW_KEY_F18; + _glfw.mir.publicKeys[KEY_F19] = GLFW_KEY_F19; + _glfw.mir.publicKeys[KEY_F20] = GLFW_KEY_F20; + _glfw.mir.publicKeys[KEY_F21] = GLFW_KEY_F21; + _glfw.mir.publicKeys[KEY_F22] = GLFW_KEY_F22; + _glfw.mir.publicKeys[KEY_F23] = GLFW_KEY_F23; + _glfw.mir.publicKeys[KEY_F24] = GLFW_KEY_F24; + _glfw.mir.publicKeys[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE; + _glfw.mir.publicKeys[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY; + _glfw.mir.publicKeys[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT; + _glfw.mir.publicKeys[KEY_KPPLUS] = GLFW_KEY_KP_ADD; + _glfw.mir.publicKeys[KEY_KP0] = GLFW_KEY_KP_0; + _glfw.mir.publicKeys[KEY_KP1] = GLFW_KEY_KP_1; + _glfw.mir.publicKeys[KEY_KP2] = GLFW_KEY_KP_2; + _glfw.mir.publicKeys[KEY_KP3] = GLFW_KEY_KP_3; + _glfw.mir.publicKeys[KEY_KP4] = GLFW_KEY_KP_4; + _glfw.mir.publicKeys[KEY_KP5] = GLFW_KEY_KP_5; + _glfw.mir.publicKeys[KEY_KP6] = GLFW_KEY_KP_6; + _glfw.mir.publicKeys[KEY_KP7] = GLFW_KEY_KP_7; + _glfw.mir.publicKeys[KEY_KP8] = GLFW_KEY_KP_8; + _glfw.mir.publicKeys[KEY_KP9] = GLFW_KEY_KP_9; + _glfw.mir.publicKeys[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL; + _glfw.mir.publicKeys[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL; + _glfw.mir.publicKeys[KEY_KPENTER] = GLFW_KEY_KP_ENTER; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + int error; + + _glfw.mir.connection = mir_connect_sync(NULL, __PRETTY_FUNCTION__); + + if (!mir_connection_is_valid(_glfw.mir.connection)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unable to connect to server: %s", + mir_connection_get_error_message(_glfw.mir.connection)); + + return GLFW_FALSE; + } + + _glfw.mir.display = + mir_connection_get_egl_native_display(_glfw.mir.connection); + + createKeyTables(); + + if (!_glfwInitThreadLocalStoragePOSIX()) + return GLFW_FALSE; + + if (!_glfwInitJoysticksLinux()) + return GLFW_FALSE; + + _glfwInitTimerPOSIX(); + + // Need the default conf for when we set a NULL cursor + _glfw.mir.default_conf = mir_cursor_configuration_from_name(mir_arrow_cursor_name); + + _glfw.mir.event_queue = calloc(1, sizeof(EventQueue)); + _glfwInitEventQueueMir(_glfw.mir.event_queue); + + error = pthread_mutex_init(&_glfw.mir.event_mutex, NULL); + if (error) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Failed to create event mutex: %s", + strerror(error)); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + _glfwTerminateEGL(); + _glfwTerminateJoysticksLinux(); + _glfwTerminateThreadLocalStoragePOSIX(); + + _glfwDeleteEventQueueMir(_glfw.mir.event_queue); + + pthread_mutex_destroy(&_glfw.mir.event_mutex); + + mir_connection_release(_glfw.mir.connection); +} + +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " Mir EGL" +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + " clock_gettime" +#else + " gettimeofday" +#endif +#if defined(__linux__) + " /dev/js" +#endif +#if defined(_GLFW_BUILD_DLL) + " shared" +#endif + ; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/mir_monitor.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/mir_monitor.c new file mode 100644 index 00000000..90aa6c93 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/mir_monitor.c @@ -0,0 +1,182 @@ +//======================================================================== +// GLFW 3.2 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014-2015 Brandon Schaefer +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwPlatformGetMonitors(int* count) +{ + int i, found = 0; + _GLFWmonitor** monitors = NULL; + MirDisplayConfiguration* displayConfig = + mir_connection_create_display_config(_glfw.mir.connection); + + *count = 0; + + for (i = 0; i < displayConfig->num_outputs; i++) + { + const MirDisplayOutput* out = displayConfig->outputs + i; + + if (out->used && + out->connected && + out->num_modes && + out->current_mode < out->num_modes) + { + found++; + monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); + monitors[i] = _glfwAllocMonitor("Unknown", + out->physical_width_mm, + out->physical_height_mm); + + monitors[i]->mir.x = out->position_x; + monitors[i]->mir.y = out->position_y; + monitors[i]->mir.output_id = out->output_id; + monitors[i]->mir.cur_mode = out->current_mode; + + monitors[i]->modes = _glfwPlatformGetVideoModes(monitors[i], + &monitors[i]->modeCount); + } + } + + mir_display_config_destroy(displayConfig); + + *count = found; + return monitors; +} + +GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) +{ + return first->mir.output_id == second->mir.output_id; +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + if (xpos) + *xpos = monitor->mir.x; + if (ypos) + *ypos = monitor->mir.y; +} + +void FillInRGBBitsFromPixelFormat(GLFWvidmode* mode, const MirPixelFormat pf) +{ + switch (pf) + { + case mir_pixel_format_rgb_565: + mode->redBits = 5; + mode->greenBits = 6; + mode->blueBits = 5; + break; + case mir_pixel_format_rgba_5551: + mode->redBits = 5; + mode->greenBits = 5; + mode->blueBits = 5; + break; + case mir_pixel_format_rgba_4444: + mode->redBits = 4; + mode->greenBits = 4; + mode->blueBits = 4; + break; + case mir_pixel_format_abgr_8888: + case mir_pixel_format_xbgr_8888: + case mir_pixel_format_argb_8888: + case mir_pixel_format_xrgb_8888: + case mir_pixel_format_bgr_888: + case mir_pixel_format_rgb_888: + default: + mode->redBits = 8; + mode->greenBits = 8; + mode->blueBits = 8; + break; + } +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +{ + int i; + GLFWvidmode* modes = NULL; + MirDisplayConfiguration* displayConfig = + mir_connection_create_display_config(_glfw.mir.connection); + + for (i = 0; i < displayConfig->num_outputs; i++) + { + const MirDisplayOutput* out = displayConfig->outputs + i; + if (out->output_id != monitor->mir.output_id) + continue; + + modes = calloc(out->num_modes, sizeof(GLFWvidmode)); + + for (*found = 0; *found < out->num_modes; (*found)++) + { + modes[*found].width = out->modes[*found].horizontal_resolution; + modes[*found].height = out->modes[*found].vertical_resolution; + modes[*found].refreshRate = out->modes[*found].refresh_rate; + + FillInRGBBitsFromPixelFormat(&modes[*found], out->output_formats[*found]); + } + + break; + } + + mir_display_config_destroy(displayConfig); + + return modes; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + *mode = monitor->modes[monitor->mir.cur_mode]; +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI int glfwGetMirMonitor(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return monitor->mir.output_id; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/mir_platform.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/mir_platform.h new file mode 100644 index 00000000..8f1cf4e4 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/mir_platform.h @@ -0,0 +1,130 @@ +//======================================================================== +// GLFW 3.2 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014-2015 Brandon Schaefer +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_mir_platform_h_ +#define _glfw3_mir_platform_h_ + +#include +#include +#include + +#include + +typedef VkFlags VkMirSurfaceCreateFlagsKHR; + +typedef struct VkMirSurfaceCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkMirSurfaceCreateFlagsKHR flags; + MirConnection* connection; + MirSurface* mirSurface; +} VkMirSurfaceCreateInfoKHR; + +typedef VkResult (APIENTRY *PFN_vkCreateMirSurfaceKHR)(VkInstance,const VkMirSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); +typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice,uint32_t,MirConnection*); + +#include "posix_tls.h" +#include "posix_time.h" +#include "linux_joystick.h" +#include "xkb_unicode.h" +#include "egl_context.h" + +#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) +#define _glfw_dlclose(handle) dlclose(handle) +#define _glfw_dlsym(handle, name) dlsym(handle, name) + +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->mir.window) +#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.mir.display) + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowMir mir +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorMir mir +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryMir mir +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorMir mir + +#define _GLFW_PLATFORM_CONTEXT_STATE +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE + + +// Mir-specific Event Queue +// +typedef struct EventQueue +{ + TAILQ_HEAD(, EventNode) head; +} EventQueue; + +// Mir-specific per-window data +// +typedef struct _GLFWwindowMir +{ + MirSurface* surface; + int width; + int height; + MirEGLNativeWindowType window; + +} _GLFWwindowMir; + +// Mir-specific per-monitor data +// +typedef struct _GLFWmonitorMir +{ + int cur_mode; + int output_id; + int x; + int y; + +} _GLFWmonitorMir; + +// Mir-specific global data +// +typedef struct _GLFWlibraryMir +{ + MirConnection* connection; + MirEGLNativeDisplayType display; + MirCursorConfiguration* default_conf; + EventQueue* event_queue; + + short int publicKeys[256]; + + pthread_mutex_t event_mutex; + pthread_cond_t event_cond; + +} _GLFWlibraryMir; + +// Mir-specific per-cursor data +// TODO: Only system cursors are implemented in Mir atm. Need to wait for support. +// +typedef struct _GLFWcursorMir +{ + MirCursorConfiguration* conf; + MirBufferStream* custom_cursor; +} _GLFWcursorMir; + + +extern void _glfwInitEventQueueMir(EventQueue* queue); +extern void _glfwDeleteEventQueueMir(EventQueue* queue); + +#endif // _glfw3_mir_platform_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/mir_window.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/mir_window.c new file mode 100644 index 00000000..411f906f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/mir_window.c @@ -0,0 +1,848 @@ +//======================================================================== +// GLFW 3.2 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014-2015 Brandon Schaefer +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + + +typedef struct EventNode +{ + TAILQ_ENTRY(EventNode) entries; + const MirEvent* event; + _GLFWwindow* window; +} EventNode; + +static void deleteNode(EventQueue* queue, EventNode* node) +{ + mir_event_unref(node->event); + free(node); +} + +static GLFWbool emptyEventQueue(EventQueue* queue) +{ + return queue->head.tqh_first == NULL; +} + +// TODO The mir_event_ref is not supposed to be used but ... its needed +// in this case. Need to wait until we can read from an FD set up by mir +// for single threaded event handling. +static EventNode* newEventNode(const MirEvent* event, _GLFWwindow* context) +{ + EventNode* new_node = calloc(1, sizeof(EventNode)); + new_node->event = mir_event_ref(event); + new_node->window = context; + + return new_node; +} + +static void enqueueEvent(const MirEvent* event, _GLFWwindow* context) +{ + pthread_mutex_lock(&_glfw.mir.event_mutex); + + EventNode* new_node = newEventNode(event, context); + TAILQ_INSERT_TAIL(&_glfw.mir.event_queue->head, new_node, entries); + + pthread_cond_signal(&_glfw.mir.event_cond); + + pthread_mutex_unlock(&_glfw.mir.event_mutex); +} + +static EventNode* dequeueEvent(EventQueue* queue) +{ + EventNode* node = NULL; + + pthread_mutex_lock(&_glfw.mir.event_mutex); + + node = queue->head.tqh_first; + + if (node) + TAILQ_REMOVE(&queue->head, node, entries); + + pthread_mutex_unlock(&_glfw.mir.event_mutex); + + return node; +} + +/* FIXME Soon to be changed upstream mir! So we can use an egl config to figure out + the best pixel format! +*/ +static MirPixelFormat findValidPixelFormat(void) +{ + unsigned int i, validFormats, mirPixelFormats = 32; + MirPixelFormat formats[mir_pixel_formats]; + + mir_connection_get_available_surface_formats(_glfw.mir.connection, formats, + mirPixelFormats, &validFormats); + + for (i = 0; i < validFormats; i++) + { + if (formats[i] == mir_pixel_format_abgr_8888 || + formats[i] == mir_pixel_format_xbgr_8888 || + formats[i] == mir_pixel_format_argb_8888 || + formats[i] == mir_pixel_format_xrgb_8888) + { + return formats[i]; + } + } + + return mir_pixel_format_invalid; +} + +static int mirModToGLFWMod(uint32_t mods) +{ + int publicMods = 0x0; + + if (mods & mir_input_event_modifier_alt) + publicMods |= GLFW_MOD_ALT; + else if (mods & mir_input_event_modifier_shift) + publicMods |= GLFW_MOD_SHIFT; + else if (mods & mir_input_event_modifier_ctrl) + publicMods |= GLFW_MOD_CONTROL; + else if (mods & mir_input_event_modifier_meta) + publicMods |= GLFW_MOD_SUPER; + + return publicMods; +} + +static int toGLFWKeyCode(uint32_t key) +{ + if (key < sizeof(_glfw.mir.publicKeys) / sizeof(_glfw.mir.publicKeys[0])) + return _glfw.mir.publicKeys[key]; + + return GLFW_KEY_UNKNOWN; +} + +static void handleKeyEvent(const MirKeyboardEvent* key_event, _GLFWwindow* window) +{ + const int action = mir_keyboard_event_action (key_event); + const int scan_code = mir_keyboard_event_scan_code(key_event); + const int key_code = mir_keyboard_event_key_code (key_event); + const int modifiers = mir_keyboard_event_modifiers(key_event); + + const int pressed = action == mir_keyboard_action_up ? GLFW_RELEASE : GLFW_PRESS; + const int mods = mirModToGLFWMod(modifiers); + const long text = _glfwKeySym2Unicode(key_code); + const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); + + _glfwInputKey(window, toGLFWKeyCode(scan_code), scan_code, pressed, mods); + + if (text != -1) + _glfwInputChar(window, text, mods, plain); +} + +static void handlePointerButton(_GLFWwindow* window, + int pressed, + const MirPointerEvent* pointer_event) +{ + int mods = mir_pointer_event_modifiers(pointer_event); + const int publicMods = mirModToGLFWMod(mods); + MirPointerButton button = mir_pointer_button_primary; + static uint32_t oldButtonStates = 0; + uint32_t newButtonStates = mir_pointer_event_buttons(pointer_event); + int publicButton = GLFW_MOUSE_BUTTON_LEFT; + + // XOR our old button states our new states to figure out what was added or removed + button = newButtonStates ^ oldButtonStates; + + switch (button) + { + case mir_pointer_button_primary: + publicButton = GLFW_MOUSE_BUTTON_LEFT; + break; + case mir_pointer_button_secondary: + publicButton = GLFW_MOUSE_BUTTON_RIGHT; + break; + case mir_pointer_button_tertiary: + publicButton = GLFW_MOUSE_BUTTON_MIDDLE; + break; + case mir_pointer_button_forward: + // FIXME What is the forward button? + publicButton = GLFW_MOUSE_BUTTON_4; + break; + case mir_pointer_button_back: + // FIXME What is the back button? + publicButton = GLFW_MOUSE_BUTTON_5; + break; + default: + break; + } + + oldButtonStates = newButtonStates; + + _glfwInputMouseClick(window, publicButton, pressed, publicMods); +} + +static void handlePointerMotion(_GLFWwindow* window, + const MirPointerEvent* pointer_event) +{ + int current_x = window->virtualCursorPosX; + int current_y = window->virtualCursorPosY; + int x = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x); + int y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y); + int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll); + int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll); + + _glfwInputCursorPos(window, x, y); + if (dx != 0 || dy != 0) + _glfwInputScroll(window, dx, dy); +} + +static void handlePointerEvent(const MirPointerEvent* pointer_event, + _GLFWwindow* window) +{ + int action = mir_pointer_event_action(pointer_event); + + switch (action) + { + case mir_pointer_action_button_down: + handlePointerButton(window, GLFW_PRESS, pointer_event); + break; + case mir_pointer_action_button_up: + handlePointerButton(window, GLFW_RELEASE, pointer_event); + break; + case mir_pointer_action_motion: + handlePointerMotion(window, pointer_event); + break; + case mir_pointer_action_enter: + case mir_pointer_action_leave: + break; + default: + break; + + } +} + +static void handleInput(const MirInputEvent* input_event, _GLFWwindow* window) +{ + int type = mir_input_event_get_type(input_event); + + switch (type) + { + case mir_input_event_type_key: + handleKeyEvent(mir_input_event_get_keyboard_event(input_event), window); + break; + case mir_input_event_type_pointer: + handlePointerEvent(mir_input_event_get_pointer_event(input_event), window); + break; + default: + break; + } +} + +static void handleEvent(const MirEvent* event, _GLFWwindow* window) +{ + int type = mir_event_get_type(event); + + switch (type) + { + case mir_event_type_input: + handleInput(mir_event_get_input_event(event), window); + break; + default: + break; + } +} + +static void addNewEvent(MirSurface* surface, const MirEvent* event, void* context) +{ + enqueueEvent(event, context); +} + +static GLFWbool createSurface(_GLFWwindow* window) +{ + MirSurfaceSpec* spec; + MirBufferUsage buffer_usage = mir_buffer_usage_hardware; + MirPixelFormat pixel_format = findValidPixelFormat(); + + if (pixel_format == mir_pixel_format_invalid) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unable to find a correct pixel format"); + return GLFW_FALSE; + } + + spec = mir_connection_create_spec_for_normal_surface(_glfw.mir.connection, + window->mir.width, + window->mir.height, + pixel_format); + + mir_surface_spec_set_buffer_usage(spec, buffer_usage); + mir_surface_spec_set_name(spec, "MirSurface"); + + window->mir.surface = mir_surface_create_sync(spec); + mir_surface_spec_release(spec); + + if (!mir_surface_is_valid(window->mir.surface)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unable to create surface: %s", + mir_surface_get_error_message(window->mir.surface)); + + return GLFW_FALSE; + } + + mir_surface_set_event_handler(window->mir.surface, addNewEvent, window); + + return GLFW_TRUE; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInitEventQueueMir(EventQueue* queue) +{ + TAILQ_INIT(&queue->head); +} + +void _glfwDeleteEventQueueMir(EventQueue* queue) +{ + if (queue) + { + EventNode* node, *node_next; + node = queue->head.tqh_first; + + while (node != NULL) + { + node_next = node->entries.tqe_next; + + TAILQ_REMOVE(&queue->head, node, entries); + deleteNode(queue, node); + + node = node_next; + } + + free(queue); + } +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + if (window->monitor) + { + GLFWvidmode mode; + _glfwPlatformGetVideoMode(window->monitor, &mode); + + mir_surface_set_state(window->mir.surface, mir_surface_state_fullscreen); + + if (wndconfig->width > mode.width || wndconfig->height > mode.height) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Requested surface size too large: %ix%i", + wndconfig->width, wndconfig->height); + + return GLFW_FALSE; + } + } + + window->mir.width = wndconfig->width; + window->mir.height = wndconfig->height; + + if (!createSurface(window)) + return GLFW_FALSE; + + window->mir.window = mir_buffer_stream_get_egl_native_window( + mir_surface_get_buffer_stream(window->mir.surface)); + + if (ctxconfig->client != GLFW_NO_API) + { + if (!_glfwInitEGL()) + return GLFW_FALSE; + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (mir_surface_is_valid(window->mir.surface)) + { + mir_surface_release_sync(window->mir.surface); + window->mir.surface = NULL; + } + + if (window->context.destroy) + window->context.destroy(window); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ + MirSurfaceSpec* spec; + const char* e_title = title ? title : ""; + + spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); + mir_surface_spec_set_name(spec, e_title); + + mir_surface_apply_spec(window->mir.surface, spec); + mir_surface_spec_release(spec); +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + MirSurfaceSpec* spec; + + spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); + mir_surface_spec_set_width (spec, width); + mir_surface_spec_set_height(spec, height); + + mir_surface_apply_spec(window->mir.surface, spec); + mir_surface_spec_release(spec); +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->mir.width; + if (height) + *height = window->mir.height; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + mir_surface_set_state(window->mir.surface, mir_surface_state_minimized); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + mir_surface_set_state(window->mir.surface, mir_surface_state_restored); +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + MirSurfaceSpec* spec; + + spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); + mir_surface_spec_set_state(spec, mir_surface_state_hidden); + + mir_surface_apply_spec(window->mir.surface, spec); + mir_surface_spec_release(spec); +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + MirSurfaceSpec* spec; + + spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); + mir_surface_spec_set_state(spec, mir_surface_state_restored); + + mir_surface_apply_spec(window->mir.surface, spec); + mir_surface_spec_release(spec); +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + return GLFW_FALSE; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + return GLFW_FALSE; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + return mir_surface_get_visibility(window->mir.surface) == mir_surface_visibility_exposed; +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + return GLFW_FALSE; +} + +void _glfwPlatformPollEvents(void) +{ + EventNode* node = NULL; + + while ((node = dequeueEvent(_glfw.mir.event_queue))) + { + handleEvent(node->event, node->window); + deleteNode(_glfw.mir.event_queue, node); + } +} + +void _glfwPlatformWaitEvents(void) +{ + pthread_mutex_lock(&_glfw.mir.event_mutex); + + if (emptyEventQueue(_glfw.mir.event_queue)) + pthread_cond_wait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex); + + pthread_mutex_unlock(&_glfw.mir.event_mutex); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + pthread_mutex_lock(&_glfw.mir.event_mutex); + + if (emptyEventQueue(_glfw.mir.event_queue)) + { + struct timespec time; + clock_gettime(CLOCK_REALTIME, &time); + time.tv_sec += (long) timeout; + time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9); + pthread_cond_timedwait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex, &time); + } + + pthread_mutex_unlock(&_glfw.mir.event_mutex); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformPostEmptyEvent(void) +{ +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->mir.width; + if (height) + *height = window->mir.height; +} + +// FIXME implement +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + MirBufferStream* stream; + MirPixelFormat pixel_format = findValidPixelFormat(); + + int i_w = image->width; + int i_h = image->height; + + if (pixel_format == mir_pixel_format_invalid) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unable to find a correct pixel format"); + return GLFW_FALSE; + } + + stream = mir_connection_create_buffer_stream_sync(_glfw.mir.connection, + i_w, i_h, + pixel_format, + mir_buffer_usage_software); + + cursor->mir.conf = mir_cursor_configuration_from_buffer_stream(stream, xhot, yhot); + + char* dest; + unsigned char *pixels; + int i, r_stride, bytes_per_pixel, bytes_per_row; + + MirGraphicsRegion region; + mir_buffer_stream_get_graphics_region(stream, ®ion); + + // FIXME Figure this out based on the current_pf + bytes_per_pixel = 4; + bytes_per_row = bytes_per_pixel * i_w; + + dest = region.vaddr; + pixels = image->pixels; + + r_stride = region.stride; + + for (i = 0; i < i_h; i++) + { + memcpy(dest, pixels, bytes_per_row); + dest += r_stride; + pixels += r_stride; + } + + cursor->mir.custom_cursor = stream; + + return GLFW_TRUE; +} + +const char* getSystemCursorName(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return mir_arrow_cursor_name; + case GLFW_IBEAM_CURSOR: + return mir_caret_cursor_name; + case GLFW_CROSSHAIR_CURSOR: + return mir_crosshair_cursor_name; + case GLFW_HAND_CURSOR: + return mir_open_hand_cursor_name; + case GLFW_HRESIZE_CURSOR: + return mir_horizontal_resize_cursor_name; + case GLFW_VRESIZE_CURSOR: + return mir_vertical_resize_cursor_name; + } + + return NULL; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + const char* cursor_name = getSystemCursorName(shape); + + if (cursor_name) + { + cursor->mir.conf = mir_cursor_configuration_from_name(cursor_name); + cursor->mir.custom_cursor = NULL; + + return GLFW_TRUE; + } + + return GLFW_FALSE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + if (cursor->mir.conf) + mir_cursor_configuration_destroy(cursor->mir.conf); + if (cursor->mir.custom_cursor) + mir_buffer_stream_release_sync(cursor->mir.custom_cursor); +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + if (cursor && cursor->mir.conf) + { + mir_wait_for(mir_surface_configure_cursor(window->mir.surface, cursor->mir.conf)); + if (cursor->mir.custom_cursor) + { + mir_buffer_stream_swap_buffers_sync(cursor->mir.custom_cursor); + } + } + else + { + mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.default_conf)); + } +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +const char* _glfwPlatformGetKeyName(int key, int scancode) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + return NULL; +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + + return NULL; +} + +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count) +{ + char** extensions; + + *count = 0; + + if (!_glfw.vk.KHR_mir_surface) + return NULL; + + extensions = calloc(2, sizeof(char*)); + extensions[0] = strdup("VK_KHR_surface"); + extensions[1] = strdup("VK_KHR_mir_surface"); + + *count = 2; + return extensions; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + PFN_vkGetPhysicalDeviceMirPresentationSupportKHR vkGetPhysicalDeviceMirPresentationSupportKHR = + (PFN_vkGetPhysicalDeviceMirPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR"); + if (!vkGetPhysicalDeviceMirPresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Mir: Vulkan instance missing VK_KHR_mir_surface extension"); + return GLFW_FALSE; + } + + return vkGetPhysicalDeviceMirPresentationSupportKHR(device, + queuefamily, + _glfw.mir.connection); +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + VkResult err; + VkMirSurfaceCreateInfoKHR sci; + PFN_vkCreateMirSurfaceKHR vkCreateMirSurfaceKHR; + + vkCreateMirSurfaceKHR = (PFN_vkCreateMirSurfaceKHR) + vkGetInstanceProcAddr(instance, "vkCreateMirSurfaceKHR"); + if (!vkCreateMirSurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Mir: Vulkan instance missing VK_KHR_mir_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR; + sci.connection = _glfw.mir.connection; + sci.mirSurface = window->mir.surface; + + err = vkCreateMirSurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Failed to create Vulkan surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI MirConnection* glfwGetMirDisplay(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfw.mir.connection; +} + +GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->mir.surface; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/monitor.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/monitor.c new file mode 100644 index 00000000..b6c312df --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/monitor.c @@ -0,0 +1,477 @@ +//======================================================================== +// GLFW 3.2 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include +#include +#include + + +// Lexically compare video modes, used by qsort +// +static int compareVideoModes(const void* fp, const void* sp) +{ + const GLFWvidmode* fm = fp; + const GLFWvidmode* sm = sp; + const int fbpp = fm->redBits + fm->greenBits + fm->blueBits; + const int sbpp = sm->redBits + sm->greenBits + sm->blueBits; + const int farea = fm->width * fm->height; + const int sarea = sm->width * sm->height; + + // First sort on color bits per pixel + if (fbpp != sbpp) + return fbpp - sbpp; + + // Then sort on screen area + if (farea != sarea) + return farea - sarea; + + // Lastly sort on refresh rate + return fm->refreshRate - sm->refreshRate; +} + +// Retrieves the available modes for the specified monitor +// +static GLFWbool refreshVideoModes(_GLFWmonitor* monitor) +{ + int modeCount; + GLFWvidmode* modes; + + if (monitor->modes) + return GLFW_TRUE; + + modes = _glfwPlatformGetVideoModes(monitor, &modeCount); + if (!modes) + return GLFW_FALSE; + + qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes); + + free(monitor->modes); + monitor->modes = modes; + monitor->modeCount = modeCount; + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInputMonitorChange(void) +{ + int i, j, monitorCount = _glfw.monitorCount; + _GLFWmonitor** monitors = _glfw.monitors; + + _glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount); + + // Re-use still connected monitor objects + + for (i = 0; i < _glfw.monitorCount; i++) + { + for (j = 0; j < monitorCount; j++) + { + if (_glfwPlatformIsSameMonitor(_glfw.monitors[i], monitors[j])) + { + _glfwFreeMonitor(_glfw.monitors[i]); + _glfw.monitors[i] = monitors[j]; + break; + } + } + } + + // Find and report disconnected monitors (not in the new list) + + for (i = 0; i < monitorCount; i++) + { + _GLFWwindow* window; + + for (j = 0; j < _glfw.monitorCount; j++) + { + if (monitors[i] == _glfw.monitors[j]) + break; + } + + if (j < _glfw.monitorCount) + continue; + + for (window = _glfw.windowListHead; window; window = window->next) + { + if (window->monitor == monitors[i]) + { + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0); + } + } + + if (_glfw.callbacks.monitor) + _glfw.callbacks.monitor((GLFWmonitor*) monitors[i], GLFW_DISCONNECTED); + } + + // Find and report newly connected monitors (not in the old list) + // Re-used monitor objects are then removed from the old list to avoid + // having them destroyed at the end of this function + + for (i = 0; i < _glfw.monitorCount; i++) + { + for (j = 0; j < monitorCount; j++) + { + if (_glfw.monitors[i] == monitors[j]) + { + monitors[j] = NULL; + break; + } + } + + if (j < monitorCount) + continue; + + if (_glfw.callbacks.monitor) + _glfw.callbacks.monitor((GLFWmonitor*) _glfw.monitors[i], GLFW_CONNECTED); + } + + _glfwFreeMonitors(monitors, monitorCount); +} + +void _glfwInputMonitorWindowChange(_GLFWmonitor* monitor, _GLFWwindow* window) +{ + monitor->window = window; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM) +{ + _GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor)); + monitor->name = strdup(name); + monitor->widthMM = widthMM; + monitor->heightMM = heightMM; + + return monitor; +} + +void _glfwFreeMonitor(_GLFWmonitor* monitor) +{ + if (monitor == NULL) + return; + + _glfwFreeGammaArrays(&monitor->originalRamp); + _glfwFreeGammaArrays(&monitor->currentRamp); + + free(monitor->modes); + free(monitor->name); + free(monitor); +} + +void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size) +{ + ramp->red = calloc(size, sizeof(unsigned short)); + ramp->green = calloc(size, sizeof(unsigned short)); + ramp->blue = calloc(size, sizeof(unsigned short)); + ramp->size = size; +} + +void _glfwFreeGammaArrays(GLFWgammaramp* ramp) +{ + free(ramp->red); + free(ramp->green); + free(ramp->blue); + + memset(ramp, 0, sizeof(GLFWgammaramp)); +} + +void _glfwFreeMonitors(_GLFWmonitor** monitors, int count) +{ + int i; + + for (i = 0; i < count; i++) + _glfwFreeMonitor(monitors[i]); + + free(monitors); +} + +const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor, + const GLFWvidmode* desired) +{ + int i; + unsigned int sizeDiff, leastSizeDiff = UINT_MAX; + unsigned int rateDiff, leastRateDiff = UINT_MAX; + unsigned int colorDiff, leastColorDiff = UINT_MAX; + const GLFWvidmode* current; + const GLFWvidmode* closest = NULL; + + if (!refreshVideoModes(monitor)) + return NULL; + + for (i = 0; i < monitor->modeCount; i++) + { + current = monitor->modes + i; + + colorDiff = 0; + + if (desired->redBits != GLFW_DONT_CARE) + colorDiff += abs(current->redBits - desired->redBits); + if (desired->greenBits != GLFW_DONT_CARE) + colorDiff += abs(current->greenBits - desired->greenBits); + if (desired->blueBits != GLFW_DONT_CARE) + colorDiff += abs(current->blueBits - desired->blueBits); + + sizeDiff = abs((current->width - desired->width) * + (current->width - desired->width) + + (current->height - desired->height) * + (current->height - desired->height)); + + if (desired->refreshRate != GLFW_DONT_CARE) + rateDiff = abs(current->refreshRate - desired->refreshRate); + else + rateDiff = UINT_MAX - current->refreshRate; + + if ((colorDiff < leastColorDiff) || + (colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) || + (colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff)) + { + closest = current; + leastSizeDiff = sizeDiff; + leastRateDiff = rateDiff; + leastColorDiff = colorDiff; + } + } + + return closest; +} + +int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm) +{ + return compareVideoModes(fm, sm); +} + +void _glfwSplitBPP(int bpp, int* red, int* green, int* blue) +{ + int delta; + + // We assume that by 32 the user really meant 24 + if (bpp == 32) + bpp = 24; + + // Convert "bits per pixel" to red, green & blue sizes + + *red = *green = *blue = bpp / 3; + delta = bpp - (*red * 3); + if (delta >= 1) + *green = *green + 1; + + if (delta == 2) + *red = *red + 1; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI GLFWmonitor** glfwGetMonitors(int* count) +{ + assert(count != NULL); + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + *count = _glfw.monitorCount; + return (GLFWmonitor**) _glfw.monitors; +} + +GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (!_glfw.monitorCount) + return NULL; + + return (GLFWmonitor*) _glfw.monitors[0]; +} + +GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + + _GLFW_REQUIRE_INIT(); + + _glfwPlatformGetMonitorPos(monitor, xpos, ypos); +} + +GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + if (widthMM) + *widthMM = 0; + if (heightMM) + *heightMM = 0; + + _GLFW_REQUIRE_INIT(); + + if (widthMM) + *widthMM = monitor->widthMM; + if (heightMM) + *heightMM = monitor->heightMM; +} + +GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return monitor->name; +} + +GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun); + return cbfun; +} + +GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + assert(count != NULL); + + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (!refreshVideoModes(monitor)) + return NULL; + + *count = monitor->modeCount; + return monitor->modes; +} + +GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + _glfwPlatformGetVideoMode(monitor, &monitor->currentMode); + return &monitor->currentMode; +} + +GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) +{ + int i; + unsigned short values[256]; + GLFWgammaramp ramp; + + _GLFW_REQUIRE_INIT(); + + if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma); + return; + } + + for (i = 0; i < 256; i++) + { + double value; + + // Calculate intensity + value = i / 255.0; + // Apply gamma curve + value = pow(value, 1.0 / gamma) * 65535.0 + 0.5; + + // Clamp to value range + if (value > 65535.0) + value = 65535.0; + + values[i] = (unsigned short) value; + } + + ramp.red = values; + ramp.green = values; + ramp.blue = values; + ramp.size = 256; + + glfwSetGammaRamp(handle, &ramp); +} + +GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + _glfwFreeGammaArrays(&monitor->currentRamp); + _glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp); + + return &monitor->currentRamp; +} + +GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + assert(ramp != NULL); + assert(ramp->red != NULL); + assert(ramp->green != NULL); + assert(ramp->blue != NULL); + + if (ramp->size <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid gamma ramp size %i", + ramp->size); + return; + } + + _GLFW_REQUIRE_INIT(); + + if (!monitor->originalRamp.size) + _glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp); + + _glfwPlatformSetGammaRamp(monitor, ramp); +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/nsgl_context.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/nsgl_context.h new file mode 100644 index 00000000..1304f2e8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/nsgl_context.h @@ -0,0 +1,60 @@ +//======================================================================== +// GLFW 3.2 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_nsgl_context_h_ +#define _glfw3_nsgl_context_h_ + +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl + + +// NSGL-specific per-context data +// +typedef struct _GLFWcontextNSGL +{ + id pixelFormat; + id object; + +} _GLFWcontextNSGL; + +// NSGL-specific global data +// +typedef struct _GLFWlibraryNSGL +{ + // dlopen handle for OpenGL.framework (for glfwGetProcAddress) + CFBundleRef framework; + +} _GLFWlibraryNSGL; + + +GLFWbool _glfwInitNSGL(void); +void _glfwTerminateNSGL(void); +GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContextNSGL(_GLFWwindow* window); + +#endif // _glfw3_nsgl_context_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/nsgl_context.m b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/nsgl_context.m new file mode 100644 index 00000000..22ebdba9 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/nsgl_context.m @@ -0,0 +1,308 @@ +//======================================================================== +// GLFW 3.2 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +static void makeContextCurrentNSGL(_GLFWwindow* window) +{ + if (window) + [window->context.nsgl.object makeCurrentContext]; + else + [NSOpenGLContext clearCurrentContext]; + + _glfwPlatformSetCurrentContext(window); +} + +static void swapBuffersNSGL(_GLFWwindow* window) +{ + // ARP appears to be unnecessary, but this is future-proof + [window->context.nsgl.object flushBuffer]; +} + +static void swapIntervalNSGL(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + GLint sync = interval; + [window->context.nsgl.object setValues:&sync + forParameter:NSOpenGLCPSwapInterval]; +} + +static int extensionSupportedNSGL(const char* extension) +{ + // There are no NSGL extensions + return GLFW_FALSE; +} + +static GLFWglproc getProcAddressNSGL(const char* procname) +{ + CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, + procname, + kCFStringEncodingASCII); + + GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework, + symbolName); + + CFRelease(symbolName); + + return symbol; +} + +// Destroy the OpenGL context +// +static void destroyContextNSGL(_GLFWwindow* window) +{ + [window->context.nsgl.pixelFormat release]; + window->context.nsgl.pixelFormat = nil; + + [window->context.nsgl.object release]; + window->context.nsgl.object = nil; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize OpenGL support +// +GLFWbool _glfwInitNSGL(void) +{ + if (_glfw.nsgl.framework) + return GLFW_TRUE; + + _glfw.nsgl.framework = + CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); + if (_glfw.nsgl.framework == NULL) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "NSGL: Failed to locate OpenGL framework"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +// Terminate OpenGL support +// +void _glfwTerminateNSGL(void) +{ +} + +// Create the OpenGL context +// +GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + unsigned int attributeCount = 0; + + if (ctxconfig->client == GLFW_OPENGL_ES_API) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "NSGL: OpenGL ES is not available on OS X"); + return GLFW_FALSE; + } + + if (ctxconfig->major == 3 && ctxconfig->minor < 2) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "NSGL: The targeted version of OS X does not support OpenGL 3.0 or 3.1"); + return GLFW_FALSE; + } + + if (ctxconfig->major > 2) + { + if (!ctxconfig->forward) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "NSGL: The targeted version of OS X only supports forward-compatible contexts for OpenGL 3.2 and above"); + return GLFW_FALSE; + } + + if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "NSGL: The targeted version of OS X only supports core profile contexts for OpenGL 3.2 and above"); + return GLFW_FALSE; + } + } + + // Context robustness modes (GL_KHR_robustness) are not yet supported on + // OS X but are not a hard constraint, so ignore and continue + + // Context release behaviors (GL_KHR_context_flush_control) are not yet + // supported on OS X but are not a hard constraint, so ignore and continue + +#define ADD_ATTR(x) { attributes[attributeCount++] = x; } +#define ADD_ATTR2(x, y) { ADD_ATTR(x); ADD_ATTR(y); } + + // Arbitrary array size here + NSOpenGLPixelFormatAttribute attributes[40]; + + ADD_ATTR(NSOpenGLPFAAccelerated); + ADD_ATTR(NSOpenGLPFAClosestPolicy); + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 + if (ctxconfig->major >= 4) + { + ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); + } + else +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + if (ctxconfig->major >= 3) + { + ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); + } + + if (ctxconfig->major <= 2) + { + if (fbconfig->auxBuffers != GLFW_DONT_CARE) + ADD_ATTR2(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); + + if (fbconfig->accumRedBits != GLFW_DONT_CARE && + fbconfig->accumGreenBits != GLFW_DONT_CARE && + fbconfig->accumBlueBits != GLFW_DONT_CARE && + fbconfig->accumAlphaBits != GLFW_DONT_CARE) + { + const int accumBits = fbconfig->accumRedBits + + fbconfig->accumGreenBits + + fbconfig->accumBlueBits + + fbconfig->accumAlphaBits; + + ADD_ATTR2(NSOpenGLPFAAccumSize, accumBits); + } + } + + if (fbconfig->redBits != GLFW_DONT_CARE && + fbconfig->greenBits != GLFW_DONT_CARE && + fbconfig->blueBits != GLFW_DONT_CARE) + { + int colorBits = fbconfig->redBits + + fbconfig->greenBits + + fbconfig->blueBits; + + // OS X needs non-zero color size, so set reasonable values + if (colorBits == 0) + colorBits = 24; + else if (colorBits < 15) + colorBits = 15; + + ADD_ATTR2(NSOpenGLPFAColorSize, colorBits); + } + + if (fbconfig->alphaBits != GLFW_DONT_CARE) + ADD_ATTR2(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); + + if (fbconfig->depthBits != GLFW_DONT_CARE) + ADD_ATTR2(NSOpenGLPFADepthSize, fbconfig->depthBits); + + if (fbconfig->stencilBits != GLFW_DONT_CARE) + ADD_ATTR2(NSOpenGLPFAStencilSize, fbconfig->stencilBits); + + if (fbconfig->stereo) + ADD_ATTR(NSOpenGLPFAStereo); + + if (fbconfig->doublebuffer) + ADD_ATTR(NSOpenGLPFADoubleBuffer); + + if (fbconfig->samples != GLFW_DONT_CARE) + { + if (fbconfig->samples == 0) + { + ADD_ATTR2(NSOpenGLPFASampleBuffers, 0); + } + else + { + ADD_ATTR2(NSOpenGLPFASampleBuffers, 1); + ADD_ATTR2(NSOpenGLPFASamples, fbconfig->samples); + } + } + + // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB + // framebuffer, so there's no need (and no way) to request it + + ADD_ATTR(0); + +#undef ADD_ATTR +#undef ADD_ATTR2 + + window->context.nsgl.pixelFormat = + [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; + if (window->context.nsgl.pixelFormat == nil) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "NSGL: Failed to find a suitable pixel format"); + return GLFW_FALSE; + } + + NSOpenGLContext* share = NULL; + + if (ctxconfig->share) + share = ctxconfig->share->context.nsgl.object; + + window->context.nsgl.object = + [[NSOpenGLContext alloc] initWithFormat:window->context.nsgl.pixelFormat + shareContext:share]; + if (window->context.nsgl.object == nil) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "NSGL: Failed to create OpenGL context"); + return GLFW_FALSE; + } + + [window->context.nsgl.object setView:window->ns.view]; + + window->context.makeCurrent = makeContextCurrentNSGL; + window->context.swapBuffers = swapBuffersNSGL; + window->context.swapInterval = swapIntervalNSGL; + window->context.extensionSupported = extensionSupportedNSGL; + window->context.getProcAddress = getProcAddressNSGL; + window->context.destroy = destroyContextNSGL; + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(nil); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return NULL; + } + + return window->context.nsgl.object; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/posix_time.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/posix_time.c new file mode 100644 index 00000000..8d0d4cd6 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/posix_time.c @@ -0,0 +1,85 @@ +//======================================================================== +// GLFW 3.2 POSIX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialise timer +// +void _glfwInitTimerPOSIX(void) +{ +#if defined(CLOCK_MONOTONIC) + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + { + _glfw.posix_time.monotonic = GLFW_TRUE; + _glfw.posix_time.frequency = 1000000000; + } + else +#endif + { + _glfw.posix_time.monotonic = GLFW_FALSE; + _glfw.posix_time.frequency = 1000000; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +uint64_t _glfwPlatformGetTimerValue(void) +{ +#if defined(CLOCK_MONOTONIC) + if (_glfw.posix_time.monotonic) + { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec; + } + else +#endif + { + struct timeval tv; + gettimeofday(&tv, NULL); + return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec; + } +} + +uint64_t _glfwPlatformGetTimerFrequency(void) +{ + return _glfw.posix_time.frequency; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/posix_time.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/posix_time.h new file mode 100644 index 00000000..4730ca7c --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/posix_time.h @@ -0,0 +1,48 @@ +//======================================================================== +// GLFW 3.2 POSIX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_posix_time_h_ +#define _glfw3_posix_time_h_ + +#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimePOSIX posix_time + +#include + + +// POSIX-specific global timer data +// +typedef struct _GLFWtimePOSIX +{ + GLFWbool monotonic; + uint64_t frequency; + +} _GLFWtimePOSIX; + + +void _glfwInitTimerPOSIX(void); + +#endif // _glfw3_posix_time_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/posix_tls.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/posix_tls.c new file mode 100644 index 00000000..c9517c67 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/posix_tls.c @@ -0,0 +1,68 @@ +//======================================================================== +// GLFW 3.2 POSIX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwInitThreadLocalStoragePOSIX(void) +{ + if (pthread_key_create(&_glfw.posix_tls.context, NULL) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "POSIX: Failed to create context TLS"); + return GLFW_FALSE; + } + + _glfw.posix_tls.allocated = GLFW_TRUE; + return GLFW_TRUE; +} + +void _glfwTerminateThreadLocalStoragePOSIX(void) +{ + if (_glfw.posix_tls.allocated) + pthread_key_delete(_glfw.posix_tls.context); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformSetCurrentContext(_GLFWwindow* context) +{ + pthread_setspecific(_glfw.posix_tls.context, context); +} + +_GLFWwindow* _glfwPlatformGetCurrentContext(void) +{ + return pthread_getspecific(_glfw.posix_tls.context); +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/posix_tls.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/posix_tls.h new file mode 100644 index 00000000..0d408ae6 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/posix_tls.h @@ -0,0 +1,49 @@ +//======================================================================== +// GLFW 3.2 POSIX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_posix_tls_h_ +#define _glfw3_posix_tls_h_ + +#include + +#define _GLFW_PLATFORM_LIBRARY_TLS_STATE _GLFWtlsPOSIX posix_tls + + +// POSIX-specific global TLS data +// +typedef struct _GLFWtlsPOSIX +{ + GLFWbool allocated; + pthread_key_t context; + +} _GLFWtlsPOSIX; + + +GLFWbool _glfwInitThreadLocalStoragePOSIX(void); +void _glfwTerminateThreadLocalStoragePOSIX(void); + +#endif // _glfw3_posix_tls_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/vulkan.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/vulkan.c new file mode 100644 index 00000000..20011deb --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/vulkan.c @@ -0,0 +1,302 @@ +//======================================================================== +// GLFW 3.2 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwInitVulkan(void) +{ + VkResult err; + VkExtensionProperties* ep; + uint32_t i, count; + +#if !defined(_GLFW_VULKAN_STATIC) +#if defined(_GLFW_WIN32) + const char* name = "vulkan-1.dll"; +#else + const char* name = "libvulkan.so.1"; +#endif + + if (_glfw.vk.available) + return GLFW_TRUE; + + _glfw.vk.handle = _glfw_dlopen(name); + if (!_glfw.vk.handle) + return GLFW_FALSE; + + _glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) + _glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr"); + if (!_glfw.vk.GetInstanceProcAddr) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Loader does not export vkGetInstanceProcAddr"); + + _glfwTerminateVulkan(); + return GLFW_FALSE; + } + + _glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties) + vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties"); + if (!_glfw.vk.EnumerateInstanceExtensionProperties) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties"); + + _glfwTerminateVulkan(); + return GLFW_FALSE; + } +#endif // _GLFW_VULKAN_STATIC + + err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Vulkan: Failed to query instance extension count: %s", + _glfwGetVulkanResultString(err)); + + _glfwTerminateVulkan(); + return GLFW_FALSE; + } + + ep = calloc(count, sizeof(VkExtensionProperties)); + + err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Vulkan: Failed to query instance extensions: %s", + _glfwGetVulkanResultString(err)); + + free(ep); + _glfwTerminateVulkan(); + return GLFW_FALSE; + } + + for (i = 0; i < count; i++) + { + if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0) + _glfw.vk.KHR_surface = GLFW_TRUE; + if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0) + _glfw.vk.KHR_win32_surface = GLFW_TRUE; + if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0) + _glfw.vk.KHR_xlib_surface = GLFW_TRUE; + if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0) + _glfw.vk.KHR_xcb_surface = GLFW_TRUE; + if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0) + _glfw.vk.KHR_wayland_surface = GLFW_TRUE; + if (strcmp(ep[i].extensionName, "VK_KHR_mir_surface") == 0) + _glfw.vk.KHR_mir_surface = GLFW_TRUE; + } + + free(ep); + + _glfw.vk.available = GLFW_TRUE; + + if (_glfw.vk.KHR_surface) + { + _glfw.vk.extensions = + _glfwPlatformGetRequiredInstanceExtensions(&_glfw.vk.extensionCount); + } + + return GLFW_TRUE; +} + +void _glfwTerminateVulkan(void) +{ + uint32_t i; + + for (i = 0; i < _glfw.vk.extensionCount; i++) + free(_glfw.vk.extensions[i]); + free(_glfw.vk.extensions); + + if (_glfw.vk.handle) + _glfw_dlclose(_glfw.vk.handle); +} + +const char* _glfwGetVulkanResultString(VkResult result) +{ + switch (result) + { + case VK_SUCCESS: + return "Success"; + case VK_NOT_READY: + return "A fence or query has not yet completed"; + case VK_TIMEOUT: + return "A wait operation has not completed in the specified time"; + case VK_EVENT_SET: + return "An event is signaled"; + case VK_EVENT_RESET: + return "An event is unsignaled"; + case VK_INCOMPLETE: + return "A return array was too small for the result"; + case VK_ERROR_OUT_OF_HOST_MEMORY: + return "A host memory allocation has failed"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: + return "A device memory allocation has failed"; + case VK_ERROR_INITIALIZATION_FAILED: + return "Initialization of an object could not be completed for implementation-specific reasons"; + case VK_ERROR_DEVICE_LOST: + return "The logical or physical device has been lost"; + case VK_ERROR_MEMORY_MAP_FAILED: + return "Mapping of a memory object has failed"; + case VK_ERROR_LAYER_NOT_PRESENT: + return "A requested layer is not present or could not be loaded"; + case VK_ERROR_EXTENSION_NOT_PRESENT: + return "A requested extension is not supported"; + case VK_ERROR_FEATURE_NOT_PRESENT: + return "A requested feature is not supported"; + case VK_ERROR_INCOMPATIBLE_DRIVER: + return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible"; + case VK_ERROR_TOO_MANY_OBJECTS: + return "Too many objects of the type have already been created"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: + return "A requested format is not supported on this device"; + case VK_ERROR_SURFACE_LOST_KHR: + return "A surface is no longer available"; + case VK_SUBOPTIMAL_KHR: + return "A swapchain no longer matches the surface properties exactly, but can still be used"; + case VK_ERROR_OUT_OF_DATE_KHR: + return "A surface has changed in such a way that it is no longer compatible with the swapchain"; + case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: + return "The display used by a swapchain does not use the same presentable image layout"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: + return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API"; + case VK_ERROR_VALIDATION_FAILED_EXT: + return "A validation layer found an error"; + default: + return "ERROR: UNKNOWN VULKAN ERROR"; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI int glfwVulkanSupported(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + return _glfwInitVulkan(); +} + +GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count) +{ + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (!_glfwInitVulkan()) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available"); + return NULL; + } + + *count = _glfw.vk.extensionCount; + return (const char**) _glfw.vk.extensions; +} + +GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, + const char* procname) +{ + GLFWvkproc proc; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (!_glfwInitVulkan()) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available"); + return NULL; + } + + proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname); + if (!proc) + proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname); + + return proc; +} + +GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + if (!_glfwInitVulkan()) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available"); + return GLFW_FALSE; + } + + if (!_glfw.vk.extensions) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Window surface creation extensions not found"); + return GLFW_FALSE; + } + + return _glfwPlatformGetPhysicalDevicePresentationSupport(instance, + device, + queuefamily); +} + +GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, + GLFWwindow* handle, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + assert(surface != NULL); + + *surface = VK_NULL_HANDLE; + + _GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED); + + if (!_glfwInitVulkan()) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available"); + return VK_ERROR_INITIALIZATION_FAILED; + } + + if (!_glfw.vk.extensions) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Window surface creation extensions not found"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface); +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wgl_context.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wgl_context.c new file mode 100644 index 00000000..696c4cba --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wgl_context.c @@ -0,0 +1,718 @@ +//======================================================================== +// GLFW 3.2 WGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + + +// Returns the specified attribute of the specified pixel format +// +static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib) +{ + int value = 0; + + assert(_glfw.wgl.ARB_pixel_format); + + if (!_glfw.wgl.GetPixelFormatAttribivARB(window->context.wgl.dc, + pixelFormat, + 0, 1, &attrib, &value)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve pixel format attribute %i", + attrib); + return 0; + } + + return value; +} + +// Return a list of available and usable framebuffer configs +// +static int choosePixelFormat(_GLFWwindow* window, const _GLFWfbconfig* desired) +{ + _GLFWfbconfig* usableConfigs; + const _GLFWfbconfig* closest; + int i, pixelFormat, nativeCount, usableCount; + + if (_glfw.wgl.ARB_pixel_format) + { + nativeCount = getPixelFormatAttrib(window, + 1, + WGL_NUMBER_PIXEL_FORMATS_ARB); + } + else + { + nativeCount = DescribePixelFormat(window->context.wgl.dc, + 1, + sizeof(PIXELFORMATDESCRIPTOR), + NULL); + } + + usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableCount = 0; + + for (i = 0; i < nativeCount; i++) + { + const int n = i + 1; + _GLFWfbconfig* u = usableConfigs + usableCount; + + if (_glfw.wgl.ARB_pixel_format) + { + // Get pixel format attributes through "modern" extension + + if (!getPixelFormatAttrib(window, n, WGL_SUPPORT_OPENGL_ARB) || + !getPixelFormatAttrib(window, n, WGL_DRAW_TO_WINDOW_ARB)) + { + continue; + } + + if (getPixelFormatAttrib(window, n, WGL_PIXEL_TYPE_ARB) != + WGL_TYPE_RGBA_ARB) + { + continue; + } + + if (getPixelFormatAttrib(window, n, WGL_ACCELERATION_ARB) == + WGL_NO_ACCELERATION_ARB) + { + continue; + } + + u->redBits = getPixelFormatAttrib(window, n, WGL_RED_BITS_ARB); + u->greenBits = getPixelFormatAttrib(window, n, WGL_GREEN_BITS_ARB); + u->blueBits = getPixelFormatAttrib(window, n, WGL_BLUE_BITS_ARB); + u->alphaBits = getPixelFormatAttrib(window, n, WGL_ALPHA_BITS_ARB); + + u->depthBits = getPixelFormatAttrib(window, n, WGL_DEPTH_BITS_ARB); + u->stencilBits = getPixelFormatAttrib(window, n, WGL_STENCIL_BITS_ARB); + + u->accumRedBits = getPixelFormatAttrib(window, n, WGL_ACCUM_RED_BITS_ARB); + u->accumGreenBits = getPixelFormatAttrib(window, n, WGL_ACCUM_GREEN_BITS_ARB); + u->accumBlueBits = getPixelFormatAttrib(window, n, WGL_ACCUM_BLUE_BITS_ARB); + u->accumAlphaBits = getPixelFormatAttrib(window, n, WGL_ACCUM_ALPHA_BITS_ARB); + + u->auxBuffers = getPixelFormatAttrib(window, n, WGL_AUX_BUFFERS_ARB); + + if (getPixelFormatAttrib(window, n, WGL_STEREO_ARB)) + u->stereo = GLFW_TRUE; + if (getPixelFormatAttrib(window, n, WGL_DOUBLE_BUFFER_ARB)) + u->doublebuffer = GLFW_TRUE; + + if (_glfw.wgl.ARB_multisample) + u->samples = getPixelFormatAttrib(window, n, WGL_SAMPLES_ARB); + + if (_glfw.wgl.ARB_framebuffer_sRGB || + _glfw.wgl.EXT_framebuffer_sRGB) + { + if (getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) + u->sRGB = GLFW_TRUE; + } + } + else + { + PIXELFORMATDESCRIPTOR pfd; + + // Get pixel format attributes through legacy PFDs + + if (!DescribePixelFormat(window->context.wgl.dc, + n, + sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) + { + continue; + } + + if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) || + !(pfd.dwFlags & PFD_SUPPORT_OPENGL)) + { + continue; + } + + if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && + (pfd.dwFlags & PFD_GENERIC_FORMAT)) + { + continue; + } + + if (pfd.iPixelType != PFD_TYPE_RGBA) + continue; + + u->redBits = pfd.cRedBits; + u->greenBits = pfd.cGreenBits; + u->blueBits = pfd.cBlueBits; + u->alphaBits = pfd.cAlphaBits; + + u->depthBits = pfd.cDepthBits; + u->stencilBits = pfd.cStencilBits; + + u->accumRedBits = pfd.cAccumRedBits; + u->accumGreenBits = pfd.cAccumGreenBits; + u->accumBlueBits = pfd.cAccumBlueBits; + u->accumAlphaBits = pfd.cAccumAlphaBits; + + u->auxBuffers = pfd.cAuxBuffers; + + if (pfd.dwFlags & PFD_STEREO) + u->stereo = GLFW_TRUE; + if (pfd.dwFlags & PFD_DOUBLEBUFFER) + u->doublebuffer = GLFW_TRUE; + } + + u->handle = n; + usableCount++; + } + + if (!usableCount) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "WGL: The driver does not appear to support OpenGL"); + + free(usableConfigs); + return 0; + } + + closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); + if (!closest) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "WGL: Failed to find a suitable pixel format"); + + free(usableConfigs); + return 0; + } + + pixelFormat = (int) closest->handle; + free(usableConfigs); + + return pixelFormat; +} + +// Returns whether desktop compositing is enabled +// +static GLFWbool isCompositionEnabled(void) +{ + BOOL enabled; + + if (!_glfw_DwmIsCompositionEnabled) + return FALSE; + + if (_glfw_DwmIsCompositionEnabled(&enabled) != S_OK) + return FALSE; + + return enabled; +} + +static void makeContextCurrentWGL(_GLFWwindow* window) +{ + if (window) + { + if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle)) + _glfwPlatformSetCurrentContext(window); + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to make context current"); + _glfwPlatformSetCurrentContext(NULL); + } + } + else + { + if (!wglMakeCurrent(NULL, NULL)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to clear current context"); + } + + _glfwPlatformSetCurrentContext(NULL); + } +} + +static void swapBuffersWGL(_GLFWwindow* window) +{ + // HACK: Use DwmFlush when desktop composition is enabled + if (isCompositionEnabled() && !window->monitor) + { + int count = abs(window->context.wgl.interval); + while (count--) + _glfw_DwmFlush(); + } + + SwapBuffers(window->context.wgl.dc); +} + +static void swapIntervalWGL(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + window->context.wgl.interval = interval; + + // HACK: Disable WGL swap interval when desktop composition is enabled to + // avoid interfering with DWM vsync + if (isCompositionEnabled() && !window->monitor) + interval = 0; + + if (_glfw.wgl.EXT_swap_control) + _glfw.wgl.SwapIntervalEXT(interval); +} + +static int extensionSupportedWGL(const char* extension) +{ + const char* extensions; + + if (_glfw.wgl.GetExtensionsStringEXT) + { + extensions = _glfw.wgl.GetExtensionsStringEXT(); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + } + + if (_glfw.wgl.GetExtensionsStringARB) + { + extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC()); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddressWGL(const char* procname) +{ + const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname); + if (proc) + return proc; + + return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname); +} + +// Destroy the OpenGL context +// +static void destroyContextWGL(_GLFWwindow* window) +{ + if (window->context.wgl.handle) + { + wglDeleteContext(window->context.wgl.handle); + window->context.wgl.handle = NULL; + } +} + +// Initialize WGL-specific extensions +// +static void loadWGLExtensions(void) +{ + PIXELFORMATDESCRIPTOR pfd; + HGLRC rc; + HDC dc = GetDC(_glfw.win32.helperWindowHandle);; + + _glfw.wgl.extensionsLoaded = GLFW_TRUE; + + // NOTE: A dummy context has to be created for opengl32.dll to load the + // OpenGL ICD, from which we can then query WGL extensions + // NOTE: This code will accept the Microsoft GDI ICD; accelerated context + // creation failure occurs during manual pixel format enumeration + + ZeroMemory(&pfd, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 24; + + if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to set pixel format for dummy context"); + return; + } + + rc = wglCreateContext(dc); + if (!rc) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to create dummy context"); + return; + } + + if (!wglMakeCurrent(dc, rc)) + { + wglDeleteContext(rc); + + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to make dummy context current"); + return; + } + + // NOTE: Functions must be loaded first as they're needed to retrieve the + // extension string that tells us whether the functions are supported + _glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) + wglGetProcAddress("wglGetExtensionsStringEXT"); + _glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) + wglGetProcAddress("wglGetExtensionsStringARB"); + _glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) + wglGetProcAddress("wglCreateContextAttribsARB"); + _glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) + wglGetProcAddress("wglSwapIntervalEXT"); + _glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) + wglGetProcAddress("wglGetPixelFormatAttribivARB"); + + // NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not + // checked below as we are already using them + _glfw.wgl.ARB_multisample = + extensionSupportedWGL("WGL_ARB_multisample"); + _glfw.wgl.ARB_framebuffer_sRGB = + extensionSupportedWGL("WGL_ARB_framebuffer_sRGB"); + _glfw.wgl.EXT_framebuffer_sRGB = + extensionSupportedWGL("WGL_EXT_framebuffer_sRGB"); + _glfw.wgl.ARB_create_context = + extensionSupportedWGL("WGL_ARB_create_context"); + _glfw.wgl.ARB_create_context_profile = + extensionSupportedWGL("WGL_ARB_create_context_profile"); + _glfw.wgl.EXT_create_context_es2_profile = + extensionSupportedWGL("WGL_EXT_create_context_es2_profile"); + _glfw.wgl.ARB_create_context_robustness = + extensionSupportedWGL("WGL_ARB_create_context_robustness"); + _glfw.wgl.EXT_swap_control = + extensionSupportedWGL("WGL_EXT_swap_control"); + _glfw.wgl.ARB_pixel_format = + extensionSupportedWGL("WGL_ARB_pixel_format"); + _glfw.wgl.ARB_context_flush_control = + extensionSupportedWGL("WGL_ARB_context_flush_control"); + + wglMakeCurrent(dc, NULL); + wglDeleteContext(rc); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize WGL +// +GLFWbool _glfwInitWGL(void) +{ + if (_glfw.wgl.instance) + return GLFW_TRUE; + + _glfw.wgl.instance = LoadLibraryA("opengl32.dll"); + if (!_glfw.wgl.instance) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to load opengl32.dll"); + return GLFW_FALSE; + } + + _glfw.wgl.CreateContext = (WGLCREATECONTEXT_T) + GetProcAddress(_glfw.wgl.instance, "wglCreateContext"); + _glfw.wgl.DeleteContext = (WGLDELETECONTEXT_T) + GetProcAddress(_glfw.wgl.instance, "wglDeleteContext"); + _glfw.wgl.GetProcAddress = (WGLGETPROCADDRESS_T) + GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress"); + _glfw.wgl.GetCurrentDC = (WGLGETCURRENTDC_T) + GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC"); + _glfw.wgl.MakeCurrent = (WGLMAKECURRENT_T) + GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent"); + _glfw.wgl.ShareLists = (WGLSHARELISTS_T) + GetProcAddress(_glfw.wgl.instance, "wglShareLists"); + + return GLFW_TRUE; +} + +// Terminate WGL +// +void _glfwTerminateWGL(void) +{ + if (_glfw.wgl.instance) + FreeLibrary(_glfw.wgl.instance); +} + +#define setWGLattrib(attribName, attribValue) \ +{ \ + attribs[index++] = attribName; \ + attribs[index++] = attribValue; \ + assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ +} + +// Create the OpenGL or OpenGL ES context +// +GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + int attribs[40]; + int pixelFormat; + PIXELFORMATDESCRIPTOR pfd; + HGLRC share = NULL; + + if (!_glfw.wgl.extensionsLoaded) + loadWGLExtensions(); + + if (ctxconfig->share) + share = ctxconfig->share->context.wgl.handle; + + window->context.wgl.dc = GetDC(window->win32.handle); + if (!window->context.wgl.dc) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve DC for window"); + return GLFW_FALSE; + } + + pixelFormat = choosePixelFormat(window, fbconfig); + if (!pixelFormat) + return GLFW_FALSE; + + if (!DescribePixelFormat(window->context.wgl.dc, + pixelFormat, sizeof(pfd), &pfd)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve PFD for selected pixel format"); + return GLFW_FALSE; + } + + if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to set selected pixel format"); + return GLFW_FALSE; + } + + if (ctxconfig->client == GLFW_OPENGL_API) + { + if (ctxconfig->forward) + { + if (!_glfw.wgl.ARB_create_context) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable"); + return GLFW_FALSE; + } + } + + if (ctxconfig->profile) + { + if (!_glfw.wgl.ARB_create_context_profile) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable"); + return GLFW_FALSE; + } + } + } + else + { + if (!_glfw.wgl.ARB_create_context || + !_glfw.wgl.ARB_create_context_profile || + !_glfw.wgl.EXT_create_context_es2_profile) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable"); + return GLFW_FALSE; + } + } + + if (_glfw.wgl.ARB_create_context) + { + int index = 0, mask = 0, flags = 0; + + if (ctxconfig->client == GLFW_OPENGL_API) + { + if (ctxconfig->forward) + flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) + mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; + else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) + mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + } + else + mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT; + + if (ctxconfig->debug) + flags |= WGL_CONTEXT_DEBUG_BIT_ARB; + if (ctxconfig->noerror) + flags |= GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR; + + if (ctxconfig->robustness) + { + if (_glfw.wgl.ARB_create_context_robustness) + { + if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) + { + setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_NO_RESET_NOTIFICATION_ARB); + } + else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) + { + setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_LOSE_CONTEXT_ON_RESET_ARB); + } + + flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; + } + } + + if (ctxconfig->release) + { + if (_glfw.wgl.ARB_context_flush_control) + { + if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) + { + setWGLattrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + } + else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) + { + setWGLattrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + } + } + } + + // NOTE: Only request an explicitly versioned context when necessary, as + // explicitly requesting version 1.0 does not always return the + // highest version supported by the driver + if (ctxconfig->major != 1 || ctxconfig->minor != 0) + { + setWGLattrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + setWGLattrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); + } + + if (flags) + setWGLattrib(WGL_CONTEXT_FLAGS_ARB, flags); + + if (mask) + setWGLattrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); + + setWGLattrib(0, 0); + + window->context.wgl.handle = + _glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc, + share, attribs); + if (!window->context.wgl.handle) + { + const DWORD error = GetLastError(); + + if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB)) + { + if (ctxconfig->client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Driver does not support OpenGL version %i.%i", + ctxconfig->major, + ctxconfig->minor); + } + else + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Driver does not support OpenGL ES version %i.%i", + ctxconfig->major, + ctxconfig->minor); + } + } + else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB)) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Driver does not support the requested OpenGL profile"); + } + else + { + if (ctxconfig->client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Failed to create OpenGL context"); + } + else + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Failed to create OpenGL ES context"); + } + } + + return GLFW_FALSE; + } + } + else + { + window->context.wgl.handle = wglCreateContext(window->context.wgl.dc); + if (!window->context.wgl.handle) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Failed to create OpenGL context"); + return GLFW_FALSE; + } + + if (share) + { + if (!wglShareLists(share, window->context.wgl.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to enable sharing with specified OpenGL context"); + return GLFW_FALSE; + } + } + } + + window->context.makeCurrent = makeContextCurrentWGL; + window->context.swapBuffers = swapBuffersWGL; + window->context.swapInterval = swapIntervalWGL; + window->context.extensionSupported = extensionSupportedWGL; + window->context.getProcAddress = getProcAddressWGL; + window->context.destroy = destroyContextWGL; + + return GLFW_TRUE; +} + +#undef setWGLattrib + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return NULL; + } + + return window->context.wgl.handle; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wgl_context.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wgl_context.h new file mode 100644 index 00000000..b837d438 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wgl_context.h @@ -0,0 +1,157 @@ +//======================================================================== +// GLFW 3.2 WGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_wgl_context_h_ +#define _glfw3_wgl_context_h_ + + +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_TYPE_RGBA_ARB 0x202b +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_RED_SHIFT_ARB 0x2016 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_GREEN_SHIFT_ARB 0x2018 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_BLUE_SHIFT_ARB 0x201a +#define WGL_ALPHA_BITS_ARB 0x201b +#define WGL_ALPHA_SHIFT_ARB 0x201c +#define WGL_ACCUM_BITS_ARB 0x201d +#define WGL_ACCUM_RED_BITS_ARB 0x201e +#define WGL_ACCUM_GREEN_BITS_ARB 0x201f +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_STEREO_ARB 0x2012 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_SAMPLES_ARB 0x2042 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 + +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 + +typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int); +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*); +typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void); +typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC); +typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*); + +typedef HGLRC (WINAPI * WGLCREATECONTEXT_T)(HDC); +typedef BOOL (WINAPI * WGLDELETECONTEXT_T)(HGLRC); +typedef PROC (WINAPI * WGLGETPROCADDRESS_T)(LPCSTR); +typedef HDC (WINAPI * WGLGETCURRENTDC_T)(void); +typedef BOOL (WINAPI * WGLMAKECURRENT_T)(HDC,HGLRC); +typedef BOOL (WINAPI * WGLSHARELISTS_T)(HGLRC,HGLRC); + +// opengl32.dll function pointer typedefs +#define wglCreateContext _glfw.wgl.CreateContext +#define wglDeleteContext _glfw.wgl.DeleteContext +#define wglGetProcAddress _glfw.wgl.GetProcAddress +#define wglGetCurrentDC _glfw.wgl.GetCurrentDC +#define wglMakeCurrent _glfw.wgl.MakeCurrent +#define wglShareLists _glfw.wgl.ShareLists + +#define _GLFW_RECREATION_NOT_NEEDED 0 +#define _GLFW_RECREATION_REQUIRED 1 +#define _GLFW_RECREATION_IMPOSSIBLE 2 + +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl + + +// WGL-specific per-context data +// +typedef struct _GLFWcontextWGL +{ + HDC dc; + HGLRC handle; + int interval; + +} _GLFWcontextWGL; + +// WGL-specific global data +// +typedef struct _GLFWlibraryWGL +{ + HINSTANCE instance; + WGLCREATECONTEXT_T CreateContext; + WGLDELETECONTEXT_T DeleteContext; + WGLGETPROCADDRESS_T GetProcAddress; + WGLGETCURRENTDC_T GetCurrentDC; + WGLMAKECURRENT_T MakeCurrent; + WGLSHARELISTS_T ShareLists; + + GLFWbool extensionsLoaded; + + PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT; + PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB; + PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; + PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB; + PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + GLFWbool EXT_swap_control; + GLFWbool ARB_multisample; + GLFWbool ARB_framebuffer_sRGB; + GLFWbool EXT_framebuffer_sRGB; + GLFWbool ARB_pixel_format; + GLFWbool ARB_create_context; + GLFWbool ARB_create_context_profile; + GLFWbool EXT_create_context_es2_profile; + GLFWbool ARB_create_context_robustness; + GLFWbool ARB_context_flush_control; + +} _GLFWlibraryWGL; + + +GLFWbool _glfwInitWGL(void); +void _glfwTerminateWGL(void); +GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); + +#endif // _glfw3_wgl_context_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_init.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_init.c new file mode 100644 index 00000000..b2a0a679 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_init.c @@ -0,0 +1,473 @@ +//======================================================================== +// GLFW 3.2 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + +#include +DEFINE_GUID(GUID_DEVINTERFACE_HID,0x4d1e55b2,0xf16f,0x11cf,0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30); + +#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG) + +// Applications exporting this symbol with this value will be automatically +// directed to the high-performance GPU on Nvidia Optimus systems with +// up-to-date drivers +// +__declspec(dllexport) DWORD NvOptimusEnablement = 1; + +// Applications exporting this symbol with this value will be automatically +// directed to the high-performance GPU on AMD PowerXpress systems with +// up-to-date drivers +// +__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; + +#endif // _GLFW_USE_HYBRID_HPG + +#if defined(_GLFW_BUILD_DLL) + +// GLFW DLL entry point +// +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) +{ + return TRUE; +} + +#endif // _GLFW_BUILD_DLL + +// Load necessary libraries (DLLs) +// +static GLFWbool loadLibraries(void) +{ + _glfw.win32.winmm.instance = LoadLibraryA("winmm.dll"); + if (!_glfw.win32.winmm.instance) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to load winmm.dll"); + return GLFW_FALSE; + } + + _glfw.win32.winmm.timeGetTime = (TIMEGETTIME_T) + GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime"); + + _glfw.win32.user32.instance = LoadLibraryA("user32.dll"); + if (!_glfw.win32.user32.instance) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to load user32.dll"); + return GLFW_FALSE; + } + + _glfw.win32.user32.SetProcessDPIAware = (SETPROCESSDPIAWARE_T) + GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware"); + _glfw.win32.user32.ChangeWindowMessageFilterEx = (CHANGEWINDOWMESSAGEFILTEREX_T) + GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); + + _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll"); + if (_glfw.win32.dinput8.instance) + { + _glfw.win32.dinput8.DirectInput8Create = (DIRECTINPUT8CREATE_T) + GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create"); + } + + { + int i; + const char* names[] = + { + "xinput1_4.dll", + "xinput1_3.dll", + "xinput9_1_0.dll", + "xinput1_2.dll", + "xinput1_1.dll", + NULL + }; + + for (i = 0; names[i]; i++) + { + _glfw.win32.xinput.instance = LoadLibraryA(names[i]); + if (_glfw.win32.xinput.instance) + { + _glfw.win32.xinput.XInputGetCapabilities = (XINPUTGETCAPABILITIES_T) + GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities"); + _glfw.win32.xinput.XInputGetState = (XINPUTGETSTATE_T) + GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState"); + + break; + } + } + } + + _glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll"); + if (_glfw.win32.dwmapi.instance) + { + _glfw.win32.dwmapi.DwmIsCompositionEnabled = (DWMISCOMPOSITIONENABLED_T) + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); + _glfw.win32.dwmapi.DwmFlush = (DWMFLUSH_T) + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush"); + } + + _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll"); + if (_glfw.win32.shcore.instance) + { + _glfw.win32.shcore.SetProcessDpiAwareness = (SETPROCESSDPIAWARENESS_T) + GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness"); + } + + return GLFW_TRUE; +} + +// Unload used libraries (DLLs) +// +static void freeLibraries(void) +{ + if (_glfw.win32.xinput.instance) + FreeLibrary(_glfw.win32.xinput.instance); + + if (_glfw.win32.dinput8.instance) + FreeLibrary(_glfw.win32.dinput8.instance); + + if (_glfw.win32.winmm.instance) + FreeLibrary(_glfw.win32.winmm.instance); + + if (_glfw.win32.user32.instance) + FreeLibrary(_glfw.win32.user32.instance); + + if (_glfw.win32.dwmapi.instance) + FreeLibrary(_glfw.win32.dwmapi.instance); + + if (_glfw.win32.shcore.instance) + FreeLibrary(_glfw.win32.shcore.instance); +} + +// Create key code translation tables +// +static void createKeyTables(void) +{ + int scancode; + + memset(_glfw.win32.publicKeys, -1, sizeof(_glfw.win32.publicKeys)); + memset(_glfw.win32.nativeKeys, -1, sizeof(_glfw.win32.nativeKeys)); + + _glfw.win32.publicKeys[0x00B] = GLFW_KEY_0; + _glfw.win32.publicKeys[0x002] = GLFW_KEY_1; + _glfw.win32.publicKeys[0x003] = GLFW_KEY_2; + _glfw.win32.publicKeys[0x004] = GLFW_KEY_3; + _glfw.win32.publicKeys[0x005] = GLFW_KEY_4; + _glfw.win32.publicKeys[0x006] = GLFW_KEY_5; + _glfw.win32.publicKeys[0x007] = GLFW_KEY_6; + _glfw.win32.publicKeys[0x008] = GLFW_KEY_7; + _glfw.win32.publicKeys[0x009] = GLFW_KEY_8; + _glfw.win32.publicKeys[0x00A] = GLFW_KEY_9; + _glfw.win32.publicKeys[0x01E] = GLFW_KEY_A; + _glfw.win32.publicKeys[0x030] = GLFW_KEY_B; + _glfw.win32.publicKeys[0x02E] = GLFW_KEY_C; + _glfw.win32.publicKeys[0x020] = GLFW_KEY_D; + _glfw.win32.publicKeys[0x012] = GLFW_KEY_E; + _glfw.win32.publicKeys[0x021] = GLFW_KEY_F; + _glfw.win32.publicKeys[0x022] = GLFW_KEY_G; + _glfw.win32.publicKeys[0x023] = GLFW_KEY_H; + _glfw.win32.publicKeys[0x017] = GLFW_KEY_I; + _glfw.win32.publicKeys[0x024] = GLFW_KEY_J; + _glfw.win32.publicKeys[0x025] = GLFW_KEY_K; + _glfw.win32.publicKeys[0x026] = GLFW_KEY_L; + _glfw.win32.publicKeys[0x032] = GLFW_KEY_M; + _glfw.win32.publicKeys[0x031] = GLFW_KEY_N; + _glfw.win32.publicKeys[0x018] = GLFW_KEY_O; + _glfw.win32.publicKeys[0x019] = GLFW_KEY_P; + _glfw.win32.publicKeys[0x010] = GLFW_KEY_Q; + _glfw.win32.publicKeys[0x013] = GLFW_KEY_R; + _glfw.win32.publicKeys[0x01F] = GLFW_KEY_S; + _glfw.win32.publicKeys[0x014] = GLFW_KEY_T; + _glfw.win32.publicKeys[0x016] = GLFW_KEY_U; + _glfw.win32.publicKeys[0x02F] = GLFW_KEY_V; + _glfw.win32.publicKeys[0x011] = GLFW_KEY_W; + _glfw.win32.publicKeys[0x02D] = GLFW_KEY_X; + _glfw.win32.publicKeys[0x015] = GLFW_KEY_Y; + _glfw.win32.publicKeys[0x02C] = GLFW_KEY_Z; + + _glfw.win32.publicKeys[0x028] = GLFW_KEY_APOSTROPHE; + _glfw.win32.publicKeys[0x02B] = GLFW_KEY_BACKSLASH; + _glfw.win32.publicKeys[0x033] = GLFW_KEY_COMMA; + _glfw.win32.publicKeys[0x00D] = GLFW_KEY_EQUAL; + _glfw.win32.publicKeys[0x029] = GLFW_KEY_GRAVE_ACCENT; + _glfw.win32.publicKeys[0x01A] = GLFW_KEY_LEFT_BRACKET; + _glfw.win32.publicKeys[0x00C] = GLFW_KEY_MINUS; + _glfw.win32.publicKeys[0x034] = GLFW_KEY_PERIOD; + _glfw.win32.publicKeys[0x01B] = GLFW_KEY_RIGHT_BRACKET; + _glfw.win32.publicKeys[0x027] = GLFW_KEY_SEMICOLON; + _glfw.win32.publicKeys[0x035] = GLFW_KEY_SLASH; + _glfw.win32.publicKeys[0x056] = GLFW_KEY_WORLD_2; + + _glfw.win32.publicKeys[0x00E] = GLFW_KEY_BACKSPACE; + _glfw.win32.publicKeys[0x153] = GLFW_KEY_DELETE; + _glfw.win32.publicKeys[0x14F] = GLFW_KEY_END; + _glfw.win32.publicKeys[0x01C] = GLFW_KEY_ENTER; + _glfw.win32.publicKeys[0x001] = GLFW_KEY_ESCAPE; + _glfw.win32.publicKeys[0x147] = GLFW_KEY_HOME; + _glfw.win32.publicKeys[0x152] = GLFW_KEY_INSERT; + _glfw.win32.publicKeys[0x15D] = GLFW_KEY_MENU; + _glfw.win32.publicKeys[0x151] = GLFW_KEY_PAGE_DOWN; + _glfw.win32.publicKeys[0x149] = GLFW_KEY_PAGE_UP; + _glfw.win32.publicKeys[0x045] = GLFW_KEY_PAUSE; + _glfw.win32.publicKeys[0x146] = GLFW_KEY_PAUSE; + _glfw.win32.publicKeys[0x039] = GLFW_KEY_SPACE; + _glfw.win32.publicKeys[0x00F] = GLFW_KEY_TAB; + _glfw.win32.publicKeys[0x03A] = GLFW_KEY_CAPS_LOCK; + _glfw.win32.publicKeys[0x145] = GLFW_KEY_NUM_LOCK; + _glfw.win32.publicKeys[0x046] = GLFW_KEY_SCROLL_LOCK; + _glfw.win32.publicKeys[0x03B] = GLFW_KEY_F1; + _glfw.win32.publicKeys[0x03C] = GLFW_KEY_F2; + _glfw.win32.publicKeys[0x03D] = GLFW_KEY_F3; + _glfw.win32.publicKeys[0x03E] = GLFW_KEY_F4; + _glfw.win32.publicKeys[0x03F] = GLFW_KEY_F5; + _glfw.win32.publicKeys[0x040] = GLFW_KEY_F6; + _glfw.win32.publicKeys[0x041] = GLFW_KEY_F7; + _glfw.win32.publicKeys[0x042] = GLFW_KEY_F8; + _glfw.win32.publicKeys[0x043] = GLFW_KEY_F9; + _glfw.win32.publicKeys[0x044] = GLFW_KEY_F10; + _glfw.win32.publicKeys[0x057] = GLFW_KEY_F11; + _glfw.win32.publicKeys[0x058] = GLFW_KEY_F12; + _glfw.win32.publicKeys[0x064] = GLFW_KEY_F13; + _glfw.win32.publicKeys[0x065] = GLFW_KEY_F14; + _glfw.win32.publicKeys[0x066] = GLFW_KEY_F15; + _glfw.win32.publicKeys[0x067] = GLFW_KEY_F16; + _glfw.win32.publicKeys[0x068] = GLFW_KEY_F17; + _glfw.win32.publicKeys[0x069] = GLFW_KEY_F18; + _glfw.win32.publicKeys[0x06A] = GLFW_KEY_F19; + _glfw.win32.publicKeys[0x06B] = GLFW_KEY_F20; + _glfw.win32.publicKeys[0x06C] = GLFW_KEY_F21; + _glfw.win32.publicKeys[0x06D] = GLFW_KEY_F22; + _glfw.win32.publicKeys[0x06E] = GLFW_KEY_F23; + _glfw.win32.publicKeys[0x076] = GLFW_KEY_F24; + _glfw.win32.publicKeys[0x038] = GLFW_KEY_LEFT_ALT; + _glfw.win32.publicKeys[0x01D] = GLFW_KEY_LEFT_CONTROL; + _glfw.win32.publicKeys[0x02A] = GLFW_KEY_LEFT_SHIFT; + _glfw.win32.publicKeys[0x15B] = GLFW_KEY_LEFT_SUPER; + _glfw.win32.publicKeys[0x137] = GLFW_KEY_PRINT_SCREEN; + _glfw.win32.publicKeys[0x138] = GLFW_KEY_RIGHT_ALT; + _glfw.win32.publicKeys[0x11D] = GLFW_KEY_RIGHT_CONTROL; + _glfw.win32.publicKeys[0x036] = GLFW_KEY_RIGHT_SHIFT; + _glfw.win32.publicKeys[0x15C] = GLFW_KEY_RIGHT_SUPER; + _glfw.win32.publicKeys[0x150] = GLFW_KEY_DOWN; + _glfw.win32.publicKeys[0x14B] = GLFW_KEY_LEFT; + _glfw.win32.publicKeys[0x14D] = GLFW_KEY_RIGHT; + _glfw.win32.publicKeys[0x148] = GLFW_KEY_UP; + + _glfw.win32.publicKeys[0x052] = GLFW_KEY_KP_0; + _glfw.win32.publicKeys[0x04F] = GLFW_KEY_KP_1; + _glfw.win32.publicKeys[0x050] = GLFW_KEY_KP_2; + _glfw.win32.publicKeys[0x051] = GLFW_KEY_KP_3; + _glfw.win32.publicKeys[0x04B] = GLFW_KEY_KP_4; + _glfw.win32.publicKeys[0x04C] = GLFW_KEY_KP_5; + _glfw.win32.publicKeys[0x04D] = GLFW_KEY_KP_6; + _glfw.win32.publicKeys[0x047] = GLFW_KEY_KP_7; + _glfw.win32.publicKeys[0x048] = GLFW_KEY_KP_8; + _glfw.win32.publicKeys[0x049] = GLFW_KEY_KP_9; + _glfw.win32.publicKeys[0x04E] = GLFW_KEY_KP_ADD; + _glfw.win32.publicKeys[0x053] = GLFW_KEY_KP_DECIMAL; + _glfw.win32.publicKeys[0x135] = GLFW_KEY_KP_DIVIDE; + _glfw.win32.publicKeys[0x11C] = GLFW_KEY_KP_ENTER; + _glfw.win32.publicKeys[0x037] = GLFW_KEY_KP_MULTIPLY; + _glfw.win32.publicKeys[0x04A] = GLFW_KEY_KP_SUBTRACT; + + for (scancode = 0; scancode < 512; scancode++) + { + if (_glfw.win32.publicKeys[scancode] > 0) + _glfw.win32.nativeKeys[_glfw.win32.publicKeys[scancode]] = scancode; + } +} + +// Creates a dummy window for behind-the-scenes work +// +static HWND createHelperWindow(void) +{ + HWND window = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, + _GLFW_WNDCLASSNAME, + L"GLFW helper window", + WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + 0, 0, 1, 1, + HWND_MESSAGE, NULL, + GetModuleHandleW(NULL), + NULL); + if (!window) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to create helper window"); + return NULL; + } + + // HACK: The first call to ShowWindow is ignored if the parent process + // passed along a STARTUPINFO, so clear that flag with a no-op call + ShowWindow(window, SW_HIDE); + + // Register for HID device notifications + { + DEV_BROADCAST_DEVICEINTERFACE_W dbi; + ZeroMemory(&dbi, sizeof(dbi)); + dbi.dbcc_size = sizeof(dbi); + dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + dbi.dbcc_classguid = GUID_DEVINTERFACE_HID; + + RegisterDeviceNotificationW(window, + (DEV_BROADCAST_HDR*) &dbi, + DEVICE_NOTIFY_WINDOW_HANDLE); + } + + return window; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Returns a wide string version of the specified UTF-8 string +// +WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source) +{ + WCHAR* target; + int length; + + length = MultiByteToWideChar(CP_UTF8, 0, source, -1, NULL, 0); + if (!length) + return NULL; + + target = calloc(length, sizeof(WCHAR)); + + if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, length)) + { + free(target); + return NULL; + } + + return target; +} + +// Returns a UTF-8 string version of the specified wide string +// +char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source) +{ + char* target; + int length; + + length = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); + if (!length) + return NULL; + + target = calloc(length, 1); + + if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, length, NULL, NULL)) + { + free(target); + return NULL; + } + + return target; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + if (!_glfwInitThreadLocalStorageWin32()) + return GLFW_FALSE; + + // To make SetForegroundWindow work as we want, we need to fiddle + // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early + // as possible in the hope of still being the foreground process) + SystemParametersInfoW(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, + &_glfw.win32.foregroundLockTimeout, 0); + SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UIntToPtr(0), + SPIF_SENDCHANGE); + + if (!loadLibraries()) + return GLFW_FALSE; + + createKeyTables(); + + if (_glfw_SetProcessDpiAwareness) + _glfw_SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); + else if (_glfw_SetProcessDPIAware) + _glfw_SetProcessDPIAware(); + + if (!_glfwRegisterWindowClassWin32()) + return GLFW_FALSE; + + _glfw.win32.helperWindowHandle = createHelperWindow(); + if (!_glfw.win32.helperWindowHandle) + return GLFW_FALSE; + + _glfwPlatformPollEvents(); + + _glfwInitTimerWin32(); + _glfwInitJoysticksWin32(); + + return GLFW_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + if (_glfw.win32.helperWindowHandle) + DestroyWindow(_glfw.win32.helperWindowHandle); + + _glfwUnregisterWindowClassWin32(); + + // Restore previous foreground lock timeout system setting + SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, + UIntToPtr(_glfw.win32.foregroundLockTimeout), + SPIF_SENDCHANGE); + + free(_glfw.win32.clipboardString); + + _glfwTerminateWGL(); + _glfwTerminateEGL(); + + _glfwTerminateJoysticksWin32(); + _glfwTerminateThreadLocalStorageWin32(); + + freeLibraries(); +} + +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " Win32 WGL EGL" +#if defined(__MINGW32__) + " MinGW" +#elif defined(_MSC_VER) + " VisualC" +#endif +#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG) + " hybrid-GPU" +#endif +#if defined(_GLFW_BUILD_DLL) + " DLL" +#endif + ; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_joystick.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_joystick.c new file mode 100644 index 00000000..49f3b871 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_joystick.c @@ -0,0 +1,763 @@ +//======================================================================== +// GLFW 3.1 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include + +#include + +#define _GLFW_PRESENCE_ONLY 1 +#define _GLFW_UPDATE_STATE 2 + +#define _GLFW_TYPE_AXIS 0 +#define _GLFW_TYPE_SLIDER 1 +#define _GLFW_TYPE_BUTTON 2 +#define _GLFW_TYPE_POV 3 + +// Data produced with DirectInput device object enumeration +// +typedef struct _GLFWobjenumWin32 +{ + IDirectInputDevice8W* device; + _GLFWjoyobjectWin32* objects; + int objectCount; + int axisCount; + int sliderCount; + int buttonCount; + int povCount; +} _GLFWobjenumWin32; + +// Define only the necessary GUIDs (it's bad enough that we're exporting these) +// +DEFINE_GUID(IID_IDirectInput8W,0xbf798031,0x483a,0x4da2,0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00); +DEFINE_GUID(GUID_XAxis,0xa36d02e0,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_YAxis,0xa36d02e1,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_ZAxis,0xa36d02e2,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RxAxis,0xa36d02f4,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RyAxis,0xa36d02f5,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RzAxis,0xa36d02e3,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Slider,0xa36d02e4,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Button,0xa36d02f0,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_POV,0xa36d02f2,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00); + +// Object data array for our clone of c_dfDIJoystick +// Generated with /~https://github.com/elmindreda/c_dfDIJoystick2 +// +static DIOBJECTDATAFORMAT _glfwObjectDataFormats[] = +{ + { &GUID_XAxis,DIJOFS_X,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_YAxis,DIJOFS_Y,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_ZAxis,DIJOFS_Z,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_RxAxis,DIJOFS_RX,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_RyAxis,DIJOFS_RY,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_RzAxis,DIJOFS_RZ,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_POV,DIJOFS_POV(0),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { &GUID_POV,DIJOFS_POV(1),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { &GUID_POV,DIJOFS_POV(2),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { &GUID_POV,DIJOFS_POV(3),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(0),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(1),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(2),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(3),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(4),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(5),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(6),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(7),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(8),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(9),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(10),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(11),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(12),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(13),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(14),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(15),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(16),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(17),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(18),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(19),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(20),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(21),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(22),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(23),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(24),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(25),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(26),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(27),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(28),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(29),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(30),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(31),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, +}; + +// Our clone of c_dfDIJoystick +// +static const DIDATAFORMAT _glfwDataFormat = +{ + sizeof(DIDATAFORMAT), + sizeof(DIOBJECTDATAFORMAT), + DIDFT_ABSAXIS, + sizeof(DIJOYSTATE), + sizeof(_glfwObjectDataFormats) / sizeof(DIOBJECTDATAFORMAT), + _glfwObjectDataFormats +}; + +// Returns a description fitting the specified XInput capabilities +// +static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic) +{ + switch (xic->SubType) + { + case XINPUT_DEVSUBTYPE_WHEEL: + return "XInput Wheel"; + case XINPUT_DEVSUBTYPE_ARCADE_STICK: + return "XInput Arcade Stick"; + case XINPUT_DEVSUBTYPE_FLIGHT_STICK: + return "XInput Flight Stick"; + case XINPUT_DEVSUBTYPE_DANCE_PAD: + return "XInput Dance Pad"; + case XINPUT_DEVSUBTYPE_GUITAR: + return "XInput Guitar"; + case XINPUT_DEVSUBTYPE_DRUM_KIT: + return "XInput Drum Kit"; + case XINPUT_DEVSUBTYPE_GAMEPAD: + { + if (xic->Flags & XINPUT_CAPS_WIRELESS) + return "Wireless Xbox 360 Controller"; + else + return "Xbox 360 Controller"; + } + } + + return "Unknown XInput Device"; +} + +// Lexically compare device objects +// +static int compareJoystickObjects(const void* first, const void* second) +{ + const _GLFWjoyobjectWin32* fo = first; + const _GLFWjoyobjectWin32* so = second; + + if (fo->type != so->type) + return fo->type - so->type; + + return fo->offset - so->offset; +} + +// Checks whether the specified device supports XInput +// Technique from FDInputJoystickManager::IsXInputDeviceFast in ZDoom +// +static GLFWbool supportsXInput(const GUID* guid) +{ + UINT i, count = 0; + RAWINPUTDEVICELIST* ridl; + GLFWbool result = GLFW_FALSE; + + if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0) + return GLFW_FALSE; + + ridl = calloc(count, sizeof(RAWINPUTDEVICELIST)); + + if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1) + { + free(ridl); + return GLFW_FALSE; + } + + for (i = 0; i < count; i++) + { + RID_DEVICE_INFO rdi; + char name[256]; + UINT size; + + if (ridl[i].dwType != RIM_TYPEHID) + continue; + + ZeroMemory(&rdi, sizeof(rdi)); + rdi.cbSize = sizeof(rdi); + size = sizeof(rdi); + + if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice, + RIDI_DEVICEINFO, + &rdi, &size) == -1) + { + continue; + } + + if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != (LONG) guid->Data1) + continue; + + memset(name, 0, sizeof(name)); + size = sizeof(name); + + if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice, + RIDI_DEVICENAME, + name, &size) == -1) + { + break; + } + + name[sizeof(name) - 1] = '\0'; + if (strstr(name, "IG_")) + { + result = GLFW_TRUE; + break; + } + } + + free(ridl); + return result; +} + +// Frees all resources associated with the specified joystick +// +static void closeJoystick(_GLFWjoystickWin32* js) +{ + if (js->device) + { + IDirectInputDevice8_Unacquire(js->device); + IDirectInputDevice8_Release(js->device); + } + + free(js->name); + free(js->axes); + free(js->buttons); + free(js->objects); + memset(js, 0, sizeof(_GLFWjoystickWin32)); + + _glfwInputJoystickChange((int) (js - _glfw.win32_js), GLFW_DISCONNECTED); +} + +// DirectInput device object enumeration callback +// Insights gleaned from SDL2 +// +static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi, + void* user) +{ + _GLFWobjenumWin32* data = user; + _GLFWjoyobjectWin32* object = data->objects + data->objectCount; + + if (DIDFT_GETTYPE(doi->dwType) & DIDFT_AXIS) + { + DIPROPRANGE dipr; + + if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0) + object->offset = DIJOFS_SLIDER(data->sliderCount); + else if (memcmp(&doi->guidType, &GUID_XAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_X; + else if (memcmp(&doi->guidType, &GUID_YAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_Y; + else if (memcmp(&doi->guidType, &GUID_ZAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_Z; + else if (memcmp(&doi->guidType, &GUID_RxAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_RX; + else if (memcmp(&doi->guidType, &GUID_RyAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_RY; + else if (memcmp(&doi->guidType, &GUID_RzAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_RZ; + else + return DIENUM_CONTINUE; + + ZeroMemory(&dipr, sizeof(dipr)); + dipr.diph.dwSize = sizeof(dipr); + dipr.diph.dwHeaderSize = sizeof(dipr.diph); + dipr.diph.dwObj = doi->dwType; + dipr.diph.dwHow = DIPH_BYID; + dipr.lMin = -32768; + dipr.lMax = 32767; + + if (FAILED(IDirectInputDevice8_SetProperty(data->device, + DIPROP_RANGE, + &dipr.diph))) + { + return DIENUM_CONTINUE; + } + + if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0) + { + object->type = _GLFW_TYPE_SLIDER; + data->sliderCount++; + } + else + { + object->type = _GLFW_TYPE_AXIS; + data->axisCount++; + } + } + else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_BUTTON) + { + object->offset = DIJOFS_BUTTON(data->buttonCount); + object->type = _GLFW_TYPE_BUTTON; + data->buttonCount++; + } + else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_POV) + { + object->offset = DIJOFS_POV(data->povCount); + object->type = _GLFW_TYPE_POV; + data->povCount++; + } + + data->objectCount++; + return DIENUM_CONTINUE; +} + +// DirectInput device enumeration callback +// +static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) +{ + int joy = 0; + DIDEVCAPS dc; + DIPROPDWORD dipd; + IDirectInputDevice8* device; + _GLFWobjenumWin32 data; + _GLFWjoystickWin32* js; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (memcmp(&_glfw.win32_js[joy].guid, &di->guidInstance, sizeof(GUID)) == 0) + return DIENUM_CONTINUE; + } + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (!_glfw.win32_js[joy].present) + break; + } + + if (joy > GLFW_JOYSTICK_LAST) + return DIENUM_STOP; + + if (supportsXInput(&di->guidProduct)) + return DIENUM_CONTINUE; + + if (FAILED(IDirectInput8_CreateDevice(_glfw.win32.dinput8.api, + &di->guidInstance, + &device, + NULL))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "DI: Failed to create device"); + return DIENUM_CONTINUE; + } + + if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "DI: Failed to set device data format"); + + IDirectInputDevice8_Release(device); + return DIENUM_CONTINUE; + } + + ZeroMemory(&dc, sizeof(dc)); + dc.dwSize = sizeof(dc); + + if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "DI: Failed to query device capabilities"); + + IDirectInputDevice8_Release(device); + return DIENUM_CONTINUE; + } + + ZeroMemory(&dipd, sizeof(dipd)); + dipd.diph.dwSize = sizeof(dipd); + dipd.diph.dwHeaderSize = sizeof(dipd.diph); + dipd.diph.dwHow = DIPH_DEVICE; + dipd.dwData = DIPROPAXISMODE_ABS; + + if (FAILED(IDirectInputDevice8_SetProperty(device, + DIPROP_AXISMODE, + &dipd.diph))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "DI: Failed to set device axis mode"); + + IDirectInputDevice8_Release(device); + return DIENUM_CONTINUE; + } + + memset(&data, 0, sizeof(data)); + data.device = device; + data.objects = calloc(dc.dwAxes + dc.dwButtons + dc.dwPOVs, + sizeof(_GLFWjoyobjectWin32)); + + if (FAILED(IDirectInputDevice8_EnumObjects(device, + deviceObjectCallback, + &data, + DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "DI: Failed to enumerate device objects"); + + IDirectInputDevice8_Release(device); + free(data.objects); + return DIENUM_CONTINUE; + } + + qsort(data.objects, data.objectCount, + sizeof(_GLFWjoyobjectWin32), + compareJoystickObjects); + + js = _glfw.win32_js + joy; + js->device = device; + js->guid = di->guidInstance; + js->axisCount = data.axisCount + data.sliderCount; + js->axes = calloc(js->axisCount, sizeof(float)); + js->buttonCount += data.buttonCount + data.povCount * 4; + js->buttons = calloc(js->buttonCount, 1); + js->objects = data.objects; + js->objectCount = data.objectCount; + js->name = _glfwCreateUTF8FromWideStringWin32(di->tszInstanceName); + js->present = GLFW_TRUE; + + _glfwInputJoystickChange(joy, GLFW_CONNECTED); + return DIENUM_CONTINUE; +} + +// Attempt to open the specified joystick device +// TODO: Pack state arrays for non-gamepad devices +// +static GLFWbool openXinputDevice(DWORD index) +{ + int joy; + XINPUT_CAPABILITIES xic; + _GLFWjoystickWin32* js; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (_glfw.win32_js[joy].present && + _glfw.win32_js[joy].device == NULL && + _glfw.win32_js[joy].index == index) + { + return GLFW_FALSE; + } + } + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (!_glfw.win32_js[joy].present) + break; + } + + if (joy > GLFW_JOYSTICK_LAST) + return GLFW_FALSE; + + if (_glfw_XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS) + return GLFW_FALSE; + + js = _glfw.win32_js + joy; + js->axisCount = 6; + js->axes = calloc(js->axisCount, sizeof(float)); + js->buttonCount = 14; + js->buttons = calloc(js->buttonCount, 1); + js->present = GLFW_TRUE; + js->name = strdup(getDeviceDescription(&xic)); + js->index = index; + + _glfwInputJoystickChange(joy, GLFW_CONNECTED); + + return GLFW_TRUE; +} + +// Polls for and processes events the specified joystick +// +static GLFWbool pollJoystickState(_GLFWjoystickWin32* js, int mode) +{ + if (!js->present) + return GLFW_FALSE; + + if (js->device) + { + int i, j, ai = 0, bi = 0; + HRESULT result; + DIJOYSTATE state; + + IDirectInputDevice8_Poll(js->device); + result = IDirectInputDevice8_GetDeviceState(js->device, + sizeof(state), + &state); + if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST) + { + IDirectInputDevice8_Acquire(js->device); + IDirectInputDevice8_Poll(js->device); + result = IDirectInputDevice8_GetDeviceState(js->device, + sizeof(state), + &state); + } + + if (FAILED(result)) + { + closeJoystick(js); + return GLFW_FALSE; + } + + if (mode == _GLFW_PRESENCE_ONLY) + return GLFW_TRUE; + + for (i = 0; i < js->objectCount; i++) + { + const void* data = (char*) &state + js->objects[i].offset; + + switch (js->objects[i].type) + { + case _GLFW_TYPE_AXIS: + case _GLFW_TYPE_SLIDER: + { + js->axes[ai++] = (*((LONG*) data) + 0.5f) / 32767.5f; + break; + } + + case _GLFW_TYPE_BUTTON: + { + if (*((BYTE*) data) & 0x80) + js->buttons[bi++] = GLFW_PRESS; + else + js->buttons[bi++] = GLFW_RELEASE; + + break; + } + + case _GLFW_TYPE_POV: + { + const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; + // Screams of horror are appropriate at this point + int value = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES); + if (value < 0 || value > 8) + value = 8; + + for (j = 0; j < 4; j++) + { + if (directions[value] & (1 << j)) + js->buttons[bi++] = GLFW_PRESS; + else + js->buttons[bi++] = GLFW_RELEASE; + } + + break; + } + } + } + + return GLFW_TRUE; + } + else + { + int i; + DWORD result; + XINPUT_STATE xis; + const WORD buttons[14] = + { + XINPUT_GAMEPAD_A, + XINPUT_GAMEPAD_B, + XINPUT_GAMEPAD_X, + XINPUT_GAMEPAD_Y, + XINPUT_GAMEPAD_LEFT_SHOULDER, + XINPUT_GAMEPAD_RIGHT_SHOULDER, + XINPUT_GAMEPAD_BACK, + XINPUT_GAMEPAD_START, + XINPUT_GAMEPAD_LEFT_THUMB, + XINPUT_GAMEPAD_RIGHT_THUMB, + XINPUT_GAMEPAD_DPAD_UP, + XINPUT_GAMEPAD_DPAD_RIGHT, + XINPUT_GAMEPAD_DPAD_DOWN, + XINPUT_GAMEPAD_DPAD_LEFT + }; + + result = _glfw_XInputGetState(js->index, &xis); + if (result != ERROR_SUCCESS) + { + if (result == ERROR_DEVICE_NOT_CONNECTED) + closeJoystick(js); + + return GLFW_FALSE; + } + + if (mode == _GLFW_PRESENCE_ONLY) + return GLFW_TRUE; + + if (sqrt((double) (xis.Gamepad.sThumbLX * xis.Gamepad.sThumbLX + + xis.Gamepad.sThumbLY * xis.Gamepad.sThumbLY)) > + (double) XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) + { + js->axes[0] = (xis.Gamepad.sThumbLX + 0.5f) / 32767.f; + js->axes[1] = (xis.Gamepad.sThumbLY + 0.5f) / 32767.f; + } + else + { + js->axes[0] = 0.f; + js->axes[1] = 0.f; + } + + if (sqrt((double) (xis.Gamepad.sThumbRX * xis.Gamepad.sThumbRX + + xis.Gamepad.sThumbRY * xis.Gamepad.sThumbRY)) > + (double) XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) + { + js->axes[2] = (xis.Gamepad.sThumbRX + 0.5f) / 32767.f; + js->axes[3] = (xis.Gamepad.sThumbRY + 0.5f) / 32767.f; + } + else + { + js->axes[2] = 0.f; + js->axes[3] = 0.f; + } + + if (xis.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + js->axes[4] = xis.Gamepad.bLeftTrigger / 127.5f - 1.f; + else + js->axes[4] = -1.f; + + if (xis.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + js->axes[5] = xis.Gamepad.bRightTrigger / 127.5f - 1.f; + else + js->axes[5] = -1.f; + + for (i = 0; i < 14; i++) + js->buttons[i] = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0; + + return GLFW_TRUE; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize joystick interface +// +void _glfwInitJoysticksWin32(void) +{ + if (_glfw.win32.dinput8.instance) + { + if (FAILED(_glfw_DirectInput8Create(GetModuleHandle(NULL), + DIRECTINPUT_VERSION, + &IID_IDirectInput8W, + (void**) &_glfw.win32.dinput8.api, + NULL))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "DI: Failed to create interface"); + } + } + + _glfwDetectJoystickConnectionWin32(); +} + +// Close all opened joystick handles +// +void _glfwTerminateJoysticksWin32(void) +{ + int joy; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + closeJoystick(_glfw.win32_js + joy); + + if (_glfw.win32.dinput8.api) + IDirectInput8_Release(_glfw.win32.dinput8.api); +} + +// Checks for new joysticks after DBT_DEVICEARRIVAL +// +void _glfwDetectJoystickConnectionWin32(void) +{ + if (_glfw.win32.xinput.instance) + { + DWORD i; + + for (i = 0; i < XUSER_MAX_COUNT; i++) + openXinputDevice(i); + } + + if (_glfw.win32.dinput8.api) + { + if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api, + DI8DEVCLASS_GAMECTRL, + deviceCallback, + NULL, + DIEDFL_ALLDEVICES))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Failed to enumerate DirectInput8 devices"); + return; + } + } +} + +// Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE +// +void _glfwDetectJoystickDisconnectionWin32(void) +{ + int joy; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + pollJoystickState(_glfw.win32_js + joy, _GLFW_PRESENCE_ONLY); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformJoystickPresent(int joy) +{ + _GLFWjoystickWin32* js = _glfw.win32_js + joy; + return pollJoystickState(js, _GLFW_PRESENCE_ONLY); +} + +const float* _glfwPlatformGetJoystickAxes(int joy, int* count) +{ + _GLFWjoystickWin32* js = _glfw.win32_js + joy; + if (!pollJoystickState(js, _GLFW_UPDATE_STATE)) + return NULL; + + *count = js->axisCount; + return js->axes; +} + +const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) +{ + _GLFWjoystickWin32* js = _glfw.win32_js + joy; + if (!pollJoystickState(js, _GLFW_UPDATE_STATE)) + return NULL; + + *count = js->buttonCount; + return js->buttons; +} + +const char* _glfwPlatformGetJoystickName(int joy) +{ + _GLFWjoystickWin32* js = _glfw.win32_js + joy; + if (!pollJoystickState(js, _GLFW_PRESENCE_ONLY)) + return NULL; + + return js->name; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_joystick.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_joystick.h new file mode 100644 index 00000000..6a75b415 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_joystick.h @@ -0,0 +1,64 @@ +//======================================================================== +// GLFW 3.2 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_win32_joystick_h_ +#define _glfw3_win32_joystick_h_ + +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \ + _GLFWjoystickWin32 win32_js[GLFW_JOYSTICK_LAST + 1] + +// Joystick element (axis, button or slider) +// +typedef struct _GLFWjoyobjectWin32 +{ + int offset; + int type; +} _GLFWjoyobjectWin32; + +// Win32-specific per-joystick data +// +typedef struct _GLFWjoystickWin32 +{ + GLFWbool present; + float* axes; + int axisCount; + unsigned char* buttons; + int buttonCount; + _GLFWjoyobjectWin32* objects; + int objectCount; + char* name; + IDirectInputDevice8W* device; + DWORD index; + GUID guid; +} _GLFWjoystickWin32; + + +void _glfwInitJoysticksWin32(void); +void _glfwTerminateJoysticksWin32(void); +void _glfwDetectJoystickConnectionWin32(void); +void _glfwDetectJoystickDisconnectionWin32(void); + +#endif // _glfw3_win32_joystick_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_monitor.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_monitor.c new file mode 100644 index 00000000..e55c9a71 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_monitor.c @@ -0,0 +1,401 @@ +//======================================================================== +// GLFW 3.2 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include + + +// Create monitor from an adapter and (optionally) a display +// +static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, + DISPLAY_DEVICEW* display) +{ + _GLFWmonitor* monitor; + char* name; + HDC dc; + + if (display) + name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString); + else + name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString); + if (!name) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert string to UTF-8"); + return NULL; + } + + dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL); + + monitor = _glfwAllocMonitor(name, + GetDeviceCaps(dc, HORZSIZE), + GetDeviceCaps(dc, VERTSIZE)); + + DeleteDC(dc); + free(name); + + if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED) + monitor->win32.modesPruned = GLFW_TRUE; + + wcscpy(monitor->win32.adapterName, adapter->DeviceName); + WideCharToMultiByte(CP_UTF8, 0, + adapter->DeviceName, -1, + monitor->win32.publicAdapterName, + sizeof(monitor->win32.publicAdapterName), + NULL, NULL); + + if (display) + { + wcscpy(monitor->win32.displayName, display->DeviceName); + WideCharToMultiByte(CP_UTF8, 0, + display->DeviceName, -1, + monitor->win32.publicDisplayName, + sizeof(monitor->win32.publicDisplayName), + NULL, NULL); + } + + return monitor; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Change the current video mode +// +GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired) +{ + GLFWvidmode current; + const GLFWvidmode* best; + DEVMODEW dm; + + best = _glfwChooseVideoMode(monitor, desired); + _glfwPlatformGetVideoMode(monitor, ¤t); + if (_glfwCompareVideoModes(¤t, best) == 0) + return GLFW_TRUE; + + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(DEVMODEW); + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | + DM_DISPLAYFREQUENCY; + dm.dmPelsWidth = best->width; + dm.dmPelsHeight = best->height; + dm.dmBitsPerPel = best->redBits + best->greenBits + best->blueBits; + dm.dmDisplayFrequency = best->refreshRate; + + if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24) + dm.dmBitsPerPel = 32; + + if (ChangeDisplaySettingsExW(monitor->win32.adapterName, + &dm, + NULL, + CDS_FULLSCREEN, + NULL) != DISP_CHANGE_SUCCESSFUL) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set video mode"); + return GLFW_FALSE; + } + + monitor->win32.modeChanged = GLFW_TRUE; + return GLFW_TRUE; +} + +// Restore the previously saved (original) video mode +// +void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor) +{ + if (monitor->win32.modeChanged) + { + ChangeDisplaySettingsExW(monitor->win32.adapterName, + NULL, NULL, CDS_FULLSCREEN, NULL); + monitor->win32.modeChanged = GLFW_FALSE; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwPlatformGetMonitors(int* count) +{ + int found = 0; + DWORD adapterIndex, displayIndex, primaryIndex = 0; + DISPLAY_DEVICEW adapter, display; + GLFWbool hasDisplays = GLFW_FALSE; + _GLFWmonitor** monitors = NULL; + + *count = 0; + + // HACK: Check if any active adapters have connected displays + // If not, this is a headless system or a VMware guest + + for (adapterIndex = 0; ; adapterIndex++) + { + ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW)); + adapter.cb = sizeof(DISPLAY_DEVICEW); + + if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0)) + break; + + if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) + continue; + + ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); + display.cb = sizeof(DISPLAY_DEVICEW); + + if (EnumDisplayDevicesW(adapter.DeviceName, 0, &display, 0)) + { + hasDisplays = GLFW_TRUE; + break; + } + } + + for (adapterIndex = 0; ; adapterIndex++) + { + ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW)); + adapter.cb = sizeof(DISPLAY_DEVICEW); + + if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0)) + break; + + if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) + continue; + + if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + primaryIndex = found; + + if (hasDisplays) + { + for (displayIndex = 0; ; displayIndex++) + { + ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); + display.cb = sizeof(DISPLAY_DEVICEW); + + if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0)) + break; + + found++; + monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); + monitors[found - 1] = createMonitor(&adapter, &display); + } + } + else + { + found++; + monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); + monitors[found - 1] = createMonitor(&adapter, NULL); + } + } + + _GLFW_SWAP_POINTERS(monitors[0], monitors[primaryIndex]); + + *count = found; + return monitors; +} + +GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) +{ + if (wcslen(first->win32.displayName)) + return wcscmp(first->win32.displayName, second->win32.displayName) == 0; + else + return wcscmp(first->win32.adapterName, second->win32.adapterName) == 0; +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + DEVMODEW settings; + ZeroMemory(&settings, sizeof(DEVMODEW)); + settings.dmSize = sizeof(DEVMODEW); + + EnumDisplaySettingsExW(monitor->win32.adapterName, + ENUM_CURRENT_SETTINGS, + &settings, + EDS_ROTATEDMODE); + + if (xpos) + *xpos = settings.dmPosition.x; + if (ypos) + *ypos = settings.dmPosition.y; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) +{ + int modeIndex = 0, size = 0; + GLFWvidmode* result = NULL; + + *count = 0; + + for (;;) + { + int i; + GLFWvidmode mode; + DEVMODEW dm; + + ZeroMemory(&dm, sizeof(DEVMODEW)); + dm.dmSize = sizeof(DEVMODEW); + + if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm)) + break; + + modeIndex++; + + // Skip modes with less than 15 BPP + if (dm.dmBitsPerPel < 15) + continue; + + mode.width = dm.dmPelsWidth; + mode.height = dm.dmPelsHeight; + mode.refreshRate = dm.dmDisplayFrequency; + _glfwSplitBPP(dm.dmBitsPerPel, + &mode.redBits, + &mode.greenBits, + &mode.blueBits); + + for (i = 0; i < *count; i++) + { + if (_glfwCompareVideoModes(result + i, &mode) == 0) + break; + } + + // Skip duplicate modes + if (i < *count) + continue; + + if (monitor->win32.modesPruned) + { + // Skip modes not supported by the connected displays + if (ChangeDisplaySettingsExW(monitor->win32.adapterName, + &dm, + NULL, + CDS_TEST, + NULL) != DISP_CHANGE_SUCCESSFUL) + { + continue; + } + } + + if (*count == size) + { + size += 128; + result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode)); + } + + (*count)++; + result[*count - 1] = mode; + } + + if (!*count) + { + // HACK: Report the current mode if no valid modes were found + result = calloc(1, sizeof(GLFWvidmode)); + _glfwPlatformGetVideoMode(monitor, result); + *count = 1; + } + + return result; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + DEVMODEW dm; + + ZeroMemory(&dm, sizeof(DEVMODEW)); + dm.dmSize = sizeof(DEVMODEW); + + EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm); + + mode->width = dm.dmPelsWidth; + mode->height = dm.dmPelsHeight; + mode->refreshRate = dm.dmDisplayFrequency; + _glfwSplitBPP(dm.dmBitsPerPel, + &mode->redBits, + &mode->greenBits, + &mode->blueBits); +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + HDC dc; + WORD values[768]; + + dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL); + GetDeviceGammaRamp(dc, values); + DeleteDC(dc); + + _glfwAllocGammaArrays(ramp, 256); + + memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short)); + memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short)); + memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short)); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + HDC dc; + WORD values[768]; + + if (ramp->size != 256) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Gamma ramp size must be 256"); + return; + } + + memcpy(values + 0, ramp->red, 256 * sizeof(unsigned short)); + memcpy(values + 256, ramp->green, 256 * sizeof(unsigned short)); + memcpy(values + 512, ramp->blue, 256 * sizeof(unsigned short)); + + dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL); + SetDeviceGammaRamp(dc, values); + DeleteDC(dc); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return monitor->win32.publicAdapterName; +} + +GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return monitor->win32.publicDisplayName; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_platform.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_platform.h new file mode 100644 index 00000000..c0dcff15 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_platform.h @@ -0,0 +1,350 @@ +//======================================================================== +// GLFW 3.2 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_win32_platform_h_ +#define _glfw3_win32_platform_h_ + +// We don't need all the fancy stuff +#ifndef NOMINMAX + #define NOMINMAX +#endif + +#ifndef VC_EXTRALEAN + #define VC_EXTRALEAN +#endif + +#ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN +#endif + +// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for +// example to allow applications to correctly declare a GL_ARB_debug_output +// callback) but windows.h assumes no one will define APIENTRY before it does +#undef APIENTRY + +// GLFW on Windows is Unicode only and does not work in MBCS mode +#ifndef UNICODE + #define UNICODE +#endif + +// GLFW requires Windows XP or later +#if WINVER < 0x0501 + #undef WINVER + #define WINVER 0x0501 +#endif +#if _WIN32_WINNT < 0x0501 + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0501 +#endif + +// GLFW uses DirectInput8 interfaces +#define DIRECTINPUT_VERSION 0x0800 + +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) + #include + #define strdup _strdup +#endif + +// HACK: Define macros that some windows.h variants don't +#ifndef WM_MOUSEHWHEEL + #define WM_MOUSEHWHEEL 0x020E +#endif +#ifndef WM_DWMCOMPOSITIONCHANGED + #define WM_DWMCOMPOSITIONCHANGED 0x031E +#endif +#ifndef WM_COPYGLOBALDATA + #define WM_COPYGLOBALDATA 0x0049 +#endif +#ifndef WM_UNICHAR + #define WM_UNICHAR 0x0109 +#endif +#ifndef UNICODE_NOCHAR + #define UNICODE_NOCHAR 0xFFFF +#endif +#ifndef WM_DPICHANGED + #define WM_DPICHANGED 0x02E0 +#endif +#ifndef GET_XBUTTON_WPARAM + #define GET_XBUTTON_WPARAM(w) (HIWORD(w)) +#endif +#ifndef EDS_ROTATEDMODE + #define EDS_ROTATEDMODE 0x00000004 +#endif +#ifndef DISPLAY_DEVICE_ACTIVE + #define DISPLAY_DEVICE_ACTIVE 0x00000001 +#endif + +#if WINVER < 0x0601 +typedef struct tagCHANGEFILTERSTRUCT +{ + DWORD cbSize; + DWORD ExtStatus; + +} CHANGEFILTERSTRUCT, *PCHANGEFILTERSTRUCT; +#ifndef MSGFLT_ALLOW + #define MSGFLT_ALLOW 1 +#endif +#endif /*Windows 7*/ + +#ifndef DPI_ENUMS_DECLARED +typedef enum PROCESS_DPI_AWARENESS +{ + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 +} PROCESS_DPI_AWARENESS; +#endif /*DPI_ENUMS_DECLARED*/ + +// HACK: Define macros that some xinput.h variants don't +#ifndef XINPUT_CAPS_WIRELESS + #define XINPUT_CAPS_WIRELESS 0x0002 +#endif +#ifndef XINPUT_DEVSUBTYPE_WHEEL + #define XINPUT_DEVSUBTYPE_WHEEL 0x02 +#endif +#ifndef XINPUT_DEVSUBTYPE_ARCADE_STICK + #define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03 +#endif +#ifndef XINPUT_DEVSUBTYPE_FLIGHT_STICK + #define XINPUT_DEVSUBTYPE_FLIGHT_STICK 0x04 +#endif +#ifndef XINPUT_DEVSUBTYPE_DANCE_PAD + #define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05 +#endif +#ifndef XINPUT_DEVSUBTYPE_GUITAR + #define XINPUT_DEVSUBTYPE_GUITAR 0x06 +#endif +#ifndef XINPUT_DEVSUBTYPE_DRUM_KIT + #define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08 +#endif +#ifndef XINPUT_DEVSUBTYPE_ARCADE_PAD + #define XINPUT_DEVSUBTYPE_ARCADE_PAD 0x13 +#endif +#ifndef XUSER_MAX_COUNT + #define XUSER_MAX_COUNT 4 +#endif + +// HACK: Define macros that some dinput.h variants don't +#ifndef DIDFT_OPTIONAL + #define DIDFT_OPTIONAL 0x80000000 +#endif + +// winmm.dll function pointer typedefs +typedef DWORD (WINAPI * TIMEGETTIME_T)(void); +#define _glfw_timeGetTime _glfw.win32.winmm.timeGetTime + +// xinput.dll function pointer typedefs +typedef DWORD (WINAPI * XINPUTGETCAPABILITIES_T)(DWORD,DWORD,XINPUT_CAPABILITIES*); +typedef DWORD (WINAPI * XINPUTGETSTATE_T)(DWORD,XINPUT_STATE*); +#define _glfw_XInputGetCapabilities _glfw.win32.xinput.XInputGetCapabilities +#define _glfw_XInputGetState _glfw.win32.xinput.XInputGetState + +// dinput8.dll function pointer typedefs +typedef HRESULT (WINAPI * DIRECTINPUT8CREATE_T)(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN); +#define _glfw_DirectInput8Create _glfw.win32.dinput8.DirectInput8Create + +// user32.dll function pointer typedefs +typedef BOOL (WINAPI * SETPROCESSDPIAWARE_T)(void); +typedef BOOL (WINAPI * CHANGEWINDOWMESSAGEFILTEREX_T)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT); +#define _glfw_SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware +#define _glfw_ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx + +// dwmapi.dll function pointer typedefs +typedef HRESULT (WINAPI * DWMISCOMPOSITIONENABLED_T)(BOOL*); +typedef HRESULT (WINAPI * DWMFLUSH_T)(VOID); +#define _glfw_DwmIsCompositionEnabled _glfw.win32.dwmapi.DwmIsCompositionEnabled +#define _glfw_DwmFlush _glfw.win32.dwmapi.DwmFlush + +// shcore.dll function pointer typedefs +typedef HRESULT (WINAPI * SETPROCESSDPIAWARENESS_T)(PROCESS_DPI_AWARENESS); +#define _glfw_SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness + +typedef VkFlags VkWin32SurfaceCreateFlagsKHR; + +typedef struct VkWin32SurfaceCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkWin32SurfaceCreateFlagsKHR flags; + HINSTANCE hinstance; + HWND hwnd; +} VkWin32SurfaceCreateInfoKHR; + +typedef VkResult (APIENTRY *PFN_vkCreateWin32SurfaceKHR)(VkInstance,const VkWin32SurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); +typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice,uint32_t); + +#include "win32_joystick.h" +#include "wgl_context.h" +#include "egl_context.h" + +#define _GLFW_WNDCLASSNAME L"GLFW30" + +#define _glfw_dlopen(name) LoadLibraryA(name) +#define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle) +#define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name) + +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->win32.handle) +#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32 +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32 +#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeWin32 win32_time +#define _GLFW_PLATFORM_LIBRARY_TLS_STATE _GLFWtlsWin32 win32_tls +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32 +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32 + + +// Win32-specific per-window data +// +typedef struct _GLFWwindowWin32 +{ + HWND handle; + HICON bigIcon; + HICON smallIcon; + + GLFWbool cursorTracked; + GLFWbool iconified; + + // The last received cursor position, regardless of source + int lastCursorPosX, lastCursorPosY; + +} _GLFWwindowWin32; + +// Win32-specific global data +// +typedef struct _GLFWlibraryWin32 +{ + HWND helperWindowHandle; + DWORD foregroundLockTimeout; + char* clipboardString; + char keyName[64]; + short int publicKeys[512]; + short int nativeKeys[GLFW_KEY_LAST + 1]; + // Where to place the cursor when re-enabled + double restoreCursorPosX, restoreCursorPosY; + // The window whose disabled cursor mode is active + _GLFWwindow* disabledCursorWindow; + + struct { + HINSTANCE instance; + TIMEGETTIME_T timeGetTime; + } winmm; + + struct { + HINSTANCE instance; + DIRECTINPUT8CREATE_T DirectInput8Create; + IDirectInput8W* api; + } dinput8; + + struct { + HINSTANCE instance; + XINPUTGETCAPABILITIES_T XInputGetCapabilities; + XINPUTGETSTATE_T XInputGetState; + } xinput; + + struct { + HINSTANCE instance; + SETPROCESSDPIAWARE_T SetProcessDPIAware; + CHANGEWINDOWMESSAGEFILTEREX_T ChangeWindowMessageFilterEx; + } user32; + + struct { + HINSTANCE instance; + DWMISCOMPOSITIONENABLED_T DwmIsCompositionEnabled; + DWMFLUSH_T DwmFlush; + } dwmapi; + + struct { + HINSTANCE instance; + SETPROCESSDPIAWARENESS_T SetProcessDpiAwareness; + } shcore; + +} _GLFWlibraryWin32; + +// Win32-specific per-monitor data +// +typedef struct _GLFWmonitorWin32 +{ + // This size matches the static size of DISPLAY_DEVICE.DeviceName + WCHAR adapterName[32]; + WCHAR displayName[32]; + char publicAdapterName[64]; + char publicDisplayName[64]; + GLFWbool modesPruned; + GLFWbool modeChanged; + +} _GLFWmonitorWin32; + +// Win32-specific per-cursor data +// +typedef struct _GLFWcursorWin32 +{ + HCURSOR handle; + +} _GLFWcursorWin32; + +// Win32-specific global timer data +// +typedef struct _GLFWtimeWin32 +{ + GLFWbool hasPC; + uint64_t frequency; + +} _GLFWtimeWin32; + +// Win32-specific global TLS data +// +typedef struct _GLFWtlsWin32 +{ + GLFWbool allocated; + DWORD context; + +} _GLFWtlsWin32; + + +GLFWbool _glfwRegisterWindowClassWin32(void); +void _glfwUnregisterWindowClassWin32(void); + +GLFWbool _glfwInitThreadLocalStorageWin32(void); +void _glfwTerminateThreadLocalStorageWin32(void); + +WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source); +char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source); + +void _glfwInitTimerWin32(void); + +GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired); +void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor); + +#endif // _glfw3_win32_platform_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_time.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_time.c new file mode 100644 index 00000000..d972f567 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_time.c @@ -0,0 +1,74 @@ +//======================================================================== +// GLFW 3.2 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialise timer +// +void _glfwInitTimerWin32(void) +{ + uint64_t frequency; + + if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency)) + { + _glfw.win32_time.hasPC = GLFW_TRUE; + _glfw.win32_time.frequency = frequency; + } + else + { + _glfw.win32_time.hasPC = GLFW_FALSE; + _glfw.win32_time.frequency = 1000; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +uint64_t _glfwPlatformGetTimerValue(void) +{ + if (_glfw.win32_time.hasPC) + { + uint64_t value; + QueryPerformanceCounter((LARGE_INTEGER*) &value); + return value; + } + else + return (uint64_t) _glfw_timeGetTime(); +} + +uint64_t _glfwPlatformGetTimerFrequency(void) +{ + return _glfw.win32_time.frequency; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_tls.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_tls.c new file mode 100644 index 00000000..ab79fcc3 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_tls.c @@ -0,0 +1,69 @@ +//======================================================================== +// GLFW 3.2 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwInitThreadLocalStorageWin32(void) +{ + _glfw.win32_tls.context = TlsAlloc(); + if (_glfw.win32_tls.context == TLS_OUT_OF_INDEXES) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to allocate TLS index"); + return GLFW_FALSE; + } + + _glfw.win32_tls.allocated = GLFW_TRUE; + return GLFW_TRUE; +} + +void _glfwTerminateThreadLocalStorageWin32(void) +{ + if (_glfw.win32_tls.allocated) + TlsFree(_glfw.win32_tls.context); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformSetCurrentContext(_GLFWwindow* context) +{ + TlsSetValue(_glfw.win32_tls.context, context); +} + +_GLFWwindow* _glfwPlatformGetCurrentContext(void) +{ + return TlsGetValue(_glfw.win32_tls.context); +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_window.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_window.c new file mode 100644 index 00000000..8e30eb64 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/win32_window.c @@ -0,0 +1,1724 @@ +//======================================================================== +// GLFW 3.2 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#define _GLFW_KEY_INVALID -2 + +// Returns the window style for the specified window +// +static DWORD getWindowStyle(const _GLFWwindow* window) +{ + DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + + if (window->monitor) + style |= WS_POPUP; + else + { + if (window->decorated) + { + style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + + if (window->resizable) + style |= WS_MAXIMIZEBOX | WS_THICKFRAME; + } + else + style |= WS_POPUP; + } + + return style; +} + +// Returns the extended window style for the specified window +// +static DWORD getWindowExStyle(const _GLFWwindow* window) +{ + DWORD style = WS_EX_APPWINDOW; + + if (window->monitor || window->floating) + style |= WS_EX_TOPMOST; + + return style; +} + +// Returns the image whose area most closely matches the desired one +// +static const GLFWimage* chooseImage(int count, const GLFWimage* images, + int width, int height) +{ + int i, leastDiff = INT_MAX; + const GLFWimage* closest = NULL; + + for (i = 0; i < count; i++) + { + const int currDiff = abs(images[i].width * images[i].height - + width * height); + if (currDiff < leastDiff) + { + closest = images + i; + leastDiff = currDiff; + } + } + + return closest; +} + +// Creates an RGBA icon or cursor +// +static HICON createIcon(const GLFWimage* image, + int xhot, int yhot, GLFWbool icon) +{ + int i; + HDC dc; + HICON handle; + HBITMAP color, mask; + BITMAPV5HEADER bi; + ICONINFO ii; + unsigned char* target = NULL; + unsigned char* source = image->pixels; + + ZeroMemory(&bi, sizeof(bi)); + bi.bV5Size = sizeof(BITMAPV5HEADER); + bi.bV5Width = image->width; + bi.bV5Height = -image->height; + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + bi.bV5RedMask = 0x00ff0000; + bi.bV5GreenMask = 0x0000ff00; + bi.bV5BlueMask = 0x000000ff; + bi.bV5AlphaMask = 0xff000000; + + dc = GetDC(NULL); + color = CreateDIBSection(dc, + (BITMAPINFO*) &bi, + DIB_RGB_COLORS, + (void**) &target, + NULL, + (DWORD) 0); + ReleaseDC(NULL, dc); + + if (!color) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to create RGBA bitmap"); + return NULL; + } + + mask = CreateBitmap(image->width, image->height, 1, 1, NULL); + if (!mask) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to create mask bitmap"); + DeleteObject(color); + return NULL; + } + + for (i = 0; i < image->width * image->height; i++) + { + target[0] = source[2]; + target[1] = source[1]; + target[2] = source[0]; + target[3] = source[3]; + target += 4; + source += 4; + } + + ZeroMemory(&ii, sizeof(ii)); + ii.fIcon = icon; + ii.xHotspot = xhot; + ii.yHotspot = yhot; + ii.hbmMask = mask; + ii.hbmColor = color; + + handle = CreateIconIndirect(&ii); + + DeleteObject(color); + DeleteObject(mask); + + if (!handle) + { + if (icon) + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create icon"); + else + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create cursor"); + } + + return handle; +} + +// Translate client window size to full window size according to styles +// +static void getFullWindowSize(DWORD style, DWORD exStyle, + int clientWidth, int clientHeight, + int* fullWidth, int* fullHeight) +{ + RECT rect = { 0, 0, clientWidth, clientHeight }; + AdjustWindowRectEx(&rect, style, FALSE, exStyle); + *fullWidth = rect.right - rect.left; + *fullHeight = rect.bottom - rect.top; +} + +// Enforce the client rect aspect ratio based on which edge is being dragged +// +static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) +{ + int xoff, yoff; + const float ratio = (float) window->numer / (float) window->denom; + + getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), + 0, 0, &xoff, &yoff); + + if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT || + edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT) + { + area->bottom = area->top + yoff + + (int) ((area->right - area->left - xoff) / ratio); + } + else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT) + { + area->top = area->bottom - yoff - + (int) ((area->right - area->left - xoff) / ratio); + } + else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM) + { + area->right = area->left + xoff + + (int) ((area->bottom - area->top - yoff) * ratio); + } +} + +// Centers the cursor over the window client area +// +static void centerCursor(_GLFWwindow* window) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); +} + +// Returns whether the cursor is in the client area of the specified window +// +static GLFWbool cursorInClientArea(_GLFWwindow* window) +{ + RECT area; + POINT pos; + + if (!GetCursorPos(&pos)) + return GLFW_FALSE; + + if (WindowFromPoint(pos) != window->win32.handle) + return GLFW_FALSE; + + GetClientRect(window->win32.handle, &area); + ClientToScreen(window->win32.handle, (POINT*) &area.left); + ClientToScreen(window->win32.handle, (POINT*) &area.right); + + return PtInRect(&area, pos); +} + +// Updates the cursor image according to its cursor mode +// +static void updateCursorImage(_GLFWwindow* window) +{ + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + if (window->cursor) + SetCursor(window->cursor->win32.handle); + else + SetCursor(LoadCursorW(NULL, IDC_ARROW)); + } + else + SetCursor(NULL); +} + +// Updates the cursor clip rect +// +static void updateClipRect(_GLFWwindow* window) +{ + if (window) + { + RECT clipRect; + GetClientRect(window->win32.handle, &clipRect); + ClientToScreen(window->win32.handle, (POINT*) &clipRect.left); + ClientToScreen(window->win32.handle, (POINT*) &clipRect.right); + ClipCursor(&clipRect); + } + else + ClipCursor(NULL); +} + +// Translates a GLFW standard cursor to a resource ID +// +static LPWSTR translateCursorShape(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return IDC_ARROW; + case GLFW_IBEAM_CURSOR: + return IDC_IBEAM; + case GLFW_CROSSHAIR_CURSOR: + return IDC_CROSS; + case GLFW_HAND_CURSOR: + return IDC_HAND; + case GLFW_HRESIZE_CURSOR: + return IDC_SIZEWE; + case GLFW_VRESIZE_CURSOR: + return IDC_SIZENS; + } + + return NULL; +} + +// Retrieves and translates modifier keys +// +static int getKeyMods(void) +{ + int mods = 0; + + if (GetKeyState(VK_SHIFT) & (1 << 31)) + mods |= GLFW_MOD_SHIFT; + if (GetKeyState(VK_CONTROL) & (1 << 31)) + mods |= GLFW_MOD_CONTROL; + if (GetKeyState(VK_MENU) & (1 << 31)) + mods |= GLFW_MOD_ALT; + if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1 << 31)) + mods |= GLFW_MOD_SUPER; + + return mods; +} + +// Retrieves and translates modifier keys +// +static int getAsyncKeyMods(void) +{ + int mods = 0; + + if (GetAsyncKeyState(VK_SHIFT) & (1 << 31)) + mods |= GLFW_MOD_SHIFT; + if (GetAsyncKeyState(VK_CONTROL) & (1 << 31)) + mods |= GLFW_MOD_CONTROL; + if (GetAsyncKeyState(VK_MENU) & (1 << 31)) + mods |= GLFW_MOD_ALT; + if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & (1 << 31)) + mods |= GLFW_MOD_SUPER; + + return mods; +} + +// Translates a Windows key to the corresponding GLFW key +// +static int translateKey(WPARAM wParam, LPARAM lParam) +{ + if (wParam == VK_CONTROL) + { + // The CTRL keys require special handling + + MSG next; + DWORD time; + + // Is this an extended key (i.e. right key)? + if (lParam & 0x01000000) + return GLFW_KEY_RIGHT_CONTROL; + + // Here is a trick: "Alt Gr" sends LCTRL, then RALT. We only + // want the RALT message, so we try to see if the next message + // is a RALT message. In that case, this is a false LCTRL! + time = GetMessageTime(); + + if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE)) + { + if (next.message == WM_KEYDOWN || + next.message == WM_SYSKEYDOWN || + next.message == WM_KEYUP || + next.message == WM_SYSKEYUP) + { + if (next.wParam == VK_MENU && + (next.lParam & 0x01000000) && + next.time == time) + { + // Next message is a RALT down message, which + // means that this is not a proper LCTRL message + return _GLFW_KEY_INVALID; + } + } + } + + return GLFW_KEY_LEFT_CONTROL; + } + + if (wParam == VK_PROCESSKEY) + { + // IME notifies that keys have been filtered by setting the virtual + // key-code to VK_PROCESSKEY + return _GLFW_KEY_INVALID; + } + + return _glfw.win32.publicKeys[HIWORD(lParam) & 0x1FF]; +} + +// Make the specified window and its video mode active on its monitor +// +static GLFWbool acquireMonitor(_GLFWwindow* window) +{ + GLFWvidmode mode; + GLFWbool status; + int xpos, ypos; + + status = _glfwSetVideoModeWin32(window->monitor, &window->videoMode); + + _glfwPlatformGetVideoMode(window->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + + SetWindowPos(window->win32.handle, HWND_TOPMOST, + xpos, ypos, mode.width, mode.height, + SWP_NOACTIVATE | SWP_NOCOPYBITS); + + _glfwInputMonitorWindowChange(window->monitor, window); + return status; +} + +// Remove the window and restore the original video mode +// +static void releaseMonitor(_GLFWwindow* window) +{ + if (window->monitor->window != window) + return; + + _glfwInputMonitorWindowChange(window->monitor, NULL); + _glfwRestoreVideoModeWin32(window->monitor); +} + +// Window callback function (handles window messages) +// +static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + _GLFWwindow* window = GetPropW(hWnd, L"GLFW"); + if (!window) + { + // This is the message handling for the hidden helper window + + switch (uMsg) + { + case WM_DEVICECHANGE: + { + if (wParam == DBT_DEVNODES_CHANGED) + { + _glfwInputMonitorChange(); + return TRUE; + } + else if (wParam == DBT_DEVICEARRIVAL) + { + DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; + if (dbh) + { + if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + _glfwDetectJoystickConnectionWin32(); + } + } + else if (wParam == DBT_DEVICEREMOVECOMPLETE) + { + DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; + if (dbh) + { + if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + _glfwDetectJoystickDisconnectionWin32(); + } + } + + break; + } + } + + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + + switch (uMsg) + { + case WM_SETFOCUS: + { + _glfwInputWindowFocus(window, GLFW_TRUE); + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + + return 0; + } + + case WM_KILLFOCUS: + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); + + if (window->monitor && window->autoIconify) + _glfwPlatformIconifyWindow(window); + + _glfwInputWindowFocus(window, GLFW_FALSE); + return 0; + } + + case WM_SYSCOMMAND: + { + switch (wParam & 0xfff0) + { + case SC_SCREENSAVE: + case SC_MONITORPOWER: + { + if (window->monitor) + { + // We are running in full screen mode, so disallow + // screen saver and screen blanking + return 0; + } + else + break; + } + + // User trying to access application menu using ALT? + case SC_KEYMENU: + return 0; + } + break; + } + + case WM_CLOSE: + { + _glfwInputWindowCloseRequest(window); + return 0; + } + + case WM_CHAR: + case WM_SYSCHAR: + case WM_UNICHAR: + { + const GLFWbool plain = (uMsg != WM_SYSCHAR); + + if (uMsg == WM_UNICHAR && wParam == UNICODE_NOCHAR) + { + // WM_UNICHAR is not sent by Windows, but is sent by some + // third-party input method engine + // Returning TRUE here announces support for this message + return TRUE; + } + + _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), plain); + return 0; + } + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + { + const int key = translateKey(wParam, lParam); + const int scancode = (lParam >> 16) & 0x1ff; + const int action = ((lParam >> 31) & 1) ? GLFW_RELEASE : GLFW_PRESS; + const int mods = getKeyMods(); + + if (key == _GLFW_KEY_INVALID) + break; + + if (action == GLFW_RELEASE && wParam == VK_SHIFT) + { + // Release both Shift keys on Shift up event, as only one event + // is sent even if both keys are released + _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, action, mods); + _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, action, mods); + } + else if (wParam == VK_SNAPSHOT) + { + // Key down is not reported for the Print Screen key + _glfwInputKey(window, key, scancode, GLFW_PRESS, mods); + _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods); + } + else + _glfwInputKey(window, key, scancode, action, mods); + + break; + } + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_XBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: + { + int button, action; + + if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP) + button = GLFW_MOUSE_BUTTON_LEFT; + else if (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP) + button = GLFW_MOUSE_BUTTON_RIGHT; + else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP) + button = GLFW_MOUSE_BUTTON_MIDDLE; + else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) + button = GLFW_MOUSE_BUTTON_4; + else + button = GLFW_MOUSE_BUTTON_5; + + if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || + uMsg == WM_MBUTTONDOWN || uMsg == WM_XBUTTONDOWN) + { + action = GLFW_PRESS; + SetCapture(hWnd); + } + else + { + action = GLFW_RELEASE; + ReleaseCapture(); + } + + _glfwInputMouseClick(window, button, action, getKeyMods()); + + if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP) + return TRUE; + + return 0; + } + + case WM_MOUSEMOVE: + { + const int x = GET_X_LPARAM(lParam); + const int y = GET_Y_LPARAM(lParam); + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + const int dx = x - window->win32.lastCursorPosX; + const int dy = y - window->win32.lastCursorPosY; + + if (_glfw.win32.disabledCursorWindow != window) + break; + + _glfwInputCursorPos(window, + window->virtualCursorPosX + dx, + window->virtualCursorPosY + dy); + } + else + _glfwInputCursorPos(window, x, y); + + window->win32.lastCursorPosX = x; + window->win32.lastCursorPosY = y; + + if (!window->win32.cursorTracked) + { + TRACKMOUSEEVENT tme; + ZeroMemory(&tme, sizeof(tme)); + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = window->win32.handle; + TrackMouseEvent(&tme); + + window->win32.cursorTracked = GLFW_TRUE; + _glfwInputCursorEnter(window, GLFW_TRUE); + } + + return 0; + } + + case WM_MOUSELEAVE: + { + window->win32.cursorTracked = GLFW_FALSE; + _glfwInputCursorEnter(window, GLFW_FALSE); + return 0; + } + + case WM_MOUSEWHEEL: + { + _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA); + return 0; + } + + case WM_MOUSEHWHEEL: + { + // This message is only sent on Windows Vista and later + // NOTE: The X-axis is inverted for consistency with OS X and X11. + _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0); + return 0; + } + + case WM_ENTERSIZEMOVE: + case WM_ENTERMENULOOP: + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); + + break; + } + + case WM_EXITSIZEMOVE: + case WM_EXITMENULOOP: + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + + break; + } + + case WM_SIZE: + { + const GLFWbool iconified = + !window->win32.iconified && wParam == SIZE_MINIMIZED; + const GLFWbool restored = + window->win32.iconified && + (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED); + + if (_glfw.win32.disabledCursorWindow == window) + updateClipRect(window); + + if (iconified) + _glfwInputWindowIconify(window, GLFW_TRUE); + else if (restored) + _glfwInputWindowIconify(window, GLFW_FALSE); + + _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); + _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); + + if (iconified) + { + window->win32.iconified = GLFW_TRUE; + if (window->monitor) + releaseMonitor(window); + } + else if (restored) + { + window->win32.iconified = GLFW_FALSE; + if (window->monitor) + acquireMonitor(window); + } + + return 0; + } + + case WM_MOVE: + { + if (_glfw.win32.disabledCursorWindow == window) + updateClipRect(window); + + // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as + // those macros do not handle negative window positions correctly + _glfwInputWindowPos(window, + GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam)); + return 0; + } + + case WM_SIZING: + { + if (window->numer == GLFW_DONT_CARE || + window->denom == GLFW_DONT_CARE) + { + break; + } + + applyAspectRatio(window, (int) wParam, (RECT*) lParam); + return TRUE; + } + + case WM_GETMINMAXINFO: + { + int xoff, yoff; + MINMAXINFO* mmi = (MINMAXINFO*) lParam; + + if (window->monitor) + break; + + getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), + 0, 0, &xoff, &yoff); + + if (window->minwidth != GLFW_DONT_CARE && + window->minheight != GLFW_DONT_CARE) + { + mmi->ptMinTrackSize.x = window->minwidth + xoff; + mmi->ptMinTrackSize.y = window->minheight + yoff; + } + + if (window->maxwidth != GLFW_DONT_CARE && + window->maxheight != GLFW_DONT_CARE) + { + mmi->ptMaxTrackSize.x = window->maxwidth + xoff; + mmi->ptMaxTrackSize.y = window->maxheight + yoff; + } + + return 0; + } + + case WM_PAINT: + { + _glfwInputWindowDamage(window); + break; + } + + case WM_ERASEBKGND: + { + return TRUE; + } + + case WM_SETCURSOR: + { + if (LOWORD(lParam) == HTCLIENT) + { + updateCursorImage(window); + return TRUE; + } + + break; + } + + case WM_DPICHANGED: + { + RECT* rect = (RECT*) lParam; + SetWindowPos(window->win32.handle, + HWND_TOP, + rect->left, + rect->top, + rect->right - rect->left, + rect->bottom - rect->top, + SWP_NOACTIVATE | SWP_NOZORDER); + break; + } + + case WM_DROPFILES: + { + HDROP drop = (HDROP) wParam; + POINT pt; + int i; + + const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0); + char** paths = calloc(count, sizeof(char*)); + + // Move the mouse to the position of the drop + DragQueryPoint(drop, &pt); + _glfwInputCursorPos(window, pt.x, pt.y); + + for (i = 0; i < count; i++) + { + const UINT length = DragQueryFileW(drop, i, NULL, 0); + WCHAR* buffer = calloc(length + 1, sizeof(WCHAR)); + + DragQueryFileW(drop, i, buffer, length + 1); + paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer); + + free(buffer); + } + + _glfwInputDrop(window, count, (const char**) paths); + + for (i = 0; i < count; i++) + free(paths[i]); + free(paths); + + DragFinish(drop); + return 0; + } + } + + return DefWindowProcW(hWnd, uMsg, wParam, lParam); +} + +// Creates the GLFW window +// +static int createNativeWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig) +{ + int xpos, ypos, fullWidth, fullHeight; + WCHAR* wideTitle; + DWORD style = getWindowStyle(window); + DWORD exStyle = getWindowExStyle(window); + + if (window->monitor) + { + GLFWvidmode mode; + + // NOTE: This window placement is temporary and approximate, as the + // correct position and size cannot be known until the monitor + // video mode has been set + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + _glfwPlatformGetVideoMode(window->monitor, &mode); + fullWidth = mode.width; + fullHeight = mode.height; + } + else + { + xpos = CW_USEDEFAULT; + ypos = CW_USEDEFAULT; + + if (wndconfig->maximized) + style |= WS_MAXIMIZE; + + getFullWindowSize(style, exStyle, + wndconfig->width, wndconfig->height, + &fullWidth, &fullHeight); + } + + wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title); + if (!wideTitle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert window title to UTF-16"); + return GLFW_FALSE; + } + + window->win32.handle = CreateWindowExW(exStyle, + _GLFW_WNDCLASSNAME, + wideTitle, + style, + xpos, ypos, + fullWidth, fullHeight, + NULL, // No parent window + NULL, // No window menu + GetModuleHandleW(NULL), + NULL); + + free(wideTitle); + + if (!window->win32.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create window"); + return GLFW_FALSE; + } + + SetPropW(window->win32.handle, L"GLFW", window); + + if (_glfw_ChangeWindowMessageFilterEx) + { + _glfw_ChangeWindowMessageFilterEx(window->win32.handle, + WM_DROPFILES, MSGFLT_ALLOW, NULL); + _glfw_ChangeWindowMessageFilterEx(window->win32.handle, + WM_COPYDATA, MSGFLT_ALLOW, NULL); + _glfw_ChangeWindowMessageFilterEx(window->win32.handle, + WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); + } + + DragAcceptFiles(window->win32.handle, TRUE); + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Registers the GLFW window class +// +GLFWbool _glfwRegisterWindowClassWin32(void) +{ + WNDCLASSEXW wc; + + ZeroMemory(&wc, sizeof(wc)); + wc.cbSize = sizeof(wc); + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wc.lpfnWndProc = (WNDPROC) windowProc; + wc.hInstance = GetModuleHandleW(NULL); + wc.hCursor = LoadCursorW(NULL, IDC_ARROW); + wc.lpszClassName = _GLFW_WNDCLASSNAME; + + // Load user-provided icon if available + wc.hIcon = LoadImageW(GetModuleHandleW(NULL), + L"GLFW_ICON", IMAGE_ICON, + 0, 0, LR_DEFAULTSIZE | LR_SHARED); + if (!wc.hIcon) + { + // No user-provided icon found, load default icon + wc.hIcon = LoadImageW(NULL, + IDI_APPLICATION, IMAGE_ICON, + 0, 0, LR_DEFAULTSIZE | LR_SHARED); + } + + if (!RegisterClassExW(&wc)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to register window class"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +// Unregisters the GLFW window class +// +void _glfwUnregisterWindowClassWin32(void) +{ + UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL)); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + if (!createNativeWindow(window, wndconfig)) + return GLFW_FALSE; + + if (ctxconfig->client != GLFW_NO_API) + { + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwInitWGL()) + return GLFW_FALSE; + if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else + { + if (!_glfwInitEGL()) + return GLFW_FALSE; + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + } + + if (window->monitor) + { + _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); + if (!acquireMonitor(window)) + return GLFW_FALSE; + + centerCursor(window); + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (window->monitor) + releaseMonitor(window); + + if (window->context.destroy) + window->context.destroy(window); + + if (_glfw.win32.disabledCursorWindow == window) + _glfw.win32.disabledCursorWindow = NULL; + + if (window->win32.handle) + { + RemovePropW(window->win32.handle, L"GLFW"); + DestroyWindow(window->win32.handle); + window->win32.handle = NULL; + } + + if (window->win32.bigIcon) + DestroyIcon(window->win32.bigIcon); + + if (window->win32.smallIcon) + DestroyIcon(window->win32.smallIcon); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ + WCHAR* wideTitle = _glfwCreateWideStringFromUTF8Win32(title); + if (!wideTitle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert window title to UTF-16"); + return; + } + + SetWindowTextW(window->win32.handle, wideTitle); + free(wideTitle); +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + HICON bigIcon = NULL, smallIcon = NULL; + + if (count) + { + const GLFWimage* bigImage = chooseImage(count, images, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON)); + const GLFWimage* smallImage = chooseImage(count, images, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON)); + + bigIcon = createIcon(bigImage, 0, 0, GLFW_TRUE); + smallIcon = createIcon(smallImage, 0, 0, GLFW_TRUE); + } + else + { + bigIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICON); + smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM); + } + + SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon); + SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon); + + if (window->win32.bigIcon) + DestroyIcon(window->win32.bigIcon); + + if (window->win32.smallIcon) + DestroyIcon(window->win32.smallIcon); + + if (count) + { + window->win32.bigIcon = bigIcon; + window->win32.smallIcon = smallIcon; + } +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + POINT pos = { 0, 0 }; + ClientToScreen(window->win32.handle, &pos); + + if (xpos) + *xpos = pos.x; + if (ypos) + *ypos = pos.y; +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + RECT rect = { xpos, ypos, xpos, ypos }; + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + RECT area; + GetClientRect(window->win32.handle, &area); + + if (width) + *width = area.right; + if (height) + *height = area.bottom; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + if (window->monitor) + { + if (window->monitor->window == window) + acquireMonitor(window); + } + else + { + RECT rect = { 0, 0, width, height }; + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + SetWindowPos(window->win32.handle, HWND_TOP, + 0, 0, rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); + } +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ + RECT area; + + if ((minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) && + (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)) + { + return; + } + + GetWindowRect(window->win32.handle, &area); + MoveWindow(window->win32.handle, + area.left, area.top, + area.right - area.left, + area.bottom - area.top, TRUE); +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +{ + RECT area; + + if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) + return; + + GetWindowRect(window->win32.handle, &area); + applyAspectRatio(window, WMSZ_BOTTOMRIGHT, &area); + MoveWindow(window->win32.handle, + area.left, area.top, + area.right - area.left, + area.bottom - area.top, TRUE); +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + _glfwPlatformGetWindowSize(window, width, height); +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + RECT rect; + int width, height; + + _glfwPlatformGetWindowSize(window, &width, &height); + SetRect(&rect, 0, 0, width, height); + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + + if (left) + *left = -rect.left; + if (top) + *top = -rect.top; + if (right) + *right = rect.right - width; + if (bottom) + *bottom = rect.bottom - height; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_MINIMIZE); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_RESTORE); +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_MAXIMIZE); +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_SHOW); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_HIDE); +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + BringWindowToTop(window->win32.handle); + SetForegroundWindow(window->win32.handle); + SetFocus(window->win32.handle); +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (window->monitor == monitor) + { + if (monitor) + { + if (monitor->window == window) + acquireMonitor(window); + } + else + { + RECT rect = { xpos, ypos, xpos + width, ypos + height }; + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + SetWindowPos(window->win32.handle, HWND_TOP, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER); + } + + return; + } + + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowMonitorChange(window, monitor); + + if (monitor) + { + GLFWvidmode mode; + DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); + UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS; + + if (window->decorated) + { + style &= ~WS_OVERLAPPEDWINDOW; + style |= getWindowStyle(window); + SetWindowLongW(window->win32.handle, GWL_STYLE, style); + + flags |= SWP_FRAMECHANGED; + } + + _glfwPlatformGetVideoMode(monitor, &mode); + _glfwPlatformGetMonitorPos(monitor, &xpos, &ypos); + + SetWindowPos(window->win32.handle, HWND_TOPMOST, + xpos, ypos, mode.width, mode.height, + flags); + + acquireMonitor(window); + } + else + { + HWND after; + RECT rect = { xpos, ypos, xpos + width, ypos + height }; + DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); + UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS; + + if (window->decorated) + { + style &= ~WS_POPUP; + style |= getWindowStyle(window); + SetWindowLongW(window->win32.handle, GWL_STYLE, style); + + flags |= SWP_FRAMECHANGED; + } + + if (window->floating) + after = HWND_TOPMOST; + else + after = HWND_NOTOPMOST; + + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + SetWindowPos(window->win32.handle, after, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + flags); + } +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + return window->win32.handle == GetActiveWindow(); +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + return IsIconic(window->win32.handle); +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + return IsWindowVisible(window->win32.handle); +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + return IsZoomed(window->win32.handle); +} + +void _glfwPlatformPollEvents(void) +{ + MSG msg; + HWND handle; + _GLFWwindow* window; + + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + // Treat WM_QUIT as a close on all windows + // While GLFW does not itself post WM_QUIT, other processes may post + // it to this one, for example Task Manager + + window = _glfw.windowListHead; + while (window) + { + _glfwInputWindowCloseRequest(window); + window = window->next; + } + } + else + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + + handle = GetActiveWindow(); + if (handle) + { + // LSHIFT/RSHIFT fixup (keys tend to "stick" without this fix) + // This is the only async event handling in GLFW, but it solves some + // nasty problems + window = GetPropW(handle, L"GLFW"); + if (window) + { + const int mods = getAsyncKeyMods(); + + // Get current state of left and right shift keys + const int lshiftDown = (GetAsyncKeyState(VK_LSHIFT) >> 15) & 1; + const int rshiftDown = (GetAsyncKeyState(VK_RSHIFT) >> 15) & 1; + + // See if this differs from our belief of what has happened + // (we only have to check for lost key up events) + if (!lshiftDown && window->keys[GLFW_KEY_LEFT_SHIFT] == 1) + _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, 0, GLFW_RELEASE, mods); + + if (!rshiftDown && window->keys[GLFW_KEY_RIGHT_SHIFT] == 1) + _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, 0, GLFW_RELEASE, mods); + } + } + + window = _glfw.win32.disabledCursorWindow; + if (window) + { + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + + // NOTE: Re-center the cursor only if it has moved since the last call, + // to avoid breaking glfwWaitEvents with WM_MOUSEMOVE + if (window->win32.lastCursorPosX != width / 2 || + window->win32.lastCursorPosY != height / 2) + { + _glfwPlatformSetCursorPos(window, width / 2, height / 2); + } + } +} + +void _glfwPlatformWaitEvents(void) +{ + WaitMessage(); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLEVENTS); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformPostEmptyEvent(void) +{ + _GLFWwindow* window = _glfw.windowListHead; + PostMessage(window->win32.handle, WM_NULL, 0, 0); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + POINT pos; + + if (GetCursorPos(&pos)) + { + ScreenToClient(window->win32.handle, &pos); + + if (xpos) + *xpos = pos.x; + if (ypos) + *ypos = pos.y; + } +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) +{ + POINT pos = { (int) xpos, (int) ypos }; + + // Store the new position so it can be recognized later + window->win32.lastCursorPosX = pos.x; + window->win32.lastCursorPosY = pos.y; + + ClientToScreen(window->win32.handle, &pos); + SetCursorPos(pos.x, pos.y); +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + if (mode == GLFW_CURSOR_DISABLED) + { + _glfw.win32.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.win32.restoreCursorPosX, + &_glfw.win32.restoreCursorPosY); + centerCursor(window); + updateClipRect(window); + } + else if (_glfw.win32.disabledCursorWindow == window) + { + _glfw.win32.disabledCursorWindow = NULL; + updateClipRect(NULL); + _glfwPlatformSetCursorPos(window, + _glfw.win32.restoreCursorPosX, + _glfw.win32.restoreCursorPosY); + } + + if (cursorInClientArea(window)) + updateCursorImage(window); +} + +const char* _glfwPlatformGetKeyName(int key, int scancode) +{ + WCHAR name[16]; + + if (key != GLFW_KEY_UNKNOWN) + scancode = _glfw.win32.nativeKeys[key]; + + if (!_glfwIsPrintable(_glfw.win32.publicKeys[scancode])) + return NULL; + + if (!GetKeyNameTextW(scancode << 16, name, sizeof(name) / sizeof(WCHAR))) + return NULL; + + if (!WideCharToMultiByte(CP_UTF8, 0, name, -1, + _glfw.win32.keyName, + sizeof(_glfw.win32.keyName), + NULL, NULL)) + { + return NULL; + } + + return _glfw.win32.keyName; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE); + if (!cursor->win32.handle) + return GLFW_FALSE; + + return GLFW_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + cursor->win32.handle = + CopyCursor(LoadCursorW(NULL, translateCursorShape(shape))); + if (!cursor->win32.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to create standard cursor"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + if (cursor->win32.handle) + DestroyIcon((HICON) cursor->win32.handle); +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + if (cursorInClientArea(window)) + updateCursorImage(window); +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + int characterCount; + HANDLE object; + WCHAR* buffer; + + characterCount = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0); + if (!characterCount) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert clipboard string to UTF-16"); + return; + } + + object = GlobalAlloc(GMEM_MOVEABLE, characterCount * sizeof(WCHAR)); + if (!object) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to allocate global handle for clipboard"); + return; + } + + buffer = GlobalLock(object); + if (!buffer) + { + GlobalFree(object); + + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to lock global handle"); + return; + } + + MultiByteToWideChar(CP_UTF8, 0, string, -1, buffer, characterCount); + GlobalUnlock(object); + + if (!OpenClipboard(_glfw.win32.helperWindowHandle)) + { + GlobalFree(object); + + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard"); + return; + } + + EmptyClipboard(); + SetClipboardData(CF_UNICODETEXT, object); + CloseClipboard(); +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + HANDLE object; + WCHAR* buffer; + + if (!OpenClipboard(_glfw.win32.helperWindowHandle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard"); + return NULL; + } + + object = GetClipboardData(CF_UNICODETEXT); + if (!object) + { + CloseClipboard(); + + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "Win32: Failed to convert clipboard to string"); + return NULL; + } + + buffer = GlobalLock(object); + if (!buffer) + { + CloseClipboard(); + + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to lock global handle"); + return NULL; + } + + free(_glfw.win32.clipboardString); + _glfw.win32.clipboardString = + _glfwCreateUTF8FromWideStringWin32(buffer); + + GlobalUnlock(object); + CloseClipboard(); + + if (!_glfw.win32.clipboardString) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert wide string to UTF-8"); + return NULL; + } + + return _glfw.win32.clipboardString; +} + +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count) +{ + char** extensions; + + *count = 0; + + if (!_glfw.vk.KHR_win32_surface) + return NULL; + + extensions = calloc(2, sizeof(char*)); + extensions[0] = strdup("VK_KHR_surface"); + extensions[1] = strdup("VK_KHR_win32_surface"); + + *count = 2; + return extensions; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR = + (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); + if (!vkGetPhysicalDeviceWin32PresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Win32: Vulkan instance missing VK_KHR_win32_surface extension"); + return GLFW_FALSE; + } + + return vkGetPhysicalDeviceWin32PresentationSupportKHR(device, queuefamily); +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + VkResult err; + VkWin32SurfaceCreateInfoKHR sci; + PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; + + vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) + vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR"); + if (!vkCreateWin32SurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Win32: Vulkan instance missing VK_KHR_win32_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + sci.hinstance = GetModuleHandle(NULL); + sci.hwnd = window->win32.handle; + + err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to create Vulkan surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->win32.handle; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/window.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/window.c new file mode 100644 index 00000000..5e74e6e0 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/window.c @@ -0,0 +1,904 @@ +//======================================================================== +// GLFW 3.2 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// Copyright (c) 2012 Torsten Walluhn +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused) +{ + if (focused) + { + if (window->callbacks.focus) + window->callbacks.focus((GLFWwindow*) window, focused); + } + else + { + int i; + + if (window->callbacks.focus) + window->callbacks.focus((GLFWwindow*) window, focused); + + // Release all pressed keyboard keys + for (i = 0; i <= GLFW_KEY_LAST; i++) + { + if (window->keys[i] == GLFW_PRESS) + _glfwInputKey(window, i, 0, GLFW_RELEASE, 0); + } + + // Release all pressed mouse buttons + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window->mouseButtons[i] == GLFW_PRESS) + _glfwInputMouseClick(window, i, GLFW_RELEASE, 0); + } + } +} + +void _glfwInputWindowPos(_GLFWwindow* window, int x, int y) +{ + if (window->callbacks.pos) + window->callbacks.pos((GLFWwindow*) window, x, y); +} + +void _glfwInputWindowSize(_GLFWwindow* window, int width, int height) +{ + if (window->callbacks.size) + window->callbacks.size((GLFWwindow*) window, width, height); +} + +void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified) +{ + if (window->callbacks.iconify) + window->callbacks.iconify((GLFWwindow*) window, iconified); +} + +void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height) +{ + if (window->callbacks.fbsize) + window->callbacks.fbsize((GLFWwindow*) window, width, height); +} + +void _glfwInputWindowDamage(_GLFWwindow* window) +{ + if (window->callbacks.refresh) + window->callbacks.refresh((GLFWwindow*) window); +} + +void _glfwInputWindowCloseRequest(_GLFWwindow* window) +{ + window->closed = GLFW_TRUE; + + if (window->callbacks.close) + window->callbacks.close((GLFWwindow*) window); +} + +void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor) +{ + window->monitor = monitor; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, + const char* title, + GLFWmonitor* monitor, + GLFWwindow* share) +{ + _GLFWfbconfig fbconfig; + _GLFWctxconfig ctxconfig; + _GLFWwndconfig wndconfig; + _GLFWwindow* window; + _GLFWwindow* previous; + + assert(title != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (width <= 0 || height <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window size %ix%i", + width, height); + + return NULL; + } + + fbconfig = _glfw.hints.framebuffer; + ctxconfig = _glfw.hints.context; + wndconfig = _glfw.hints.window; + + wndconfig.width = width; + wndconfig.height = height; + wndconfig.title = title; + ctxconfig.share = (_GLFWwindow*) share; + + if (ctxconfig.share) + { + if (ctxconfig.client == GLFW_NO_API || + ctxconfig.share->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return NULL; + } + } + + if (!_glfwIsValidContextConfig(&ctxconfig)) + return NULL; + + window = calloc(1, sizeof(_GLFWwindow)); + window->next = _glfw.windowListHead; + _glfw.windowListHead = window; + + window->videoMode.width = width; + window->videoMode.height = height; + window->videoMode.redBits = fbconfig.redBits; + window->videoMode.greenBits = fbconfig.greenBits; + window->videoMode.blueBits = fbconfig.blueBits; + window->videoMode.refreshRate = _glfw.hints.refreshRate; + + window->monitor = (_GLFWmonitor*) monitor; + window->resizable = wndconfig.resizable; + window->decorated = wndconfig.decorated; + window->autoIconify = wndconfig.autoIconify; + window->floating = wndconfig.floating; + window->cursorMode = GLFW_CURSOR_NORMAL; + + window->minwidth = GLFW_DONT_CARE; + window->minheight = GLFW_DONT_CARE; + window->maxwidth = GLFW_DONT_CARE; + window->maxheight = GLFW_DONT_CARE; + window->numer = GLFW_DONT_CARE; + window->denom = GLFW_DONT_CARE; + + // Save the currently current context so it can be restored later + previous = _glfwPlatformGetCurrentContext(); + if (ctxconfig.client != GLFW_NO_API) + glfwMakeContextCurrent(NULL); + + // Open the actual window and create its context + if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) + { + glfwMakeContextCurrent((GLFWwindow*) previous); + glfwDestroyWindow((GLFWwindow*) window); + return NULL; + } + + if (ctxconfig.client != GLFW_NO_API) + { + window->context.makeCurrent(window); + + // Retrieve the actual (as opposed to requested) context attributes + if (!_glfwRefreshContextAttribs(&ctxconfig)) + { + glfwMakeContextCurrent((GLFWwindow*) previous); + glfwDestroyWindow((GLFWwindow*) window); + return NULL; + } + + // Restore the previously current context (or NULL) + glfwMakeContextCurrent((GLFWwindow*) previous); + } + + if (!window->monitor) + { + if (wndconfig.visible) + { + _glfwPlatformShowWindow(window); + if (wndconfig.focused) + _glfwPlatformFocusWindow(window); + } + } + + return (GLFWwindow*) window; +} + +void glfwDefaultWindowHints(void) +{ + _GLFW_REQUIRE_INIT(); + + memset(&_glfw.hints, 0, sizeof(_glfw.hints)); + + // The default is OpenGL with minimum version 1.0 + _glfw.hints.context.client = GLFW_OPENGL_API; + _glfw.hints.context.source = GLFW_NATIVE_CONTEXT_API; + _glfw.hints.context.major = 1; + _glfw.hints.context.minor = 0; + + // The default is a focused, visible, resizable window with decorations + _glfw.hints.window.resizable = GLFW_TRUE; + _glfw.hints.window.visible = GLFW_TRUE; + _glfw.hints.window.decorated = GLFW_TRUE; + _glfw.hints.window.focused = GLFW_TRUE; + _glfw.hints.window.autoIconify = GLFW_TRUE; + + // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil, + // double buffered + _glfw.hints.framebuffer.redBits = 8; + _glfw.hints.framebuffer.greenBits = 8; + _glfw.hints.framebuffer.blueBits = 8; + _glfw.hints.framebuffer.alphaBits = 8; + _glfw.hints.framebuffer.depthBits = 24; + _glfw.hints.framebuffer.stencilBits = 8; + _glfw.hints.framebuffer.doublebuffer = GLFW_TRUE; + + // The default is to select the highest available refresh rate + _glfw.hints.refreshRate = GLFW_DONT_CARE; +} + +GLFWAPI void glfwWindowHint(int hint, int value) +{ + _GLFW_REQUIRE_INIT(); + + switch (hint) + { + case GLFW_RED_BITS: + _glfw.hints.framebuffer.redBits = value; + break; + case GLFW_GREEN_BITS: + _glfw.hints.framebuffer.greenBits = value; + break; + case GLFW_BLUE_BITS: + _glfw.hints.framebuffer.blueBits = value; + break; + case GLFW_ALPHA_BITS: + _glfw.hints.framebuffer.alphaBits = value; + break; + case GLFW_DEPTH_BITS: + _glfw.hints.framebuffer.depthBits = value; + break; + case GLFW_STENCIL_BITS: + _glfw.hints.framebuffer.stencilBits = value; + break; + case GLFW_ACCUM_RED_BITS: + _glfw.hints.framebuffer.accumRedBits = value; + break; + case GLFW_ACCUM_GREEN_BITS: + _glfw.hints.framebuffer.accumGreenBits = value; + break; + case GLFW_ACCUM_BLUE_BITS: + _glfw.hints.framebuffer.accumBlueBits = value; + break; + case GLFW_ACCUM_ALPHA_BITS: + _glfw.hints.framebuffer.accumAlphaBits = value; + break; + case GLFW_AUX_BUFFERS: + _glfw.hints.framebuffer.auxBuffers = value; + break; + case GLFW_STEREO: + _glfw.hints.framebuffer.stereo = value ? GLFW_TRUE : GLFW_FALSE; + break; + case GLFW_DOUBLEBUFFER: + _glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE; + break; + case GLFW_SAMPLES: + _glfw.hints.framebuffer.samples = value; + break; + case GLFW_SRGB_CAPABLE: + _glfw.hints.framebuffer.sRGB = value ? GLFW_TRUE : GLFW_FALSE; + break; + case GLFW_RESIZABLE: + _glfw.hints.window.resizable = value ? GLFW_TRUE : GLFW_FALSE; + break; + case GLFW_DECORATED: + _glfw.hints.window.decorated = value ? GLFW_TRUE : GLFW_FALSE; + break; + case GLFW_FOCUSED: + _glfw.hints.window.focused = value ? GLFW_TRUE : GLFW_FALSE; + break; + case GLFW_AUTO_ICONIFY: + _glfw.hints.window.autoIconify = value ? GLFW_TRUE : GLFW_FALSE; + break; + case GLFW_FLOATING: + _glfw.hints.window.floating = value ? GLFW_TRUE : GLFW_FALSE; + break; + case GLFW_MAXIMIZED: + _glfw.hints.window.maximized = value ? GLFW_TRUE : GLFW_FALSE; + break; + case GLFW_VISIBLE: + _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE; + break; + case GLFW_CLIENT_API: + _glfw.hints.context.client = value; + break; + case GLFW_CONTEXT_CREATION_API: + _glfw.hints.context.source = value; + break; + case GLFW_CONTEXT_VERSION_MAJOR: + _glfw.hints.context.major = value; + break; + case GLFW_CONTEXT_VERSION_MINOR: + _glfw.hints.context.minor = value; + break; + case GLFW_CONTEXT_ROBUSTNESS: + _glfw.hints.context.robustness = value; + break; + case GLFW_OPENGL_FORWARD_COMPAT: + _glfw.hints.context.forward = value ? GLFW_TRUE : GLFW_FALSE; + break; + case GLFW_OPENGL_DEBUG_CONTEXT: + _glfw.hints.context.debug = value ? GLFW_TRUE : GLFW_FALSE; + break; + case GLFW_CONTEXT_NO_ERROR: + _glfw.hints.context.noerror = value ? GLFW_TRUE : GLFW_FALSE; + break; + case GLFW_OPENGL_PROFILE: + _glfw.hints.context.profile = value; + break; + case GLFW_CONTEXT_RELEASE_BEHAVIOR: + _glfw.hints.context.release = value; + break; + case GLFW_REFRESH_RATE: + _glfw.hints.refreshRate = value; + break; + default: + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint %i", hint); + break; + } +} + +GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + // Allow closing of NULL (to match the behavior of free) + if (window == NULL) + return; + + // Clear all callbacks to avoid exposing a half torn-down window object + memset(&window->callbacks, 0, sizeof(window->callbacks)); + + // The window's context must not be current on another thread when the + // window is destroyed + if (window == _glfwPlatformGetCurrentContext()) + glfwMakeContextCurrent(NULL); + + _glfwPlatformDestroyWindow(window); + + // Unlink window from global linked list + { + _GLFWwindow** prev = &_glfw.windowListHead; + + while (*prev != window) + prev = &((*prev)->next); + + *prev = window->next; + } + + free(window); +} + +GLFWAPI int glfwWindowShouldClose(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return window->closed; +} + +GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* handle, int value) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + window->closed = value; +} + +GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + assert(title != NULL); + + _GLFW_REQUIRE_INIT(); + _glfwPlatformSetWindowTitle(window, title); +} + +GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle, + int count, const GLFWimage* images) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + assert(count >= 0); + assert(count == 0 || images != NULL); + + _GLFW_REQUIRE_INIT(); + _glfwPlatformSetWindowIcon(window, count, images); +} + +GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetWindowPos(window, xpos, ypos); +} + +GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (window->monitor) + return; + + _glfwPlatformSetWindowPos(window, xpos, ypos); +} + +GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + if (width) + *width = 0; + if (height) + *height = 0; + + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetWindowSize(window, width, height); +} + +GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + window->videoMode.width = width; + window->videoMode.height = height; + + _glfwPlatformSetWindowSize(window, width, height); +} + +GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (minwidth != GLFW_DONT_CARE && minheight != GLFW_DONT_CARE) + { + if (minwidth < 0 || minheight < 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window minimum size %ix%i", + minwidth, minheight); + return; + } + } + + if (maxwidth != GLFW_DONT_CARE && maxheight != GLFW_DONT_CARE) + { + if (maxwidth < 0 || maxheight < 0 || + maxwidth < minwidth || maxheight < minheight) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window maximum size %ix%i", + maxwidth, maxheight); + return; + } + } + + window->minwidth = minwidth; + window->minheight = minheight; + window->maxwidth = maxwidth; + window->maxheight = maxheight; + + if (window->monitor || !window->resizable) + return; + + _glfwPlatformSetWindowSizeLimits(window, + minwidth, minheight, + maxwidth, maxheight); +} + +GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE) + { + if (numer <= 0 || denom <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window aspect ratio %i:%i", + numer, denom); + return; + } + } + + window->numer = numer; + window->denom = denom; + + if (window->monitor || !window->resizable) + return; + + _glfwPlatformSetWindowAspectRatio(window, numer, denom); +} + +GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + if (width) + *width = 0; + if (height) + *height = 0; + + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetFramebufferSize(window, width, height); +} + +GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle, + int* left, int* top, + int* right, int* bottom) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + if (left) + *left = 0; + if (top) + *top = 0; + if (right) + *right = 0; + if (bottom) + *bottom = 0; + + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetWindowFrameSize(window, left, top, right, bottom); +} + +GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + _glfwPlatformIconifyWindow(window); +} + +GLFWAPI void glfwRestoreWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + _glfwPlatformRestoreWindow(window); +} + +GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + _glfwPlatformMaximizeWindow(window); +} + +GLFWAPI void glfwShowWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (window->monitor) + return; + + _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); +} + +GLFWAPI void glfwHideWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (window->monitor) + return; + + _glfwPlatformHideWindow(window); +} + +GLFWAPI void glfwFocusWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + _glfwPlatformFocusWindow(window); +} + +GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(0); + + switch (attrib) + { + case GLFW_FOCUSED: + return _glfwPlatformWindowFocused(window); + case GLFW_ICONIFIED: + return _glfwPlatformWindowIconified(window); + case GLFW_VISIBLE: + return _glfwPlatformWindowVisible(window); + case GLFW_MAXIMIZED: + return _glfwPlatformWindowMaximized(window); + case GLFW_RESIZABLE: + return window->resizable; + case GLFW_DECORATED: + return window->decorated; + case GLFW_FLOATING: + return window->floating; + case GLFW_CLIENT_API: + return window->context.client; + case GLFW_CONTEXT_CREATION_API: + return window->context.source; + case GLFW_CONTEXT_VERSION_MAJOR: + return window->context.major; + case GLFW_CONTEXT_VERSION_MINOR: + return window->context.minor; + case GLFW_CONTEXT_REVISION: + return window->context.revision; + case GLFW_CONTEXT_ROBUSTNESS: + return window->context.robustness; + case GLFW_OPENGL_FORWARD_COMPAT: + return window->context.forward; + case GLFW_OPENGL_DEBUG_CONTEXT: + return window->context.debug; + case GLFW_OPENGL_PROFILE: + return window->context.profile; + case GLFW_CONTEXT_RELEASE_BEHAVIOR: + return window->context.release; + case GLFW_CONTEXT_NO_ERROR: + return window->context.noerror; + } + + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute %i", attrib); + return 0; +} + +GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return (GLFWmonitor*) window->monitor; +} + +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* wh, + GLFWmonitor* mh, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + _GLFWwindow* window = (_GLFWwindow*) wh; + _GLFWmonitor* monitor = (_GLFWmonitor*) mh; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (width <= 0 || height <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window size %ix%i", + width, height); + return; + } + + if (refreshRate < 0 && refreshRate != GLFW_DONT_CARE) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid refresh rate %i", + refreshRate); + return; + } + + window->videoMode.width = width; + window->videoMode.height = height; + window->videoMode.refreshRate = refreshRate; + + _glfwPlatformSetWindowMonitor(window, monitor, + xpos, ypos, width, height, + refreshRate); +} + +GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + window->userPointer = pointer; +} + +GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->userPointer; +} + +GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* handle, + GLFWwindowposfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.pos, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* handle, + GLFWwindowsizefun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.size, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* handle, + GLFWwindowclosefun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.close, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* handle, + GLFWwindowrefreshfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.refresh, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* handle, + GLFWwindowfocusfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.focus, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle, + GLFWwindowiconifyfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.iconify, cbfun); + return cbfun; +} + +GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle, + GLFWframebuffersizefun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.fbsize, cbfun); + return cbfun; +} + +GLFWAPI void glfwPollEvents(void) +{ + _GLFW_REQUIRE_INIT(); + _glfwPlatformPollEvents(); +} + +GLFWAPI void glfwWaitEvents(void) +{ + _GLFW_REQUIRE_INIT(); + + if (!_glfw.windowListHead) + return; + + _glfwPlatformWaitEvents(); +} + +GLFWAPI void glfwWaitEventsTimeout(double timeout) +{ + _GLFW_REQUIRE_INIT(); + + if (timeout != timeout || timeout < 0.0 || timeout > DBL_MAX) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", timeout); + return; + } + + _glfwPlatformWaitEventsTimeout(timeout); +} + +GLFWAPI void glfwPostEmptyEvent(void) +{ + _GLFW_REQUIRE_INIT(); + + if (!_glfw.windowListHead) + return; + + _glfwPlatformPostEmptyEvent(); +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wl_init.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wl_init.c new file mode 100644 index 00000000..44f7d0c8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wl_init.c @@ -0,0 +1,658 @@ +//======================================================================== +// GLFW 3.2 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ã…dahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +static inline int min(int n1, int n2) +{ + return n1 < n2 ? n1 : n2; +} + +static void pointerHandleEnter(void* data, + struct wl_pointer* pointer, + uint32_t serial, + struct wl_surface* surface, + wl_fixed_t sx, + wl_fixed_t sy) +{ + _GLFWwindow* window = wl_surface_get_user_data(surface); + + _glfw.wl.pointerSerial = serial; + _glfw.wl.pointerFocus = window; + + _glfwPlatformSetCursor(window, window->wl.currentCursor); + _glfwInputCursorEnter(window, GLFW_TRUE); +} + +static void pointerHandleLeave(void* data, + struct wl_pointer* pointer, + uint32_t serial, + struct wl_surface* surface) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + + if (!window) + return; + + _glfw.wl.pointerSerial = serial; + _glfw.wl.pointerFocus = NULL; + _glfwInputCursorEnter(window, GLFW_FALSE); +} + +static void pointerHandleMotion(void* data, + struct wl_pointer* pointer, + uint32_t time, + wl_fixed_t sx, + wl_fixed_t sy) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + + if (!window) + return; + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + return; + else + { + window->wl.cursorPosX = wl_fixed_to_double(sx); + window->wl.cursorPosY = wl_fixed_to_double(sy); + } + + _glfwInputCursorPos(window, + wl_fixed_to_double(sx), + wl_fixed_to_double(sy)); +} + +static void pointerHandleButton(void* data, + struct wl_pointer* wl_pointer, + uint32_t serial, + uint32_t time, + uint32_t button, + uint32_t state) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + int glfwButton; + + if (!window) + return; + + /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev + * codes. */ + glfwButton = button - BTN_LEFT; + + _glfwInputMouseClick(window, + glfwButton, + state == WL_POINTER_BUTTON_STATE_PRESSED + ? GLFW_PRESS + : GLFW_RELEASE, + _glfw.wl.xkb.modifiers); +} + +static void pointerHandleAxis(void* data, + struct wl_pointer* wl_pointer, + uint32_t time, + uint32_t axis, + wl_fixed_t value) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + double scroll_factor; + double x, y; + + if (!window) + return; + + /* Wayland scroll events are in pointer motion coordinate space (think + * two finger scroll). The factor 10 is commonly used to convert to + * "scroll step means 1.0. */ + scroll_factor = 1.0/10.0; + + switch (axis) + { + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + x = wl_fixed_to_double(value) * scroll_factor; + y = 0.0; + break; + case WL_POINTER_AXIS_VERTICAL_SCROLL: + x = 0.0; + y = wl_fixed_to_double(value) * scroll_factor; + break; + default: + break; + } + + _glfwInputScroll(window, x, y); +} + +static const struct wl_pointer_listener pointerListener = { + pointerHandleEnter, + pointerHandleLeave, + pointerHandleMotion, + pointerHandleButton, + pointerHandleAxis, +}; + +static void keyboardHandleKeymap(void* data, + struct wl_keyboard* keyboard, + uint32_t format, + int fd, + uint32_t size) +{ + struct xkb_keymap* keymap; + struct xkb_state* state; + char* mapStr; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) + { + close(fd); + return; + } + + mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (mapStr == MAP_FAILED) { + close(fd); + return; + } + + keymap = xkb_map_new_from_string(_glfw.wl.xkb.context, + mapStr, + XKB_KEYMAP_FORMAT_TEXT_V1, + 0); + munmap(mapStr, size); + close(fd); + + if (!keymap) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to compile keymap"); + return; + } + + state = xkb_state_new(keymap); + if (!state) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create XKB state"); + xkb_map_unref(keymap); + return; + } + + xkb_keymap_unref(_glfw.wl.xkb.keymap); + xkb_state_unref(_glfw.wl.xkb.state); + _glfw.wl.xkb.keymap = keymap; + _glfw.wl.xkb.state = state; + + _glfw.wl.xkb.control_mask = + 1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Control"); + _glfw.wl.xkb.alt_mask = + 1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Mod1"); + _glfw.wl.xkb.shift_mask = + 1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); + _glfw.wl.xkb.super_mask = + 1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); +} + +static void keyboardHandleEnter(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + struct wl_surface* surface, + struct wl_array* keys) +{ + _GLFWwindow* window = wl_surface_get_user_data(surface); + + _glfw.wl.keyboardFocus = window; + _glfwInputWindowFocus(window, GLFW_TRUE); +} + +static void keyboardHandleLeave(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + struct wl_surface* surface) +{ + _GLFWwindow* window = _glfw.wl.keyboardFocus; + + if (!window) + return; + + _glfw.wl.keyboardFocus = NULL; + _glfwInputWindowFocus(window, GLFW_FALSE); +} + +static int toGLFWKeyCode(uint32_t key) +{ + if (key < sizeof(_glfw.wl.publicKeys) / sizeof(_glfw.wl.publicKeys[0])) + return _glfw.wl.publicKeys[key]; + + return GLFW_KEY_UNKNOWN; +} + +static void keyboardHandleKey(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state) +{ + uint32_t code, num_syms; + long cp; + int keyCode; + int action; + const xkb_keysym_t *syms; + _GLFWwindow* window = _glfw.wl.keyboardFocus; + + if (!window) + return; + + keyCode = toGLFWKeyCode(key); + action = state == WL_KEYBOARD_KEY_STATE_PRESSED + ? GLFW_PRESS : GLFW_RELEASE; + + _glfwInputKey(window, keyCode, key, action, + _glfw.wl.xkb.modifiers); + + code = key + 8; + num_syms = xkb_key_get_syms(_glfw.wl.xkb.state, code, &syms); + + if (num_syms == 1) + { + cp = _glfwKeySym2Unicode(syms[0]); + if (cp != -1) + { + const int mods = _glfw.wl.xkb.modifiers; + const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); + _glfwInputChar(window, cp, mods, plain); + } + } +} + +static void keyboardHandleModifiers(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + uint32_t modsDepressed, + uint32_t modsLatched, + uint32_t modsLocked, + uint32_t group) +{ + xkb_mod_mask_t mask; + unsigned int modifiers = 0; + + if (!_glfw.wl.xkb.keymap) + return; + + xkb_state_update_mask(_glfw.wl.xkb.state, + modsDepressed, + modsLatched, + modsLocked, + 0, + 0, + group); + + mask = xkb_state_serialize_mods(_glfw.wl.xkb.state, + XKB_STATE_DEPRESSED | + XKB_STATE_LATCHED); + if (mask & _glfw.wl.xkb.control_mask) + modifiers |= GLFW_MOD_CONTROL; + if (mask & _glfw.wl.xkb.alt_mask) + modifiers |= GLFW_MOD_ALT; + if (mask & _glfw.wl.xkb.shift_mask) + modifiers |= GLFW_MOD_SHIFT; + if (mask & _glfw.wl.xkb.super_mask) + modifiers |= GLFW_MOD_SUPER; + _glfw.wl.xkb.modifiers = modifiers; +} + +static const struct wl_keyboard_listener keyboardListener = { + keyboardHandleKeymap, + keyboardHandleEnter, + keyboardHandleLeave, + keyboardHandleKey, + keyboardHandleModifiers, +}; + +static void seatHandleCapabilities(void* data, + struct wl_seat* seat, + enum wl_seat_capability caps) +{ + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer) + { + _glfw.wl.pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL); + } + else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer) + { + wl_pointer_destroy(_glfw.wl.pointer); + _glfw.wl.pointer = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard) + { + _glfw.wl.keyboard = wl_seat_get_keyboard(seat); + wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL); + } + else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard) + { + wl_keyboard_destroy(_glfw.wl.keyboard); + _glfw.wl.keyboard = NULL; + } +} + +static const struct wl_seat_listener seatListener = { + seatHandleCapabilities +}; + +static void registryHandleGlobal(void* data, + struct wl_registry* registry, + uint32_t name, + const char* interface, + uint32_t version) +{ + if (strcmp(interface, "wl_compositor") == 0) + { + _glfw.wl.wl_compositor_version = min(3, version); + _glfw.wl.compositor = + wl_registry_bind(registry, name, &wl_compositor_interface, + _glfw.wl.wl_compositor_version); + } + else if (strcmp(interface, "wl_shm") == 0) + { + _glfw.wl.shm = + wl_registry_bind(registry, name, &wl_shm_interface, 1); + } + else if (strcmp(interface, "wl_shell") == 0) + { + _glfw.wl.shell = + wl_registry_bind(registry, name, &wl_shell_interface, 1); + } + else if (strcmp(interface, "wl_output") == 0) + { + _glfwAddOutputWayland(name, version); + } + else if (strcmp(interface, "wl_seat") == 0) + { + if (!_glfw.wl.seat) + { + _glfw.wl.seat = + wl_registry_bind(registry, name, &wl_seat_interface, 1); + wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL); + } + } + else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) + { + _glfw.wl.relativePointerManager = + wl_registry_bind(registry, name, + &zwp_relative_pointer_manager_v1_interface, + 1); + } + else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) + { + _glfw.wl.pointerConstraints = + wl_registry_bind(registry, name, + &zwp_pointer_constraints_v1_interface, + 1); + } +} + +static void registryHandleGlobalRemove(void *data, + struct wl_registry *registry, + uint32_t name) +{ +} + + +static const struct wl_registry_listener registryListener = { + registryHandleGlobal, + registryHandleGlobalRemove +}; + +// Create key code translation tables +// +static void createKeyTables(void) +{ + memset(_glfw.wl.publicKeys, -1, sizeof(_glfw.wl.publicKeys)); + + _glfw.wl.publicKeys[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT; + _glfw.wl.publicKeys[KEY_1] = GLFW_KEY_1; + _glfw.wl.publicKeys[KEY_2] = GLFW_KEY_2; + _glfw.wl.publicKeys[KEY_3] = GLFW_KEY_3; + _glfw.wl.publicKeys[KEY_4] = GLFW_KEY_4; + _glfw.wl.publicKeys[KEY_5] = GLFW_KEY_5; + _glfw.wl.publicKeys[KEY_6] = GLFW_KEY_6; + _glfw.wl.publicKeys[KEY_7] = GLFW_KEY_7; + _glfw.wl.publicKeys[KEY_8] = GLFW_KEY_8; + _glfw.wl.publicKeys[KEY_9] = GLFW_KEY_9; + _glfw.wl.publicKeys[KEY_0] = GLFW_KEY_0; + _glfw.wl.publicKeys[KEY_MINUS] = GLFW_KEY_MINUS; + _glfw.wl.publicKeys[KEY_EQUAL] = GLFW_KEY_EQUAL; + _glfw.wl.publicKeys[KEY_Q] = GLFW_KEY_Q; + _glfw.wl.publicKeys[KEY_W] = GLFW_KEY_W; + _glfw.wl.publicKeys[KEY_E] = GLFW_KEY_E; + _glfw.wl.publicKeys[KEY_R] = GLFW_KEY_R; + _glfw.wl.publicKeys[KEY_T] = GLFW_KEY_T; + _glfw.wl.publicKeys[KEY_Y] = GLFW_KEY_Y; + _glfw.wl.publicKeys[KEY_U] = GLFW_KEY_U; + _glfw.wl.publicKeys[KEY_I] = GLFW_KEY_I; + _glfw.wl.publicKeys[KEY_O] = GLFW_KEY_O; + _glfw.wl.publicKeys[KEY_P] = GLFW_KEY_P; + _glfw.wl.publicKeys[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET; + _glfw.wl.publicKeys[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET; + _glfw.wl.publicKeys[KEY_A] = GLFW_KEY_A; + _glfw.wl.publicKeys[KEY_S] = GLFW_KEY_S; + _glfw.wl.publicKeys[KEY_D] = GLFW_KEY_D; + _glfw.wl.publicKeys[KEY_F] = GLFW_KEY_F; + _glfw.wl.publicKeys[KEY_G] = GLFW_KEY_G; + _glfw.wl.publicKeys[KEY_H] = GLFW_KEY_H; + _glfw.wl.publicKeys[KEY_J] = GLFW_KEY_J; + _glfw.wl.publicKeys[KEY_K] = GLFW_KEY_K; + _glfw.wl.publicKeys[KEY_L] = GLFW_KEY_L; + _glfw.wl.publicKeys[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON; + _glfw.wl.publicKeys[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE; + _glfw.wl.publicKeys[KEY_Z] = GLFW_KEY_Z; + _glfw.wl.publicKeys[KEY_X] = GLFW_KEY_X; + _glfw.wl.publicKeys[KEY_C] = GLFW_KEY_C; + _glfw.wl.publicKeys[KEY_V] = GLFW_KEY_V; + _glfw.wl.publicKeys[KEY_B] = GLFW_KEY_B; + _glfw.wl.publicKeys[KEY_N] = GLFW_KEY_N; + _glfw.wl.publicKeys[KEY_M] = GLFW_KEY_M; + _glfw.wl.publicKeys[KEY_COMMA] = GLFW_KEY_COMMA; + _glfw.wl.publicKeys[KEY_DOT] = GLFW_KEY_PERIOD; + _glfw.wl.publicKeys[KEY_SLASH] = GLFW_KEY_SLASH; + _glfw.wl.publicKeys[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH; + _glfw.wl.publicKeys[KEY_ESC] = GLFW_KEY_ESCAPE; + _glfw.wl.publicKeys[KEY_TAB] = GLFW_KEY_TAB; + _glfw.wl.publicKeys[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT; + _glfw.wl.publicKeys[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT; + _glfw.wl.publicKeys[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL; + _glfw.wl.publicKeys[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL; + _glfw.wl.publicKeys[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT; + _glfw.wl.publicKeys[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT; + _glfw.wl.publicKeys[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER; + _glfw.wl.publicKeys[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER; + _glfw.wl.publicKeys[KEY_MENU] = GLFW_KEY_MENU; + _glfw.wl.publicKeys[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK; + _glfw.wl.publicKeys[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK; + _glfw.wl.publicKeys[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN; + _glfw.wl.publicKeys[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK; + _glfw.wl.publicKeys[KEY_PAUSE] = GLFW_KEY_PAUSE; + _glfw.wl.publicKeys[KEY_DELETE] = GLFW_KEY_DELETE; + _glfw.wl.publicKeys[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE; + _glfw.wl.publicKeys[KEY_ENTER] = GLFW_KEY_ENTER; + _glfw.wl.publicKeys[KEY_HOME] = GLFW_KEY_HOME; + _glfw.wl.publicKeys[KEY_END] = GLFW_KEY_END; + _glfw.wl.publicKeys[KEY_PAGEUP] = GLFW_KEY_PAGE_UP; + _glfw.wl.publicKeys[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN; + _glfw.wl.publicKeys[KEY_INSERT] = GLFW_KEY_INSERT; + _glfw.wl.publicKeys[KEY_LEFT] = GLFW_KEY_LEFT; + _glfw.wl.publicKeys[KEY_RIGHT] = GLFW_KEY_RIGHT; + _glfw.wl.publicKeys[KEY_DOWN] = GLFW_KEY_DOWN; + _glfw.wl.publicKeys[KEY_UP] = GLFW_KEY_UP; + _glfw.wl.publicKeys[KEY_F1] = GLFW_KEY_F1; + _glfw.wl.publicKeys[KEY_F2] = GLFW_KEY_F2; + _glfw.wl.publicKeys[KEY_F3] = GLFW_KEY_F3; + _glfw.wl.publicKeys[KEY_F4] = GLFW_KEY_F4; + _glfw.wl.publicKeys[KEY_F5] = GLFW_KEY_F5; + _glfw.wl.publicKeys[KEY_F6] = GLFW_KEY_F6; + _glfw.wl.publicKeys[KEY_F7] = GLFW_KEY_F7; + _glfw.wl.publicKeys[KEY_F8] = GLFW_KEY_F8; + _glfw.wl.publicKeys[KEY_F9] = GLFW_KEY_F9; + _glfw.wl.publicKeys[KEY_F10] = GLFW_KEY_F10; + _glfw.wl.publicKeys[KEY_F11] = GLFW_KEY_F11; + _glfw.wl.publicKeys[KEY_F12] = GLFW_KEY_F12; + _glfw.wl.publicKeys[KEY_F13] = GLFW_KEY_F13; + _glfw.wl.publicKeys[KEY_F14] = GLFW_KEY_F14; + _glfw.wl.publicKeys[KEY_F15] = GLFW_KEY_F15; + _glfw.wl.publicKeys[KEY_F16] = GLFW_KEY_F16; + _glfw.wl.publicKeys[KEY_F17] = GLFW_KEY_F17; + _glfw.wl.publicKeys[KEY_F18] = GLFW_KEY_F18; + _glfw.wl.publicKeys[KEY_F19] = GLFW_KEY_F19; + _glfw.wl.publicKeys[KEY_F20] = GLFW_KEY_F20; + _glfw.wl.publicKeys[KEY_F21] = GLFW_KEY_F21; + _glfw.wl.publicKeys[KEY_F22] = GLFW_KEY_F22; + _glfw.wl.publicKeys[KEY_F23] = GLFW_KEY_F23; + _glfw.wl.publicKeys[KEY_F24] = GLFW_KEY_F24; + _glfw.wl.publicKeys[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE; + _glfw.wl.publicKeys[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY; + _glfw.wl.publicKeys[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT; + _glfw.wl.publicKeys[KEY_KPPLUS] = GLFW_KEY_KP_ADD; + _glfw.wl.publicKeys[KEY_KP0] = GLFW_KEY_KP_0; + _glfw.wl.publicKeys[KEY_KP1] = GLFW_KEY_KP_1; + _glfw.wl.publicKeys[KEY_KP2] = GLFW_KEY_KP_2; + _glfw.wl.publicKeys[KEY_KP3] = GLFW_KEY_KP_3; + _glfw.wl.publicKeys[KEY_KP4] = GLFW_KEY_KP_4; + _glfw.wl.publicKeys[KEY_KP5] = GLFW_KEY_KP_5; + _glfw.wl.publicKeys[KEY_KP6] = GLFW_KEY_KP_6; + _glfw.wl.publicKeys[KEY_KP7] = GLFW_KEY_KP_7; + _glfw.wl.publicKeys[KEY_KP8] = GLFW_KEY_KP_8; + _glfw.wl.publicKeys[KEY_KP9] = GLFW_KEY_KP_9; + _glfw.wl.publicKeys[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL; + _glfw.wl.publicKeys[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL; + _glfw.wl.publicKeys[KEY_KPENTER] = GLFW_KEY_KP_ENTER; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + _glfw.wl.display = wl_display_connect(NULL); + if (!_glfw.wl.display) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to connect to display"); + return GLFW_FALSE; + } + + _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display); + wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL); + + _glfw.wl.monitors = calloc(4, sizeof(_GLFWmonitor*)); + _glfw.wl.monitorsSize = 4; + + createKeyTables(); + + _glfw.wl.xkb.context = xkb_context_new(0); + if (!_glfw.wl.xkb.context) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to initialize xkb context"); + return GLFW_FALSE; + } + + // Sync so we got all registry objects + wl_display_roundtrip(_glfw.wl.display); + + // Sync so we got all initial output events + wl_display_roundtrip(_glfw.wl.display); + + if (!_glfwInitThreadLocalStoragePOSIX()) + return GLFW_FALSE; + + if (!_glfwInitJoysticksLinux()) + return GLFW_FALSE; + + _glfwInitTimerPOSIX(); + + if (_glfw.wl.pointer && _glfw.wl.shm) + { + _glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm); + if (!_glfw.wl.cursorTheme) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unable to load default cursor theme\n"); + return GLFW_FALSE; + } + _glfw.wl.cursorSurface = + wl_compositor_create_surface(_glfw.wl.compositor); + } + + return GLFW_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + _glfwTerminateEGL(); + _glfwTerminateJoysticksLinux(); + _glfwTerminateThreadLocalStoragePOSIX(); + + if (_glfw.wl.cursorTheme) + wl_cursor_theme_destroy(_glfw.wl.cursorTheme); + if (_glfw.wl.cursorSurface) + wl_surface_destroy(_glfw.wl.cursorSurface); + if (_glfw.wl.registry) + wl_registry_destroy(_glfw.wl.registry); + if (_glfw.wl.display) + wl_display_flush(_glfw.wl.display); + if (_glfw.wl.display) + wl_display_disconnect(_glfw.wl.display); +} + +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " Wayland EGL" +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + " clock_gettime" +#else + " gettimeofday" +#endif +#if defined(__linux__) + " /dev/js" +#endif +#if defined(_GLFW_BUILD_DLL) + " shared" +#endif + ; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wl_monitor.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wl_monitor.c new file mode 100644 index 00000000..27731c22 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wl_monitor.c @@ -0,0 +1,269 @@ +//======================================================================== +// GLFW 3.2 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ã…dahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include + + +struct _GLFWvidmodeWayland +{ + GLFWvidmode base; + uint32_t flags; +}; + +static void geometry(void* data, + struct wl_output* output, + int32_t x, + int32_t y, + int32_t physicalWidth, + int32_t physicalHeight, + int32_t subpixel, + const char* make, + const char* model, + int32_t transform) +{ + struct _GLFWmonitor *monitor = data; + + monitor->wl.x = x; + monitor->wl.y = y; + monitor->widthMM = physicalWidth; + monitor->heightMM = physicalHeight; +} + +static void mode(void* data, + struct wl_output* output, + uint32_t flags, + int32_t width, + int32_t height, + int32_t refresh) +{ + struct _GLFWmonitor *monitor = data; + _GLFWvidmodeWayland mode = { { 0 }, }; + + mode.base.width = width; + mode.base.height = height; + mode.base.refreshRate = refresh / 1000; + mode.flags = flags; + + if (monitor->wl.modesCount + 1 >= monitor->wl.modesSize) + { + int size = monitor->wl.modesSize * 2; + _GLFWvidmodeWayland* modes = + realloc(monitor->wl.modes, + size * sizeof(_GLFWvidmodeWayland)); + monitor->wl.modes = modes; + monitor->wl.modesSize = size; + } + + monitor->wl.modes[monitor->wl.modesCount++] = mode; +} + +static void done(void* data, + struct wl_output* output) +{ + struct _GLFWmonitor *monitor = data; + + monitor->wl.done = GLFW_TRUE; +} + +static void scale(void* data, + struct wl_output* output, + int32_t factor) +{ + struct _GLFWmonitor *monitor = data; + + monitor->wl.scale = factor; +} + +static const struct wl_output_listener output_listener = { + geometry, + mode, + done, + scale, +}; + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwAddOutputWayland(uint32_t name, uint32_t version) +{ + _GLFWmonitor *monitor; + struct wl_output *output; + char name_str[80]; + + memset(name_str, 0, sizeof(name_str)); + snprintf(name_str, 79, "wl_output@%u", name); + + if (version < 2) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unsupported output interface version"); + return; + } + + monitor = _glfwAllocMonitor(name_str, 0, 0); + + output = wl_registry_bind(_glfw.wl.registry, + name, + &wl_output_interface, + 2); + if (!output) + { + _glfwFreeMonitor(monitor); + return; + } + + monitor->wl.modes = calloc(4, sizeof(_GLFWvidmodeWayland)); + monitor->wl.modesSize = 4; + + monitor->wl.scale = 1; + + monitor->wl.output = output; + wl_output_add_listener(output, &output_listener, monitor); + + if (_glfw.wl.monitorsCount + 1 >= _glfw.wl.monitorsSize) + { + _GLFWmonitor** monitors = _glfw.wl.monitors; + int size = _glfw.wl.monitorsSize * 2; + + monitors = realloc(monitors, size * sizeof(_GLFWmonitor*)); + + _glfw.wl.monitors = monitors; + _glfw.wl.monitorsSize = size; + } + + _glfw.wl.monitors[_glfw.wl.monitorsCount++] = monitor; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwPlatformGetMonitors(int* count) +{ + _GLFWmonitor** monitors; + _GLFWmonitor* monitor; + int i, monitorsCount = _glfw.wl.monitorsCount; + + if (_glfw.wl.monitorsCount == 0) + goto err; + + monitors = calloc(monitorsCount, sizeof(_GLFWmonitor*)); + + for (i = 0; i < monitorsCount; i++) + { + _GLFWmonitor* origMonitor = _glfw.wl.monitors[i]; + monitor = calloc(1, sizeof(_GLFWmonitor)); + + monitor->modes = + _glfwPlatformGetVideoModes(origMonitor, + &origMonitor->wl.modesCount); + *monitor = *_glfw.wl.monitors[i]; + monitors[i] = monitor; + } + + *count = monitorsCount; + return monitors; + +err: + *count = 0; + return NULL; +} + +GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) +{ + return first->wl.output == second->wl.output; +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + if (xpos) + *xpos = monitor->wl.x; + if (ypos) + *ypos = monitor->wl.y; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +{ + GLFWvidmode *modes; + int i, modesCount = monitor->wl.modesCount; + + modes = calloc(modesCount, sizeof(GLFWvidmode)); + + for (i = 0; i < modesCount; i++) + modes[i] = monitor->wl.modes[i].base; + + *found = modesCount; + return modes; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + int i; + + for (i = 0; i < monitor->wl.modesCount; i++) + { + if (monitor->wl.modes[i].flags & WL_OUTPUT_MODE_CURRENT) + { + *mode = monitor->wl.modes[i].base; + return; + } + } +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Gamma ramp getting not supported yet"); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Gamma ramp setting not supported yet"); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return monitor->wl.output; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wl_platform.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wl_platform.h new file mode 100644 index 00000000..9e42b36f --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wl_platform.h @@ -0,0 +1,179 @@ +//======================================================================== +// GLFW 3.2 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ã…dahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_wayland_platform_h_ +#define _glfw3_wayland_platform_h_ + +#include +#include +#include + +typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; + +typedef struct VkWaylandSurfaceCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + struct wl_display* display; + struct wl_surface* surface; +} VkWaylandSurfaceCreateInfoKHR; + +typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWaylandSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); +typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*); + +#include "posix_tls.h" +#include "posix_time.h" +#include "linux_joystick.h" +#include "xkb_unicode.h" +#include "egl_context.h" + +#include "wayland-relative-pointer-unstable-v1-client-protocol.h" +#include "wayland-pointer-constraints-unstable-v1-client-protocol.h" + +#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) +#define _glfw_dlclose(handle) dlclose(handle) +#define _glfw_dlsym(handle, name) dlsym(handle, name) + +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->wl.native) +#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.wl.display) + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWayland wl +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wl +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWayland wl +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWayland wl + +#define _GLFW_PLATFORM_CONTEXT_STATE +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE + + +// Wayland-specific video mode data +// +typedef struct _GLFWvidmodeWayland _GLFWvidmodeWayland; + +// Wayland-specific per-window data +// +typedef struct _GLFWwindowWayland +{ + int width, height; + GLFWbool visible; + GLFWbool maximized; + struct wl_surface* surface; + struct wl_egl_window* native; + struct wl_shell_surface* shell_surface; + struct wl_callback* callback; + + _GLFWcursor* currentCursor; + double cursorPosX, cursorPosY; + + char* title; + + // We need to track the monitors the window spans on to calculate the + // optimal scaling factor. + int scale; + _GLFWmonitor** monitors; + int monitorsCount; + int monitorsSize; + + struct { + struct zwp_relative_pointer_v1* relativePointer; + struct zwp_locked_pointer_v1* lockedPointer; + } pointerLock; +} _GLFWwindowWayland; + +// Wayland-specific global data +// +typedef struct _GLFWlibraryWayland +{ + struct wl_display* display; + struct wl_registry* registry; + struct wl_compositor* compositor; + struct wl_shell* shell; + struct wl_shm* shm; + struct wl_seat* seat; + struct wl_pointer* pointer; + struct wl_keyboard* keyboard; + struct zwp_relative_pointer_manager_v1* relativePointerManager; + struct zwp_pointer_constraints_v1* pointerConstraints; + + int wl_compositor_version; + + struct wl_cursor_theme* cursorTheme; + struct wl_surface* cursorSurface; + uint32_t pointerSerial; + + _GLFWmonitor** monitors; + int monitorsCount; + int monitorsSize; + + short int publicKeys[256]; + + struct { + struct xkb_context* context; + struct xkb_keymap* keymap; + struct xkb_state* state; + xkb_mod_mask_t control_mask; + xkb_mod_mask_t alt_mask; + xkb_mod_mask_t shift_mask; + xkb_mod_mask_t super_mask; + unsigned int modifiers; + } xkb; + + _GLFWwindow* pointerFocus; + _GLFWwindow* keyboardFocus; + +} _GLFWlibraryWayland; + +// Wayland-specific per-monitor data +// +typedef struct _GLFWmonitorWayland +{ + struct wl_output* output; + + _GLFWvidmodeWayland* modes; + int modesCount; + int modesSize; + GLFWbool done; + + int x; + int y; + int scale; +} _GLFWmonitorWayland; + +// Wayland-specific per-cursor data +// +typedef struct _GLFWcursorWayland +{ + struct wl_cursor_image* image; + struct wl_buffer* buffer; + int width, height; + int xhot, yhot; +} _GLFWcursorWayland; + + +void _glfwAddOutputWayland(uint32_t name, uint32_t version); + +#endif // _glfw3_wayland_platform_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wl_window.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wl_window.c new file mode 100644 index 00000000..cf75ec82 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/wl_window.c @@ -0,0 +1,1050 @@ +//======================================================================== +// GLFW 3.2 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ã…dahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define _GNU_SOURCE + +#include "internal.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +static void handlePing(void* data, + struct wl_shell_surface* shellSurface, + uint32_t serial) +{ + wl_shell_surface_pong(shellSurface, serial); +} + +static void handleConfigure(void* data, + struct wl_shell_surface* shellSurface, + uint32_t edges, + int32_t width, + int32_t height) +{ + _GLFWwindow* window = data; + float aspectRatio; + float targetRatio; + + if (!window->monitor) + { + if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) + { + aspectRatio = (float)width / (float)height; + targetRatio = (float)window->numer / (float)window->denom; + if (aspectRatio < targetRatio) + height = width / targetRatio; + else if (aspectRatio > targetRatio) + width = height * targetRatio; + } + + if (window->minwidth != GLFW_DONT_CARE && width < window->minwidth) + width = window->minwidth; + else if (window->maxwidth != GLFW_DONT_CARE && width > window->maxwidth) + width = window->maxwidth; + + if (window->minheight != GLFW_DONT_CARE && height < window->minheight) + height = window->minheight; + else if (window->maxheight != GLFW_DONT_CARE && height > window->maxheight) + height = window->maxheight; + } + + _glfwInputWindowSize(window, width, height); + _glfwPlatformSetWindowSize(window, width, height); + _glfwInputWindowDamage(window); +} + +static void handlePopupDone(void* data, + struct wl_shell_surface* shellSurface) +{ +} + +static const struct wl_shell_surface_listener shellSurfaceListener = { + handlePing, + handleConfigure, + handlePopupDone +}; + +static void checkScaleChange(_GLFWwindow* window) +{ + int scaledWidth, scaledHeight; + int scale = 1; + int i; + int monitorScale; + + // Check if we will be able to set the buffer scale or not. + if (_glfw.wl.wl_compositor_version < 3) + return; + + // Get the scale factor from the highest scale monitor. + for (i = 0; i < window->wl.monitorsCount; ++i) + { + monitorScale = window->wl.monitors[i]->wl.scale; + if (scale < monitorScale) + scale = monitorScale; + } + + // Only change the framebuffer size if the scale changed. + if (scale != window->wl.scale) + { + window->wl.scale = scale; + scaledWidth = window->wl.width * scale; + scaledHeight = window->wl.height * scale; + wl_surface_set_buffer_scale(window->wl.surface, scale); + wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0); + _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); + } +} + +static void handleEnter(void *data, + struct wl_surface *surface, + struct wl_output *output) +{ + _GLFWwindow* window = data; + _GLFWmonitor* monitor = wl_output_get_user_data(output); + + if (window->wl.monitorsCount + 1 > window->wl.monitorsSize) + { + ++window->wl.monitorsSize; + window->wl.monitors = + realloc(window->wl.monitors, + window->wl.monitorsSize * sizeof(_GLFWmonitor*)); + } + + window->wl.monitors[window->wl.monitorsCount++] = monitor; + + checkScaleChange(window); +} + +static void handleLeave(void *data, + struct wl_surface *surface, + struct wl_output *output) +{ + _GLFWwindow* window = data; + _GLFWmonitor* monitor = wl_output_get_user_data(output); + GLFWbool found; + int i; + + for (i = 0, found = GLFW_FALSE; i < window->wl.monitorsCount - 1; ++i) + { + if (monitor == window->wl.monitors[i]) + found = GLFW_TRUE; + if (found) + window->wl.monitors[i] = window->wl.monitors[i + 1]; + } + window->wl.monitors[--window->wl.monitorsCount] = NULL; + + checkScaleChange(window); +} + +static const struct wl_surface_listener surfaceListener = { + handleEnter, + handleLeave +}; + +// Makes the surface considered as XRGB instead of ARGB. +static void setOpaqueRegion(_GLFWwindow* window) +{ + struct wl_region* region; + + region = wl_compositor_create_region(_glfw.wl.compositor); + if (!region) + return; + + wl_region_add(region, 0, 0, window->wl.width, window->wl.height); + wl_surface_set_opaque_region(window->wl.surface, region); + wl_surface_commit(window->wl.surface); + wl_region_destroy(region); +} + +static GLFWbool createSurface(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig) +{ + window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor); + if (!window->wl.surface) + return GLFW_FALSE; + + wl_surface_add_listener(window->wl.surface, + &surfaceListener, + window); + + wl_surface_set_user_data(window->wl.surface, window); + + window->wl.native = wl_egl_window_create(window->wl.surface, + wndconfig->width, + wndconfig->height); + if (!window->wl.native) + return GLFW_FALSE; + + window->wl.width = wndconfig->width; + window->wl.height = wndconfig->height; + window->wl.scale = 1; + + // TODO: make this optional once issue #197 is fixed. + setOpaqueRegion(window); + + return GLFW_TRUE; +} + +static GLFWbool createShellSurface(_GLFWwindow* window) +{ + window->wl.shell_surface = wl_shell_get_shell_surface(_glfw.wl.shell, + window->wl.surface); + if (!window->wl.shell_surface) + return GLFW_FALSE; + + wl_shell_surface_add_listener(window->wl.shell_surface, + &shellSurfaceListener, + window); + + if (window->wl.title) + wl_shell_surface_set_title(window->wl.shell_surface, window->wl.title); + + if (window->monitor) + { + wl_shell_surface_set_fullscreen( + window->wl.shell_surface, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, + 0, + window->monitor->wl.output); + } + else if (window->wl.maximized) + { + wl_shell_surface_set_maximized(window->wl.shell_surface, NULL); + } + else + { + wl_shell_surface_set_toplevel(window->wl.shell_surface); + } + + return GLFW_TRUE; +} + +static int +createTmpfileCloexec(char* tmpname) +{ + int fd; + + fd = mkostemp(tmpname, O_CLOEXEC); + if (fd >= 0) + unlink(tmpname); + + return fd; +} + +static void +handleEvents(int timeout) +{ + struct wl_display* display = _glfw.wl.display; + struct pollfd fds[] = { + { wl_display_get_fd(display), POLLIN }, + }; + + while (wl_display_prepare_read(display) != 0) + wl_display_dispatch_pending(display); + + // If an error different from EAGAIN happens, we have likely been + // disconnected from the Wayland session, try to handle that the best we + // can. + if (wl_display_flush(display) < 0 && errno != EAGAIN) + { + _GLFWwindow* window = _glfw.windowListHead; + while (window) + { + _glfwInputWindowCloseRequest(window); + window = window->next; + } + wl_display_cancel_read(display); + return; + } + + if (poll(fds, 1, timeout) > 0) + { + wl_display_read_events(display); + wl_display_dispatch_pending(display); + } + else + { + wl_display_cancel_read(display); + } +} + +/* + * Create a new, unique, anonymous file of the given size, and + * return the file descriptor for it. The file descriptor is set + * CLOEXEC. The file is immediately suitable for mmap()'ing + * the given size at offset zero. + * + * The file should not have a permanent backing store like a disk, + * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. + * + * The file name is deleted from the file system. + * + * The file is suitable for buffer sharing between processes by + * transmitting the file descriptor over Unix sockets using the + * SCM_RIGHTS methods. + * + * posix_fallocate() is used to guarantee that disk space is available + * for the file at the given size. If disk space is insufficent, errno + * is set to ENOSPC. If posix_fallocate() is not supported, program may + * receive SIGBUS on accessing mmap()'ed file contents instead. + */ +int +createAnonymousFile(off_t size) +{ + static const char template[] = "/glfw-shared-XXXXXX"; + const char* path; + char* name; + int fd; + int ret; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) + { + errno = ENOENT; + return -1; + } + + name = calloc(strlen(path) + sizeof(template), 1); + strcpy(name, path); + strcat(name, template); + + fd = createTmpfileCloexec(name); + + free(name); + + if (fd < 0) + return -1; + ret = posix_fallocate(fd, 0, size); + if (ret != 0) + { + close(fd); + errno = ret; + return -1; + } + return fd; +} + +// Translates a GLFW standard cursor to a theme cursor name +// +static char *translateCursorShape(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return "left_ptr"; + case GLFW_IBEAM_CURSOR: + return "xterm"; + case GLFW_CROSSHAIR_CURSOR: + return "crosshair"; + case GLFW_HAND_CURSOR: + return "grabbing"; + case GLFW_HRESIZE_CURSOR: + return "sb_h_double_arrow"; + case GLFW_VRESIZE_CURSOR: + return "sb_v_double_arrow"; + } + return NULL; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + if (!createSurface(window, wndconfig)) + return GLFW_FALSE; + + if (ctxconfig->client != GLFW_NO_API) + { + if (!_glfwInitEGL()) + return GLFW_FALSE; + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + + if (wndconfig->title) + window->wl.title = strdup(wndconfig->title); + + if (wndconfig->visible) + { + if (!createShellSurface(window)) + return GLFW_FALSE; + + window->wl.visible = GLFW_TRUE; + } + else + { + window->wl.shell_surface = NULL; + window->wl.visible = GLFW_FALSE; + } + + window->wl.currentCursor = NULL; + + window->wl.monitors = calloc(1, sizeof(_GLFWmonitor*)); + window->wl.monitorsCount = 0; + window->wl.monitorsSize = 1; + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (window == _glfw.wl.pointerFocus) + { + _glfw.wl.pointerFocus = NULL; + _glfwInputCursorEnter(window, GLFW_FALSE); + } + if (window == _glfw.wl.keyboardFocus) + { + _glfw.wl.keyboardFocus = NULL; + _glfwInputWindowFocus(window, GLFW_FALSE); + } + + if (window->context.destroy) + window->context.destroy(window); + + if (window->wl.native) + wl_egl_window_destroy(window->wl.native); + + if (window->wl.shell_surface) + wl_shell_surface_destroy(window->wl.shell_surface); + + if (window->wl.surface) + wl_surface_destroy(window->wl.surface); + + free(window->wl.title); + free(window->wl.monitors); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ + if (window->wl.title) + free(window->wl.title); + window->wl.title = strdup(title); + if (window->wl.shell_surface) + wl_shell_surface_set_title(window->wl.shell_surface, title); +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Setting window icon not supported"); +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + // A Wayland client is not aware of its position, so just warn and leave it + // as (0, 0) + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window position retrieval not supported"); +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + // A Wayland client can not set its position, so just warn + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window position setting not supported"); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->wl.width; + if (height) + *height = window->wl.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + int scaledWidth = width * window->wl.scale; + int scaledHeight = height * window->wl.scale; + window->wl.width = width; + window->wl.height = height; + wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0); + setOpaqueRegion(window); + _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ + // TODO: find out how to trigger a resize. + // The actual limits are checked in the wl_shell_surface::configure handler. +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +{ + // TODO: find out how to trigger a resize. + // The actual limits are checked in the wl_shell_surface::configure handler. +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + _glfwPlatformGetWindowSize(window, width, height); + *width *= window->wl.scale; + *height *= window->wl.scale; +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + // TODO: will need a proper implementation once decorations are + // implemented, but for now just leave everything as 0. +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + // TODO: move to xdg_shell instead of wl_shell. + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Iconify window not supported"); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + // TODO: also do the same for iconified. + if (window->monitor || window->wl.maximized) + { + if (window->wl.shell_surface) + wl_shell_surface_set_toplevel(window->wl.shell_surface); + + window->wl.maximized = GLFW_FALSE; + } +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + if (!window->monitor && !window->wl.maximized) + { + if (window->wl.shell_surface) + { + // Let the compositor select the best output. + wl_shell_surface_set_maximized(window->wl.shell_surface, NULL); + } + window->wl.maximized = GLFW_TRUE; + } +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + if (!window->monitor) + { + if (!window->wl.shell_surface) + createShellSurface(window); + window->wl.visible = GLFW_TRUE; + } +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + if (!window->monitor) + { + if (window->wl.shell_surface) + wl_shell_surface_destroy(window->wl.shell_surface); + window->wl.visible = GLFW_FALSE; + } +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Focusing a window requires user interaction"); +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (monitor) + { + wl_shell_surface_set_fullscreen( + window->wl.shell_surface, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, + refreshRate * 1000, // Convert Hz to mHz. + monitor->wl.output); + } + else + { + wl_shell_surface_set_toplevel(window->wl.shell_surface); + } + _glfwInputWindowMonitorChange(window, monitor); +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + return _glfw.wl.keyboardFocus == window; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + // TODO: move to xdg_shell, wl_shell doesn't have any iconified concept. + return GLFW_FALSE; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + return window->wl.visible; +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + return window->wl.maximized; +} + +void _glfwPlatformPollEvents(void) +{ + handleEvents(0); +} + +void _glfwPlatformWaitEvents(void) +{ + handleEvents(-1); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + handleEvents((int) (timeout * 1e3)); +} + +void _glfwPlatformPostEmptyEvent(void) +{ + wl_display_sync(_glfw.wl.display); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + if (xpos) + *xpos = window->wl.cursorPosX; + if (ypos) + *ypos = window->wl.cursorPosY; +} + +static GLFWbool isPointerLocked(_GLFWwindow* window); + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +{ + if (isPointerLocked(window)) + { + zwp_locked_pointer_v1_set_cursor_position_hint( + window->wl.pointerLock.lockedPointer, + wl_fixed_from_double(x), wl_fixed_from_double(y)); + wl_surface_commit(window->wl.surface); + } +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + _glfwPlatformSetCursor(window, window->wl.currentCursor); +} + +const char* _glfwPlatformGetKeyName(int key, int scancode) +{ + // TODO + return NULL; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + struct wl_shm_pool* pool; + int stride = image->width * 4; + int length = image->width * image->height * 4; + void* data; + int fd, i; + + fd = createAnonymousFile(length); + if (fd < 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Creating a buffer file for %d B failed: %m", + length); + return GLFW_FALSE; + } + + data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Cursor mmap failed: %m"); + close(fd); + return GLFW_FALSE; + } + + pool = wl_shm_create_pool(_glfw.wl.shm, fd, length); + + close(fd); + unsigned char* source = (unsigned char*) image->pixels; + unsigned char* target = data; + for (i = 0; i < image->width * image->height; i++, source += 4) + { + unsigned int alpha = source[3]; + + *target++ = (unsigned char) ((source[2] * alpha) / 255); + *target++ = (unsigned char) ((source[1] * alpha) / 255); + *target++ = (unsigned char) ((source[0] * alpha) / 255); + *target++ = (unsigned char) alpha; + } + + cursor->wl.buffer = + wl_shm_pool_create_buffer(pool, 0, + image->width, + image->height, + stride, WL_SHM_FORMAT_ARGB8888); + munmap(data, length); + wl_shm_pool_destroy(pool); + + cursor->wl.width = image->width; + cursor->wl.height = image->height; + cursor->wl.xhot = xhot; + cursor->wl.yhot = yhot; + return GLFW_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + struct wl_cursor* standardCursor; + + standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, + translateCursorShape(shape)); + if (!standardCursor) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Standard cursor \"%s\" not found", + translateCursorShape(shape)); + return GLFW_FALSE; + } + + cursor->wl.image = standardCursor->images[0]; + return GLFW_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + // If it's a standard cursor we don't need to do anything here + if (cursor->wl.image) + return; + + if (cursor->wl.buffer) + wl_buffer_destroy(cursor->wl.buffer); +} + +static void handleRelativeMotion(void* data, + struct zwp_relative_pointer_v1* pointer, + uint32_t timeHi, + uint32_t timeLo, + wl_fixed_t dx, + wl_fixed_t dy, + wl_fixed_t dxUnaccel, + wl_fixed_t dyUnaccel) +{ + _GLFWwindow* window = data; + + if (window->cursorMode != GLFW_CURSOR_DISABLED) + return; + + _glfwInputCursorPos(window, + window->virtualCursorPosX + wl_fixed_to_double(dxUnaccel), + window->virtualCursorPosY + wl_fixed_to_double(dyUnaccel)); +} + +static const struct zwp_relative_pointer_v1_listener relativePointerListener = { + handleRelativeMotion +}; + +static void handleLocked(void* data, + struct zwp_locked_pointer_v1* lockedPointer) +{ +} + +static void unlockPointer(_GLFWwindow* window) +{ + struct zwp_relative_pointer_v1* relativePointer = + window->wl.pointerLock.relativePointer; + struct zwp_locked_pointer_v1* lockedPointer = + window->wl.pointerLock.lockedPointer; + + zwp_relative_pointer_v1_destroy(relativePointer); + zwp_locked_pointer_v1_destroy(lockedPointer); + + window->wl.pointerLock.relativePointer = NULL; + window->wl.pointerLock.lockedPointer = NULL; +} + +static void lockPointer(_GLFWwindow* window); + +static void handleUnlocked(void* data, + struct zwp_locked_pointer_v1* lockedPointer) +{ +} + +static const struct zwp_locked_pointer_v1_listener lockedPointerListener = { + handleLocked, + handleUnlocked +}; + +static void lockPointer(_GLFWwindow* window) +{ + struct zwp_relative_pointer_v1* relativePointer; + struct zwp_locked_pointer_v1* lockedPointer; + + if (!_glfw.wl.relativePointerManager) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: no relative pointer manager"); + return; + } + + relativePointer = + zwp_relative_pointer_manager_v1_get_relative_pointer( + _glfw.wl.relativePointerManager, + _glfw.wl.pointer); + zwp_relative_pointer_v1_add_listener(relativePointer, + &relativePointerListener, + window); + + lockedPointer = + zwp_pointer_constraints_v1_lock_pointer( + _glfw.wl.pointerConstraints, + window->wl.surface, + _glfw.wl.pointer, + NULL, + ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + zwp_locked_pointer_v1_add_listener(lockedPointer, + &lockedPointerListener, + window); + + window->wl.pointerLock.relativePointer = relativePointer; + window->wl.pointerLock.lockedPointer = lockedPointer; + + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, + NULL, 0, 0); +} + +static GLFWbool isPointerLocked(_GLFWwindow* window) +{ + return window->wl.pointerLock.lockedPointer != NULL; +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + struct wl_buffer* buffer; + struct wl_cursor* defaultCursor; + struct wl_cursor_image* image; + struct wl_surface* surface = _glfw.wl.cursorSurface; + + if (!_glfw.wl.pointer) + return; + + window->wl.currentCursor = cursor; + + // If we're not in the correct window just save the cursor + // the next time the pointer enters the window the cursor will change + if (window != _glfw.wl.pointerFocus) + return; + + // Unlock possible pointer lock if no longer disabled. + if (window->cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window)) + unlockPointer(window); + + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + if (cursor) + image = cursor->wl.image; + else + { + defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, + "left_ptr"); + if (!defaultCursor) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Standard cursor not found"); + return; + } + image = defaultCursor->images[0]; + } + + if (image) + { + buffer = wl_cursor_image_get_buffer(image); + if (!buffer) + return; + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, + surface, + image->hotspot_x, + image->hotspot_y); + wl_surface_attach(surface, buffer, 0, 0); + wl_surface_damage(surface, 0, 0, + image->width, image->height); + wl_surface_commit(surface); + } + else + { + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, + surface, + cursor->wl.xhot, + cursor->wl.yhot); + wl_surface_attach(surface, cursor->wl.buffer, 0, 0); + wl_surface_damage(surface, 0, 0, + cursor->wl.width, cursor->wl.height); + wl_surface_commit(surface); + } + } + else if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + if (!isPointerLocked(window)) + lockPointer(window); + } + else if (window->cursorMode == GLFW_CURSOR_HIDDEN) + { + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, + NULL, 0, 0); + } +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Clipboard setting not implemented yet"); +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Clipboard getting not implemented yet"); + return NULL; +} + +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count) +{ + char** extensions; + + *count = 0; + + if (!_glfw.vk.KHR_wayland_surface) + return NULL; + + extensions = calloc(2, sizeof(char*)); + extensions[0] = strdup("VK_KHR_surface"); + extensions[1] = strdup("VK_KHR_wayland_surface"); + + *count = 2; + return extensions; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR = + (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); + if (!vkGetPhysicalDeviceWaylandPresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension"); + return VK_NULL_HANDLE; + } + + return vkGetPhysicalDeviceWaylandPresentationSupportKHR(device, + queuefamily, + _glfw.wl.display); +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + VkResult err; + VkWaylandSurfaceCreateInfoKHR sci; + PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; + + vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR) + vkGetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR"); + if (!vkCreateWaylandSurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + sci.display = _glfw.wl.display; + sci.surface = window->wl.surface; + + err = vkCreateWaylandSurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create Vulkan surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI struct wl_display* glfwGetWaylandDisplay(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfw.wl.display; +} + +GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->wl.surface; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/x11_init.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/x11_init.c new file mode 100644 index 00000000..f7a06c1d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/x11_init.c @@ -0,0 +1,833 @@ +//======================================================================== +// GLFW 3.2 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include + +#include +#include +#include +#include +#include + + +// Translate an X11 key code to a GLFW key code. +// +static int translateKeyCode(int scancode) +{ + int keySym; + + // Valid key code range is [8,255], according to the Xlib manual + if (scancode < 8 || scancode > 255) + return GLFW_KEY_UNKNOWN; + + if (_glfw.x11.xkb.available) + { + // Try secondary keysym, for numeric keypad keys + // Note: This way we always force "NumLock = ON", which is intentional + // since the returned key code should correspond to a physical + // location. + keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 1); + switch (keySym) + { + case XK_KP_0: return GLFW_KEY_KP_0; + case XK_KP_1: return GLFW_KEY_KP_1; + case XK_KP_2: return GLFW_KEY_KP_2; + case XK_KP_3: return GLFW_KEY_KP_3; + case XK_KP_4: return GLFW_KEY_KP_4; + case XK_KP_5: return GLFW_KEY_KP_5; + case XK_KP_6: return GLFW_KEY_KP_6; + case XK_KP_7: return GLFW_KEY_KP_7; + case XK_KP_8: return GLFW_KEY_KP_8; + case XK_KP_9: return GLFW_KEY_KP_9; + case XK_KP_Separator: + case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + default: break; + } + + // Now try primary keysym for function keys (non-printable keys) + // These should not depend on the current keyboard layout + keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); + } + else + { + int dummy; + KeySym* keySyms; + + keySyms = XGetKeyboardMapping(_glfw.x11.display, scancode, 1, &dummy); + keySym = keySyms[0]; + XFree(keySyms); + } + + switch (keySym) + { + case XK_Escape: return GLFW_KEY_ESCAPE; + case XK_Tab: return GLFW_KEY_TAB; + case XK_Shift_L: return GLFW_KEY_LEFT_SHIFT; + case XK_Shift_R: return GLFW_KEY_RIGHT_SHIFT; + case XK_Control_L: return GLFW_KEY_LEFT_CONTROL; + case XK_Control_R: return GLFW_KEY_RIGHT_CONTROL; + case XK_Meta_L: + case XK_Alt_L: return GLFW_KEY_LEFT_ALT; + case XK_Mode_switch: // Mapped to Alt_R on many keyboards + case XK_ISO_Level3_Shift: // AltGr on at least some machines + case XK_Meta_R: + case XK_Alt_R: return GLFW_KEY_RIGHT_ALT; + case XK_Super_L: return GLFW_KEY_LEFT_SUPER; + case XK_Super_R: return GLFW_KEY_RIGHT_SUPER; + case XK_Menu: return GLFW_KEY_MENU; + case XK_Num_Lock: return GLFW_KEY_NUM_LOCK; + case XK_Caps_Lock: return GLFW_KEY_CAPS_LOCK; + case XK_Print: return GLFW_KEY_PRINT_SCREEN; + case XK_Scroll_Lock: return GLFW_KEY_SCROLL_LOCK; + case XK_Pause: return GLFW_KEY_PAUSE; + case XK_Delete: return GLFW_KEY_DELETE; + case XK_BackSpace: return GLFW_KEY_BACKSPACE; + case XK_Return: return GLFW_KEY_ENTER; + case XK_Home: return GLFW_KEY_HOME; + case XK_End: return GLFW_KEY_END; + case XK_Page_Up: return GLFW_KEY_PAGE_UP; + case XK_Page_Down: return GLFW_KEY_PAGE_DOWN; + case XK_Insert: return GLFW_KEY_INSERT; + case XK_Left: return GLFW_KEY_LEFT; + case XK_Right: return GLFW_KEY_RIGHT; + case XK_Down: return GLFW_KEY_DOWN; + case XK_Up: return GLFW_KEY_UP; + case XK_F1: return GLFW_KEY_F1; + case XK_F2: return GLFW_KEY_F2; + case XK_F3: return GLFW_KEY_F3; + case XK_F4: return GLFW_KEY_F4; + case XK_F5: return GLFW_KEY_F5; + case XK_F6: return GLFW_KEY_F6; + case XK_F7: return GLFW_KEY_F7; + case XK_F8: return GLFW_KEY_F8; + case XK_F9: return GLFW_KEY_F9; + case XK_F10: return GLFW_KEY_F10; + case XK_F11: return GLFW_KEY_F11; + case XK_F12: return GLFW_KEY_F12; + case XK_F13: return GLFW_KEY_F13; + case XK_F14: return GLFW_KEY_F14; + case XK_F15: return GLFW_KEY_F15; + case XK_F16: return GLFW_KEY_F16; + case XK_F17: return GLFW_KEY_F17; + case XK_F18: return GLFW_KEY_F18; + case XK_F19: return GLFW_KEY_F19; + case XK_F20: return GLFW_KEY_F20; + case XK_F21: return GLFW_KEY_F21; + case XK_F22: return GLFW_KEY_F22; + case XK_F23: return GLFW_KEY_F23; + case XK_F24: return GLFW_KEY_F24; + case XK_F25: return GLFW_KEY_F25; + + // Numeric keypad + case XK_KP_Divide: return GLFW_KEY_KP_DIVIDE; + case XK_KP_Multiply: return GLFW_KEY_KP_MULTIPLY; + case XK_KP_Subtract: return GLFW_KEY_KP_SUBTRACT; + case XK_KP_Add: return GLFW_KEY_KP_ADD; + + // These should have been detected in secondary keysym test above! + case XK_KP_Insert: return GLFW_KEY_KP_0; + case XK_KP_End: return GLFW_KEY_KP_1; + case XK_KP_Down: return GLFW_KEY_KP_2; + case XK_KP_Page_Down: return GLFW_KEY_KP_3; + case XK_KP_Left: return GLFW_KEY_KP_4; + case XK_KP_Right: return GLFW_KEY_KP_6; + case XK_KP_Home: return GLFW_KEY_KP_7; + case XK_KP_Up: return GLFW_KEY_KP_8; + case XK_KP_Page_Up: return GLFW_KEY_KP_9; + case XK_KP_Delete: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + + // Last resort: Check for printable keys (should not happen if the XKB + // extension is available). This will give a layout dependent mapping + // (which is wrong, and we may miss some keys, especially on non-US + // keyboards), but it's better than nothing... + case XK_a: return GLFW_KEY_A; + case XK_b: return GLFW_KEY_B; + case XK_c: return GLFW_KEY_C; + case XK_d: return GLFW_KEY_D; + case XK_e: return GLFW_KEY_E; + case XK_f: return GLFW_KEY_F; + case XK_g: return GLFW_KEY_G; + case XK_h: return GLFW_KEY_H; + case XK_i: return GLFW_KEY_I; + case XK_j: return GLFW_KEY_J; + case XK_k: return GLFW_KEY_K; + case XK_l: return GLFW_KEY_L; + case XK_m: return GLFW_KEY_M; + case XK_n: return GLFW_KEY_N; + case XK_o: return GLFW_KEY_O; + case XK_p: return GLFW_KEY_P; + case XK_q: return GLFW_KEY_Q; + case XK_r: return GLFW_KEY_R; + case XK_s: return GLFW_KEY_S; + case XK_t: return GLFW_KEY_T; + case XK_u: return GLFW_KEY_U; + case XK_v: return GLFW_KEY_V; + case XK_w: return GLFW_KEY_W; + case XK_x: return GLFW_KEY_X; + case XK_y: return GLFW_KEY_Y; + case XK_z: return GLFW_KEY_Z; + case XK_1: return GLFW_KEY_1; + case XK_2: return GLFW_KEY_2; + case XK_3: return GLFW_KEY_3; + case XK_4: return GLFW_KEY_4; + case XK_5: return GLFW_KEY_5; + case XK_6: return GLFW_KEY_6; + case XK_7: return GLFW_KEY_7; + case XK_8: return GLFW_KEY_8; + case XK_9: return GLFW_KEY_9; + case XK_0: return GLFW_KEY_0; + case XK_space: return GLFW_KEY_SPACE; + case XK_minus: return GLFW_KEY_MINUS; + case XK_equal: return GLFW_KEY_EQUAL; + case XK_bracketleft: return GLFW_KEY_LEFT_BRACKET; + case XK_bracketright: return GLFW_KEY_RIGHT_BRACKET; + case XK_backslash: return GLFW_KEY_BACKSLASH; + case XK_semicolon: return GLFW_KEY_SEMICOLON; + case XK_apostrophe: return GLFW_KEY_APOSTROPHE; + case XK_grave: return GLFW_KEY_GRAVE_ACCENT; + case XK_comma: return GLFW_KEY_COMMA; + case XK_period: return GLFW_KEY_PERIOD; + case XK_slash: return GLFW_KEY_SLASH; + case XK_less: return GLFW_KEY_WORLD_1; // At least in some layouts... + default: break; + } + + // No matching translation was found + return GLFW_KEY_UNKNOWN; +} + +// Create key code translation tables +// +static void createKeyTables(void) +{ + int scancode, key; + + memset(_glfw.x11.publicKeys, -1, sizeof(_glfw.x11.publicKeys)); + memset(_glfw.x11.nativeKeys, -1, sizeof(_glfw.x11.nativeKeys)); + + if (_glfw.x11.xkb.available) + { + // Use XKB to determine physical key locations independently of the current + // keyboard layout + + char name[XkbKeyNameLength + 1]; + XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd); + XkbGetNames(_glfw.x11.display, XkbKeyNamesMask, desc); + + // Find the X11 key code -> GLFW key code mapping + for (scancode = desc->min_key_code; scancode <= desc->max_key_code; scancode++) + { + memcpy(name, desc->names->keys[scancode].name, XkbKeyNameLength); + name[XkbKeyNameLength] = '\0'; + + // Map the key name to a GLFW key code. Note: We only map printable + // keys here, and we use the US keyboard layout. The rest of the + // keys (function keys) are mapped using traditional KeySym + // translations. + if (strcmp(name, "TLDE") == 0) key = GLFW_KEY_GRAVE_ACCENT; + else if (strcmp(name, "AE01") == 0) key = GLFW_KEY_1; + else if (strcmp(name, "AE02") == 0) key = GLFW_KEY_2; + else if (strcmp(name, "AE03") == 0) key = GLFW_KEY_3; + else if (strcmp(name, "AE04") == 0) key = GLFW_KEY_4; + else if (strcmp(name, "AE05") == 0) key = GLFW_KEY_5; + else if (strcmp(name, "AE06") == 0) key = GLFW_KEY_6; + else if (strcmp(name, "AE07") == 0) key = GLFW_KEY_7; + else if (strcmp(name, "AE08") == 0) key = GLFW_KEY_8; + else if (strcmp(name, "AE09") == 0) key = GLFW_KEY_9; + else if (strcmp(name, "AE10") == 0) key = GLFW_KEY_0; + else if (strcmp(name, "AE11") == 0) key = GLFW_KEY_MINUS; + else if (strcmp(name, "AE12") == 0) key = GLFW_KEY_EQUAL; + else if (strcmp(name, "AD01") == 0) key = GLFW_KEY_Q; + else if (strcmp(name, "AD02") == 0) key = GLFW_KEY_W; + else if (strcmp(name, "AD03") == 0) key = GLFW_KEY_E; + else if (strcmp(name, "AD04") == 0) key = GLFW_KEY_R; + else if (strcmp(name, "AD05") == 0) key = GLFW_KEY_T; + else if (strcmp(name, "AD06") == 0) key = GLFW_KEY_Y; + else if (strcmp(name, "AD07") == 0) key = GLFW_KEY_U; + else if (strcmp(name, "AD08") == 0) key = GLFW_KEY_I; + else if (strcmp(name, "AD09") == 0) key = GLFW_KEY_O; + else if (strcmp(name, "AD10") == 0) key = GLFW_KEY_P; + else if (strcmp(name, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET; + else if (strcmp(name, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET; + else if (strcmp(name, "AC01") == 0) key = GLFW_KEY_A; + else if (strcmp(name, "AC02") == 0) key = GLFW_KEY_S; + else if (strcmp(name, "AC03") == 0) key = GLFW_KEY_D; + else if (strcmp(name, "AC04") == 0) key = GLFW_KEY_F; + else if (strcmp(name, "AC05") == 0) key = GLFW_KEY_G; + else if (strcmp(name, "AC06") == 0) key = GLFW_KEY_H; + else if (strcmp(name, "AC07") == 0) key = GLFW_KEY_J; + else if (strcmp(name, "AC08") == 0) key = GLFW_KEY_K; + else if (strcmp(name, "AC09") == 0) key = GLFW_KEY_L; + else if (strcmp(name, "AC10") == 0) key = GLFW_KEY_SEMICOLON; + else if (strcmp(name, "AC11") == 0) key = GLFW_KEY_APOSTROPHE; + else if (strcmp(name, "AB01") == 0) key = GLFW_KEY_Z; + else if (strcmp(name, "AB02") == 0) key = GLFW_KEY_X; + else if (strcmp(name, "AB03") == 0) key = GLFW_KEY_C; + else if (strcmp(name, "AB04") == 0) key = GLFW_KEY_V; + else if (strcmp(name, "AB05") == 0) key = GLFW_KEY_B; + else if (strcmp(name, "AB06") == 0) key = GLFW_KEY_N; + else if (strcmp(name, "AB07") == 0) key = GLFW_KEY_M; + else if (strcmp(name, "AB08") == 0) key = GLFW_KEY_COMMA; + else if (strcmp(name, "AB09") == 0) key = GLFW_KEY_PERIOD; + else if (strcmp(name, "AB10") == 0) key = GLFW_KEY_SLASH; + else if (strcmp(name, "BKSL") == 0) key = GLFW_KEY_BACKSLASH; + else if (strcmp(name, "LSGT") == 0) key = GLFW_KEY_WORLD_1; + else key = GLFW_KEY_UNKNOWN; + + if ((scancode >= 0) && (scancode < 256)) + _glfw.x11.publicKeys[scancode] = key; + } + + XkbFreeNames(desc, XkbKeyNamesMask, True); + XkbFreeKeyboard(desc, 0, True); + } + + for (scancode = 0; scancode < 256; scancode++) + { + // Translate the un-translated key codes using traditional X11 KeySym + // lookups + if (_glfw.x11.publicKeys[scancode] < 0) + _glfw.x11.publicKeys[scancode] = translateKeyCode(scancode); + + // Store the reverse translation for faster key name lookup + if (_glfw.x11.publicKeys[scancode] > 0) + _glfw.x11.nativeKeys[_glfw.x11.publicKeys[scancode]] = scancode; + } +} + +// Check whether the IM has a usable style +// +static GLFWbool hasUsableInputMethodStyle(void) +{ + unsigned int i; + GLFWbool found = GLFW_FALSE; + XIMStyles* styles = NULL; + + if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL) + return GLFW_FALSE; + + for (i = 0; i < styles->count_styles; i++) + { + if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) + { + found = GLFW_TRUE; + break; + } + } + + XFree(styles); + return found; +} + +// Check whether the specified atom is supported +// +static Atom getSupportedAtom(Atom* supportedAtoms, + unsigned long atomCount, + const char* atomName) +{ + unsigned long i; + const Atom atom = XInternAtom(_glfw.x11.display, atomName, False); + + for (i = 0; i < atomCount; i++) + { + if (supportedAtoms[i] == atom) + return atom; + } + + return None; +} + +// Check whether the running window manager is EWMH-compliant +// +static void detectEWMH(void) +{ + Window* windowFromRoot = NULL; + Window* windowFromChild = NULL; + + // First we need a couple of atoms + const Atom supportingWmCheck = + XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False); + const Atom wmSupported = + XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False); + + // Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window + if (_glfwGetWindowPropertyX11(_glfw.x11.root, + supportingWmCheck, + XA_WINDOW, + (unsigned char**) &windowFromRoot) != 1) + { + if (windowFromRoot) + XFree(windowFromRoot); + return; + } + + _glfwGrabErrorHandlerX11(); + + // It should be the ID of a child window (of the root) + // Then we look for the same property on the child window + if (_glfwGetWindowPropertyX11(*windowFromRoot, + supportingWmCheck, + XA_WINDOW, + (unsigned char**) &windowFromChild) != 1) + { + XFree(windowFromRoot); + if (windowFromChild) + XFree(windowFromChild); + return; + } + + _glfwReleaseErrorHandlerX11(); + + // It should be the ID of that same child window + if (*windowFromRoot != *windowFromChild) + { + XFree(windowFromRoot); + XFree(windowFromChild); + return; + } + + XFree(windowFromRoot); + XFree(windowFromChild); + + // We are now fairly sure that an EWMH-compliant window manager is running + + Atom* supportedAtoms; + unsigned long atomCount; + + // Now we need to check the _NET_SUPPORTED property of the root window + // It should be a list of supported WM protocol and state atoms + atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root, + wmSupported, + XA_ATOM, + (unsigned char**) &supportedAtoms); + + // See which of the atoms we support that are supported by the WM + _glfw.x11.NET_WM_STATE = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE"); + _glfw.x11.NET_WM_STATE_ABOVE = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); + _glfw.x11.NET_WM_STATE_FULLSCREEN = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT"); + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); + _glfw.x11.NET_WM_FULLSCREEN_MONITORS = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); + _glfw.x11.NET_WM_WINDOW_TYPE = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE"); + _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL"); + _glfw.x11.NET_ACTIVE_WINDOW = + getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); + _glfw.x11.NET_FRAME_EXTENTS = + getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); + _glfw.x11.NET_REQUEST_FRAME_EXTENTS = + getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); + + XFree(supportedAtoms); +} + +// Initialize X11 display and look for supported X11 extensions +// +static GLFWbool initExtensions(void) +{ +#if defined(_GLFW_HAS_XF86VM) + // Check for XF86VidMode extension + _glfw.x11.vidmode.available = + XF86VidModeQueryExtension(_glfw.x11.display, + &_glfw.x11.vidmode.eventBase, + &_glfw.x11.vidmode.errorBase); +#endif /*_GLFW_HAS_XF86VM*/ + + // Check for RandR extension + if (XRRQueryExtension(_glfw.x11.display, + &_glfw.x11.randr.eventBase, + &_glfw.x11.randr.errorBase)) + { + if (XRRQueryVersion(_glfw.x11.display, + &_glfw.x11.randr.major, + &_glfw.x11.randr.minor)) + { + // The GLFW RandR path requires at least version 1.3 + if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3) + _glfw.x11.randr.available = GLFW_TRUE; + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to query RandR version"); + } + } + + if (_glfw.x11.randr.available) + { + XRRScreenResources* sr = XRRGetScreenResources(_glfw.x11.display, + _glfw.x11.root); + + if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0])) + { + // This is either a headless system or an older Nvidia binary driver + // with broken gamma support + // Flag it as useless and fall back to Xf86VidMode gamma, if + // available + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: RandR gamma ramp support seems broken"); + _glfw.x11.randr.gammaBroken = GLFW_TRUE; + } + + XRRFreeScreenResources(sr); + + XRRSelectInput(_glfw.x11.display, _glfw.x11.root, + RROutputChangeNotifyMask); + } + + if (XineramaQueryExtension(_glfw.x11.display, + &_glfw.x11.xinerama.major, + &_glfw.x11.xinerama.minor)) + { + if (XineramaIsActive(_glfw.x11.display)) + _glfw.x11.xinerama.available = GLFW_TRUE; + } + + // Check if Xkb is supported on this display + _glfw.x11.xkb.major = 1; + _glfw.x11.xkb.minor = 0; + _glfw.x11.xkb.available = + XkbQueryExtension(_glfw.x11.display, + &_glfw.x11.xkb.majorOpcode, + &_glfw.x11.xkb.eventBase, + &_glfw.x11.xkb.errorBase, + &_glfw.x11.xkb.major, + &_glfw.x11.xkb.minor); + + if (_glfw.x11.xkb.available) + { + Bool supported; + + if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) + { + if (supported) + _glfw.x11.xkb.detectable = GLFW_TRUE; + } + } + + _glfw.x11.x11xcb.handle = dlopen("libX11-xcb.so", RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.x11.x11xcb.handle) + { + _glfw.x11.x11xcb.XGetXCBConnection = (XGETXCBCONNECTION_T) + dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); + } + + // Update the key code LUT + // FIXME: We should listen to XkbMapNotify events to track changes to + // the keyboard mapping. + createKeyTables(); + + // Detect whether an EWMH-conformant window manager is running + detectEWMH(); + + // String format atoms + _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False); + _glfw.x11.UTF8_STRING = + XInternAtom(_glfw.x11.display, "UTF8_STRING", False); + _glfw.x11.COMPOUND_STRING = + XInternAtom(_glfw.x11.display, "COMPOUND_STRING", False); + _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False); + + // Custom selection property atom + _glfw.x11.GLFW_SELECTION = + XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False); + + // ICCCM standard clipboard atoms + _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False); + _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False); + _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False); + + // Clipboard manager atoms + _glfw.x11.CLIPBOARD_MANAGER = + XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False); + _glfw.x11.SAVE_TARGETS = + XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False); + + // Xdnd (drag and drop) atoms + _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False); + _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False); + _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False); + _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False); + _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False); + _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False); + _glfw.x11.XdndLeave = XInternAtom(_glfw.x11.display, "XdndLeave", False); + _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False); + _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False); + + // ICCCM, EWMH and Motif window property atoms + // These can be set safely even without WM support + // The EWMH atoms that require WM support are handled in detectEWMH + _glfw.x11.WM_PROTOCOLS = + XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False); + _glfw.x11.WM_STATE = + XInternAtom(_glfw.x11.display, "WM_STATE", False); + _glfw.x11.WM_DELETE_WINDOW = + XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False); + _glfw.x11.NET_WM_ICON = + XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False); + _glfw.x11.NET_WM_PING = + XInternAtom(_glfw.x11.display, "_NET_WM_PING", False); + _glfw.x11.NET_WM_PID = + XInternAtom(_glfw.x11.display, "_NET_WM_PID", False); + _glfw.x11.NET_WM_NAME = + XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False); + _glfw.x11.NET_WM_ICON_NAME = + XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False); + _glfw.x11.NET_WM_BYPASS_COMPOSITOR = + XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False); + _glfw.x11.MOTIF_WM_HINTS = + XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); + + return GLFW_TRUE; +} + +// Create a blank cursor for hidden and disabled cursor modes +// +static Cursor createHiddenCursor(void) +{ + unsigned char pixels[16 * 16 * 4]; + GLFWimage image = { 16, 16, pixels }; + + memset(pixels, 0, sizeof(pixels)); + + return _glfwCreateCursorX11(&image, 0, 0); +} + +// X error handler +// +static int errorHandler(Display *display, XErrorEvent* event) +{ + _glfw.x11.errorCode = event->error_code; + return 0; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Sets the X error handler callback +// +void _glfwGrabErrorHandlerX11(void) +{ + _glfw.x11.errorCode = Success; + XSetErrorHandler(errorHandler); +} + +// Clears the X error handler callback +// +void _glfwReleaseErrorHandlerX11(void) +{ + // Synchronize to make sure all commands are processed + XSync(_glfw.x11.display, False); + XSetErrorHandler(NULL); +} + +// Reports the specified error, appending information about the last X error +// +void _glfwInputErrorX11(int error, const char* message) +{ + char buffer[8192]; + XGetErrorText(_glfw.x11.display, _glfw.x11.errorCode, + buffer, sizeof(buffer)); + + _glfwInputError(error, "%s: %s", message, buffer); +} + +// Creates a native cursor object from the specified image and hotspot +// +Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) +{ + int i; + Cursor cursor; + + XcursorImage* native = XcursorImageCreate(image->width, image->height); + if (native == NULL) + return None; + + native->xhot = xhot; + native->yhot = yhot; + + unsigned char* source = (unsigned char*) image->pixels; + XcursorPixel* target = native->pixels; + + for (i = 0; i < image->width * image->height; i++, target++, source += 4) + { + unsigned int alpha = source[3]; + + *target = (alpha << 24) | + ((unsigned char) ((source[0] * alpha) / 255) << 16) | + ((unsigned char) ((source[1] * alpha) / 255) << 8) | + ((unsigned char) ((source[2] * alpha) / 255) << 0); + } + + cursor = XcursorImageLoadCursor(_glfw.x11.display, native); + XcursorImageDestroy(native); + + return cursor; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ +#if !defined(X_HAVE_UTF8_STRING) + // HACK: If the current locale is C, apply the environment's locale + // This is done because the C locale breaks wide character input + if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0) + setlocale(LC_CTYPE, ""); +#endif + + XInitThreads(); + + _glfw.x11.display = XOpenDisplay(NULL); + if (!_glfw.x11.display) + { + const char* display = getenv("DISPLAY"); + if (display) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to open display %s", display); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: The DISPLAY environment variable is missing"); + } + + return GLFW_FALSE; + } + + _glfw.x11.screen = DefaultScreen(_glfw.x11.display); + _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen); + _glfw.x11.context = XUniqueContext(); + + if (!initExtensions()) + return GLFW_FALSE; + + _glfw.x11.cursor = createHiddenCursor(); + + if (XSupportsLocale()) + { + XSetLocaleModifiers(""); + + _glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL); + if (_glfw.x11.im) + { + if (!hasUsableInputMethodStyle()) + { + XCloseIM(_glfw.x11.im); + _glfw.x11.im = NULL; + } + } + } + + if (!_glfwInitThreadLocalStoragePOSIX()) + return GLFW_FALSE; + + if (!_glfwInitJoysticksLinux()) + return GLFW_FALSE; + + _glfwInitTimerPOSIX(); + + return GLFW_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + if (_glfw.x11.x11xcb.handle) + { + dlclose(_glfw.x11.x11xcb.handle); + _glfw.x11.x11xcb.handle = NULL; + } + + if (_glfw.x11.cursor) + { + XFreeCursor(_glfw.x11.display, _glfw.x11.cursor); + _glfw.x11.cursor = (Cursor) 0; + } + + free(_glfw.x11.clipboardString); + + if (_glfw.x11.im) + { + XCloseIM(_glfw.x11.im); + _glfw.x11.im = NULL; + } + + _glfwTerminateEGL(); + + if (_glfw.x11.display) + { + XCloseDisplay(_glfw.x11.display); + _glfw.x11.display = NULL; + } + + // NOTE: This needs to be done after XCloseDisplay, as libGL registers + // cleanup callbacks that get called by it + _glfwTerminateGLX(); + + _glfwTerminateJoysticksLinux(); + _glfwTerminateThreadLocalStoragePOSIX(); +} + +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " X11 GLX EGL" +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + " clock_gettime" +#else + " gettimeofday" +#endif +#if defined(__linux__) + " /dev/js" +#endif +#if defined(_GLFW_HAS_XF86VM) + " Xf86vm" +#endif +#if defined(_GLFW_BUILD_DLL) + " shared" +#endif + ; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/x11_monitor.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/x11_monitor.c new file mode 100644 index 00000000..2cec7918 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/x11_monitor.c @@ -0,0 +1,491 @@ +//======================================================================== +// GLFW 3.2 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + + +// Check whether the display mode should be included in enumeration +// +static GLFWbool modeIsGood(const XRRModeInfo* mi) +{ + return (mi->modeFlags & RR_Interlace) == 0; +} + +// Calculates the refresh rate, in Hz, from the specified RandR mode info +// +static int calculateRefreshRate(const XRRModeInfo* mi) +{ + if (mi->hTotal && mi->vTotal) + return (int) ((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal)); + else + return 0; +} + +// Returns the mode info for a RandR mode XID +// +static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id) +{ + int i; + + for (i = 0; i < sr->nmode; i++) + { + if (sr->modes[i].id == id) + return sr->modes + i; + } + + return NULL; +} + +// Convert RandR mode info to GLFW video mode +// +static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi, + const XRRCrtcInfo* ci) +{ + GLFWvidmode mode; + + if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) + { + mode.width = mi->height; + mode.height = mi->width; + } + else + { + mode.width = mi->width; + mode.height = mi->height; + } + + mode.refreshRate = calculateRefreshRate(mi); + + _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), + &mode.redBits, &mode.greenBits, &mode.blueBits); + + return mode; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Set the current video mode for the specified monitor +// +GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRScreenResources* sr; + XRRCrtcInfo* ci; + XRROutputInfo* oi; + GLFWvidmode current; + const GLFWvidmode* best; + RRMode native = None; + int i; + + best = _glfwChooseVideoMode(monitor, desired); + _glfwPlatformGetVideoMode(monitor, ¤t); + if (_glfwCompareVideoModes(¤t, best) == 0) + return GLFW_TRUE; + + sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); + + for (i = 0; i < oi->nmode; i++) + { + const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); + if (!modeIsGood(mi)) + continue; + + const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); + if (_glfwCompareVideoModes(best, &mode) == 0) + { + native = mi->id; + break; + } + } + + if (native) + { + if (monitor->x11.oldMode == None) + monitor->x11.oldMode = ci->mode; + + XRRSetCrtcConfig(_glfw.x11.display, + sr, monitor->x11.crtc, + CurrentTime, + ci->x, ci->y, + native, + ci->rotation, + ci->outputs, + ci->noutput); + } + + XRRFreeOutputInfo(oi); + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + + if (!native) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Monitor mode list changed"); + return GLFW_FALSE; + } + } + + return GLFW_TRUE; +} + +// Restore the saved (original) video mode for the specified monitor +// +void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRScreenResources* sr; + XRRCrtcInfo* ci; + + if (monitor->x11.oldMode == None) + return; + + sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + + XRRSetCrtcConfig(_glfw.x11.display, + sr, monitor->x11.crtc, + CurrentTime, + ci->x, ci->y, + monitor->x11.oldMode, + ci->rotation, + ci->outputs, + ci->noutput); + + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + + monitor->x11.oldMode = None; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwPlatformGetMonitors(int* count) +{ + int i, j, k, found = 0; + _GLFWmonitor** monitors = NULL; + + *count = 0; + + if (_glfw.x11.randr.available) + { + int screenCount = 0; + XineramaScreenInfo* screens = NULL; + XRRScreenResources* sr = XRRGetScreenResources(_glfw.x11.display, + _glfw.x11.root); + RROutput primary = XRRGetOutputPrimary(_glfw.x11.display, + _glfw.x11.root); + + monitors = calloc(sr->noutput, sizeof(_GLFWmonitor*)); + + if (_glfw.x11.xinerama.available) + screens = XineramaQueryScreens(_glfw.x11.display, &screenCount); + + for (i = 0; i < sr->ncrtc; i++) + { + XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, + sr, sr->crtcs[i]); + + for (j = 0; j < ci->noutput; j++) + { + int widthMM, heightMM; + _GLFWmonitor* monitor; + XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, + sr, ci->outputs[j]); + if (oi->connection != RR_Connected) + { + XRRFreeOutputInfo(oi); + continue; + } + + if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) + { + widthMM = oi->mm_height; + heightMM = oi->mm_width; + } + else + { + widthMM = oi->mm_width; + heightMM = oi->mm_height; + } + + monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM); + monitor->x11.output = ci->outputs[j]; + monitor->x11.crtc = oi->crtc; + + for (k = 0; k < screenCount; k++) + { + if (screens[k].x_org == ci->x && + screens[k].y_org == ci->y && + screens[k].width == ci->width && + screens[k].height == ci->height) + { + monitor->x11.index = k; + break; + } + } + + XRRFreeOutputInfo(oi); + + found++; + monitors[found - 1] = monitor; + + if (ci->outputs[j] == primary) + _GLFW_SWAP_POINTERS(monitors[0], monitors[found - 1]); + } + + XRRFreeCrtcInfo(ci); + } + + XRRFreeScreenResources(sr); + + if (screens) + XFree(screens); + + if (found == 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: RandR monitor support seems broken"); + + _glfw.x11.randr.monitorBroken = GLFW_TRUE; + free(monitors); + monitors = NULL; + } + } + + if (!monitors) + { + monitors = calloc(1, sizeof(_GLFWmonitor*)); + monitors[0] = _glfwAllocMonitor("Display", + DisplayWidthMM(_glfw.x11.display, + _glfw.x11.screen), + DisplayHeightMM(_glfw.x11.display, + _glfw.x11.screen)); + found = 1; + } + + *count = found; + return monitors; +} + +GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) +{ + return first->x11.crtc == second->x11.crtc; +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRScreenResources* sr; + XRRCrtcInfo* ci; + + sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + + if (xpos) + *xpos = ci->x; + if (ypos) + *ypos = ci->y; + + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + } +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) +{ + GLFWvidmode* result; + + *count = 0; + + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + int i, j; + XRRScreenResources* sr; + XRRCrtcInfo* ci; + XRROutputInfo* oi; + + sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); + + result = calloc(oi->nmode, sizeof(GLFWvidmode)); + + for (i = 0; i < oi->nmode; i++) + { + const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); + if (!modeIsGood(mi)) + continue; + + const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); + + for (j = 0; j < *count; j++) + { + if (_glfwCompareVideoModes(result + j, &mode) == 0) + break; + } + + // Skip duplicate modes + if (j < *count) + continue; + + (*count)++; + result[*count - 1] = mode; + } + + XRRFreeOutputInfo(oi); + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + } + else + { + *count = 1; + result = calloc(1, sizeof(GLFWvidmode)); + _glfwPlatformGetVideoMode(monitor, result); + } + + return result; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRScreenResources* sr; + XRRCrtcInfo* ci; + + sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + + *mode = vidmodeFromModeInfo(getModeInfo(sr, ci->mode), ci); + + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + } + else + { + mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); + mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); + mode->refreshRate = 0; + + _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), + &mode->redBits, &mode->greenBits, &mode->blueBits); + } +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) + { + const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display, + monitor->x11.crtc); + XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display, + monitor->x11.crtc); + + _glfwAllocGammaArrays(ramp, size); + + memcpy(ramp->red, gamma->red, size * sizeof(unsigned short)); + memcpy(ramp->green, gamma->green, size * sizeof(unsigned short)); + memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short)); + + XRRFreeGamma(gamma); + } +#if defined(_GLFW_HAS_XF86VM) + else if (_glfw.x11.vidmode.available) + { + int size; + XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size); + + _glfwAllocGammaArrays(ramp, size); + + XF86VidModeGetGammaRamp(_glfw.x11.display, + _glfw.x11.screen, + ramp->size, ramp->red, ramp->green, ramp->blue); + } +#endif /*_GLFW_HAS_XF86VM*/ +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) + { + XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size); + + memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short)); + memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short)); + memcpy(gamma->blue, ramp->blue, ramp->size * sizeof(unsigned short)); + + XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma); + XRRFreeGamma(gamma); + } +#if defined(_GLFW_HAS_XF86VM) + else if (_glfw.x11.vidmode.available) + { + XF86VidModeSetGammaRamp(_glfw.x11.display, + _glfw.x11.screen, + ramp->size, + (unsigned short*) ramp->red, + (unsigned short*) ramp->green, + (unsigned short*) ramp->blue); + } +#endif /*_GLFW_HAS_XF86VM*/ +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(None); + return monitor->x11.crtc; +} + +GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(None); + return monitor->x11.output; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/x11_platform.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/x11_platform.h new file mode 100644 index 00000000..33043069 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/x11_platform.h @@ -0,0 +1,296 @@ +//======================================================================== +// GLFW 3.2 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_x11_platform_h_ +#define _glfw3_x11_platform_h_ + +#include +#include +#include +#include + +#include +#include +#include +#include + +// The XRandR extension provides mode setting and gamma control +#include + +// The Xkb extension provides improved keyboard support +#include + +// The Xinerama extension provides legacy monitor indices +#include + +#if defined(_GLFW_HAS_XF86VM) + // The Xf86VidMode extension provides fallback gamma control + #include +#endif + +typedef XID xcb_window_t; +typedef XID xcb_visualid_t; +typedef struct xcb_connection_t xcb_connection_t; +typedef xcb_connection_t* (* XGETXCBCONNECTION_T)(Display*); + +typedef VkFlags VkXlibSurfaceCreateFlagsKHR; +typedef VkFlags VkXcbSurfaceCreateFlagsKHR; + +typedef struct VkXlibSurfaceCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display* dpy; + Window window; +} VkXlibSurfaceCreateInfoKHR; + +typedef struct VkXcbSurfaceCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t* connection; + xcb_window_t window; +} VkXcbSurfaceCreateInfoKHR; + +typedef VkResult (APIENTRY *PFN_vkCreateXlibSurfaceKHR)(VkInstance,const VkXlibSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); +typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice,uint32_t,Display*,VisualID); +typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); +typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t); + +#include "posix_tls.h" +#include "posix_time.h" +#include "linux_joystick.h" +#include "xkb_unicode.h" +#include "glx_context.h" +#include "egl_context.h" + +#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) +#define _glfw_dlclose(handle) dlclose(handle) +#define _glfw_dlsym(handle, name) dlsym(handle, name) + +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->x11.handle) +#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display) + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11 +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11 +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorX11 x11 + + +// X11-specific per-window data +// +typedef struct _GLFWwindowX11 +{ + Colormap colormap; + Window handle; + XIC ic; + + GLFWbool overrideRedirect; + + // Cached position and size used to filter out duplicate events + int width, height; + int xpos, ypos; + + // The last received cursor position, regardless of source + int lastCursorPosX, lastCursorPosY; + // The last position the cursor was warped to by GLFW + int warpCursorPosX, warpCursorPosY; + + // The information from the last KeyPress event + unsigned int lastKeyCode; + Time lastKeyTime; + +} _GLFWwindowX11; + +// X11-specific global data +// +typedef struct _GLFWlibraryX11 +{ + Display* display; + int screen; + Window root; + + // Invisible cursor for hidden cursor mode + Cursor cursor; + // Context for mapping window XIDs to _GLFWwindow pointers + XContext context; + // XIM input method + XIM im; + // Most recent error code received by X error handler + int errorCode; + // Clipboard string (while the selection is owned) + char* clipboardString; + // Key name string + char keyName[64]; + // X11 keycode to GLFW key LUT + short int publicKeys[256]; + // GLFW key to X11 keycode LUT + short int nativeKeys[GLFW_KEY_LAST + 1]; + // Where to place the cursor when re-enabled + double restoreCursorPosX, restoreCursorPosY; + // The window whose disabled cursor mode is active + _GLFWwindow* disabledCursorWindow; + + // Window manager atoms + Atom WM_PROTOCOLS; + Atom WM_STATE; + Atom WM_DELETE_WINDOW; + Atom NET_WM_NAME; + Atom NET_WM_ICON_NAME; + Atom NET_WM_ICON; + Atom NET_WM_PID; + Atom NET_WM_PING; + Atom NET_WM_WINDOW_TYPE; + Atom NET_WM_WINDOW_TYPE_NORMAL; + Atom NET_WM_STATE; + Atom NET_WM_STATE_ABOVE; + Atom NET_WM_STATE_FULLSCREEN; + Atom NET_WM_STATE_MAXIMIZED_VERT; + Atom NET_WM_STATE_MAXIMIZED_HORZ; + Atom NET_WM_BYPASS_COMPOSITOR; + Atom NET_WM_FULLSCREEN_MONITORS; + Atom NET_ACTIVE_WINDOW; + Atom NET_FRAME_EXTENTS; + Atom NET_REQUEST_FRAME_EXTENTS; + Atom MOTIF_WM_HINTS; + + // Xdnd (drag and drop) atoms + Atom XdndAware; + Atom XdndEnter; + Atom XdndPosition; + Atom XdndStatus; + Atom XdndActionCopy; + Atom XdndDrop; + Atom XdndLeave; + Atom XdndFinished; + Atom XdndSelection; + + // Selection (clipboard) atoms + Atom TARGETS; + Atom MULTIPLE; + Atom CLIPBOARD; + Atom CLIPBOARD_MANAGER; + Atom SAVE_TARGETS; + Atom NULL_; + Atom UTF8_STRING; + Atom COMPOUND_STRING; + Atom ATOM_PAIR; + Atom GLFW_SELECTION; + + struct { + GLFWbool available; + int eventBase; + int errorBase; + int major; + int minor; + GLFWbool gammaBroken; + GLFWbool monitorBroken; + } randr; + + struct { + GLFWbool available; + GLFWbool detectable; + int majorOpcode; + int eventBase; + int errorBase; + int major; + int minor; + } xkb; + + struct { + int count; + int timeout; + int interval; + int blanking; + int exposure; + } saver; + + struct { + Window source; + } xdnd; + + struct { + GLFWbool available; + int major; + int minor; + } xinerama; + + struct { + void* handle; + XGETXCBCONNECTION_T XGetXCBConnection; + } x11xcb; + +#if defined(_GLFW_HAS_XF86VM) + struct { + GLFWbool available; + int eventBase; + int errorBase; + } vidmode; +#endif /*_GLFW_HAS_XF86VM*/ + +} _GLFWlibraryX11; + +// X11-specific per-monitor data +// +typedef struct _GLFWmonitorX11 +{ + RROutput output; + RRCrtc crtc; + RRMode oldMode; + + // Index of corresponding Xinerama screen, + // for EWMH full screen window placement + int index; + +} _GLFWmonitorX11; + +// X11-specific per-cursor data +// +typedef struct _GLFWcursorX11 +{ + Cursor handle; + +} _GLFWcursorX11; + + +GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired); +void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor); + +Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot); + +unsigned long _glfwGetWindowPropertyX11(Window window, + Atom property, + Atom type, + unsigned char** value); + +void _glfwGrabErrorHandlerX11(void); +void _glfwReleaseErrorHandlerX11(void); +void _glfwInputErrorX11(int error, const char* message); + +#endif // _glfw3_x11_platform_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/x11_window.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/x11_window.c new file mode 100644 index 00000000..077eebb6 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/x11_window.c @@ -0,0 +1,2475 @@ +//======================================================================== +// GLFW 3.2 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +// Action for EWMH client messages +#define _NET_WM_STATE_REMOVE 0 +#define _NET_WM_STATE_ADD 1 +#define _NET_WM_STATE_TOGGLE 2 + +// Additional mouse button names for XButtonEvent +#define Button6 6 +#define Button7 7 + + +// Wait for data to arrive using select +// This avoids blocking other threads via the per-display Xlib lock that also +// covers GLX functions +// +static GLFWbool waitForEvent(double* timeout) +{ + fd_set fds; + const int fd = ConnectionNumber(_glfw.x11.display); + int count = fd + 1; + + FD_ZERO(&fds); + FD_SET(fd, &fds); +#if defined(__linux__) + FD_SET(_glfw.linux_js.inotify, &fds); + + if (fd < _glfw.linux_js.inotify) + count = _glfw.linux_js.inotify + 1; +#endif + for (;;) + { + if (timeout) + { + const long seconds = (long) *timeout; + const long microseconds = (long) ((*timeout - seconds) * 1e6); + struct timeval tv = { seconds, microseconds }; + const uint64_t base = _glfwPlatformGetTimerValue(); + + const int result = select(count, &fds, NULL, NULL, &tv); + const int error = errno; + + *timeout -= (_glfwPlatformGetTimerValue() - base) / + (double) _glfwPlatformGetTimerFrequency(); + + if (result > 0) + return GLFW_TRUE; + if ((result == -1 && error == EINTR) || *timeout <= 0.0) + return GLFW_FALSE; + } + else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR) + return GLFW_TRUE; + } +} + +// Waits until a VisibilityNotify event arrives for the specified window or the +// timeout period elapses (ICCCM section 4.2.2) +// +static GLFWbool waitForVisibilityNotify(_GLFWwindow* window) +{ + XEvent dummy; + double timeout = 0.1; + + while (!XCheckTypedWindowEvent(_glfw.x11.display, + window->x11.handle, + VisibilityNotify, + &dummy)) + { + if (!waitForEvent(&timeout)) + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +// Returns whether the window is iconified +// +static int getWindowState(_GLFWwindow* window) +{ + int result = WithdrawnState; + struct { + CARD32 state; + Window icon; + } *state = NULL; + + if (_glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.WM_STATE, + _glfw.x11.WM_STATE, + (unsigned char**) &state) >= 2) + { + result = state->state; + } + + XFree(state); + return result; +} + +// Returns whether the event is a selection event +// +static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer) +{ + return event->type == SelectionRequest || + event->type == SelectionNotify || + event->type == SelectionClear; +} + +// Returns whether it is a _NET_FRAME_EXTENTS event for the specified window +// +static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointer) +{ + _GLFWwindow* window = (_GLFWwindow*) pointer; + return event->type == PropertyNotify && + event->xproperty.state == PropertyNewValue && + event->xproperty.window == window->x11.handle && + event->xproperty.atom == _glfw.x11.NET_FRAME_EXTENTS; +} + +// Translates a GLFW standard cursor to a font cursor shape +// +static int translateCursorShape(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return XC_left_ptr; + case GLFW_IBEAM_CURSOR: + return XC_xterm; + case GLFW_CROSSHAIR_CURSOR: + return XC_crosshair; + case GLFW_HAND_CURSOR: + return XC_hand1; + case GLFW_HRESIZE_CURSOR: + return XC_sb_h_double_arrow; + case GLFW_VRESIZE_CURSOR: + return XC_sb_v_double_arrow; + } + + return 0; +} + +// Translates an X event modifier state mask +// +static int translateState(int state) +{ + int mods = 0; + + if (state & ShiftMask) + mods |= GLFW_MOD_SHIFT; + if (state & ControlMask) + mods |= GLFW_MOD_CONTROL; + if (state & Mod1Mask) + mods |= GLFW_MOD_ALT; + if (state & Mod4Mask) + mods |= GLFW_MOD_SUPER; + + return mods; +} + +// Translates an X11 key code to a GLFW key token +// +static int translateKey(int scancode) +{ + // Use the pre-filled LUT (see createKeyTables() in x11_init.c) + if (scancode < 0 || scancode > 255) + return GLFW_KEY_UNKNOWN; + + return _glfw.x11.publicKeys[scancode]; +} + +// Return the GLFW window corresponding to the specified X11 window +// +static _GLFWwindow* findWindowByHandle(Window handle) +{ + _GLFWwindow* window; + + if (XFindContext(_glfw.x11.display, + handle, + _glfw.x11.context, + (XPointer*) &window) != 0) + { + return NULL; + } + + return window; +} + +// Sends an EWMH or ICCCM event to the window manager +// +static void sendEventToWM(_GLFWwindow* window, Atom type, + long a, long b, long c, long d, long e) +{ + XEvent event; + memset(&event, 0, sizeof(event)); + + event.type = ClientMessage; + event.xclient.window = window->x11.handle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = type; + event.xclient.data.l[0] = a; + event.xclient.data.l[1] = b; + event.xclient.data.l[2] = c; + event.xclient.data.l[3] = d; + event.xclient.data.l[4] = e; + + XSendEvent(_glfw.x11.display, _glfw.x11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); +} + +// Updates the normal hints according to the window settings +// +static void updateNormalHints(_GLFWwindow* window, int width, int height) +{ + XSizeHints* hints = XAllocSizeHints(); + + if (!window->monitor) + { + if (window->resizable) + { + if (window->minwidth != GLFW_DONT_CARE && + window->minheight != GLFW_DONT_CARE) + { + hints->flags |= PMinSize; + hints->min_width = window->minwidth; + hints->min_height = window->minheight; + } + + if (window->maxwidth != GLFW_DONT_CARE && + window->maxheight != GLFW_DONT_CARE) + { + hints->flags |= PMaxSize; + hints->max_width = window->maxwidth; + hints->max_height = window->maxheight; + } + + if (window->numer != GLFW_DONT_CARE && + window->denom != GLFW_DONT_CARE) + { + hints->flags |= PAspect; + hints->min_aspect.x = hints->max_aspect.x = window->numer; + hints->min_aspect.y = hints->max_aspect.y = window->denom; + } + } + else + { + hints->flags |= (PMinSize | PMaxSize); + hints->min_width = hints->max_width = width; + hints->min_height = hints->max_height = height; + } + } + + hints->flags |= PWinGravity; + hints->win_gravity = StaticGravity; + + XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); + XFree(hints); +} + +// Updates the full screen status of the window +// +static void updateWindowMode(_GLFWwindow* window) +{ + if (window->monitor) + { + if (_glfw.x11.xinerama.available && + _glfw.x11.NET_WM_FULLSCREEN_MONITORS) + { + sendEventToWM(window, + _glfw.x11.NET_WM_FULLSCREEN_MONITORS, + window->monitor->x11.index, + window->monitor->x11.index, + window->monitor->x11.index, + window->monitor->x11.index, + 0); + } + + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + _glfw.x11.NET_WM_STATE_FULLSCREEN, + 0, 1, 0); + } + else + { + // This is the butcher's way of removing window decorations + // Setting the override-redirect attribute on a window makes the + // window manager ignore the window completely (ICCCM, section 4) + // The good thing is that this makes undecorated full screen windows + // easy to do; the bad thing is that we have to do everything + // manually and some things (like iconify/restore) won't work at + // all, as those are tasks usually performed by the window manager + + XSetWindowAttributes attributes; + attributes.override_redirect = True; + XChangeWindowAttributes(_glfw.x11.display, + window->x11.handle, + CWOverrideRedirect, + &attributes); + + window->x11.overrideRedirect = GLFW_TRUE; + } + + // Enable compositor bypass + { + const unsigned long value = 1; + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*) &value, 1); + } + } + else + { + if (_glfw.x11.xinerama.available && + _glfw.x11.NET_WM_FULLSCREEN_MONITORS) + { + XDeleteProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_FULLSCREEN_MONITORS); + } + + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_REMOVE, + _glfw.x11.NET_WM_STATE_FULLSCREEN, + 0, 1, 0); + } + else + { + XSetWindowAttributes attributes; + attributes.override_redirect = False; + XChangeWindowAttributes(_glfw.x11.display, + window->x11.handle, + CWOverrideRedirect, + &attributes); + + window->x11.overrideRedirect = GLFW_FALSE; + } + + // Disable compositor bypass + { + XDeleteProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_BYPASS_COMPOSITOR); + } + } +} + +// Splits and translates a text/uri-list into separate file paths +// NOTE: This function destroys the provided string +// +static char** parseUriList(char* text, int* count) +{ + const char* prefix = "file://"; + char** paths = NULL; + char* line; + + *count = 0; + + while ((line = strtok(text, "\r\n"))) + { + text = NULL; + + if (line[0] == '#') + continue; + + if (strncmp(line, prefix, strlen(prefix)) == 0) + line += strlen(prefix); + + (*count)++; + + char* path = calloc(strlen(line) + 1, 1); + paths = realloc(paths, *count * sizeof(char*)); + paths[*count - 1] = path; + + while (*line) + { + if (line[0] == '%' && line[1] && line[2]) + { + const char digits[3] = { line[1], line[2], '\0' }; + *path = strtol(digits, NULL, 16); + line += 2; + } + else + *path = *line; + + path++; + line++; + } + } + + return paths; +} + +// Centers the cursor over the window client area +// +static void centerCursor(_GLFWwindow* window) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); +} + +// Updates the cursor image according to its cursor mode +// +static void updateCursorImage(_GLFWwindow* window) +{ + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + if (window->cursor) + { + XDefineCursor(_glfw.x11.display, window->x11.handle, + window->cursor->x11.handle); + } + else + XUndefineCursor(_glfw.x11.display, window->x11.handle); + } + else + XDefineCursor(_glfw.x11.display, window->x11.handle, _glfw.x11.cursor); +} + +// Create the X11 window (and its colormap) +// +static GLFWbool createNativeWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + Visual* visual, int depth) +{ + // Create a colormap based on the visual used by the current context + window->x11.colormap = XCreateColormap(_glfw.x11.display, + _glfw.x11.root, + visual, + AllocNone); + + // Create the actual window + { + XSetWindowAttributes wa; + const unsigned long wamask = CWBorderPixel | CWColormap | CWEventMask; + + wa.colormap = window->x11.colormap; + wa.border_pixel = 0; + wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask | + ExposureMask | FocusChangeMask | VisibilityChangeMask | + EnterWindowMask | LeaveWindowMask | PropertyChangeMask; + + _glfwGrabErrorHandlerX11(); + + window->x11.handle = XCreateWindow(_glfw.x11.display, + _glfw.x11.root, + 0, 0, + wndconfig->width, wndconfig->height, + 0, // Border width + depth, // Color depth + InputOutput, + visual, + wamask, + &wa); + + _glfwReleaseErrorHandlerX11(); + + if (!window->x11.handle) + { + _glfwInputErrorX11(GLFW_PLATFORM_ERROR, + "X11: Failed to create window"); + return GLFW_FALSE; + } + + XSaveContext(_glfw.x11.display, + window->x11.handle, + _glfw.x11.context, + (XPointer) window); + } + + if (!wndconfig->decorated) + { + struct + { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; + } hints; + + hints.flags = 2; // Set decorations + hints.decorations = 0; // No decorations + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.MOTIF_WM_HINTS, + _glfw.x11.MOTIF_WM_HINTS, 32, + PropModeReplace, + (unsigned char*) &hints, + sizeof(hints) / sizeof(long)); + } + + if (_glfw.x11.NET_WM_STATE && !window->monitor) + { + Atom states[3]; + int count = 0; + + if (wndconfig->floating) + { + if (_glfw.x11.NET_WM_STATE_ABOVE) + states[count++] = _glfw.x11.NET_WM_STATE_ABOVE; + } + + if (wndconfig->maximized) + { + if (_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT; + states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ; + } + } + + if (count) + { + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &states, count); + } + } + + // Declare the WM protocols supported by GLFW + { + Atom protocols[] = + { + _glfw.x11.WM_DELETE_WINDOW, + _glfw.x11.NET_WM_PING + }; + + XSetWMProtocols(_glfw.x11.display, window->x11.handle, + protocols, sizeof(protocols) / sizeof(Atom)); + } + + // Declare our PID + { + const pid_t pid = getpid(); + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_PID, XA_CARDINAL, 32, + PropModeReplace, + (unsigned char*) &pid, 1); + } + + if (_glfw.x11.NET_WM_WINDOW_TYPE && _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL) + { + Atom type = _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL; + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_WINDOW_TYPE, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &type, 1); + } + + // Set ICCCM WM_HINTS property + { + XWMHints* hints = XAllocWMHints(); + if (!hints) + { + _glfwInputError(GLFW_OUT_OF_MEMORY, + "X11: Failed to allocate WM hints"); + return GLFW_FALSE; + } + + hints->flags = StateHint; + hints->initial_state = NormalState; + + XSetWMHints(_glfw.x11.display, window->x11.handle, hints); + XFree(hints); + } + + updateNormalHints(window, wndconfig->width, wndconfig->height); + + // Set ICCCM WM_CLASS property + // HACK: Until a mechanism for specifying the application name is added, the + // initial window title is used as the window class name + if (strlen(wndconfig->title)) + { + XClassHint* hint = XAllocClassHint(); + hint->res_name = (char*) wndconfig->title; + hint->res_class = (char*) wndconfig->title; + + XSetClassHint(_glfw.x11.display, window->x11.handle, hint); + XFree(hint); + } + + if (_glfw.x11.XdndAware) + { + // Announce support for Xdnd (drag and drop) + const Atom version = 5; + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.XdndAware, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &version, 1); + } + + _glfwPlatformSetWindowTitle(window, wndconfig->title); + + if (_glfw.x11.im) + { + window->x11.ic = XCreateIC(_glfw.x11.im, + XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, + window->x11.handle, + XNFocusWindow, + window->x11.handle, + NULL); + } + + _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos); + _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height); + + return GLFW_TRUE; +} + +// Set the specified property to the selection converted to the requested target +// +static Atom writeTargetToProperty(const XSelectionRequestEvent* request) +{ + int i; + const Atom formats[] = { _glfw.x11.UTF8_STRING, + _glfw.x11.COMPOUND_STRING, + XA_STRING }; + const int formatCount = sizeof(formats) / sizeof(formats[0]); + + if (request->property == None) + { + // The requester is a legacy client (ICCCM section 2.2) + // We don't support legacy clients, so fail here + return None; + } + + if (request->target == _glfw.x11.TARGETS) + { + // The list of supported targets was requested + + const Atom targets[] = { _glfw.x11.TARGETS, + _glfw.x11.MULTIPLE, + _glfw.x11.UTF8_STRING, + _glfw.x11.COMPOUND_STRING, + XA_STRING }; + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + XA_ATOM, + 32, + PropModeReplace, + (unsigned char*) targets, + sizeof(targets) / sizeof(targets[0])); + + return request->property; + } + + if (request->target == _glfw.x11.MULTIPLE) + { + // Multiple conversions were requested + + Atom* targets; + unsigned long i, count; + + count = _glfwGetWindowPropertyX11(request->requestor, + request->property, + _glfw.x11.ATOM_PAIR, + (unsigned char**) &targets); + + for (i = 0; i < count; i += 2) + { + int j; + + for (j = 0; j < formatCount; j++) + { + if (targets[i] == formats[j]) + break; + } + + if (j < formatCount) + { + XChangeProperty(_glfw.x11.display, + request->requestor, + targets[i + 1], + targets[i], + 8, + PropModeReplace, + (unsigned char*) _glfw.x11.clipboardString, + strlen(_glfw.x11.clipboardString)); + } + else + targets[i + 1] = None; + } + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + _glfw.x11.ATOM_PAIR, + 32, + PropModeReplace, + (unsigned char*) targets, + count); + + XFree(targets); + + return request->property; + } + + if (request->target == _glfw.x11.SAVE_TARGETS) + { + // The request is a check whether we support SAVE_TARGETS + // It should be handled as a no-op side effect target + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + _glfw.x11.NULL_, + 32, + PropModeReplace, + NULL, + 0); + + return request->property; + } + + // Conversion to a data target was requested + + for (i = 0; i < formatCount; i++) + { + if (request->target == formats[i]) + { + // The requested target is one we support + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + request->target, + 8, + PropModeReplace, + (unsigned char*) _glfw.x11.clipboardString, + strlen(_glfw.x11.clipboardString)); + + return request->property; + } + } + + // The requested target is not supported + + return None; +} + +static void handleSelectionClear(XEvent* event) +{ + free(_glfw.x11.clipboardString); + _glfw.x11.clipboardString = NULL; +} + +static void handleSelectionRequest(XEvent* event) +{ + const XSelectionRequestEvent* request = &event->xselectionrequest; + + XEvent reply; + memset(&reply, 0, sizeof(reply)); + + reply.xselection.property = writeTargetToProperty(request); + reply.xselection.type = SelectionNotify; + reply.xselection.display = request->display; + reply.xselection.requestor = request->requestor; + reply.xselection.selection = request->selection; + reply.xselection.target = request->target; + reply.xselection.time = request->time; + + XSendEvent(_glfw.x11.display, request->requestor, False, 0, &reply); +} + +static void pushSelectionToManager(_GLFWwindow* window) +{ + XConvertSelection(_glfw.x11.display, + _glfw.x11.CLIPBOARD_MANAGER, + _glfw.x11.SAVE_TARGETS, + None, + window->x11.handle, + CurrentTime); + + for (;;) + { + XEvent event; + + while (XCheckIfEvent(_glfw.x11.display, &event, isSelectionEvent, NULL)) + { + switch (event.type) + { + case SelectionRequest: + handleSelectionRequest(&event); + break; + + case SelectionClear: + handleSelectionClear(&event); + break; + + case SelectionNotify: + { + if (event.xselection.target == _glfw.x11.SAVE_TARGETS) + { + // This means one of two things; either the selection was + // not owned, which means there is no clipboard manager, or + // the transfer to the clipboard manager has completed + // In either case, it means we are done here + return; + } + + break; + } + } + } + + waitForEvent(NULL); + } +} + +// Make the specified window and its video mode active on its monitor +// +static GLFWbool acquireMonitor(_GLFWwindow* window) +{ + GLFWbool status; + + if (_glfw.x11.saver.count == 0) + { + // Remember old screen saver settings + XGetScreenSaver(_glfw.x11.display, + &_glfw.x11.saver.timeout, + &_glfw.x11.saver.interval, + &_glfw.x11.saver.blanking, + &_glfw.x11.saver.exposure); + + // Disable screen saver + XSetScreenSaver(_glfw.x11.display, 0, 0, DontPreferBlanking, + DefaultExposures); + } + + if (!window->monitor->window) + _glfw.x11.saver.count++; + + status = _glfwSetVideoModeX11(window->monitor, &window->videoMode); + + if (window->x11.overrideRedirect) + { + int xpos, ypos; + GLFWvidmode mode; + + // Manually position the window over its monitor + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + _glfwPlatformGetVideoMode(window->monitor, &mode); + + XMoveResizeWindow(_glfw.x11.display, window->x11.handle, + xpos, ypos, mode.width, mode.height); + } + + _glfwInputMonitorWindowChange(window->monitor, window); + return status; +} + +// Remove the window and restore the original video mode +// +static void releaseMonitor(_GLFWwindow* window) +{ + if (window->monitor->window != window) + return; + + _glfwInputMonitorWindowChange(window->monitor, NULL); + _glfwRestoreVideoModeX11(window->monitor); + + _glfw.x11.saver.count--; + + if (_glfw.x11.saver.count == 0) + { + // Restore old screen saver settings + XSetScreenSaver(_glfw.x11.display, + _glfw.x11.saver.timeout, + _glfw.x11.saver.interval, + _glfw.x11.saver.blanking, + _glfw.x11.saver.exposure); + } +} + +// Decode a Unicode code point from a UTF-8 stream +// Based on cutef8 by Jeff Bezanson (Public Domain) +// +#if defined(X_HAVE_UTF8_STRING) +static unsigned int decodeUTF8(const char** s) +{ + unsigned int ch = 0, count = 0; + static const unsigned int offsets[] = + { + 0x00000000u, 0x00003080u, 0x000e2080u, + 0x03c82080u, 0xfa082080u, 0x82082080u + }; + + do + { + ch = (ch << 6) + (unsigned char) **s; + (*s)++; + count++; + } while ((**s & 0xc0) == 0x80); + + assert(count <= 6); + return ch - offsets[count - 1]; +} +#endif /*X_HAVE_UTF8_STRING*/ + +// Process the specified X event +// +static void processEvent(XEvent *event) +{ + _GLFWwindow* window = NULL; + int keycode = 0; + Bool filtered = False; + + // HACK: Save scancode as some IMs clear the field in XFilterEvent + if (event->type == KeyPress || event->type == KeyRelease) + keycode = event->xkey.keycode; + + if (_glfw.x11.im) + filtered = XFilterEvent(event, None); + + if (_glfw.x11.randr.available) + { + if (event->type == _glfw.x11.randr.eventBase + RRNotify) + { + XRRUpdateConfiguration(event); + _glfwInputMonitorChange(); + return; + } + } + + if (event->type != GenericEvent) + { + window = findWindowByHandle(event->xany.window); + if (window == NULL) + { + // This is an event for a window that has already been destroyed + return; + } + } + + switch (event->type) + { + case KeyPress: + { + const int key = translateKey(keycode); + const int mods = translateState(event->xkey.state); + const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); + + if (window->x11.ic) + { + // HACK: Ignore duplicate key press events generated by ibus + // Corresponding release events are filtered out by the + // GLFW key repeat logic + if (window->x11.lastKeyCode != keycode || + window->x11.lastKeyTime != event->xkey.time) + { + if (keycode) + _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); + } + + window->x11.lastKeyCode = keycode; + window->x11.lastKeyTime = event->xkey.time; + + if (!filtered) + { + int count; + Status status; +#if defined(X_HAVE_UTF8_STRING) + char buffer[100]; + char* chars = buffer; + + count = Xutf8LookupString(window->x11.ic, + &event->xkey, + buffer, sizeof(buffer) - 1, + NULL, &status); + + if (status == XBufferOverflow) + { + chars = calloc(count + 1, 1); + count = Xutf8LookupString(window->x11.ic, + &event->xkey, + chars, count, + NULL, &status); + } + + if (status == XLookupChars || status == XLookupBoth) + { + const char* c = chars; + chars[count] = '\0'; + while (c - chars < count) + _glfwInputChar(window, decodeUTF8(&c), mods, plain); + } +#else /*X_HAVE_UTF8_STRING*/ + wchar_t buffer[16]; + wchar_t* chars = buffer; + + count = XwcLookupString(window->x11.ic, + &event->xkey, + buffer, sizeof(buffer) / sizeof(wchar_t), + NULL, &status); + + if (status == XBufferOverflow) + { + chars = calloc(count, sizeof(wchar_t)); + count = XwcLookupString(window->x11.ic, + &event->xkey, + chars, count, + NULL, &status); + } + + if (status == XLookupChars || status == XLookupBoth) + { + int i; + for (i = 0; i < count; i++) + _glfwInputChar(window, chars[i], mods, plain); + } +#endif /*X_HAVE_UTF8_STRING*/ + + if (chars != buffer) + free(chars); + } + } + else + { + KeySym keysym; + XLookupString(&event->xkey, NULL, 0, &keysym, NULL); + + _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); + + const long character = _glfwKeySym2Unicode(keysym); + if (character != -1) + _glfwInputChar(window, character, mods, plain); + } + + return; + } + + case KeyRelease: + { + const int key = translateKey(keycode); + const int mods = translateState(event->xkey.state); + + if (!_glfw.x11.xkb.detectable) + { + // HACK: Key repeat events will arrive as KeyRelease/KeyPress + // pairs with similar or identical time stamps + // The key repeat logic in _glfwInputKey expects only key + // presses to repeat, so detect and discard release events + if (XEventsQueued(_glfw.x11.display, QueuedAfterReading)) + { + XEvent next; + XPeekEvent(_glfw.x11.display, &next); + + if (next.type == KeyPress && + next.xkey.window == event->xkey.window && + next.xkey.keycode == keycode) + { + // HACK: The time of repeat events sometimes doesn't + // match that of the press event, so add an + // epsilon + // Toshiyuki Takahashi can press a button + // 16 times per second so it's fairly safe to + // assume that no human is pressing the key 50 + // times per second (value is ms) + if ((next.xkey.time - event->xkey.time) < 20) + { + // This is very likely a server-generated key repeat + // event, so ignore it + return; + } + } + } + } + + _glfwInputKey(window, key, keycode, GLFW_RELEASE, mods); + return; + } + + case ButtonPress: + { + const int mods = translateState(event->xbutton.state); + + if (event->xbutton.button == Button1) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods); + else if (event->xbutton.button == Button2) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods); + else if (event->xbutton.button == Button3) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods); + + // Modern X provides scroll events as mouse button presses + else if (event->xbutton.button == Button4) + _glfwInputScroll(window, 0.0, 1.0); + else if (event->xbutton.button == Button5) + _glfwInputScroll(window, 0.0, -1.0); + else if (event->xbutton.button == Button6) + _glfwInputScroll(window, 1.0, 0.0); + else if (event->xbutton.button == Button7) + _glfwInputScroll(window, -1.0, 0.0); + + else + { + // Additional buttons after 7 are treated as regular buttons + // We subtract 4 to fill the gap left by scroll input above + _glfwInputMouseClick(window, + event->xbutton.button - Button1 - 4, + GLFW_PRESS, + mods); + } + + return; + } + + case ButtonRelease: + { + const int mods = translateState(event->xbutton.state); + + if (event->xbutton.button == Button1) + { + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_LEFT, + GLFW_RELEASE, + mods); + } + else if (event->xbutton.button == Button2) + { + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_MIDDLE, + GLFW_RELEASE, + mods); + } + else if (event->xbutton.button == Button3) + { + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_RIGHT, + GLFW_RELEASE, + mods); + } + else if (event->xbutton.button > Button7) + { + // Additional buttons after 7 are treated as regular buttons + // We subtract 4 to fill the gap left by scroll input above + _glfwInputMouseClick(window, + event->xbutton.button - Button1 - 4, + GLFW_RELEASE, + mods); + } + + return; + } + + case EnterNotify: + { + // HACK: This is a workaround for WMs (KWM, Fluxbox) that otherwise + // ignore the defined cursor for hidden cursor mode + if (window->cursorMode == GLFW_CURSOR_HIDDEN) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_HIDDEN); + + _glfwInputCursorEnter(window, GLFW_TRUE); + return; + } + + case LeaveNotify: + { + _glfwInputCursorEnter(window, GLFW_FALSE); + return; + } + + case MotionNotify: + { + const int x = event->xmotion.x; + const int y = event->xmotion.y; + + if (x != window->x11.warpCursorPosX || y != window->x11.warpCursorPosY) + { + // The cursor was moved by something other than GLFW + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + if (_glfw.x11.disabledCursorWindow != window) + return; + + const int dx = x - window->x11.lastCursorPosX; + const int dy = y - window->x11.lastCursorPosY; + + _glfwInputCursorPos(window, + window->virtualCursorPosX + dx, + window->virtualCursorPosY + dy); + } + else + _glfwInputCursorPos(window, x, y); + } + + window->x11.lastCursorPosX = x; + window->x11.lastCursorPosY = y; + return; + } + + case ConfigureNotify: + { + if (event->xconfigure.width != window->x11.width || + event->xconfigure.height != window->x11.height) + { + _glfwInputFramebufferSize(window, + event->xconfigure.width, + event->xconfigure.height); + + _glfwInputWindowSize(window, + event->xconfigure.width, + event->xconfigure.height); + + window->x11.width = event->xconfigure.width; + window->x11.height = event->xconfigure.height; + } + + if (event->xconfigure.x != window->x11.xpos || + event->xconfigure.y != window->x11.ypos) + { + if (window->x11.overrideRedirect || event->xany.send_event) + { + _glfwInputWindowPos(window, + event->xconfigure.x, + event->xconfigure.y); + + window->x11.xpos = event->xconfigure.x; + window->x11.ypos = event->xconfigure.y; + } + } + + return; + } + + case ClientMessage: + { + // Custom client message, probably from the window manager + + if (filtered) + return; + + if (event->xclient.message_type == None) + return; + + if (event->xclient.message_type == _glfw.x11.WM_PROTOCOLS) + { + const Atom protocol = event->xclient.data.l[0]; + if (protocol == None) + return; + + if (protocol == _glfw.x11.WM_DELETE_WINDOW) + { + // The window manager was asked to close the window, for example by + // the user pressing a 'close' window decoration button + _glfwInputWindowCloseRequest(window); + } + else if (protocol == _glfw.x11.NET_WM_PING) + { + // The window manager is pinging the application to ensure it's + // still responding to events + + XEvent reply = *event; + reply.xclient.window = _glfw.x11.root; + + XSendEvent(_glfw.x11.display, _glfw.x11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &reply); + } + } + else if (event->xclient.message_type == _glfw.x11.XdndEnter) + { + // A drag operation has entered the window + // TODO: Check if UTF-8 string is supported by the source + } + else if (event->xclient.message_type == _glfw.x11.XdndDrop) + { + // The drag operation has finished dropping on + // the window, ask to convert it to a UTF-8 string + _glfw.x11.xdnd.source = event->xclient.data.l[0]; + XConvertSelection(_glfw.x11.display, + _glfw.x11.XdndSelection, + _glfw.x11.UTF8_STRING, + _glfw.x11.XdndSelection, + window->x11.handle, CurrentTime); + } + else if (event->xclient.message_type == _glfw.x11.XdndPosition) + { + // The drag operation has moved over the window + const int absX = (event->xclient.data.l[2] >> 16) & 0xFFFF; + const int absY = (event->xclient.data.l[2]) & 0xFFFF; + int x, y; + + _glfwPlatformGetWindowPos(window, &x, &y); + _glfwInputCursorPos(window, absX - x, absY - y); + + // Reply that we are ready to copy the dragged data + XEvent reply; + memset(&reply, 0, sizeof(reply)); + + reply.type = ClientMessage; + reply.xclient.window = event->xclient.data.l[0]; + reply.xclient.message_type = _glfw.x11.XdndStatus; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[1] = 1; // Always accept the dnd with no rectangle + reply.xclient.data.l[2] = 0; // Specify an empty rectangle + reply.xclient.data.l[3] = 0; + reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy; + + XSendEvent(_glfw.x11.display, event->xclient.data.l[0], + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } + + return; + } + + case SelectionNotify: + { + if (event->xselection.property) + { + // The converted data from the drag operation has arrived + char* data; + const int result = + _glfwGetWindowPropertyX11(event->xselection.requestor, + event->xselection.property, + event->xselection.target, + (unsigned char**) &data); + + if (result) + { + int i, count; + char** paths = parseUriList(data, &count); + + _glfwInputDrop(window, count, (const char**) paths); + + for (i = 0; i < count; i++) + free(paths[i]); + free(paths); + } + + XFree(data); + + XEvent reply; + memset(&reply, 0, sizeof(reply)); + + reply.type = ClientMessage; + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[1] = result; + reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy; + + // Reply that all is well + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } + + return; + } + + case FocusIn: + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + + if (event->xfocus.mode == NotifyGrab || + event->xfocus.mode == NotifyUngrab) + { + // Ignore focus events from popup indicator windows, window menu + // key chords and window dragging + return; + } + + if (window->x11.ic) + XSetICFocus(window->x11.ic); + + _glfwInputWindowFocus(window, GLFW_TRUE); + return; + } + + case FocusOut: + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); + + if (event->xfocus.mode == NotifyGrab || + event->xfocus.mode == NotifyUngrab) + { + // Ignore focus events from popup indicator windows, window menu + // key chords and window dragging + return; + } + + if (window->x11.ic) + XUnsetICFocus(window->x11.ic); + + if (window->monitor && window->autoIconify) + _glfwPlatformIconifyWindow(window); + + _glfwInputWindowFocus(window, GLFW_FALSE); + return; + } + + case Expose: + { + _glfwInputWindowDamage(window); + return; + } + + case PropertyNotify: + { + if (event->xproperty.atom == _glfw.x11.WM_STATE && + event->xproperty.state == PropertyNewValue) + { + const int state = getWindowState(window); + if (state == IconicState) + { + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowIconify(window, GLFW_TRUE); + } + else if (state == NormalState) + { + if (window->monitor) + acquireMonitor(window); + + _glfwInputWindowIconify(window, GLFW_FALSE); + } + } + + return; + } + + case SelectionClear: + { + handleSelectionClear(event); + return; + } + + case SelectionRequest: + { + handleSelectionRequest(event); + return; + } + + case DestroyNotify: + return; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Retrieve a single window property of the specified type +// Inspired by fghGetWindowProperty from freeglut +// +unsigned long _glfwGetWindowPropertyX11(Window window, + Atom property, + Atom type, + unsigned char** value) +{ + Atom actualType; + int actualFormat; + unsigned long itemCount, bytesAfter; + + XGetWindowProperty(_glfw.x11.display, + window, + property, + 0, + LONG_MAX, + False, + type, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + value); + + if (type != AnyPropertyType && actualType != type) + return 0; + + return itemCount; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + Visual* visual; + int depth; + + if (ctxconfig->client == GLFW_NO_API) + { + visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen); + depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen); + } + else + { + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwInitGLX()) + return GLFW_FALSE; + if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth)) + return GLFW_FALSE; + } + else + { + if (!_glfwInitEGL()) + return GLFW_FALSE; + if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth)) + return GLFW_FALSE; + } + } + + if (!createNativeWindow(window, wndconfig, visual, depth)) + return GLFW_FALSE; + + if (ctxconfig->client != GLFW_NO_API) + { + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwCreateContextGLX(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else + { + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + } + + if (window->monitor) + { + _glfwPlatformShowWindow(window); + updateWindowMode(window); + if (!acquireMonitor(window)) + return GLFW_FALSE; + + centerCursor(window); + } + + XFlush(_glfw.x11.display); + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (_glfw.x11.disabledCursorWindow == window) + _glfw.x11.disabledCursorWindow = NULL; + + if (window->monitor) + releaseMonitor(window); + + if (window->x11.ic) + { + XDestroyIC(window->x11.ic); + window->x11.ic = NULL; + } + + if (window->context.destroy) + window->context.destroy(window); + + if (window->x11.handle) + { + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) == + window->x11.handle) + { + pushSelectionToManager(window); + } + + XDeleteContext(_glfw.x11.display, window->x11.handle, _glfw.x11.context); + XUnmapWindow(_glfw.x11.display, window->x11.handle); + XDestroyWindow(_glfw.x11.display, window->x11.handle); + window->x11.handle = (Window) 0; + } + + if (window->x11.colormap) + { + XFreeColormap(_glfw.x11.display, window->x11.colormap); + window->x11.colormap = (Colormap) 0; + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ +#if defined(X_HAVE_UTF8_STRING) + Xutf8SetWMProperties(_glfw.x11.display, + window->x11.handle, + title, title, + NULL, 0, + NULL, NULL, NULL); +#else + // This may be a slightly better fallback than using XStoreName and + // XSetIconName, which always store their arguments using STRING + XmbSetWMProperties(_glfw.x11.display, + window->x11.handle, + title, title, + NULL, 0, + NULL, NULL, NULL); +#endif + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_NAME, _glfw.x11.UTF8_STRING, 8, + PropModeReplace, + (unsigned char*) title, strlen(title)); + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_ICON_NAME, _glfw.x11.UTF8_STRING, 8, + PropModeReplace, + (unsigned char*) title, strlen(title)); + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + if (count) + { + int i, j, longCount = 0; + + for (i = 0; i < count; i++) + longCount += 2 + images[i].width * images[i].height; + + long* icon = calloc(longCount, sizeof(long)); + long* target = icon; + + for (i = 0; i < count; i++) + { + *target++ = images[i].width; + *target++ = images[i].height; + + for (j = 0; j < images[i].width * images[i].height; j++) + { + *target++ = (images[i].pixels[j * 4 + 0] << 16) | + (images[i].pixels[j * 4 + 1] << 8) | + (images[i].pixels[j * 4 + 2] << 0) | + (images[i].pixels[j * 4 + 3] << 24); + } + } + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_ICON, + XA_CARDINAL, 32, + PropModeReplace, + (unsigned char*) icon, + longCount); + + free(icon); + } + else + { + XDeleteProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_ICON); + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + Window dummy; + int x, y; + + XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root, + 0, 0, &x, &y, &dummy); + + if (xpos) + *xpos = x; + if (ypos) + *ypos = y; +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + // HACK: Explicitly setting PPosition to any value causes some WMs, notably + // Compiz and Metacity, to honor the position of unmapped windows + if (!_glfwPlatformWindowVisible(window)) + { + long supplied; + XSizeHints* hints = XAllocSizeHints(); + + if (XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied)) + { + hints->flags |= PPosition; + hints->x = hints->y = 0; + + XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); + } + + XFree(hints); + } + + XMoveWindow(_glfw.x11.display, window->x11.handle, xpos, ypos); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + XWindowAttributes attribs; + XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &attribs); + + if (width) + *width = attribs.width; + if (height) + *height = attribs.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + if (window->monitor) + { + if (window->monitor->window == window) + acquireMonitor(window); + } + else + { + if (!window->resizable) + updateNormalHints(window, width, height); + + XResizeWindow(_glfw.x11.display, window->x11.handle, width, height); + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + updateNormalHints(window, width, height); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + updateNormalHints(window, width, height); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + _glfwPlatformGetWindowSize(window, width, height); +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + long* extents = NULL; + + if (window->monitor || !window->decorated) + return; + + if (_glfw.x11.NET_FRAME_EXTENTS == None) + return; + + if (!_glfwPlatformWindowVisible(window) && + _glfw.x11.NET_REQUEST_FRAME_EXTENTS) + { + XEvent event; + double timeout = 0.5; + + // Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to + // function before the window is mapped + sendEventToWM(window, _glfw.x11.NET_REQUEST_FRAME_EXTENTS, + 0, 0, 0, 0, 0); + + // HACK: Use a timeout because earlier versions of some window managers + // (at least Unity, Fluxbox and Xfwm) failed to send the reply + // They have been fixed but broken versions are still in the wild + // If you are affected by this and your window manager is NOT + // listed above, PLEASE report it to their and our issue trackers + while (!XCheckIfEvent(_glfw.x11.display, + &event, + isFrameExtentsEvent, + (XPointer) window)) + { + if (!waitForEvent(&timeout)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue"); + return; + } + } + } + + if (_glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.NET_FRAME_EXTENTS, + XA_CARDINAL, + (unsigned char**) &extents) == 4) + { + if (left) + *left = extents[0]; + if (top) + *top = extents[2]; + if (right) + *right = extents[1]; + if (bottom) + *bottom = extents[3]; + } + + if (extents) + XFree(extents); +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + if (window->x11.overrideRedirect) + { + // Override-redirect windows cannot be iconified or restored, as those + // tasks are performed by the window manager + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Iconification of full screen windows requires a WM that supports EWMH full screen"); + return; + } + + XIconifyWindow(_glfw.x11.display, window->x11.handle, _glfw.x11.screen); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + if (window->x11.overrideRedirect) + { + // Override-redirect windows cannot be iconified or restored, as those + // tasks are performed by the window manager + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Iconification of full screen windows requires a WM that supports EWMH full screen"); + return; + } + + if (_glfwPlatformWindowIconified(window)) + { + XMapWindow(_glfw.x11.display, window->x11.handle); + waitForVisibilityNotify(window); + } + else if (_glfwPlatformWindowVisible(window)) + { + if (_glfw.x11.NET_WM_STATE && + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_REMOVE, + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, + 1, 0); + } + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + if (_glfw.x11.NET_WM_STATE && + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, + 1, 0); + XFlush(_glfw.x11.display); + } +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + if (_glfwPlatformWindowVisible(window)) + return; + + XMapWindow(_glfw.x11.display, window->x11.handle); + waitForVisibilityNotify(window); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + XUnmapWindow(_glfw.x11.display, window->x11.handle); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + if (_glfw.x11.NET_ACTIVE_WINDOW) + sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); + else + { + XRaiseWindow(_glfw.x11.display, window->x11.handle); + XSetInputFocus(_glfw.x11.display, window->x11.handle, + RevertToParent, CurrentTime); + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (window->monitor == monitor) + { + if (monitor) + { + if (monitor->window == window) + acquireMonitor(window); + } + else + { + XMoveResizeWindow(_glfw.x11.display, window->x11.handle, + xpos, ypos, width, height); + } + + return; + } + + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowMonitorChange(window, monitor); + updateNormalHints(window, width, height); + updateWindowMode(window); + + if (window->monitor) + { + XMapRaised(_glfw.x11.display, window->x11.handle); + if (waitForVisibilityNotify(window)) + acquireMonitor(window); + } + else + { + XMoveResizeWindow(_glfw.x11.display, window->x11.handle, + xpos, ypos, width, height); + } + + XFlush(_glfw.x11.display); +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + Window focused; + int state; + + XGetInputFocus(_glfw.x11.display, &focused, &state); + return window->x11.handle == focused; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + return getWindowState(window) == IconicState; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + XWindowAttributes wa; + XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &wa); + return wa.map_state == IsViewable; +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + Atom* states; + unsigned long i; + GLFWbool maximized = GLFW_FALSE; + const unsigned long count = + _glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.NET_WM_STATE, + XA_ATOM, + (unsigned char**) &states); + + for (i = 0; i < count; i++) + { + if (states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || + states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + maximized = GLFW_TRUE; + break; + } + } + + XFree(states); + return maximized; +} + +void _glfwPlatformPollEvents(void) +{ + _glfwPollJoystickEvents(); + + int count = XPending(_glfw.x11.display); + while (count--) + { + XEvent event; + XNextEvent(_glfw.x11.display, &event); + processEvent(&event); + } + + if (_glfw.x11.disabledCursorWindow) + centerCursor(_glfw.x11.disabledCursorWindow); + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformWaitEvents(void) +{ + while (!XPending(_glfw.x11.display)) + waitForEvent(NULL); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + while (!XPending(_glfw.x11.display)) + { + if (!waitForEvent(&timeout)) + break; + } + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformPostEmptyEvent(void) +{ + XEvent event; + _GLFWwindow* window = _glfw.windowListHead; + + memset(&event, 0, sizeof(event)); + event.type = ClientMessage; + event.xclient.window = window->x11.handle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfw.x11.NULL_; + + XSendEvent(_glfw.x11.display, window->x11.handle, False, 0, &event); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + Window root, child; + int rootX, rootY, childX, childY; + unsigned int mask; + + XQueryPointer(_glfw.x11.display, window->x11.handle, + &root, &child, + &rootX, &rootY, &childX, &childY, + &mask); + + if (xpos) + *xpos = childX; + if (ypos) + *ypos = childY; +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +{ + // Store the new position so it can be recognized later + window->x11.warpCursorPosX = (int) x; + window->x11.warpCursorPosY = (int) y; + + XWarpPointer(_glfw.x11.display, None, window->x11.handle, + 0,0,0,0, (int) x, (int) y); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + if (mode == GLFW_CURSOR_DISABLED) + { + _glfw.x11.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.x11.restoreCursorPosX, + &_glfw.x11.restoreCursorPosY); + centerCursor(window); + XGrabPointer(_glfw.x11.display, window->x11.handle, True, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + window->x11.handle, _glfw.x11.cursor, CurrentTime); + } + else if (_glfw.x11.disabledCursorWindow == window) + { + _glfw.x11.disabledCursorWindow = NULL; + XUngrabPointer(_glfw.x11.display, CurrentTime); + _glfwPlatformSetCursorPos(window, + _glfw.x11.restoreCursorPosX, + _glfw.x11.restoreCursorPosY); + } + + updateCursorImage(window); + XFlush(_glfw.x11.display); +} + +const char* _glfwPlatformGetKeyName(int key, int scancode) +{ + KeySym keysym; + int extra; + + if (!_glfw.x11.xkb.available) + return NULL; + + if (key != GLFW_KEY_UNKNOWN) + scancode = _glfw.x11.nativeKeys[key]; + + if (!_glfwIsPrintable(_glfw.x11.publicKeys[scancode])) + return NULL; + + keysym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); + if (keysym == NoSymbol) + return NULL; + + XkbTranslateKeySym(_glfw.x11.display, &keysym, 0, + _glfw.x11.keyName, sizeof(_glfw.x11.keyName), + &extra); + + if (!strlen(_glfw.x11.keyName)) + return NULL; + + return _glfw.x11.keyName; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + cursor->x11.handle = _glfwCreateCursorX11(image, xhot, yhot); + if (!cursor->x11.handle) + return GLFW_FALSE; + + return GLFW_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, + translateCursorShape(shape)); + if (!cursor->x11.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create standard cursor"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + if (cursor->x11.handle) + XFreeCursor(_glfw.x11.display, cursor->x11.handle); +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + updateCursorImage(window); + XFlush(_glfw.x11.display); + } +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + free(_glfw.x11.clipboardString); + _glfw.x11.clipboardString = strdup(string); + + XSetSelectionOwner(_glfw.x11.display, + _glfw.x11.CLIPBOARD, + window->x11.handle, CurrentTime); + + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) != + window->x11.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to become owner of clipboard selection"); + } +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + size_t i; + const Atom formats[] = { _glfw.x11.UTF8_STRING, + _glfw.x11.COMPOUND_STRING, + XA_STRING }; + const size_t formatCount = sizeof(formats) / sizeof(formats[0]); + + if (findWindowByHandle(XGetSelectionOwner(_glfw.x11.display, + _glfw.x11.CLIPBOARD))) + { + // Instead of doing a large number of X round-trips just to put this + // string into a window property and then read it back, just return it + return _glfw.x11.clipboardString; + } + + free(_glfw.x11.clipboardString); + _glfw.x11.clipboardString = NULL; + + for (i = 0; i < formatCount; i++) + { + char* data; + XEvent event; + + XConvertSelection(_glfw.x11.display, + _glfw.x11.CLIPBOARD, + formats[i], + _glfw.x11.GLFW_SELECTION, + window->x11.handle, CurrentTime); + + while (!XCheckTypedEvent(_glfw.x11.display, SelectionNotify, &event)) + waitForEvent(NULL); + + if (event.xselection.property == None) + continue; + + if (_glfwGetWindowPropertyX11(event.xselection.requestor, + event.xselection.property, + event.xselection.target, + (unsigned char**) &data)) + { + _glfw.x11.clipboardString = strdup(data); + } + + XFree(data); + + XDeleteProperty(_glfw.x11.display, + event.xselection.requestor, + event.xselection.property); + + if (_glfw.x11.clipboardString) + break; + } + + if (_glfw.x11.clipboardString == NULL) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "X11: Failed to convert clipboard to string"); + } + + return _glfw.x11.clipboardString; +} + +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count) +{ + char** extensions; + + *count = 0; + + if (!_glfw.vk.KHR_xcb_surface || !_glfw.x11.x11xcb.handle) + { + if (!_glfw.vk.KHR_xlib_surface) + return NULL; + } + + extensions = calloc(2, sizeof(char*)); + extensions[0] = strdup("VK_KHR_surface"); + + if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) + extensions[1] = strdup("VK_KHR_xcb_surface"); + else + extensions[1] = strdup("VK_KHR_xlib_surface"); + + *count = 2; + return extensions; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + VisualID visualID = XVisualIDFromVisual(DefaultVisual(_glfw.x11.display, + _glfw.x11.screen)); + + if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) + { + PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR = + (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); + if (!vkGetPhysicalDeviceXcbPresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xcb_surface extension"); + return GLFW_FALSE; + } + + xcb_connection_t* connection = + _glfw.x11.x11xcb.XGetXCBConnection(_glfw.x11.display); + if (!connection) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to retrieve XCB connection"); + return GLFW_FALSE; + } + + return vkGetPhysicalDeviceXcbPresentationSupportKHR(device, + queuefamily, + connection, + visualID); + } + else + { + PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR = + (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); + if (!vkGetPhysicalDeviceXlibPresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xlib_surface extension"); + return GLFW_FALSE; + } + + return vkGetPhysicalDeviceXlibPresentationSupportKHR(device, + queuefamily, + _glfw.x11.display, + visualID); + } +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) + { + VkResult err; + VkXcbSurfaceCreateInfoKHR sci; + PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; + + xcb_connection_t* connection = + _glfw.x11.x11xcb.XGetXCBConnection(_glfw.x11.display); + if (!connection) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to retrieve XCB connection"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + vkCreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR) + vkGetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR"); + if (!vkCreateXcbSurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xcb_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + sci.connection = connection; + sci.window = window->x11.handle; + + err = vkCreateXcbSurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create Vulkan XCB surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; + } + else + { + VkResult err; + VkXlibSurfaceCreateInfoKHR sci; + PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; + + vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR) + vkGetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR"); + if (!vkCreateXlibSurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xlib_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + sci.dpy = _glfw.x11.display; + sci.window = window->x11.handle; + + err = vkCreateXlibSurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create Vulkan X11 surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI Display* glfwGetX11Display(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfw.x11.display; +} + +GLFWAPI Window glfwGetX11Window(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(None); + return window->x11.handle; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/xkb_unicode.c b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/xkb_unicode.c new file mode 100644 index 00000000..32233359 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/xkb_unicode.c @@ -0,0 +1,889 @@ +//======================================================================== +// GLFW 3.2 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +/* + * Marcus: This code was originally written by Markus G. Kuhn. + * I have made some slight changes (trimmed it down a bit from >60 KB to + * 20 KB), but the functionality is the same. + */ + +/* + * This module converts keysym values into the corresponding ISO 10646 + * (UCS, Unicode) values. + * + * The array keysymtab[] contains pairs of X11 keysym values for graphical + * characters and the corresponding Unicode value. The function + * _glfwKeySym2Unicode() maps a keysym onto a Unicode value using a binary + * search, therefore keysymtab[] must remain SORTED by keysym value. + * + * We allow to represent any UCS character in the range U-00000000 to + * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. + * This admittedly does not cover the entire 31-bit space of UCS, but + * it does cover all of the characters up to U-10FFFF, which can be + * represented by UTF-16, and more, and it is very unlikely that higher + * UCS codes will ever be assigned by ISO. So to get Unicode character + * U+ABCD you can directly use keysym 0x0100abcd. + * + * Original author: Markus G. Kuhn , University of + * Cambridge, April 2001 + * + * Special thanks to Richard Verhoeven for preparing + * an initial draft of the mapping table. + * + */ + + +//************************************************************************ +//**** KeySym to Unicode mapping table **** +//************************************************************************ + +static const struct codepair { + unsigned short keysym; + unsigned short ucs; +} keysymtab[] = { + { 0x01a1, 0x0104 }, + { 0x01a2, 0x02d8 }, + { 0x01a3, 0x0141 }, + { 0x01a5, 0x013d }, + { 0x01a6, 0x015a }, + { 0x01a9, 0x0160 }, + { 0x01aa, 0x015e }, + { 0x01ab, 0x0164 }, + { 0x01ac, 0x0179 }, + { 0x01ae, 0x017d }, + { 0x01af, 0x017b }, + { 0x01b1, 0x0105 }, + { 0x01b2, 0x02db }, + { 0x01b3, 0x0142 }, + { 0x01b5, 0x013e }, + { 0x01b6, 0x015b }, + { 0x01b7, 0x02c7 }, + { 0x01b9, 0x0161 }, + { 0x01ba, 0x015f }, + { 0x01bb, 0x0165 }, + { 0x01bc, 0x017a }, + { 0x01bd, 0x02dd }, + { 0x01be, 0x017e }, + { 0x01bf, 0x017c }, + { 0x01c0, 0x0154 }, + { 0x01c3, 0x0102 }, + { 0x01c5, 0x0139 }, + { 0x01c6, 0x0106 }, + { 0x01c8, 0x010c }, + { 0x01ca, 0x0118 }, + { 0x01cc, 0x011a }, + { 0x01cf, 0x010e }, + { 0x01d0, 0x0110 }, + { 0x01d1, 0x0143 }, + { 0x01d2, 0x0147 }, + { 0x01d5, 0x0150 }, + { 0x01d8, 0x0158 }, + { 0x01d9, 0x016e }, + { 0x01db, 0x0170 }, + { 0x01de, 0x0162 }, + { 0x01e0, 0x0155 }, + { 0x01e3, 0x0103 }, + { 0x01e5, 0x013a }, + { 0x01e6, 0x0107 }, + { 0x01e8, 0x010d }, + { 0x01ea, 0x0119 }, + { 0x01ec, 0x011b }, + { 0x01ef, 0x010f }, + { 0x01f0, 0x0111 }, + { 0x01f1, 0x0144 }, + { 0x01f2, 0x0148 }, + { 0x01f5, 0x0151 }, + { 0x01f8, 0x0159 }, + { 0x01f9, 0x016f }, + { 0x01fb, 0x0171 }, + { 0x01fe, 0x0163 }, + { 0x01ff, 0x02d9 }, + { 0x02a1, 0x0126 }, + { 0x02a6, 0x0124 }, + { 0x02a9, 0x0130 }, + { 0x02ab, 0x011e }, + { 0x02ac, 0x0134 }, + { 0x02b1, 0x0127 }, + { 0x02b6, 0x0125 }, + { 0x02b9, 0x0131 }, + { 0x02bb, 0x011f }, + { 0x02bc, 0x0135 }, + { 0x02c5, 0x010a }, + { 0x02c6, 0x0108 }, + { 0x02d5, 0x0120 }, + { 0x02d8, 0x011c }, + { 0x02dd, 0x016c }, + { 0x02de, 0x015c }, + { 0x02e5, 0x010b }, + { 0x02e6, 0x0109 }, + { 0x02f5, 0x0121 }, + { 0x02f8, 0x011d }, + { 0x02fd, 0x016d }, + { 0x02fe, 0x015d }, + { 0x03a2, 0x0138 }, + { 0x03a3, 0x0156 }, + { 0x03a5, 0x0128 }, + { 0x03a6, 0x013b }, + { 0x03aa, 0x0112 }, + { 0x03ab, 0x0122 }, + { 0x03ac, 0x0166 }, + { 0x03b3, 0x0157 }, + { 0x03b5, 0x0129 }, + { 0x03b6, 0x013c }, + { 0x03ba, 0x0113 }, + { 0x03bb, 0x0123 }, + { 0x03bc, 0x0167 }, + { 0x03bd, 0x014a }, + { 0x03bf, 0x014b }, + { 0x03c0, 0x0100 }, + { 0x03c7, 0x012e }, + { 0x03cc, 0x0116 }, + { 0x03cf, 0x012a }, + { 0x03d1, 0x0145 }, + { 0x03d2, 0x014c }, + { 0x03d3, 0x0136 }, + { 0x03d9, 0x0172 }, + { 0x03dd, 0x0168 }, + { 0x03de, 0x016a }, + { 0x03e0, 0x0101 }, + { 0x03e7, 0x012f }, + { 0x03ec, 0x0117 }, + { 0x03ef, 0x012b }, + { 0x03f1, 0x0146 }, + { 0x03f2, 0x014d }, + { 0x03f3, 0x0137 }, + { 0x03f9, 0x0173 }, + { 0x03fd, 0x0169 }, + { 0x03fe, 0x016b }, + { 0x047e, 0x203e }, + { 0x04a1, 0x3002 }, + { 0x04a2, 0x300c }, + { 0x04a3, 0x300d }, + { 0x04a4, 0x3001 }, + { 0x04a5, 0x30fb }, + { 0x04a6, 0x30f2 }, + { 0x04a7, 0x30a1 }, + { 0x04a8, 0x30a3 }, + { 0x04a9, 0x30a5 }, + { 0x04aa, 0x30a7 }, + { 0x04ab, 0x30a9 }, + { 0x04ac, 0x30e3 }, + { 0x04ad, 0x30e5 }, + { 0x04ae, 0x30e7 }, + { 0x04af, 0x30c3 }, + { 0x04b0, 0x30fc }, + { 0x04b1, 0x30a2 }, + { 0x04b2, 0x30a4 }, + { 0x04b3, 0x30a6 }, + { 0x04b4, 0x30a8 }, + { 0x04b5, 0x30aa }, + { 0x04b6, 0x30ab }, + { 0x04b7, 0x30ad }, + { 0x04b8, 0x30af }, + { 0x04b9, 0x30b1 }, + { 0x04ba, 0x30b3 }, + { 0x04bb, 0x30b5 }, + { 0x04bc, 0x30b7 }, + { 0x04bd, 0x30b9 }, + { 0x04be, 0x30bb }, + { 0x04bf, 0x30bd }, + { 0x04c0, 0x30bf }, + { 0x04c1, 0x30c1 }, + { 0x04c2, 0x30c4 }, + { 0x04c3, 0x30c6 }, + { 0x04c4, 0x30c8 }, + { 0x04c5, 0x30ca }, + { 0x04c6, 0x30cb }, + { 0x04c7, 0x30cc }, + { 0x04c8, 0x30cd }, + { 0x04c9, 0x30ce }, + { 0x04ca, 0x30cf }, + { 0x04cb, 0x30d2 }, + { 0x04cc, 0x30d5 }, + { 0x04cd, 0x30d8 }, + { 0x04ce, 0x30db }, + { 0x04cf, 0x30de }, + { 0x04d0, 0x30df }, + { 0x04d1, 0x30e0 }, + { 0x04d2, 0x30e1 }, + { 0x04d3, 0x30e2 }, + { 0x04d4, 0x30e4 }, + { 0x04d5, 0x30e6 }, + { 0x04d6, 0x30e8 }, + { 0x04d7, 0x30e9 }, + { 0x04d8, 0x30ea }, + { 0x04d9, 0x30eb }, + { 0x04da, 0x30ec }, + { 0x04db, 0x30ed }, + { 0x04dc, 0x30ef }, + { 0x04dd, 0x30f3 }, + { 0x04de, 0x309b }, + { 0x04df, 0x309c }, + { 0x05ac, 0x060c }, + { 0x05bb, 0x061b }, + { 0x05bf, 0x061f }, + { 0x05c1, 0x0621 }, + { 0x05c2, 0x0622 }, + { 0x05c3, 0x0623 }, + { 0x05c4, 0x0624 }, + { 0x05c5, 0x0625 }, + { 0x05c6, 0x0626 }, + { 0x05c7, 0x0627 }, + { 0x05c8, 0x0628 }, + { 0x05c9, 0x0629 }, + { 0x05ca, 0x062a }, + { 0x05cb, 0x062b }, + { 0x05cc, 0x062c }, + { 0x05cd, 0x062d }, + { 0x05ce, 0x062e }, + { 0x05cf, 0x062f }, + { 0x05d0, 0x0630 }, + { 0x05d1, 0x0631 }, + { 0x05d2, 0x0632 }, + { 0x05d3, 0x0633 }, + { 0x05d4, 0x0634 }, + { 0x05d5, 0x0635 }, + { 0x05d6, 0x0636 }, + { 0x05d7, 0x0637 }, + { 0x05d8, 0x0638 }, + { 0x05d9, 0x0639 }, + { 0x05da, 0x063a }, + { 0x05e0, 0x0640 }, + { 0x05e1, 0x0641 }, + { 0x05e2, 0x0642 }, + { 0x05e3, 0x0643 }, + { 0x05e4, 0x0644 }, + { 0x05e5, 0x0645 }, + { 0x05e6, 0x0646 }, + { 0x05e7, 0x0647 }, + { 0x05e8, 0x0648 }, + { 0x05e9, 0x0649 }, + { 0x05ea, 0x064a }, + { 0x05eb, 0x064b }, + { 0x05ec, 0x064c }, + { 0x05ed, 0x064d }, + { 0x05ee, 0x064e }, + { 0x05ef, 0x064f }, + { 0x05f0, 0x0650 }, + { 0x05f1, 0x0651 }, + { 0x05f2, 0x0652 }, + { 0x06a1, 0x0452 }, + { 0x06a2, 0x0453 }, + { 0x06a3, 0x0451 }, + { 0x06a4, 0x0454 }, + { 0x06a5, 0x0455 }, + { 0x06a6, 0x0456 }, + { 0x06a7, 0x0457 }, + { 0x06a8, 0x0458 }, + { 0x06a9, 0x0459 }, + { 0x06aa, 0x045a }, + { 0x06ab, 0x045b }, + { 0x06ac, 0x045c }, + { 0x06ae, 0x045e }, + { 0x06af, 0x045f }, + { 0x06b0, 0x2116 }, + { 0x06b1, 0x0402 }, + { 0x06b2, 0x0403 }, + { 0x06b3, 0x0401 }, + { 0x06b4, 0x0404 }, + { 0x06b5, 0x0405 }, + { 0x06b6, 0x0406 }, + { 0x06b7, 0x0407 }, + { 0x06b8, 0x0408 }, + { 0x06b9, 0x0409 }, + { 0x06ba, 0x040a }, + { 0x06bb, 0x040b }, + { 0x06bc, 0x040c }, + { 0x06be, 0x040e }, + { 0x06bf, 0x040f }, + { 0x06c0, 0x044e }, + { 0x06c1, 0x0430 }, + { 0x06c2, 0x0431 }, + { 0x06c3, 0x0446 }, + { 0x06c4, 0x0434 }, + { 0x06c5, 0x0435 }, + { 0x06c6, 0x0444 }, + { 0x06c7, 0x0433 }, + { 0x06c8, 0x0445 }, + { 0x06c9, 0x0438 }, + { 0x06ca, 0x0439 }, + { 0x06cb, 0x043a }, + { 0x06cc, 0x043b }, + { 0x06cd, 0x043c }, + { 0x06ce, 0x043d }, + { 0x06cf, 0x043e }, + { 0x06d0, 0x043f }, + { 0x06d1, 0x044f }, + { 0x06d2, 0x0440 }, + { 0x06d3, 0x0441 }, + { 0x06d4, 0x0442 }, + { 0x06d5, 0x0443 }, + { 0x06d6, 0x0436 }, + { 0x06d7, 0x0432 }, + { 0x06d8, 0x044c }, + { 0x06d9, 0x044b }, + { 0x06da, 0x0437 }, + { 0x06db, 0x0448 }, + { 0x06dc, 0x044d }, + { 0x06dd, 0x0449 }, + { 0x06de, 0x0447 }, + { 0x06df, 0x044a }, + { 0x06e0, 0x042e }, + { 0x06e1, 0x0410 }, + { 0x06e2, 0x0411 }, + { 0x06e3, 0x0426 }, + { 0x06e4, 0x0414 }, + { 0x06e5, 0x0415 }, + { 0x06e6, 0x0424 }, + { 0x06e7, 0x0413 }, + { 0x06e8, 0x0425 }, + { 0x06e9, 0x0418 }, + { 0x06ea, 0x0419 }, + { 0x06eb, 0x041a }, + { 0x06ec, 0x041b }, + { 0x06ed, 0x041c }, + { 0x06ee, 0x041d }, + { 0x06ef, 0x041e }, + { 0x06f0, 0x041f }, + { 0x06f1, 0x042f }, + { 0x06f2, 0x0420 }, + { 0x06f3, 0x0421 }, + { 0x06f4, 0x0422 }, + { 0x06f5, 0x0423 }, + { 0x06f6, 0x0416 }, + { 0x06f7, 0x0412 }, + { 0x06f8, 0x042c }, + { 0x06f9, 0x042b }, + { 0x06fa, 0x0417 }, + { 0x06fb, 0x0428 }, + { 0x06fc, 0x042d }, + { 0x06fd, 0x0429 }, + { 0x06fe, 0x0427 }, + { 0x06ff, 0x042a }, + { 0x07a1, 0x0386 }, + { 0x07a2, 0x0388 }, + { 0x07a3, 0x0389 }, + { 0x07a4, 0x038a }, + { 0x07a5, 0x03aa }, + { 0x07a7, 0x038c }, + { 0x07a8, 0x038e }, + { 0x07a9, 0x03ab }, + { 0x07ab, 0x038f }, + { 0x07ae, 0x0385 }, + { 0x07af, 0x2015 }, + { 0x07b1, 0x03ac }, + { 0x07b2, 0x03ad }, + { 0x07b3, 0x03ae }, + { 0x07b4, 0x03af }, + { 0x07b5, 0x03ca }, + { 0x07b6, 0x0390 }, + { 0x07b7, 0x03cc }, + { 0x07b8, 0x03cd }, + { 0x07b9, 0x03cb }, + { 0x07ba, 0x03b0 }, + { 0x07bb, 0x03ce }, + { 0x07c1, 0x0391 }, + { 0x07c2, 0x0392 }, + { 0x07c3, 0x0393 }, + { 0x07c4, 0x0394 }, + { 0x07c5, 0x0395 }, + { 0x07c6, 0x0396 }, + { 0x07c7, 0x0397 }, + { 0x07c8, 0x0398 }, + { 0x07c9, 0x0399 }, + { 0x07ca, 0x039a }, + { 0x07cb, 0x039b }, + { 0x07cc, 0x039c }, + { 0x07cd, 0x039d }, + { 0x07ce, 0x039e }, + { 0x07cf, 0x039f }, + { 0x07d0, 0x03a0 }, + { 0x07d1, 0x03a1 }, + { 0x07d2, 0x03a3 }, + { 0x07d4, 0x03a4 }, + { 0x07d5, 0x03a5 }, + { 0x07d6, 0x03a6 }, + { 0x07d7, 0x03a7 }, + { 0x07d8, 0x03a8 }, + { 0x07d9, 0x03a9 }, + { 0x07e1, 0x03b1 }, + { 0x07e2, 0x03b2 }, + { 0x07e3, 0x03b3 }, + { 0x07e4, 0x03b4 }, + { 0x07e5, 0x03b5 }, + { 0x07e6, 0x03b6 }, + { 0x07e7, 0x03b7 }, + { 0x07e8, 0x03b8 }, + { 0x07e9, 0x03b9 }, + { 0x07ea, 0x03ba }, + { 0x07eb, 0x03bb }, + { 0x07ec, 0x03bc }, + { 0x07ed, 0x03bd }, + { 0x07ee, 0x03be }, + { 0x07ef, 0x03bf }, + { 0x07f0, 0x03c0 }, + { 0x07f1, 0x03c1 }, + { 0x07f2, 0x03c3 }, + { 0x07f3, 0x03c2 }, + { 0x07f4, 0x03c4 }, + { 0x07f5, 0x03c5 }, + { 0x07f6, 0x03c6 }, + { 0x07f7, 0x03c7 }, + { 0x07f8, 0x03c8 }, + { 0x07f9, 0x03c9 }, + { 0x08a1, 0x23b7 }, + { 0x08a2, 0x250c }, + { 0x08a3, 0x2500 }, + { 0x08a4, 0x2320 }, + { 0x08a5, 0x2321 }, + { 0x08a6, 0x2502 }, + { 0x08a7, 0x23a1 }, + { 0x08a8, 0x23a3 }, + { 0x08a9, 0x23a4 }, + { 0x08aa, 0x23a6 }, + { 0x08ab, 0x239b }, + { 0x08ac, 0x239d }, + { 0x08ad, 0x239e }, + { 0x08ae, 0x23a0 }, + { 0x08af, 0x23a8 }, + { 0x08b0, 0x23ac }, + { 0x08bc, 0x2264 }, + { 0x08bd, 0x2260 }, + { 0x08be, 0x2265 }, + { 0x08bf, 0x222b }, + { 0x08c0, 0x2234 }, + { 0x08c1, 0x221d }, + { 0x08c2, 0x221e }, + { 0x08c5, 0x2207 }, + { 0x08c8, 0x223c }, + { 0x08c9, 0x2243 }, + { 0x08cd, 0x21d4 }, + { 0x08ce, 0x21d2 }, + { 0x08cf, 0x2261 }, + { 0x08d6, 0x221a }, + { 0x08da, 0x2282 }, + { 0x08db, 0x2283 }, + { 0x08dc, 0x2229 }, + { 0x08dd, 0x222a }, + { 0x08de, 0x2227 }, + { 0x08df, 0x2228 }, + { 0x08ef, 0x2202 }, + { 0x08f6, 0x0192 }, + { 0x08fb, 0x2190 }, + { 0x08fc, 0x2191 }, + { 0x08fd, 0x2192 }, + { 0x08fe, 0x2193 }, + { 0x09e0, 0x25c6 }, + { 0x09e1, 0x2592 }, + { 0x09e2, 0x2409 }, + { 0x09e3, 0x240c }, + { 0x09e4, 0x240d }, + { 0x09e5, 0x240a }, + { 0x09e8, 0x2424 }, + { 0x09e9, 0x240b }, + { 0x09ea, 0x2518 }, + { 0x09eb, 0x2510 }, + { 0x09ec, 0x250c }, + { 0x09ed, 0x2514 }, + { 0x09ee, 0x253c }, + { 0x09ef, 0x23ba }, + { 0x09f0, 0x23bb }, + { 0x09f1, 0x2500 }, + { 0x09f2, 0x23bc }, + { 0x09f3, 0x23bd }, + { 0x09f4, 0x251c }, + { 0x09f5, 0x2524 }, + { 0x09f6, 0x2534 }, + { 0x09f7, 0x252c }, + { 0x09f8, 0x2502 }, + { 0x0aa1, 0x2003 }, + { 0x0aa2, 0x2002 }, + { 0x0aa3, 0x2004 }, + { 0x0aa4, 0x2005 }, + { 0x0aa5, 0x2007 }, + { 0x0aa6, 0x2008 }, + { 0x0aa7, 0x2009 }, + { 0x0aa8, 0x200a }, + { 0x0aa9, 0x2014 }, + { 0x0aaa, 0x2013 }, + { 0x0aae, 0x2026 }, + { 0x0aaf, 0x2025 }, + { 0x0ab0, 0x2153 }, + { 0x0ab1, 0x2154 }, + { 0x0ab2, 0x2155 }, + { 0x0ab3, 0x2156 }, + { 0x0ab4, 0x2157 }, + { 0x0ab5, 0x2158 }, + { 0x0ab6, 0x2159 }, + { 0x0ab7, 0x215a }, + { 0x0ab8, 0x2105 }, + { 0x0abb, 0x2012 }, + { 0x0abc, 0x2329 }, + { 0x0abe, 0x232a }, + { 0x0ac3, 0x215b }, + { 0x0ac4, 0x215c }, + { 0x0ac5, 0x215d }, + { 0x0ac6, 0x215e }, + { 0x0ac9, 0x2122 }, + { 0x0aca, 0x2613 }, + { 0x0acc, 0x25c1 }, + { 0x0acd, 0x25b7 }, + { 0x0ace, 0x25cb }, + { 0x0acf, 0x25af }, + { 0x0ad0, 0x2018 }, + { 0x0ad1, 0x2019 }, + { 0x0ad2, 0x201c }, + { 0x0ad3, 0x201d }, + { 0x0ad4, 0x211e }, + { 0x0ad6, 0x2032 }, + { 0x0ad7, 0x2033 }, + { 0x0ad9, 0x271d }, + { 0x0adb, 0x25ac }, + { 0x0adc, 0x25c0 }, + { 0x0add, 0x25b6 }, + { 0x0ade, 0x25cf }, + { 0x0adf, 0x25ae }, + { 0x0ae0, 0x25e6 }, + { 0x0ae1, 0x25ab }, + { 0x0ae2, 0x25ad }, + { 0x0ae3, 0x25b3 }, + { 0x0ae4, 0x25bd }, + { 0x0ae5, 0x2606 }, + { 0x0ae6, 0x2022 }, + { 0x0ae7, 0x25aa }, + { 0x0ae8, 0x25b2 }, + { 0x0ae9, 0x25bc }, + { 0x0aea, 0x261c }, + { 0x0aeb, 0x261e }, + { 0x0aec, 0x2663 }, + { 0x0aed, 0x2666 }, + { 0x0aee, 0x2665 }, + { 0x0af0, 0x2720 }, + { 0x0af1, 0x2020 }, + { 0x0af2, 0x2021 }, + { 0x0af3, 0x2713 }, + { 0x0af4, 0x2717 }, + { 0x0af5, 0x266f }, + { 0x0af6, 0x266d }, + { 0x0af7, 0x2642 }, + { 0x0af8, 0x2640 }, + { 0x0af9, 0x260e }, + { 0x0afa, 0x2315 }, + { 0x0afb, 0x2117 }, + { 0x0afc, 0x2038 }, + { 0x0afd, 0x201a }, + { 0x0afe, 0x201e }, + { 0x0ba3, 0x003c }, + { 0x0ba6, 0x003e }, + { 0x0ba8, 0x2228 }, + { 0x0ba9, 0x2227 }, + { 0x0bc0, 0x00af }, + { 0x0bc2, 0x22a5 }, + { 0x0bc3, 0x2229 }, + { 0x0bc4, 0x230a }, + { 0x0bc6, 0x005f }, + { 0x0bca, 0x2218 }, + { 0x0bcc, 0x2395 }, + { 0x0bce, 0x22a4 }, + { 0x0bcf, 0x25cb }, + { 0x0bd3, 0x2308 }, + { 0x0bd6, 0x222a }, + { 0x0bd8, 0x2283 }, + { 0x0bda, 0x2282 }, + { 0x0bdc, 0x22a2 }, + { 0x0bfc, 0x22a3 }, + { 0x0cdf, 0x2017 }, + { 0x0ce0, 0x05d0 }, + { 0x0ce1, 0x05d1 }, + { 0x0ce2, 0x05d2 }, + { 0x0ce3, 0x05d3 }, + { 0x0ce4, 0x05d4 }, + { 0x0ce5, 0x05d5 }, + { 0x0ce6, 0x05d6 }, + { 0x0ce7, 0x05d7 }, + { 0x0ce8, 0x05d8 }, + { 0x0ce9, 0x05d9 }, + { 0x0cea, 0x05da }, + { 0x0ceb, 0x05db }, + { 0x0cec, 0x05dc }, + { 0x0ced, 0x05dd }, + { 0x0cee, 0x05de }, + { 0x0cef, 0x05df }, + { 0x0cf0, 0x05e0 }, + { 0x0cf1, 0x05e1 }, + { 0x0cf2, 0x05e2 }, + { 0x0cf3, 0x05e3 }, + { 0x0cf4, 0x05e4 }, + { 0x0cf5, 0x05e5 }, + { 0x0cf6, 0x05e6 }, + { 0x0cf7, 0x05e7 }, + { 0x0cf8, 0x05e8 }, + { 0x0cf9, 0x05e9 }, + { 0x0cfa, 0x05ea }, + { 0x0da1, 0x0e01 }, + { 0x0da2, 0x0e02 }, + { 0x0da3, 0x0e03 }, + { 0x0da4, 0x0e04 }, + { 0x0da5, 0x0e05 }, + { 0x0da6, 0x0e06 }, + { 0x0da7, 0x0e07 }, + { 0x0da8, 0x0e08 }, + { 0x0da9, 0x0e09 }, + { 0x0daa, 0x0e0a }, + { 0x0dab, 0x0e0b }, + { 0x0dac, 0x0e0c }, + { 0x0dad, 0x0e0d }, + { 0x0dae, 0x0e0e }, + { 0x0daf, 0x0e0f }, + { 0x0db0, 0x0e10 }, + { 0x0db1, 0x0e11 }, + { 0x0db2, 0x0e12 }, + { 0x0db3, 0x0e13 }, + { 0x0db4, 0x0e14 }, + { 0x0db5, 0x0e15 }, + { 0x0db6, 0x0e16 }, + { 0x0db7, 0x0e17 }, + { 0x0db8, 0x0e18 }, + { 0x0db9, 0x0e19 }, + { 0x0dba, 0x0e1a }, + { 0x0dbb, 0x0e1b }, + { 0x0dbc, 0x0e1c }, + { 0x0dbd, 0x0e1d }, + { 0x0dbe, 0x0e1e }, + { 0x0dbf, 0x0e1f }, + { 0x0dc0, 0x0e20 }, + { 0x0dc1, 0x0e21 }, + { 0x0dc2, 0x0e22 }, + { 0x0dc3, 0x0e23 }, + { 0x0dc4, 0x0e24 }, + { 0x0dc5, 0x0e25 }, + { 0x0dc6, 0x0e26 }, + { 0x0dc7, 0x0e27 }, + { 0x0dc8, 0x0e28 }, + { 0x0dc9, 0x0e29 }, + { 0x0dca, 0x0e2a }, + { 0x0dcb, 0x0e2b }, + { 0x0dcc, 0x0e2c }, + { 0x0dcd, 0x0e2d }, + { 0x0dce, 0x0e2e }, + { 0x0dcf, 0x0e2f }, + { 0x0dd0, 0x0e30 }, + { 0x0dd1, 0x0e31 }, + { 0x0dd2, 0x0e32 }, + { 0x0dd3, 0x0e33 }, + { 0x0dd4, 0x0e34 }, + { 0x0dd5, 0x0e35 }, + { 0x0dd6, 0x0e36 }, + { 0x0dd7, 0x0e37 }, + { 0x0dd8, 0x0e38 }, + { 0x0dd9, 0x0e39 }, + { 0x0dda, 0x0e3a }, + { 0x0ddf, 0x0e3f }, + { 0x0de0, 0x0e40 }, + { 0x0de1, 0x0e41 }, + { 0x0de2, 0x0e42 }, + { 0x0de3, 0x0e43 }, + { 0x0de4, 0x0e44 }, + { 0x0de5, 0x0e45 }, + { 0x0de6, 0x0e46 }, + { 0x0de7, 0x0e47 }, + { 0x0de8, 0x0e48 }, + { 0x0de9, 0x0e49 }, + { 0x0dea, 0x0e4a }, + { 0x0deb, 0x0e4b }, + { 0x0dec, 0x0e4c }, + { 0x0ded, 0x0e4d }, + { 0x0df0, 0x0e50 }, + { 0x0df1, 0x0e51 }, + { 0x0df2, 0x0e52 }, + { 0x0df3, 0x0e53 }, + { 0x0df4, 0x0e54 }, + { 0x0df5, 0x0e55 }, + { 0x0df6, 0x0e56 }, + { 0x0df7, 0x0e57 }, + { 0x0df8, 0x0e58 }, + { 0x0df9, 0x0e59 }, + { 0x0ea1, 0x3131 }, + { 0x0ea2, 0x3132 }, + { 0x0ea3, 0x3133 }, + { 0x0ea4, 0x3134 }, + { 0x0ea5, 0x3135 }, + { 0x0ea6, 0x3136 }, + { 0x0ea7, 0x3137 }, + { 0x0ea8, 0x3138 }, + { 0x0ea9, 0x3139 }, + { 0x0eaa, 0x313a }, + { 0x0eab, 0x313b }, + { 0x0eac, 0x313c }, + { 0x0ead, 0x313d }, + { 0x0eae, 0x313e }, + { 0x0eaf, 0x313f }, + { 0x0eb0, 0x3140 }, + { 0x0eb1, 0x3141 }, + { 0x0eb2, 0x3142 }, + { 0x0eb3, 0x3143 }, + { 0x0eb4, 0x3144 }, + { 0x0eb5, 0x3145 }, + { 0x0eb6, 0x3146 }, + { 0x0eb7, 0x3147 }, + { 0x0eb8, 0x3148 }, + { 0x0eb9, 0x3149 }, + { 0x0eba, 0x314a }, + { 0x0ebb, 0x314b }, + { 0x0ebc, 0x314c }, + { 0x0ebd, 0x314d }, + { 0x0ebe, 0x314e }, + { 0x0ebf, 0x314f }, + { 0x0ec0, 0x3150 }, + { 0x0ec1, 0x3151 }, + { 0x0ec2, 0x3152 }, + { 0x0ec3, 0x3153 }, + { 0x0ec4, 0x3154 }, + { 0x0ec5, 0x3155 }, + { 0x0ec6, 0x3156 }, + { 0x0ec7, 0x3157 }, + { 0x0ec8, 0x3158 }, + { 0x0ec9, 0x3159 }, + { 0x0eca, 0x315a }, + { 0x0ecb, 0x315b }, + { 0x0ecc, 0x315c }, + { 0x0ecd, 0x315d }, + { 0x0ece, 0x315e }, + { 0x0ecf, 0x315f }, + { 0x0ed0, 0x3160 }, + { 0x0ed1, 0x3161 }, + { 0x0ed2, 0x3162 }, + { 0x0ed3, 0x3163 }, + { 0x0ed4, 0x11a8 }, + { 0x0ed5, 0x11a9 }, + { 0x0ed6, 0x11aa }, + { 0x0ed7, 0x11ab }, + { 0x0ed8, 0x11ac }, + { 0x0ed9, 0x11ad }, + { 0x0eda, 0x11ae }, + { 0x0edb, 0x11af }, + { 0x0edc, 0x11b0 }, + { 0x0edd, 0x11b1 }, + { 0x0ede, 0x11b2 }, + { 0x0edf, 0x11b3 }, + { 0x0ee0, 0x11b4 }, + { 0x0ee1, 0x11b5 }, + { 0x0ee2, 0x11b6 }, + { 0x0ee3, 0x11b7 }, + { 0x0ee4, 0x11b8 }, + { 0x0ee5, 0x11b9 }, + { 0x0ee6, 0x11ba }, + { 0x0ee7, 0x11bb }, + { 0x0ee8, 0x11bc }, + { 0x0ee9, 0x11bd }, + { 0x0eea, 0x11be }, + { 0x0eeb, 0x11bf }, + { 0x0eec, 0x11c0 }, + { 0x0eed, 0x11c1 }, + { 0x0eee, 0x11c2 }, + { 0x0eef, 0x316d }, + { 0x0ef0, 0x3171 }, + { 0x0ef1, 0x3178 }, + { 0x0ef2, 0x317f }, + { 0x0ef3, 0x3181 }, + { 0x0ef4, 0x3184 }, + { 0x0ef5, 0x3186 }, + { 0x0ef6, 0x318d }, + { 0x0ef7, 0x318e }, + { 0x0ef8, 0x11eb }, + { 0x0ef9, 0x11f0 }, + { 0x0efa, 0x11f9 }, + { 0x0eff, 0x20a9 }, + { 0x13a4, 0x20ac }, + { 0x13bc, 0x0152 }, + { 0x13bd, 0x0153 }, + { 0x13be, 0x0178 }, + { 0x20ac, 0x20ac }, + // Numeric keypad with numlock on + { 0xff80 /*XKB_KEY_KP_Space*/, ' ' }, + { 0xffbd /*XKB_KEY_KP_Equal*/, '=' }, + { 0xffaa /*XKB_KEY_KP_Multiply*/, '*' }, + { 0xffab /*XKB_KEY_KP_Add*/, '+' }, + { 0xffac /*XKB_KEY_KP_Separator*/, ',' }, + { 0xffad /*XKB_KEY_KP_Subtract*/, '-' }, + { 0xffae /*XKB_KEY_KP_Decimal*/, '.' }, + { 0xffaf /*XKB_KEY_KP_Divide*/, '/' }, + { 0xffb0 /*XKB_KEY_KP_0*/, 0x0030 }, + { 0xffb1 /*XKB_KEY_KP_1*/, 0x0031 }, + { 0xffb2 /*XKB_KEY_KP_2*/, 0x0032 }, + { 0xffb3 /*XKB_KEY_KP_3*/, 0x0033 }, + { 0xffb4 /*XKB_KEY_KP_4*/, 0x0034 }, + { 0xffb5 /*XKB_KEY_KP_5*/, 0x0035 }, + { 0xffb6 /*XKB_KEY_KP_6*/, 0x0036 }, + { 0xffb7 /*XKB_KEY_KP_7*/, 0x0037 }, + { 0xffb8 /*XKB_KEY_KP_8*/, 0x0038 }, + { 0xffb9 /*XKB_KEY_KP_9*/, 0x0039 } +}; + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Convert XKB KeySym to Unicode +// +long _glfwKeySym2Unicode(unsigned int keysym) +{ + int min = 0; + int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; + int mid; + + // First check for Latin-1 characters (1:1 mapping) + if ((keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff)) + { + return keysym; + } + + // Also check for directly encoded 24-bit UCS characters + if ((keysym & 0xff000000) == 0x01000000) + return keysym & 0x00ffffff; + + // Binary search in table + while (max >= min) + { + mid = (min + max) / 2; + if (keysymtab[mid].keysym < keysym) + min = mid + 1; + else if (keysymtab[mid].keysym > keysym) + max = mid - 1; + else + return keysymtab[mid].ucs; + } + + // No matching Unicode value found + return -1; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/xkb_unicode.h b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/xkb_unicode.h new file mode 100644 index 00000000..688374d8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/GLFW/src/xkb_unicode.h @@ -0,0 +1,33 @@ +//======================================================================== +// GLFW 3.2 Linux - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ã…dahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _glfw3_xkb_unicode_h_ +#define _glfw3_xkb_unicode_h_ + + +long _glfwKeySym2Unicode(unsigned int keysym); + +#endif // _glfw3_xkb_unicode_h_ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/KHR/khrplatform.h b/Extern/3rdParty/OptiX/Linux/SDK/support/KHR/khrplatform.h new file mode 100644 index 00000000..975bbffe --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/KHR/khrplatform.h @@ -0,0 +1,282 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2018 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * The master copy of khrplatform.h is maintained in the Khronos EGL + * Registry repository at /~https://github.com/KhronosGroup/EGL-Registry + * The last semantic modification to khrplatform.h was at commit ID: + * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by filing pull requests or issues on + * the EGL Registry repository linked above. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(_WIN32) && !defined(__SCITECH_SNAP__) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#elif defined(__ANDROID__) +# define KHRONOS_APICALL __attribute__((visibility("default"))) +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef _WIN64 +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/glad/glad.c b/Extern/3rdParty/OptiX/Linux/SDK/support/glad/glad.c new file mode 100644 index 00000000..f2560443 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/glad/glad.c @@ -0,0 +1,1837 @@ +/* + + OpenGL loader generated by glad 0.1.29 on Fri Mar 22 21:20:36 2019. + + Language/Generator: C/C++ + Specification: gl + APIs: gl=3.3 + Profile: compatibility + Extensions: + + Loader: True + Local files: False + Omit khrplatform: False + Reproducible: False + + Commandline: + --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="" + Online: + https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3 +*/ + +#include +#include +#include +#include + +static void* get_proc(const char *namez); + +#if defined(_WIN32) || defined(__CYGWIN__) +#include +static HMODULE libGL; + +typedef void* (APIENTRYP PFNWGLGETPROCADDRESSPROC_PRIVATE)(const char*); +static PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; + +#ifdef _MSC_VER +#ifdef __has_include + #if __has_include() + #define HAVE_WINAPIFAMILY 1 + #endif +#elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ + #define HAVE_WINAPIFAMILY 1 +#endif +#endif + +#ifdef HAVE_WINAPIFAMILY + #include + #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + #define IS_UWP 1 + #endif +#endif + +static +int open_gl(void) { +#ifndef IS_UWP + libGL = LoadLibraryW(L"opengl32.dll"); + if(libGL != NULL) { + void (* tmp)(void); + tmp = (void(*)(void)) GetProcAddress(libGL, "wglGetProcAddress"); + gladGetProcAddressPtr = (PFNWGLGETPROCADDRESSPROC_PRIVATE) tmp; + return gladGetProcAddressPtr != NULL; + } +#endif + + return 0; +} + +static +void close_gl(void) { + if(libGL != NULL) { + FreeLibrary((HMODULE) libGL); + libGL = NULL; + } +} +#else +#include +static void* libGL; + +#if !defined(__APPLE__) && !defined(__HAIKU__) +typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*); +static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; +#endif + +static +int open_gl(void) { +#ifdef __APPLE__ + static const char *NAMES[] = { + "../Frameworks/OpenGL.framework/OpenGL", + "/Library/Frameworks/OpenGL.framework/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" + }; +#else + static const char *NAMES[] = {"libGL.so.1", "libGL.so"}; +#endif + + unsigned int index = 0; + for(index = 0; index < (sizeof(NAMES) / sizeof(NAMES[0])); index++) { + libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL); + + if(libGL != NULL) { +#if defined(__APPLE__) || defined(__HAIKU__) + return 1; +#else + gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL, + "glXGetProcAddressARB"); + return gladGetProcAddressPtr != NULL; +#endif + } + } + + return 0; +} + +static +void close_gl(void) { + if(libGL != NULL) { + dlclose(libGL); + libGL = NULL; + } +} +#endif + +static +void* get_proc(const char *namez) { + void* result = NULL; + if(libGL == NULL) return NULL; + +#if !defined(__APPLE__) && !defined(__HAIKU__) + if(gladGetProcAddressPtr != NULL) { + result = gladGetProcAddressPtr(namez); + } +#endif + if(result == NULL) { +#if defined(_WIN32) || defined(__CYGWIN__) + result = (void*)GetProcAddress((HMODULE) libGL, namez); +#else + result = dlsym(libGL, namez); +#endif + } + + return result; +} + +int gladLoadGL(void) { + int status = 0; + + if(open_gl()) { + status = gladLoadGLLoader(&get_proc); + close_gl(); + } + + return status; +} + +struct gladGLversionStruct GLVersion = { 0, 0 }; + +#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) +#define _GLAD_IS_SOME_NEW_VERSION 1 +#endif + +static int max_loaded_major; +static int max_loaded_minor; + +static const char *exts = NULL; +static int num_exts_i = 0; +static char **exts_i = NULL; + +static int get_exts(void) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + exts = (const char *)glGetString(GL_EXTENSIONS); +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + unsigned int index; + + num_exts_i = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); + if (num_exts_i > 0) { + exts_i = (char **)malloc((size_t)num_exts_i * (sizeof *exts_i)); + } + + if (exts_i == NULL) { + return 0; + } + + for(index = 0; index < (unsigned)num_exts_i; index++) { + const char *gl_str_tmp = (const char*)glGetStringi(GL_EXTENSIONS, index); + size_t len = strlen(gl_str_tmp); + + char *local_str = (char*)malloc((len+1) * sizeof(char)); + if(local_str != NULL) { + memcpy(local_str, gl_str_tmp, (len+1) * sizeof(char)); + } + exts_i[index] = local_str; + } + } +#endif + return 1; +} + +static void free_exts(void) { + if (exts_i != NULL) { + int index; + for(index = 0; index < num_exts_i; index++) { + free((char *)exts_i[index]); + } + free((void *)exts_i); + exts_i = NULL; + } +} + +static int has_ext(const char *ext) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + const char *extensions; + const char *loc; + const char *terminator; + extensions = exts; + if(extensions == NULL || ext == NULL) { + return 0; + } + + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + int index; + if(exts_i == NULL) return 0; + for(index = 0; index < num_exts_i; index++) { + const char *e = exts_i[index]; + + if(exts_i[index] != NULL && strcmp(e, ext) == 0) { + return 1; + } + } + } +#endif + + return 0; +} +int GLAD_GL_VERSION_1_0 = 0; +int GLAD_GL_VERSION_1_1 = 0; +int GLAD_GL_VERSION_1_2 = 0; +int GLAD_GL_VERSION_1_3 = 0; +int GLAD_GL_VERSION_1_4 = 0; +int GLAD_GL_VERSION_1_5 = 0; +int GLAD_GL_VERSION_2_0 = 0; +int GLAD_GL_VERSION_2_1 = 0; +int GLAD_GL_VERSION_3_0 = 0; +int GLAD_GL_VERSION_3_1 = 0; +int GLAD_GL_VERSION_3_2 = 0; +int GLAD_GL_VERSION_3_3 = 0; +PFNGLACCUMPROC glad_glAccum = NULL; +PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; +PFNGLALPHAFUNCPROC glad_glAlphaFunc = NULL; +PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident = NULL; +PFNGLARRAYELEMENTPROC glad_glArrayElement = NULL; +PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; +PFNGLBEGINPROC glad_glBegin = NULL; +PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL; +PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL; +PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; +PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; +PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL; +PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL; +PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL; +PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; +PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL; +PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; +PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL; +PFNGLBITMAPPROC glad_glBitmap = NULL; +PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; +PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; +PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL; +PFNGLBUFFERDATAPROC glad_glBufferData = NULL; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; +PFNGLCALLLISTPROC glad_glCallList = NULL; +PFNGLCALLLISTSPROC glad_glCallLists = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; +PFNGLCLAMPCOLORPROC glad_glClampColor = NULL; +PFNGLCLEARPROC glad_glClear = NULL; +PFNGLCLEARACCUMPROC glad_glClearAccum = NULL; +PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL; +PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL; +PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL; +PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL; +PFNGLCLEARCOLORPROC glad_glClearColor = NULL; +PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL; +PFNGLCLEARINDEXPROC glad_glClearIndex = NULL; +PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; +PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture = NULL; +PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL; +PFNGLCLIPPLANEPROC glad_glClipPlane = NULL; +PFNGLCOLOR3BPROC glad_glColor3b = NULL; +PFNGLCOLOR3BVPROC glad_glColor3bv = NULL; +PFNGLCOLOR3DPROC glad_glColor3d = NULL; +PFNGLCOLOR3DVPROC glad_glColor3dv = NULL; +PFNGLCOLOR3FPROC glad_glColor3f = NULL; +PFNGLCOLOR3FVPROC glad_glColor3fv = NULL; +PFNGLCOLOR3IPROC glad_glColor3i = NULL; +PFNGLCOLOR3IVPROC glad_glColor3iv = NULL; +PFNGLCOLOR3SPROC glad_glColor3s = NULL; +PFNGLCOLOR3SVPROC glad_glColor3sv = NULL; +PFNGLCOLOR3UBPROC glad_glColor3ub = NULL; +PFNGLCOLOR3UBVPROC glad_glColor3ubv = NULL; +PFNGLCOLOR3UIPROC glad_glColor3ui = NULL; +PFNGLCOLOR3UIVPROC glad_glColor3uiv = NULL; +PFNGLCOLOR3USPROC glad_glColor3us = NULL; +PFNGLCOLOR3USVPROC glad_glColor3usv = NULL; +PFNGLCOLOR4BPROC glad_glColor4b = NULL; +PFNGLCOLOR4BVPROC glad_glColor4bv = NULL; +PFNGLCOLOR4DPROC glad_glColor4d = NULL; +PFNGLCOLOR4DVPROC glad_glColor4dv = NULL; +PFNGLCOLOR4FPROC glad_glColor4f = NULL; +PFNGLCOLOR4FVPROC glad_glColor4fv = NULL; +PFNGLCOLOR4IPROC glad_glColor4i = NULL; +PFNGLCOLOR4IVPROC glad_glColor4iv = NULL; +PFNGLCOLOR4SPROC glad_glColor4s = NULL; +PFNGLCOLOR4SVPROC glad_glColor4sv = NULL; +PFNGLCOLOR4UBPROC glad_glColor4ub = NULL; +PFNGLCOLOR4UBVPROC glad_glColor4ubv = NULL; +PFNGLCOLOR4UIPROC glad_glColor4ui = NULL; +PFNGLCOLOR4UIVPROC glad_glColor4uiv = NULL; +PFNGLCOLOR4USPROC glad_glColor4us = NULL; +PFNGLCOLOR4USVPROC glad_glColor4usv = NULL; +PFNGLCOLORMASKPROC glad_glColorMask = NULL; +PFNGLCOLORMASKIPROC glad_glColorMaski = NULL; +PFNGLCOLORMATERIALPROC glad_glColorMaterial = NULL; +PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL; +PFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL; +PFNGLCOLORP4UIPROC glad_glColorP4ui = NULL; +PFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL; +PFNGLCOLORPOINTERPROC glad_glColorPointer = NULL; +PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; +PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; +PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL; +PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL; +PFNGLCOPYPIXELSPROC glad_glCopyPixels = NULL; +PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; +PFNGLCREATESHADERPROC glad_glCreateShader = NULL; +PFNGLCULLFACEPROC glad_glCullFace = NULL; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; +PFNGLDELETELISTSPROC glad_glDeleteLists = NULL; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; +PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; +PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL; +PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; +PFNGLDELETESYNCPROC glad_glDeleteSync = NULL; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; +PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL; +PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; +PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; +PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL; +PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; +PFNGLDISABLEPROC glad_glDisable = NULL; +PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; +PFNGLDISABLEIPROC glad_glDisablei = NULL; +PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; +PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL; +PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL; +PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL; +PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; +PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL; +PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL; +PFNGLDRAWPIXELSPROC glad_glDrawPixels = NULL; +PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL; +PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL; +PFNGLEDGEFLAGPROC glad_glEdgeFlag = NULL; +PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer = NULL; +PFNGLEDGEFLAGVPROC glad_glEdgeFlagv = NULL; +PFNGLENABLEPROC glad_glEnable = NULL; +PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState = NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; +PFNGLENABLEIPROC glad_glEnablei = NULL; +PFNGLENDPROC glad_glEnd = NULL; +PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL; +PFNGLENDLISTPROC glad_glEndList = NULL; +PFNGLENDQUERYPROC glad_glEndQuery = NULL; +PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL; +PFNGLEVALCOORD1DPROC glad_glEvalCoord1d = NULL; +PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv = NULL; +PFNGLEVALCOORD1FPROC glad_glEvalCoord1f = NULL; +PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv = NULL; +PFNGLEVALCOORD2DPROC glad_glEvalCoord2d = NULL; +PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv = NULL; +PFNGLEVALCOORD2FPROC glad_glEvalCoord2f = NULL; +PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv = NULL; +PFNGLEVALMESH1PROC glad_glEvalMesh1 = NULL; +PFNGLEVALMESH2PROC glad_glEvalMesh2 = NULL; +PFNGLEVALPOINT1PROC glad_glEvalPoint1 = NULL; +PFNGLEVALPOINT2PROC glad_glEvalPoint2 = NULL; +PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer = NULL; +PFNGLFENCESYNCPROC glad_glFenceSync = NULL; +PFNGLFINISHPROC glad_glFinish = NULL; +PFNGLFLUSHPROC glad_glFlush = NULL; +PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL; +PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer = NULL; +PFNGLFOGCOORDDPROC glad_glFogCoordd = NULL; +PFNGLFOGCOORDDVPROC glad_glFogCoorddv = NULL; +PFNGLFOGCOORDFPROC glad_glFogCoordf = NULL; +PFNGLFOGCOORDFVPROC glad_glFogCoordfv = NULL; +PFNGLFOGFPROC glad_glFogf = NULL; +PFNGLFOGFVPROC glad_glFogfv = NULL; +PFNGLFOGIPROC glad_glFogi = NULL; +PFNGLFOGIVPROC glad_glFogiv = NULL; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; +PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL; +PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; +PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL; +PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL; +PFNGLFRONTFACEPROC glad_glFrontFace = NULL; +PFNGLFRUSTUMPROC glad_glFrustum = NULL; +PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; +PFNGLGENLISTSPROC glad_glGenLists = NULL; +PFNGLGENQUERIESPROC glad_glGenQueries = NULL; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; +PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL; +PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; +PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; +PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL; +PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL; +PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL; +PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; +PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; +PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; +PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL; +PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL; +PFNGLGETCLIPPLANEPROC glad_glGetClipPlane = NULL; +PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL; +PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL; +PFNGLGETERRORPROC glad_glGetError = NULL; +PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; +PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL; +PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; +PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL; +PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL; +PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL; +PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; +PFNGLGETLIGHTFVPROC glad_glGetLightfv = NULL; +PFNGLGETLIGHTIVPROC glad_glGetLightiv = NULL; +PFNGLGETMAPDVPROC glad_glGetMapdv = NULL; +PFNGLGETMAPFVPROC glad_glGetMapfv = NULL; +PFNGLGETMAPIVPROC glad_glGetMapiv = NULL; +PFNGLGETMATERIALFVPROC glad_glGetMaterialfv = NULL; +PFNGLGETMATERIALIVPROC glad_glGetMaterialiv = NULL; +PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL; +PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv = NULL; +PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv = NULL; +PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv = NULL; +PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL; +PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple = NULL; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; +PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL; +PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL; +PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL; +PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL; +PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; +PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL; +PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL; +PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL; +PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; +PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; +PFNGLGETSTRINGPROC glad_glGetString = NULL; +PFNGLGETSTRINGIPROC glad_glGetStringi = NULL; +PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL; +PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv = NULL; +PFNGLGETTEXENVIVPROC glad_glGetTexEnviv = NULL; +PFNGLGETTEXGENDVPROC glad_glGetTexGendv = NULL; +PFNGLGETTEXGENFVPROC glad_glGetTexGenfv = NULL; +PFNGLGETTEXGENIVPROC glad_glGetTexGeniv = NULL; +PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL; +PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL; +PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL; +PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL; +PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; +PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL; +PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL; +PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; +PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL; +PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL; +PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; +PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; +PFNGLHINTPROC glad_glHint = NULL; +PFNGLINDEXMASKPROC glad_glIndexMask = NULL; +PFNGLINDEXPOINTERPROC glad_glIndexPointer = NULL; +PFNGLINDEXDPROC glad_glIndexd = NULL; +PFNGLINDEXDVPROC glad_glIndexdv = NULL; +PFNGLINDEXFPROC glad_glIndexf = NULL; +PFNGLINDEXFVPROC glad_glIndexfv = NULL; +PFNGLINDEXIPROC glad_glIndexi = NULL; +PFNGLINDEXIVPROC glad_glIndexiv = NULL; +PFNGLINDEXSPROC glad_glIndexs = NULL; +PFNGLINDEXSVPROC glad_glIndexsv = NULL; +PFNGLINDEXUBPROC glad_glIndexub = NULL; +PFNGLINDEXUBVPROC glad_glIndexubv = NULL; +PFNGLINITNAMESPROC glad_glInitNames = NULL; +PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays = NULL; +PFNGLISBUFFERPROC glad_glIsBuffer = NULL; +PFNGLISENABLEDPROC glad_glIsEnabled = NULL; +PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; +PFNGLISLISTPROC glad_glIsList = NULL; +PFNGLISPROGRAMPROC glad_glIsProgram = NULL; +PFNGLISQUERYPROC glad_glIsQuery = NULL; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; +PFNGLISSAMPLERPROC glad_glIsSampler = NULL; +PFNGLISSHADERPROC glad_glIsShader = NULL; +PFNGLISSYNCPROC glad_glIsSync = NULL; +PFNGLISTEXTUREPROC glad_glIsTexture = NULL; +PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL; +PFNGLLIGHTMODELFPROC glad_glLightModelf = NULL; +PFNGLLIGHTMODELFVPROC glad_glLightModelfv = NULL; +PFNGLLIGHTMODELIPROC glad_glLightModeli = NULL; +PFNGLLIGHTMODELIVPROC glad_glLightModeliv = NULL; +PFNGLLIGHTFPROC glad_glLightf = NULL; +PFNGLLIGHTFVPROC glad_glLightfv = NULL; +PFNGLLIGHTIPROC glad_glLighti = NULL; +PFNGLLIGHTIVPROC glad_glLightiv = NULL; +PFNGLLINESTIPPLEPROC glad_glLineStipple = NULL; +PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; +PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; +PFNGLLISTBASEPROC glad_glListBase = NULL; +PFNGLLOADIDENTITYPROC glad_glLoadIdentity = NULL; +PFNGLLOADMATRIXDPROC glad_glLoadMatrixd = NULL; +PFNGLLOADMATRIXFPROC glad_glLoadMatrixf = NULL; +PFNGLLOADNAMEPROC glad_glLoadName = NULL; +PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd = NULL; +PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf = NULL; +PFNGLLOGICOPPROC glad_glLogicOp = NULL; +PFNGLMAP1DPROC glad_glMap1d = NULL; +PFNGLMAP1FPROC glad_glMap1f = NULL; +PFNGLMAP2DPROC glad_glMap2d = NULL; +PFNGLMAP2FPROC glad_glMap2f = NULL; +PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL; +PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL; +PFNGLMAPGRID1DPROC glad_glMapGrid1d = NULL; +PFNGLMAPGRID1FPROC glad_glMapGrid1f = NULL; +PFNGLMAPGRID2DPROC glad_glMapGrid2d = NULL; +PFNGLMAPGRID2FPROC glad_glMapGrid2f = NULL; +PFNGLMATERIALFPROC glad_glMaterialf = NULL; +PFNGLMATERIALFVPROC glad_glMaterialfv = NULL; +PFNGLMATERIALIPROC glad_glMateriali = NULL; +PFNGLMATERIALIVPROC glad_glMaterialiv = NULL; +PFNGLMATRIXMODEPROC glad_glMatrixMode = NULL; +PFNGLMULTMATRIXDPROC glad_glMultMatrixd = NULL; +PFNGLMULTMATRIXFPROC glad_glMultMatrixf = NULL; +PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd = NULL; +PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf = NULL; +PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL; +PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL; +PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL; +PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d = NULL; +PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv = NULL; +PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f = NULL; +PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv = NULL; +PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i = NULL; +PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv = NULL; +PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s = NULL; +PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv = NULL; +PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d = NULL; +PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv = NULL; +PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f = NULL; +PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv = NULL; +PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i = NULL; +PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv = NULL; +PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s = NULL; +PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv = NULL; +PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d = NULL; +PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv = NULL; +PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f = NULL; +PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv = NULL; +PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i = NULL; +PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv = NULL; +PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s = NULL; +PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv = NULL; +PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d = NULL; +PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv = NULL; +PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f = NULL; +PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv = NULL; +PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i = NULL; +PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv = NULL; +PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s = NULL; +PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv = NULL; +PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL; +PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL; +PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL; +PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL; +PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL; +PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL; +PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL; +PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL; +PFNGLNEWLISTPROC glad_glNewList = NULL; +PFNGLNORMAL3BPROC glad_glNormal3b = NULL; +PFNGLNORMAL3BVPROC glad_glNormal3bv = NULL; +PFNGLNORMAL3DPROC glad_glNormal3d = NULL; +PFNGLNORMAL3DVPROC glad_glNormal3dv = NULL; +PFNGLNORMAL3FPROC glad_glNormal3f = NULL; +PFNGLNORMAL3FVPROC glad_glNormal3fv = NULL; +PFNGLNORMAL3IPROC glad_glNormal3i = NULL; +PFNGLNORMAL3IVPROC glad_glNormal3iv = NULL; +PFNGLNORMAL3SPROC glad_glNormal3s = NULL; +PFNGLNORMAL3SVPROC glad_glNormal3sv = NULL; +PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL; +PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL; +PFNGLNORMALPOINTERPROC glad_glNormalPointer = NULL; +PFNGLORTHOPROC glad_glOrtho = NULL; +PFNGLPASSTHROUGHPROC glad_glPassThrough = NULL; +PFNGLPIXELMAPFVPROC glad_glPixelMapfv = NULL; +PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv = NULL; +PFNGLPIXELMAPUSVPROC glad_glPixelMapusv = NULL; +PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL; +PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; +PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf = NULL; +PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi = NULL; +PFNGLPIXELZOOMPROC glad_glPixelZoom = NULL; +PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL; +PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL; +PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL; +PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL; +PFNGLPOINTSIZEPROC glad_glPointSize = NULL; +PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; +PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple = NULL; +PFNGLPOPATTRIBPROC glad_glPopAttrib = NULL; +PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib = NULL; +PFNGLPOPMATRIXPROC glad_glPopMatrix = NULL; +PFNGLPOPNAMEPROC glad_glPopName = NULL; +PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL; +PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures = NULL; +PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL; +PFNGLPUSHATTRIBPROC glad_glPushAttrib = NULL; +PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib = NULL; +PFNGLPUSHMATRIXPROC glad_glPushMatrix = NULL; +PFNGLPUSHNAMEPROC glad_glPushName = NULL; +PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL; +PFNGLRASTERPOS2DPROC glad_glRasterPos2d = NULL; +PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv = NULL; +PFNGLRASTERPOS2FPROC glad_glRasterPos2f = NULL; +PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv = NULL; +PFNGLRASTERPOS2IPROC glad_glRasterPos2i = NULL; +PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv = NULL; +PFNGLRASTERPOS2SPROC glad_glRasterPos2s = NULL; +PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv = NULL; +PFNGLRASTERPOS3DPROC glad_glRasterPos3d = NULL; +PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv = NULL; +PFNGLRASTERPOS3FPROC glad_glRasterPos3f = NULL; +PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv = NULL; +PFNGLRASTERPOS3IPROC glad_glRasterPos3i = NULL; +PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv = NULL; +PFNGLRASTERPOS3SPROC glad_glRasterPos3s = NULL; +PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv = NULL; +PFNGLRASTERPOS4DPROC glad_glRasterPos4d = NULL; +PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv = NULL; +PFNGLRASTERPOS4FPROC glad_glRasterPos4f = NULL; +PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv = NULL; +PFNGLRASTERPOS4IPROC glad_glRasterPos4i = NULL; +PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv = NULL; +PFNGLRASTERPOS4SPROC glad_glRasterPos4s = NULL; +PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv = NULL; +PFNGLREADBUFFERPROC glad_glReadBuffer = NULL; +PFNGLREADPIXELSPROC glad_glReadPixels = NULL; +PFNGLRECTDPROC glad_glRectd = NULL; +PFNGLRECTDVPROC glad_glRectdv = NULL; +PFNGLRECTFPROC glad_glRectf = NULL; +PFNGLRECTFVPROC glad_glRectfv = NULL; +PFNGLRECTIPROC glad_glRecti = NULL; +PFNGLRECTIVPROC glad_glRectiv = NULL; +PFNGLRECTSPROC glad_glRects = NULL; +PFNGLRECTSVPROC glad_glRectsv = NULL; +PFNGLRENDERMODEPROC glad_glRenderMode = NULL; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL; +PFNGLROTATEDPROC glad_glRotated = NULL; +PFNGLROTATEFPROC glad_glRotatef = NULL; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; +PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL; +PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL; +PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL; +PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL; +PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL; +PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL; +PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL; +PFNGLSCALEDPROC glad_glScaled = NULL; +PFNGLSCALEFPROC glad_glScalef = NULL; +PFNGLSCISSORPROC glad_glScissor = NULL; +PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b = NULL; +PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv = NULL; +PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d = NULL; +PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv = NULL; +PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f = NULL; +PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv = NULL; +PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i = NULL; +PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv = NULL; +PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s = NULL; +PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv = NULL; +PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub = NULL; +PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv = NULL; +PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui = NULL; +PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv = NULL; +PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us = NULL; +PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv = NULL; +PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL; +PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL; +PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer = NULL; +PFNGLSELECTBUFFERPROC glad_glSelectBuffer = NULL; +PFNGLSHADEMODELPROC glad_glShadeModel = NULL; +PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; +PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; +PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; +PFNGLSTENCILOPPROC glad_glStencilOp = NULL; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; +PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL; +PFNGLTEXCOORD1DPROC glad_glTexCoord1d = NULL; +PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv = NULL; +PFNGLTEXCOORD1FPROC glad_glTexCoord1f = NULL; +PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv = NULL; +PFNGLTEXCOORD1IPROC glad_glTexCoord1i = NULL; +PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv = NULL; +PFNGLTEXCOORD1SPROC glad_glTexCoord1s = NULL; +PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv = NULL; +PFNGLTEXCOORD2DPROC glad_glTexCoord2d = NULL; +PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv = NULL; +PFNGLTEXCOORD2FPROC glad_glTexCoord2f = NULL; +PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv = NULL; +PFNGLTEXCOORD2IPROC glad_glTexCoord2i = NULL; +PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv = NULL; +PFNGLTEXCOORD2SPROC glad_glTexCoord2s = NULL; +PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv = NULL; +PFNGLTEXCOORD3DPROC glad_glTexCoord3d = NULL; +PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv = NULL; +PFNGLTEXCOORD3FPROC glad_glTexCoord3f = NULL; +PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv = NULL; +PFNGLTEXCOORD3IPROC glad_glTexCoord3i = NULL; +PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv = NULL; +PFNGLTEXCOORD3SPROC glad_glTexCoord3s = NULL; +PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv = NULL; +PFNGLTEXCOORD4DPROC glad_glTexCoord4d = NULL; +PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv = NULL; +PFNGLTEXCOORD4FPROC glad_glTexCoord4f = NULL; +PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv = NULL; +PFNGLTEXCOORD4IPROC glad_glTexCoord4i = NULL; +PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv = NULL; +PFNGLTEXCOORD4SPROC glad_glTexCoord4s = NULL; +PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv = NULL; +PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL; +PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL; +PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL; +PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL; +PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL; +PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL; +PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL; +PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL; +PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer = NULL; +PFNGLTEXENVFPROC glad_glTexEnvf = NULL; +PFNGLTEXENVFVPROC glad_glTexEnvfv = NULL; +PFNGLTEXENVIPROC glad_glTexEnvi = NULL; +PFNGLTEXENVIVPROC glad_glTexEnviv = NULL; +PFNGLTEXGENDPROC glad_glTexGend = NULL; +PFNGLTEXGENDVPROC glad_glTexGendv = NULL; +PFNGLTEXGENFPROC glad_glTexGenf = NULL; +PFNGLTEXGENFVPROC glad_glTexGenfv = NULL; +PFNGLTEXGENIPROC glad_glTexGeni = NULL; +PFNGLTEXGENIVPROC glad_glTexGeniv = NULL; +PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; +PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL; +PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL; +PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL; +PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL; +PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; +PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; +PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL; +PFNGLTRANSLATEDPROC glad_glTranslated = NULL; +PFNGLTRANSLATEFPROC glad_glTranslatef = NULL; +PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; +PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; +PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; +PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; +PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL; +PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL; +PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; +PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; +PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; +PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; +PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL; +PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL; +PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; +PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; +PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; +PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; +PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL; +PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL; +PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; +PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; +PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; +PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; +PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL; +PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL; +PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; +PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL; +PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; +PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL; +PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; +PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL; +PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL; +PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL; +PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; +PFNGLVERTEX2DPROC glad_glVertex2d = NULL; +PFNGLVERTEX2DVPROC glad_glVertex2dv = NULL; +PFNGLVERTEX2FPROC glad_glVertex2f = NULL; +PFNGLVERTEX2FVPROC glad_glVertex2fv = NULL; +PFNGLVERTEX2IPROC glad_glVertex2i = NULL; +PFNGLVERTEX2IVPROC glad_glVertex2iv = NULL; +PFNGLVERTEX2SPROC glad_glVertex2s = NULL; +PFNGLVERTEX2SVPROC glad_glVertex2sv = NULL; +PFNGLVERTEX3DPROC glad_glVertex3d = NULL; +PFNGLVERTEX3DVPROC glad_glVertex3dv = NULL; +PFNGLVERTEX3FPROC glad_glVertex3f = NULL; +PFNGLVERTEX3FVPROC glad_glVertex3fv = NULL; +PFNGLVERTEX3IPROC glad_glVertex3i = NULL; +PFNGLVERTEX3IVPROC glad_glVertex3iv = NULL; +PFNGLVERTEX3SPROC glad_glVertex3s = NULL; +PFNGLVERTEX3SVPROC glad_glVertex3sv = NULL; +PFNGLVERTEX4DPROC glad_glVertex4d = NULL; +PFNGLVERTEX4DVPROC glad_glVertex4dv = NULL; +PFNGLVERTEX4FPROC glad_glVertex4f = NULL; +PFNGLVERTEX4FVPROC glad_glVertex4fv = NULL; +PFNGLVERTEX4IPROC glad_glVertex4i = NULL; +PFNGLVERTEX4IVPROC glad_glVertex4iv = NULL; +PFNGLVERTEX4SPROC glad_glVertex4s = NULL; +PFNGLVERTEX4SVPROC glad_glVertex4sv = NULL; +PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL; +PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; +PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL; +PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL; +PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL; +PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; +PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL; +PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL; +PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL; +PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; +PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL; +PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL; +PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL; +PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL; +PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL; +PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL; +PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL; +PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL; +PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL; +PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL; +PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL; +PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; +PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL; +PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL; +PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL; +PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL; +PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL; +PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL; +PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL; +PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL; +PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL; +PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL; +PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL; +PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL; +PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL; +PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL; +PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL; +PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL; +PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL; +PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL; +PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL; +PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL; +PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL; +PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL; +PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL; +PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL; +PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL; +PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL; +PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL; +PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL; +PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL; +PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL; +PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL; +PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL; +PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL; +PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL; +PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL; +PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; +PFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL; +PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL; +PFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL; +PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL; +PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL; +PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL; +PFNGLVERTEXPOINTERPROC glad_glVertexPointer = NULL; +PFNGLVIEWPORTPROC glad_glViewport = NULL; +PFNGLWAITSYNCPROC glad_glWaitSync = NULL; +PFNGLWINDOWPOS2DPROC glad_glWindowPos2d = NULL; +PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv = NULL; +PFNGLWINDOWPOS2FPROC glad_glWindowPos2f = NULL; +PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv = NULL; +PFNGLWINDOWPOS2IPROC glad_glWindowPos2i = NULL; +PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv = NULL; +PFNGLWINDOWPOS2SPROC glad_glWindowPos2s = NULL; +PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv = NULL; +PFNGLWINDOWPOS3DPROC glad_glWindowPos3d = NULL; +PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv = NULL; +PFNGLWINDOWPOS3FPROC glad_glWindowPos3f = NULL; +PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv = NULL; +PFNGLWINDOWPOS3IPROC glad_glWindowPos3i = NULL; +PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv = NULL; +PFNGLWINDOWPOS3SPROC glad_glWindowPos3s = NULL; +PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv = NULL; +static void load_GL_VERSION_1_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_0) return; + glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); + glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); + glad_glHint = (PFNGLHINTPROC)load("glHint"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); + glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize"); + glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode"); + glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); + glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); + glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer"); + glad_glClear = (PFNGLCLEARPROC)load("glClear"); + glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); + glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); + glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); + glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); + glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); + glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); + glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); + glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); + glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); + glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); + glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer"); + glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); + glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev"); + glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); + glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); + glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv"); + glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv"); + glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); + glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange"); + glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); + glad_glNewList = (PFNGLNEWLISTPROC)load("glNewList"); + glad_glEndList = (PFNGLENDLISTPROC)load("glEndList"); + glad_glCallList = (PFNGLCALLLISTPROC)load("glCallList"); + glad_glCallLists = (PFNGLCALLLISTSPROC)load("glCallLists"); + glad_glDeleteLists = (PFNGLDELETELISTSPROC)load("glDeleteLists"); + glad_glGenLists = (PFNGLGENLISTSPROC)load("glGenLists"); + glad_glListBase = (PFNGLLISTBASEPROC)load("glListBase"); + glad_glBegin = (PFNGLBEGINPROC)load("glBegin"); + glad_glBitmap = (PFNGLBITMAPPROC)load("glBitmap"); + glad_glColor3b = (PFNGLCOLOR3BPROC)load("glColor3b"); + glad_glColor3bv = (PFNGLCOLOR3BVPROC)load("glColor3bv"); + glad_glColor3d = (PFNGLCOLOR3DPROC)load("glColor3d"); + glad_glColor3dv = (PFNGLCOLOR3DVPROC)load("glColor3dv"); + glad_glColor3f = (PFNGLCOLOR3FPROC)load("glColor3f"); + glad_glColor3fv = (PFNGLCOLOR3FVPROC)load("glColor3fv"); + glad_glColor3i = (PFNGLCOLOR3IPROC)load("glColor3i"); + glad_glColor3iv = (PFNGLCOLOR3IVPROC)load("glColor3iv"); + glad_glColor3s = (PFNGLCOLOR3SPROC)load("glColor3s"); + glad_glColor3sv = (PFNGLCOLOR3SVPROC)load("glColor3sv"); + glad_glColor3ub = (PFNGLCOLOR3UBPROC)load("glColor3ub"); + glad_glColor3ubv = (PFNGLCOLOR3UBVPROC)load("glColor3ubv"); + glad_glColor3ui = (PFNGLCOLOR3UIPROC)load("glColor3ui"); + glad_glColor3uiv = (PFNGLCOLOR3UIVPROC)load("glColor3uiv"); + glad_glColor3us = (PFNGLCOLOR3USPROC)load("glColor3us"); + glad_glColor3usv = (PFNGLCOLOR3USVPROC)load("glColor3usv"); + glad_glColor4b = (PFNGLCOLOR4BPROC)load("glColor4b"); + glad_glColor4bv = (PFNGLCOLOR4BVPROC)load("glColor4bv"); + glad_glColor4d = (PFNGLCOLOR4DPROC)load("glColor4d"); + glad_glColor4dv = (PFNGLCOLOR4DVPROC)load("glColor4dv"); + glad_glColor4f = (PFNGLCOLOR4FPROC)load("glColor4f"); + glad_glColor4fv = (PFNGLCOLOR4FVPROC)load("glColor4fv"); + glad_glColor4i = (PFNGLCOLOR4IPROC)load("glColor4i"); + glad_glColor4iv = (PFNGLCOLOR4IVPROC)load("glColor4iv"); + glad_glColor4s = (PFNGLCOLOR4SPROC)load("glColor4s"); + glad_glColor4sv = (PFNGLCOLOR4SVPROC)load("glColor4sv"); + glad_glColor4ub = (PFNGLCOLOR4UBPROC)load("glColor4ub"); + glad_glColor4ubv = (PFNGLCOLOR4UBVPROC)load("glColor4ubv"); + glad_glColor4ui = (PFNGLCOLOR4UIPROC)load("glColor4ui"); + glad_glColor4uiv = (PFNGLCOLOR4UIVPROC)load("glColor4uiv"); + glad_glColor4us = (PFNGLCOLOR4USPROC)load("glColor4us"); + glad_glColor4usv = (PFNGLCOLOR4USVPROC)load("glColor4usv"); + glad_glEdgeFlag = (PFNGLEDGEFLAGPROC)load("glEdgeFlag"); + glad_glEdgeFlagv = (PFNGLEDGEFLAGVPROC)load("glEdgeFlagv"); + glad_glEnd = (PFNGLENDPROC)load("glEnd"); + glad_glIndexd = (PFNGLINDEXDPROC)load("glIndexd"); + glad_glIndexdv = (PFNGLINDEXDVPROC)load("glIndexdv"); + glad_glIndexf = (PFNGLINDEXFPROC)load("glIndexf"); + glad_glIndexfv = (PFNGLINDEXFVPROC)load("glIndexfv"); + glad_glIndexi = (PFNGLINDEXIPROC)load("glIndexi"); + glad_glIndexiv = (PFNGLINDEXIVPROC)load("glIndexiv"); + glad_glIndexs = (PFNGLINDEXSPROC)load("glIndexs"); + glad_glIndexsv = (PFNGLINDEXSVPROC)load("glIndexsv"); + glad_glNormal3b = (PFNGLNORMAL3BPROC)load("glNormal3b"); + glad_glNormal3bv = (PFNGLNORMAL3BVPROC)load("glNormal3bv"); + glad_glNormal3d = (PFNGLNORMAL3DPROC)load("glNormal3d"); + glad_glNormal3dv = (PFNGLNORMAL3DVPROC)load("glNormal3dv"); + glad_glNormal3f = (PFNGLNORMAL3FPROC)load("glNormal3f"); + glad_glNormal3fv = (PFNGLNORMAL3FVPROC)load("glNormal3fv"); + glad_glNormal3i = (PFNGLNORMAL3IPROC)load("glNormal3i"); + glad_glNormal3iv = (PFNGLNORMAL3IVPROC)load("glNormal3iv"); + glad_glNormal3s = (PFNGLNORMAL3SPROC)load("glNormal3s"); + glad_glNormal3sv = (PFNGLNORMAL3SVPROC)load("glNormal3sv"); + glad_glRasterPos2d = (PFNGLRASTERPOS2DPROC)load("glRasterPos2d"); + glad_glRasterPos2dv = (PFNGLRASTERPOS2DVPROC)load("glRasterPos2dv"); + glad_glRasterPos2f = (PFNGLRASTERPOS2FPROC)load("glRasterPos2f"); + glad_glRasterPos2fv = (PFNGLRASTERPOS2FVPROC)load("glRasterPos2fv"); + glad_glRasterPos2i = (PFNGLRASTERPOS2IPROC)load("glRasterPos2i"); + glad_glRasterPos2iv = (PFNGLRASTERPOS2IVPROC)load("glRasterPos2iv"); + glad_glRasterPos2s = (PFNGLRASTERPOS2SPROC)load("glRasterPos2s"); + glad_glRasterPos2sv = (PFNGLRASTERPOS2SVPROC)load("glRasterPos2sv"); + glad_glRasterPos3d = (PFNGLRASTERPOS3DPROC)load("glRasterPos3d"); + glad_glRasterPos3dv = (PFNGLRASTERPOS3DVPROC)load("glRasterPos3dv"); + glad_glRasterPos3f = (PFNGLRASTERPOS3FPROC)load("glRasterPos3f"); + glad_glRasterPos3fv = (PFNGLRASTERPOS3FVPROC)load("glRasterPos3fv"); + glad_glRasterPos3i = (PFNGLRASTERPOS3IPROC)load("glRasterPos3i"); + glad_glRasterPos3iv = (PFNGLRASTERPOS3IVPROC)load("glRasterPos3iv"); + glad_glRasterPos3s = (PFNGLRASTERPOS3SPROC)load("glRasterPos3s"); + glad_glRasterPos3sv = (PFNGLRASTERPOS3SVPROC)load("glRasterPos3sv"); + glad_glRasterPos4d = (PFNGLRASTERPOS4DPROC)load("glRasterPos4d"); + glad_glRasterPos4dv = (PFNGLRASTERPOS4DVPROC)load("glRasterPos4dv"); + glad_glRasterPos4f = (PFNGLRASTERPOS4FPROC)load("glRasterPos4f"); + glad_glRasterPos4fv = (PFNGLRASTERPOS4FVPROC)load("glRasterPos4fv"); + glad_glRasterPos4i = (PFNGLRASTERPOS4IPROC)load("glRasterPos4i"); + glad_glRasterPos4iv = (PFNGLRASTERPOS4IVPROC)load("glRasterPos4iv"); + glad_glRasterPos4s = (PFNGLRASTERPOS4SPROC)load("glRasterPos4s"); + glad_glRasterPos4sv = (PFNGLRASTERPOS4SVPROC)load("glRasterPos4sv"); + glad_glRectd = (PFNGLRECTDPROC)load("glRectd"); + glad_glRectdv = (PFNGLRECTDVPROC)load("glRectdv"); + glad_glRectf = (PFNGLRECTFPROC)load("glRectf"); + glad_glRectfv = (PFNGLRECTFVPROC)load("glRectfv"); + glad_glRecti = (PFNGLRECTIPROC)load("glRecti"); + glad_glRectiv = (PFNGLRECTIVPROC)load("glRectiv"); + glad_glRects = (PFNGLRECTSPROC)load("glRects"); + glad_glRectsv = (PFNGLRECTSVPROC)load("glRectsv"); + glad_glTexCoord1d = (PFNGLTEXCOORD1DPROC)load("glTexCoord1d"); + glad_glTexCoord1dv = (PFNGLTEXCOORD1DVPROC)load("glTexCoord1dv"); + glad_glTexCoord1f = (PFNGLTEXCOORD1FPROC)load("glTexCoord1f"); + glad_glTexCoord1fv = (PFNGLTEXCOORD1FVPROC)load("glTexCoord1fv"); + glad_glTexCoord1i = (PFNGLTEXCOORD1IPROC)load("glTexCoord1i"); + glad_glTexCoord1iv = (PFNGLTEXCOORD1IVPROC)load("glTexCoord1iv"); + glad_glTexCoord1s = (PFNGLTEXCOORD1SPROC)load("glTexCoord1s"); + glad_glTexCoord1sv = (PFNGLTEXCOORD1SVPROC)load("glTexCoord1sv"); + glad_glTexCoord2d = (PFNGLTEXCOORD2DPROC)load("glTexCoord2d"); + glad_glTexCoord2dv = (PFNGLTEXCOORD2DVPROC)load("glTexCoord2dv"); + glad_glTexCoord2f = (PFNGLTEXCOORD2FPROC)load("glTexCoord2f"); + glad_glTexCoord2fv = (PFNGLTEXCOORD2FVPROC)load("glTexCoord2fv"); + glad_glTexCoord2i = (PFNGLTEXCOORD2IPROC)load("glTexCoord2i"); + glad_glTexCoord2iv = (PFNGLTEXCOORD2IVPROC)load("glTexCoord2iv"); + glad_glTexCoord2s = (PFNGLTEXCOORD2SPROC)load("glTexCoord2s"); + glad_glTexCoord2sv = (PFNGLTEXCOORD2SVPROC)load("glTexCoord2sv"); + glad_glTexCoord3d = (PFNGLTEXCOORD3DPROC)load("glTexCoord3d"); + glad_glTexCoord3dv = (PFNGLTEXCOORD3DVPROC)load("glTexCoord3dv"); + glad_glTexCoord3f = (PFNGLTEXCOORD3FPROC)load("glTexCoord3f"); + glad_glTexCoord3fv = (PFNGLTEXCOORD3FVPROC)load("glTexCoord3fv"); + glad_glTexCoord3i = (PFNGLTEXCOORD3IPROC)load("glTexCoord3i"); + glad_glTexCoord3iv = (PFNGLTEXCOORD3IVPROC)load("glTexCoord3iv"); + glad_glTexCoord3s = (PFNGLTEXCOORD3SPROC)load("glTexCoord3s"); + glad_glTexCoord3sv = (PFNGLTEXCOORD3SVPROC)load("glTexCoord3sv"); + glad_glTexCoord4d = (PFNGLTEXCOORD4DPROC)load("glTexCoord4d"); + glad_glTexCoord4dv = (PFNGLTEXCOORD4DVPROC)load("glTexCoord4dv"); + glad_glTexCoord4f = (PFNGLTEXCOORD4FPROC)load("glTexCoord4f"); + glad_glTexCoord4fv = (PFNGLTEXCOORD4FVPROC)load("glTexCoord4fv"); + glad_glTexCoord4i = (PFNGLTEXCOORD4IPROC)load("glTexCoord4i"); + glad_glTexCoord4iv = (PFNGLTEXCOORD4IVPROC)load("glTexCoord4iv"); + glad_glTexCoord4s = (PFNGLTEXCOORD4SPROC)load("glTexCoord4s"); + glad_glTexCoord4sv = (PFNGLTEXCOORD4SVPROC)load("glTexCoord4sv"); + glad_glVertex2d = (PFNGLVERTEX2DPROC)load("glVertex2d"); + glad_glVertex2dv = (PFNGLVERTEX2DVPROC)load("glVertex2dv"); + glad_glVertex2f = (PFNGLVERTEX2FPROC)load("glVertex2f"); + glad_glVertex2fv = (PFNGLVERTEX2FVPROC)load("glVertex2fv"); + glad_glVertex2i = (PFNGLVERTEX2IPROC)load("glVertex2i"); + glad_glVertex2iv = (PFNGLVERTEX2IVPROC)load("glVertex2iv"); + glad_glVertex2s = (PFNGLVERTEX2SPROC)load("glVertex2s"); + glad_glVertex2sv = (PFNGLVERTEX2SVPROC)load("glVertex2sv"); + glad_glVertex3d = (PFNGLVERTEX3DPROC)load("glVertex3d"); + glad_glVertex3dv = (PFNGLVERTEX3DVPROC)load("glVertex3dv"); + glad_glVertex3f = (PFNGLVERTEX3FPROC)load("glVertex3f"); + glad_glVertex3fv = (PFNGLVERTEX3FVPROC)load("glVertex3fv"); + glad_glVertex3i = (PFNGLVERTEX3IPROC)load("glVertex3i"); + glad_glVertex3iv = (PFNGLVERTEX3IVPROC)load("glVertex3iv"); + glad_glVertex3s = (PFNGLVERTEX3SPROC)load("glVertex3s"); + glad_glVertex3sv = (PFNGLVERTEX3SVPROC)load("glVertex3sv"); + glad_glVertex4d = (PFNGLVERTEX4DPROC)load("glVertex4d"); + glad_glVertex4dv = (PFNGLVERTEX4DVPROC)load("glVertex4dv"); + glad_glVertex4f = (PFNGLVERTEX4FPROC)load("glVertex4f"); + glad_glVertex4fv = (PFNGLVERTEX4FVPROC)load("glVertex4fv"); + glad_glVertex4i = (PFNGLVERTEX4IPROC)load("glVertex4i"); + glad_glVertex4iv = (PFNGLVERTEX4IVPROC)load("glVertex4iv"); + glad_glVertex4s = (PFNGLVERTEX4SPROC)load("glVertex4s"); + glad_glVertex4sv = (PFNGLVERTEX4SVPROC)load("glVertex4sv"); + glad_glClipPlane = (PFNGLCLIPPLANEPROC)load("glClipPlane"); + glad_glColorMaterial = (PFNGLCOLORMATERIALPROC)load("glColorMaterial"); + glad_glFogf = (PFNGLFOGFPROC)load("glFogf"); + glad_glFogfv = (PFNGLFOGFVPROC)load("glFogfv"); + glad_glFogi = (PFNGLFOGIPROC)load("glFogi"); + glad_glFogiv = (PFNGLFOGIVPROC)load("glFogiv"); + glad_glLightf = (PFNGLLIGHTFPROC)load("glLightf"); + glad_glLightfv = (PFNGLLIGHTFVPROC)load("glLightfv"); + glad_glLighti = (PFNGLLIGHTIPROC)load("glLighti"); + glad_glLightiv = (PFNGLLIGHTIVPROC)load("glLightiv"); + glad_glLightModelf = (PFNGLLIGHTMODELFPROC)load("glLightModelf"); + glad_glLightModelfv = (PFNGLLIGHTMODELFVPROC)load("glLightModelfv"); + glad_glLightModeli = (PFNGLLIGHTMODELIPROC)load("glLightModeli"); + glad_glLightModeliv = (PFNGLLIGHTMODELIVPROC)load("glLightModeliv"); + glad_glLineStipple = (PFNGLLINESTIPPLEPROC)load("glLineStipple"); + glad_glMaterialf = (PFNGLMATERIALFPROC)load("glMaterialf"); + glad_glMaterialfv = (PFNGLMATERIALFVPROC)load("glMaterialfv"); + glad_glMateriali = (PFNGLMATERIALIPROC)load("glMateriali"); + glad_glMaterialiv = (PFNGLMATERIALIVPROC)load("glMaterialiv"); + glad_glPolygonStipple = (PFNGLPOLYGONSTIPPLEPROC)load("glPolygonStipple"); + glad_glShadeModel = (PFNGLSHADEMODELPROC)load("glShadeModel"); + glad_glTexEnvf = (PFNGLTEXENVFPROC)load("glTexEnvf"); + glad_glTexEnvfv = (PFNGLTEXENVFVPROC)load("glTexEnvfv"); + glad_glTexEnvi = (PFNGLTEXENVIPROC)load("glTexEnvi"); + glad_glTexEnviv = (PFNGLTEXENVIVPROC)load("glTexEnviv"); + glad_glTexGend = (PFNGLTEXGENDPROC)load("glTexGend"); + glad_glTexGendv = (PFNGLTEXGENDVPROC)load("glTexGendv"); + glad_glTexGenf = (PFNGLTEXGENFPROC)load("glTexGenf"); + glad_glTexGenfv = (PFNGLTEXGENFVPROC)load("glTexGenfv"); + glad_glTexGeni = (PFNGLTEXGENIPROC)load("glTexGeni"); + glad_glTexGeniv = (PFNGLTEXGENIVPROC)load("glTexGeniv"); + glad_glFeedbackBuffer = (PFNGLFEEDBACKBUFFERPROC)load("glFeedbackBuffer"); + glad_glSelectBuffer = (PFNGLSELECTBUFFERPROC)load("glSelectBuffer"); + glad_glRenderMode = (PFNGLRENDERMODEPROC)load("glRenderMode"); + glad_glInitNames = (PFNGLINITNAMESPROC)load("glInitNames"); + glad_glLoadName = (PFNGLLOADNAMEPROC)load("glLoadName"); + glad_glPassThrough = (PFNGLPASSTHROUGHPROC)load("glPassThrough"); + glad_glPopName = (PFNGLPOPNAMEPROC)load("glPopName"); + glad_glPushName = (PFNGLPUSHNAMEPROC)load("glPushName"); + glad_glClearAccum = (PFNGLCLEARACCUMPROC)load("glClearAccum"); + glad_glClearIndex = (PFNGLCLEARINDEXPROC)load("glClearIndex"); + glad_glIndexMask = (PFNGLINDEXMASKPROC)load("glIndexMask"); + glad_glAccum = (PFNGLACCUMPROC)load("glAccum"); + glad_glPopAttrib = (PFNGLPOPATTRIBPROC)load("glPopAttrib"); + glad_glPushAttrib = (PFNGLPUSHATTRIBPROC)load("glPushAttrib"); + glad_glMap1d = (PFNGLMAP1DPROC)load("glMap1d"); + glad_glMap1f = (PFNGLMAP1FPROC)load("glMap1f"); + glad_glMap2d = (PFNGLMAP2DPROC)load("glMap2d"); + glad_glMap2f = (PFNGLMAP2FPROC)load("glMap2f"); + glad_glMapGrid1d = (PFNGLMAPGRID1DPROC)load("glMapGrid1d"); + glad_glMapGrid1f = (PFNGLMAPGRID1FPROC)load("glMapGrid1f"); + glad_glMapGrid2d = (PFNGLMAPGRID2DPROC)load("glMapGrid2d"); + glad_glMapGrid2f = (PFNGLMAPGRID2FPROC)load("glMapGrid2f"); + glad_glEvalCoord1d = (PFNGLEVALCOORD1DPROC)load("glEvalCoord1d"); + glad_glEvalCoord1dv = (PFNGLEVALCOORD1DVPROC)load("glEvalCoord1dv"); + glad_glEvalCoord1f = (PFNGLEVALCOORD1FPROC)load("glEvalCoord1f"); + glad_glEvalCoord1fv = (PFNGLEVALCOORD1FVPROC)load("glEvalCoord1fv"); + glad_glEvalCoord2d = (PFNGLEVALCOORD2DPROC)load("glEvalCoord2d"); + glad_glEvalCoord2dv = (PFNGLEVALCOORD2DVPROC)load("glEvalCoord2dv"); + glad_glEvalCoord2f = (PFNGLEVALCOORD2FPROC)load("glEvalCoord2f"); + glad_glEvalCoord2fv = (PFNGLEVALCOORD2FVPROC)load("glEvalCoord2fv"); + glad_glEvalMesh1 = (PFNGLEVALMESH1PROC)load("glEvalMesh1"); + glad_glEvalPoint1 = (PFNGLEVALPOINT1PROC)load("glEvalPoint1"); + glad_glEvalMesh2 = (PFNGLEVALMESH2PROC)load("glEvalMesh2"); + glad_glEvalPoint2 = (PFNGLEVALPOINT2PROC)load("glEvalPoint2"); + glad_glAlphaFunc = (PFNGLALPHAFUNCPROC)load("glAlphaFunc"); + glad_glPixelZoom = (PFNGLPIXELZOOMPROC)load("glPixelZoom"); + glad_glPixelTransferf = (PFNGLPIXELTRANSFERFPROC)load("glPixelTransferf"); + glad_glPixelTransferi = (PFNGLPIXELTRANSFERIPROC)load("glPixelTransferi"); + glad_glPixelMapfv = (PFNGLPIXELMAPFVPROC)load("glPixelMapfv"); + glad_glPixelMapuiv = (PFNGLPIXELMAPUIVPROC)load("glPixelMapuiv"); + glad_glPixelMapusv = (PFNGLPIXELMAPUSVPROC)load("glPixelMapusv"); + glad_glCopyPixels = (PFNGLCOPYPIXELSPROC)load("glCopyPixels"); + glad_glDrawPixels = (PFNGLDRAWPIXELSPROC)load("glDrawPixels"); + glad_glGetClipPlane = (PFNGLGETCLIPPLANEPROC)load("glGetClipPlane"); + glad_glGetLightfv = (PFNGLGETLIGHTFVPROC)load("glGetLightfv"); + glad_glGetLightiv = (PFNGLGETLIGHTIVPROC)load("glGetLightiv"); + glad_glGetMapdv = (PFNGLGETMAPDVPROC)load("glGetMapdv"); + glad_glGetMapfv = (PFNGLGETMAPFVPROC)load("glGetMapfv"); + glad_glGetMapiv = (PFNGLGETMAPIVPROC)load("glGetMapiv"); + glad_glGetMaterialfv = (PFNGLGETMATERIALFVPROC)load("glGetMaterialfv"); + glad_glGetMaterialiv = (PFNGLGETMATERIALIVPROC)load("glGetMaterialiv"); + glad_glGetPixelMapfv = (PFNGLGETPIXELMAPFVPROC)load("glGetPixelMapfv"); + glad_glGetPixelMapuiv = (PFNGLGETPIXELMAPUIVPROC)load("glGetPixelMapuiv"); + glad_glGetPixelMapusv = (PFNGLGETPIXELMAPUSVPROC)load("glGetPixelMapusv"); + glad_glGetPolygonStipple = (PFNGLGETPOLYGONSTIPPLEPROC)load("glGetPolygonStipple"); + glad_glGetTexEnvfv = (PFNGLGETTEXENVFVPROC)load("glGetTexEnvfv"); + glad_glGetTexEnviv = (PFNGLGETTEXENVIVPROC)load("glGetTexEnviv"); + glad_glGetTexGendv = (PFNGLGETTEXGENDVPROC)load("glGetTexGendv"); + glad_glGetTexGenfv = (PFNGLGETTEXGENFVPROC)load("glGetTexGenfv"); + glad_glGetTexGeniv = (PFNGLGETTEXGENIVPROC)load("glGetTexGeniv"); + glad_glIsList = (PFNGLISLISTPROC)load("glIsList"); + glad_glFrustum = (PFNGLFRUSTUMPROC)load("glFrustum"); + glad_glLoadIdentity = (PFNGLLOADIDENTITYPROC)load("glLoadIdentity"); + glad_glLoadMatrixf = (PFNGLLOADMATRIXFPROC)load("glLoadMatrixf"); + glad_glLoadMatrixd = (PFNGLLOADMATRIXDPROC)load("glLoadMatrixd"); + glad_glMatrixMode = (PFNGLMATRIXMODEPROC)load("glMatrixMode"); + glad_glMultMatrixf = (PFNGLMULTMATRIXFPROC)load("glMultMatrixf"); + glad_glMultMatrixd = (PFNGLMULTMATRIXDPROC)load("glMultMatrixd"); + glad_glOrtho = (PFNGLORTHOPROC)load("glOrtho"); + glad_glPopMatrix = (PFNGLPOPMATRIXPROC)load("glPopMatrix"); + glad_glPushMatrix = (PFNGLPUSHMATRIXPROC)load("glPushMatrix"); + glad_glRotated = (PFNGLROTATEDPROC)load("glRotated"); + glad_glRotatef = (PFNGLROTATEFPROC)load("glRotatef"); + glad_glScaled = (PFNGLSCALEDPROC)load("glScaled"); + glad_glScalef = (PFNGLSCALEFPROC)load("glScalef"); + glad_glTranslated = (PFNGLTRANSLATEDPROC)load("glTranslated"); + glad_glTranslatef = (PFNGLTRANSLATEFPROC)load("glTranslatef"); +} +static void load_GL_VERSION_1_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_1) return; + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); + glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); + glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); + glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); + glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); + glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); + glad_glArrayElement = (PFNGLARRAYELEMENTPROC)load("glArrayElement"); + glad_glColorPointer = (PFNGLCOLORPOINTERPROC)load("glColorPointer"); + glad_glDisableClientState = (PFNGLDISABLECLIENTSTATEPROC)load("glDisableClientState"); + glad_glEdgeFlagPointer = (PFNGLEDGEFLAGPOINTERPROC)load("glEdgeFlagPointer"); + glad_glEnableClientState = (PFNGLENABLECLIENTSTATEPROC)load("glEnableClientState"); + glad_glIndexPointer = (PFNGLINDEXPOINTERPROC)load("glIndexPointer"); + glad_glInterleavedArrays = (PFNGLINTERLEAVEDARRAYSPROC)load("glInterleavedArrays"); + glad_glNormalPointer = (PFNGLNORMALPOINTERPROC)load("glNormalPointer"); + glad_glTexCoordPointer = (PFNGLTEXCOORDPOINTERPROC)load("glTexCoordPointer"); + glad_glVertexPointer = (PFNGLVERTEXPOINTERPROC)load("glVertexPointer"); + glad_glAreTexturesResident = (PFNGLARETEXTURESRESIDENTPROC)load("glAreTexturesResident"); + glad_glPrioritizeTextures = (PFNGLPRIORITIZETEXTURESPROC)load("glPrioritizeTextures"); + glad_glIndexub = (PFNGLINDEXUBPROC)load("glIndexub"); + glad_glIndexubv = (PFNGLINDEXUBVPROC)load("glIndexubv"); + glad_glPopClientAttrib = (PFNGLPOPCLIENTATTRIBPROC)load("glPopClientAttrib"); + glad_glPushClientAttrib = (PFNGLPUSHCLIENTATTRIBPROC)load("glPushClientAttrib"); +} +static void load_GL_VERSION_1_2(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_2) return; + glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements"); + glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D"); + glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D"); + glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D"); +} +static void load_GL_VERSION_1_3(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_3) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); + glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); + glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D"); + glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); + glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D"); + glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage"); + glad_glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)load("glClientActiveTexture"); + glad_glMultiTexCoord1d = (PFNGLMULTITEXCOORD1DPROC)load("glMultiTexCoord1d"); + glad_glMultiTexCoord1dv = (PFNGLMULTITEXCOORD1DVPROC)load("glMultiTexCoord1dv"); + glad_glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC)load("glMultiTexCoord1f"); + glad_glMultiTexCoord1fv = (PFNGLMULTITEXCOORD1FVPROC)load("glMultiTexCoord1fv"); + glad_glMultiTexCoord1i = (PFNGLMULTITEXCOORD1IPROC)load("glMultiTexCoord1i"); + glad_glMultiTexCoord1iv = (PFNGLMULTITEXCOORD1IVPROC)load("glMultiTexCoord1iv"); + glad_glMultiTexCoord1s = (PFNGLMULTITEXCOORD1SPROC)load("glMultiTexCoord1s"); + glad_glMultiTexCoord1sv = (PFNGLMULTITEXCOORD1SVPROC)load("glMultiTexCoord1sv"); + glad_glMultiTexCoord2d = (PFNGLMULTITEXCOORD2DPROC)load("glMultiTexCoord2d"); + glad_glMultiTexCoord2dv = (PFNGLMULTITEXCOORD2DVPROC)load("glMultiTexCoord2dv"); + glad_glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC)load("glMultiTexCoord2f"); + glad_glMultiTexCoord2fv = (PFNGLMULTITEXCOORD2FVPROC)load("glMultiTexCoord2fv"); + glad_glMultiTexCoord2i = (PFNGLMULTITEXCOORD2IPROC)load("glMultiTexCoord2i"); + glad_glMultiTexCoord2iv = (PFNGLMULTITEXCOORD2IVPROC)load("glMultiTexCoord2iv"); + glad_glMultiTexCoord2s = (PFNGLMULTITEXCOORD2SPROC)load("glMultiTexCoord2s"); + glad_glMultiTexCoord2sv = (PFNGLMULTITEXCOORD2SVPROC)load("glMultiTexCoord2sv"); + glad_glMultiTexCoord3d = (PFNGLMULTITEXCOORD3DPROC)load("glMultiTexCoord3d"); + glad_glMultiTexCoord3dv = (PFNGLMULTITEXCOORD3DVPROC)load("glMultiTexCoord3dv"); + glad_glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC)load("glMultiTexCoord3f"); + glad_glMultiTexCoord3fv = (PFNGLMULTITEXCOORD3FVPROC)load("glMultiTexCoord3fv"); + glad_glMultiTexCoord3i = (PFNGLMULTITEXCOORD3IPROC)load("glMultiTexCoord3i"); + glad_glMultiTexCoord3iv = (PFNGLMULTITEXCOORD3IVPROC)load("glMultiTexCoord3iv"); + glad_glMultiTexCoord3s = (PFNGLMULTITEXCOORD3SPROC)load("glMultiTexCoord3s"); + glad_glMultiTexCoord3sv = (PFNGLMULTITEXCOORD3SVPROC)load("glMultiTexCoord3sv"); + glad_glMultiTexCoord4d = (PFNGLMULTITEXCOORD4DPROC)load("glMultiTexCoord4d"); + glad_glMultiTexCoord4dv = (PFNGLMULTITEXCOORD4DVPROC)load("glMultiTexCoord4dv"); + glad_glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC)load("glMultiTexCoord4f"); + glad_glMultiTexCoord4fv = (PFNGLMULTITEXCOORD4FVPROC)load("glMultiTexCoord4fv"); + glad_glMultiTexCoord4i = (PFNGLMULTITEXCOORD4IPROC)load("glMultiTexCoord4i"); + glad_glMultiTexCoord4iv = (PFNGLMULTITEXCOORD4IVPROC)load("glMultiTexCoord4iv"); + glad_glMultiTexCoord4s = (PFNGLMULTITEXCOORD4SPROC)load("glMultiTexCoord4s"); + glad_glMultiTexCoord4sv = (PFNGLMULTITEXCOORD4SVPROC)load("glMultiTexCoord4sv"); + glad_glLoadTransposeMatrixf = (PFNGLLOADTRANSPOSEMATRIXFPROC)load("glLoadTransposeMatrixf"); + glad_glLoadTransposeMatrixd = (PFNGLLOADTRANSPOSEMATRIXDPROC)load("glLoadTransposeMatrixd"); + glad_glMultTransposeMatrixf = (PFNGLMULTTRANSPOSEMATRIXFPROC)load("glMultTransposeMatrixf"); + glad_glMultTransposeMatrixd = (PFNGLMULTTRANSPOSEMATRIXDPROC)load("glMultTransposeMatrixd"); +} +static void load_GL_VERSION_1_4(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_4) return; + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); + glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays"); + glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements"); + glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf"); + glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv"); + glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri"); + glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv"); + glad_glFogCoordf = (PFNGLFOGCOORDFPROC)load("glFogCoordf"); + glad_glFogCoordfv = (PFNGLFOGCOORDFVPROC)load("glFogCoordfv"); + glad_glFogCoordd = (PFNGLFOGCOORDDPROC)load("glFogCoordd"); + glad_glFogCoorddv = (PFNGLFOGCOORDDVPROC)load("glFogCoorddv"); + glad_glFogCoordPointer = (PFNGLFOGCOORDPOINTERPROC)load("glFogCoordPointer"); + glad_glSecondaryColor3b = (PFNGLSECONDARYCOLOR3BPROC)load("glSecondaryColor3b"); + glad_glSecondaryColor3bv = (PFNGLSECONDARYCOLOR3BVPROC)load("glSecondaryColor3bv"); + glad_glSecondaryColor3d = (PFNGLSECONDARYCOLOR3DPROC)load("glSecondaryColor3d"); + glad_glSecondaryColor3dv = (PFNGLSECONDARYCOLOR3DVPROC)load("glSecondaryColor3dv"); + glad_glSecondaryColor3f = (PFNGLSECONDARYCOLOR3FPROC)load("glSecondaryColor3f"); + glad_glSecondaryColor3fv = (PFNGLSECONDARYCOLOR3FVPROC)load("glSecondaryColor3fv"); + glad_glSecondaryColor3i = (PFNGLSECONDARYCOLOR3IPROC)load("glSecondaryColor3i"); + glad_glSecondaryColor3iv = (PFNGLSECONDARYCOLOR3IVPROC)load("glSecondaryColor3iv"); + glad_glSecondaryColor3s = (PFNGLSECONDARYCOLOR3SPROC)load("glSecondaryColor3s"); + glad_glSecondaryColor3sv = (PFNGLSECONDARYCOLOR3SVPROC)load("glSecondaryColor3sv"); + glad_glSecondaryColor3ub = (PFNGLSECONDARYCOLOR3UBPROC)load("glSecondaryColor3ub"); + glad_glSecondaryColor3ubv = (PFNGLSECONDARYCOLOR3UBVPROC)load("glSecondaryColor3ubv"); + glad_glSecondaryColor3ui = (PFNGLSECONDARYCOLOR3UIPROC)load("glSecondaryColor3ui"); + glad_glSecondaryColor3uiv = (PFNGLSECONDARYCOLOR3UIVPROC)load("glSecondaryColor3uiv"); + glad_glSecondaryColor3us = (PFNGLSECONDARYCOLOR3USPROC)load("glSecondaryColor3us"); + glad_glSecondaryColor3usv = (PFNGLSECONDARYCOLOR3USVPROC)load("glSecondaryColor3usv"); + glad_glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)load("glSecondaryColorPointer"); + glad_glWindowPos2d = (PFNGLWINDOWPOS2DPROC)load("glWindowPos2d"); + glad_glWindowPos2dv = (PFNGLWINDOWPOS2DVPROC)load("glWindowPos2dv"); + glad_glWindowPos2f = (PFNGLWINDOWPOS2FPROC)load("glWindowPos2f"); + glad_glWindowPos2fv = (PFNGLWINDOWPOS2FVPROC)load("glWindowPos2fv"); + glad_glWindowPos2i = (PFNGLWINDOWPOS2IPROC)load("glWindowPos2i"); + glad_glWindowPos2iv = (PFNGLWINDOWPOS2IVPROC)load("glWindowPos2iv"); + glad_glWindowPos2s = (PFNGLWINDOWPOS2SPROC)load("glWindowPos2s"); + glad_glWindowPos2sv = (PFNGLWINDOWPOS2SVPROC)load("glWindowPos2sv"); + glad_glWindowPos3d = (PFNGLWINDOWPOS3DPROC)load("glWindowPos3d"); + glad_glWindowPos3dv = (PFNGLWINDOWPOS3DVPROC)load("glWindowPos3dv"); + glad_glWindowPos3f = (PFNGLWINDOWPOS3FPROC)load("glWindowPos3f"); + glad_glWindowPos3fv = (PFNGLWINDOWPOS3FVPROC)load("glWindowPos3fv"); + glad_glWindowPos3i = (PFNGLWINDOWPOS3IPROC)load("glWindowPos3i"); + glad_glWindowPos3iv = (PFNGLWINDOWPOS3IVPROC)load("glWindowPos3iv"); + glad_glWindowPos3s = (PFNGLWINDOWPOS3SPROC)load("glWindowPos3s"); + glad_glWindowPos3sv = (PFNGLWINDOWPOS3SVPROC)load("glWindowPos3sv"); + glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); +} +static void load_GL_VERSION_1_5(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_5) return; + glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries"); + glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries"); + glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery"); + glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery"); + glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery"); + glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv"); + glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv"); + glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); + glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); + glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); + glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData"); + glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer"); + glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); + glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); +} +static void load_GL_VERSION_2_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_0) return; + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); + glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); + glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); + glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); + glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); + glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); + glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d"); + glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); + glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s"); + glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv"); + glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d"); + glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); + glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s"); + glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv"); + glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d"); + glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); + glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s"); + glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv"); + glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv"); + glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv"); + glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv"); + glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub"); + glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv"); + glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv"); + glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv"); + glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv"); + glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d"); + glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); + glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv"); + glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s"); + glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv"); + glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv"); + glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv"); + glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); +} +static void load_GL_VERSION_2_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_1) return; + glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv"); + glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv"); + glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv"); + glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv"); + glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv"); + glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv"); +} +static void load_GL_VERSION_3_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_0) return; + glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski"); + glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); + glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei"); + glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei"); + glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi"); + glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback"); + glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings"); + glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying"); + glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor"); + glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender"); + glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender"); + glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer"); + glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv"); + glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv"); + glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i"); + glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i"); + glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i"); + glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i"); + glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui"); + glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui"); + glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui"); + glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui"); + glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv"); + glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv"); + glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv"); + glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv"); + glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv"); + glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv"); + glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv"); + glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv"); + glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv"); + glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv"); + glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv"); + glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv"); + glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv"); + glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation"); + glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation"); + glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui"); + glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui"); + glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui"); + glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui"); + glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv"); + glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv"); + glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv"); + glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv"); + glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv"); + glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv"); + glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv"); + glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv"); + glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv"); + glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv"); + glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv"); + glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi"); + glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); + glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); + glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); + glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); + glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); + glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); + glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange"); + glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange"); + glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); + glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); + glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); + glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); +} +static void load_GL_VERSION_3_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_1) return; + glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced"); + glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced"); + glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer"); + glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load("glPrimitiveRestartIndex"); + glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData"); + glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices"); + glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv"); + glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName"); + glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex"); + glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv"); + glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName"); + glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); +} +static void load_GL_VERSION_3_2(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_2) return; + glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex"); + glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex"); + glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex"); + glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load("glMultiDrawElementsBaseVertex"); + glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load("glProvokingVertex"); + glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync"); + glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync"); + glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync"); + glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync"); + glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync"); + glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v"); + glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv"); + glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v"); + glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v"); + glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture"); + glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample"); + glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample"); + glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv"); + glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski"); +} +static void load_GL_VERSION_3_3(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_3) return; + glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)load("glBindFragDataLocationIndexed"); + glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC)load("glGetFragDataIndex"); + glad_glGenSamplers = (PFNGLGENSAMPLERSPROC)load("glGenSamplers"); + glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)load("glDeleteSamplers"); + glad_glIsSampler = (PFNGLISSAMPLERPROC)load("glIsSampler"); + glad_glBindSampler = (PFNGLBINDSAMPLERPROC)load("glBindSampler"); + glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)load("glSamplerParameteri"); + glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)load("glSamplerParameteriv"); + glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)load("glSamplerParameterf"); + glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)load("glSamplerParameterfv"); + glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)load("glSamplerParameterIiv"); + glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)load("glSamplerParameterIuiv"); + glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load("glGetSamplerParameteriv"); + glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)load("glGetSamplerParameterIiv"); + glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load("glGetSamplerParameterfv"); + glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)load("glGetSamplerParameterIuiv"); + glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC)load("glQueryCounter"); + glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC)load("glGetQueryObjecti64v"); + glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC)load("glGetQueryObjectui64v"); + glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load("glVertexAttribDivisor"); + glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC)load("glVertexAttribP1ui"); + glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC)load("glVertexAttribP1uiv"); + glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC)load("glVertexAttribP2ui"); + glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC)load("glVertexAttribP2uiv"); + glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC)load("glVertexAttribP3ui"); + glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC)load("glVertexAttribP3uiv"); + glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC)load("glVertexAttribP4ui"); + glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC)load("glVertexAttribP4uiv"); + glad_glVertexP2ui = (PFNGLVERTEXP2UIPROC)load("glVertexP2ui"); + glad_glVertexP2uiv = (PFNGLVERTEXP2UIVPROC)load("glVertexP2uiv"); + glad_glVertexP3ui = (PFNGLVERTEXP3UIPROC)load("glVertexP3ui"); + glad_glVertexP3uiv = (PFNGLVERTEXP3UIVPROC)load("glVertexP3uiv"); + glad_glVertexP4ui = (PFNGLVERTEXP4UIPROC)load("glVertexP4ui"); + glad_glVertexP4uiv = (PFNGLVERTEXP4UIVPROC)load("glVertexP4uiv"); + glad_glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC)load("glTexCoordP1ui"); + glad_glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC)load("glTexCoordP1uiv"); + glad_glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC)load("glTexCoordP2ui"); + glad_glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC)load("glTexCoordP2uiv"); + glad_glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC)load("glTexCoordP3ui"); + glad_glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC)load("glTexCoordP3uiv"); + glad_glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC)load("glTexCoordP4ui"); + glad_glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC)load("glTexCoordP4uiv"); + glad_glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC)load("glMultiTexCoordP1ui"); + glad_glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC)load("glMultiTexCoordP1uiv"); + glad_glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC)load("glMultiTexCoordP2ui"); + glad_glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC)load("glMultiTexCoordP2uiv"); + glad_glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC)load("glMultiTexCoordP3ui"); + glad_glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC)load("glMultiTexCoordP3uiv"); + glad_glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC)load("glMultiTexCoordP4ui"); + glad_glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC)load("glMultiTexCoordP4uiv"); + glad_glNormalP3ui = (PFNGLNORMALP3UIPROC)load("glNormalP3ui"); + glad_glNormalP3uiv = (PFNGLNORMALP3UIVPROC)load("glNormalP3uiv"); + glad_glColorP3ui = (PFNGLCOLORP3UIPROC)load("glColorP3ui"); + glad_glColorP3uiv = (PFNGLCOLORP3UIVPROC)load("glColorP3uiv"); + glad_glColorP4ui = (PFNGLCOLORP4UIPROC)load("glColorP4ui"); + glad_glColorP4uiv = (PFNGLCOLORP4UIVPROC)load("glColorP4uiv"); + glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui"); + glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv"); +} +static int find_extensionsGL(void) { + if (!get_exts()) return 0; + (void)&has_ext; + free_exts(); + return 1; +} + +static void find_coreGL(void) { + + /* Thank you @elmindreda + * /~https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + * /~https://github.com/glfw/glfw/blob/master/src/context.c#L36 + */ + int i, major, minor; + + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + NULL + }; + + version = (const char*) glGetString(GL_VERSION); + if (!version) return; + + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + +/* PR #18 */ +#ifdef _MSC_VER + sscanf_s(version, "%d.%d", &major, &minor); +#else + sscanf(version, "%d.%d", &major, &minor); +#endif + + GLVersion.major = major; GLVersion.minor = minor; + max_loaded_major = major; max_loaded_minor = minor; + GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; + GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; + GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; + GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; + GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; + GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; + GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; + GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3; + if (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 3)) { + max_loaded_major = 3; + max_loaded_minor = 3; + } +} + +int gladLoadGLLoader(GLADloadproc load) { + GLVersion.major = 0; GLVersion.minor = 0; + glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + if(glGetString == NULL) return 0; + if(glGetString(GL_VERSION) == NULL) return 0; + find_coreGL(); + load_GL_VERSION_1_0(load); + load_GL_VERSION_1_1(load); + load_GL_VERSION_1_2(load); + load_GL_VERSION_1_3(load); + load_GL_VERSION_1_4(load); + load_GL_VERSION_1_5(load); + load_GL_VERSION_2_0(load); + load_GL_VERSION_2_1(load); + load_GL_VERSION_3_0(load); + load_GL_VERSION_3_1(load); + load_GL_VERSION_3_2(load); + load_GL_VERSION_3_3(load); + + if (!find_extensionsGL()) return 0; + return GLVersion.major != 0 || GLVersion.minor != 0; +} + diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/glad/glad.h b/Extern/3rdParty/OptiX/Linux/SDK/support/glad/glad.h new file mode 100644 index 00000000..f872fb25 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/glad/glad.h @@ -0,0 +1,3617 @@ +/* + + OpenGL loader generated by glad 0.1.29 on Fri Mar 22 21:20:36 2019. + + Language/Generator: C/C++ + Specification: gl + APIs: gl=3.3 + Profile: compatibility + Extensions: + + Loader: True + Local files: False + Omit khrplatform: False + Reproducible: False + + Commandline: + --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="" + Online: + https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3 +*/ + + +#ifndef __glad_h_ +#define __glad_h_ + +#ifdef __gl_h_ +#error OpenGL header already included, remove this include, glad already provides it +#endif +#define __gl_h_ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#ifndef NOMINMAX +#define NOMINMAX 1 +#endif +#include +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY APIENTRY +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct gladGLversionStruct { + int major; + int minor; +}; + +typedef void* (* GLADloadproc)(const char *name); + +#ifndef GLAPI +# if defined(GLAD_GLAPI_EXPORT) +# if defined(_WIN32) || defined(__CYGWIN__) +# if defined(GLAD_GLAPI_EXPORT_BUILD) +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllexport)) extern +# else +# define GLAPI __declspec(dllexport) extern +# endif +# else +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllimport)) extern +# else +# define GLAPI __declspec(dllimport) extern +# endif +# endif +# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) +# define GLAPI __attribute__ ((visibility ("default"))) extern +# else +# define GLAPI extern +# endif +# else +# define GLAPI extern +# endif +#endif + +GLAPI struct gladGLversionStruct GLVersion; + +GLAPI int gladLoadGL(void); + +GLAPI int gladLoadGLLoader(GLADloadproc); + +#include +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef khronos_int8_t GLbyte; +typedef khronos_uint8_t GLubyte; +typedef khronos_int16_t GLshort; +typedef khronos_uint16_t GLushort; +typedef int GLint; +typedef unsigned int GLuint; +typedef khronos_int32_t GLclampx; +typedef int GLsizei; +typedef khronos_float_t GLfloat; +typedef khronos_float_t GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglClientBufferEXT; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef khronos_uint16_t GLhalf; +typedef khronos_uint16_t GLhalfARB; +typedef khronos_int32_t GLfixed; +typedef khronos_intptr_t GLintptr; +typedef khronos_intptr_t GLintptrARB; +typedef khronos_ssize_t GLsizeiptr; +typedef khronos_ssize_t GLsizeiptrARB; +typedef khronos_int64_t GLint64; +typedef khronos_int64_t GLint64EXT; +typedef khronos_uint64_t GLuint64; +typedef khronos_uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +typedef void (APIENTRY *GLVULKANPROCNV)(void); +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_QUADS 0x0007 +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_NONE 0 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_VIEWPORT 0x0BA2 +#define GL_DITHER 0x0BD0 +#define GL_BLEND_DST 0x0BE0 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND 0x0BE2 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_READ_BUFFER 0x0C02 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_STEREO 0x0C33 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_CLEAR 0x1500 +#define GL_AND 0x1501 +#define GL_AND_REVERSE 0x1502 +#define GL_COPY 0x1503 +#define GL_AND_INVERTED 0x1504 +#define GL_NOOP 0x1505 +#define GL_XOR 0x1506 +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_EQUIV 0x1509 +#define GL_INVERT 0x150A +#define GL_OR_REVERSE 0x150B +#define GL_COPY_INVERTED 0x150C +#define GL_OR_INVERTED 0x150D +#define GL_NAND 0x150E +#define GL_SET 0x150F +#define GL_TEXTURE 0x1702 +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_STENCIL_INDEX 0x1901 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_REPEAT 0x2901 +#define GL_CURRENT_BIT 0x00000001 +#define GL_POINT_BIT 0x00000002 +#define GL_LINE_BIT 0x00000004 +#define GL_POLYGON_BIT 0x00000008 +#define GL_POLYGON_STIPPLE_BIT 0x00000010 +#define GL_PIXEL_MODE_BIT 0x00000020 +#define GL_LIGHTING_BIT 0x00000040 +#define GL_FOG_BIT 0x00000080 +#define GL_ACCUM_BUFFER_BIT 0x00000200 +#define GL_VIEWPORT_BIT 0x00000800 +#define GL_TRANSFORM_BIT 0x00001000 +#define GL_ENABLE_BIT 0x00002000 +#define GL_HINT_BIT 0x00008000 +#define GL_EVAL_BIT 0x00010000 +#define GL_LIST_BIT 0x00020000 +#define GL_TEXTURE_BIT 0x00040000 +#define GL_SCISSOR_BIT 0x00080000 +#define GL_ALL_ATTRIB_BITS 0xFFFFFFFF +#define GL_QUAD_STRIP 0x0008 +#define GL_POLYGON 0x0009 +#define GL_ACCUM 0x0100 +#define GL_LOAD 0x0101 +#define GL_RETURN 0x0102 +#define GL_MULT 0x0103 +#define GL_ADD 0x0104 +#define GL_AUX0 0x0409 +#define GL_AUX1 0x040A +#define GL_AUX2 0x040B +#define GL_AUX3 0x040C +#define GL_2D 0x0600 +#define GL_3D 0x0601 +#define GL_3D_COLOR 0x0602 +#define GL_3D_COLOR_TEXTURE 0x0603 +#define GL_4D_COLOR_TEXTURE 0x0604 +#define GL_PASS_THROUGH_TOKEN 0x0700 +#define GL_POINT_TOKEN 0x0701 +#define GL_LINE_TOKEN 0x0702 +#define GL_POLYGON_TOKEN 0x0703 +#define GL_BITMAP_TOKEN 0x0704 +#define GL_DRAW_PIXEL_TOKEN 0x0705 +#define GL_COPY_PIXEL_TOKEN 0x0706 +#define GL_LINE_RESET_TOKEN 0x0707 +#define GL_EXP 0x0800 +#define GL_EXP2 0x0801 +#define GL_COEFF 0x0A00 +#define GL_ORDER 0x0A01 +#define GL_DOMAIN 0x0A02 +#define GL_PIXEL_MAP_I_TO_I 0x0C70 +#define GL_PIXEL_MAP_S_TO_S 0x0C71 +#define GL_PIXEL_MAP_I_TO_R 0x0C72 +#define GL_PIXEL_MAP_I_TO_G 0x0C73 +#define GL_PIXEL_MAP_I_TO_B 0x0C74 +#define GL_PIXEL_MAP_I_TO_A 0x0C75 +#define GL_PIXEL_MAP_R_TO_R 0x0C76 +#define GL_PIXEL_MAP_G_TO_G 0x0C77 +#define GL_PIXEL_MAP_B_TO_B 0x0C78 +#define GL_PIXEL_MAP_A_TO_A 0x0C79 +#define GL_CURRENT_COLOR 0x0B00 +#define GL_CURRENT_INDEX 0x0B01 +#define GL_CURRENT_NORMAL 0x0B02 +#define GL_CURRENT_TEXTURE_COORDS 0x0B03 +#define GL_CURRENT_RASTER_COLOR 0x0B04 +#define GL_CURRENT_RASTER_INDEX 0x0B05 +#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 +#define GL_CURRENT_RASTER_POSITION 0x0B07 +#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08 +#define GL_CURRENT_RASTER_DISTANCE 0x0B09 +#define GL_POINT_SMOOTH 0x0B10 +#define GL_LINE_STIPPLE 0x0B24 +#define GL_LINE_STIPPLE_PATTERN 0x0B25 +#define GL_LINE_STIPPLE_REPEAT 0x0B26 +#define GL_LIST_MODE 0x0B30 +#define GL_MAX_LIST_NESTING 0x0B31 +#define GL_LIST_BASE 0x0B32 +#define GL_LIST_INDEX 0x0B33 +#define GL_POLYGON_STIPPLE 0x0B42 +#define GL_EDGE_FLAG 0x0B43 +#define GL_LIGHTING 0x0B50 +#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 +#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 +#define GL_LIGHT_MODEL_AMBIENT 0x0B53 +#define GL_SHADE_MODEL 0x0B54 +#define GL_COLOR_MATERIAL_FACE 0x0B55 +#define GL_COLOR_MATERIAL_PARAMETER 0x0B56 +#define GL_COLOR_MATERIAL 0x0B57 +#define GL_FOG 0x0B60 +#define GL_FOG_INDEX 0x0B61 +#define GL_FOG_DENSITY 0x0B62 +#define GL_FOG_START 0x0B63 +#define GL_FOG_END 0x0B64 +#define GL_FOG_MODE 0x0B65 +#define GL_FOG_COLOR 0x0B66 +#define GL_ACCUM_CLEAR_VALUE 0x0B80 +#define GL_MATRIX_MODE 0x0BA0 +#define GL_NORMALIZE 0x0BA1 +#define GL_MODELVIEW_STACK_DEPTH 0x0BA3 +#define GL_PROJECTION_STACK_DEPTH 0x0BA4 +#define GL_TEXTURE_STACK_DEPTH 0x0BA5 +#define GL_MODELVIEW_MATRIX 0x0BA6 +#define GL_PROJECTION_MATRIX 0x0BA7 +#define GL_TEXTURE_MATRIX 0x0BA8 +#define GL_ATTRIB_STACK_DEPTH 0x0BB0 +#define GL_ALPHA_TEST 0x0BC0 +#define GL_ALPHA_TEST_FUNC 0x0BC1 +#define GL_ALPHA_TEST_REF 0x0BC2 +#define GL_LOGIC_OP 0x0BF1 +#define GL_AUX_BUFFERS 0x0C00 +#define GL_INDEX_CLEAR_VALUE 0x0C20 +#define GL_INDEX_WRITEMASK 0x0C21 +#define GL_INDEX_MODE 0x0C30 +#define GL_RGBA_MODE 0x0C31 +#define GL_RENDER_MODE 0x0C40 +#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 +#define GL_POINT_SMOOTH_HINT 0x0C51 +#define GL_FOG_HINT 0x0C54 +#define GL_TEXTURE_GEN_S 0x0C60 +#define GL_TEXTURE_GEN_T 0x0C61 +#define GL_TEXTURE_GEN_R 0x0C62 +#define GL_TEXTURE_GEN_Q 0x0C63 +#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 +#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 +#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 +#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 +#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 +#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 +#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 +#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 +#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 +#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 +#define GL_MAP_COLOR 0x0D10 +#define GL_MAP_STENCIL 0x0D11 +#define GL_INDEX_SHIFT 0x0D12 +#define GL_INDEX_OFFSET 0x0D13 +#define GL_RED_SCALE 0x0D14 +#define GL_RED_BIAS 0x0D15 +#define GL_ZOOM_X 0x0D16 +#define GL_ZOOM_Y 0x0D17 +#define GL_GREEN_SCALE 0x0D18 +#define GL_GREEN_BIAS 0x0D19 +#define GL_BLUE_SCALE 0x0D1A +#define GL_BLUE_BIAS 0x0D1B +#define GL_ALPHA_SCALE 0x0D1C +#define GL_ALPHA_BIAS 0x0D1D +#define GL_DEPTH_SCALE 0x0D1E +#define GL_DEPTH_BIAS 0x0D1F +#define GL_MAX_EVAL_ORDER 0x0D30 +#define GL_MAX_LIGHTS 0x0D31 +#define GL_MAX_CLIP_PLANES 0x0D32 +#define GL_MAX_PIXEL_MAP_TABLE 0x0D34 +#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 +#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 +#define GL_MAX_NAME_STACK_DEPTH 0x0D37 +#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 +#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 +#define GL_INDEX_BITS 0x0D51 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_ALPHA_BITS 0x0D55 +#define GL_DEPTH_BITS 0x0D56 +#define GL_STENCIL_BITS 0x0D57 +#define GL_ACCUM_RED_BITS 0x0D58 +#define GL_ACCUM_GREEN_BITS 0x0D59 +#define GL_ACCUM_BLUE_BITS 0x0D5A +#define GL_ACCUM_ALPHA_BITS 0x0D5B +#define GL_NAME_STACK_DEPTH 0x0D70 +#define GL_AUTO_NORMAL 0x0D80 +#define GL_MAP1_COLOR_4 0x0D90 +#define GL_MAP1_INDEX 0x0D91 +#define GL_MAP1_NORMAL 0x0D92 +#define GL_MAP1_TEXTURE_COORD_1 0x0D93 +#define GL_MAP1_TEXTURE_COORD_2 0x0D94 +#define GL_MAP1_TEXTURE_COORD_3 0x0D95 +#define GL_MAP1_TEXTURE_COORD_4 0x0D96 +#define GL_MAP1_VERTEX_3 0x0D97 +#define GL_MAP1_VERTEX_4 0x0D98 +#define GL_MAP2_COLOR_4 0x0DB0 +#define GL_MAP2_INDEX 0x0DB1 +#define GL_MAP2_NORMAL 0x0DB2 +#define GL_MAP2_TEXTURE_COORD_1 0x0DB3 +#define GL_MAP2_TEXTURE_COORD_2 0x0DB4 +#define GL_MAP2_TEXTURE_COORD_3 0x0DB5 +#define GL_MAP2_TEXTURE_COORD_4 0x0DB6 +#define GL_MAP2_VERTEX_3 0x0DB7 +#define GL_MAP2_VERTEX_4 0x0DB8 +#define GL_MAP1_GRID_DOMAIN 0x0DD0 +#define GL_MAP1_GRID_SEGMENTS 0x0DD1 +#define GL_MAP2_GRID_DOMAIN 0x0DD2 +#define GL_MAP2_GRID_SEGMENTS 0x0DD3 +#define GL_TEXTURE_COMPONENTS 0x1003 +#define GL_TEXTURE_BORDER 0x1005 +#define GL_AMBIENT 0x1200 +#define GL_DIFFUSE 0x1201 +#define GL_SPECULAR 0x1202 +#define GL_POSITION 0x1203 +#define GL_SPOT_DIRECTION 0x1204 +#define GL_SPOT_EXPONENT 0x1205 +#define GL_SPOT_CUTOFF 0x1206 +#define GL_CONSTANT_ATTENUATION 0x1207 +#define GL_LINEAR_ATTENUATION 0x1208 +#define GL_QUADRATIC_ATTENUATION 0x1209 +#define GL_COMPILE 0x1300 +#define GL_COMPILE_AND_EXECUTE 0x1301 +#define GL_2_BYTES 0x1407 +#define GL_3_BYTES 0x1408 +#define GL_4_BYTES 0x1409 +#define GL_EMISSION 0x1600 +#define GL_SHININESS 0x1601 +#define GL_AMBIENT_AND_DIFFUSE 0x1602 +#define GL_COLOR_INDEXES 0x1603 +#define GL_MODELVIEW 0x1700 +#define GL_PROJECTION 0x1701 +#define GL_COLOR_INDEX 0x1900 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_BITMAP 0x1A00 +#define GL_RENDER 0x1C00 +#define GL_FEEDBACK 0x1C01 +#define GL_SELECT 0x1C02 +#define GL_FLAT 0x1D00 +#define GL_SMOOTH 0x1D01 +#define GL_S 0x2000 +#define GL_T 0x2001 +#define GL_R 0x2002 +#define GL_Q 0x2003 +#define GL_MODULATE 0x2100 +#define GL_DECAL 0x2101 +#define GL_TEXTURE_ENV_MODE 0x2200 +#define GL_TEXTURE_ENV_COLOR 0x2201 +#define GL_TEXTURE_ENV 0x2300 +#define GL_EYE_LINEAR 0x2400 +#define GL_OBJECT_LINEAR 0x2401 +#define GL_SPHERE_MAP 0x2402 +#define GL_TEXTURE_GEN_MODE 0x2500 +#define GL_OBJECT_PLANE 0x2501 +#define GL_EYE_PLANE 0x2502 +#define GL_CLAMP 0x2900 +#define GL_CLIP_PLANE0 0x3000 +#define GL_CLIP_PLANE1 0x3001 +#define GL_CLIP_PLANE2 0x3002 +#define GL_CLIP_PLANE3 0x3003 +#define GL_CLIP_PLANE4 0x3004 +#define GL_CLIP_PLANE5 0x3005 +#define GL_LIGHT0 0x4000 +#define GL_LIGHT1 0x4001 +#define GL_LIGHT2 0x4002 +#define GL_LIGHT3 0x4003 +#define GL_LIGHT4 0x4004 +#define GL_LIGHT5 0x4005 +#define GL_LIGHT6 0x4006 +#define GL_LIGHT7 0x4007 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_DOUBLE 0x140A +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 +#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 +#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF +#define GL_VERTEX_ARRAY_POINTER 0x808E +#define GL_NORMAL_ARRAY_POINTER 0x808F +#define GL_COLOR_ARRAY_POINTER 0x8090 +#define GL_INDEX_ARRAY_POINTER 0x8091 +#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 +#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093 +#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 +#define GL_SELECTION_BUFFER_POINTER 0x0DF3 +#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 +#define GL_INDEX_LOGIC_OP 0x0BF1 +#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B +#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 +#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 +#define GL_SELECTION_BUFFER_SIZE 0x0DF4 +#define GL_VERTEX_ARRAY 0x8074 +#define GL_NORMAL_ARRAY 0x8075 +#define GL_COLOR_ARRAY 0x8076 +#define GL_INDEX_ARRAY 0x8077 +#define GL_TEXTURE_COORD_ARRAY 0x8078 +#define GL_EDGE_FLAG_ARRAY 0x8079 +#define GL_VERTEX_ARRAY_SIZE 0x807A +#define GL_VERTEX_ARRAY_TYPE 0x807B +#define GL_VERTEX_ARRAY_STRIDE 0x807C +#define GL_NORMAL_ARRAY_TYPE 0x807E +#define GL_NORMAL_ARRAY_STRIDE 0x807F +#define GL_COLOR_ARRAY_SIZE 0x8081 +#define GL_COLOR_ARRAY_TYPE 0x8082 +#define GL_COLOR_ARRAY_STRIDE 0x8083 +#define GL_INDEX_ARRAY_TYPE 0x8085 +#define GL_INDEX_ARRAY_STRIDE 0x8086 +#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 +#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 +#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A +#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C +#define GL_TEXTURE_LUMINANCE_SIZE 0x8060 +#define GL_TEXTURE_INTENSITY_SIZE 0x8061 +#define GL_TEXTURE_PRIORITY 0x8066 +#define GL_TEXTURE_RESIDENT 0x8067 +#define GL_ALPHA4 0x803B +#define GL_ALPHA8 0x803C +#define GL_ALPHA12 0x803D +#define GL_ALPHA16 0x803E +#define GL_LUMINANCE4 0x803F +#define GL_LUMINANCE8 0x8040 +#define GL_LUMINANCE12 0x8041 +#define GL_LUMINANCE16 0x8042 +#define GL_LUMINANCE4_ALPHA4 0x8043 +#define GL_LUMINANCE6_ALPHA2 0x8044 +#define GL_LUMINANCE8_ALPHA8 0x8045 +#define GL_LUMINANCE12_ALPHA4 0x8046 +#define GL_LUMINANCE12_ALPHA12 0x8047 +#define GL_LUMINANCE16_ALPHA16 0x8048 +#define GL_INTENSITY 0x8049 +#define GL_INTENSITY4 0x804A +#define GL_INTENSITY8 0x804B +#define GL_INTENSITY12 0x804C +#define GL_INTENSITY16 0x804D +#define GL_V2F 0x2A20 +#define GL_V3F 0x2A21 +#define GL_C4UB_V2F 0x2A22 +#define GL_C4UB_V3F 0x2A23 +#define GL_C3F_V3F 0x2A24 +#define GL_N3F_V3F 0x2A25 +#define GL_C4F_N3F_V3F 0x2A26 +#define GL_T2F_V3F 0x2A27 +#define GL_T4F_V4F 0x2A28 +#define GL_T2F_C4UB_V3F 0x2A29 +#define GL_T2F_C3F_V3F 0x2A2A +#define GL_T2F_N3F_V3F 0x2A2B +#define GL_T2F_C4F_N3F_V3F 0x2A2C +#define GL_T4F_C4F_N3F_V4F 0x2A2D +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_RESCALE_NORMAL 0x803A +#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 +#define GL_SINGLE_COLOR 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR 0x81FA +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 +#define GL_MAX_TEXTURE_UNITS 0x84E2 +#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 +#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 +#define GL_MULTISAMPLE_BIT 0x20000000 +#define GL_NORMAL_MAP 0x8511 +#define GL_REFLECTION_MAP 0x8512 +#define GL_COMPRESSED_ALPHA 0x84E9 +#define GL_COMPRESSED_LUMINANCE 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB +#define GL_COMPRESSED_INTENSITY 0x84EC +#define GL_COMBINE 0x8570 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_SOURCE0_RGB 0x8580 +#define GL_SOURCE1_RGB 0x8581 +#define GL_SOURCE2_RGB 0x8582 +#define GL_SOURCE0_ALPHA 0x8588 +#define GL_SOURCE1_ALPHA 0x8589 +#define GL_SOURCE2_ALPHA 0x858A +#define GL_OPERAND0_RGB 0x8590 +#define GL_OPERAND1_RGB 0x8591 +#define GL_OPERAND2_RGB 0x8592 +#define GL_OPERAND0_ALPHA 0x8598 +#define GL_OPERAND1_ALPHA 0x8599 +#define GL_OPERAND2_ALPHA 0x859A +#define GL_RGB_SCALE 0x8573 +#define GL_ADD_SIGNED 0x8574 +#define GL_INTERPOLATE 0x8575 +#define GL_SUBTRACT 0x84E7 +#define GL_CONSTANT 0x8576 +#define GL_PRIMARY_COLOR 0x8577 +#define GL_PREVIOUS 0x8578 +#define GL_DOT3_RGB 0x86AE +#define GL_DOT3_RGBA 0x86AF +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_POINT_SIZE_MIN 0x8126 +#define GL_POINT_SIZE_MAX 0x8127 +#define GL_POINT_DISTANCE_ATTENUATION 0x8129 +#define GL_GENERATE_MIPMAP 0x8191 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_FOG_COORDINATE_SOURCE 0x8450 +#define GL_FOG_COORDINATE 0x8451 +#define GL_FRAGMENT_DEPTH 0x8452 +#define GL_CURRENT_FOG_COORDINATE 0x8453 +#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 +#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 +#define GL_FOG_COORDINATE_ARRAY 0x8457 +#define GL_COLOR_SUM 0x8458 +#define GL_CURRENT_SECONDARY_COLOR 0x8459 +#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A +#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B +#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C +#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D +#define GL_SECONDARY_COLOR_ARRAY 0x845E +#define GL_TEXTURE_FILTER_CONTROL 0x8500 +#define GL_DEPTH_TEXTURE_MODE 0x884B +#define GL_COMPARE_R_TO_TEXTURE 0x884E +#define GL_BLEND_COLOR 0x8005 +#define GL_BLEND_EQUATION 0x8009 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_FUNC_SUBTRACT 0x800A +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E +#define GL_FOG_COORD_SRC 0x8450 +#define GL_FOG_COORD 0x8451 +#define GL_CURRENT_FOG_COORD 0x8453 +#define GL_FOG_COORD_ARRAY_TYPE 0x8454 +#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORD_ARRAY_POINTER 0x8456 +#define GL_FOG_COORD_ARRAY 0x8457 +#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D +#define GL_SRC0_RGB 0x8580 +#define GL_SRC1_RGB 0x8581 +#define GL_SRC2_RGB 0x8582 +#define GL_SRC0_ALPHA 0x8588 +#define GL_SRC2_ALPHA 0x858A +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define GL_POINT_SPRITE 0x8861 +#define GL_COORD_REPLACE 0x8862 +#define GL_MAX_TEXTURE_COORDS 0x8871 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F +#define GL_SLUMINANCE_ALPHA 0x8C44 +#define GL_SLUMINANCE8_ALPHA8 0x8C45 +#define GL_SLUMINANCE 0x8C46 +#define GL_SLUMINANCE8 0x8C47 +#define GL_COMPRESSED_SLUMINANCE 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_COLOR_ATTACHMENT16 0x8CF0 +#define GL_COLOR_ATTACHMENT17 0x8CF1 +#define GL_COLOR_ATTACHMENT18 0x8CF2 +#define GL_COLOR_ATTACHMENT19 0x8CF3 +#define GL_COLOR_ATTACHMENT20 0x8CF4 +#define GL_COLOR_ATTACHMENT21 0x8CF5 +#define GL_COLOR_ATTACHMENT22 0x8CF6 +#define GL_COLOR_ATTACHMENT23 0x8CF7 +#define GL_COLOR_ATTACHMENT24 0x8CF8 +#define GL_COLOR_ATTACHMENT25 0x8CF9 +#define GL_COLOR_ATTACHMENT26 0x8CFA +#define GL_COLOR_ATTACHMENT27 0x8CFB +#define GL_COLOR_ATTACHMENT28 0x8CFC +#define GL_COLOR_ATTACHMENT29 0x8CFD +#define GL_COLOR_ATTACHMENT30 0x8CFE +#define GL_COLOR_ATTACHMENT31 0x8CFF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_INDEX 0x8222 +#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 +#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_HALF_FLOAT 0x140B +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#define GL_CLAMP_VERTEX_COLOR 0x891A +#define GL_CLAMP_FRAGMENT_COLOR 0x891B +#define GL_ALPHA_INTEGER 0x8D97 +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_INVALID_INDEX 0xFFFFFFFF +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_DEPTH_CLAMP 0x864F +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE +#define GL_SRC1_COLOR 0x88F9 +#define GL_ONE_MINUS_SRC1_COLOR 0x88FA +#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC +#define GL_ANY_SAMPLES_PASSED 0x8C2F +#define GL_SAMPLER_BINDING 0x8919 +#define GL_RGB10_A2UI 0x906F +#define GL_TEXTURE_SWIZZLE_R 0x8E42 +#define GL_TEXTURE_SWIZZLE_G 0x8E43 +#define GL_TEXTURE_SWIZZLE_B 0x8E44 +#define GL_TEXTURE_SWIZZLE_A 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 +#define GL_TIME_ELAPSED 0x88BF +#define GL_TIMESTAMP 0x8E28 +#define GL_INT_2_10_10_10_REV 0x8D9F +#ifndef GL_VERSION_1_0 +#define GL_VERSION_1_0 1 +GLAPI int GLAD_GL_VERSION_1_0; +typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode); +GLAPI PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode); +GLAPI PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode); +GLAPI PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width); +GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size); +GLAPI PFNGLPOINTSIZEPROC glad_glPointSize; +#define glPointSize glad_glPointSize +typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); +GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode; +#define glPolygonMode glad_glPolygonMode +typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat *params); +GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint *params); +GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D; +#define glTexImage1D glad_glTexImage1D +typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf); +GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer; +#define glDrawBuffer glad_glDrawBuffer +typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask); +GLAPI PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s); +GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth); +GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth; +#define glClearDepth glad_glClearDepth +typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask); +GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GLAPI PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag); +GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap); +GLAPI PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap); +GLAPI PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +typedef void (APIENTRYP PFNGLFINISHPROC)(void); +GLAPI PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +typedef void (APIENTRYP PFNGLFLUSHPROC)(void); +GLAPI PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode); +GLAPI PFNGLLOGICOPPROC glad_glLogicOp; +#define glLogicOp glad_glLogicOp +typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +GLAPI PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func); +GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref; +#define glPixelStoref glad_glPixelStoref +typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src); +GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer; +#define glReadBuffer glad_glReadBuffer +typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); +GLAPI PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean *data); +GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble *data); +GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev; +#define glGetDoublev glad_glGetDoublev +typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(void); +GLAPI PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat *data); +GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint *data); +GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name); +GLAPI PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage; +#define glGetTexImage glad_glGetTexImage +typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; +#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; +#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv +typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap); +GLAPI PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f); +GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange; +#define glDepthRange glad_glDepthRange +typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport +typedef void (APIENTRYP PFNGLNEWLISTPROC)(GLuint list, GLenum mode); +GLAPI PFNGLNEWLISTPROC glad_glNewList; +#define glNewList glad_glNewList +typedef void (APIENTRYP PFNGLENDLISTPROC)(void); +GLAPI PFNGLENDLISTPROC glad_glEndList; +#define glEndList glad_glEndList +typedef void (APIENTRYP PFNGLCALLLISTPROC)(GLuint list); +GLAPI PFNGLCALLLISTPROC glad_glCallList; +#define glCallList glad_glCallList +typedef void (APIENTRYP PFNGLCALLLISTSPROC)(GLsizei n, GLenum type, const void *lists); +GLAPI PFNGLCALLLISTSPROC glad_glCallLists; +#define glCallLists glad_glCallLists +typedef void (APIENTRYP PFNGLDELETELISTSPROC)(GLuint list, GLsizei range); +GLAPI PFNGLDELETELISTSPROC glad_glDeleteLists; +#define glDeleteLists glad_glDeleteLists +typedef GLuint (APIENTRYP PFNGLGENLISTSPROC)(GLsizei range); +GLAPI PFNGLGENLISTSPROC glad_glGenLists; +#define glGenLists glad_glGenLists +typedef void (APIENTRYP PFNGLLISTBASEPROC)(GLuint base); +GLAPI PFNGLLISTBASEPROC glad_glListBase; +#define glListBase glad_glListBase +typedef void (APIENTRYP PFNGLBEGINPROC)(GLenum mode); +GLAPI PFNGLBEGINPROC glad_glBegin; +#define glBegin glad_glBegin +typedef void (APIENTRYP PFNGLBITMAPPROC)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +GLAPI PFNGLBITMAPPROC glad_glBitmap; +#define glBitmap glad_glBitmap +typedef void (APIENTRYP PFNGLCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); +GLAPI PFNGLCOLOR3BPROC glad_glColor3b; +#define glColor3b glad_glColor3b +typedef void (APIENTRYP PFNGLCOLOR3BVPROC)(const GLbyte *v); +GLAPI PFNGLCOLOR3BVPROC glad_glColor3bv; +#define glColor3bv glad_glColor3bv +typedef void (APIENTRYP PFNGLCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); +GLAPI PFNGLCOLOR3DPROC glad_glColor3d; +#define glColor3d glad_glColor3d +typedef void (APIENTRYP PFNGLCOLOR3DVPROC)(const GLdouble *v); +GLAPI PFNGLCOLOR3DVPROC glad_glColor3dv; +#define glColor3dv glad_glColor3dv +typedef void (APIENTRYP PFNGLCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); +GLAPI PFNGLCOLOR3FPROC glad_glColor3f; +#define glColor3f glad_glColor3f +typedef void (APIENTRYP PFNGLCOLOR3FVPROC)(const GLfloat *v); +GLAPI PFNGLCOLOR3FVPROC glad_glColor3fv; +#define glColor3fv glad_glColor3fv +typedef void (APIENTRYP PFNGLCOLOR3IPROC)(GLint red, GLint green, GLint blue); +GLAPI PFNGLCOLOR3IPROC glad_glColor3i; +#define glColor3i glad_glColor3i +typedef void (APIENTRYP PFNGLCOLOR3IVPROC)(const GLint *v); +GLAPI PFNGLCOLOR3IVPROC glad_glColor3iv; +#define glColor3iv glad_glColor3iv +typedef void (APIENTRYP PFNGLCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); +GLAPI PFNGLCOLOR3SPROC glad_glColor3s; +#define glColor3s glad_glColor3s +typedef void (APIENTRYP PFNGLCOLOR3SVPROC)(const GLshort *v); +GLAPI PFNGLCOLOR3SVPROC glad_glColor3sv; +#define glColor3sv glad_glColor3sv +typedef void (APIENTRYP PFNGLCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); +GLAPI PFNGLCOLOR3UBPROC glad_glColor3ub; +#define glColor3ub glad_glColor3ub +typedef void (APIENTRYP PFNGLCOLOR3UBVPROC)(const GLubyte *v); +GLAPI PFNGLCOLOR3UBVPROC glad_glColor3ubv; +#define glColor3ubv glad_glColor3ubv +typedef void (APIENTRYP PFNGLCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); +GLAPI PFNGLCOLOR3UIPROC glad_glColor3ui; +#define glColor3ui glad_glColor3ui +typedef void (APIENTRYP PFNGLCOLOR3UIVPROC)(const GLuint *v); +GLAPI PFNGLCOLOR3UIVPROC glad_glColor3uiv; +#define glColor3uiv glad_glColor3uiv +typedef void (APIENTRYP PFNGLCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); +GLAPI PFNGLCOLOR3USPROC glad_glColor3us; +#define glColor3us glad_glColor3us +typedef void (APIENTRYP PFNGLCOLOR3USVPROC)(const GLushort *v); +GLAPI PFNGLCOLOR3USVPROC glad_glColor3usv; +#define glColor3usv glad_glColor3usv +typedef void (APIENTRYP PFNGLCOLOR4BPROC)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +GLAPI PFNGLCOLOR4BPROC glad_glColor4b; +#define glColor4b glad_glColor4b +typedef void (APIENTRYP PFNGLCOLOR4BVPROC)(const GLbyte *v); +GLAPI PFNGLCOLOR4BVPROC glad_glColor4bv; +#define glColor4bv glad_glColor4bv +typedef void (APIENTRYP PFNGLCOLOR4DPROC)(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +GLAPI PFNGLCOLOR4DPROC glad_glColor4d; +#define glColor4d glad_glColor4d +typedef void (APIENTRYP PFNGLCOLOR4DVPROC)(const GLdouble *v); +GLAPI PFNGLCOLOR4DVPROC glad_glColor4dv; +#define glColor4dv glad_glColor4dv +typedef void (APIENTRYP PFNGLCOLOR4FPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCOLOR4FPROC glad_glColor4f; +#define glColor4f glad_glColor4f +typedef void (APIENTRYP PFNGLCOLOR4FVPROC)(const GLfloat *v); +GLAPI PFNGLCOLOR4FVPROC glad_glColor4fv; +#define glColor4fv glad_glColor4fv +typedef void (APIENTRYP PFNGLCOLOR4IPROC)(GLint red, GLint green, GLint blue, GLint alpha); +GLAPI PFNGLCOLOR4IPROC glad_glColor4i; +#define glColor4i glad_glColor4i +typedef void (APIENTRYP PFNGLCOLOR4IVPROC)(const GLint *v); +GLAPI PFNGLCOLOR4IVPROC glad_glColor4iv; +#define glColor4iv glad_glColor4iv +typedef void (APIENTRYP PFNGLCOLOR4SPROC)(GLshort red, GLshort green, GLshort blue, GLshort alpha); +GLAPI PFNGLCOLOR4SPROC glad_glColor4s; +#define glColor4s glad_glColor4s +typedef void (APIENTRYP PFNGLCOLOR4SVPROC)(const GLshort *v); +GLAPI PFNGLCOLOR4SVPROC glad_glColor4sv; +#define glColor4sv glad_glColor4sv +typedef void (APIENTRYP PFNGLCOLOR4UBPROC)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +GLAPI PFNGLCOLOR4UBPROC glad_glColor4ub; +#define glColor4ub glad_glColor4ub +typedef void (APIENTRYP PFNGLCOLOR4UBVPROC)(const GLubyte *v); +GLAPI PFNGLCOLOR4UBVPROC glad_glColor4ubv; +#define glColor4ubv glad_glColor4ubv +typedef void (APIENTRYP PFNGLCOLOR4UIPROC)(GLuint red, GLuint green, GLuint blue, GLuint alpha); +GLAPI PFNGLCOLOR4UIPROC glad_glColor4ui; +#define glColor4ui glad_glColor4ui +typedef void (APIENTRYP PFNGLCOLOR4UIVPROC)(const GLuint *v); +GLAPI PFNGLCOLOR4UIVPROC glad_glColor4uiv; +#define glColor4uiv glad_glColor4uiv +typedef void (APIENTRYP PFNGLCOLOR4USPROC)(GLushort red, GLushort green, GLushort blue, GLushort alpha); +GLAPI PFNGLCOLOR4USPROC glad_glColor4us; +#define glColor4us glad_glColor4us +typedef void (APIENTRYP PFNGLCOLOR4USVPROC)(const GLushort *v); +GLAPI PFNGLCOLOR4USVPROC glad_glColor4usv; +#define glColor4usv glad_glColor4usv +typedef void (APIENTRYP PFNGLEDGEFLAGPROC)(GLboolean flag); +GLAPI PFNGLEDGEFLAGPROC glad_glEdgeFlag; +#define glEdgeFlag glad_glEdgeFlag +typedef void (APIENTRYP PFNGLEDGEFLAGVPROC)(const GLboolean *flag); +GLAPI PFNGLEDGEFLAGVPROC glad_glEdgeFlagv; +#define glEdgeFlagv glad_glEdgeFlagv +typedef void (APIENTRYP PFNGLENDPROC)(void); +GLAPI PFNGLENDPROC glad_glEnd; +#define glEnd glad_glEnd +typedef void (APIENTRYP PFNGLINDEXDPROC)(GLdouble c); +GLAPI PFNGLINDEXDPROC glad_glIndexd; +#define glIndexd glad_glIndexd +typedef void (APIENTRYP PFNGLINDEXDVPROC)(const GLdouble *c); +GLAPI PFNGLINDEXDVPROC glad_glIndexdv; +#define glIndexdv glad_glIndexdv +typedef void (APIENTRYP PFNGLINDEXFPROC)(GLfloat c); +GLAPI PFNGLINDEXFPROC glad_glIndexf; +#define glIndexf glad_glIndexf +typedef void (APIENTRYP PFNGLINDEXFVPROC)(const GLfloat *c); +GLAPI PFNGLINDEXFVPROC glad_glIndexfv; +#define glIndexfv glad_glIndexfv +typedef void (APIENTRYP PFNGLINDEXIPROC)(GLint c); +GLAPI PFNGLINDEXIPROC glad_glIndexi; +#define glIndexi glad_glIndexi +typedef void (APIENTRYP PFNGLINDEXIVPROC)(const GLint *c); +GLAPI PFNGLINDEXIVPROC glad_glIndexiv; +#define glIndexiv glad_glIndexiv +typedef void (APIENTRYP PFNGLINDEXSPROC)(GLshort c); +GLAPI PFNGLINDEXSPROC glad_glIndexs; +#define glIndexs glad_glIndexs +typedef void (APIENTRYP PFNGLINDEXSVPROC)(const GLshort *c); +GLAPI PFNGLINDEXSVPROC glad_glIndexsv; +#define glIndexsv glad_glIndexsv +typedef void (APIENTRYP PFNGLNORMAL3BPROC)(GLbyte nx, GLbyte ny, GLbyte nz); +GLAPI PFNGLNORMAL3BPROC glad_glNormal3b; +#define glNormal3b glad_glNormal3b +typedef void (APIENTRYP PFNGLNORMAL3BVPROC)(const GLbyte *v); +GLAPI PFNGLNORMAL3BVPROC glad_glNormal3bv; +#define glNormal3bv glad_glNormal3bv +typedef void (APIENTRYP PFNGLNORMAL3DPROC)(GLdouble nx, GLdouble ny, GLdouble nz); +GLAPI PFNGLNORMAL3DPROC glad_glNormal3d; +#define glNormal3d glad_glNormal3d +typedef void (APIENTRYP PFNGLNORMAL3DVPROC)(const GLdouble *v); +GLAPI PFNGLNORMAL3DVPROC glad_glNormal3dv; +#define glNormal3dv glad_glNormal3dv +typedef void (APIENTRYP PFNGLNORMAL3FPROC)(GLfloat nx, GLfloat ny, GLfloat nz); +GLAPI PFNGLNORMAL3FPROC glad_glNormal3f; +#define glNormal3f glad_glNormal3f +typedef void (APIENTRYP PFNGLNORMAL3FVPROC)(const GLfloat *v); +GLAPI PFNGLNORMAL3FVPROC glad_glNormal3fv; +#define glNormal3fv glad_glNormal3fv +typedef void (APIENTRYP PFNGLNORMAL3IPROC)(GLint nx, GLint ny, GLint nz); +GLAPI PFNGLNORMAL3IPROC glad_glNormal3i; +#define glNormal3i glad_glNormal3i +typedef void (APIENTRYP PFNGLNORMAL3IVPROC)(const GLint *v); +GLAPI PFNGLNORMAL3IVPROC glad_glNormal3iv; +#define glNormal3iv glad_glNormal3iv +typedef void (APIENTRYP PFNGLNORMAL3SPROC)(GLshort nx, GLshort ny, GLshort nz); +GLAPI PFNGLNORMAL3SPROC glad_glNormal3s; +#define glNormal3s glad_glNormal3s +typedef void (APIENTRYP PFNGLNORMAL3SVPROC)(const GLshort *v); +GLAPI PFNGLNORMAL3SVPROC glad_glNormal3sv; +#define glNormal3sv glad_glNormal3sv +typedef void (APIENTRYP PFNGLRASTERPOS2DPROC)(GLdouble x, GLdouble y); +GLAPI PFNGLRASTERPOS2DPROC glad_glRasterPos2d; +#define glRasterPos2d glad_glRasterPos2d +typedef void (APIENTRYP PFNGLRASTERPOS2DVPROC)(const GLdouble *v); +GLAPI PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv; +#define glRasterPos2dv glad_glRasterPos2dv +typedef void (APIENTRYP PFNGLRASTERPOS2FPROC)(GLfloat x, GLfloat y); +GLAPI PFNGLRASTERPOS2FPROC glad_glRasterPos2f; +#define glRasterPos2f glad_glRasterPos2f +typedef void (APIENTRYP PFNGLRASTERPOS2FVPROC)(const GLfloat *v); +GLAPI PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv; +#define glRasterPos2fv glad_glRasterPos2fv +typedef void (APIENTRYP PFNGLRASTERPOS2IPROC)(GLint x, GLint y); +GLAPI PFNGLRASTERPOS2IPROC glad_glRasterPos2i; +#define glRasterPos2i glad_glRasterPos2i +typedef void (APIENTRYP PFNGLRASTERPOS2IVPROC)(const GLint *v); +GLAPI PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv; +#define glRasterPos2iv glad_glRasterPos2iv +typedef void (APIENTRYP PFNGLRASTERPOS2SPROC)(GLshort x, GLshort y); +GLAPI PFNGLRASTERPOS2SPROC glad_glRasterPos2s; +#define glRasterPos2s glad_glRasterPos2s +typedef void (APIENTRYP PFNGLRASTERPOS2SVPROC)(const GLshort *v); +GLAPI PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv; +#define glRasterPos2sv glad_glRasterPos2sv +typedef void (APIENTRYP PFNGLRASTERPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLRASTERPOS3DPROC glad_glRasterPos3d; +#define glRasterPos3d glad_glRasterPos3d +typedef void (APIENTRYP PFNGLRASTERPOS3DVPROC)(const GLdouble *v); +GLAPI PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv; +#define glRasterPos3dv glad_glRasterPos3dv +typedef void (APIENTRYP PFNGLRASTERPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLRASTERPOS3FPROC glad_glRasterPos3f; +#define glRasterPos3f glad_glRasterPos3f +typedef void (APIENTRYP PFNGLRASTERPOS3FVPROC)(const GLfloat *v); +GLAPI PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv; +#define glRasterPos3fv glad_glRasterPos3fv +typedef void (APIENTRYP PFNGLRASTERPOS3IPROC)(GLint x, GLint y, GLint z); +GLAPI PFNGLRASTERPOS3IPROC glad_glRasterPos3i; +#define glRasterPos3i glad_glRasterPos3i +typedef void (APIENTRYP PFNGLRASTERPOS3IVPROC)(const GLint *v); +GLAPI PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv; +#define glRasterPos3iv glad_glRasterPos3iv +typedef void (APIENTRYP PFNGLRASTERPOS3SPROC)(GLshort x, GLshort y, GLshort z); +GLAPI PFNGLRASTERPOS3SPROC glad_glRasterPos3s; +#define glRasterPos3s glad_glRasterPos3s +typedef void (APIENTRYP PFNGLRASTERPOS3SVPROC)(const GLshort *v); +GLAPI PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv; +#define glRasterPos3sv glad_glRasterPos3sv +typedef void (APIENTRYP PFNGLRASTERPOS4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLRASTERPOS4DPROC glad_glRasterPos4d; +#define glRasterPos4d glad_glRasterPos4d +typedef void (APIENTRYP PFNGLRASTERPOS4DVPROC)(const GLdouble *v); +GLAPI PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv; +#define glRasterPos4dv glad_glRasterPos4dv +typedef void (APIENTRYP PFNGLRASTERPOS4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLRASTERPOS4FPROC glad_glRasterPos4f; +#define glRasterPos4f glad_glRasterPos4f +typedef void (APIENTRYP PFNGLRASTERPOS4FVPROC)(const GLfloat *v); +GLAPI PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv; +#define glRasterPos4fv glad_glRasterPos4fv +typedef void (APIENTRYP PFNGLRASTERPOS4IPROC)(GLint x, GLint y, GLint z, GLint w); +GLAPI PFNGLRASTERPOS4IPROC glad_glRasterPos4i; +#define glRasterPos4i glad_glRasterPos4i +typedef void (APIENTRYP PFNGLRASTERPOS4IVPROC)(const GLint *v); +GLAPI PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv; +#define glRasterPos4iv glad_glRasterPos4iv +typedef void (APIENTRYP PFNGLRASTERPOS4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI PFNGLRASTERPOS4SPROC glad_glRasterPos4s; +#define glRasterPos4s glad_glRasterPos4s +typedef void (APIENTRYP PFNGLRASTERPOS4SVPROC)(const GLshort *v); +GLAPI PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv; +#define glRasterPos4sv glad_glRasterPos4sv +typedef void (APIENTRYP PFNGLRECTDPROC)(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +GLAPI PFNGLRECTDPROC glad_glRectd; +#define glRectd glad_glRectd +typedef void (APIENTRYP PFNGLRECTDVPROC)(const GLdouble *v1, const GLdouble *v2); +GLAPI PFNGLRECTDVPROC glad_glRectdv; +#define glRectdv glad_glRectdv +typedef void (APIENTRYP PFNGLRECTFPROC)(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +GLAPI PFNGLRECTFPROC glad_glRectf; +#define glRectf glad_glRectf +typedef void (APIENTRYP PFNGLRECTFVPROC)(const GLfloat *v1, const GLfloat *v2); +GLAPI PFNGLRECTFVPROC glad_glRectfv; +#define glRectfv glad_glRectfv +typedef void (APIENTRYP PFNGLRECTIPROC)(GLint x1, GLint y1, GLint x2, GLint y2); +GLAPI PFNGLRECTIPROC glad_glRecti; +#define glRecti glad_glRecti +typedef void (APIENTRYP PFNGLRECTIVPROC)(const GLint *v1, const GLint *v2); +GLAPI PFNGLRECTIVPROC glad_glRectiv; +#define glRectiv glad_glRectiv +typedef void (APIENTRYP PFNGLRECTSPROC)(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +GLAPI PFNGLRECTSPROC glad_glRects; +#define glRects glad_glRects +typedef void (APIENTRYP PFNGLRECTSVPROC)(const GLshort *v1, const GLshort *v2); +GLAPI PFNGLRECTSVPROC glad_glRectsv; +#define glRectsv glad_glRectsv +typedef void (APIENTRYP PFNGLTEXCOORD1DPROC)(GLdouble s); +GLAPI PFNGLTEXCOORD1DPROC glad_glTexCoord1d; +#define glTexCoord1d glad_glTexCoord1d +typedef void (APIENTRYP PFNGLTEXCOORD1DVPROC)(const GLdouble *v); +GLAPI PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv; +#define glTexCoord1dv glad_glTexCoord1dv +typedef void (APIENTRYP PFNGLTEXCOORD1FPROC)(GLfloat s); +GLAPI PFNGLTEXCOORD1FPROC glad_glTexCoord1f; +#define glTexCoord1f glad_glTexCoord1f +typedef void (APIENTRYP PFNGLTEXCOORD1FVPROC)(const GLfloat *v); +GLAPI PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv; +#define glTexCoord1fv glad_glTexCoord1fv +typedef void (APIENTRYP PFNGLTEXCOORD1IPROC)(GLint s); +GLAPI PFNGLTEXCOORD1IPROC glad_glTexCoord1i; +#define glTexCoord1i glad_glTexCoord1i +typedef void (APIENTRYP PFNGLTEXCOORD1IVPROC)(const GLint *v); +GLAPI PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv; +#define glTexCoord1iv glad_glTexCoord1iv +typedef void (APIENTRYP PFNGLTEXCOORD1SPROC)(GLshort s); +GLAPI PFNGLTEXCOORD1SPROC glad_glTexCoord1s; +#define glTexCoord1s glad_glTexCoord1s +typedef void (APIENTRYP PFNGLTEXCOORD1SVPROC)(const GLshort *v); +GLAPI PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv; +#define glTexCoord1sv glad_glTexCoord1sv +typedef void (APIENTRYP PFNGLTEXCOORD2DPROC)(GLdouble s, GLdouble t); +GLAPI PFNGLTEXCOORD2DPROC glad_glTexCoord2d; +#define glTexCoord2d glad_glTexCoord2d +typedef void (APIENTRYP PFNGLTEXCOORD2DVPROC)(const GLdouble *v); +GLAPI PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv; +#define glTexCoord2dv glad_glTexCoord2dv +typedef void (APIENTRYP PFNGLTEXCOORD2FPROC)(GLfloat s, GLfloat t); +GLAPI PFNGLTEXCOORD2FPROC glad_glTexCoord2f; +#define glTexCoord2f glad_glTexCoord2f +typedef void (APIENTRYP PFNGLTEXCOORD2FVPROC)(const GLfloat *v); +GLAPI PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv; +#define glTexCoord2fv glad_glTexCoord2fv +typedef void (APIENTRYP PFNGLTEXCOORD2IPROC)(GLint s, GLint t); +GLAPI PFNGLTEXCOORD2IPROC glad_glTexCoord2i; +#define glTexCoord2i glad_glTexCoord2i +typedef void (APIENTRYP PFNGLTEXCOORD2IVPROC)(const GLint *v); +GLAPI PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv; +#define glTexCoord2iv glad_glTexCoord2iv +typedef void (APIENTRYP PFNGLTEXCOORD2SPROC)(GLshort s, GLshort t); +GLAPI PFNGLTEXCOORD2SPROC glad_glTexCoord2s; +#define glTexCoord2s glad_glTexCoord2s +typedef void (APIENTRYP PFNGLTEXCOORD2SVPROC)(const GLshort *v); +GLAPI PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv; +#define glTexCoord2sv glad_glTexCoord2sv +typedef void (APIENTRYP PFNGLTEXCOORD3DPROC)(GLdouble s, GLdouble t, GLdouble r); +GLAPI PFNGLTEXCOORD3DPROC glad_glTexCoord3d; +#define glTexCoord3d glad_glTexCoord3d +typedef void (APIENTRYP PFNGLTEXCOORD3DVPROC)(const GLdouble *v); +GLAPI PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv; +#define glTexCoord3dv glad_glTexCoord3dv +typedef void (APIENTRYP PFNGLTEXCOORD3FPROC)(GLfloat s, GLfloat t, GLfloat r); +GLAPI PFNGLTEXCOORD3FPROC glad_glTexCoord3f; +#define glTexCoord3f glad_glTexCoord3f +typedef void (APIENTRYP PFNGLTEXCOORD3FVPROC)(const GLfloat *v); +GLAPI PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv; +#define glTexCoord3fv glad_glTexCoord3fv +typedef void (APIENTRYP PFNGLTEXCOORD3IPROC)(GLint s, GLint t, GLint r); +GLAPI PFNGLTEXCOORD3IPROC glad_glTexCoord3i; +#define glTexCoord3i glad_glTexCoord3i +typedef void (APIENTRYP PFNGLTEXCOORD3IVPROC)(const GLint *v); +GLAPI PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv; +#define glTexCoord3iv glad_glTexCoord3iv +typedef void (APIENTRYP PFNGLTEXCOORD3SPROC)(GLshort s, GLshort t, GLshort r); +GLAPI PFNGLTEXCOORD3SPROC glad_glTexCoord3s; +#define glTexCoord3s glad_glTexCoord3s +typedef void (APIENTRYP PFNGLTEXCOORD3SVPROC)(const GLshort *v); +GLAPI PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv; +#define glTexCoord3sv glad_glTexCoord3sv +typedef void (APIENTRYP PFNGLTEXCOORD4DPROC)(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +GLAPI PFNGLTEXCOORD4DPROC glad_glTexCoord4d; +#define glTexCoord4d glad_glTexCoord4d +typedef void (APIENTRYP PFNGLTEXCOORD4DVPROC)(const GLdouble *v); +GLAPI PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv; +#define glTexCoord4dv glad_glTexCoord4dv +typedef void (APIENTRYP PFNGLTEXCOORD4FPROC)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +GLAPI PFNGLTEXCOORD4FPROC glad_glTexCoord4f; +#define glTexCoord4f glad_glTexCoord4f +typedef void (APIENTRYP PFNGLTEXCOORD4FVPROC)(const GLfloat *v); +GLAPI PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv; +#define glTexCoord4fv glad_glTexCoord4fv +typedef void (APIENTRYP PFNGLTEXCOORD4IPROC)(GLint s, GLint t, GLint r, GLint q); +GLAPI PFNGLTEXCOORD4IPROC glad_glTexCoord4i; +#define glTexCoord4i glad_glTexCoord4i +typedef void (APIENTRYP PFNGLTEXCOORD4IVPROC)(const GLint *v); +GLAPI PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv; +#define glTexCoord4iv glad_glTexCoord4iv +typedef void (APIENTRYP PFNGLTEXCOORD4SPROC)(GLshort s, GLshort t, GLshort r, GLshort q); +GLAPI PFNGLTEXCOORD4SPROC glad_glTexCoord4s; +#define glTexCoord4s glad_glTexCoord4s +typedef void (APIENTRYP PFNGLTEXCOORD4SVPROC)(const GLshort *v); +GLAPI PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv; +#define glTexCoord4sv glad_glTexCoord4sv +typedef void (APIENTRYP PFNGLVERTEX2DPROC)(GLdouble x, GLdouble y); +GLAPI PFNGLVERTEX2DPROC glad_glVertex2d; +#define glVertex2d glad_glVertex2d +typedef void (APIENTRYP PFNGLVERTEX2DVPROC)(const GLdouble *v); +GLAPI PFNGLVERTEX2DVPROC glad_glVertex2dv; +#define glVertex2dv glad_glVertex2dv +typedef void (APIENTRYP PFNGLVERTEX2FPROC)(GLfloat x, GLfloat y); +GLAPI PFNGLVERTEX2FPROC glad_glVertex2f; +#define glVertex2f glad_glVertex2f +typedef void (APIENTRYP PFNGLVERTEX2FVPROC)(const GLfloat *v); +GLAPI PFNGLVERTEX2FVPROC glad_glVertex2fv; +#define glVertex2fv glad_glVertex2fv +typedef void (APIENTRYP PFNGLVERTEX2IPROC)(GLint x, GLint y); +GLAPI PFNGLVERTEX2IPROC glad_glVertex2i; +#define glVertex2i glad_glVertex2i +typedef void (APIENTRYP PFNGLVERTEX2IVPROC)(const GLint *v); +GLAPI PFNGLVERTEX2IVPROC glad_glVertex2iv; +#define glVertex2iv glad_glVertex2iv +typedef void (APIENTRYP PFNGLVERTEX2SPROC)(GLshort x, GLshort y); +GLAPI PFNGLVERTEX2SPROC glad_glVertex2s; +#define glVertex2s glad_glVertex2s +typedef void (APIENTRYP PFNGLVERTEX2SVPROC)(const GLshort *v); +GLAPI PFNGLVERTEX2SVPROC glad_glVertex2sv; +#define glVertex2sv glad_glVertex2sv +typedef void (APIENTRYP PFNGLVERTEX3DPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLVERTEX3DPROC glad_glVertex3d; +#define glVertex3d glad_glVertex3d +typedef void (APIENTRYP PFNGLVERTEX3DVPROC)(const GLdouble *v); +GLAPI PFNGLVERTEX3DVPROC glad_glVertex3dv; +#define glVertex3dv glad_glVertex3dv +typedef void (APIENTRYP PFNGLVERTEX3FPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLVERTEX3FPROC glad_glVertex3f; +#define glVertex3f glad_glVertex3f +typedef void (APIENTRYP PFNGLVERTEX3FVPROC)(const GLfloat *v); +GLAPI PFNGLVERTEX3FVPROC glad_glVertex3fv; +#define glVertex3fv glad_glVertex3fv +typedef void (APIENTRYP PFNGLVERTEX3IPROC)(GLint x, GLint y, GLint z); +GLAPI PFNGLVERTEX3IPROC glad_glVertex3i; +#define glVertex3i glad_glVertex3i +typedef void (APIENTRYP PFNGLVERTEX3IVPROC)(const GLint *v); +GLAPI PFNGLVERTEX3IVPROC glad_glVertex3iv; +#define glVertex3iv glad_glVertex3iv +typedef void (APIENTRYP PFNGLVERTEX3SPROC)(GLshort x, GLshort y, GLshort z); +GLAPI PFNGLVERTEX3SPROC glad_glVertex3s; +#define glVertex3s glad_glVertex3s +typedef void (APIENTRYP PFNGLVERTEX3SVPROC)(const GLshort *v); +GLAPI PFNGLVERTEX3SVPROC glad_glVertex3sv; +#define glVertex3sv glad_glVertex3sv +typedef void (APIENTRYP PFNGLVERTEX4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLVERTEX4DPROC glad_glVertex4d; +#define glVertex4d glad_glVertex4d +typedef void (APIENTRYP PFNGLVERTEX4DVPROC)(const GLdouble *v); +GLAPI PFNGLVERTEX4DVPROC glad_glVertex4dv; +#define glVertex4dv glad_glVertex4dv +typedef void (APIENTRYP PFNGLVERTEX4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLVERTEX4FPROC glad_glVertex4f; +#define glVertex4f glad_glVertex4f +typedef void (APIENTRYP PFNGLVERTEX4FVPROC)(const GLfloat *v); +GLAPI PFNGLVERTEX4FVPROC glad_glVertex4fv; +#define glVertex4fv glad_glVertex4fv +typedef void (APIENTRYP PFNGLVERTEX4IPROC)(GLint x, GLint y, GLint z, GLint w); +GLAPI PFNGLVERTEX4IPROC glad_glVertex4i; +#define glVertex4i glad_glVertex4i +typedef void (APIENTRYP PFNGLVERTEX4IVPROC)(const GLint *v); +GLAPI PFNGLVERTEX4IVPROC glad_glVertex4iv; +#define glVertex4iv glad_glVertex4iv +typedef void (APIENTRYP PFNGLVERTEX4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI PFNGLVERTEX4SPROC glad_glVertex4s; +#define glVertex4s glad_glVertex4s +typedef void (APIENTRYP PFNGLVERTEX4SVPROC)(const GLshort *v); +GLAPI PFNGLVERTEX4SVPROC glad_glVertex4sv; +#define glVertex4sv glad_glVertex4sv +typedef void (APIENTRYP PFNGLCLIPPLANEPROC)(GLenum plane, const GLdouble *equation); +GLAPI PFNGLCLIPPLANEPROC glad_glClipPlane; +#define glClipPlane glad_glClipPlane +typedef void (APIENTRYP PFNGLCOLORMATERIALPROC)(GLenum face, GLenum mode); +GLAPI PFNGLCOLORMATERIALPROC glad_glColorMaterial; +#define glColorMaterial glad_glColorMaterial +typedef void (APIENTRYP PFNGLFOGFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLFOGFPROC glad_glFogf; +#define glFogf glad_glFogf +typedef void (APIENTRYP PFNGLFOGFVPROC)(GLenum pname, const GLfloat *params); +GLAPI PFNGLFOGFVPROC glad_glFogfv; +#define glFogfv glad_glFogfv +typedef void (APIENTRYP PFNGLFOGIPROC)(GLenum pname, GLint param); +GLAPI PFNGLFOGIPROC glad_glFogi; +#define glFogi glad_glFogi +typedef void (APIENTRYP PFNGLFOGIVPROC)(GLenum pname, const GLint *params); +GLAPI PFNGLFOGIVPROC glad_glFogiv; +#define glFogiv glad_glFogiv +typedef void (APIENTRYP PFNGLLIGHTFPROC)(GLenum light, GLenum pname, GLfloat param); +GLAPI PFNGLLIGHTFPROC glad_glLightf; +#define glLightf glad_glLightf +typedef void (APIENTRYP PFNGLLIGHTFVPROC)(GLenum light, GLenum pname, const GLfloat *params); +GLAPI PFNGLLIGHTFVPROC glad_glLightfv; +#define glLightfv glad_glLightfv +typedef void (APIENTRYP PFNGLLIGHTIPROC)(GLenum light, GLenum pname, GLint param); +GLAPI PFNGLLIGHTIPROC glad_glLighti; +#define glLighti glad_glLighti +typedef void (APIENTRYP PFNGLLIGHTIVPROC)(GLenum light, GLenum pname, const GLint *params); +GLAPI PFNGLLIGHTIVPROC glad_glLightiv; +#define glLightiv glad_glLightiv +typedef void (APIENTRYP PFNGLLIGHTMODELFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLLIGHTMODELFPROC glad_glLightModelf; +#define glLightModelf glad_glLightModelf +typedef void (APIENTRYP PFNGLLIGHTMODELFVPROC)(GLenum pname, const GLfloat *params); +GLAPI PFNGLLIGHTMODELFVPROC glad_glLightModelfv; +#define glLightModelfv glad_glLightModelfv +typedef void (APIENTRYP PFNGLLIGHTMODELIPROC)(GLenum pname, GLint param); +GLAPI PFNGLLIGHTMODELIPROC glad_glLightModeli; +#define glLightModeli glad_glLightModeli +typedef void (APIENTRYP PFNGLLIGHTMODELIVPROC)(GLenum pname, const GLint *params); +GLAPI PFNGLLIGHTMODELIVPROC glad_glLightModeliv; +#define glLightModeliv glad_glLightModeliv +typedef void (APIENTRYP PFNGLLINESTIPPLEPROC)(GLint factor, GLushort pattern); +GLAPI PFNGLLINESTIPPLEPROC glad_glLineStipple; +#define glLineStipple glad_glLineStipple +typedef void (APIENTRYP PFNGLMATERIALFPROC)(GLenum face, GLenum pname, GLfloat param); +GLAPI PFNGLMATERIALFPROC glad_glMaterialf; +#define glMaterialf glad_glMaterialf +typedef void (APIENTRYP PFNGLMATERIALFVPROC)(GLenum face, GLenum pname, const GLfloat *params); +GLAPI PFNGLMATERIALFVPROC glad_glMaterialfv; +#define glMaterialfv glad_glMaterialfv +typedef void (APIENTRYP PFNGLMATERIALIPROC)(GLenum face, GLenum pname, GLint param); +GLAPI PFNGLMATERIALIPROC glad_glMateriali; +#define glMateriali glad_glMateriali +typedef void (APIENTRYP PFNGLMATERIALIVPROC)(GLenum face, GLenum pname, const GLint *params); +GLAPI PFNGLMATERIALIVPROC glad_glMaterialiv; +#define glMaterialiv glad_glMaterialiv +typedef void (APIENTRYP PFNGLPOLYGONSTIPPLEPROC)(const GLubyte *mask); +GLAPI PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple; +#define glPolygonStipple glad_glPolygonStipple +typedef void (APIENTRYP PFNGLSHADEMODELPROC)(GLenum mode); +GLAPI PFNGLSHADEMODELPROC glad_glShadeModel; +#define glShadeModel glad_glShadeModel +typedef void (APIENTRYP PFNGLTEXENVFPROC)(GLenum target, GLenum pname, GLfloat param); +GLAPI PFNGLTEXENVFPROC glad_glTexEnvf; +#define glTexEnvf glad_glTexEnvf +typedef void (APIENTRYP PFNGLTEXENVFVPROC)(GLenum target, GLenum pname, const GLfloat *params); +GLAPI PFNGLTEXENVFVPROC glad_glTexEnvfv; +#define glTexEnvfv glad_glTexEnvfv +typedef void (APIENTRYP PFNGLTEXENVIPROC)(GLenum target, GLenum pname, GLint param); +GLAPI PFNGLTEXENVIPROC glad_glTexEnvi; +#define glTexEnvi glad_glTexEnvi +typedef void (APIENTRYP PFNGLTEXENVIVPROC)(GLenum target, GLenum pname, const GLint *params); +GLAPI PFNGLTEXENVIVPROC glad_glTexEnviv; +#define glTexEnviv glad_glTexEnviv +typedef void (APIENTRYP PFNGLTEXGENDPROC)(GLenum coord, GLenum pname, GLdouble param); +GLAPI PFNGLTEXGENDPROC glad_glTexGend; +#define glTexGend glad_glTexGend +typedef void (APIENTRYP PFNGLTEXGENDVPROC)(GLenum coord, GLenum pname, const GLdouble *params); +GLAPI PFNGLTEXGENDVPROC glad_glTexGendv; +#define glTexGendv glad_glTexGendv +typedef void (APIENTRYP PFNGLTEXGENFPROC)(GLenum coord, GLenum pname, GLfloat param); +GLAPI PFNGLTEXGENFPROC glad_glTexGenf; +#define glTexGenf glad_glTexGenf +typedef void (APIENTRYP PFNGLTEXGENFVPROC)(GLenum coord, GLenum pname, const GLfloat *params); +GLAPI PFNGLTEXGENFVPROC glad_glTexGenfv; +#define glTexGenfv glad_glTexGenfv +typedef void (APIENTRYP PFNGLTEXGENIPROC)(GLenum coord, GLenum pname, GLint param); +GLAPI PFNGLTEXGENIPROC glad_glTexGeni; +#define glTexGeni glad_glTexGeni +typedef void (APIENTRYP PFNGLTEXGENIVPROC)(GLenum coord, GLenum pname, const GLint *params); +GLAPI PFNGLTEXGENIVPROC glad_glTexGeniv; +#define glTexGeniv glad_glTexGeniv +typedef void (APIENTRYP PFNGLFEEDBACKBUFFERPROC)(GLsizei size, GLenum type, GLfloat *buffer); +GLAPI PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer; +#define glFeedbackBuffer glad_glFeedbackBuffer +typedef void (APIENTRYP PFNGLSELECTBUFFERPROC)(GLsizei size, GLuint *buffer); +GLAPI PFNGLSELECTBUFFERPROC glad_glSelectBuffer; +#define glSelectBuffer glad_glSelectBuffer +typedef GLint (APIENTRYP PFNGLRENDERMODEPROC)(GLenum mode); +GLAPI PFNGLRENDERMODEPROC glad_glRenderMode; +#define glRenderMode glad_glRenderMode +typedef void (APIENTRYP PFNGLINITNAMESPROC)(void); +GLAPI PFNGLINITNAMESPROC glad_glInitNames; +#define glInitNames glad_glInitNames +typedef void (APIENTRYP PFNGLLOADNAMEPROC)(GLuint name); +GLAPI PFNGLLOADNAMEPROC glad_glLoadName; +#define glLoadName glad_glLoadName +typedef void (APIENTRYP PFNGLPASSTHROUGHPROC)(GLfloat token); +GLAPI PFNGLPASSTHROUGHPROC glad_glPassThrough; +#define glPassThrough glad_glPassThrough +typedef void (APIENTRYP PFNGLPOPNAMEPROC)(void); +GLAPI PFNGLPOPNAMEPROC glad_glPopName; +#define glPopName glad_glPopName +typedef void (APIENTRYP PFNGLPUSHNAMEPROC)(GLuint name); +GLAPI PFNGLPUSHNAMEPROC glad_glPushName; +#define glPushName glad_glPushName +typedef void (APIENTRYP PFNGLCLEARACCUMPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCLEARACCUMPROC glad_glClearAccum; +#define glClearAccum glad_glClearAccum +typedef void (APIENTRYP PFNGLCLEARINDEXPROC)(GLfloat c); +GLAPI PFNGLCLEARINDEXPROC glad_glClearIndex; +#define glClearIndex glad_glClearIndex +typedef void (APIENTRYP PFNGLINDEXMASKPROC)(GLuint mask); +GLAPI PFNGLINDEXMASKPROC glad_glIndexMask; +#define glIndexMask glad_glIndexMask +typedef void (APIENTRYP PFNGLACCUMPROC)(GLenum op, GLfloat value); +GLAPI PFNGLACCUMPROC glad_glAccum; +#define glAccum glad_glAccum +typedef void (APIENTRYP PFNGLPOPATTRIBPROC)(void); +GLAPI PFNGLPOPATTRIBPROC glad_glPopAttrib; +#define glPopAttrib glad_glPopAttrib +typedef void (APIENTRYP PFNGLPUSHATTRIBPROC)(GLbitfield mask); +GLAPI PFNGLPUSHATTRIBPROC glad_glPushAttrib; +#define glPushAttrib glad_glPushAttrib +typedef void (APIENTRYP PFNGLMAP1DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +GLAPI PFNGLMAP1DPROC glad_glMap1d; +#define glMap1d glad_glMap1d +typedef void (APIENTRYP PFNGLMAP1FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +GLAPI PFNGLMAP1FPROC glad_glMap1f; +#define glMap1f glad_glMap1f +typedef void (APIENTRYP PFNGLMAP2DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +GLAPI PFNGLMAP2DPROC glad_glMap2d; +#define glMap2d glad_glMap2d +typedef void (APIENTRYP PFNGLMAP2FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +GLAPI PFNGLMAP2FPROC glad_glMap2f; +#define glMap2f glad_glMap2f +typedef void (APIENTRYP PFNGLMAPGRID1DPROC)(GLint un, GLdouble u1, GLdouble u2); +GLAPI PFNGLMAPGRID1DPROC glad_glMapGrid1d; +#define glMapGrid1d glad_glMapGrid1d +typedef void (APIENTRYP PFNGLMAPGRID1FPROC)(GLint un, GLfloat u1, GLfloat u2); +GLAPI PFNGLMAPGRID1FPROC glad_glMapGrid1f; +#define glMapGrid1f glad_glMapGrid1f +typedef void (APIENTRYP PFNGLMAPGRID2DPROC)(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +GLAPI PFNGLMAPGRID2DPROC glad_glMapGrid2d; +#define glMapGrid2d glad_glMapGrid2d +typedef void (APIENTRYP PFNGLMAPGRID2FPROC)(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +GLAPI PFNGLMAPGRID2FPROC glad_glMapGrid2f; +#define glMapGrid2f glad_glMapGrid2f +typedef void (APIENTRYP PFNGLEVALCOORD1DPROC)(GLdouble u); +GLAPI PFNGLEVALCOORD1DPROC glad_glEvalCoord1d; +#define glEvalCoord1d glad_glEvalCoord1d +typedef void (APIENTRYP PFNGLEVALCOORD1DVPROC)(const GLdouble *u); +GLAPI PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv; +#define glEvalCoord1dv glad_glEvalCoord1dv +typedef void (APIENTRYP PFNGLEVALCOORD1FPROC)(GLfloat u); +GLAPI PFNGLEVALCOORD1FPROC glad_glEvalCoord1f; +#define glEvalCoord1f glad_glEvalCoord1f +typedef void (APIENTRYP PFNGLEVALCOORD1FVPROC)(const GLfloat *u); +GLAPI PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv; +#define glEvalCoord1fv glad_glEvalCoord1fv +typedef void (APIENTRYP PFNGLEVALCOORD2DPROC)(GLdouble u, GLdouble v); +GLAPI PFNGLEVALCOORD2DPROC glad_glEvalCoord2d; +#define glEvalCoord2d glad_glEvalCoord2d +typedef void (APIENTRYP PFNGLEVALCOORD2DVPROC)(const GLdouble *u); +GLAPI PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv; +#define glEvalCoord2dv glad_glEvalCoord2dv +typedef void (APIENTRYP PFNGLEVALCOORD2FPROC)(GLfloat u, GLfloat v); +GLAPI PFNGLEVALCOORD2FPROC glad_glEvalCoord2f; +#define glEvalCoord2f glad_glEvalCoord2f +typedef void (APIENTRYP PFNGLEVALCOORD2FVPROC)(const GLfloat *u); +GLAPI PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv; +#define glEvalCoord2fv glad_glEvalCoord2fv +typedef void (APIENTRYP PFNGLEVALMESH1PROC)(GLenum mode, GLint i1, GLint i2); +GLAPI PFNGLEVALMESH1PROC glad_glEvalMesh1; +#define glEvalMesh1 glad_glEvalMesh1 +typedef void (APIENTRYP PFNGLEVALPOINT1PROC)(GLint i); +GLAPI PFNGLEVALPOINT1PROC glad_glEvalPoint1; +#define glEvalPoint1 glad_glEvalPoint1 +typedef void (APIENTRYP PFNGLEVALMESH2PROC)(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +GLAPI PFNGLEVALMESH2PROC glad_glEvalMesh2; +#define glEvalMesh2 glad_glEvalMesh2 +typedef void (APIENTRYP PFNGLEVALPOINT2PROC)(GLint i, GLint j); +GLAPI PFNGLEVALPOINT2PROC glad_glEvalPoint2; +#define glEvalPoint2 glad_glEvalPoint2 +typedef void (APIENTRYP PFNGLALPHAFUNCPROC)(GLenum func, GLfloat ref); +GLAPI PFNGLALPHAFUNCPROC glad_glAlphaFunc; +#define glAlphaFunc glad_glAlphaFunc +typedef void (APIENTRYP PFNGLPIXELZOOMPROC)(GLfloat xfactor, GLfloat yfactor); +GLAPI PFNGLPIXELZOOMPROC glad_glPixelZoom; +#define glPixelZoom glad_glPixelZoom +typedef void (APIENTRYP PFNGLPIXELTRANSFERFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf; +#define glPixelTransferf glad_glPixelTransferf +typedef void (APIENTRYP PFNGLPIXELTRANSFERIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi; +#define glPixelTransferi glad_glPixelTransferi +typedef void (APIENTRYP PFNGLPIXELMAPFVPROC)(GLenum map, GLsizei mapsize, const GLfloat *values); +GLAPI PFNGLPIXELMAPFVPROC glad_glPixelMapfv; +#define glPixelMapfv glad_glPixelMapfv +typedef void (APIENTRYP PFNGLPIXELMAPUIVPROC)(GLenum map, GLsizei mapsize, const GLuint *values); +GLAPI PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv; +#define glPixelMapuiv glad_glPixelMapuiv +typedef void (APIENTRYP PFNGLPIXELMAPUSVPROC)(GLenum map, GLsizei mapsize, const GLushort *values); +GLAPI PFNGLPIXELMAPUSVPROC glad_glPixelMapusv; +#define glPixelMapusv glad_glPixelMapusv +typedef void (APIENTRYP PFNGLCOPYPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +GLAPI PFNGLCOPYPIXELSPROC glad_glCopyPixels; +#define glCopyPixels glad_glCopyPixels +typedef void (APIENTRYP PFNGLDRAWPIXELSPROC)(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLDRAWPIXELSPROC glad_glDrawPixels; +#define glDrawPixels glad_glDrawPixels +typedef void (APIENTRYP PFNGLGETCLIPPLANEPROC)(GLenum plane, GLdouble *equation); +GLAPI PFNGLGETCLIPPLANEPROC glad_glGetClipPlane; +#define glGetClipPlane glad_glGetClipPlane +typedef void (APIENTRYP PFNGLGETLIGHTFVPROC)(GLenum light, GLenum pname, GLfloat *params); +GLAPI PFNGLGETLIGHTFVPROC glad_glGetLightfv; +#define glGetLightfv glad_glGetLightfv +typedef void (APIENTRYP PFNGLGETLIGHTIVPROC)(GLenum light, GLenum pname, GLint *params); +GLAPI PFNGLGETLIGHTIVPROC glad_glGetLightiv; +#define glGetLightiv glad_glGetLightiv +typedef void (APIENTRYP PFNGLGETMAPDVPROC)(GLenum target, GLenum query, GLdouble *v); +GLAPI PFNGLGETMAPDVPROC glad_glGetMapdv; +#define glGetMapdv glad_glGetMapdv +typedef void (APIENTRYP PFNGLGETMAPFVPROC)(GLenum target, GLenum query, GLfloat *v); +GLAPI PFNGLGETMAPFVPROC glad_glGetMapfv; +#define glGetMapfv glad_glGetMapfv +typedef void (APIENTRYP PFNGLGETMAPIVPROC)(GLenum target, GLenum query, GLint *v); +GLAPI PFNGLGETMAPIVPROC glad_glGetMapiv; +#define glGetMapiv glad_glGetMapiv +typedef void (APIENTRYP PFNGLGETMATERIALFVPROC)(GLenum face, GLenum pname, GLfloat *params); +GLAPI PFNGLGETMATERIALFVPROC glad_glGetMaterialfv; +#define glGetMaterialfv glad_glGetMaterialfv +typedef void (APIENTRYP PFNGLGETMATERIALIVPROC)(GLenum face, GLenum pname, GLint *params); +GLAPI PFNGLGETMATERIALIVPROC glad_glGetMaterialiv; +#define glGetMaterialiv glad_glGetMaterialiv +typedef void (APIENTRYP PFNGLGETPIXELMAPFVPROC)(GLenum map, GLfloat *values); +GLAPI PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv; +#define glGetPixelMapfv glad_glGetPixelMapfv +typedef void (APIENTRYP PFNGLGETPIXELMAPUIVPROC)(GLenum map, GLuint *values); +GLAPI PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv; +#define glGetPixelMapuiv glad_glGetPixelMapuiv +typedef void (APIENTRYP PFNGLGETPIXELMAPUSVPROC)(GLenum map, GLushort *values); +GLAPI PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv; +#define glGetPixelMapusv glad_glGetPixelMapusv +typedef void (APIENTRYP PFNGLGETPOLYGONSTIPPLEPROC)(GLubyte *mask); +GLAPI PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple; +#define glGetPolygonStipple glad_glGetPolygonStipple +typedef void (APIENTRYP PFNGLGETTEXENVFVPROC)(GLenum target, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv; +#define glGetTexEnvfv glad_glGetTexEnvfv +typedef void (APIENTRYP PFNGLGETTEXENVIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXENVIVPROC glad_glGetTexEnviv; +#define glGetTexEnviv glad_glGetTexEnviv +typedef void (APIENTRYP PFNGLGETTEXGENDVPROC)(GLenum coord, GLenum pname, GLdouble *params); +GLAPI PFNGLGETTEXGENDVPROC glad_glGetTexGendv; +#define glGetTexGendv glad_glGetTexGendv +typedef void (APIENTRYP PFNGLGETTEXGENFVPROC)(GLenum coord, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXGENFVPROC glad_glGetTexGenfv; +#define glGetTexGenfv glad_glGetTexGenfv +typedef void (APIENTRYP PFNGLGETTEXGENIVPROC)(GLenum coord, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXGENIVPROC glad_glGetTexGeniv; +#define glGetTexGeniv glad_glGetTexGeniv +typedef GLboolean (APIENTRYP PFNGLISLISTPROC)(GLuint list); +GLAPI PFNGLISLISTPROC glad_glIsList; +#define glIsList glad_glIsList +typedef void (APIENTRYP PFNGLFRUSTUMPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI PFNGLFRUSTUMPROC glad_glFrustum; +#define glFrustum glad_glFrustum +typedef void (APIENTRYP PFNGLLOADIDENTITYPROC)(void); +GLAPI PFNGLLOADIDENTITYPROC glad_glLoadIdentity; +#define glLoadIdentity glad_glLoadIdentity +typedef void (APIENTRYP PFNGLLOADMATRIXFPROC)(const GLfloat *m); +GLAPI PFNGLLOADMATRIXFPROC glad_glLoadMatrixf; +#define glLoadMatrixf glad_glLoadMatrixf +typedef void (APIENTRYP PFNGLLOADMATRIXDPROC)(const GLdouble *m); +GLAPI PFNGLLOADMATRIXDPROC glad_glLoadMatrixd; +#define glLoadMatrixd glad_glLoadMatrixd +typedef void (APIENTRYP PFNGLMATRIXMODEPROC)(GLenum mode); +GLAPI PFNGLMATRIXMODEPROC glad_glMatrixMode; +#define glMatrixMode glad_glMatrixMode +typedef void (APIENTRYP PFNGLMULTMATRIXFPROC)(const GLfloat *m); +GLAPI PFNGLMULTMATRIXFPROC glad_glMultMatrixf; +#define glMultMatrixf glad_glMultMatrixf +typedef void (APIENTRYP PFNGLMULTMATRIXDPROC)(const GLdouble *m); +GLAPI PFNGLMULTMATRIXDPROC glad_glMultMatrixd; +#define glMultMatrixd glad_glMultMatrixd +typedef void (APIENTRYP PFNGLORTHOPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI PFNGLORTHOPROC glad_glOrtho; +#define glOrtho glad_glOrtho +typedef void (APIENTRYP PFNGLPOPMATRIXPROC)(void); +GLAPI PFNGLPOPMATRIXPROC glad_glPopMatrix; +#define glPopMatrix glad_glPopMatrix +typedef void (APIENTRYP PFNGLPUSHMATRIXPROC)(void); +GLAPI PFNGLPUSHMATRIXPROC glad_glPushMatrix; +#define glPushMatrix glad_glPushMatrix +typedef void (APIENTRYP PFNGLROTATEDPROC)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLROTATEDPROC glad_glRotated; +#define glRotated glad_glRotated +typedef void (APIENTRYP PFNGLROTATEFPROC)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLROTATEFPROC glad_glRotatef; +#define glRotatef glad_glRotatef +typedef void (APIENTRYP PFNGLSCALEDPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLSCALEDPROC glad_glScaled; +#define glScaled glad_glScaled +typedef void (APIENTRYP PFNGLSCALEFPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLSCALEFPROC glad_glScalef; +#define glScalef glad_glScalef +typedef void (APIENTRYP PFNGLTRANSLATEDPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLTRANSLATEDPROC glad_glTranslated; +#define glTranslated glad_glTranslated +typedef void (APIENTRYP PFNGLTRANSLATEFPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLTRANSLATEFPROC glad_glTranslatef; +#define glTranslatef glad_glTranslatef +#endif +#ifndef GL_VERSION_1_1 +#define GL_VERSION_1_1 1 +GLAPI int GLAD_GL_VERSION_1_1; +typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices); +GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +typedef void (APIENTRYP PFNGLGETPOINTERVPROC)(GLenum pname, void **params); +GLAPI PFNGLGETPOINTERVPROC glad_glGetPointerv; +#define glGetPointerv glad_glGetPointerv +typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; +#define glCopyTexImage1D glad_glCopyTexImage1D +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; +#define glCopyTexSubImage1D glad_glCopyTexSubImage1D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; +#define glTexSubImage1D glad_glTexSubImage1D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures); +GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint *textures); +GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture); +GLAPI PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +typedef void (APIENTRYP PFNGLARRAYELEMENTPROC)(GLint i); +GLAPI PFNGLARRAYELEMENTPROC glad_glArrayElement; +#define glArrayElement glad_glArrayElement +typedef void (APIENTRYP PFNGLCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLCOLORPOINTERPROC glad_glColorPointer; +#define glColorPointer glad_glColorPointer +typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEPROC)(GLenum array); +GLAPI PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState; +#define glDisableClientState glad_glDisableClientState +typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERPROC)(GLsizei stride, const void *pointer); +GLAPI PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer; +#define glEdgeFlagPointer glad_glEdgeFlagPointer +typedef void (APIENTRYP PFNGLENABLECLIENTSTATEPROC)(GLenum array); +GLAPI PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState; +#define glEnableClientState glad_glEnableClientState +typedef void (APIENTRYP PFNGLINDEXPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLINDEXPOINTERPROC glad_glIndexPointer; +#define glIndexPointer glad_glIndexPointer +typedef void (APIENTRYP PFNGLINTERLEAVEDARRAYSPROC)(GLenum format, GLsizei stride, const void *pointer); +GLAPI PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays; +#define glInterleavedArrays glad_glInterleavedArrays +typedef void (APIENTRYP PFNGLNORMALPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLNORMALPOINTERPROC glad_glNormalPointer; +#define glNormalPointer glad_glNormalPointer +typedef void (APIENTRYP PFNGLTEXCOORDPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer; +#define glTexCoordPointer glad_glTexCoordPointer +typedef void (APIENTRYP PFNGLVERTEXPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXPOINTERPROC glad_glVertexPointer; +#define glVertexPointer glad_glVertexPointer +typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTPROC)(GLsizei n, const GLuint *textures, GLboolean *residences); +GLAPI PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident; +#define glAreTexturesResident glad_glAreTexturesResident +typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESPROC)(GLsizei n, const GLuint *textures, const GLfloat *priorities); +GLAPI PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures; +#define glPrioritizeTextures glad_glPrioritizeTextures +typedef void (APIENTRYP PFNGLINDEXUBPROC)(GLubyte c); +GLAPI PFNGLINDEXUBPROC glad_glIndexub; +#define glIndexub glad_glIndexub +typedef void (APIENTRYP PFNGLINDEXUBVPROC)(const GLubyte *c); +GLAPI PFNGLINDEXUBVPROC glad_glIndexubv; +#define glIndexubv glad_glIndexubv +typedef void (APIENTRYP PFNGLPOPCLIENTATTRIBPROC)(void); +GLAPI PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib; +#define glPopClientAttrib glad_glPopClientAttrib +typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBPROC)(GLbitfield mask); +GLAPI PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib; +#define glPushClientAttrib glad_glPushClientAttrib +#endif +#ifndef GL_VERSION_1_2 +#define GL_VERSION_1_2 1 +GLAPI int GLAD_GL_VERSION_1_2; +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; +#define glDrawRangeElements glad_glDrawRangeElements +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D; +#define glTexImage3D glad_glTexImage3D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; +#define glTexSubImage3D glad_glTexSubImage3D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; +#define glCopyTexSubImage3D glad_glCopyTexSubImage3D +#endif +#ifndef GL_VERSION_1_3 +#define GL_VERSION_1_3 1 +GLAPI int GLAD_GL_VERSION_1_3; +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture); +GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; +#define glCompressedTexImage3D glad_glCompressedTexImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; +#define glCompressedTexImage1D glad_glCompressedTexImage1D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; +#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; +#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void *img); +GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; +#define glGetCompressedTexImage glad_glGetCompressedTexImage +typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC)(GLenum texture); +GLAPI PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture; +#define glClientActiveTexture glad_glClientActiveTexture +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC)(GLenum target, GLdouble s); +GLAPI PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d; +#define glMultiTexCoord1d glad_glMultiTexCoord1d +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC)(GLenum target, const GLdouble *v); +GLAPI PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv; +#define glMultiTexCoord1dv glad_glMultiTexCoord1dv +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC)(GLenum target, GLfloat s); +GLAPI PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f; +#define glMultiTexCoord1f glad_glMultiTexCoord1f +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC)(GLenum target, const GLfloat *v); +GLAPI PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv; +#define glMultiTexCoord1fv glad_glMultiTexCoord1fv +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC)(GLenum target, GLint s); +GLAPI PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i; +#define glMultiTexCoord1i glad_glMultiTexCoord1i +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC)(GLenum target, const GLint *v); +GLAPI PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv; +#define glMultiTexCoord1iv glad_glMultiTexCoord1iv +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC)(GLenum target, GLshort s); +GLAPI PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s; +#define glMultiTexCoord1s glad_glMultiTexCoord1s +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC)(GLenum target, const GLshort *v); +GLAPI PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv; +#define glMultiTexCoord1sv glad_glMultiTexCoord1sv +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC)(GLenum target, GLdouble s, GLdouble t); +GLAPI PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d; +#define glMultiTexCoord2d glad_glMultiTexCoord2d +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC)(GLenum target, const GLdouble *v); +GLAPI PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv; +#define glMultiTexCoord2dv glad_glMultiTexCoord2dv +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC)(GLenum target, GLfloat s, GLfloat t); +GLAPI PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f; +#define glMultiTexCoord2f glad_glMultiTexCoord2f +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC)(GLenum target, const GLfloat *v); +GLAPI PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv; +#define glMultiTexCoord2fv glad_glMultiTexCoord2fv +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC)(GLenum target, GLint s, GLint t); +GLAPI PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i; +#define glMultiTexCoord2i glad_glMultiTexCoord2i +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC)(GLenum target, const GLint *v); +GLAPI PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv; +#define glMultiTexCoord2iv glad_glMultiTexCoord2iv +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC)(GLenum target, GLshort s, GLshort t); +GLAPI PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s; +#define glMultiTexCoord2s glad_glMultiTexCoord2s +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC)(GLenum target, const GLshort *v); +GLAPI PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv; +#define glMultiTexCoord2sv glad_glMultiTexCoord2sv +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r); +GLAPI PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d; +#define glMultiTexCoord3d glad_glMultiTexCoord3d +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC)(GLenum target, const GLdouble *v); +GLAPI PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv; +#define glMultiTexCoord3dv glad_glMultiTexCoord3dv +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r); +GLAPI PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f; +#define glMultiTexCoord3f glad_glMultiTexCoord3f +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC)(GLenum target, const GLfloat *v); +GLAPI PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv; +#define glMultiTexCoord3fv glad_glMultiTexCoord3fv +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC)(GLenum target, GLint s, GLint t, GLint r); +GLAPI PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i; +#define glMultiTexCoord3i glad_glMultiTexCoord3i +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC)(GLenum target, const GLint *v); +GLAPI PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv; +#define glMultiTexCoord3iv glad_glMultiTexCoord3iv +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC)(GLenum target, GLshort s, GLshort t, GLshort r); +GLAPI PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s; +#define glMultiTexCoord3s glad_glMultiTexCoord3s +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC)(GLenum target, const GLshort *v); +GLAPI PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv; +#define glMultiTexCoord3sv glad_glMultiTexCoord3sv +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +GLAPI PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d; +#define glMultiTexCoord4d glad_glMultiTexCoord4d +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC)(GLenum target, const GLdouble *v); +GLAPI PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv; +#define glMultiTexCoord4dv glad_glMultiTexCoord4dv +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +GLAPI PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f; +#define glMultiTexCoord4f glad_glMultiTexCoord4f +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC)(GLenum target, const GLfloat *v); +GLAPI PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv; +#define glMultiTexCoord4fv glad_glMultiTexCoord4fv +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC)(GLenum target, GLint s, GLint t, GLint r, GLint q); +GLAPI PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i; +#define glMultiTexCoord4i glad_glMultiTexCoord4i +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC)(GLenum target, const GLint *v); +GLAPI PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv; +#define glMultiTexCoord4iv glad_glMultiTexCoord4iv +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC)(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +GLAPI PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s; +#define glMultiTexCoord4s glad_glMultiTexCoord4s +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC)(GLenum target, const GLshort *v); +GLAPI PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv; +#define glMultiTexCoord4sv glad_glMultiTexCoord4sv +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC)(const GLfloat *m); +GLAPI PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf; +#define glLoadTransposeMatrixf glad_glLoadTransposeMatrixf +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC)(const GLdouble *m); +GLAPI PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd; +#define glLoadTransposeMatrixd glad_glLoadTransposeMatrixd +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC)(const GLfloat *m); +GLAPI PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf; +#define glMultTransposeMatrixf glad_glMultTransposeMatrixf +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC)(const GLdouble *m); +GLAPI PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd; +#define glMultTransposeMatrixd glad_glMultTransposeMatrixd +#endif +#ifndef GL_VERSION_1_4 +#define GL_VERSION_1_4 1 +GLAPI int GLAD_GL_VERSION_1_4; +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; +#define glMultiDrawArrays glad_glMultiDrawArrays +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); +GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; +#define glMultiDrawElements glad_glMultiDrawElements +typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; +#define glPointParameterf glad_glPointParameterf +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat *params); +GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; +#define glPointParameterfv glad_glPointParameterfv +typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; +#define glPointParameteri glad_glPointParameteri +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint *params); +GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; +#define glPointParameteriv glad_glPointParameteriv +typedef void (APIENTRYP PFNGLFOGCOORDFPROC)(GLfloat coord); +GLAPI PFNGLFOGCOORDFPROC glad_glFogCoordf; +#define glFogCoordf glad_glFogCoordf +typedef void (APIENTRYP PFNGLFOGCOORDFVPROC)(const GLfloat *coord); +GLAPI PFNGLFOGCOORDFVPROC glad_glFogCoordfv; +#define glFogCoordfv glad_glFogCoordfv +typedef void (APIENTRYP PFNGLFOGCOORDDPROC)(GLdouble coord); +GLAPI PFNGLFOGCOORDDPROC glad_glFogCoordd; +#define glFogCoordd glad_glFogCoordd +typedef void (APIENTRYP PFNGLFOGCOORDDVPROC)(const GLdouble *coord); +GLAPI PFNGLFOGCOORDDVPROC glad_glFogCoorddv; +#define glFogCoorddv glad_glFogCoorddv +typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer; +#define glFogCoordPointer glad_glFogCoordPointer +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); +GLAPI PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b; +#define glSecondaryColor3b glad_glSecondaryColor3b +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC)(const GLbyte *v); +GLAPI PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv; +#define glSecondaryColor3bv glad_glSecondaryColor3bv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); +GLAPI PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d; +#define glSecondaryColor3d glad_glSecondaryColor3d +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC)(const GLdouble *v); +GLAPI PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv; +#define glSecondaryColor3dv glad_glSecondaryColor3dv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); +GLAPI PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f; +#define glSecondaryColor3f glad_glSecondaryColor3f +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC)(const GLfloat *v); +GLAPI PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv; +#define glSecondaryColor3fv glad_glSecondaryColor3fv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC)(GLint red, GLint green, GLint blue); +GLAPI PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i; +#define glSecondaryColor3i glad_glSecondaryColor3i +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC)(const GLint *v); +GLAPI PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv; +#define glSecondaryColor3iv glad_glSecondaryColor3iv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); +GLAPI PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s; +#define glSecondaryColor3s glad_glSecondaryColor3s +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC)(const GLshort *v); +GLAPI PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv; +#define glSecondaryColor3sv glad_glSecondaryColor3sv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); +GLAPI PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub; +#define glSecondaryColor3ub glad_glSecondaryColor3ub +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC)(const GLubyte *v); +GLAPI PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv; +#define glSecondaryColor3ubv glad_glSecondaryColor3ubv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); +GLAPI PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui; +#define glSecondaryColor3ui glad_glSecondaryColor3ui +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC)(const GLuint *v); +GLAPI PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv; +#define glSecondaryColor3uiv glad_glSecondaryColor3uiv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); +GLAPI PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us; +#define glSecondaryColor3us glad_glSecondaryColor3us +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC)(const GLushort *v); +GLAPI PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv; +#define glSecondaryColor3usv glad_glSecondaryColor3usv +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer; +#define glSecondaryColorPointer glad_glSecondaryColorPointer +typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC)(GLdouble x, GLdouble y); +GLAPI PFNGLWINDOWPOS2DPROC glad_glWindowPos2d; +#define glWindowPos2d glad_glWindowPos2d +typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC)(const GLdouble *v); +GLAPI PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv; +#define glWindowPos2dv glad_glWindowPos2dv +typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC)(GLfloat x, GLfloat y); +GLAPI PFNGLWINDOWPOS2FPROC glad_glWindowPos2f; +#define glWindowPos2f glad_glWindowPos2f +typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC)(const GLfloat *v); +GLAPI PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv; +#define glWindowPos2fv glad_glWindowPos2fv +typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC)(GLint x, GLint y); +GLAPI PFNGLWINDOWPOS2IPROC glad_glWindowPos2i; +#define glWindowPos2i glad_glWindowPos2i +typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC)(const GLint *v); +GLAPI PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv; +#define glWindowPos2iv glad_glWindowPos2iv +typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC)(GLshort x, GLshort y); +GLAPI PFNGLWINDOWPOS2SPROC glad_glWindowPos2s; +#define glWindowPos2s glad_glWindowPos2s +typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC)(const GLshort *v); +GLAPI PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv; +#define glWindowPos2sv glad_glWindowPos2sv +typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLWINDOWPOS3DPROC glad_glWindowPos3d; +#define glWindowPos3d glad_glWindowPos3d +typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC)(const GLdouble *v); +GLAPI PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv; +#define glWindowPos3dv glad_glWindowPos3dv +typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLWINDOWPOS3FPROC glad_glWindowPos3f; +#define glWindowPos3f glad_glWindowPos3f +typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC)(const GLfloat *v); +GLAPI PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv; +#define glWindowPos3fv glad_glWindowPos3fv +typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC)(GLint x, GLint y, GLint z); +GLAPI PFNGLWINDOWPOS3IPROC glad_glWindowPos3i; +#define glWindowPos3i glad_glWindowPos3i +typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC)(const GLint *v); +GLAPI PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv; +#define glWindowPos3iv glad_glWindowPos3iv +typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC)(GLshort x, GLshort y, GLshort z); +GLAPI PFNGLWINDOWPOS3SPROC glad_glWindowPos3s; +#define glWindowPos3s glad_glWindowPos3s +typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC)(const GLshort *v); +GLAPI PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv; +#define glWindowPos3sv glad_glWindowPos3sv +typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode); +GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +#endif +#ifndef GL_VERSION_1_5 +#define GL_VERSION_1_5 1 +GLAPI int GLAD_GL_VERSION_1_5; +typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint *ids); +GLAPI PFNGLGENQUERIESPROC glad_glGenQueries; +#define glGenQueries glad_glGenQueries +typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint *ids); +GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries; +#define glDeleteQueries glad_glDeleteQueries +typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id); +GLAPI PFNGLISQUERYPROC glad_glIsQuery; +#define glIsQuery glad_glIsQuery +typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); +GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery; +#define glBeginQuery glad_glBeginQuery +typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target); +GLAPI PFNGLENDQUERYPROC glad_glEndQuery; +#define glEndQuery glad_glEndQuery +typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv; +#define glGetQueryiv glad_glGetQueryiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint *params); +GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; +#define glGetQueryObjectiv glad_glGetQueryObjectiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint *params); +GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; +#define glGetQueryObjectuiv glad_glGetQueryObjectuiv +typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers); +GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers); +GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer); +GLAPI PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void *data, GLenum usage); +GLAPI PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void *data); +GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; +#define glGetBufferSubData glad_glGetBufferSubData +typedef void * (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); +GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer; +#define glMapBuffer glad_glMapBuffer +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target); +GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; +#define glUnmapBuffer glad_glUnmapBuffer +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void **params); +GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; +#define glGetBufferPointerv glad_glGetBufferPointerv +#endif +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +GLAPI int GLAD_GL_VERSION_2_0; +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum *bufs); +GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; +#define glDrawBuffers glad_glDrawBuffers +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar *name); +GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader); +GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(void); +GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type); +GLAPI PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program); +GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader); +GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint *params); +GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint *params); +GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat *params); +GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint *params); +GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble *params); +GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; +#define glGetVertexAttribdv glad_glGetVertexAttribdv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat *params); +GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint *params); +GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void **pointer); +GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program); +GLAPI PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader); +GLAPI PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program); +GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program); +GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program); +GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); +GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; +#define glVertexAttrib1d glad_glVertexAttrib1d +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; +#define glVertexAttrib1dv glad_glVertexAttrib1dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); +GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; +#define glVertexAttrib1s glad_glVertexAttrib1s +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; +#define glVertexAttrib1sv glad_glVertexAttrib1sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); +GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; +#define glVertexAttrib2d glad_glVertexAttrib2d +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; +#define glVertexAttrib2dv glad_glVertexAttrib2dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); +GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; +#define glVertexAttrib2s glad_glVertexAttrib2s +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; +#define glVertexAttrib2sv glad_glVertexAttrib2sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; +#define glVertexAttrib3d glad_glVertexAttrib3d +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; +#define glVertexAttrib3dv glad_glVertexAttrib3dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; +#define glVertexAttrib3s glad_glVertexAttrib3s +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; +#define glVertexAttrib3sv glad_glVertexAttrib3sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte *v); +GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; +#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; +#define glVertexAttrib4Niv glad_glVertexAttrib4Niv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; +#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; +#define glVertexAttrib4Nub glad_glVertexAttrib4Nub +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte *v); +GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; +#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; +#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort *v); +GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; +#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte *v); +GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; +#define glVertexAttrib4bv glad_glVertexAttrib4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; +#define glVertexAttrib4d glad_glVertexAttrib4d +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; +#define glVertexAttrib4dv glad_glVertexAttrib4dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; +#define glVertexAttrib4iv glad_glVertexAttrib4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; +#define glVertexAttrib4s glad_glVertexAttrib4s +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; +#define glVertexAttrib4sv glad_glVertexAttrib4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte *v); +GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; +#define glVertexAttrib4ubv glad_glVertexAttrib4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; +#define glVertexAttrib4uiv glad_glVertexAttrib4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort *v); +GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; +#define glVertexAttrib4usv glad_glVertexAttrib4usv +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +#endif +#ifndef GL_VERSION_2_1 +#define GL_VERSION_2_1 1 +GLAPI int GLAD_GL_VERSION_2_1; +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; +#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; +#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; +#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; +#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; +#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; +#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv +#endif +#ifndef GL_VERSION_3_0 +#define GL_VERSION_3_0 1 +GLAPI int GLAD_GL_VERSION_3_0; +typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski; +#define glColorMaski glad_glColorMaski +typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean *data); +GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; +#define glGetBooleani_v glad_glGetBooleani_v +typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint *data); +GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; +#define glGetIntegeri_v glad_glGetIntegeri_v +typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index); +GLAPI PFNGLENABLEIPROC glad_glEnablei; +#define glEnablei glad_glEnablei +typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index); +GLAPI PFNGLDISABLEIPROC glad_glDisablei; +#define glDisablei glad_glDisablei +typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index); +GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi; +#define glIsEnabledi glad_glIsEnabledi +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); +GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; +#define glBeginTransformFeedback glad_glBeginTransformFeedback +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(void); +GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; +#define glEndTransformFeedback glad_glEndTransformFeedback +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; +#define glBindBufferRange glad_glBindBufferRange +typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); +GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; +#define glBindBufferBase glad_glBindBufferBase +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; +#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; +#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying +typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); +GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor; +#define glClampColor glad_glClampColor +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); +GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; +#define glBeginConditionalRender glad_glBeginConditionalRender +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(void); +GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; +#define glEndConditionalRender glad_glEndConditionalRender +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; +#define glVertexAttribIPointer glad_glVertexAttribIPointer +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint *params); +GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; +#define glGetVertexAttribIiv glad_glGetVertexAttribIiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint *params); +GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; +#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); +GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; +#define glVertexAttribI1i glad_glVertexAttribI1i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); +GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; +#define glVertexAttribI2i glad_glVertexAttribI2i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); +GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; +#define glVertexAttribI3i glad_glVertexAttribI3i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; +#define glVertexAttribI4i glad_glVertexAttribI4i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); +GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; +#define glVertexAttribI1ui glad_glVertexAttribI1ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); +GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; +#define glVertexAttribI2ui glad_glVertexAttribI2ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; +#define glVertexAttribI3ui glad_glVertexAttribI3ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; +#define glVertexAttribI4ui glad_glVertexAttribI4ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; +#define glVertexAttribI1iv glad_glVertexAttribI1iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; +#define glVertexAttribI2iv glad_glVertexAttribI2iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; +#define glVertexAttribI3iv glad_glVertexAttribI3iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; +#define glVertexAttribI4iv glad_glVertexAttribI4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; +#define glVertexAttribI1uiv glad_glVertexAttribI1uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; +#define glVertexAttribI2uiv glad_glVertexAttribI2uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; +#define glVertexAttribI3uiv glad_glVertexAttribI3uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; +#define glVertexAttribI4uiv glad_glVertexAttribI4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte *v); +GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; +#define glVertexAttribI4bv glad_glVertexAttribI4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; +#define glVertexAttribI4sv glad_glVertexAttribI4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte *v); +GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; +#define glVertexAttribI4ubv glad_glVertexAttribI4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort *v); +GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; +#define glVertexAttribI4usv glad_glVertexAttribI4usv +typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint *params); +GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; +#define glGetUniformuiv glad_glGetUniformuiv +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar *name); +GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; +#define glBindFragDataLocation glad_glBindFragDataLocation +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; +#define glGetFragDataLocation glad_glGetFragDataLocation +typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); +GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui; +#define glUniform1ui glad_glUniform1ui +typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); +GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui; +#define glUniform2ui glad_glUniform2ui +typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui; +#define glUniform3ui glad_glUniform3ui +typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui; +#define glUniform4ui glad_glUniform4ui +typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; +#define glUniform1uiv glad_glUniform1uiv +typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; +#define glUniform2uiv glad_glUniform2uiv +typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; +#define glUniform3uiv glad_glUniform3uiv +typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; +#define glUniform4uiv glad_glUniform4uiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint *params); +GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; +#define glTexParameterIiv glad_glTexParameterIiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint *params); +GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; +#define glTexParameterIuiv glad_glTexParameterIuiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; +#define glGetTexParameterIiv glad_glGetTexParameterIiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint *params); +GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; +#define glGetTexParameterIuiv glad_glGetTexParameterIuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint *value); +GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; +#define glClearBufferiv glad_glClearBufferiv +typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint *value); +GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; +#define glClearBufferuiv glad_glClearBufferuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat *value); +GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; +#define glClearBufferfv glad_glClearBufferfv +typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; +#define glClearBufferfi glad_glClearBufferfi +typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); +GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi; +#define glGetStringi glad_glGetStringi +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint *renderbuffers); +GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers); +GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers); +GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers); +GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; +#define glFramebufferTexture1D glad_glFramebufferTexture1D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; +#define glFramebufferTexture3D glad_glFramebufferTexture3D +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target); +GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; +#define glBlitFramebuffer glad_glBlitFramebuffer +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; +#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; +#define glFramebufferTextureLayer glad_glFramebufferTextureLayer +typedef void * (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; +#define glMapBufferRange glad_glMapBufferRange +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); +GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; +#define glFlushMappedBufferRange glad_glFlushMappedBufferRange +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array); +GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; +#define glBindVertexArray glad_glBindVertexArray +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint *arrays); +GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; +#define glDeleteVertexArrays glad_glDeleteVertexArrays +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint *arrays); +GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; +#define glGenVertexArrays glad_glGenVertexArrays +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array); +GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; +#define glIsVertexArray glad_glIsVertexArray +#endif +#ifndef GL_VERSION_3_1 +#define GL_VERSION_3_1 1 +GLAPI int GLAD_GL_VERSION_3_1; +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +GLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; +#define glDrawArraysInstanced glad_glDrawArraysInstanced +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); +GLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; +#define glDrawElementsInstanced glad_glDrawElementsInstanced +typedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); +GLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer; +#define glTexBuffer glad_glTexBuffer +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); +GLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; +#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex +typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; +#define glCopyBufferSubData glad_glCopyBufferSubData +typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +GLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; +#define glGetUniformIndices glad_glGetUniformIndices +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +GLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; +#define glGetActiveUniformsiv glad_glGetActiveUniformsiv +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +GLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; +#define glGetActiveUniformName glad_glGetActiveUniformName +typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar *uniformBlockName); +GLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; +#define glGetUniformBlockIndex glad_glGetUniformBlockIndex +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +GLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; +#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +GLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; +#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName +typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +GLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; +#define glUniformBlockBinding glad_glUniformBlockBinding +#endif +#ifndef GL_VERSION_3_2 +#define GL_VERSION_3_2 1 +GLAPI int GLAD_GL_VERSION_3_2; +typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; +#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; +#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); +GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; +#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); +GLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; +#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode); +GLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; +#define glProvokingVertex glad_glProvokingVertex +typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); +GLAPI PFNGLFENCESYNCPROC glad_glFenceSync; +#define glFenceSync glad_glFenceSync +typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync); +GLAPI PFNGLISSYNCPROC glad_glIsSync; +#define glIsSync glad_glIsSync +typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync); +GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync; +#define glDeleteSync glad_glDeleteSync +typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; +#define glClientWaitSync glad_glClientWaitSync +typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI PFNGLWAITSYNCPROC glad_glWaitSync; +#define glWaitSync glad_glWaitSync +typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 *data); +GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v; +#define glGetInteger64v glad_glGetInteger64v +typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv; +#define glGetSynciv glad_glGetSynciv +typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 *data); +GLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; +#define glGetInteger64i_v glad_glGetInteger64i_v +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 *params); +GLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; +#define glGetBufferParameteri64v glad_glGetBufferParameteri64v +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; +#define glFramebufferTexture glad_glFramebufferTexture +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; +#define glTexImage2DMultisample glad_glTexImage2DMultisample +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; +#define glTexImage3DMultisample glad_glTexImage3DMultisample +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat *val); +GLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; +#define glGetMultisamplefv glad_glGetMultisamplefv +typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); +GLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski; +#define glSampleMaski glad_glSampleMaski +#endif +#ifndef GL_VERSION_3_3 +#define GL_VERSION_3_3 1 +GLAPI int GLAD_GL_VERSION_3_3; +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); +GLAPI PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed; +#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed +typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex; +#define glGetFragDataIndex glad_glGetFragDataIndex +typedef void (APIENTRYP PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint *samplers); +GLAPI PFNGLGENSAMPLERSPROC glad_glGenSamplers; +#define glGenSamplers glad_glGenSamplers +typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint *samplers); +GLAPI PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers; +#define glDeleteSamplers glad_glDeleteSamplers +typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC)(GLuint sampler); +GLAPI PFNGLISSAMPLERPROC glad_glIsSampler; +#define glIsSampler glad_glIsSampler +typedef void (APIENTRYP PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler); +GLAPI PFNGLBINDSAMPLERPROC glad_glBindSampler; +#define glBindSampler glad_glBindSampler +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param); +GLAPI PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri; +#define glSamplerParameteri glad_glSamplerParameteri +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint *param); +GLAPI PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv; +#define glSamplerParameteriv glad_glSamplerParameteriv +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param); +GLAPI PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf; +#define glSamplerParameterf glad_glSamplerParameterf +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat *param); +GLAPI PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv; +#define glSamplerParameterfv glad_glSamplerParameterfv +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint *param); +GLAPI PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv; +#define glSamplerParameterIiv glad_glSamplerParameterIiv +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint *param); +GLAPI PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv; +#define glSamplerParameterIuiv glad_glSamplerParameterIuiv +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint *params); +GLAPI PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv; +#define glGetSamplerParameteriv glad_glGetSamplerParameteriv +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint *params); +GLAPI PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv; +#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat *params); +GLAPI PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv; +#define glGetSamplerParameterfv glad_glGetSamplerParameterfv +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint *params); +GLAPI PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv; +#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv +typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target); +GLAPI PFNGLQUERYCOUNTERPROC glad_glQueryCounter; +#define glQueryCounter glad_glQueryCounter +typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 *params); +GLAPI PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v; +#define glGetQueryObjecti64v glad_glGetQueryObjecti64v +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 *params); +GLAPI PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v; +#define glGetQueryObjectui64v glad_glGetQueryObjectui64v +typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor); +GLAPI PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor; +#define glVertexAttribDivisor glad_glVertexAttribDivisor +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui; +#define glVertexAttribP1ui glad_glVertexAttribP1ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv; +#define glVertexAttribP1uiv glad_glVertexAttribP1uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui; +#define glVertexAttribP2ui glad_glVertexAttribP2ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv; +#define glVertexAttribP2uiv glad_glVertexAttribP2uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui; +#define glVertexAttribP3ui glad_glVertexAttribP3ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv; +#define glVertexAttribP3uiv glad_glVertexAttribP3uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui; +#define glVertexAttribP4ui glad_glVertexAttribP4ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv; +#define glVertexAttribP4uiv glad_glVertexAttribP4uiv +typedef void (APIENTRYP PFNGLVERTEXP2UIPROC)(GLenum type, GLuint value); +GLAPI PFNGLVERTEXP2UIPROC glad_glVertexP2ui; +#define glVertexP2ui glad_glVertexP2ui +typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC)(GLenum type, const GLuint *value); +GLAPI PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv; +#define glVertexP2uiv glad_glVertexP2uiv +typedef void (APIENTRYP PFNGLVERTEXP3UIPROC)(GLenum type, GLuint value); +GLAPI PFNGLVERTEXP3UIPROC glad_glVertexP3ui; +#define glVertexP3ui glad_glVertexP3ui +typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC)(GLenum type, const GLuint *value); +GLAPI PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv; +#define glVertexP3uiv glad_glVertexP3uiv +typedef void (APIENTRYP PFNGLVERTEXP4UIPROC)(GLenum type, GLuint value); +GLAPI PFNGLVERTEXP4UIPROC glad_glVertexP4ui; +#define glVertexP4ui glad_glVertexP4ui +typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC)(GLenum type, const GLuint *value); +GLAPI PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv; +#define glVertexP4uiv glad_glVertexP4uiv +typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui; +#define glTexCoordP1ui glad_glTexCoordP1ui +typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC)(GLenum type, const GLuint *coords); +GLAPI PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv; +#define glTexCoordP1uiv glad_glTexCoordP1uiv +typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui; +#define glTexCoordP2ui glad_glTexCoordP2ui +typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC)(GLenum type, const GLuint *coords); +GLAPI PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv; +#define glTexCoordP2uiv glad_glTexCoordP2uiv +typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui; +#define glTexCoordP3ui glad_glTexCoordP3ui +typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC)(GLenum type, const GLuint *coords); +GLAPI PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv; +#define glTexCoordP3uiv glad_glTexCoordP3uiv +typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui; +#define glTexCoordP4ui glad_glTexCoordP4ui +typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC)(GLenum type, const GLuint *coords); +GLAPI PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv; +#define glTexCoordP4uiv glad_glTexCoordP4uiv +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC)(GLenum texture, GLenum type, GLuint coords); +GLAPI PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui; +#define glMultiTexCoordP1ui glad_glMultiTexCoordP1ui +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); +GLAPI PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv; +#define glMultiTexCoordP1uiv glad_glMultiTexCoordP1uiv +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC)(GLenum texture, GLenum type, GLuint coords); +GLAPI PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui; +#define glMultiTexCoordP2ui glad_glMultiTexCoordP2ui +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); +GLAPI PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv; +#define glMultiTexCoordP2uiv glad_glMultiTexCoordP2uiv +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC)(GLenum texture, GLenum type, GLuint coords); +GLAPI PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui; +#define glMultiTexCoordP3ui glad_glMultiTexCoordP3ui +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); +GLAPI PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv; +#define glMultiTexCoordP3uiv glad_glMultiTexCoordP3uiv +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC)(GLenum texture, GLenum type, GLuint coords); +GLAPI PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui; +#define glMultiTexCoordP4ui glad_glMultiTexCoordP4ui +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); +GLAPI PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv; +#define glMultiTexCoordP4uiv glad_glMultiTexCoordP4uiv +typedef void (APIENTRYP PFNGLNORMALP3UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLNORMALP3UIPROC glad_glNormalP3ui; +#define glNormalP3ui glad_glNormalP3ui +typedef void (APIENTRYP PFNGLNORMALP3UIVPROC)(GLenum type, const GLuint *coords); +GLAPI PFNGLNORMALP3UIVPROC glad_glNormalP3uiv; +#define glNormalP3uiv glad_glNormalP3uiv +typedef void (APIENTRYP PFNGLCOLORP3UIPROC)(GLenum type, GLuint color); +GLAPI PFNGLCOLORP3UIPROC glad_glColorP3ui; +#define glColorP3ui glad_glColorP3ui +typedef void (APIENTRYP PFNGLCOLORP3UIVPROC)(GLenum type, const GLuint *color); +GLAPI PFNGLCOLORP3UIVPROC glad_glColorP3uiv; +#define glColorP3uiv glad_glColorP3uiv +typedef void (APIENTRYP PFNGLCOLORP4UIPROC)(GLenum type, GLuint color); +GLAPI PFNGLCOLORP4UIPROC glad_glColorP4ui; +#define glColorP4ui glad_glColorP4ui +typedef void (APIENTRYP PFNGLCOLORP4UIVPROC)(GLenum type, const GLuint *color); +GLAPI PFNGLCOLORP4UIVPROC glad_glColorP4uiv; +#define glColorP4uiv glad_glColorP4uiv +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC)(GLenum type, GLuint color); +GLAPI PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui; +#define glSecondaryColorP3ui glad_glSecondaryColorP3ui +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint *color); +GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv; +#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/CMakeLists.txt b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/CMakeLists.txt new file mode 100644 index 00000000..05d5ed15 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/CMakeLists.txt @@ -0,0 +1,51 @@ +# +# SPDX-FileCopyrightText: Copyright (c) 2019 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +add_library( imgui STATIC + imconfig.h + imgui.cpp + imgui_demo.cpp + imgui_draw.cpp + imgui.h + imgui_impl_glfw.cpp + imgui_impl_glfw.h + imgui_impl_opengl3.cpp + imgui_impl_opengl3.h + imgui_internal.h + imgui_widgets.cpp + imstb_rectpack.h + imstb_textedit.h + imstb_truetype.h + ) + +target_include_directories( imgui + INTERFACE .. + PRIVATE . ) +target_compile_definitions( imgui PRIVATE IMGUI_IMPL_OPENGL_LOADER_GLAD ) +target_link_libraries( imgui glfw glad ${OPENGL_gl_LIBRARY}) diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/LICENSE.txt b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/LICENSE.txt new file mode 100644 index 00000000..3b439aa4 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2019 Omar Cornut + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imconfig.h b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imconfig.h new file mode 100644 index 00000000..825505bf --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imconfig.h @@ -0,0 +1,73 @@ +//----------------------------------------------------------------------------- +// COMPILE-TIME OPTIONS FOR DEAR IMGUI +// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. +// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. +//----------------------------------------------------------------------------- +// A) You may edit imconfig.h (and not overwrite it when updating imgui, or maintain a patch/branch with your modifications to imconfig.h) +// B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h" +// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ dear imgui is used, which include +// the imgui*.cpp files but also _any_ of your code that uses imgui. This is because some compile-time options have an affect on data structures. +// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. +// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. +//----------------------------------------------------------------------------- + +#pragma once + +//---- Define assertion handler. Defaults to calling assert(). +//#define IM_ASSERT(_EXPR) MyAssert(_EXPR) +//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts + +//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows. +//#define IMGUI_API __declspec( dllexport ) +//#define IMGUI_API __declspec( dllimport ) + +//---- Don't define obsolete functions/enums names. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. +//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +//---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty) +//---- It is very strongly recommended to NOT disable the demo windows during development. Please read the comments in imgui_demo.cpp. +//#define IMGUI_DISABLE_DEMO_WINDOWS + +//---- Don't implement some functions to reduce linkage requirements. +//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. +//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. +//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function. +//#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself if you don't want to link with vsnprintf. +//#define IMGUI_DISABLE_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 wrapper so you can implement them yourself. Declare your prototypes in imconfig.h. +//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). + +//---- Include imgui_user.h at the end of imgui.h as a convenience +//#define IMGUI_INCLUDE_IMGUI_USER_H + +//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) +//#define IMGUI_USE_BGRA_PACKED_COLOR + +//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version +// By default the embedded implementations are declared static and not available outside of imgui cpp files. +//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" +//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" +//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION + +//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. +// This will be inlined as part of ImVec2 and ImVec4 class declarations. +/* +#define IM_VEC2_CLASS_EXTRA \ + ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ + operator MyVec2() const { return MyVec2(x,y); } + +#define IM_VEC4_CLASS_EXTRA \ + ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ + operator MyVec4() const { return MyVec4(x,y,z,w); } +*/ + +//---- Use 32-bit vertex indices (default is 16-bit) to allow meshes with more than 64K vertices. Render function needs to support it. +//#define ImDrawIdx unsigned int + +//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. +/* +namespace ImGui +{ + void MyFunction(const char* name, const MyMatrix44& v); +} +*/ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui.cpp b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui.cpp new file mode 100644 index 00000000..a1020234 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui.cpp @@ -0,0 +1,9620 @@ +// dear imgui, v1.69 +// (main code and documentation) + +// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. +// Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase. +// Get latest version at /~https://github.com/ocornut/imgui +// Releases change-log at /~https://github.com/ocornut/imgui/releases +// Technical Support for Getting Started https://discourse.dearimgui.org/c/getting-started +// Gallery (please post your screenshots/video there!): /~https://github.com/ocornut/imgui/issues/1269 + +// Developed by Omar Cornut and every direct or indirect contributors to the GitHub. +// See LICENSE.txt for copyright and licensing details (standard MIT License). +// This library is free but I need your support to sustain development and maintenance. +// Businesses: you can support continued maintenance and development via support contracts or sponsoring, see docs/README. +// Individuals: you can support continued maintenance and development via donations or Patreon https://www.patreon.com/imgui. + +// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library. +// Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without +// modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't +// come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you +// to a better solution or official support for them. + +/* + +Index of this file: + +DOCUMENTATION + +- MISSION STATEMENT +- END-USER GUIDE +- PROGRAMMER GUIDE (read me!) + - Read first. + - How to update to a newer version of Dear ImGui. + - Getting started with integrating Dear ImGui in your code/engine. + - This is how a simple application may look like (2 variations). + - This is how a simple rendering function may look like. + - Using gamepad/keyboard navigation controls. +- API BREAKING CHANGES (read me when you update!) +- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS + - How can I tell whether to dispatch mouse/keyboard to imgui or to my application? + - How can I display an image? What is ImTextureID, how does it works? + - How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack. + - How can I use my own math types instead of ImVec2/ImVec4? + - How can I load a different font than the default? + - How can I easily use icons in my application? + - How can I load multiple fonts? + - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? + - How can I interact with standard C++ types (such as std::string and std::vector)? + - How can I use the drawing facilities without an ImGui window? (using ImDrawList API) + - How can I use Dear ImGui on a platform that doesn't have a mouse or a keyboard? (input share, remoting, gamepad) + - I integrated Dear ImGui in my engine and the text or lines are blurry.. + - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. + - How can I help? + +CODE +(search for "[SECTION]" in the code to find them) + +// [SECTION] FORWARD DECLARATIONS +// [SECTION] CONTEXT AND MEMORY ALLOCATORS +// [SECTION] MAIN USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) +// [SECTION] MISC HELPERS/UTILITIES (Maths, String, Format, Hash, File functions) +// [SECTION] MISC HELPERS/UTILITIES (ImText* functions) +// [SECTION] MISC HELPERS/UTILITIES (Color functions) +// [SECTION] ImGuiStorage +// [SECTION] ImGuiTextFilter +// [SECTION] ImGuiTextBuffer +// [SECTION] ImGuiListClipper +// [SECTION] RENDER HELPERS +// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +// [SECTION] TOOLTIPS +// [SECTION] POPUPS +// [SECTION] KEYBOARD/GAMEPAD NAVIGATION +// [SECTION] COLUMNS +// [SECTION] DRAG AND DROP +// [SECTION] LOGGING/CAPTURING +// [SECTION] SETTINGS +// [SECTION] PLATFORM DEPENDENT HELPERS +// [SECTION] METRICS/DEBUG WINDOW + +*/ + +//----------------------------------------------------------------------------- +// DOCUMENTATION +//----------------------------------------------------------------------------- + +/* + + MISSION STATEMENT + ================= + + - Easy to use to create code-driven and data-driven tools. + - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools. + - Easy to hack and improve. + - Minimize screen real-estate usage. + - Minimize setup and maintenance. + - Minimize state storage on user side. + - Portable, minimize dependencies, run on target (consoles, phones, etc.). + - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window,. + opening a tree node for the first time, etc. but a typical frame should not allocate anything). + + Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes: + - Doesn't look fancy, doesn't animate. + - Limited layout features, intricate layouts are typically crafted in code. + + + END-USER GUIDE + ============== + + - Double-click on title bar to collapse window. + - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin(). + - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents). + - Click and drag on any empty space to move window. + - TAB/SHIFT+TAB to cycle through keyboard editable fields. + - CTRL+Click on a slider or drag box to input value as text. + - Use mouse wheel to scroll. + - Text editor: + - Hold SHIFT or use mouse to select text. + - CTRL+Left/Right to word jump. + - CTRL+Shift+Left/Right to select words. + - CTRL+A our Double-Click to select all. + - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/ + - CTRL+Z,CTRL+Y to undo/redo. + - ESCAPE to revert text to its original value. + - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!) + - Controls are automatically adjusted for OSX to match standard OSX text editing operations. + - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard. + - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW + + + PROGRAMMER GUIDE + ================ + + READ FIRST: + + - Read the FAQ below this section! + - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction + or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, less bugs. + - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. + - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. + - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). + You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links docs/README.md. + - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances. + For every application frame your UI code will be called only once. This is in contrast to e.g. Unity's own implementation of an IMGUI, + where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches. + - Our origin are on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right. + - This codebase is also optimized to yield decent performances with typical "Debug" builds settings. + - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected). + If you get an assert, read the messages and comments around the assert. + - C++: this is a very C-ish codebase: we don't rely on C++11, we don't include any C++ headers, and ImGui:: is a namespace. + - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types. + See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that. + However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase. + - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!). + + HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI: + + - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h) + - Or maintain your own branch where you have imconfig.h modified. + - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes. + If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed + from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will + likely be a comment about it. Please report any issue to the GitHub page! + - Try to keep your copy of dear imgui reasonably up to date. + + GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE: + + - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library. + - Add the Dear ImGui source files to your projects or using your preferred build system. + It is recommended you build and statically link the .cpp files as part of your project and not as shared library (DLL). + - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating imgui types with your own maths types. + - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them. + - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide. + Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" + phases of your own application. All rendering informatioe are stored into command-lists that you will retrieve after calling ImGui::Render(). + - Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code. + - If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder. + + HOW A SIMPLE APPLICATION MAY LOOK LIKE: + EXHIBIT 1: USING THE EXAMPLE BINDINGS (imgui_impl_XXX.cpp files from the examples/ folder). + + // Application init: create a dear imgui context, setup some options, load fonts + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. + // TODO: Fill optional fields of the io structure later. + // TODO: Load TTF/OTF fonts if you don't want to use the default font. + + // Initialize helper Platform and Renderer bindings (here we are using imgui_impl_win32 and imgui_impl_dx11) + ImGui_ImplWin32_Init(hwnd); + ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); + + // Application main loop + while (true) + { + // Feed inputs to dear imgui, start new frame + ImGui_ImplDX11_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + + // Any application code here + ImGui::Text("Hello, world!"); + + // Render dear imgui into screen + ImGui::Render(); + ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); + g_pSwapChain->Present(1, 0); + } + + // Shutdown + ImGui_ImplDX11_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); + + HOW A SIMPLE APPLICATION MAY LOOK LIKE: + EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE. + + // Application init: create a dear imgui context, setup some options, load fonts + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. + // TODO: Fill optional fields of the io structure later. + // TODO: Load TTF/OTF fonts if you don't want to use the default font. + + // Build and load the texture atlas into a texture + // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer) + int width, height; + unsigned char* pixels = NULL; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + + // At this point you've got the texture data and you need to upload that your your graphic system: + // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'. + // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ below for details about ImTextureID. + MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32) + io.Fonts->TexID = (void*)texture; + + // Application main loop + while (true) + { + // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc. + // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform bindings) + io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds) + io.DisplaySize.x = 1920.0f; // set the current display width + io.DisplaySize.y = 1280.0f; // set the current display height here + io.MousePos = my_mouse_pos; // set the mouse position + io.MouseDown[0] = my_mouse_buttons[0]; // set the mouse button states + io.MouseDown[1] = my_mouse_buttons[1]; + + // Call NewFrame(), after this point you can use ImGui::* functions anytime + // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use imgui everywhere) + ImGui::NewFrame(); + + // Most of your application code here + ImGui::Text("Hello, world!"); + MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End(); + MyGameRender(); // may use any ImGui functions as well! + + // Render imgui, swap buffers + // (You want to try calling EndFrame/Render as late as you can, to be able to use imgui in your own game rendering code) + ImGui::EndFrame(); + ImGui::Render(); + ImDrawData* draw_data = ImGui::GetDrawData(); + MyImGuiRenderFunction(draw_data); + SwapBuffers(); + } + + // Shutdown + ImGui::DestroyContext(); + + HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE: + + void void MyImGuiRenderFunction(ImDrawData* draw_data) + { + // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled + // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize + // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize + // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui + const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback) + { + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + // The texture for the draw call is specified by pcmd->TextureId. + // The vast majority of draw calls will use the imgui texture atlas, which value you have set yourself during initialization. + MyEngineBindTexture((MyTexture*)pcmd->TextureId); + + // We are using scissoring to clip some objects. All low-level graphics API should supports it. + // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches + // (some elements visible outside their bounds) but you can fix that once everything else works! + // - Clipping coordinates are provided in imgui coordinates space (from draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize) + // In a single viewport application, draw_data->DisplayPos will always be (0,0) and draw_data->DisplaySize will always be == io.DisplaySize. + // However, in the interest of supporting multi-viewport applications in the future (see 'viewport' branch on github), + // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. + // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min) + ImVec2 pos = draw_data->DisplayPos; + MyEngineScissor((int)(pcmd->ClipRect.x - pos.x), (int)(pcmd->ClipRect.y - pos.y), (int)(pcmd->ClipRect.z - pos.x), (int)(pcmd->ClipRect.w - pos.y)); + + // Render 'pcmd->ElemCount/3' indexed triangles. + // By default the indices ImDrawIdx are 16-bits, you can change them to 32-bits in imconfig.h if your engine doesn't support 16-bits indices. + MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer); + } + idx_buffer += pcmd->ElemCount; + } + } + } + + - The examples/ folders contains many actual implementation of the pseudo-codes above. + - When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated. + They tell you if Dear ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs + from the rest of your application. In every cases you need to pass on the inputs to imgui. Refer to the FAQ for more information. + - Please read the FAQ below!. Amusingly, it is called a FAQ because people frequently run into the same issues! + + USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS + + - The gamepad/keyboard navigation is fairly functional and keeps being improved. + - Gamepad support is particularly useful to use dear imgui on a console system (e.g. PS4, Switch, XB1) without a mouse! + - You can ask questions and report issues at /~https://github.com/ocornut/imgui/issues/787 + - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable. + - Gamepad: + - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. + - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame(). + Note that io.NavInputs[] is cleared by EndFrame(). + - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values: + 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks. + - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone. + Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). + - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://goo.gl/9LgVZW. + - If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo + to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. + - Keyboard: + - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. + NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. + - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag + will be set. For more advanced uses, you may want to read from: + - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. + - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used). + - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions. + Please reach out if you think the game vs navigation input sharing could be improved. + - Mouse: + - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback. + - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keyboard. + - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag. + Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements. + When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved. + When that happens your back-end NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the binding in examples/ do that. + (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse as moving back and forth!) + (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want + to set a boolean to ignore your other external mouse positions until the external source is moved again.) + + + API BREAKING CHANGES + ==================== + + Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix. + Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code. + When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. + You can read releases logs /~https://github.com/ocornut/imgui/releases for more details. + + - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete). + - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete). + - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with a dummy small value! + - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already). + - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! + - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Keep redirection typedef (will obsolete). + - 2018/12/20 (1.67) - made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable side-effects. + - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags. + - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files. + - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete). + - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h. + If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths. + - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427) + - 2018/08/31 (1.64) - added imgui_widgets.cpp file, extracted and moved widgets code out of imgui.cpp into imgui_widgets.cpp. Re-ordered some of the code remaining in imgui.cpp. + NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED. + Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions. + - 2018/08/22 (1.63) - renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent). + - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete). + - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly). + - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges [update 1.67 renamed to ConfigWindowsResizeFromEdges] to enable the feature. + - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency. + - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time. + - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete). + - 2018/06/08 (1.62) - examples: the imgui_impl_xxx files have been split to separate platform (Win32, Glfw, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.). + old binding will still work as is, however prefer using the separated bindings as they will be updated to be multi-viewport conformant. + when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call. + - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set. + - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details. + - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more. + If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format. + To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code. + If you have IMGUI_DISABLE_OBSOLETE_FUNCTIONS enabled, the code will instead assert! You may run a reg-exp search on your codebase for e.g. "DragInt.*%f" to help you find them. + - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional "int decimal_precision" in favor of an equivalent and more flexible "const char* format", + consistent with other functions. Kept redirection functions (will obsolete). + - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value. + - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some binding ahead of merging the Nav branch). + - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now. + - 2018/03/08 (1.60) - changed ImFont::DisplayOffset.y to default to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. If you were adding or subtracting to ImFont::DisplayOffset check if your fonts are correctly aligned vertically. + - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums. + - 2018/02/18 (1.60) - BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment. + - 2018/02/16 (1.60) - obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). Use ImGui::GetDrawData() to retrieve the ImDrawData* to display. + - 2018/02/07 (1.60) - reorganized context handling to be more explicit, + - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. + - removed Shutdown() function, as DestroyContext() serve this purpose. + - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance. + - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts. + - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts. + - 2018/01/31 (1.60) - moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths. + - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete). + - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete). + - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData. + - 2017/12/29 (1.60) - removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it it's easy to replicate on your side. + - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete). + - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags + - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame. + - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set. + - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete). + - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete). + - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete). + - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete). + - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete). + - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed. + - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up. + Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions. + - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency. + - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg. + - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding. + - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); + - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency. + - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it. + - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See /~https://github.com/ocornut/imgui/issues/1382 for details. + removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting. + - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead! + - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). + - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Keep redirection typedef (will obsolete). + - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete). + - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)". + - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)! + - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). + - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete). + - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency. + - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix. + - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame. + - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely. + - 2017/08/13 (1.51) - renamed ImGuiCol_Columns*** to ImGuiCol_Separator***. Kept redirection enums (will obsolete). + - 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete). + - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton(). + - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu. + - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options. + - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0))' + - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse + - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. + - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity. + - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild(). + - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. + - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. + - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. + - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. + If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. + If your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. + This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color. + ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) + { + float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; + return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); + } + If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color. + - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). + - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. + - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). + - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDrawList::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. + - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337). + - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337) + - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). + - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert. + - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you. + - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis. + - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete. + - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position. + GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side. + GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out! + - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize + - 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project. + - 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason + - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure. + you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text. + - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost. + this necessary change will break your rendering function! the fix should be very easy. sorry for that :( + - if you are using a vanilla copy of one of the imgui_impl_XXXX.cpp provided in the example, you just need to update your copy and you can ignore the rest. + - the signature of the io.RenderDrawListsFn handler has changed! + old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) + new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data). + parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount' + ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new. + ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'. + - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer. + - if you REALLY cannot render indexed primitives, you can call the draw_data->DeIndexAllBuffers() method to de-index the buffers. This is slow and a waste of CPU/GPU. Prefer using indexed rendering! + - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade! + - 2015/07/10 (1.43) - changed SameLine() parameters from int to float. + - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete). + - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount. + - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence + - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry! + - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). + - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). + - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. + - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened. + - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). + - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50. + - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API + - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. + - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead. + - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50. + - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing + - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50. + - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing) + - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50. + - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. + - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. + - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior + - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing() + - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused) + - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions. + - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. + (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. + font init: { const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..>; } + became: { unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier; } + you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. + it is now recommended that you sample the font texture with bilinear interpolation. + (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID. + (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) + (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets + - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver) + - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph) + - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility + - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered() + - 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly) + - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity) + - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale() + - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn + - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically) + - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite + - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes + + + FREQUENTLY ASKED QUESTIONS (FAQ), TIPS + ====================================== + + Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application? + A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } ) + - When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application. + - When 'io.WantCaptureKeyboard' is set, imgui wants to use your keyboard state, and you may want to discard/hide the inputs from the rest of your application. + - When 'io.WantTextInput' is set to may want to notify your OS to popup an on-screen keyboard, if available (e.g. on a mobile phone, or console OS). + Note: you should always pass your mouse/keyboard inputs to imgui, even when the io.WantCaptureXXX flag are set false. + This is because imgui needs to detect that you clicked in the void to unfocus its own windows. + Note: The 'io.WantCaptureMouse' is more accurate that any attempt to "check if the mouse is hovering a window" (don't do that!). + It handle mouse dragging correctly (both dragging that started over your application or over an imgui window) and handle e.g. modal windows blocking inputs. + Those flags are updated by ImGui::NewFrame(). Preferably read the flags after calling NewFrame() if you can afford it, but reading them before is also + perfectly fine, as the bool toggle fairly rarely. If you have on a touch device, you might find use for an early call to UpdateHoveredWindowAndCaptureFlags(). + Note: Text input widget releases focus on "Return KeyDown", so the subsequent "Return KeyUp" event that your application receive will typically + have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs + were targeted for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.) + + Q: How can I display an image? What is ImTextureID, how does it works? + A: Short explanation: + - You may use functions such as ImGui::Image(), ImGui::ImageButton() or lower-level ImDrawList::AddImage() to emit draw calls that will use your own textures. + - Actual textures are identified in a way that is up to the user/engine. Those identifiers are stored and passed as ImTextureID (void*) value. + - Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason). + Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward. + + Long explanation: + - Dear ImGui's job is to create "meshes", defined in a renderer-agnostic format made of draw commands and vertices. + At the end of the frame those meshes (ImDrawList) will be displayed by your rendering function. They are made up of textured polygons and the code + to render them is generally fairly short (a few dozen lines). In the examples/ folder we provide functions for popular graphics API (OpenGL, DirectX, etc.). + - Each rendering function decides on a data type to represent "textures". The concept of what is a "texture" is entirely tied to your underlying engine/graphics API. + We carry the information to identify a "texture" in the ImTextureID type. + ImTextureID is nothing more that a void*, aka 4/8 bytes worth of data: just enough to store 1 pointer or 1 integer of your choice. + Dear ImGui doesn't know or understand what you are storing in ImTextureID, it merely pass ImTextureID values until they reach your rendering function. + - In the examples/ bindings, for each graphics API binding we decided on a type that is likely to be a good representation for specifying + an image from the end-user perspective. This is what the _examples_ rendering functions are using: + + OpenGL: ImTextureID = GLuint (see ImGui_ImplGlfwGL3_RenderDrawData() function in imgui_impl_glfw_gl3.cpp) + DirectX9: ImTextureID = LPDIRECT3DTEXTURE9 (see ImGui_ImplDX9_RenderDrawData() function in imgui_impl_dx9.cpp) + DirectX11: ImTextureID = ID3D11ShaderResourceView* (see ImGui_ImplDX11_RenderDrawData() function in imgui_impl_dx11.cpp) + DirectX12: ImTextureID = D3D12_GPU_DESCRIPTOR_HANDLE (see ImGui_ImplDX12_RenderDrawData() function in imgui_impl_dx12.cpp) + + For example, in the OpenGL example binding we store raw OpenGL texture identifier (GLuint) inside ImTextureID. + Whereas in the DirectX11 example binding we store a pointer to ID3D11ShaderResourceView inside ImTextureID, which is a higher-level structure + tying together both the texture and information about its format and how to read it. + - If you have a custom engine built over e.g. OpenGL, instead of passing GLuint around you may decide to use a high-level data type to carry information about + the texture as well as how to display it (shaders, etc.). The decision of what to use as ImTextureID can always be made better knowing how your codebase + is designed. If your engine has high-level data types for "textures" and "material" then you may want to use them. + If you are starting with OpenGL or DirectX or Vulkan and haven't built much of a rendering engine over them, keeping the default ImTextureID + representation suggested by the example bindings is probably the best choice. + (Advanced users may also decide to keep a low-level type in ImTextureID, and use ImDrawList callback and pass information to their renderer) + + User code may do: + + // Cast our texture type to ImTextureID / void* + MyTexture* texture = g_CoffeeTableTexture; + ImGui::Image((void*)texture, ImVec2(texture->Width, texture->Height)); + + The renderer function called after ImGui::Render() will receive that same value that the user code passed: + + // Cast ImTextureID / void* stored in the draw command as our texture type + MyTexture* texture = (MyTexture*)pcmd->TextureId; + MyEngineBindTexture2D(texture); + + Once you understand this design you will understand that loading image files and turning them into displayable textures is not within the scope of Dear ImGui. + This is by design and is actually a good thing, because it means your code has full control over your data types and how you display them. + If you want to display an image file (e.g. PNG file) into the screen, please refer to documentation and tutorials for the graphics API you are using. + + Here's a simplified OpenGL example using stb_image.h: + + // Use stb_image.h to load a PNG from disk and turn it into raw RGBA pixel data: + #define STB_IMAGE_IMPLEMENTATION + #include + [...] + int my_image_width, my_image_height; + unsigned char* my_image_data = stbi_load("my_image.png", &my_image_width, &my_image_height, NULL, 4); + + // Turn the RGBA pixel data into an OpenGL texture: + GLuint my_opengl_texture; + glGenTextures(1, &my_opengl_texture); + glBindTexture(GL_TEXTURE_2D, my_opengl_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data); + + // Now that we have an OpenGL texture, assuming our imgui rendering function (imgui_impl_xxx.cpp file) takes GLuint as ImTextureID, we can display it: + ImGui::Image((void*)(intptr_t)my_opengl_texture, ImVec2(my_image_width, my_image_height)); + + C/C++ tip: a void* is pointer-sized storage. You may safely store any pointer or integer into it by casting your value to ImTexture / void*, and vice-versa. + Because both end-points (user code and rendering function) are under your control, you know exactly what is stored inside the ImTexture / void*. + Examples: + + GLuint my_tex = XXX; + void* my_void_ptr; + my_void_ptr = (void*)(intptr_t)my_tex; // cast a GLuint into a void* (we don't take its address! we literally store the value inside the pointer) + my_tex = (GLuint)(intptr_t)my_void_ptr; // cast a void* into a GLuint + + ID3D11ShaderResourceView* my_dx11_srv = XXX; + void* my_void_ptr; + my_void_ptr = (void*)my_dx11_srv; // cast a ID3D11ShaderResourceView* into an opaque void* + my_dx11_srv = (ID3D11ShaderResourceView*)my_void_ptr; // cast a void* into a ID3D11ShaderResourceView* + + Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated. + + Q: How can I have multiple widgets with the same label or with an empty label? + Q: I have multiple widgets with the same label, and only the first one works. Why is that? + A: A primer on labels and the ID Stack... + + Dear ImGui internally need to uniquely identify UI elements. + Elements that are typically not clickable (such as calls to the Text functions) don't need an ID. + Interactive widgets (such as calls to Button buttons) need a unique ID. + Unique ID are used internally to track active widgets and occasionally associate state to widgets. + Unique ID are implicitly built from the hash of multiple elements that identify the "path" to the UI element. + + - Unique ID are often derived from a string label: + + Button("OK"); // Label = "OK", ID = hash of (..., "OK") + Button("Cancel"); // Label = "Cancel", ID = hash of (..., "Cancel") + + - ID are uniquely scoped within windows, tree nodes, etc. which all pushes to the ID stack. Having + two buttons labeled "OK" in different windows or different tree locations is fine. + We used "..." above to signify whatever was already pushed to the ID stack previously: + + Begin("MyWindow"); + Button("OK"); // Label = "OK", ID = hash of ("MyWindow", "OK") + End(); + Begin("MyOtherWindow"); + Button("OK"); // Label = "OK", ID = hash of ("MyOtherWindow", "OK") + End(); + + - If you have a same ID twice in the same location, you'll have a conflict: + + Button("OK"); + Button("OK"); // ID collision! Interacting with either button will trigger the first one. + + Fear not! this is easy to solve and there are many ways to solve it! + + - Solving ID conflict in a simple/local context: + When passing a label you can optionally specify extra ID information within string itself. + Use "##" to pass a complement to the ID that won't be visible to the end-user. + This helps solving the simple collision cases when you know e.g. at compilation time which items + are going to be created: + + Begin("MyWindow"); + Button("Play"); // Label = "Play", ID = hash of ("MyWindow", "Play") + Button("Play##foo1"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo1") // Different from above + Button("Play##foo2"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo2") // Different from above + End(); + + - If you want to completely hide the label, but still need an ID: + + Checkbox("##On", &b); // Label = "", ID = hash of (..., "##On") // No visible label, just a checkbox! + + - Occasionally/rarely you might want change a label while preserving a constant ID. This allows + you to animate labels. For example you may want to include varying information in a window title bar, + but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID: + + Button("Hello###ID"); // Label = "Hello", ID = hash of (..., "###ID") + Button("World###ID"); // Label = "World", ID = hash of (..., "###ID") // Same as above, even though the label looks different + + sprintf(buf, "My game (%f FPS)###MyGame", fps); + Begin(buf); // Variable title, ID = hash of "MyGame" + + - Solving ID conflict in a more general manner: + Use PushID() / PopID() to create scopes and manipulate the ID stack, as to avoid ID conflicts + within the same window. This is the most convenient way of distinguishing ID when iterating and + creating many UI elements programmatically. + You can push a pointer, a string or an integer value into the ID stack. + Remember that ID are formed from the concatenation of _everything_ pushed into the ID stack. + At each level of the stack we store the seed used for items at this level of the ID stack. + + Begin("Window"); + for (int i = 0; i < 100; i++) + { + PushID(i); // Push i to the id tack + Button("Click"); // Label = "Click", ID = hash of ("Window", i, "Click") + PopID(); + } + for (int i = 0; i < 100; i++) + { + MyObject* obj = Objects[i]; + PushID(obj); + Button("Click"); // Label = "Click", ID = hash of ("Window", obj pointer, "Click") + PopID(); + } + for (int i = 0; i < 100; i++) + { + MyObject* obj = Objects[i]; + PushID(obj->Name); + Button("Click"); // Label = "Click", ID = hash of ("Window", obj->Name, "Click") + PopID(); + } + End(); + + - You can stack multiple prefixes into the ID stack: + + Button("Click"); // Label = "Click", ID = hash of (..., "Click") + PushID("node"); + Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click") + PushID(my_ptr); + Button("Click"); // Label = "Click", ID = hash of (..., "node", my_ptr, "Click") + PopID(); + PopID(); + + - Tree nodes implicitly creates a scope for you by calling PushID(). + + Button("Click"); // Label = "Click", ID = hash of (..., "Click") + if (TreeNode("node")) // <-- this function call will do a PushID() for you (unless instructed not to, with a special flag) + { + Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click") + TreePop(); + } + + - When working with trees, ID are used to preserve the open/close state of each tree node. + Depending on your use cases you may want to use strings, indices or pointers as ID. + e.g. when following a single pointer that may change over time, using a static string as ID + will preserve your node open/closed state when the targeted object change. + e.g. when displaying a list of objects, using indices or pointers as ID will preserve the + node open/closed state differently. See what makes more sense in your situation! + + Q: How can I use my own math types instead of ImVec2/ImVec4? + A: You can edit imconfig.h and setup the IM_VEC2_CLASS_EXTRA/IM_VEC4_CLASS_EXTRA macros to add implicit type conversions. + This way you'll be able to use your own types everywhere, e.g. passing glm::vec2 to ImGui functions instead of ImVec2. + + Q: How can I load a different font than the default? + A: Use the font atlas to load the TTF/OTF file you want: + ImGuiIO& io = ImGui::GetIO(); + io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); + io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() + Default is ProggyClean.ttf, monospace, rendered at size 13, embedded in dear imgui's source code. + (Tip: monospace fonts are convenient because they allow to facilitate horizontal alignment directly at the string level.) + (Read the 'misc/fonts/README.txt' file for more details about font loading.) + + New programmers: remember that in C/C++ and most programming languages if you want to use a + backslash \ within a string literal, you need to write it double backslash "\\": + io.Fonts->AddFontFromFileTTF("MyDataFolder\MyFontFile.ttf", size_in_pixels); // WRONG (you are escape the M here!) + io.Fonts->AddFontFromFileTTF("MyDataFolder\\MyFontFile.ttf", size_in_pixels); // CORRECT + io.Fonts->AddFontFromFileTTF("MyDataFolder/MyFontFile.ttf", size_in_pixels); // ALSO CORRECT + + Q: How can I easily use icons in my application? + A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you + main font. Then you can refer to icons within your strings. + You may want to see ImFontConfig::GlyphMinAdvanceX to make your icon look monospace to facilitate alignment. + (Read the 'misc/fonts/README.txt' file for more details about icons font loading.) + + Q: How can I load multiple fonts? + A: Use the font atlas to pack them into a single texture: + (Read the 'misc/fonts/README.txt' file and the code in ImFontAtlas for more details.) + + ImGuiIO& io = ImGui::GetIO(); + ImFont* font0 = io.Fonts->AddFontDefault(); + ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); + ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels); + io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() + // the first loaded font gets used by default + // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime + + // Options + ImFontConfig config; + config.OversampleH = 2; + config.OversampleV = 1; + config.GlyphOffset.y -= 1.0f; // Move everything by 1 pixels up + config.GlyphExtraSpacing.x = 1.0f; // Increase spacing between characters + io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_pixels, &config); + + // Combine multiple fonts into one (e.g. for icon fonts) + static ImWchar ranges[] = { 0xf000, 0xf3ff, 0 }; + ImFontConfig config; + config.MergeMode = true; + io.Fonts->AddFontDefault(); + io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font + io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs + + Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? + A: When loading a font, pass custom Unicode ranges to specify the glyphs to load. + + // Add default Japanese ranges + io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); + + // Or create your own custom ranges (e.g. for a game you can feed your entire game script and only build the characters the game need) + ImVector ranges; + ImFontGlyphRangesBuilder builder; + builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters) + builder.AddChar(0x7262); // Add a specific character + builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges + builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted) + io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data); + + All your strings needs to use UTF-8 encoding. In C++11 you can encode a string literal in UTF-8 + by using the u8"hello" syntax. Specifying literal in your source code using a local code page + (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work! + Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8. + + Text input: it is up to your application to pass the right character code by calling io.AddInputCharacter(). + The applications in examples/ are doing that. + Windows: you can use the WM_CHAR or WM_UNICHAR or WM_IME_CHAR message (depending if your app is built using Unicode or MultiByte mode). + You may also use MultiByteToWideChar() or ToUnicode() to retrieve Unicode codepoints from MultiByte characters or keyboard state. + Windows: if your language is relying on an Input Method Editor (IME), you copy the HWND of your window to io.ImeWindowHandle in order for + the default implementation of io.ImeSetInputScreenPosFn() to set your Microsoft IME position correctly. + + Q: How can I interact with standard C++ types (such as std::string and std::vector)? + A: - Being highly portable (bindings for several languages, frameworks, programming style, obscure or older platforms/compilers), + and aiming for compatibility & performance suitable for every modern real-time game engines, dear imgui does not use + any of std C++ types. We use raw types (e.g. char* instead of std::string) because they adapt to more use cases. + - To use ImGui::InputText() with a std::string or any resizable string class, see misc/cpp/imgui_stdlib.h. + - To use combo boxes and list boxes with std::vector or any other data structure: the BeginCombo()/EndCombo() API + lets you iterate and submit items yourself, so does the ListBoxHeader()/ListBoxFooter() API. + Prefer using them over the old and awkward Combo()/ListBox() api. + - Generally for most high-level types you should be able to access the underlying data type. + You may write your own one-liner wrappers to facilitate user code (tip: add new functions in ImGui:: namespace from your code). + - Dear ImGui applications often need to make intensive use of strings. It is expected that many of the strings you will pass + to the API are raw literals (free in C/C++) or allocated in a manner that won't incur a large cost on your application. + Please bear in mind that using std::string on applications with large amount of UI may incur unsatisfactory performances. + Modern implementations of std::string often include small-string optimization (which is often a local buffer) but those + are not configurable and not the same across implementations. + - If you are finding your UI traversal cost to be too large, make sure your string usage is not leading to excessive amount + of heap allocations. Consider using literals, statically sized buffers and your own helper functions. A common pattern + is that you will need to build lots of strings on the fly, and their maximum length can be easily be scoped ahead. + One possible implementation of a helper to facilitate printf-style building of strings: /~https://github.com/ocornut/Str + This is a small helper where you can instance strings with configurable local buffers length. Many game engines will + provide similar or better string helpers. + + Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API) + A: - You can create a dummy window. Call Begin() with the NoBackground | NoDecoration | NoSavedSettings | NoInputs flags. + (The ImGuiWindowFlags_NoDecoration flag itself is a shortcut for NoTitleBar | NoResize | NoScrollbar | NoCollapse) + Then you can retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like. + - You can call ImGui::GetBackgroundDrawList() or ImGui::GetForegroundDrawList() and use those draw list to display + contents behind or over every other imgui windows. + - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create + your own ImDrawListSharedData, and then call your rendered code with your own ImDrawList or ImDrawData data. + + Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display) + A: - You can control Dear ImGui with a gamepad. Read about navigation in "Using gamepad/keyboard navigation controls". + (short version: map gamepad inputs into the io.NavInputs[] array + set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad) + - You can share your computer mouse seamlessly with your console/tablet/phone using Synergy (https://symless.com/synergy) + This is the preferred solution for developer productivity. + In particular, the "micro-synergy-client" repository (/~https://github.com/symless/micro-synergy-client) has simple + and portable source code (uSynergy.c/.h) for a small embeddable client that you can use on any platform to connect + to your host computer, based on the Synergy 1.x protocol. Make sure you download the Synergy 1 server on your computer. + Console SDK also sometimes provide equivalent tooling or wrapper for Synergy-like protocols. + - You may also use a third party solution such as Remote ImGui (/~https://github.com/JordiRos/remoteimgui) which sends + the vertices to render over the local network, allowing you to use Dear ImGui even on a screen-less machine. + - For touch inputs, you can increase the hit box of widgets (via the style.TouchPadding setting) to accommodate + for the lack of precision of touch inputs, but it is recommended you use a mouse or gamepad to allow optimizing + for screen real-estate and precision. + + Q: I integrated Dear ImGui in my engine and the text or lines are blurry.. + A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f). + Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension. + + Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. + A: You are probably mishandling the clipping rectangles in your render function. + Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height). + + Q: How can I help? + A: - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt + and see how you want to help and can help! + - Businesses: convince your company to fund development via support contracts/sponsoring! This is among the most useful thing you can do for dear imgui. + - Individuals: you can also become a Patron (http://www.patreon.com/imgui) or donate on PayPal! See README. + - Disclose your usage of dear imgui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. + You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1902). Visuals are ideal as they inspire other programmers. + But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions. + - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on github or privately). + + - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window. + this is also useful to set yourself in the context of another window (to get/set other settings) + - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug". + - tip: the ImGuiOnceUponAFrame helper will allow run the block of code only once a frame. You can use it to quickly add custom UI in the middle + of a deep nested inner loop in your code. + - tip: you can call Render() multiple times (e.g for VR renders). + - tip: call and read the ShowDemoWindow() code in imgui_demo.cpp for more example of how to use ImGui! + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +#include // toupper, isprint +#include // vsnprintf, sscanf, printf +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif + +// Debug options +#define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL +#define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#endif + +// Clang/GCC warnings with -Weverything +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning : unknown warning group '-Wformat-pedantic *' // not all warnings are known by all clang versions.. so ignoring warnings triggers new warnings on some configuration. great! +#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. +#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference is. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // +#pragma clang diagnostic ignored "-Wformat-pedantic" // warning : format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic. +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#endif +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#endif +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false +#if __GNUC__ >= 8 +#pragma GCC diagnostic ignored "-Wclass-memaccess" // warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif +#endif + +// When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch. +static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in +static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear + +// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by back-end) +static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow(). +static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time. + +//------------------------------------------------------------------------- +// [SECTION] FORWARD DECLARATIONS +//------------------------------------------------------------------------- + +static void SetCurrentWindow(ImGuiWindow* window); +static void FindHoveredWindow(); +static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags); +static void CheckStacksSize(ImGuiWindow* window, bool write); +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges); + +static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list); +static void AddWindowToSortBuffer(ImVector* out_sorted_windows, ImGuiWindow* window); + +static ImRect GetViewportRect(); + +// Settings +static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); +static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line); +static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf); + +// Platform Dependents default implementation for IO functions +static const char* GetClipboardTextFn_DefaultImpl(void* user_data); +static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text); +static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); + +namespace ImGui +{ +static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags); + +// Navigation +static void NavUpdate(); +static void NavUpdateWindowing(); +static void NavUpdateWindowingList(); +static void NavUpdateMoveResult(); +static float NavUpdatePageUpPageDown(int allowed_dir_flags); +static inline void NavUpdateAnyRequestFlag(); +static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id); +static ImVec2 NavCalcPreferredRefPos(); +static void NavSaveLastChildNavWindow(ImGuiWindow* nav_window); +static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); + +// Misc +static void UpdateMouseInputs(); +static void UpdateMouseWheel(); +static void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]); +static void RenderOuterBorders(ImGuiWindow* window); + +} + +//----------------------------------------------------------------------------- +// [SECTION] CONTEXT AND MEMORY ALLOCATORS +//----------------------------------------------------------------------------- + +// Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL. +// ImGui::CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext(). +// 1) Important: globals are not shared across DLL boundaries! If you use DLLs or any form of hot-reloading: you will need to call +// SetCurrentContext() (with the pointer you got from CreateContext) from each unique static/DLL boundary, and after each hot-reloading. +// In your debugger, add GImGui to your watch window and notice how its value changes depending on which location you are currently stepping into. +// 2) Important: Dear ImGui functions are not thread-safe because of this pointer. +// If you want thread-safety to allow N threads to access N different contexts, you can: +// - Change this variable to use thread local storage so each thread can refer to a different context, in imconfig.h: +// struct ImGuiContext; +// extern thread_local ImGuiContext* MyImGuiTLS; +// #define GImGui MyImGuiTLS +// And then define MyImGuiTLS in one of your cpp file. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword. +// - Future development aim to make this context pointer explicit to all calls. Also read /~https://github.com/ocornut/imgui/issues/586 +// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from different namespace. +#ifndef GImGui +ImGuiContext* GImGui = NULL; +#endif + +// Memory Allocator functions. Use SetAllocatorFunctions() to change them. +// If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file. +// Otherwise, you probably don't want to modify them mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction. +#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS +static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); } +static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); } +#else +static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; } +static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); } +#endif + +static void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper; +static void (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper; +static void* GImAllocatorUserData = NULL; + +//----------------------------------------------------------------------------- +// [SECTION] MAIN USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) +//----------------------------------------------------------------------------- + +ImGuiStyle::ImGuiStyle() +{ + Alpha = 1.0f; // Global alpha applies to everything in ImGui + WindowPadding = ImVec2(8,8); // Padding within a window + WindowRounding = 7.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows + WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested. + WindowMinSize = ImVec2(32,32); // Minimum window size + WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text + ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows + ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested. + PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows + PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested. + FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets) + FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). + FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested. + ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines + ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) + TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! + IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). + ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns + ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar + ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar + GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar + GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + TabBorderSize = 0.0f; // Thickness of border around tabs. + ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. + SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text when button is larger than text. + DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows. + DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. + MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. + AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU. + AntiAliasedFill = true; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.) + CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. + + // Default theme + ImGui::StyleColorsDark(this); +} + +// To scale your entire UI (e.g. if you want your app to use High DPI or generally be DPI aware) you may use this helper function. Scaling the fonts is done separately and is up to you. +// Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times. +void ImGuiStyle::ScaleAllSizes(float scale_factor) +{ + WindowPadding = ImFloor(WindowPadding * scale_factor); + WindowRounding = ImFloor(WindowRounding * scale_factor); + WindowMinSize = ImFloor(WindowMinSize * scale_factor); + ChildRounding = ImFloor(ChildRounding * scale_factor); + PopupRounding = ImFloor(PopupRounding * scale_factor); + FramePadding = ImFloor(FramePadding * scale_factor); + FrameRounding = ImFloor(FrameRounding * scale_factor); + ItemSpacing = ImFloor(ItemSpacing * scale_factor); + ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); + TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); + IndentSpacing = ImFloor(IndentSpacing * scale_factor); + ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor); + ScrollbarSize = ImFloor(ScrollbarSize * scale_factor); + ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); + GrabMinSize = ImFloor(GrabMinSize * scale_factor); + GrabRounding = ImFloor(GrabRounding * scale_factor); + TabRounding = ImFloor(TabRounding * scale_factor); + DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); + DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); + MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); +} + +ImGuiIO::ImGuiIO() +{ + // Most fields are initialized with zero + memset(this, 0, sizeof(*this)); + + // Settings + ConfigFlags = ImGuiConfigFlags_None; + BackendFlags = ImGuiBackendFlags_None; + DisplaySize = ImVec2(-1.0f, -1.0f); + DeltaTime = 1.0f/60.0f; + IniSavingRate = 5.0f; + IniFilename = "imgui.ini"; + LogFilename = "imgui_log.txt"; + MouseDoubleClickTime = 0.30f; + MouseDoubleClickMaxDist = 6.0f; + for (int i = 0; i < ImGuiKey_COUNT; i++) + KeyMap[i] = -1; + KeyRepeatDelay = 0.250f; + KeyRepeatRate = 0.050f; + UserData = NULL; + + Fonts = NULL; + FontGlobalScale = 1.0f; + FontDefault = NULL; + FontAllowUserScaling = false; + DisplayFramebufferScale = ImVec2(1.0f, 1.0f); + + // Miscellaneous options + MouseDrawCursor = false; +#ifdef __APPLE__ + ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag +#else + ConfigMacOSXBehaviors = false; +#endif + ConfigInputTextCursorBlink = true; + ConfigWindowsResizeFromEdges = true; + ConfigWindowsMoveFromTitleBarOnly = false; + + // Platform Functions + BackendPlatformName = BackendRendererName = NULL; + BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; + GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations + SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; + ClipboardUserData = NULL; + ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl; + ImeWindowHandle = NULL; + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + RenderDrawListsFn = NULL; +#endif + + // Input (NB: we already have memset zero the entire structure!) + MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX); + MouseDragThreshold = 6.0f; + for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f; + for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f; + for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f; +} + +// Pass in translated ASCII characters for text input. +// - with glfw you can get those from the callback set in glfwSetCharCallback() +// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message +void ImGuiIO::AddInputCharacter(ImWchar c) +{ + InputQueueCharacters.push_back(c); +} + +void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) +{ + while (*utf8_chars != 0) + { + unsigned int c = 0; + utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); + if (c > 0 && c <= 0xFFFF) + InputQueueCharacters.push_back((ImWchar)c); + } +} + +void ImGuiIO::ClearInputCharacters() +{ + InputQueueCharacters.resize(0); +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (Maths, String, Format, Hash, File functions) +//----------------------------------------------------------------------------- + +ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p) +{ + ImVec2 ap = p - a; + ImVec2 ab_dir = b - a; + float dot = ap.x * ab_dir.x + ap.y * ab_dir.y; + if (dot < 0.0f) + return a; + float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y; + if (dot > ab_len_sqr) + return b; + return a + ab_dir * dot / ab_len_sqr; +} + +bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p) +{ + bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f; + bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f; + bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f; + return ((b1 == b2) && (b2 == b3)); +} + +void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w) +{ + ImVec2 v0 = b - a; + ImVec2 v1 = c - a; + ImVec2 v2 = p - a; + const float denom = v0.x * v1.y - v1.x * v0.y; + out_v = (v2.x * v1.y - v1.x * v2.y) / denom; + out_w = (v0.x * v2.y - v2.x * v0.y) / denom; + out_u = 1.0f - out_v - out_w; +} + +ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p) +{ + ImVec2 proj_ab = ImLineClosestPoint(a, b, p); + ImVec2 proj_bc = ImLineClosestPoint(b, c, p); + ImVec2 proj_ca = ImLineClosestPoint(c, a, p); + float dist2_ab = ImLengthSqr(p - proj_ab); + float dist2_bc = ImLengthSqr(p - proj_bc); + float dist2_ca = ImLengthSqr(p - proj_ca); + float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca)); + if (m == dist2_ab) + return proj_ab; + if (m == dist2_bc) + return proj_bc; + return proj_ca; +} + +// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more. +int ImStricmp(const char* str1, const char* str2) +{ + int d; + while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } + return d; +} + +int ImStrnicmp(const char* str1, const char* str2, size_t count) +{ + int d = 0; + while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; } + return d; +} + +void ImStrncpy(char* dst, const char* src, size_t count) +{ + if (count < 1) + return; + if (count > 1) + strncpy(dst, src, count - 1); + dst[count - 1] = 0; +} + +char* ImStrdup(const char* str) +{ + size_t len = strlen(str); + void* buf = ImGui::MemAlloc(len + 1); + return (char*)memcpy(buf, (const void*)str, len + 1); +} + +char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src) +{ + size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1; + size_t src_size = strlen(src) + 1; + if (dst_buf_size < src_size) + { + ImGui::MemFree(dst); + dst = (char*)ImGui::MemAlloc(src_size); + if (p_dst_size) + *p_dst_size = src_size; + } + return (char*)memcpy(dst, (const void*)src, src_size); +} + +const char* ImStrchrRange(const char* str, const char* str_end, char c) +{ + const char* p = (const char*)memchr(str, (int)c, str_end - str); + return p; +} + +int ImStrlenW(const ImWchar* str) +{ + //return (int)wcslen((const wchar_t*)str); // FIXME-OPT: Could use this when wchar_t are 16-bits + int n = 0; + while (*str++) n++; + return n; +} + +// Find end-of-line. Return pointer will point to either first \n, either str_end. +const char* ImStreolRange(const char* str, const char* str_end) +{ + const char* p = (const char*)memchr(str, '\n', str_end - str); + return p ? p : str_end; +} + +const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line +{ + while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n') + buf_mid_line--; + return buf_mid_line; +} + +const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end) +{ + if (!needle_end) + needle_end = needle + strlen(needle); + + const char un0 = (char)toupper(*needle); + while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end)) + { + if (toupper(*haystack) == un0) + { + const char* b = needle + 1; + for (const char* a = haystack + 1; b < needle_end; a++, b++) + if (toupper(*a) != toupper(*b)) + break; + if (b == needle_end) + return haystack; + } + haystack++; + } + return NULL; +} + +// Trim str by offsetting contents when there's leading data + writing a \0 at the trailing position. We use this in situation where the cost is negligible. +void ImStrTrimBlanks(char* buf) +{ + char* p = buf; + while (p[0] == ' ' || p[0] == '\t') // Leading blanks + p++; + char* p_start = p; + while (*p != 0) // Find end of string + p++; + while (p > p_start && (p[-1] == ' ' || p[-1] == '\t')) // Trailing blanks + p--; + if (p_start != buf) // Copy memory if we had leading blanks + memmove(buf, p_start, p - p_start); + buf[p - p_start] = 0; // Zero terminate +} + +// A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size). +// Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm. +// B) When buf==NULL vsnprintf() will return the output size. +#ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS + +//#define IMGUI_USE_STB_SPRINTF +#ifdef IMGUI_USE_STB_SPRINTF +#define STB_SPRINTF_IMPLEMENTATION +#include "imstb_sprintf.h" +#endif + +#if defined(_MSC_VER) && !defined(vsnprintf) +#define vsnprintf _vsnprintf +#endif + +int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else + int w = vsnprintf(buf, buf_size, fmt, args); +#endif + va_end(args); + if (buf == NULL) + return w; + if (w == -1 || w >= (int)buf_size) + w = (int)buf_size - 1; + buf[w] = 0; + return w; +} + +int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) +{ +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else + int w = vsnprintf(buf, buf_size, fmt, args); +#endif + if (buf == NULL) + return w; + if (w == -1 || w >= (int)buf_size) + w = (int)buf_size - 1; + buf[w] = 0; + return w; +} +#endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS + +// CRC32 needs a 1KB lookup table (not cache friendly) +// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: +// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe. +static const ImU32 GCrc32LookupTable[256] = +{ + 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, + 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, + 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, + 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, + 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, + 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, + 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, + 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, + 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, + 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, + 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, + 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, + 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, + 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, +}; + +// Known size hash +// It is ok to call ImHashData on a string with known length but the ### operator won't be supported. +// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. +ImU32 ImHashData(const void* data_p, size_t data_size, ImU32 seed) +{ + ImU32 crc = ~seed; + const unsigned char* data = (const unsigned char*)data_p; + const ImU32* crc32_lut = GCrc32LookupTable; + while (data_size-- != 0) + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++]; + return ~crc; +} + +// Zero-terminated string hash, with support for ### to reset back to seed value +// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed. +// Because this syntax is rarely used we are optimizing for the common case. +// - If we reach ### in the string we discard the hash so far and reset to the seed. +// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build) +// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. +ImU32 ImHashStr(const char* data_p, size_t data_size, ImU32 seed) +{ + seed = ~seed; + ImU32 crc = seed; + const unsigned char* data = (const unsigned char*)data_p; + const ImU32* crc32_lut = GCrc32LookupTable; + if (data_size != 0) + { + while (data_size-- != 0) + { + unsigned char c = *data++; + if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#') + crc = seed; + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; + } + } + else + { + while (unsigned char c = *data++) + { + if (c == '#' && data[0] == '#' && data[1] == '#') + crc = seed; + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; + } + } + return ~crc; +} + +FILE* ImFileOpen(const char* filename, const char* mode) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__GNUC__) + // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. Converting both strings from UTF-8 to wchar format (using a single allocation, because we can) + const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1; + const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1; + ImVector buf; + buf.resize(filename_wsize + mode_wsize); + ImTextStrFromUtf8(&buf[0], filename_wsize, filename, NULL); + ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL); + return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]); +#else + return fopen(filename, mode); +#endif +} + +// Load file content into memory +// Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree() +void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes) +{ + IM_ASSERT(filename && file_open_mode); + if (out_file_size) + *out_file_size = 0; + + FILE* f; + if ((f = ImFileOpen(filename, file_open_mode)) == NULL) + return NULL; + + long file_size_signed; + if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET)) + { + fclose(f); + return NULL; + } + + size_t file_size = (size_t)file_size_signed; + void* file_data = ImGui::MemAlloc(file_size + padding_bytes); + if (file_data == NULL) + { + fclose(f); + return NULL; + } + if (fread(file_data, 1, file_size, f) != file_size) + { + fclose(f); + ImGui::MemFree(file_data); + return NULL; + } + if (padding_bytes > 0) + memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes); + + fclose(f); + if (out_file_size) + *out_file_size = file_size; + + return file_data; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (ImText* functions) +//----------------------------------------------------------------------------- + +// Convert UTF-8 to 32-bits character, process single character input. +// Based on stb_from_utf8() from github.com/nothings/stb/ +// We handle UTF-8 decoding error by skipping forward. +int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end) +{ + unsigned int c = (unsigned int)-1; + const unsigned char* str = (const unsigned char*)in_text; + if (!(*str & 0x80)) + { + c = (unsigned int)(*str++); + *out_char = c; + return 1; + } + if ((*str & 0xe0) == 0xc0) + { + *out_char = 0xFFFD; // will be invalid but not end of string + if (in_text_end && in_text_end - (const char*)str < 2) return 1; + if (*str < 0xc2) return 2; + c = (unsigned int)((*str++ & 0x1f) << 6); + if ((*str & 0xc0) != 0x80) return 2; + c += (*str++ & 0x3f); + *out_char = c; + return 2; + } + if ((*str & 0xf0) == 0xe0) + { + *out_char = 0xFFFD; // will be invalid but not end of string + if (in_text_end && in_text_end - (const char*)str < 3) return 1; + if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3; + if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below + c = (unsigned int)((*str++ & 0x0f) << 12); + if ((*str & 0xc0) != 0x80) return 3; + c += (unsigned int)((*str++ & 0x3f) << 6); + if ((*str & 0xc0) != 0x80) return 3; + c += (*str++ & 0x3f); + *out_char = c; + return 3; + } + if ((*str & 0xf8) == 0xf0) + { + *out_char = 0xFFFD; // will be invalid but not end of string + if (in_text_end && in_text_end - (const char*)str < 4) return 1; + if (*str > 0xf4) return 4; + if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4; + if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below + c = (unsigned int)((*str++ & 0x07) << 18); + if ((*str & 0xc0) != 0x80) return 4; + c += (unsigned int)((*str++ & 0x3f) << 12); + if ((*str & 0xc0) != 0x80) return 4; + c += (unsigned int)((*str++ & 0x3f) << 6); + if ((*str & 0xc0) != 0x80) return 4; + c += (*str++ & 0x3f); + // utf-8 encodings of values used in surrogate pairs are invalid + if ((c & 0xFFFFF800) == 0xD800) return 4; + *out_char = c; + return 4; + } + *out_char = 0; + return 0; +} + +int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining) +{ + ImWchar* buf_out = buf; + ImWchar* buf_end = buf + buf_size; + while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c; + in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); + if (c == 0) + break; + if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes + *buf_out++ = (ImWchar)c; + } + *buf_out = 0; + if (in_text_remaining) + *in_text_remaining = in_text; + return (int)(buf_out - buf); +} + +int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end) +{ + int char_count = 0; + while ((!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c; + in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); + if (c == 0) + break; + if (c < 0x10000) + char_count++; + } + return char_count; +} + +// Based on stb_to_utf8() from github.com/nothings/stb/ +static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c) +{ + if (c < 0x80) + { + buf[0] = (char)c; + return 1; + } + if (c < 0x800) + { + if (buf_size < 2) return 0; + buf[0] = (char)(0xc0 + (c >> 6)); + buf[1] = (char)(0x80 + (c & 0x3f)); + return 2; + } + if (c >= 0xdc00 && c < 0xe000) + { + return 0; + } + if (c >= 0xd800 && c < 0xdc00) + { + if (buf_size < 4) return 0; + buf[0] = (char)(0xf0 + (c >> 18)); + buf[1] = (char)(0x80 + ((c >> 12) & 0x3f)); + buf[2] = (char)(0x80 + ((c >> 6) & 0x3f)); + buf[3] = (char)(0x80 + ((c ) & 0x3f)); + return 4; + } + //else if (c < 0x10000) + { + if (buf_size < 3) return 0; + buf[0] = (char)(0xe0 + (c >> 12)); + buf[1] = (char)(0x80 + ((c>> 6) & 0x3f)); + buf[2] = (char)(0x80 + ((c ) & 0x3f)); + return 3; + } +} + +// Not optimal but we very rarely use this function. +int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end) +{ + unsigned int dummy = 0; + return ImTextCharFromUtf8(&dummy, in_text, in_text_end); +} + +static inline int ImTextCountUtf8BytesFromChar(unsigned int c) +{ + if (c < 0x80) return 1; + if (c < 0x800) return 2; + if (c >= 0xdc00 && c < 0xe000) return 0; + if (c >= 0xd800 && c < 0xdc00) return 4; + return 3; +} + +int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end) +{ + char* buf_out = buf; + const char* buf_end = buf + buf_size; + while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c = (unsigned int)(*in_text++); + if (c < 0x80) + *buf_out++ = (char)c; + else + buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end-buf_out-1), c); + } + *buf_out = 0; + return (int)(buf_out - buf); +} + +int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end) +{ + int bytes_count = 0; + while ((!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c = (unsigned int)(*in_text++); + if (c < 0x80) + bytes_count++; + else + bytes_count += ImTextCountUtf8BytesFromChar(c); + } + return bytes_count; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILTIES (Color functions) +// Note: The Convert functions are early design which are not consistent with other API. +//----------------------------------------------------------------------------- + +ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in) +{ + float s = 1.0f/255.0f; + return ImVec4( + ((in >> IM_COL32_R_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_G_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_B_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_A_SHIFT) & 0xFF) * s); +} + +ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in) +{ + ImU32 out; + out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT; + return out; +} + +// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592 +// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv +void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v) +{ + float K = 0.f; + if (g < b) + { + ImSwap(g, b); + K = -1.f; + } + if (r < g) + { + ImSwap(r, g); + K = -2.f / 6.f - K; + } + + const float chroma = r - (g < b ? g : b); + out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f)); + out_s = chroma / (r + 1e-20f); + out_v = r; +} + +// Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593 +// also http://en.wikipedia.org/wiki/HSL_and_HSV +void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b) +{ + if (s == 0.0f) + { + // gray + out_r = out_g = out_b = v; + return; + } + + h = ImFmod(h, 1.0f) / (60.0f/360.0f); + int i = (int)h; + float f = h - (float)i; + float p = v * (1.0f - s); + float q = v * (1.0f - s * f); + float t = v * (1.0f - s * (1.0f - f)); + + switch (i) + { + case 0: out_r = v; out_g = t; out_b = p; break; + case 1: out_r = q; out_g = v; out_b = p; break; + case 2: out_r = p; out_g = v; out_b = t; break; + case 3: out_r = p; out_g = q; out_b = v; break; + case 4: out_r = t; out_g = p; out_b = v; break; + case 5: default: out_r = v; out_g = p; out_b = q; break; + } +} + +ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul) +{ + ImGuiStyle& style = GImGui->Style; + ImVec4 c = style.Colors[idx]; + c.w *= style.Alpha * alpha_mul; + return ColorConvertFloat4ToU32(c); +} + +ImU32 ImGui::GetColorU32(const ImVec4& col) +{ + ImGuiStyle& style = GImGui->Style; + ImVec4 c = col; + c.w *= style.Alpha; + return ColorConvertFloat4ToU32(c); +} + +const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx) +{ + ImGuiStyle& style = GImGui->Style; + return style.Colors[idx]; +} + +ImU32 ImGui::GetColorU32(ImU32 col) +{ + float style_alpha = GImGui->Style.Alpha; + if (style_alpha >= 1.0f) + return col; + ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT; + a = (ImU32)(a * style_alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range. + return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiStorage +// Helper: Key->value storage +//----------------------------------------------------------------------------- + +// std::lower_bound but without the bullshit +static ImGuiStorage::Pair* LowerBound(ImVector& data, ImGuiID key) +{ + ImGuiStorage::Pair* first = data.Data; + ImGuiStorage::Pair* last = data.Data + data.Size; + size_t count = (size_t)(last - first); + while (count > 0) + { + size_t count2 = count >> 1; + ImGuiStorage::Pair* mid = first + count2; + if (mid->key < key) + { + first = ++mid; + count -= count2 + 1; + } + else + { + count = count2; + } + } + return first; +} + +// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. +void ImGuiStorage::BuildSortByKey() +{ + struct StaticFunc + { + static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs) + { + // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that. + if (((const Pair*)lhs)->key > ((const Pair*)rhs)->key) return +1; + if (((const Pair*)lhs)->key < ((const Pair*)rhs)->key) return -1; + return 0; + } + }; + if (Data.Size > 1) + ImQsort(Data.Data, (size_t)Data.Size, sizeof(Pair), StaticFunc::PairCompareByID); +} + +int ImGuiStorage::GetInt(ImGuiID key, int default_val) const +{ + ImGuiStorage::Pair* it = LowerBound(const_cast&>(Data), key); + if (it == Data.end() || it->key != key) + return default_val; + return it->val_i; +} + +bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const +{ + return GetInt(key, default_val ? 1 : 0) != 0; +} + +float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const +{ + ImGuiStorage::Pair* it = LowerBound(const_cast&>(Data), key); + if (it == Data.end() || it->key != key) + return default_val; + return it->val_f; +} + +void* ImGuiStorage::GetVoidPtr(ImGuiID key) const +{ + ImGuiStorage::Pair* it = LowerBound(const_cast&>(Data), key); + if (it == Data.end() || it->key != key) + return NULL; + return it->val_p; +} + +// References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer. +int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val) +{ + ImGuiStorage::Pair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + it = Data.insert(it, Pair(key, default_val)); + return &it->val_i; +} + +bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val) +{ + return (bool*)GetIntRef(key, default_val ? 1 : 0); +} + +float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) +{ + ImGuiStorage::Pair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + it = Data.insert(it, Pair(key, default_val)); + return &it->val_f; +} + +void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) +{ + ImGuiStorage::Pair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + it = Data.insert(it, Pair(key, default_val)); + return &it->val_p; +} + +// FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame) +void ImGuiStorage::SetInt(ImGuiID key, int val) +{ + ImGuiStorage::Pair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + { + Data.insert(it, Pair(key, val)); + return; + } + it->val_i = val; +} + +void ImGuiStorage::SetBool(ImGuiID key, bool val) +{ + SetInt(key, val ? 1 : 0); +} + +void ImGuiStorage::SetFloat(ImGuiID key, float val) +{ + ImGuiStorage::Pair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + { + Data.insert(it, Pair(key, val)); + return; + } + it->val_f = val; +} + +void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val) +{ + ImGuiStorage::Pair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + { + Data.insert(it, Pair(key, val)); + return; + } + it->val_p = val; +} + +void ImGuiStorage::SetAllInt(int v) +{ + for (int i = 0; i < Data.Size; i++) + Data[i].val_i = v; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiTextFilter +//----------------------------------------------------------------------------- + +// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" +ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) +{ + if (default_filter) + { + ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf)); + Build(); + } + else + { + InputBuf[0] = 0; + CountGrep = 0; + } +} + +bool ImGuiTextFilter::Draw(const char* label, float width) +{ + if (width != 0.0f) + ImGui::PushItemWidth(width); + bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf)); + if (width != 0.0f) + ImGui::PopItemWidth(); + if (value_changed) + Build(); + return value_changed; +} + +void ImGuiTextFilter::TextRange::split(char separator, ImVector* out) const +{ + out->resize(0); + const char* wb = b; + const char* we = wb; + while (we < e) + { + if (*we == separator) + { + out->push_back(TextRange(wb, we)); + wb = we + 1; + } + we++; + } + if (wb != we) + out->push_back(TextRange(wb, we)); +} + +void ImGuiTextFilter::Build() +{ + Filters.resize(0); + TextRange input_range(InputBuf, InputBuf+strlen(InputBuf)); + input_range.split(',', &Filters); + + CountGrep = 0; + for (int i = 0; i != Filters.Size; i++) + { + TextRange& f = Filters[i]; + while (f.b < f.e && ImCharIsBlankA(f.b[0])) + f.b++; + while (f.e > f.b && ImCharIsBlankA(f.e[-1])) + f.e--; + if (f.empty()) + continue; + if (Filters[i].b[0] != '-') + CountGrep += 1; + } +} + +bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const +{ + if (Filters.empty()) + return true; + + if (text == NULL) + text = ""; + + for (int i = 0; i != Filters.Size; i++) + { + const TextRange& f = Filters[i]; + if (f.empty()) + continue; + if (f.b[0] == '-') + { + // Subtract + if (ImStristr(text, text_end, f.begin()+1, f.end()) != NULL) + return false; + } + else + { + // Grep + if (ImStristr(text, text_end, f.begin(), f.end()) != NULL) + return true; + } + } + + // Implicit * grep + if (CountGrep == 0) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiTextBuffer +//----------------------------------------------------------------------------- + +// On some platform vsnprintf() takes va_list by reference and modifies it. +// va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it. +#ifndef va_copy +#if defined(__GNUC__) || defined(__clang__) +#define va_copy(dest, src) __builtin_va_copy(dest, src) +#else +#define va_copy(dest, src) (dest = src) +#endif +#endif + +char ImGuiTextBuffer::EmptyString[1] = { 0 }; + +void ImGuiTextBuffer::append(const char* str, const char* str_end) +{ + int len = str_end ? (int)(str_end - str) : (int)strlen(str); + + // Add zero-terminator the first time + const int write_off = (Buf.Size != 0) ? Buf.Size : 1; + const int needed_sz = write_off + len; + if (write_off + len >= Buf.Capacity) + { + int new_capacity = Buf.Capacity * 2; + Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); + } + + Buf.resize(needed_sz); + memcpy(&Buf[write_off - 1], str, (size_t)len); + Buf[write_off - 1 + len] = 0; +} + +void ImGuiTextBuffer::appendf(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + appendfv(fmt, args); + va_end(args); +} + +// Helper: Text buffer for logging/accumulating text +void ImGuiTextBuffer::appendfv(const char* fmt, va_list args) +{ + va_list args_copy; + va_copy(args_copy, args); + + int len = ImFormatStringV(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass. + if (len <= 0) + { + va_end(args_copy); + return; + } + + // Add zero-terminator the first time + const int write_off = (Buf.Size != 0) ? Buf.Size : 1; + const int needed_sz = write_off + len; + if (write_off + len >= Buf.Capacity) + { + int new_capacity = Buf.Capacity * 2; + Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); + } + + Buf.resize(needed_sz); + ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy); + va_end(args_copy); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiListClipper +// This is currently not as flexible/powerful as it should be, needs some rework (see TODO) +//----------------------------------------------------------------------------- + +static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) +{ + // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor. + // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. + // The clipper should probably have a 4th step to display the last item in a regular manner. + ImGui::SetCursorPosY(pos_y); + ImGuiWindow* window = ImGui::GetCurrentWindow(); + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage. + window->DC.PrevLineSize.y = (line_height - GImGui->Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list. + if (window->DC.ColumnsSet) + window->DC.ColumnsSet->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly +} + +// Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1 +// Use case B: Begin() called from constructor with items_height>0 +// FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style. +void ImGuiListClipper::Begin(int count, float items_height) +{ + StartPosY = ImGui::GetCursorPosY(); + ItemsHeight = items_height; + ItemsCount = count; + StepNo = 0; + DisplayEnd = DisplayStart = -1; + if (ItemsHeight > 0.0f) + { + ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display + if (DisplayStart > 0) + SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor + StepNo = 2; + } +} + +void ImGuiListClipper::End() +{ + if (ItemsCount < 0) + return; + // In theory here we should assert that ImGui::GetCursorPosY() == StartPosY + DisplayEnd * ItemsHeight, but it feels saner to just seek at the end and not assert/crash the user. + if (ItemsCount < INT_MAX) + SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor + ItemsCount = -1; + StepNo = 3; +} + +bool ImGuiListClipper::Step() +{ + if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems) + { + ItemsCount = -1; + return false; + } + if (StepNo == 0) // Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height. + { + DisplayStart = 0; + DisplayEnd = 1; + StartPosY = ImGui::GetCursorPosY(); + StepNo = 1; + return true; + } + if (StepNo == 1) // Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element. + { + if (ItemsCount == 1) { ItemsCount = -1; return false; } + float items_height = ImGui::GetCursorPosY() - StartPosY; + IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically + Begin(ItemsCount-1, items_height); + DisplayStart++; + DisplayEnd++; + StepNo = 3; + return true; + } + if (StepNo == 2) // Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3. + { + IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0); + StepNo = 3; + return true; + } + if (StepNo == 3) // Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop. + End(); + return false; +} + +//----------------------------------------------------------------------------- +// [SECTION] RENDER HELPERS +// Those (internal) functions are currently quite a legacy mess - their signature and behavior will change. +// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: state. +//----------------------------------------------------------------------------- + +const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end) +{ + const char* text_display_end = text; + if (!text_end) + text_end = (const char*)-1; + + while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) + text_display_end++; + return text_display_end; +} + +// Internal ImGui functions to render text +// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText() +void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // Hide anything after a '##' string + const char* text_display_end; + if (hide_text_after_hash) + { + text_display_end = FindRenderedTextEnd(text, text_end); + } + else + { + if (!text_end) + text_end = text + strlen(text); // FIXME-OPT + text_display_end = text_end; + } + + if (text != text_display_end) + { + window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end); + if (g.LogEnabled) + LogRenderedText(&pos, text, text_display_end); + } +} + +void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (!text_end) + text_end = text + strlen(text); // FIXME-OPT + + if (text != text_end) + { + window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width); + if (g.LogEnabled) + LogRenderedText(&pos, text, text_end); + } +} + +// Default clip_rect uses (pos_min,pos_max) +// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) +void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) +{ + // Perform CPU side clipping for single clipped element to avoid using scissor state + ImVec2 pos = pos_min; + const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); + + const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min; + const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max; + bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); + if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min + need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); + + // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment. + if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); + if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); + + // Render + if (need_clipping) + { + ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y); + draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect); + } + else + { + draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); + } +} + +void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) +{ + // Hide anything after a '##' string + const char* text_display_end = FindRenderedTextEnd(text, text_end); + const int text_len = (int)(text_display_end - text); + if (text_len == 0) + return; + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect); + if (g.LogEnabled) + LogRenderedText(&pos_min, text, text_display_end); +} + +// Render a rectangle shaped with optional rounding and borders +void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding); + const float border_size = g.Style.FrameBorderSize; + if (border && border_size > 0.0f) + { + window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + } +} + +void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const float border_size = g.Style.FrameBorderSize; + if (border_size > 0.0f) + { + window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + } +} + +// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state +void ImGui::RenderArrow(ImVec2 p_min, ImGuiDir dir, float scale) +{ + ImGuiContext& g = *GImGui; + + const float h = g.FontSize * 1.00f; + float r = h * 0.40f * scale; + ImVec2 center = p_min + ImVec2(h * 0.50f, h * 0.50f * scale); + + ImVec2 a, b, c; + switch (dir) + { + case ImGuiDir_Up: + case ImGuiDir_Down: + if (dir == ImGuiDir_Up) r = -r; + a = ImVec2(+0.000f,+0.750f) * r; + b = ImVec2(-0.866f,-0.750f) * r; + c = ImVec2(+0.866f,-0.750f) * r; + break; + case ImGuiDir_Left: + case ImGuiDir_Right: + if (dir == ImGuiDir_Left) r = -r; + a = ImVec2(+0.750f,+0.000f) * r; + b = ImVec2(-0.750f,+0.866f) * r; + c = ImVec2(-0.750f,-0.866f) * r; + break; + case ImGuiDir_None: + case ImGuiDir_COUNT: + IM_ASSERT(0); + break; + } + + g.CurrentWindow->DrawList->AddTriangleFilled(center + a, center + b, center + c, GetColorU32(ImGuiCol_Text)); +} + +void ImGui::RenderBullet(ImVec2 pos) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DrawList->AddCircleFilled(pos, g.FontSize*0.20f, GetColorU32(ImGuiCol_Text), 8); +} + +void ImGui::RenderCheckMark(ImVec2 pos, ImU32 col, float sz) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + float thickness = ImMax(sz / 5.0f, 1.0f); + sz -= thickness*0.5f; + pos += ImVec2(thickness*0.25f, thickness*0.25f); + + float third = sz / 3.0f; + float bx = pos.x + third; + float by = pos.y + sz - third*0.5f; + window->DrawList->PathLineTo(ImVec2(bx - third, by - third)); + window->DrawList->PathLineTo(ImVec2(bx, by)); + window->DrawList->PathLineTo(ImVec2(bx + third*2, by - third*2)); + window->DrawList->PathStroke(col, false, thickness); +} + +void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags) +{ + ImGuiContext& g = *GImGui; + if (id != g.NavId) + return; + if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) + return; + ImGuiWindow* window = g.CurrentWindow; + if (window->DC.NavHideHighlightOneFrame) + return; + + float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; + ImRect display_rect = bb; + display_rect.ClipWith(window->ClipRect); + if (flags & ImGuiNavHighlightFlags_TypeDefault) + { + const float THICKNESS = 2.0f; + const float DISTANCE = 3.0f + THICKNESS * 0.5f; + display_rect.Expand(ImVec2(DISTANCE,DISTANCE)); + bool fully_visible = window->ClipRect.Contains(display_rect); + if (!fully_visible) + window->DrawList->PushClipRect(display_rect.Min, display_rect.Max); + window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), display_rect.Max - ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, ImDrawCornerFlags_All, THICKNESS); + if (!fully_visible) + window->DrawList->PopClipRect(); + } + if (flags & ImGuiNavHighlightFlags_TypeThin) + { + window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +//----------------------------------------------------------------------------- + +// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods +ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) + : DrawListInst(&context->DrawListSharedData) +{ + Name = ImStrdup(name); + ID = ImHashStr(name, 0); + IDStack.push_back(ID); + Flags = ImGuiWindowFlags_None; + Pos = ImVec2(0.0f, 0.0f); + Size = SizeFull = ImVec2(0.0f, 0.0f); + SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f); + WindowPadding = ImVec2(0.0f, 0.0f); + WindowRounding = 0.0f; + WindowBorderSize = 0.0f; + NameBufLen = (int)strlen(name) + 1; + MoveId = GetID("#MOVE"); + ChildId = 0; + Scroll = ImVec2(0.0f, 0.0f); + ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); + ScrollbarSizes = ImVec2(0.0f, 0.0f); + ScrollbarX = ScrollbarY = false; + Active = WasActive = false; + WriteAccessed = false; + Collapsed = false; + WantCollapseToggle = false; + SkipItems = false; + Appearing = false; + Hidden = false; + HasCloseButton = false; + ResizeBorderHeld = -1; + BeginCount = 0; + BeginOrderWithinParent = -1; + BeginOrderWithinContext = -1; + PopupId = 0; + AutoFitFramesX = AutoFitFramesY = -1; + AutoFitOnlyGrows = false; + AutoFitChildAxises = 0x00; + AutoPosLastDirection = ImGuiDir_None; + HiddenFramesRegular = HiddenFramesForResize = 0; + SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; + SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); + + LastFrameActive = -1; + ItemWidthDefault = 0.0f; + FontWindowScale = 1.0f; + SettingsIdx = -1; + + DrawList = &DrawListInst; + DrawList->_OwnerName = Name; + ParentWindow = NULL; + RootWindow = NULL; + RootWindowForTitleBarHighlight = NULL; + RootWindowForNav = NULL; + + NavLastIds[0] = NavLastIds[1] = 0; + NavRectRel[0] = NavRectRel[1] = ImRect(); + NavLastChildNavWindow = NULL; +} + +ImGuiWindow::~ImGuiWindow() +{ + IM_ASSERT(DrawList == &DrawListInst); + IM_DELETE(Name); + for (int i = 0; i != ColumnsStorage.Size; i++) + ColumnsStorage[i].~ImGuiColumnsSet(); +} + +ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); + ImGui::KeepAliveID(id); + return id; +} + +ImGuiID ImGuiWindow::GetID(const void* ptr) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); + ImGui::KeepAliveID(id); + return id; +} + +ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end) +{ + ImGuiID seed = IDStack.back(); + return ImHashStr(str, str_end ? (str_end - str) : 0, seed); +} + +ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr) +{ + ImGuiID seed = IDStack.back(); + return ImHashData(&ptr, sizeof(void*), seed); +} + +// This is only used in rare/specific situations to manufacture an ID out of nowhere. +ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) +{ + ImGuiID seed = IDStack.back(); + const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) }; + ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed); + ImGui::KeepAliveID(id); + return id; +} + +static void SetCurrentWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + g.CurrentWindow = window; + if (window) + g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); +} + +void ImGui::SetNavID(ImGuiID id, int nav_layer) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindow); + IM_ASSERT(nav_layer == 0 || nav_layer == 1); + g.NavId = id; + g.NavWindow->NavLastIds[nav_layer] = id; +} + +void ImGui::SetNavIDWithRectRel(ImGuiID id, int nav_layer, const ImRect& rect_rel) +{ + ImGuiContext& g = *GImGui; + SetNavID(id, nav_layer); + g.NavWindow->NavRectRel[nav_layer] = rect_rel; + g.NavMousePosDirty = true; + g.NavDisableHighlight = false; + g.NavDisableMouseHover = true; +} + +void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + g.ActiveIdIsJustActivated = (g.ActiveId != id); + if (g.ActiveIdIsJustActivated) + { + g.ActiveIdTimer = 0.0f; + g.ActiveIdHasBeenPressed = false; + g.ActiveIdHasBeenEdited = false; + if (id != 0) + { + g.LastActiveId = id; + g.LastActiveIdTimer = 0.0f; + } + } + g.ActiveId = id; + g.ActiveIdAllowNavDirFlags = 0; + g.ActiveIdBlockNavInputFlags = 0; + g.ActiveIdAllowOverlap = false; + g.ActiveIdWindow = window; + if (id) + { + g.ActiveIdIsAlive = id; + g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse; + } +} + +// FIXME-NAV: The existence of SetNavID/SetNavIDWithRectRel/SetFocusID is incredibly messy and confusing and needs some explanation or refactoring. +void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(id != 0); + + // Assume that SetFocusID() is called in the context where its NavLayer is the current layer, which is the case everywhere we call it. + const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent; + if (g.NavWindow != window) + g.NavInitRequest = false; + g.NavId = id; + g.NavWindow = window; + g.NavLayer = nav_layer; + window->NavLastIds[nav_layer] = id; + if (window->DC.LastItemId == id) + window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos); + + if (g.ActiveIdSource == ImGuiInputSource_Nav) + g.NavDisableMouseHover = true; + else + g.NavDisableHighlight = true; +} + +void ImGui::ClearActiveID() +{ + SetActiveID(0, NULL); +} + +void ImGui::SetHoveredID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + g.HoveredId = id; + g.HoveredIdAllowOverlap = false; + if (id != 0 && g.HoveredIdPreviousFrame != id) + g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f; +} + +ImGuiID ImGui::GetHoveredID() +{ + ImGuiContext& g = *GImGui; + return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame; +} + +void ImGui::KeepAliveID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId == id) + g.ActiveIdIsAlive = id; + if (g.ActiveIdPreviousFrame == id) + g.ActiveIdPreviousFrameIsAlive = true; +} + +void ImGui::MarkItemEdited(ImGuiID id) +{ + // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit(). + // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need need to fill the data. + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive); + IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out. + //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id); + g.ActiveIdHasBeenEdited = true; + g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; +} + +static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) +{ + // An active popup disable hovering on other windows (apart from its own children) + // FIXME-OPT: This could be cached/stored within the window. + ImGuiContext& g = *GImGui; + if (g.NavWindow) + if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow) + if (focused_root_window->WasActive && focused_root_window != window->RootWindow) + { + // For the purpose of those flags we differentiate "standard popup" from "modal popup" + // NB: The order of those two tests is important because Modal windows are also Popups. + if (focused_root_window->Flags & ImGuiWindowFlags_Modal) + return false; + if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + return false; + } + + return true; +} + +// Advance cursor given item size for layout. +void ImGui::ItemSize(const ImVec2& size, float text_offset_y) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + // Always align ourselves on pixel boundaries + const float line_height = ImMax(window->DC.CurrentLineSize.y, size.y); + const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y); + //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] + window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y); + window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + window->DC.CursorPos.y = (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y); + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); + //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] + + window->DC.PrevLineSize.y = line_height; + window->DC.PrevLineTextBaseOffset = text_base_offset; + window->DC.CurrentLineSize.y = window->DC.CurrentLineTextBaseOffset = 0.0f; + + // Horizontal layout mode + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + SameLine(); +} + +void ImGui::ItemSize(const ImRect& bb, float text_offset_y) +{ + ItemSize(bb.GetSize(), text_offset_y); +} + +// Declare item bounding box for clipping and interaction. +// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface +// declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd(). +bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (id != 0) + { + // Navigation processing runs prior to clipping early-out + // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget + // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests unfortunately, but it is still limited to one window. + // it may not scale very well for windows with ten of thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame. + // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick) + window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask; + if (g.NavId == id || g.NavAnyRequest) + if (g.NavWindow->RootWindowForNav == window->RootWindowForNav) + if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened)) + NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id); + } + + window->DC.LastItemId = id; + window->DC.LastItemRect = bb; + window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; + +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (id != 0) + ImGuiTestEngineHook_ItemAdd(&g, nav_bb_arg ? *nav_bb_arg : bb, id); +#endif + + // Clipping test + const bool is_clipped = IsClippedEx(bb, id, false); + if (is_clipped) + return false; + //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] + + // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) + if (IsMouseHoveringRect(bb.Min, bb.Max)) + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect; + return true; +} + +// This is roughly matching the behavior of internal-facing ItemHoverable() +// - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered() +// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId +bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavDisableMouseHover && !g.NavDisableHighlight) + return IsItemFocused(); + + // Test for bounding box overlap, as updated as ItemAdd() + if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) + return false; + IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function + + // Test if we are hovering the right window (our window could be behind another window) + // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable to use IsItemHovered() after EndChild() itself. + // Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was the test that has been running for a long while. + //if (g.HoveredWindow != window) + // return false; + if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped)) + return false; + + // Test if another item is active (e.g. being dragged) + if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) + return false; + + // Test if interactions on this window are blocked by an active popup or modal + if (!IsWindowContentHoverable(window, flags)) + return false; + + // Test if the item is disabled + if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + return false; + + // Special handling for the dummy item after Begin() which represent the title bar or tab. + // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. + if (window->DC.LastItemId == window->MoveId && window->WriteAccessed) + return false; + return true; +} + +// Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered(). +bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) +{ + ImGuiContext& g = *GImGui; + if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap) + return false; + + ImGuiWindow* window = g.CurrentWindow; + if (g.HoveredWindow != window) + return false; + if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap) + return false; + if (!IsMouseHoveringRect(bb.Min, bb.Max)) + return false; + if (g.NavDisableMouseHover || !IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) + return false; + if (window->DC.ItemFlags & ImGuiItemFlags_Disabled) + return false; + + SetHoveredID(id); + return true; +} + +bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!bb.Overlaps(window->ClipRect)) + if (id == 0 || id != g.ActiveId) + if (clip_even_when_logged || !g.LogEnabled) + return true; + return false; +} + +// Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out. +bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id) +{ + ImGuiContext& g = *GImGui; + + // Increment counters + const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0; + window->DC.FocusCounterAll++; + if (is_tab_stop) + window->DC.FocusCounterTab++; + + // Process TAB/Shift-TAB to tab *OUT* of the currently focused item. + // (Note that we can always TAB out of a widget that doesn't allow tabbing in) + if (g.ActiveId == id && g.FocusTabPressed && !(g.ActiveIdBlockNavInputFlags & (1 << ImGuiNavInput_KeyTab_)) && g.FocusRequestNextWindow == NULL) + { + g.FocusRequestNextWindow = window; + g.FocusRequestNextCounterTab = window->DC.FocusCounterTab + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items. + } + + // Handle focus requests + if (g.FocusRequestCurrWindow == window) + { + if (window->DC.FocusCounterAll == g.FocusRequestCurrCounterAll) + return true; + if (is_tab_stop && window->DC.FocusCounterTab == g.FocusRequestCurrCounterTab) + { + g.NavJustTabbedId = id; + return true; + } + + // If another item is about to be focused, we clear our own active id + if (g.ActiveId == id) + ClearActiveID(); + } + + return false; +} + +void ImGui::FocusableItemUnregister(ImGuiWindow* window) +{ + window->DC.FocusCounterAll--; + window->DC.FocusCounterTab--; +} + +ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_x, float default_y) +{ + ImGuiContext& g = *GImGui; + ImVec2 content_max; + if (size.x < 0.0f || size.y < 0.0f) + content_max = g.CurrentWindow->Pos + GetContentRegionMax(); + if (size.x <= 0.0f) + size.x = (size.x == 0.0f) ? default_x : ImMax(content_max.x - g.CurrentWindow->DC.CursorPos.x, 4.0f) + size.x; + if (size.y <= 0.0f) + size.y = (size.y == 0.0f) ? default_y : ImMax(content_max.y - g.CurrentWindow->DC.CursorPos.y, 4.0f) + size.y; + return size; +} + +float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) +{ + if (wrap_pos_x < 0.0f) + return 0.0f; + + ImGuiWindow* window = GetCurrentWindowRead(); + if (wrap_pos_x == 0.0f) + wrap_pos_x = GetContentRegionMax().x + window->Pos.x; + else if (wrap_pos_x > 0.0f) + wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space + + return ImMax(wrap_pos_x - pos.x, 1.0f); +} + +void* ImGui::MemAlloc(size_t size) +{ + if (ImGuiContext* ctx = GImGui) + ctx->IO.MetricsActiveAllocations++; + return GImAllocatorAllocFunc(size, GImAllocatorUserData); +} + +void ImGui::MemFree(void* ptr) +{ + if (ptr) + if (ImGuiContext* ctx = GImGui) + ctx->IO.MetricsActiveAllocations--; + return GImAllocatorFreeFunc(ptr, GImAllocatorUserData); +} + +const char* ImGui::GetClipboardText() +{ + return GImGui->IO.GetClipboardTextFn ? GImGui->IO.GetClipboardTextFn(GImGui->IO.ClipboardUserData) : ""; +} + +void ImGui::SetClipboardText(const char* text) +{ + if (GImGui->IO.SetClipboardTextFn) + GImGui->IO.SetClipboardTextFn(GImGui->IO.ClipboardUserData, text); +} + +const char* ImGui::GetVersion() +{ + return IMGUI_VERSION; +} + +// Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself +// Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module +ImGuiContext* ImGui::GetCurrentContext() +{ + return GImGui; +} + +void ImGui::SetCurrentContext(ImGuiContext* ctx) +{ +#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC + IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this. +#else + GImGui = ctx; +#endif +} + +// Helper function to verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit +// If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. you may see different structures from what imgui.cpp sees which is highly problematic. +bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert) +{ + bool error = false; + if (strcmp(version, IMGUI_VERSION)!=0) { error = true; IM_ASSERT(strcmp(version,IMGUI_VERSION)==0 && "Mismatched version string!"); } + if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); } + if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); } + if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); } + if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); } + if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); } + return !error; +} + +void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data) +{ + GImAllocatorAllocFunc = alloc_func; + GImAllocatorFreeFunc = free_func; + GImAllocatorUserData = user_data; +} + +ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas) +{ + ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas); + if (GImGui == NULL) + SetCurrentContext(ctx); + Initialize(ctx); + return ctx; +} + +void ImGui::DestroyContext(ImGuiContext* ctx) +{ + if (ctx == NULL) + ctx = GImGui; + Shutdown(ctx); + if (GImGui == ctx) + SetCurrentContext(NULL); + IM_DELETE(ctx); +} + +ImGuiIO& ImGui::GetIO() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); + return GImGui->IO; +} + +ImGuiStyle& ImGui::GetStyle() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); + return GImGui->Style; +} + +// Same value as passed to the old io.RenderDrawListsFn function. Valid after Render() and until the next call to NewFrame() +ImDrawData* ImGui::GetDrawData() +{ + ImGuiContext& g = *GImGui; + return g.DrawData.Valid ? &g.DrawData : NULL; +} + +double ImGui::GetTime() +{ + return GImGui->Time; +} + +int ImGui::GetFrameCount() +{ + return GImGui->FrameCount; +} + +ImDrawList* ImGui::GetBackgroundDrawList() +{ + return &GImGui->BackgroundDrawList; +} + +static ImDrawList* GetForegroundDrawList(ImGuiWindow*) +{ + // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. + return &GImGui->ForegroundDrawList; +} + +ImDrawList* ImGui::GetForegroundDrawList() +{ + return &GImGui->ForegroundDrawList; +} + +ImDrawListSharedData* ImGui::GetDrawListSharedData() +{ + return &GImGui->DrawListSharedData; +} + +void ImGui::StartMouseMovingWindow(ImGuiWindow* window) +{ + // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows. + // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward. + // This is because we want ActiveId to be set even when the window is not permitted to move. + ImGuiContext& g = *GImGui; + FocusWindow(window); + SetActiveID(window->MoveId, window); + g.NavDisableHighlight = true; + g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos; + + bool can_move_window = true; + if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove)) + can_move_window = false; + if (can_move_window) + g.MovingWindow = window; +} + +// Handle mouse moving window +// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing() +void ImGui::UpdateMouseMovingWindowNewFrame() +{ + ImGuiContext& g = *GImGui; + if (g.MovingWindow != NULL) + { + // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window). + // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency. + KeepAliveID(g.ActiveId); + IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow); + ImGuiWindow* moving_window = g.MovingWindow->RootWindow; + if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos)) + { + ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset; + if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y) + { + MarkIniSettingsDirty(moving_window); + SetWindowPos(moving_window, pos, ImGuiCond_Always); + } + FocusWindow(g.MovingWindow); + } + else + { + ClearActiveID(); + g.MovingWindow = NULL; + } + } + else + { + // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others. + if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId) + { + KeepAliveID(g.ActiveId); + if (!g.IO.MouseDown[0]) + ClearActiveID(); + } + } +} + +// Initiate moving window, handle left-click and right-click focus +void ImGui::UpdateMouseMovingWindowEndFrame() +{ + // Initiate moving window + ImGuiContext& g = *GImGui; + if (g.ActiveId != 0 || g.HoveredId != 0) + return; + + // Unless we just made a window/popup appear + if (g.NavWindow && g.NavWindow->Appearing) + return; + + // Click to focus window and start moving (after we're done with all our widgets) + if (g.IO.MouseClicked[0]) + { + if (g.HoveredRootWindow != NULL) + { + StartMouseMovingWindow(g.HoveredWindow); + if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoTitleBar)) + if (!g.HoveredRootWindow->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) + g.MovingWindow = NULL; + } + else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL) + { + // Clicking on void disable focus + FocusWindow(NULL); + } + } + + // With right mouse button we close popups without changing focus + // (The left mouse button path calls FocusWindow which will lead NewFrame->ClosePopupsOverWindow to trigger) + if (g.IO.MouseClicked[1]) + { + // Find the top-most window between HoveredWindow and the front most Modal Window. + // This is where we can trim the popup stack. + ImGuiWindow* modal = GetFrontMostPopupModal(); + bool hovered_window_above_modal = false; + if (modal == NULL) + hovered_window_above_modal = true; + for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--) + { + ImGuiWindow* window = g.Windows[i]; + if (window == modal) + break; + if (window == g.HoveredWindow) + hovered_window_above_modal = true; + } + ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal); + } +} + +static bool IsWindowActiveAndVisible(ImGuiWindow* window) +{ + return (window->Active) && (!window->Hidden); +} + +static void ImGui::UpdateMouseInputs() +{ + ImGuiContext& g = *GImGui; + + // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) + if (IsMousePosValid(&g.IO.MousePos)) + g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos); + + // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta + if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev)) + g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev; + else + g.IO.MouseDelta = ImVec2(0.0f, 0.0f); + if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f) + g.NavDisableMouseHover = false; + + g.IO.MousePosPrev = g.IO.MousePos; + for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) + { + g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f; + g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f; + g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i]; + g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f; + g.IO.MouseDoubleClicked[i] = false; + if (g.IO.MouseClicked[i]) + { + if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime) + { + ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); + if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist) + g.IO.MouseDoubleClicked[i] = true; + g.IO.MouseClickedTime[i] = -FLT_MAX; // so the third click isn't turned into a double-click + } + else + { + g.IO.MouseClickedTime[i] = g.Time; + } + g.IO.MouseClickedPos[i] = g.IO.MousePos; + g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f); + g.IO.MouseDragMaxDistanceSqr[i] = 0.0f; + } + else if (g.IO.MouseDown[i]) + { + // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold + ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); + g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos)); + g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceAbs[i].x, delta_from_click_pos.x < 0.0f ? -delta_from_click_pos.x : delta_from_click_pos.x); + g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, delta_from_click_pos.y < 0.0f ? -delta_from_click_pos.y : delta_from_click_pos.y); + } + if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation + g.NavDisableMouseHover = false; + } +} + +void ImGui::UpdateMouseWheel() +{ + ImGuiContext& g = *GImGui; + if (!g.HoveredWindow || g.HoveredWindow->Collapsed) + return; + if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f) + return; + + // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent (unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set). + ImGuiWindow* window = g.HoveredWindow; + ImGuiWindow* scroll_window = window; + while ((scroll_window->Flags & ImGuiWindowFlags_ChildWindow) && (scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoScrollbar) && !(scroll_window->Flags & ImGuiWindowFlags_NoMouseInputs) && scroll_window->ParentWindow) + scroll_window = scroll_window->ParentWindow; + const bool scroll_allowed = !(scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoMouseInputs); + + if (g.IO.MouseWheel != 0.0f) + { + if (g.IO.KeyCtrl && g.IO.FontAllowUserScaling) + { + // Zoom / Scale window + const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); + const float scale = new_font_scale / window->FontWindowScale; + window->FontWindowScale = new_font_scale; + + const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; + window->Pos += offset; + window->Size *= scale; + window->SizeFull *= scale; + } + else if (!g.IO.KeyCtrl && scroll_allowed) + { + // Mouse wheel vertical scrolling + float scroll_amount = 5 * scroll_window->CalcFontSize(); + scroll_amount = (float)(int)ImMin(scroll_amount, (scroll_window->ContentsRegionRect.GetHeight() + scroll_window->WindowPadding.y * 2.0f) * 0.67f); + SetWindowScrollY(scroll_window, scroll_window->Scroll.y - g.IO.MouseWheel * scroll_amount); + } + } + if (g.IO.MouseWheelH != 0.0f && scroll_allowed && !g.IO.KeyCtrl) + { + // Mouse wheel horizontal scrolling (for hardware that supports it) + float scroll_amount = scroll_window->CalcFontSize(); + SetWindowScrollX(scroll_window, scroll_window->Scroll.x - g.IO.MouseWheelH * scroll_amount); + } +} + +// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app) +void ImGui::UpdateHoveredWindowAndCaptureFlags() +{ + ImGuiContext& g = *GImGui; + + // Find the window hovered by mouse: + // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow. + // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame. + // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms. + FindHoveredWindow(); + + // Modal windows prevents cursor from hovering behind them. + ImGuiWindow* modal_window = GetFrontMostPopupModal(); + if (modal_window) + if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window)) + g.HoveredRootWindow = g.HoveredWindow = NULL; + + // Disabled mouse? + if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse) + g.HoveredWindow = g.HoveredRootWindow = NULL; + + // We track click ownership. When clicked outside of a window the click is owned by the application and won't report hovering nor request capture even while dragging over our windows afterward. + int mouse_earliest_button_down = -1; + bool mouse_any_down = false; + for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) + { + if (g.IO.MouseClicked[i]) + g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenPopupStack.empty()); + mouse_any_down |= g.IO.MouseDown[i]; + if (g.IO.MouseDown[i]) + if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down]) + mouse_earliest_button_down = i; + } + const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down]; + + // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. + // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02) + const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0; + if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload) + g.HoveredWindow = g.HoveredRootWindow = NULL; + + // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to imgui + app) + if (g.WantCaptureMouseNextFrame != -1) + g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0); + else + g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty()); + + // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to imgui + app) + if (g.WantCaptureKeyboardNextFrame != -1) + g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); + else + g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); + if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) + g.IO.WantCaptureKeyboard = true; + + // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible + g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; +} + +void ImGui::NewFrame() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); + ImGuiContext& g = *GImGui; + +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiTestEngineHook_PreNewFrame(&g); +#endif + + // Check user data + // (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument) + IM_ASSERT(g.Initialized); + IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!"); + IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?"); + IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!"); + IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); + IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); + IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)!"); + IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); + for (int n = 0; n < ImGuiKey_COUNT; n++) + IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)"); + + // Perform simple check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only recently added in 1.60 WIP) + if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) + IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); + + // Perform simple check: the beta io.ConfigWindowsResizeFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly. + if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors)) + g.IO.ConfigWindowsResizeFromEdges = false; + + // Load settings on first frame (if not explicitly loaded manually before) + if (!g.SettingsLoaded) + { + IM_ASSERT(g.SettingsWindows.empty()); + if (g.IO.IniFilename) + LoadIniSettingsFromDisk(g.IO.IniFilename); + g.SettingsLoaded = true; + } + + // Save settings (with a delay after the last modification, so we don't spam disk too much) + if (g.SettingsDirtyTimer > 0.0f) + { + g.SettingsDirtyTimer -= g.IO.DeltaTime; + if (g.SettingsDirtyTimer <= 0.0f) + { + if (g.IO.IniFilename != NULL) + SaveIniSettingsToDisk(g.IO.IniFilename); + else + g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves. + g.SettingsDirtyTimer = 0.0f; + } + } + + g.Time += g.IO.DeltaTime; + g.FrameScopeActive = true; + g.FrameCount += 1; + g.TooltipOverrideCount = 0; + g.WindowsActiveCount = 0; + + // Setup current font and draw list shared data + g.IO.Fonts->Locked = true; + SetCurrentFont(GetDefaultFont()); + IM_ASSERT(g.Font->IsLoaded()); + g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); + g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; + + g.BackgroundDrawList.Clear(); + g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID); + g.BackgroundDrawList.PushClipRectFullScreen(); + g.BackgroundDrawList.Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0); + + g.ForegroundDrawList.Clear(); + g.ForegroundDrawList.PushTextureID(g.IO.Fonts->TexID); + g.ForegroundDrawList.PushClipRectFullScreen(); + g.ForegroundDrawList.Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0); + + // Mark rendering data as invalid to prevent user who may have a handle on it to use it. + g.DrawData.Clear(); + + // Drag and drop keep the source ID alive so even if the source disappear our state is consistent + if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId) + KeepAliveID(g.DragDropPayload.SourceId); + + // Clear reference to active widget if the widget isn't alive anymore + if (!g.HoveredIdPreviousFrame) + g.HoveredIdTimer = 0.0f; + if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId)) + g.HoveredIdNotActiveTimer = 0.0f; + if (g.HoveredId) + g.HoveredIdTimer += g.IO.DeltaTime; + if (g.HoveredId && g.ActiveId != g.HoveredId) + g.HoveredIdNotActiveTimer += g.IO.DeltaTime; + g.HoveredIdPreviousFrame = g.HoveredId; + g.HoveredId = 0; + g.HoveredIdAllowOverlap = false; + if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) + ClearActiveID(); + if (g.ActiveId) + g.ActiveIdTimer += g.IO.DeltaTime; + g.LastActiveIdTimer += g.IO.DeltaTime; + g.ActiveIdPreviousFrame = g.ActiveId; + g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow; + g.ActiveIdPreviousFrameHasBeenEdited = g.ActiveIdHasBeenEdited; + g.ActiveIdIsAlive = 0; + g.ActiveIdPreviousFrameIsAlive = false; + g.ActiveIdIsJustActivated = false; + if (g.ScalarAsInputTextId && g.ActiveId != g.ScalarAsInputTextId) + g.ScalarAsInputTextId = 0; + + // Drag and drop + g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; + g.DragDropAcceptIdCurr = 0; + g.DragDropAcceptIdCurrRectSurface = FLT_MAX; + g.DragDropWithinSourceOrTarget = false; + + // Update keyboard input state + memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration)); + for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++) + g.IO.KeysDownDuration[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownDuration[i] < 0.0f ? 0.0f : g.IO.KeysDownDuration[i] + g.IO.DeltaTime) : -1.0f; + + // Update gamepad/keyboard directional navigation + NavUpdate(); + + // Update mouse input state + UpdateMouseInputs(); + + // Calculate frame-rate for the user, as a purely luxurious feature + g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx]; + g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime; + g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame); + g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX; + + // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering) + UpdateMouseMovingWindowNewFrame(); + UpdateHoveredWindowAndCaptureFlags(); + + // Background darkening/whitening + if (GetFrontMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f)) + g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f); + else + g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f); + + g.MouseCursor = ImGuiMouseCursor_Arrow; + g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1; + g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default + + // Mouse wheel scrolling, scale + UpdateMouseWheel(); + + // Pressing TAB activate widget focus + g.FocusTabPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab)); + if (g.ActiveId == 0 && g.FocusTabPressed) + { + // Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also + // manipulate the Next fields even, even though they will be turned into Curr fields by the code below. + g.FocusRequestNextWindow = g.NavWindow; + g.FocusRequestNextCounterAll = INT_MAX; + if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX) + g.FocusRequestNextCounterTab = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1); + else + g.FocusRequestNextCounterTab = g.IO.KeyShift ? -1 : 0; + } + + // Turn queued focus request into current one + g.FocusRequestCurrWindow = NULL; + g.FocusRequestCurrCounterAll = g.FocusRequestCurrCounterTab = INT_MAX; + if (g.FocusRequestNextWindow != NULL) + { + ImGuiWindow* window = g.FocusRequestNextWindow; + g.FocusRequestCurrWindow = window; + if (g.FocusRequestNextCounterAll != INT_MAX && window->DC.FocusCounterAll != -1) + g.FocusRequestCurrCounterAll = ImModPositive(g.FocusRequestNextCounterAll, window->DC.FocusCounterAll + 1); + if (g.FocusRequestNextCounterTab != INT_MAX && window->DC.FocusCounterTab != -1) + g.FocusRequestCurrCounterTab = ImModPositive(g.FocusRequestNextCounterTab, window->DC.FocusCounterTab + 1); + g.FocusRequestNextWindow = NULL; + g.FocusRequestNextCounterAll = g.FocusRequestNextCounterTab = INT_MAX; + } + + g.NavIdTabCounter = INT_MAX; + + // Mark all windows as not visible + IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size); + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + window->WasActive = window->Active; + window->Active = false; + window->WriteAccessed = false; + } + + // Closing the focused window restore focus to the first active root window in descending z-order + if (g.NavWindow && !g.NavWindow->WasActive) + FocusPreviousWindowIgnoringOne(NULL); + + // No window should be open at the beginning of the frame. + // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. + g.CurrentWindowStack.resize(0); + g.BeginPopupStack.resize(0); + ClosePopupsOverWindow(g.NavWindow); + + // Create implicit/fallback window - which we will only render it if the user has added something to it. + // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. + // This fallback is particularly important as it avoid ImGui:: calls from crashing. + SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver); + Begin("Debug##Default"); + g.FrameScopePushedImplicitWindow = true; + +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiTestEngineHook_PostNewFrame(&g); +#endif +} + +void ImGui::Initialize(ImGuiContext* context) +{ + ImGuiContext& g = *context; + IM_ASSERT(!g.Initialized && !g.SettingsLoaded); + + // Add .ini handle for ImGuiWindow type + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "Window"; + ini_handler.TypeHash = ImHashStr("Window", 0); + ini_handler.ReadOpenFn = SettingsHandlerWindow_ReadOpen; + ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine; + ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll; + g.SettingsHandlers.push_back(ini_handler); + + g.Initialized = true; +} + +// This function is merely here to free heap allocations. +void ImGui::Shutdown(ImGuiContext* context) +{ + // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame) + ImGuiContext& g = *context; + if (g.IO.Fonts && g.FontAtlasOwnedByContext) + { + g.IO.Fonts->Locked = false; + IM_DELETE(g.IO.Fonts); + } + g.IO.Fonts = NULL; + + // Cleanup of other data are conditional on actually having initialized ImGui. + if (!g.Initialized) + return; + + // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file) + if (g.SettingsLoaded && g.IO.IniFilename != NULL) + { + ImGuiContext* backup_context = GImGui; + SetCurrentContext(context); + SaveIniSettingsToDisk(g.IO.IniFilename); + SetCurrentContext(backup_context); + } + + // Clear everything else + for (int i = 0; i < g.Windows.Size; i++) + IM_DELETE(g.Windows[i]); + g.Windows.clear(); + g.WindowsFocusOrder.clear(); + g.WindowsSortBuffer.clear(); + g.CurrentWindow = NULL; + g.CurrentWindowStack.clear(); + g.WindowsById.Clear(); + g.NavWindow = NULL; + g.HoveredWindow = g.HoveredRootWindow = NULL; + g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; + g.MovingWindow = NULL; + g.ColorModifiers.clear(); + g.StyleModifiers.clear(); + g.FontStack.clear(); + g.OpenPopupStack.clear(); + g.BeginPopupStack.clear(); + g.DrawDataBuilder.ClearFreeMemory(); + g.BackgroundDrawList.ClearFreeMemory(); + g.ForegroundDrawList.ClearFreeMemory(); + g.PrivateClipboard.clear(); + g.InputTextState.ClearFreeMemory(); + + for (int i = 0; i < g.SettingsWindows.Size; i++) + IM_DELETE(g.SettingsWindows[i].Name); + g.SettingsWindows.clear(); + g.SettingsHandlers.clear(); + + if (g.LogFile && g.LogFile != stdout) + { + fclose(g.LogFile); + g.LogFile = NULL; + } + g.LogBuffer.clear(); + + g.Initialized = false; +} + +// FIXME: Add a more explicit sort order in the window structure. +static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs) +{ + const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs; + const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs; + if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup)) + return d; + if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip)) + return d; + return (a->BeginOrderWithinParent - b->BeginOrderWithinParent); +} + +static void AddWindowToSortBuffer(ImVector* out_sorted_windows, ImGuiWindow* window) +{ + out_sorted_windows->push_back(window); + if (window->Active) + { + int count = window->DC.ChildWindows.Size; + if (count > 1) + ImQsort(window->DC.ChildWindows.begin(), (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer); + for (int i = 0; i < count; i++) + { + ImGuiWindow* child = window->DC.ChildWindows[i]; + if (child->Active) + AddWindowToSortBuffer(out_sorted_windows, child); + } + } +} + +static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list) +{ + if (draw_list->CmdBuffer.empty()) + return; + + // Remove trailing command if unused + ImDrawCmd& last_cmd = draw_list->CmdBuffer.back(); + if (last_cmd.ElemCount == 0 && last_cmd.UserCallback == NULL) + { + draw_list->CmdBuffer.pop_back(); + if (draw_list->CmdBuffer.empty()) + return; + } + + // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. May trigger for you if you are using PrimXXX functions incorrectly. + IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); + IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); + IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); + + // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) + // If this assert triggers because you are drawing lots of stuff manually: + // A) Make sure you are coarse clipping, because ImDrawList let all your vertices pass. You can use the Metrics window to inspect draw list contents. + // B) If you need/want meshes with more than 64K vertices, uncomment the '#define ImDrawIdx unsigned int' line in imconfig.h to set the index size to 4 bytes. + // You'll need to handle the 4-bytes indices to your renderer. For example, the OpenGL example code detect index size at compile-time by doing: + // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); + // Your own engine or render API may use different parameters or function calls to specify index sizes. 2 and 4 bytes indices are generally supported by most API. + // C) If for some reason you cannot use 4 bytes indices or don't want to, a workaround is to call BeginChild()/EndChild() before reaching the 64K limit to split your draw commands in multiple draw lists. + if (sizeof(ImDrawIdx) == 2) + IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); + + out_list->push_back(draw_list); +} + +static void AddWindowToDrawData(ImVector* out_render_list, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + g.IO.MetricsRenderWindows++; + AddDrawListToDrawData(out_render_list, window->DrawList); + for (int i = 0; i < window->DC.ChildWindows.Size; i++) + { + ImGuiWindow* child = window->DC.ChildWindows[i]; + if (IsWindowActiveAndVisible(child)) // clipped children may have been marked not active + AddWindowToDrawData(out_render_list, child); + } +} + +static void AddRootWindowToDrawData(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (window->Flags & ImGuiWindowFlags_Tooltip) + AddWindowToDrawData(&g.DrawDataBuilder.Layers[1], window); + else + AddWindowToDrawData(&g.DrawDataBuilder.Layers[0], window); +} + +void ImDrawDataBuilder::FlattenIntoSingleLayer() +{ + int n = Layers[0].Size; + int size = n; + for (int i = 1; i < IM_ARRAYSIZE(Layers); i++) + size += Layers[i].Size; + Layers[0].resize(size); + for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++) + { + ImVector& layer = Layers[layer_n]; + if (layer.empty()) + continue; + memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*)); + n += layer.Size; + layer.resize(0); + } +} + +static void SetupDrawData(ImVector* draw_lists, ImDrawData* draw_data) +{ + ImGuiIO& io = ImGui::GetIO(); + draw_data->Valid = true; + draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL; + draw_data->CmdListsCount = draw_lists->Size; + draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0; + draw_data->DisplayPos = ImVec2(0.0f, 0.0f); + draw_data->DisplaySize = io.DisplaySize; + draw_data->FramebufferScale = io.DisplayFramebufferScale; + for (int n = 0; n < draw_lists->Size; n++) + { + draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size; + draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size; + } +} + +// When using this function it is sane to ensure that float are perfectly rounded to integer values, to that e.g. (int)(max.x-min.x) in user's render produce correct result. +void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect); + window->ClipRect = window->DrawList->_ClipRectStack.back(); +} + +void ImGui::PopClipRect() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DrawList->PopClipRect(); + window->ClipRect = window->DrawList->_ClipRectStack.back(); +} + +// This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal. +void ImGui::EndFrame() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + if (g.FrameCountEnded == g.FrameCount) // Don't process EndFrame() multiple times. + return; + IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()?"); + + // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) + if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f)) + { + g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y); + g.PlatformImeLastPos = g.PlatformImePos; + } + + // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you + // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). + if (g.CurrentWindowStack.Size != 1) + { + if (g.CurrentWindowStack.Size > 1) + { + IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); + while (g.CurrentWindowStack.Size > 1) // FIXME-ERRORHANDLING + End(); + } + else + { + IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); + } + } + + // Hide implicit/fallback "Debug" window if it hasn't been used + g.FrameScopePushedImplicitWindow = false; + if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) + g.CurrentWindow->Active = false; + End(); + + // Show CTRL+TAB list window + if (g.NavWindowingTarget) + NavUpdateWindowingList(); + + // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted) + if (g.DragDropActive) + { + bool is_delivered = g.DragDropPayload.Delivery; + bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton)); + if (is_delivered || is_elapsed) + ClearDragDrop(); + } + + // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing. + if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount) + { + g.DragDropWithinSourceOrTarget = true; + SetTooltip("..."); + g.DragDropWithinSourceOrTarget = false; + } + + // End frame + g.FrameScopeActive = false; + g.FrameCountEnded = g.FrameCount; + + // Initiate moving window + handle left-click and right-click focus + UpdateMouseMovingWindowEndFrame(); + + // Sort the window list so that all child windows are after their parent + // We cannot do that on FocusWindow() because childs may not exist yet + g.WindowsSortBuffer.resize(0); + g.WindowsSortBuffer.reserve(g.Windows.Size); + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it + continue; + AddWindowToSortBuffer(&g.WindowsSortBuffer, window); + } + + // This usually assert if there is a mismatch between the ImGuiWindowFlags_ChildWindow / ParentWindow values and DC.ChildWindows[] in parents, aka we've done something wrong. + IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size); + g.Windows.swap(g.WindowsSortBuffer); + g.IO.MetricsActiveWindows = g.WindowsActiveCount; + + // Unlock font atlas + g.IO.Fonts->Locked = false; + + // Clear Input data for next frame + g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f; + g.IO.InputQueueCharacters.resize(0); + memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs)); +} + +void ImGui::Render() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + + if (g.FrameCountEnded != g.FrameCount) + EndFrame(); + g.FrameCountRendered = g.FrameCount; + + // Gather ImDrawList to render (for each active window) + g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = g.IO.MetricsRenderWindows = 0; + g.DrawDataBuilder.Clear(); + if (!g.BackgroundDrawList.VtxBuffer.empty()) + AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.BackgroundDrawList); + + ImGuiWindow* windows_to_render_front_most[2]; + windows_to_render_front_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL; + windows_to_render_front_most[1] = g.NavWindowingTarget ? g.NavWindowingList : NULL; + for (int n = 0; n != g.Windows.Size; n++) + { + ImGuiWindow* window = g.Windows[n]; + if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_front_most[0] && window != windows_to_render_front_most[1]) + AddRootWindowToDrawData(window); + } + for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_front_most); n++) + if (windows_to_render_front_most[n] && IsWindowActiveAndVisible(windows_to_render_front_most[n])) // NavWindowingTarget is always temporarily displayed as the front-most window + AddRootWindowToDrawData(windows_to_render_front_most[n]); + g.DrawDataBuilder.FlattenIntoSingleLayer(); + + // Draw software mouse cursor if requested + if (g.IO.MouseDrawCursor) + RenderMouseCursor(&g.ForegroundDrawList, g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor); + + if (!g.ForegroundDrawList.VtxBuffer.empty()) + AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.ForegroundDrawList); + + // Setup ImDrawData structure for end-user + SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData); + g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount; + g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount; + + // (Legacy) Call the Render callback function. The current prefer way is to let the user retrieve GetDrawData() and call the render function themselves. +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (g.DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL) + g.IO.RenderDrawListsFn(&g.DrawData); +#endif +} + +// Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker. +// CalcTextSize("") should return ImVec2(0.0f, GImGui->FontSize) +ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) +{ + ImGuiContext& g = *GImGui; + + const char* text_display_end; + if (hide_text_after_double_hash) + text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string + else + text_display_end = text_end; + + ImFont* font = g.Font; + const float font_size = g.FontSize; + if (text == text_display_end) + return ImVec2(0.0f, font_size); + ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); + + // Round + text_size.x = (float)(int)(text_size.x + 0.95f); + + return text_size; +} + +// Helper to calculate coarse clipping of large list of evenly sized items. +// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern. +// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX +void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.LogEnabled) + { + // If logging is active, do not perform any clipping + *out_items_display_start = 0; + *out_items_display_end = items_count; + return; + } + if (window->SkipItems) + { + *out_items_display_start = *out_items_display_end = 0; + return; + } + + // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect + ImRect unclipped_rect = window->ClipRect; + if (g.NavMoveRequest) + unclipped_rect.Add(g.NavScoringRectScreen); + + const ImVec2 pos = window->DC.CursorPos; + int start = (int)((unclipped_rect.Min.y - pos.y) / items_height); + int end = (int)((unclipped_rect.Max.y - pos.y) / items_height); + + // When performing a navigation request, ensure we have one item extra in the direction we are moving to + if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up) + start--; + if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down) + end++; + + start = ImClamp(start, 0, items_count); + end = ImClamp(end + 1, start, items_count); + *out_items_display_start = start; + *out_items_display_end = end; +} + +// Find window given position, search front-to-back +// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programatically +// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is +// called, aka before the next Begin(). Moving window isn't affected. +static void FindHoveredWindow() +{ + ImGuiContext& g = *GImGui; + + ImGuiWindow* hovered_window = NULL; + if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs)) + hovered_window = g.MovingWindow; + + ImVec2 padding_regular = g.Style.TouchExtraPadding; + ImVec2 padding_for_resize_from_edges = g.IO.ConfigWindowsResizeFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)) : padding_regular; + for (int i = g.Windows.Size - 1; i >= 0; i--) + { + ImGuiWindow* window = g.Windows[i]; + if (!window->Active || window->Hidden) + continue; + if (window->Flags & ImGuiWindowFlags_NoMouseInputs) + continue; + + // Using the clipped AABB, a child window will typically be clipped by its parent (not always) + ImRect bb(window->OuterRectClipped); + if ((window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_NoResize)) + bb.Expand(padding_regular); + else + bb.Expand(padding_for_resize_from_edges); + if (!bb.Contains(g.IO.MousePos)) + continue; + + // Those seemingly unnecessary extra tests are because the code here is a little different in viewport/docking branches. + if (hovered_window == NULL) + hovered_window = window; + if (hovered_window) + break; + } + + g.HoveredWindow = hovered_window; + g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; + +} + +// Test if mouse cursor is hovering given rectangle +// NB- Rectangle is clipped by our current clip setting +// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) +bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) +{ + ImGuiContext& g = *GImGui; + + // Clip + ImRect rect_clipped(r_min, r_max); + if (clip) + rect_clipped.ClipWith(g.CurrentWindow->ClipRect); + + // Expand for touch input + const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); + if (!rect_for_touch.Contains(g.IO.MousePos)) + return false; + return true; +} + +int ImGui::GetKeyIndex(ImGuiKey imgui_key) +{ + IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT); + return GImGui->IO.KeyMap[imgui_key]; +} + +// Note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]! +bool ImGui::IsKeyDown(int user_key_index) +{ + if (user_key_index < 0) return false; + IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(GImGui->IO.KeysDown)); + return GImGui->IO.KeysDown[user_key_index]; +} + +int ImGui::CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate) +{ + if (t == 0.0f) + return 1; + if (t <= repeat_delay || repeat_rate <= 0.0f) + return 0; + const int count = (int)((t - repeat_delay) / repeat_rate) - (int)((t_prev - repeat_delay) / repeat_rate); + return (count > 0) ? count : 0; +} + +int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate) +{ + ImGuiContext& g = *GImGui; + if (key_index < 0) + return 0; + IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + const float t = g.IO.KeysDownDuration[key_index]; + return CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, repeat_delay, repeat_rate); +} + +bool ImGui::IsKeyPressed(int user_key_index, bool repeat) +{ + ImGuiContext& g = *GImGui; + if (user_key_index < 0) + return false; + IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + const float t = g.IO.KeysDownDuration[user_key_index]; + if (t == 0.0f) + return true; + if (repeat && t > g.IO.KeyRepeatDelay) + return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; + return false; +} + +bool ImGui::IsKeyReleased(int user_key_index) +{ + ImGuiContext& g = *GImGui; + if (user_key_index < 0) return false; + IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index]; +} + +bool ImGui::IsMouseDown(int button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDown[button]; +} + +bool ImGui::IsAnyMouseDown() +{ + ImGuiContext& g = *GImGui; + for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++) + if (g.IO.MouseDown[n]) + return true; + return false; +} + +bool ImGui::IsMouseClicked(int button, bool repeat) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + const float t = g.IO.MouseDownDuration[button]; + if (t == 0.0f) + return true; + + if (repeat && t > g.IO.KeyRepeatDelay) + { + float delay = g.IO.KeyRepeatDelay, rate = g.IO.KeyRepeatRate; + if ((ImFmod(t - delay, rate) > rate*0.5f) != (ImFmod(t - delay - g.IO.DeltaTime, rate) > rate*0.5f)) + return true; + } + + return false; +} + +bool ImGui::IsMouseReleased(int button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseReleased[button]; +} + +bool ImGui::IsMouseDoubleClicked(int button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDoubleClicked[button]; +} + +bool ImGui::IsMouseDragging(int button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (!g.IO.MouseDown[button]) + return false; + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold; +} + +ImVec2 ImGui::GetMousePos() +{ + return GImGui->IO.MousePos; +} + +// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! +ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() +{ + ImGuiContext& g = *GImGui; + if (g.BeginPopupStack.Size > 0) + return g.OpenPopupStack[g.BeginPopupStack.Size-1].OpenMousePos; + return g.IO.MousePos; +} + +// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. +bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) +{ + // The assert is only to silence a false-positive in XCode Static Analysis. + // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions). + IM_ASSERT(GImGui != NULL); + const float MOUSE_INVALID = -256000.0f; + ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; + return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; +} + +// Return the delta from the initial clicking position. +// This is locked and return 0.0f until the mouse moves past a distance threshold at least once. +// NB: This is only valid if IsMousePosValid(). Back-ends in theory should always keep mouse position valid when dragging even outside the client window. +ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + if (g.IO.MouseDown[button]) + if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) + return g.IO.MousePos - g.IO.MouseClickedPos[button]; // Assume we can only get active with left-mouse button (at the moment). + return ImVec2(0.0f, 0.0f); +} + +void ImGui::ResetMouseDragDelta(int button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr + g.IO.MouseClickedPos[button] = g.IO.MousePos; +} + +ImGuiMouseCursor ImGui::GetMouseCursor() +{ + return GImGui->MouseCursor; +} + +void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) +{ + GImGui->MouseCursor = cursor_type; +} + +void ImGui::CaptureKeyboardFromApp(bool capture) +{ + GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0; +} + +void ImGui::CaptureMouseFromApp(bool capture) +{ + GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0; +} + +bool ImGui::IsItemActive() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId) + { + ImGuiWindow* window = g.CurrentWindow; + return g.ActiveId == window->DC.LastItemId; + } + return false; +} + +bool ImGui::IsItemActivated() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId) + { + ImGuiWindow* window = g.CurrentWindow; + if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId) + return true; + } + return false; +} + +bool ImGui::IsItemDeactivated() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId); +} + +bool ImGui::IsItemDeactivatedAfterEdit() +{ + ImGuiContext& g = *GImGui; + return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEdited || (g.ActiveId == 0 && g.ActiveIdHasBeenEdited)); +} + +bool ImGui::IsItemFocused() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (g.NavId == 0 || g.NavDisableHighlight || g.NavId != window->DC.LastItemId) + return false; + return true; +} + +bool ImGui::IsItemClicked(int mouse_button) +{ + return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None); +} + +bool ImGui::IsAnyItemHovered() +{ + ImGuiContext& g = *GImGui; + return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0; +} + +bool ImGui::IsAnyItemActive() +{ + ImGuiContext& g = *GImGui; + return g.ActiveId != 0; +} + +bool ImGui::IsAnyItemFocused() +{ + ImGuiContext& g = *GImGui; + return g.NavId != 0 && !g.NavDisableHighlight; +} + +bool ImGui::IsItemVisible() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->ClipRect.Overlaps(window->DC.LastItemRect); +} + +bool ImGui::IsItemEdited() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0; +} + +// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority. +void ImGui::SetItemAllowOverlap() +{ + ImGuiContext& g = *GImGui; + if (g.HoveredId == g.CurrentWindow->DC.LastItemId) + g.HoveredIdAllowOverlap = true; + if (g.ActiveId == g.CurrentWindow->DC.LastItemId) + g.ActiveIdAllowOverlap = true; +} + +ImVec2 ImGui::GetItemRectMin() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.LastItemRect.Min; +} + +ImVec2 ImGui::GetItemRectMax() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.LastItemRect.Max; +} + +ImVec2 ImGui::GetItemRectSize() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.LastItemRect.GetSize(); +} + +static ImRect GetViewportRect() +{ + ImGuiContext& g = *GImGui; + return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); +} + +static bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* parent_window = g.CurrentWindow; + + flags |= ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_ChildWindow; + flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag + + // Size + const ImVec2 content_avail = GetContentRegionAvail(); + ImVec2 size = ImFloor(size_arg); + const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00); + if (size.x <= 0.0f) + size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues) + if (size.y <= 0.0f) + size.y = ImMax(content_avail.y + size.y, 4.0f); + SetNextWindowSize(size); + + // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value. + char title[256]; + if (name) + ImFormatString(title, IM_ARRAYSIZE(title), "%s/%s_%08X", parent_window->Name, name, id); + else + ImFormatString(title, IM_ARRAYSIZE(title), "%s/%08X", parent_window->Name, id); + + const float backup_border_size = g.Style.ChildBorderSize; + if (!border) + g.Style.ChildBorderSize = 0.0f; + bool ret = Begin(title, NULL, flags); + g.Style.ChildBorderSize = backup_border_size; + + ImGuiWindow* child_window = g.CurrentWindow; + child_window->ChildId = id; + child_window->AutoFitChildAxises = auto_fit_axises; + + // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually. + // While this is not really documented/defined, it seems that the expected thing to do. + if (child_window->BeginCount == 1) + parent_window->DC.CursorPos = child_window->Pos; + + // Process navigation-in immediately so NavInit can run on first frame + if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll)) + { + FocusWindow(child_window); + NavInitWindow(child_window, false); + SetActiveID(id+1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item + g.ActiveIdSource = ImGuiInputSource_Nav; + } + return ret; +} + +bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags); +} + +bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) +{ + IM_ASSERT(id != 0); + return BeginChildEx(NULL, id, size_arg, border, extra_flags); +} + +void ImGui::EndChild() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() callss + if (window->BeginCount > 1) + { + End(); + } + else + { + ImVec2 sz = window->Size; + if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f + sz.x = ImMax(4.0f, sz.x); + if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y)) + sz.y = ImMax(4.0f, sz.y); + End(); + + ImGuiWindow* parent_window = g.CurrentWindow; + ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz); + ItemSize(sz); + if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) + { + ItemAdd(bb, window->ChildId); + RenderNavHighlight(bb, window->ChildId); + + // When browsing a window that has no activable items (scroll only) we keep a highlight on the child + if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow) + RenderNavHighlight(ImRect(bb.Min - ImVec2(2,2), bb.Max + ImVec2(2,2)), g.NavId, ImGuiNavHighlightFlags_TypeThin); + } + else + { + // Not navigable into + ItemAdd(bb, 0); + } + } +} + +// Helper to create a child window / scrolling region that looks like a normal widget frame. +bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags) +{ + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); + PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); + PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); + PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); + bool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags); + PopStyleVar(3); + PopStyleColor(); + return ret; +} + +void ImGui::EndChildFrame() +{ + EndChild(); +} + +// Save and compare stack sizes on Begin()/End() to detect usage errors +static void CheckStacksSize(ImGuiWindow* window, bool write) +{ + // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) + ImGuiContext& g = *GImGui; + short* p_backup = &window->DC.StackSizesBackup[0]; + { int current = window->IDStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop() + { int current = window->DC.GroupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup() + { int current = g.BeginPopupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup() + // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. + { int current = g.ColorModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor() + { int current = g.StyleModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar() + { int current = g.FontStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushFont/PopFont Mismatch!"); p_backup++; } // Too few or too many PopFont() + IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); +} + +static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled) +{ + window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags); + window->SetWindowSizeAllowFlags = enabled ? (window->SetWindowSizeAllowFlags | flags) : (window->SetWindowSizeAllowFlags & ~flags); + window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags); +} + +ImGuiWindow* ImGui::FindWindowByID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id); +} + +ImGuiWindow* ImGui::FindWindowByName(const char* name) +{ + ImGuiID id = ImHashStr(name, 0); + return FindWindowByID(id); +} + +static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + + // Create window the first time + ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); + window->Flags = flags; + g.WindowsById.SetVoidPtr(window->ID, window); + + // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. + window->Pos = ImVec2(60, 60); + + // User can disable loading and saving of settings. Tooltip and child windows also don't store settings. + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) + if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) + { + // Retrieve settings from .ini file + window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings); + SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); + window->Pos = ImFloor(settings->Pos); + window->Collapsed = settings->Collapsed; + if (ImLengthSqr(settings->Size) > 0.00001f) + size = ImFloor(settings->Size); + } + window->Size = window->SizeFull = window->SizeFullAtLastBegin = ImFloor(size); + window->DC.CursorMaxPos = window->Pos; // So first call to CalcSizeContents() doesn't return crazy values + + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) + { + window->AutoFitFramesX = window->AutoFitFramesY = 2; + window->AutoFitOnlyGrows = false; + } + else + { + if (window->Size.x <= 0.0f) + window->AutoFitFramesX = 2; + if (window->Size.y <= 0.0f) + window->AutoFitFramesY = 2; + window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0); + } + + g.WindowsFocusOrder.push_back(window); + if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) + g.Windows.push_front(window); // Quite slow but rare and only once + else + g.Windows.push_back(window); + return window; +} + +static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size) +{ + ImGuiContext& g = *GImGui; + if (g.NextWindowData.SizeConstraintCond != 0) + { + // Using -1,-1 on either X/Y axis to preserve the current size. + ImRect cr = g.NextWindowData.SizeConstraintRect; + new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x; + new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y; + if (g.NextWindowData.SizeCallback) + { + ImGuiSizeCallbackData data; + data.UserData = g.NextWindowData.SizeCallbackUserData; + data.Pos = window->Pos; + data.CurrentSize = window->SizeFull; + data.DesiredSize = new_size; + g.NextWindowData.SizeCallback(&data); + new_size = data.DesiredSize; + } + } + + // Minimum size + if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) + { + new_size = ImMax(new_size, g.Style.WindowMinSize); + new_size.y = ImMax(new_size.y, window->TitleBarHeight() + window->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows + } + return new_size; +} + +static ImVec2 CalcSizeContents(ImGuiWindow* window) +{ + if (window->Collapsed) + if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + return window->SizeContents; + if (window->Hidden && window->HiddenFramesForResize == 0 && window->HiddenFramesRegular > 0) + return window->SizeContents; + + ImVec2 sz; + sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : (window->DC.CursorMaxPos.x - window->Pos.x + window->Scroll.x)); + sz.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : (window->DC.CursorMaxPos.y - window->Pos.y + window->Scroll.y)); + return sz + window->WindowPadding; +} + +static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + if (window->Flags & ImGuiWindowFlags_Tooltip) + { + // Tooltip always resize + return size_contents; + } + else + { + // Maximum window size is determined by the display size + const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0; + const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0; + ImVec2 size_min = style.WindowMinSize; + if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups) + size_min = ImMin(size_min, ImVec2(4.0f, 4.0f)); + ImVec2 size_auto_fit = ImClamp(size_contents, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f)); + + // When the window cannot fit all contents (either because of constraints, either because screen is too small), + // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. + ImVec2 size_auto_fit_after_constraint = CalcSizeAfterConstraint(window, size_auto_fit); + if (size_auto_fit_after_constraint.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) + size_auto_fit.y += style.ScrollbarSize; + if (size_auto_fit_after_constraint.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) + size_auto_fit.x += style.ScrollbarSize; + return size_auto_fit; + } +} + +ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window) +{ + ImVec2 size_contents = CalcSizeContents(window); + return CalcSizeAfterConstraint(window, CalcSizeAutoFit(window, size_contents)); +} + +float ImGui::GetWindowScrollMaxX(ImGuiWindow* window) +{ + return ImMax(0.0f, window->SizeContents.x - (window->SizeFull.x - window->ScrollbarSizes.x)); +} + +float ImGui::GetWindowScrollMaxY(ImGuiWindow* window) +{ + return ImMax(0.0f, window->SizeContents.y - (window->SizeFull.y - window->ScrollbarSizes.y)); +} + +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges) +{ + ImGuiContext& g = *GImGui; + ImVec2 scroll = window->Scroll; + if (window->ScrollTarget.x < FLT_MAX) + { + float cr_x = window->ScrollTargetCenterRatio.x; + scroll.x = window->ScrollTarget.x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x); + } + if (window->ScrollTarget.y < FLT_MAX) + { + // 'snap_on_edges' allows for a discontinuity at the edge of scrolling limits to take account of WindowPadding so that scrolling to make the last item visible scroll far enough to see the padding. + float cr_y = window->ScrollTargetCenterRatio.y; + float target_y = window->ScrollTarget.y; + if (snap_on_edges && cr_y <= 0.0f && target_y <= window->WindowPadding.y) + target_y = 0.0f; + if (snap_on_edges && cr_y >= 1.0f && target_y >= window->SizeContents.y - window->WindowPadding.y + g.Style.ItemSpacing.y) + target_y = window->SizeContents.y; + scroll.y = target_y - (1.0f - cr_y) * (window->TitleBarHeight() + window->MenuBarHeight()) - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y); + } + scroll = ImMax(scroll, ImVec2(0.0f, 0.0f)); + if (!window->Collapsed && !window->SkipItems) + { + scroll.x = ImMin(scroll.x, ImGui::GetWindowScrollMaxX(window)); + scroll.y = ImMin(scroll.y, ImGui::GetWindowScrollMaxY(window)); + } + return scroll; +} + +static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags) +{ + if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) + return ImGuiCol_PopupBg; + if (flags & ImGuiWindowFlags_ChildWindow) + return ImGuiCol_ChildBg; + return ImGuiCol_WindowBg; +} + +static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size) +{ + ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left + ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right + ImVec2 size_expected = pos_max - pos_min; + ImVec2 size_constrained = CalcSizeAfterConstraint(window, size_expected); + *out_pos = pos_min; + if (corner_norm.x == 0.0f) + out_pos->x -= (size_constrained.x - size_expected.x); + if (corner_norm.y == 0.0f) + out_pos->y -= (size_constrained.y - size_expected.y); + *out_size = size_constrained; +} + +struct ImGuiResizeGripDef +{ + ImVec2 CornerPosN; + ImVec2 InnerDir; + int AngleMin12, AngleMax12; +}; + +static const ImGuiResizeGripDef resize_grip_def[4] = +{ + { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower right + { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower left + { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper left + { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper right +}; + +static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness) +{ + ImRect rect = window->Rect(); + if (thickness == 0.0f) rect.Max -= ImVec2(1,1); + if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); // Top + if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); // Right + if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); // Bottom + if (border_n == 3) return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); // Left + IM_ASSERT(0); + return ImRect(); +} + +// Handle resize for: Resize Grips, Borders, Gamepad +static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]) +{ + ImGuiContext& g = *GImGui; + ImGuiWindowFlags flags = window->Flags; + if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) + return; + if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window. + return; + + const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0; + const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f); + const float grip_hover_inner_size = (float)(int)(grip_draw_size * 0.75f); + const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f; + + ImVec2 pos_target(FLT_MAX, FLT_MAX); + ImVec2 size_target(FLT_MAX, FLT_MAX); + + // Manual resize grips + PushID("#RESIZE"); + for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) + { + const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); + + // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window + ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size); + if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x); + if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y); + bool hovered, held; + ButtonBehavior(resize_rect, window->GetID((void*)(intptr_t)resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); + //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255)); + if (hovered || held) + g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; + + if (held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0) + { + // Manual auto-fit when double-clicking + size_target = CalcSizeAfterConstraint(window, size_auto_fit); + ClearActiveID(); + } + else if (held) + { + // Resize from any of the four corners + // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position + ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN); // Corner of the window corresponding to our corner grip + CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target); + } + if (resize_grip_n == 0 || held || hovered) + resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); + } + for (int border_n = 0; border_n < resize_border_count; border_n++) + { + bool hovered, held; + ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); + ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren); + //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255)); + if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) + { + g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; + if (held) + *border_held = border_n; + } + if (held) + { + ImVec2 border_target = window->Pos; + ImVec2 border_posn; + if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Top + if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Right + if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Bottom + if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Left + CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target); + } + } + PopID(); + + // Navigation resize (keyboard/gamepad) + if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window) + { + ImVec2 nav_resize_delta; + if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift) + nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); + if (g.NavInputSource == ImGuiInputSource_NavGamepad) + nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down); + if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f) + { + const float NAV_RESIZE_SPEED = 600.0f; + nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); + g.NavWindowingToggleLayer = false; + g.NavDisableMouseHover = true; + resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive); + // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck. + size_target = CalcSizeAfterConstraint(window, window->SizeFull + nav_resize_delta); + } + } + + // Apply back modified position/size to window + if (size_target.x != FLT_MAX) + { + window->SizeFull = size_target; + MarkIniSettingsDirty(window); + } + if (pos_target.x != FLT_MAX) + { + window->Pos = ImFloor(pos_target); + MarkIniSettingsDirty(window); + } + + window->Size = window->SizeFull; +} + +static void ImGui::RenderOuterBorders(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + float rounding = window->WindowRounding; + float border_size = window->WindowBorderSize; + if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground)) + window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + + int border_held = window->ResizeBorderHeld; + if (border_held != -1) + { + struct ImGuiResizeBorderDef + { + ImVec2 InnerDir; + ImVec2 CornerPosN1, CornerPosN2; + float OuterAngle; + }; + static const ImGuiResizeBorderDef resize_border_def[4] = + { + { ImVec2(0,+1), ImVec2(0,0), ImVec2(1,0), IM_PI*1.50f }, // Top + { ImVec2(-1,0), ImVec2(1,0), ImVec2(1,1), IM_PI*0.00f }, // Right + { ImVec2(0,-1), ImVec2(1,1), ImVec2(0,1), IM_PI*0.50f }, // Bottom + { ImVec2(+1,0), ImVec2(0,1), ImVec2(0,0), IM_PI*1.00f } // Left + }; + const ImGuiResizeBorderDef& def = resize_border_def[border_held]; + ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI*0.25f, def.OuterAngle); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI*0.25f); + window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); // Thicker than usual + } + if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) + { + float y = window->Pos.y + window->TitleBarHeight() - 1; + window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), GetColorU32(ImGuiCol_Border), g.Style.FrameBorderSize); + } +} + +void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window) +{ + window->ParentWindow = parent_window; + window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window; + if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) + window->RootWindow = parent_window->RootWindow; + if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) + window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight; + while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened) + { + IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL); + window->RootWindowForNav = window->RootWindowForNav->ParentWindow; + } +} + +// Push a new ImGui window to add widgets to. +// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair. +// - Begin/End can be called multiple times during the frame with the same window name to append content. +// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file). +// You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file. +// - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned. +// - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed. +bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + IM_ASSERT(name != NULL && name[0] != '\0'); // Window name required + IM_ASSERT(g.FrameScopeActive); // Forgot to call ImGui::NewFrame() + IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet + + // Find or create + ImGuiWindow* window = FindWindowByName(name); + const bool window_just_created = (window == NULL); + if (window_just_created) + { + ImVec2 size_on_first_use = (g.NextWindowData.SizeCond != 0) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here. + window = CreateNewWindow(name, size_on_first_use, flags); + } + + // Automatically disable manual moving/resizing when NoInputs is set + if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs) + flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize; + + if (flags & ImGuiWindowFlags_NavFlattened) + IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow); + + const int current_frame = g.FrameCount; + const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame); + + // Update Flags, LastFrameActive, BeginOrderXXX fields + if (first_begin_of_the_frame) + window->Flags = (ImGuiWindowFlags)flags; + else + flags = window->Flags; + + // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack + ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back(); + ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow; + IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow)); + window->HasCloseButton = (p_open != NULL); + + // Update the Appearing flag + bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on + const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesForResize > 0); + if (flags & ImGuiWindowFlags_Popup) + { + ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; + window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed + window_just_activated_by_user |= (window != popup_ref.Window); + } + window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize); + if (window->Appearing) + SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true); + + // Add to stack + g.CurrentWindowStack.push_back(window); + SetCurrentWindow(window); + CheckStacksSize(window, true); + if (flags & ImGuiWindowFlags_Popup) + { + ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; + popup_ref.Window = window; + g.BeginPopupStack.push_back(popup_ref); + window->PopupId = popup_ref.PopupId; + } + + if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow)) + window->NavLastIds[0] = 0; + + // Process SetNextWindow***() calls + bool window_pos_set_by_api = false; + bool window_size_x_set_by_api = false, window_size_y_set_by_api = false; + if (g.NextWindowData.PosCond) + { + window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0; + if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f) + { + // May be processed on the next frame if this is our first frame and we are measuring size + // FIXME: Look into removing the branch so everything can go through this same code path for consistency. + window->SetWindowPosVal = g.NextWindowData.PosVal; + window->SetWindowPosPivot = g.NextWindowData.PosPivotVal; + window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + } + else + { + SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond); + } + } + if (g.NextWindowData.SizeCond) + { + window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f); + window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f); + SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); + } + if (g.NextWindowData.ContentSizeCond) + { + // Adjust passed "client size" to become a "window size" + window->SizeContentsExplicit = g.NextWindowData.ContentSizeVal; + if (window->SizeContentsExplicit.y != 0.0f) + window->SizeContentsExplicit.y += window->TitleBarHeight() + window->MenuBarHeight(); + } + else if (first_begin_of_the_frame) + { + window->SizeContentsExplicit = ImVec2(0.0f, 0.0f); + } + if (g.NextWindowData.CollapsedCond) + SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); + if (g.NextWindowData.FocusCond) + FocusWindow(window); + if (window->Appearing) + SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false); + + // When reusing window again multiple times a frame, just append content (don't need to setup again) + if (first_begin_of_the_frame) + { + // Initialize + const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345) + UpdateWindowParentAndRootLinks(window, flags, parent_window); + + window->Active = true; + window->BeginOrderWithinParent = 0; + window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++); + window->BeginCount = 0; + window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX); + window->LastFrameActive = current_frame; + window->IDStack.resize(1); + + // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged). + // The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere. + bool window_title_visible_elsewhere = false; + if (g.NavWindowingList != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB + window_title_visible_elsewhere = true; + if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0) + { + size_t buf_len = (size_t)window->NameBufLen; + window->Name = ImStrdupcpy(window->Name, &buf_len, name); + window->NameBufLen = (int)buf_len; + } + + // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS + + // Update contents size from last frame for auto-fitting (or use explicit size) + window->SizeContents = CalcSizeContents(window); + if (window->HiddenFramesRegular > 0) + window->HiddenFramesRegular--; + if (window->HiddenFramesForResize > 0) + window->HiddenFramesForResize--; + + // Hide new windows for one frame until they calculate their size + if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api)) + window->HiddenFramesForResize = 1; + + // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows) + // We reset Size/SizeContents for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size. + if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0) + { + window->HiddenFramesForResize = 1; + if (flags & ImGuiWindowFlags_AlwaysAutoResize) + { + if (!window_size_x_set_by_api) + window->Size.x = window->SizeFull.x = 0.f; + if (!window_size_y_set_by_api) + window->Size.y = window->SizeFull.y = 0.f; + window->SizeContents = ImVec2(0.f, 0.f); + } + } + + SetCurrentWindow(window); + + // Lock border size and padding for the frame (so that altering them doesn't cause inconsistencies) + window->WindowBorderSize = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildBorderSize : ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize; + window->WindowPadding = style.WindowPadding; + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f) + window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f); + window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x); + window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y; + + // Collapse window by double-clicking on title bar + // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing + if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse)) + { + // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar. + ImRect title_bar_rect = window->TitleBarRect(); + if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0]) + window->WantCollapseToggle = true; + if (window->WantCollapseToggle) + { + window->Collapsed = !window->Collapsed; + MarkIniSettingsDirty(window); + FocusWindow(window); + } + } + else + { + window->Collapsed = false; + } + window->WantCollapseToggle = false; + + // SIZE + + // Calculate auto-fit size, handle automatic resize + const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->SizeContents); + ImVec2 size_full_modified(FLT_MAX, FLT_MAX); + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) + { + // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. + if (!window_size_x_set_by_api) + window->SizeFull.x = size_full_modified.x = size_auto_fit.x; + if (!window_size_y_set_by_api) + window->SizeFull.y = size_full_modified.y = size_auto_fit.y; + } + else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) + { + // Auto-fit may only grow window during the first few frames + // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. + if (!window_size_x_set_by_api && window->AutoFitFramesX > 0) + window->SizeFull.x = size_full_modified.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; + if (!window_size_y_set_by_api && window->AutoFitFramesY > 0) + window->SizeFull.y = size_full_modified.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; + if (!window->Collapsed) + MarkIniSettingsDirty(window); + } + + // Apply minimum/maximum window size constraints and final size + window->SizeFull = CalcSizeAfterConstraint(window, window->SizeFull); + window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull; + + // SCROLLBAR STATUS + + // Update scrollbar status (based on the Size that was effective during last frame or the auto-resized Size). + if (!window->Collapsed) + { + // When reading the current size we need to read it after size constraints have been applied + float size_x_for_scrollbars = size_full_modified.x != FLT_MAX ? window->SizeFull.x : window->SizeFullAtLastBegin.x; + float size_y_for_scrollbars = size_full_modified.y != FLT_MAX ? window->SizeFull.y : window->SizeFullAtLastBegin.y; + window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); + window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); + if (window->ScrollbarX && !window->ScrollbarY) + window->ScrollbarY = (window->SizeContents.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar); + window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); + } + + // POSITION + + // Popup latch its initial position, will position itself when it appears next frame + if (window_just_activated_by_user) + { + window->AutoPosLastDirection = ImGuiDir_None; + if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api) + window->Pos = g.BeginPopupStack.back().OpenPopupPos; + } + + // Position child window + if (flags & ImGuiWindowFlags_ChildWindow) + { + IM_ASSERT(parent_window && parent_window->Active); + window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size; + parent_window->DC.ChildWindows.push_back(window); + if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip) + window->Pos = parent_window->DC.CursorPos; + } + + const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesForResize == 0); + if (window_pos_with_pivot) + SetWindowPos(window, ImMax(style.DisplaySafeAreaPadding, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot), 0); // Position given a pivot (e.g. for centering) + else if ((flags & ImGuiWindowFlags_ChildMenu) != 0) + window->Pos = FindBestWindowPosForPopup(window); + else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize) + window->Pos = FindBestWindowPosForPopup(window); + else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip) + window->Pos = FindBestWindowPosForPopup(window); + + // Clamp position so it stays visible + // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. + if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + { + if (g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. + { + ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); + ImVec2 size_for_clamping = ((g.IO.ConfigWindowsMoveFromTitleBarOnly) && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) ? ImVec2(window->Size.x, window->TitleBarHeight()) : window->Size; + window->Pos = ImMax(window->Pos + size_for_clamping, padding) - size_for_clamping; + window->Pos = ImMin(window->Pos, g.IO.DisplaySize - padding); + } + } + window->Pos = ImFloor(window->Pos); + + // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies) + window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; + + // Apply scrolling + window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true); + window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + + // Apply window focus (new and reactivated windows are moved to front) + bool want_focus = false; + if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing)) + { + if (flags & ImGuiWindowFlags_Popup) + want_focus = true; + else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0) + want_focus = true; + } + + // Handle manual resize: Resize Grips, Borders, Gamepad + int border_held = -1; + ImU32 resize_grip_col[4] = { 0 }; + const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // 4 + const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f); + if (!window->Collapsed) + UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]); + window->ResizeBorderHeld = (signed char)border_held; + + // Default item width. Make it proportional to window size if window manually resizes + if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) + window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f); + else + window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f); + + // DRAWING + + // Setup draw list and outer clipping rectangle + window->DrawList->Clear(); + window->DrawList->Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0); + window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); + ImRect viewport_rect(GetViewportRect()); + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) + PushClipRect(parent_window->ClipRect.Min, parent_window->ClipRect.Max, true); + else + PushClipRect(viewport_rect.Min, viewport_rect.Max, true); + + // Draw modal window background (darkens what is behind them, all viewports) + const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetFrontMostPopupModal() && window->HiddenFramesForResize <= 0; + const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow); + if (dim_bg_for_modal || dim_bg_for_window_list) + { + const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio); + window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col); + } + + // Draw navigation selection/windowing rectangle background + if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim) + { + ImRect bb = window->Rect(); + bb.Expand(g.FontSize); + if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding); + } + + // Draw window + handle manual resize + // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame. + const float window_rounding = window->WindowRounding; + const float window_border_size = window->WindowBorderSize; + const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; + const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight); + const ImRect title_bar_rect = window->TitleBarRect(); + if (window->Collapsed) + { + // Title bar only + float backup_border_size = style.FrameBorderSize; + g.Style.FrameBorderSize = window->WindowBorderSize; + ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); + RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding); + g.Style.FrameBorderSize = backup_border_size; + } + else + { + // Window background + if (!(flags & ImGuiWindowFlags_NoBackground)) + { + ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags)); + float alpha = 1.0f; + if (g.NextWindowData.BgAlphaCond != 0) + alpha = g.NextWindowData.BgAlphaVal; + if (alpha != 1.0f) + bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT); + window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); + } + g.NextWindowData.BgAlphaCond = 0; + + // Title bar + if (!(flags & ImGuiWindowFlags_NoTitleBar)) + { + ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); + window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top); + } + + // Menu bar + if (flags & ImGuiWindowFlags_MenuBar) + { + ImRect menu_bar_rect = window->MenuBarRect(); + menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. + window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); + if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) + window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); + } + + // Scrollbars + if (window->ScrollbarX) + Scrollbar(ImGuiAxis_X); + if (window->ScrollbarY) + Scrollbar(ImGuiAxis_Y); + + // Render resize grips (after their input handling so we don't have a frame of latency) + if (!(flags & ImGuiWindowFlags_NoResize)) + { + for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) + { + const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, grip_draw_size) : ImVec2(grip_draw_size, window_border_size))); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(grip_draw_size, window_border_size) : ImVec2(window_border_size, grip_draw_size))); + window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12); + window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]); + } + } + + // Borders + RenderOuterBorders(window); + } + + // Draw navigation selection/windowing rectangle border + if (g.NavWindowingTargetAnim == window) + { + float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding); + ImRect bb = window->Rect(); + bb.Expand(g.FontSize); + if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward + { + bb.Expand(-g.FontSize - 1.0f); + rounding = window->WindowRounding; + } + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f); + } + + // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars. + window->SizeFullAtLastBegin = window->SizeFull; + + // Update various regions. Variables they depends on are set above in this function. + // FIXME: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. + window->ContentsRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; + window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight(); + window->ContentsRegionRect.Max.x = window->Pos.x - window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x)); + window->ContentsRegionRect.Max.y = window->Pos.y - window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y)); + + // Setup drawing context + // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) + window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; + window->DC.GroupOffset.x = 0.0f; + window->DC.ColumnsOffset.x = 0.0f; + window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y); + window->DC.CursorPos = window->DC.CursorStartPos; + window->DC.CursorPosPrevLine = window->DC.CursorPos; + window->DC.CursorMaxPos = window->DC.CursorStartPos; + window->DC.CurrentLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f); + window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; + window->DC.NavHideHighlightOneFrame = false; + window->DC.NavHasScroll = (GetWindowScrollMaxY(window) > 0.0f); + window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; + window->DC.NavLayerActiveMaskNext = 0x00; + window->DC.MenuBarAppending = false; + window->DC.ChildWindows.resize(0); + window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical; + window->DC.FocusCounterAll = window->DC.FocusCounterTab = -1; + window->DC.ItemFlags = parent_window ? parent_window->DC.ItemFlags : ImGuiItemFlags_Default_; + window->DC.ItemWidth = window->ItemWidthDefault; + window->DC.TextWrapPos = -1.0f; // disabled + window->DC.ItemFlagsStack.resize(0); + window->DC.ItemWidthStack.resize(0); + window->DC.TextWrapPosStack.resize(0); + window->DC.ColumnsSet = NULL; + window->DC.TreeDepth = 0; + window->DC.TreeDepthMayJumpToParentOnPop = 0x00; + window->DC.StateStorage = &window->StateStorage; + window->DC.GroupStack.resize(0); + window->MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user); + + if ((flags & ImGuiWindowFlags_ChildWindow) && (window->DC.ItemFlags != parent_window->DC.ItemFlags)) + { + window->DC.ItemFlags = parent_window->DC.ItemFlags; + window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); + } + + if (window->AutoFitFramesX > 0) + window->AutoFitFramesX--; + if (window->AutoFitFramesY > 0) + window->AutoFitFramesY--; + + // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there) + if (want_focus) + { + FocusWindow(window); + NavInitWindow(window, false); + } + + // Title bar + if (!(flags & ImGuiWindowFlags_NoTitleBar)) + { + // Close & collapse button are on layer 1 (same as menus) and don't default focus + const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; + window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); + + // Collapse button + if (!(flags & ImGuiWindowFlags_NoCollapse)) + if (CollapseButton(window->GetID("#COLLAPSE"), window->Pos)) + window->WantCollapseToggle = true; // Defer collapsing to next frame as we are too far in the Begin() function + + // Close button + if (p_open != NULL) + { + const float pad = style.FramePadding.y; + const float rad = g.FontSize * 0.5f; + if (CloseButton(window->GetID("#CLOSE"), window->Rect().GetTR() + ImVec2(-pad - rad, pad + rad), rad + 1)) + *p_open = false; + } + + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); + window->DC.ItemFlags = item_flags_backup; + + // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker) + // FIXME: Refactor text alignment facilities along with RenderText helpers, this is too much code.. + const char* UNSAVED_DOCUMENT_MARKER = "*"; + float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f; + ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f); + ImRect text_r = title_bar_rect; + float pad_left = (flags & ImGuiWindowFlags_NoCollapse) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); + float pad_right = (p_open == NULL) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); + if (style.WindowTitleAlign.x > 0.0f) + pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x); + text_r.Min.x += pad_left; + text_r.Max.x -= pad_right; + ImRect clip_rect = text_r; + clip_rect.Max.x = window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x); // Match the size of CloseButton() + RenderTextClipped(text_r.Min, text_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect); + if (flags & ImGuiWindowFlags_UnsavedDocument) + { + ImVec2 marker_pos = ImVec2(ImMax(text_r.Min.x, text_r.Min.x + (text_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, text_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f); + ImVec2 off = ImVec2(0.0f, (float)(int)(-g.FontSize * 0.25f)); + RenderTextClipped(marker_pos + off, text_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_rect); + } + } + + // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() + window->OuterRectClipped = window->Rect(); + window->OuterRectClipped.ClipWith(window->ClipRect); + + // Pressing CTRL+C while holding on a window copy its content to the clipboard + // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. + // Maybe we can support CTRL+C on every element? + /* + if (g.ActiveId == move_id) + if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C)) + LogToClipboard(); + */ + + // Inner rectangle + // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame + // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior. + window->InnerMainRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize; + window->InnerMainRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); + window->InnerMainRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x - window->WindowBorderSize; + window->InnerMainRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y - window->WindowBorderSize; + //window->DrawList->AddRect(window->InnerRect.Min, window->InnerRect.Max, IM_COL32_WHITE); + + // Inner clipping rectangle + // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. + window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerMainRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - window->WindowBorderSize))); + window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y); + window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - window->WindowBorderSize))); + window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y); + + // We fill last item data based on Title Bar, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). + // This is useful to allow creating context menus on title bar only, etc. + window->DC.LastItemId = window->MoveId; + window->DC.LastItemStatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0; + window->DC.LastItemRect = title_bar_rect; + } + + PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); + + // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused) + if (first_begin_of_the_frame) + window->WriteAccessed = false; + + window->BeginCount++; + g.NextWindowData.Clear(); + + if (flags & ImGuiWindowFlags_ChildWindow) + { + // Child window can be out of sight and have "negative" clip windows. + // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). + IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); + if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) + window->HiddenFramesRegular = 1; + + // Completely hide along with parent or if parent is collapsed + if (parent_window && (parent_window->Collapsed || parent_window->Hidden)) + window->HiddenFramesRegular = 1; + } + + // Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point) + if (style.Alpha <= 0.0f) + window->HiddenFramesRegular = 1; + + // Update the Hidden flag + window->Hidden = (window->HiddenFramesRegular > 0) || (window->HiddenFramesForResize > 0); + + // Return false if we don't intend to display anything to allow user to perform an early out optimization + window->SkipItems = (window->Collapsed || !window->Active || window->Hidden) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesForResize <= 0; + + return !window->SkipItems; +} + +// Old Begin() API with 5 parameters, avoid calling this version directly! Use SetNextWindowSize()/SetNextWindowBgAlpha() + Begin() instead. +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_first_use, float bg_alpha_override, ImGuiWindowFlags flags) +{ + // Old API feature: we could pass the initial window size as a parameter. This was misleading because it only had an effect if the window didn't have data in the .ini file. + if (size_first_use.x != 0.0f || size_first_use.y != 0.0f) + SetNextWindowSize(size_first_use, ImGuiCond_FirstUseEver); + + // Old API feature: override the window background alpha with a parameter. + if (bg_alpha_override >= 0.0f) + SetNextWindowBgAlpha(bg_alpha_override); + + return Begin(name, p_open, flags); +} +#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +void ImGui::End() +{ + ImGuiContext& g = *GImGui; + + if (g.CurrentWindowStack.Size <= 1 && g.FrameScopePushedImplicitWindow) + { + IM_ASSERT(g.CurrentWindowStack.Size > 1 && "Calling End() too many times!"); + return; // FIXME-ERRORHANDLING + } + IM_ASSERT(g.CurrentWindowStack.Size > 0); + + ImGuiWindow* window = g.CurrentWindow; + + if (window->DC.ColumnsSet != NULL) + EndColumns(); + PopClipRect(); // Inner window clip rectangle + + // Stop logging + if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging + LogFinish(); + + // Pop from window stack + g.CurrentWindowStack.pop_back(); + if (window->Flags & ImGuiWindowFlags_Popup) + g.BeginPopupStack.pop_back(); + CheckStacksSize(window, false); + SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); +} + +void ImGui::BringWindowToFocusFront(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.WindowsFocusOrder.back() == window) + return; + for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the front most window + if (g.WindowsFocusOrder[i] == window) + { + memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*)); + g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window; + break; + } +} + +void ImGui::BringWindowToDisplayFront(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* current_front_window = g.Windows.back(); + if (current_front_window == window || current_front_window->RootWindow == window) + return; + for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the front most window + if (g.Windows[i] == window) + { + memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*)); + g.Windows[g.Windows.Size - 1] = window; + break; + } +} + +void ImGui::BringWindowToDisplayBack(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.Windows[0] == window) + return; + for (int i = 0; i < g.Windows.Size; i++) + if (g.Windows[i] == window) + { + memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*)); + g.Windows[0] = window; + break; + } +} + +// Moving window to front of display and set focus (which happens to be back of our sorted list) +void ImGui::FocusWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + + if (g.NavWindow != window) + { + g.NavWindow = window; + if (window && g.NavDisableMouseHover) + g.NavMousePosDirty = true; + g.NavInitRequest = false; + g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId + g.NavIdIsAlive = false; + g.NavLayer = ImGuiNavLayer_Main; + //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL); + } + + // Passing NULL allow to disable keyboard focus + if (!window) + return; + + // Move the root window to the top of the pile + if (window->RootWindow) + window = window->RootWindow; + + // Steal focus on active widgets + if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it.. + if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window) + ClearActiveID(); + + // Bring to front + BringWindowToFocusFront(window); + if (!(window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) + BringWindowToDisplayFront(window); +} + +void ImGui::FocusPreviousWindowIgnoringOne(ImGuiWindow* ignore_window) +{ + ImGuiContext& g = *GImGui; + for (int i = g.WindowsFocusOrder.Size - 1; i >= 0; i--) + { + // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user. + ImGuiWindow* window = g.WindowsFocusOrder[i]; + if (window != ignore_window && window->WasActive && !(window->Flags & ImGuiWindowFlags_ChildWindow)) + if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) + { + ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window); + FocusWindow(focus_window); + return; + } + } +} + +void ImGui::PushItemWidth(float item_width) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); + window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); +} + +void ImGui::PushMultiItemsWidths(int components, float w_full) +{ + ImGuiWindow* window = GetCurrentWindow(); + const ImGuiStyle& style = GImGui->Style; + if (w_full <= 0.0f) + w_full = CalcItemWidth(); + const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components)); + const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1))); + window->DC.ItemWidthStack.push_back(w_item_last); + for (int i = 0; i < components-1; i++) + window->DC.ItemWidthStack.push_back(w_item_one); + window->DC.ItemWidth = window->DC.ItemWidthStack.back(); +} + +void ImGui::PopItemWidth() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.ItemWidthStack.pop_back(); + window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back(); +} + +float ImGui::CalcItemWidth() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + float w = window->DC.ItemWidth; + if (w < 0.0f) + { + // Align to a right-side limit. We include 1 frame padding in the calculation because this is how the width is always used (we add 2 frame padding to it), but we could move that responsibility to the widget as well. + float width_to_right_edge = GetContentRegionAvail().x; + w = ImMax(1.0f, width_to_right_edge + w); + } + w = (float)(int)w; + return w; +} + +void ImGui::SetCurrentFont(ImFont* font) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? + IM_ASSERT(font->Scale > 0.0f); + g.Font = font; + g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); + g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; + + ImFontAtlas* atlas = g.Font->ContainerAtlas; + g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel; + g.DrawListSharedData.Font = g.Font; + g.DrawListSharedData.FontSize = g.FontSize; +} + +void ImGui::PushFont(ImFont* font) +{ + ImGuiContext& g = *GImGui; + if (!font) + font = GetDefaultFont(); + SetCurrentFont(font); + g.FontStack.push_back(font); + g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID); +} + +void ImGui::PopFont() +{ + ImGuiContext& g = *GImGui; + g.CurrentWindow->DrawList->PopTextureID(); + g.FontStack.pop_back(); + SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back()); +} + +void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (enabled) + window->DC.ItemFlags |= option; + else + window->DC.ItemFlags &= ~option; + window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); +} + +void ImGui::PopItemFlag() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.ItemFlagsStack.pop_back(); + window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back(); +} + +// FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system. +void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) +{ + PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus); +} + +void ImGui::PopAllowKeyboardFocus() +{ + PopItemFlag(); +} + +void ImGui::PushButtonRepeat(bool repeat) +{ + PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); +} + +void ImGui::PopButtonRepeat() +{ + PopItemFlag(); +} + +void ImGui::PushTextWrapPos(float wrap_pos_x) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.TextWrapPos = wrap_pos_x; + window->DC.TextWrapPosStack.push_back(wrap_pos_x); +} + +void ImGui::PopTextWrapPos() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.TextWrapPosStack.pop_back(); + window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back(); +} + +// FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32 +void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col) +{ + ImGuiContext& g = *GImGui; + ImGuiColorMod backup; + backup.Col = idx; + backup.BackupValue = g.Style.Colors[idx]; + g.ColorModifiers.push_back(backup); + g.Style.Colors[idx] = ColorConvertU32ToFloat4(col); +} + +void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) +{ + ImGuiContext& g = *GImGui; + ImGuiColorMod backup; + backup.Col = idx; + backup.BackupValue = g.Style.Colors[idx]; + g.ColorModifiers.push_back(backup); + g.Style.Colors[idx] = col; +} + +void ImGui::PopStyleColor(int count) +{ + ImGuiContext& g = *GImGui; + while (count > 0) + { + ImGuiColorMod& backup = g.ColorModifiers.back(); + g.Style.Colors[backup.Col] = backup.BackupValue; + g.ColorModifiers.pop_back(); + count--; + } +} + +struct ImGuiStyleVarInfo +{ + ImGuiDataType Type; + ImU32 Count; + ImU32 Offset; + void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); } +}; + +static const ImGuiStyleVarInfo GStyleVarInfo[] = +{ + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign +}; + +static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) +{ + IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); + IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); + return &GStyleVarInfo[idx]; +} + +void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) +{ + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) + { + ImGuiContext& g = *GImGui; + float* pvar = (float*)var_info->GetVarPtr(&g.Style); + g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT(0); // Called function with wrong-type? Variable is not a float. +} + +void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) +{ + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) + { + ImGuiContext& g = *GImGui; + ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); + g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT(0); // Called function with wrong-type? Variable is not a ImVec2. +} + +void ImGui::PopStyleVar(int count) +{ + ImGuiContext& g = *GImGui; + while (count > 0) + { + // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. + ImGuiStyleMod& backup = g.StyleModifiers.back(); + const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx); + void* data = info->GetVarPtr(&g.Style); + if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } + else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } + g.StyleModifiers.pop_back(); + count--; + } +} + +const char* ImGui::GetStyleColorName(ImGuiCol idx) +{ + // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1"; + switch (idx) + { + case ImGuiCol_Text: return "Text"; + case ImGuiCol_TextDisabled: return "TextDisabled"; + case ImGuiCol_WindowBg: return "WindowBg"; + case ImGuiCol_ChildBg: return "ChildBg"; + case ImGuiCol_PopupBg: return "PopupBg"; + case ImGuiCol_Border: return "Border"; + case ImGuiCol_BorderShadow: return "BorderShadow"; + case ImGuiCol_FrameBg: return "FrameBg"; + case ImGuiCol_FrameBgHovered: return "FrameBgHovered"; + case ImGuiCol_FrameBgActive: return "FrameBgActive"; + case ImGuiCol_TitleBg: return "TitleBg"; + case ImGuiCol_TitleBgActive: return "TitleBgActive"; + case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed"; + case ImGuiCol_MenuBarBg: return "MenuBarBg"; + case ImGuiCol_ScrollbarBg: return "ScrollbarBg"; + case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab"; + case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered"; + case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive"; + case ImGuiCol_CheckMark: return "CheckMark"; + case ImGuiCol_SliderGrab: return "SliderGrab"; + case ImGuiCol_SliderGrabActive: return "SliderGrabActive"; + case ImGuiCol_Button: return "Button"; + case ImGuiCol_ButtonHovered: return "ButtonHovered"; + case ImGuiCol_ButtonActive: return "ButtonActive"; + case ImGuiCol_Header: return "Header"; + case ImGuiCol_HeaderHovered: return "HeaderHovered"; + case ImGuiCol_HeaderActive: return "HeaderActive"; + case ImGuiCol_Separator: return "Separator"; + case ImGuiCol_SeparatorHovered: return "SeparatorHovered"; + case ImGuiCol_SeparatorActive: return "SeparatorActive"; + case ImGuiCol_ResizeGrip: return "ResizeGrip"; + case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered"; + case ImGuiCol_ResizeGripActive: return "ResizeGripActive"; + case ImGuiCol_Tab: return "Tab"; + case ImGuiCol_TabHovered: return "TabHovered"; + case ImGuiCol_TabActive: return "TabActive"; + case ImGuiCol_TabUnfocused: return "TabUnfocused"; + case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive"; + case ImGuiCol_PlotLines: return "PlotLines"; + case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered"; + case ImGuiCol_PlotHistogram: return "PlotHistogram"; + case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; + case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; + case ImGuiCol_DragDropTarget: return "DragDropTarget"; + case ImGuiCol_NavHighlight: return "NavHighlight"; + case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; + case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg"; + case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg"; + } + IM_ASSERT(0); + return "Unknown"; +} + +bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent) +{ + if (window->RootWindow == potential_parent) + return true; + while (window != NULL) + { + if (window == potential_parent) + return true; + window = window->ParentWindow; + } + return false; +} + +bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) +{ + IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0); // Flags not supported by this function + ImGuiContext& g = *GImGui; + + if (flags & ImGuiHoveredFlags_AnyWindow) + { + if (g.HoveredWindow == NULL) + return false; + } + else + { + switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) + { + case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows: + if (g.HoveredRootWindow != g.CurrentWindow->RootWindow) + return false; + break; + case ImGuiHoveredFlags_RootWindow: + if (g.HoveredWindow != g.CurrentWindow->RootWindow) + return false; + break; + case ImGuiHoveredFlags_ChildWindows: + if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow)) + return false; + break; + default: + if (g.HoveredWindow != g.CurrentWindow) + return false; + break; + } + } + + if (!IsWindowContentHoverable(g.HoveredRootWindow, flags)) + return false; + if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId) + return false; + return true; +} + +bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) +{ + ImGuiContext& g = *GImGui; + + if (flags & ImGuiFocusedFlags_AnyWindow) + return g.NavWindow != NULL; + + IM_ASSERT(g.CurrentWindow); // Not inside a Begin()/End() + switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows)) + { + case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows: + return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow; + case ImGuiFocusedFlags_RootWindow: + return g.NavWindow == g.CurrentWindow->RootWindow; + case ImGuiFocusedFlags_ChildWindows: + return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow); + default: + return g.NavWindow == g.CurrentWindow; + } +} + +// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext) +// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmaticaly. +// If you want a window to never be focused, you may use the e.g. NoInputs flag. +bool ImGui::IsWindowNavFocusable(ImGuiWindow* window) +{ + return window->Active && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus); +} + +float ImGui::GetWindowWidth() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Size.x; +} + +float ImGui::GetWindowHeight() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Size.y; +} + +ImVec2 ImGui::GetWindowPos() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + return window->Pos; +} + +void ImGui::SetWindowScrollX(ImGuiWindow* window, float new_scroll_x) +{ + window->DC.CursorMaxPos.x += window->Scroll.x; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it. + window->Scroll.x = new_scroll_x; + window->DC.CursorMaxPos.x -= window->Scroll.x; +} + +void ImGui::SetWindowScrollY(ImGuiWindow* window, float new_scroll_y) +{ + window->DC.CursorMaxPos.y += window->Scroll.y; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it. + window->Scroll.y = new_scroll_y; + window->DC.CursorMaxPos.y -= window->Scroll.y; +} + +void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) +{ + // Test condition (NB: bit 0 is always true) and clear flags for next time + if (cond && (window->SetWindowPosAllowFlags & cond) == 0) + return; + + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX); + + // Set + const ImVec2 old_pos = window->Pos; + window->Pos = ImFloor(pos); + window->DC.CursorPos += (window->Pos - old_pos); // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor + window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected. +} + +void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + SetWindowPos(window, pos, cond); +} + +void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + SetWindowPos(window, pos, cond); +} + +ImVec2 ImGui::GetWindowSize() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->Size; +} + +void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond) +{ + // Test condition (NB: bit 0 is always true) and clear flags for next time + if (cond && (window->SetWindowSizeAllowFlags & cond) == 0) + return; + + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + + // Set + if (size.x > 0.0f) + { + window->AutoFitFramesX = 0; + window->SizeFull.x = ImFloor(size.x); + } + else + { + window->AutoFitFramesX = 2; + window->AutoFitOnlyGrows = false; + } + if (size.y > 0.0f) + { + window->AutoFitFramesY = 0; + window->SizeFull.y = ImFloor(size.y); + } + else + { + window->AutoFitFramesY = 2; + window->AutoFitOnlyGrows = false; + } +} + +void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond) +{ + SetWindowSize(GImGui->CurrentWindow, size, cond); +} + +void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + SetWindowSize(window, size, cond); +} + +void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond) +{ + // Test condition (NB: bit 0 is always true) and clear flags for next time + if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0) + return; + window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + + // Set + window->Collapsed = collapsed; +} + +void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond) +{ + SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond); +} + +bool ImGui::IsWindowCollapsed() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->Collapsed; +} + +bool ImGui::IsWindowAppearing() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->Appearing; +} + +void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + SetWindowCollapsed(window, collapsed, cond); +} + +void ImGui::SetWindowFocus() +{ + FocusWindow(GImGui->CurrentWindow); +} + +void ImGui::SetWindowFocus(const char* name) +{ + if (name) + { + if (ImGuiWindow* window = FindWindowByName(name)) + FocusWindow(window); + } + else + { + FocusWindow(NULL); + } +} + +void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.PosVal = pos; + g.NextWindowData.PosPivotVal = pivot; + g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always; +} + +void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.SizeVal = size; + g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always; +} + +void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.SizeConstraintCond = ImGuiCond_Always; + g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max); + g.NextWindowData.SizeCallback = custom_callback; + g.NextWindowData.SizeCallbackUserData = custom_callback_user_data; +} + +void ImGui::SetNextWindowContentSize(const ImVec2& size) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.ContentSizeVal = size; // In Begin() we will add the size of window decorations (title bar, menu etc.) to that to form a SizeContents value. + g.NextWindowData.ContentSizeCond = ImGuiCond_Always; +} + +void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.CollapsedVal = collapsed; + g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always; +} + +void ImGui::SetNextWindowFocus() +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.FocusCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op) +} + +void ImGui::SetNextWindowBgAlpha(float alpha) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.BgAlphaVal = alpha; + g.NextWindowData.BgAlphaCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op) +} + +// FIXME: This is in window space (not screen space!) +ImVec2 ImGui::GetContentRegionMax() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImVec2 mx = window->ContentsRegionRect.Max - window->Pos; + if (window->DC.ColumnsSet) + mx.x = GetColumnOffset(window->DC.ColumnsSet->Current + 1) - window->WindowPadding.x; + return mx; +} + +ImVec2 ImGui::GetContentRegionAvail() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return GetContentRegionMax() - (window->DC.CursorPos - window->Pos); +} + +float ImGui::GetContentRegionAvailWidth() +{ + return GetContentRegionAvail().x; +} + +// In window space (not screen space!) +ImVec2 ImGui::GetWindowContentRegionMin() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->ContentsRegionRect.Min - window->Pos; +} + +ImVec2 ImGui::GetWindowContentRegionMax() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->ContentsRegionRect.Max - window->Pos; +} + +float ImGui::GetWindowContentRegionWidth() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->ContentsRegionRect.GetWidth(); +} + +float ImGui::GetTextLineHeight() +{ + ImGuiContext& g = *GImGui; + return g.FontSize; +} + +float ImGui::GetTextLineHeightWithSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.ItemSpacing.y; +} + +float ImGui::GetFrameHeight() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.FramePadding.y * 2.0f; +} + +float ImGui::GetFrameHeightWithSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; +} + +ImDrawList* ImGui::GetWindowDrawList() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->DrawList; +} + +ImFont* ImGui::GetFont() +{ + return GImGui->Font; +} + +float ImGui::GetFontSize() +{ + return GImGui->FontSize; +} + +ImVec2 ImGui::GetFontTexUvWhitePixel() +{ + return GImGui->DrawListSharedData.TexUvWhitePixel; +} + +void ImGui::SetWindowFontScale(float scale) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->FontWindowScale = scale; + g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); +} + +// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient. +// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'. +ImVec2 ImGui::GetCursorPos() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos - window->Pos + window->Scroll; +} + +float ImGui::GetCursorPosX() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x; +} + +float ImGui::GetCursorPosY() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y; +} + +void ImGui::SetCursorPos(const ImVec2& local_pos) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos = window->Pos - window->Scroll + local_pos; + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); +} + +void ImGui::SetCursorPosX(float x) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x; + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x); +} + +void ImGui::SetCursorPosY(float y) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y; + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); +} + +ImVec2 ImGui::GetCursorStartPos() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorStartPos - window->Pos; +} + +ImVec2 ImGui::GetCursorScreenPos() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos; +} + +void ImGui::SetCursorScreenPos(const ImVec2& pos) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos = pos; + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); +} + +float ImGui::GetScrollX() +{ + return GImGui->CurrentWindow->Scroll.x; +} + +float ImGui::GetScrollY() +{ + return GImGui->CurrentWindow->Scroll.y; +} + +float ImGui::GetScrollMaxX() +{ + return GetWindowScrollMaxX(GImGui->CurrentWindow); +} + +float ImGui::GetScrollMaxY() +{ + return GetWindowScrollMaxY(GImGui->CurrentWindow); +} + +void ImGui::SetScrollX(float scroll_x) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->ScrollTarget.x = scroll_x; + window->ScrollTargetCenterRatio.x = 0.0f; +} + +void ImGui::SetScrollY(float scroll_y) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->ScrollTarget.y = scroll_y + window->TitleBarHeight() + window->MenuBarHeight(); // title bar height canceled out when using ScrollTargetRelY + window->ScrollTargetCenterRatio.y = 0.0f; +} + +void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio) +{ + // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size + ImGuiWindow* window = GetCurrentWindow(); + IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); + window->ScrollTarget.y = (float)(int)(local_y + window->Scroll.y); + window->ScrollTargetCenterRatio.y = center_y_ratio; +} + +// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item. +void ImGui::SetScrollHereY(float center_y_ratio) +{ + ImGuiWindow* window = GetCurrentWindow(); + float target_y = window->DC.CursorPosPrevLine.y - window->Pos.y; // Top of last item, in window space + target_y += (window->DC.PrevLineSize.y * center_y_ratio) + (GImGui->Style.ItemSpacing.y * (center_y_ratio - 0.5f) * 2.0f); // Precisely aim above, in the middle or below the last line. + SetScrollFromPosY(target_y, center_y_ratio); +} + +void ImGui::ActivateItem(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + g.NavNextActivateId = id; +} + +void ImGui::SetKeyboardFocusHere(int offset) +{ + IM_ASSERT(offset >= -1); // -1 is allowed but not below + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + g.FocusRequestNextWindow = window; + g.FocusRequestNextCounterAll = window->DC.FocusCounterAll + 1 + offset; + g.FocusRequestNextCounterTab = INT_MAX; +} + +void ImGui::SetItemDefaultFocus() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!window->Appearing) + return; + if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent) + { + g.NavInitRequest = false; + g.NavInitResultId = g.NavWindow->DC.LastItemId; + g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos); + NavUpdateAnyRequestFlag(); + if (!IsItemVisible()) + SetScrollHereY(); + } +} + +void ImGui::SetStateStorage(ImGuiStorage* tree) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + window->DC.StateStorage = tree ? tree : &window->StateStorage; +} + +ImGuiStorage* ImGui::GetStateStorage() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->DC.StateStorage; +} + +void ImGui::PushID(const char* str_id) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + window->IDStack.push_back(window->GetIDNoKeepAlive(str_id)); +} + +void ImGui::PushID(const char* str_id_begin, const char* str_id_end) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + window->IDStack.push_back(window->GetIDNoKeepAlive(str_id_begin, str_id_end)); +} + +void ImGui::PushID(const void* ptr_id) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id)); +} + +void ImGui::PushID(int int_id) +{ + const void* ptr_id = (void*)(intptr_t)int_id; + ImGuiWindow* window = GImGui->CurrentWindow; + window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id)); +} + +void ImGui::PopID() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + window->IDStack.pop_back(); +} + +ImGuiID ImGui::GetID(const char* str_id) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(str_id); +} + +ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(str_id_begin, str_id_end); +} + +ImGuiID ImGui::GetID(const void* ptr_id) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(ptr_id); +} + +bool ImGui::IsRectVisible(const ImVec2& size) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); +} + +bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ClipRect.Overlaps(ImRect(rect_min, rect_max)); +} + +// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) +void ImGui::BeginGroup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1); + ImGuiGroupData& group_data = window->DC.GroupStack.back(); + group_data.BackupCursorPos = window->DC.CursorPos; + group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; + group_data.BackupIndent = window->DC.Indent; + group_data.BackupGroupOffset = window->DC.GroupOffset; + group_data.BackupCurrentLineSize = window->DC.CurrentLineSize; + group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; + group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; + group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; + group_data.AdvanceCursor = true; + + window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x; + window->DC.Indent = window->DC.GroupOffset; + window->DC.CursorMaxPos = window->DC.CursorPos; + window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f); + if (g.LogEnabled) + g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return +} + +void ImGui::EndGroup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls + + ImGuiGroupData& group_data = window->DC.GroupStack.back(); + + ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos); + group_bb.Max = ImMax(group_bb.Min, group_bb.Max); + + window->DC.CursorPos = group_data.BackupCursorPos; + window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); + window->DC.Indent = group_data.BackupIndent; + window->DC.GroupOffset = group_data.BackupGroupOffset; + window->DC.CurrentLineSize = group_data.BackupCurrentLineSize; + window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; + if (g.LogEnabled) + g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return + + if (group_data.AdvanceCursor) + { + window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. + ItemSize(group_bb.GetSize(), 0.0f); + ItemAdd(group_bb, 0); + } + + // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. + // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets. + // (and if you grep for LastItemId you'll notice it is only used in that context. + if ((group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId) // && g.ActiveIdWindow->RootWindow == window->RootWindow) + window->DC.LastItemId = g.ActiveId; + else if (!group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive) // && g.ActiveIdPreviousFrameWindow->RootWindow == window->RootWindow) + window->DC.LastItemId = g.ActiveIdPreviousFrame; + window->DC.LastItemRect = group_bb; + + window->DC.GroupStack.pop_back(); + + //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] +} + +// Gets back to previous line and continue with horizontal layout +// pos_x == 0 : follow right after previous item +// pos_x != 0 : align to specified x position (relative to window/group left) +// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 +// spacing_w >= 0 : enforce spacing amount +void ImGui::SameLine(float pos_x, float spacing_w) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + if (pos_x != 0.0f) + { + if (spacing_w < 0.0f) spacing_w = 0.0f; + window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x; + window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; + } + else + { + if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x; + window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w; + window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; + } + window->DC.CurrentLineSize = window->DC.PrevLineSize; + window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; +} + +void ImGui::Indent(float indent_w) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; + window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; +} + +void ImGui::Unindent(float indent_w) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; + window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; +} + +//----------------------------------------------------------------------------- +// [SECTION] TOOLTIPS +//----------------------------------------------------------------------------- + +void ImGui::BeginTooltip() +{ + ImGuiContext& g = *GImGui; + if (g.DragDropWithinSourceOrTarget) + { + // The default tooltip position is a little offset to give space to see the context menu (it's also clamped within the current viewport/monitor) + // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor. + // Whatever we do we want to call SetNextWindowPos() to enforce a tooltip position and disable clipping the tooltip without our display area, like regular tooltip do. + //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding; + ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale); + SetNextWindowPos(tooltip_pos); + SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f); + //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :( + BeginTooltipEx(0, true); + } + else + { + BeginTooltipEx(0, false); + } +} + +// Not exposed publicly as BeginTooltip() because bool parameters are evil. Let's see if other needs arise first. +void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip) +{ + ImGuiContext& g = *GImGui; + char window_name[16]; + ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount); + if (override_previous_tooltip) + if (ImGuiWindow* window = FindWindowByName(window_name)) + if (window->Active) + { + // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one. + window->Hidden = true; + window->HiddenFramesRegular = 1; + ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); + } + ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip|ImGuiWindowFlags_NoInputs|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; + Begin(window_name, NULL, flags | extra_flags); +} + +void ImGui::EndTooltip() +{ + IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls + End(); +} + +void ImGui::SetTooltipV(const char* fmt, va_list args) +{ + ImGuiContext& g = *GImGui; + if (g.DragDropWithinSourceOrTarget) + BeginTooltip(); + else + BeginTooltipEx(0, true); + TextV(fmt, args); + EndTooltip(); +} + +void ImGui::SetTooltip(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + SetTooltipV(fmt, args); + va_end(args); +} + +//----------------------------------------------------------------------------- +// [SECTION] POPUPS +//----------------------------------------------------------------------------- + +bool ImGui::IsPopupOpen(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id; +} + +bool ImGui::IsPopupOpen(const char* str_id) +{ + ImGuiContext& g = *GImGui; + return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id); +} + +ImGuiWindow* ImGui::GetFrontMostPopupModal() +{ + ImGuiContext& g = *GImGui; + for (int n = g.OpenPopupStack.Size-1; n >= 0; n--) + if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) + if (popup->Flags & ImGuiWindowFlags_Modal) + return popup; + return NULL; +} + +void ImGui::OpenPopup(const char* str_id) +{ + ImGuiContext& g = *GImGui; + OpenPopupEx(g.CurrentWindow->GetID(str_id)); +} + +// Mark popup as open (toggle toward open state). +// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. +// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). +// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) +void ImGui::OpenPopupEx(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* parent_window = g.CurrentWindow; + int current_stack_size = g.BeginPopupStack.Size; + ImGuiPopupRef popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. + popup_ref.PopupId = id; + popup_ref.Window = NULL; + popup_ref.ParentWindow = parent_window; + popup_ref.OpenFrameCount = g.FrameCount; + popup_ref.OpenParentId = parent_window->IDStack.back(); + popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); + popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos; + + //IMGUI_DEBUG_LOG("OpenPopupEx(0x%08X)\n", g.FrameCount, id); + if (g.OpenPopupStack.Size < current_stack_size + 1) + { + g.OpenPopupStack.push_back(popup_ref); + } + else + { + // Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui + // would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing + // situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand. + if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1) + { + g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount; + } + else + { + // Close child popups if any, then flag popup for open/reopen + g.OpenPopupStack.resize(current_stack_size + 1); + g.OpenPopupStack[current_stack_size] = popup_ref; + } + + // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow(). + // This is equivalent to what ClosePopupToLevel() does. + //if (g.OpenPopupStack[current_stack_size].PopupId == id) + // FocusWindow(parent_window); + } +} + +bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + { + ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! + IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) + OpenPopupEx(id); + return true; + } + return false; +} + +void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.empty()) + return; + + // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. + // Don't close our own child popup windows. + int popup_count_to_keep = 0; + if (ref_window) + { + // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow) + for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++) + { + ImGuiPopupRef& popup = g.OpenPopupStack[popup_count_to_keep]; + if (!popup.Window) + continue; + IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); + if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) + continue; + + // Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow) + bool popup_or_descendent_has_focus = false; + for (int m = popup_count_to_keep; m < g.OpenPopupStack.Size && !popup_or_descendent_has_focus; m++) + if (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow) + popup_or_descendent_has_focus = true; + if (!popup_or_descendent_has_focus) + break; + } + } + if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below + { + //IMGUI_DEBUG_LOG("ClosePopupsOverWindow(%s) -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep); + ClosePopupToLevel(popup_count_to_keep, false); + } +} + +void ImGui::ClosePopupToLevel(int remaining, bool apply_focus_to_window_under) +{ + IM_ASSERT(remaining >= 0); + ImGuiContext& g = *GImGui; + ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining-1].Window : g.OpenPopupStack[0].ParentWindow; + g.OpenPopupStack.resize(remaining); + + // FIXME: This code is faulty and we may want to eventually to replace or remove the 'apply_focus_to_window_under=true' path completely. + // Instead of using g.OpenPopupStack[remaining-1].Window etc. we should find the highest root window that is behind the popups we are closing. + // The current code will set focus to the parent of the popup window which is incorrect. + // It rarely manifested until now because UpdateMouseMovingWindowNewFrame() would call FocusWindow() again on the clicked window, + // leading to a chain of focusing A (clicked window) then B (parent window of the popup) then A again. + // However if the clicked window has the _NoMove flag set we would be left with B focused. + // For now, we have disabled this path when called from ClosePopupsOverWindow() because the users of ClosePopupsOverWindow() don't need to alter focus anyway, + // but we should inspect and fix this properly. + if (apply_focus_to_window_under) + { + if (g.NavLayer == 0) + focus_window = NavRestoreLastChildNavWindow(focus_window); + FocusWindow(focus_window); + } +} + +// Close the popup we have begin-ed into. +void ImGui::CloseCurrentPopup() +{ + ImGuiContext& g = *GImGui; + int popup_idx = g.BeginPopupStack.Size - 1; + if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) + return; + + // Closing a menu closes its top-most parent popup (unless a modal) + while (popup_idx > 0) + { + ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window; + ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window; + bool close_parent = false; + if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu)) + if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal)) + close_parent = true; + if (!close_parent) + break; + popup_idx--; + } + //IMGUI_DEBUG_LOG("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx); + ClosePopupToLevel(popup_idx, true); + + // A common pattern is to close a popup when selecting a menu item/selectable that will open another window. + // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window. + // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic. + if (ImGuiWindow* window = g.NavWindow) + window->DC.NavHideHighlightOneFrame = true; +} + +bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags) +{ + ImGuiContext& g = *GImGui; + if (!IsPopupOpen(id)) + { + g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values + return false; + } + + char name[20]; + if (extra_flags & ImGuiWindowFlags_ChildMenu) + ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth + else + ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame + + bool is_open = Begin(name, NULL, extra_flags | ImGuiWindowFlags_Popup); + if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display) + EndPopup(); + + return is_open; +} + +bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance + { + g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values + return false; + } + flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings; + return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags); +} + +// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup. +// Note that popup visibility status is owned by imgui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here. +bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiID id = window->GetID(name); + if (!IsPopupOpen(id)) + { + g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values + return false; + } + + // Center modal windows by default + // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window. + if (g.NextWindowData.PosCond == 0) + SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + + flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings; + const bool is_open = Begin(name, p_open, flags); + if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + { + EndPopup(); + if (is_open) + ClosePopupToLevel(g.BeginPopupStack.Size, true); + return false; + } + return is_open; +} + +void ImGui::EndPopup() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls + IM_ASSERT(g.BeginPopupStack.Size > 0); + + // Make all menus and popups wrap around for now, may need to expose that policy. + NavMoveRequestTryWrapping(g.CurrentWindow, ImGuiNavMoveFlags_LoopY); + + End(); +} + +// This is a helper to handle the simplest case of associating one named popup to one given widget. +// You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). +// You can pass a NULL str_id to use the identifier of the last item. +bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! + IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) + if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + OpenPopupEx(id); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); +} + +bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool also_over_items) +{ + if (!str_id) + str_id = "window_context"; + ImGuiID id = GImGui->CurrentWindow->GetID(str_id); + if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + if (also_over_items || !IsAnyItemHovered()) + OpenPopupEx(id); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); +} + +bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button) +{ + if (!str_id) + str_id = "void_context"; + ImGuiID id = GImGui->CurrentWindow->GetID(str_id); + if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) + OpenPopupEx(id); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); +} + +ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow*) +{ + ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding; + ImRect r_screen = GetViewportRect(); + r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f)); + return r_screen; +} + +// r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.) +// r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it. +ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy) +{ + ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); + //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); + //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); + + // Combo Box policy (we want a connecting edge) + if (policy == ImGuiPopupPositionPolicy_ComboBox) + { + const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up }; + for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) + { + const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; + if (n != -1 && dir == *last_dir) // Already tried this direction? + continue; + ImVec2 pos; + if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default) + if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right + if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left + if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left + if (!r_outer.Contains(ImRect(pos, pos + size))) + continue; + *last_dir = dir; + return pos; + } + } + + // Default popup policy + const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; + for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) + { + const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; + if (n != -1 && dir == *last_dir) // Already tried this direction? + continue; + float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x); + float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y); + if (avail_w < size.x || avail_h < size.y) + continue; + ImVec2 pos; + pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; + pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y; + *last_dir = dir; + return pos; + } + + // Fallback, try to keep within display + *last_dir = ImGuiDir_None; + ImVec2 pos = ref_pos; + pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x); + pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y); + return pos; +} + +ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + + ImRect r_outer = GetWindowAllowedExtentRect(window); + if (window->Flags & ImGuiWindowFlags_ChildMenu) + { + // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds. + // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu. + IM_ASSERT(g.CurrentWindow == window); + ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2]; + float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x). + ImRect r_avoid; + if (parent_window->DC.MenuBarAppending) + r_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight()); + else + r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX); + return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); + } + if (window->Flags & ImGuiWindowFlags_Popup) + { + ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1); + return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); + } + if (window->Flags & ImGuiWindowFlags_Tooltip) + { + // Position tooltip (always follows mouse) + float sc = g.Style.MouseCursorScale; + ImVec2 ref_pos = NavCalcPreferredRefPos(); + ImRect r_avoid; + if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)) + r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); + else + r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. + ImVec2 pos = FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); + if (window->AutoPosLastDirection == ImGuiDir_None) + pos = ref_pos + ImVec2(2, 2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. + return pos; + } + IM_ASSERT(0); + return window->Pos; +} + + +//----------------------------------------------------------------------------- +// [SECTION] KEYBOARD/GAMEPAD NAVIGATION +//----------------------------------------------------------------------------- + +ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy) +{ + if (ImFabs(dx) > ImFabs(dy)) + return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left; + return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up; +} + +static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1) +{ + if (a1 < b0) + return a1 - b0; + if (b1 < a0) + return a0 - b1; + return 0.0f; +} + +static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect) +{ + if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) + { + r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y); + r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y); + } + else + { + r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x); + r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x); + } +} + +// Scoring function for directional navigation. Based on https://gist.github.com/rygorous/6981057 +static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavLayer != window->DC.NavLayerCurrent) + return false; + + const ImRect& curr = g.NavScoringRectScreen; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width) + g.NavScoringCount++; + + // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring + if (window->ParentWindow == g.NavWindow) + { + IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened); + if (!window->ClipRect.Contains(cand)) + return false; + cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window + } + + // We perform scoring on items bounding box clipped by the current clipping rectangle on the other axis (clipping on our movement axis would give us equal scores for all clipped items) + // For example, this ensure that items in one column are not reached when moving vertically from items in another column. + NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect); + + // Compute distance between boxes + // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed. + float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x); + float dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items + if (dby != 0.0f && dbx != 0.0f) + dbx = (dbx/1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f); + float dist_box = ImFabs(dbx) + ImFabs(dby); + + // Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter) + float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x); + float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y); + float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee) + + // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance + ImGuiDir quadrant; + float dax = 0.0f, day = 0.0f, dist_axial = 0.0f; + if (dbx != 0.0f || dby != 0.0f) + { + // For non-overlapping boxes, use distance between boxes + dax = dbx; + day = dby; + dist_axial = dist_box; + quadrant = ImGetDirQuadrantFromDelta(dbx, dby); + } + else if (dcx != 0.0f || dcy != 0.0f) + { + // For overlapping boxes with different centers, use distance between centers + dax = dcx; + day = dcy; + dist_axial = dist_center; + quadrant = ImGetDirQuadrantFromDelta(dcx, dcy); + } + else + { + // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter) + quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; + } + +#if IMGUI_DEBUG_NAV_SCORING + char buf[128]; + if (ImGui::IsMouseHoveringRect(cand.Min, cand.Max)) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]); + ImDrawList* draw_list = ImGui::GetForegroundDrawList(window); + draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100)); + draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200)); + draw_list->AddRectFilled(cand.Max-ImVec2(4,4), cand.Max+ImGui::CalcTextSize(buf)+ImVec2(4,4), IM_COL32(40,0,0,150)); + draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf); + } + else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate. + { + if (ImGui::IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; } + if (quadrant == g.NavMoveDir) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); + ImDrawList* draw_list = ImGui::GetForegroundDrawList(window); + draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200)); + draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf); + } + } + #endif + + // Is it in the quadrant we're interesting in moving to? + bool new_best = false; + if (quadrant == g.NavMoveDir) + { + // Does it beat the current best candidate? + if (dist_box < result->DistBox) + { + result->DistBox = dist_box; + result->DistCenter = dist_center; + return true; + } + if (dist_box == result->DistBox) + { + // Try using distance between center points to break ties + if (dist_center < result->DistCenter) + { + result->DistCenter = dist_center; + new_best = true; + } + else if (dist_center == result->DistCenter) + { + // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items + // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index), + // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis. + if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance + new_best = true; + } + } + } + + // Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no "real" matches + // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness) + // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too. + // 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward. + // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option? + if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match + if (g.NavLayer == 1 && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) + if ((g.NavMoveDir == ImGuiDir_Left && dax < 0.0f) || (g.NavMoveDir == ImGuiDir_Right && dax > 0.0f) || (g.NavMoveDir == ImGuiDir_Up && day < 0.0f) || (g.NavMoveDir == ImGuiDir_Down && day > 0.0f)) + { + result->DistAxial = dist_axial; + new_best = true; + } + + return new_best; +} + +// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) +static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id) +{ + ImGuiContext& g = *GImGui; + //if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag. + // return; + + const ImGuiItemFlags item_flags = window->DC.ItemFlags; + const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos); + + // Process Init Request + if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent) + { + // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback + if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0) + { + g.NavInitResultId = id; + g.NavInitResultRectRel = nav_bb_rel; + } + if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus)) + { + g.NavInitRequest = false; // Found a match, clear request + NavUpdateAnyRequestFlag(); + } + } + + // Process Move Request (scoring for navigation) + // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy) + if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled|ImGuiItemFlags_NoNav))) + { + ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; +#if IMGUI_DEBUG_NAV_SCORING + // [DEBUG] Score all items in NavWindow at all times + if (!g.NavMoveRequest) + g.NavMoveDir = g.NavMoveDirLast; + bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest; +#else + bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb); +#endif + if (new_best) + { + result->ID = id; + result->SelectScopeId = g.MultiSelectScopeId; + result->Window = window; + result->RectRel = nav_bb_rel; + } + + const float VISIBLE_RATIO = 0.70f; + if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb)) + if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO) + if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb)) + { + result = &g.NavMoveResultLocalVisibleSet; + result->ID = id; + result->SelectScopeId = g.MultiSelectScopeId; + result->Window = window; + result->RectRel = nav_bb_rel; + } + } + + // Update window-relative bounding box of navigated item + if (g.NavId == id) + { + g.NavWindow = window; // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window. + g.NavLayer = window->DC.NavLayerCurrent; + g.NavIdIsAlive = true; + g.NavIdTabCounter = window->DC.FocusCounterTab; + window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position) + } +} + +bool ImGui::NavMoveRequestButNoResultYet() +{ + ImGuiContext& g = *GImGui; + return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0; +} + +void ImGui::NavMoveRequestCancel() +{ + ImGuiContext& g = *GImGui; + g.NavMoveRequest = false; + NavUpdateAnyRequestFlag(); +} + +void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None); + ImGui::NavMoveRequestCancel(); + g.NavMoveDir = move_dir; + g.NavMoveClipDir = clip_dir; + g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; + g.NavMoveRequestFlags = move_flags; + g.NavWindow->NavRectRel[g.NavLayer] = bb_rel; +} + +void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags) +{ + ImGuiContext& g = *GImGui; + if (g.NavWindow != window || !NavMoveRequestButNoResultYet() || g.NavMoveRequestForward != ImGuiNavForward_None || g.NavLayer != 0) + return; + IM_ASSERT(move_flags != 0); // No points calling this with no wrapping + ImRect bb_rel = window->NavRectRel[0]; + + ImGuiDir clip_dir = g.NavMoveDir; + if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) + { + bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->SizeContents.x) - window->Scroll.x; + if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(-bb_rel.GetHeight()); clip_dir = ImGuiDir_Up; } + NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + } + if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) + { + bb_rel.Min.x = bb_rel.Max.x = -window->Scroll.x; + if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(+bb_rel.GetHeight()); clip_dir = ImGuiDir_Down; } + NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + } + if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + { + bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->SizeContents.y) - window->Scroll.y; + if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(-bb_rel.GetWidth()); clip_dir = ImGuiDir_Left; } + NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + } + if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + { + bb_rel.Min.y = bb_rel.Max.y = -window->Scroll.y; + if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(+bb_rel.GetWidth()); clip_dir = ImGuiDir_Right; } + NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + } +} + +static void ImGui::NavSaveLastChildNavWindow(ImGuiWindow* nav_window) +{ + ImGuiWindow* parent_window = nav_window; + while (parent_window && (parent_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) + parent_window = parent_window->ParentWindow; + if (parent_window && parent_window != nav_window) + parent_window->NavLastChildNavWindow = nav_window; +} + +// Call when we are expected to land on Layer 0 after FocusWindow() +static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window) +{ + return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window; +} + +static void NavRestoreLayer(ImGuiNavLayer layer) +{ + ImGuiContext& g = *GImGui; + g.NavLayer = layer; + if (layer == 0) + g.NavWindow = ImGui::NavRestoreLastChildNavWindow(g.NavWindow); + if (layer == 0 && g.NavWindow->NavLastIds[0] != 0) + ImGui::SetNavIDWithRectRel(g.NavWindow->NavLastIds[0], layer, g.NavWindow->NavRectRel[0]); + else + ImGui::NavInitWindow(g.NavWindow, true); +} + +static inline void ImGui::NavUpdateAnyRequestFlag() +{ + ImGuiContext& g = *GImGui; + g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL); + if (g.NavAnyRequest) + IM_ASSERT(g.NavWindow != NULL); +} + +// This needs to be called before we submit any widget (aka in or before Begin) +void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(window == g.NavWindow); + bool init_for_nav = false; + if (!(window->Flags & ImGuiWindowFlags_NoNavInputs)) + if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) + init_for_nav = true; + if (init_for_nav) + { + SetNavID(0, g.NavLayer); + g.NavInitRequest = true; + g.NavInitRequestFromMove = false; + g.NavInitResultId = 0; + g.NavInitResultRectRel = ImRect(); + NavUpdateAnyRequestFlag(); + } + else + { + g.NavId = window->NavLastIds[0]; + } +} + +static ImVec2 ImGui::NavCalcPreferredRefPos() +{ + ImGuiContext& g = *GImGui; + if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow) + { + // Mouse (we need a fallback in case the mouse becomes invalid after being used) + if (IsMousePosValid(&g.IO.MousePos)) + return g.IO.MousePos; + return g.LastValidMousePos; + } + else + { + // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item. + const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer]; + ImVec2 pos = g.NavWindow->Pos + ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight())); + ImRect visible_rect = GetViewportRect(); + return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max)); // ImFloor() is important because non-integer mouse position application in back-end might be lossy and result in undesirable non-zero delta. + } +} + +float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode) +{ + ImGuiContext& g = *GImGui; + if (mode == ImGuiInputReadMode_Down) + return g.IO.NavInputs[n]; // Instant, read analog input (0.0f..1.0f, as provided by user) + + const float t = g.IO.NavInputsDownDuration[n]; + if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when just released, no repeat, ignore analog input. + return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f); + if (t < 0.0f) + return 0.0f; + if (mode == ImGuiInputReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input. + return (t == 0.0f) ? 1.0f : 0.0f; + if (mode == ImGuiInputReadMode_Repeat) + return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.80f); + if (mode == ImGuiInputReadMode_RepeatSlow) + return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 1.00f, g.IO.KeyRepeatRate * 2.00f); + if (mode == ImGuiInputReadMode_RepeatFast) + return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.30f); + return 0.0f; +} + +ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor) +{ + ImVec2 delta(0.0f, 0.0f); + if (dir_sources & ImGuiNavDirSourceFlags_Keyboard) + delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - GetNavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode)); + if (dir_sources & ImGuiNavDirSourceFlags_PadDPad) + delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - GetNavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode)); + if (dir_sources & ImGuiNavDirSourceFlags_PadLStick) + delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode)); + if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow)) + delta *= slow_factor; + if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast)) + delta *= fast_factor; + return delta; +} + +// Scroll to keep newly navigated item fully into view +// NB: We modify rect_rel by the amount we scrolled for, so it is immediately updated. +static void NavScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item_rect) +{ + ImRect window_rect(window->InnerMainRect.Min - ImVec2(1, 1), window->InnerMainRect.Max + ImVec2(1, 1)); + //GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG] + if (window_rect.Contains(item_rect)) + return; + + ImGuiContext& g = *GImGui; + if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x) + { + window->ScrollTarget.x = item_rect.Min.x - window->Pos.x + window->Scroll.x - g.Style.ItemSpacing.x; + window->ScrollTargetCenterRatio.x = 0.0f; + } + else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x) + { + window->ScrollTarget.x = item_rect.Max.x - window->Pos.x + window->Scroll.x + g.Style.ItemSpacing.x; + window->ScrollTargetCenterRatio.x = 1.0f; + } + if (item_rect.Min.y < window_rect.Min.y) + { + window->ScrollTarget.y = item_rect.Min.y - window->Pos.y + window->Scroll.y - g.Style.ItemSpacing.y; + window->ScrollTargetCenterRatio.y = 0.0f; + } + else if (item_rect.Max.y >= window_rect.Max.y) + { + window->ScrollTarget.y = item_rect.Max.y - window->Pos.y + window->Scroll.y + g.Style.ItemSpacing.y; + window->ScrollTargetCenterRatio.y = 1.0f; + } +} + +static void ImGui::NavUpdate() +{ + ImGuiContext& g = *GImGui; + g.IO.WantSetMousePos = false; +#if 0 + if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); +#endif + + // Set input source as Gamepad when buttons are pressed before we map Keyboard (some features differs when used with Gamepad vs Keyboard) + bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + if (nav_gamepad_active) + if (g.IO.NavInputs[ImGuiNavInput_Activate] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Input] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Cancel] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Menu] > 0.0f) + g.NavInputSource = ImGuiInputSource_NavGamepad; + + // Update Keyboard->Nav inputs mapping + if (nav_keyboard_active) + { + #define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; } + NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate ); + NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input ); + NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel ); + NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ ); + NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_); + NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ ); + NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ ); + NAV_MAP_KEY(ImGuiKey_Tab, ImGuiNavInput_KeyTab_ ); + if (g.IO.KeyCtrl) + g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f; + if (g.IO.KeyShift) + g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f; + if (g.IO.KeyAlt && !g.IO.KeyCtrl) // AltGR is Alt+Ctrl, also even on keyboards without AltGR we don't want Alt+Ctrl to open menu. + g.IO.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f; + #undef NAV_MAP_KEY + } + memcpy(g.IO.NavInputsDownDurationPrev, g.IO.NavInputsDownDuration, sizeof(g.IO.NavInputsDownDuration)); + for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++) + g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f; + + // Process navigation init request (select first/default focus) + if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove)) + { + // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) + IM_ASSERT(g.NavWindow); + if (g.NavInitRequestFromMove) + SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel); + else + SetNavID(g.NavInitResultId, g.NavLayer); + g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel; + } + g.NavInitRequest = false; + g.NavInitRequestFromMove = false; + g.NavInitResultId = 0; + g.NavJustMovedToId = 0; + + // Process navigation move request + if (g.NavMoveRequest) + NavUpdateMoveResult(); + + // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame + if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive) + { + IM_ASSERT(g.NavMoveRequest); + if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) + g.NavDisableHighlight = false; + g.NavMoveRequestForward = ImGuiNavForward_None; + } + + // Apply application mouse position movement, after we had a chance to process move request result. + if (g.NavMousePosDirty && g.NavIdIsAlive) + { + // Set mouse position given our knowledge of the navigated item position from last frame + if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (g.IO.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) + { + if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow) + { + g.IO.MousePos = g.IO.MousePosPrev = NavCalcPreferredRefPos(); + g.IO.WantSetMousePos = true; + } + } + g.NavMousePosDirty = false; + } + g.NavIdIsAlive = false; + g.NavJustTabbedId = 0; + IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1); + + // Store our return window (for returning from Layer 1 to Layer 0) and clear it as soon as we step back in our own Layer 0 + if (g.NavWindow) + NavSaveLastChildNavWindow(g.NavWindow); + if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == 0) + g.NavWindow->NavLastChildNavWindow = NULL; + + // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.) + NavUpdateWindowing(); + + // Set output flags for user application + g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); + g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); + + // Process NavCancel input (to close a popup, get back to parent, clear focus) + if (IsNavInputPressed(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) + { + if (g.ActiveId != 0) + { + if (!(g.ActiveIdBlockNavInputFlags & (1 << ImGuiNavInput_Cancel))) + ClearActiveID(); + } + else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow) + { + // Exit child window + ImGuiWindow* child_window = g.NavWindow; + ImGuiWindow* parent_window = g.NavWindow->ParentWindow; + IM_ASSERT(child_window->ChildId != 0); + FocusWindow(parent_window); + SetNavID(child_window->ChildId, 0); + g.NavIdIsAlive = false; + if (g.NavDisableMouseHover) + g.NavMousePosDirty = true; + } + else if (g.OpenPopupStack.Size > 0) + { + // Close open popup/menu + if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) + ClosePopupToLevel(g.OpenPopupStack.Size - 1, true); + } + else if (g.NavLayer != 0) + { + // Leave the "menu" layer + NavRestoreLayer(ImGuiNavLayer_Main); + } + else + { + // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were + if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) + g.NavWindow->NavLastIds[0] = 0; + g.NavId = 0; + } + } + + // Process manual activation request + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0; + if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + { + bool activate_down = IsNavInputDown(ImGuiNavInput_Activate); + bool activate_pressed = activate_down && IsNavInputPressed(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed); + if (g.ActiveId == 0 && activate_pressed) + g.NavActivateId = g.NavId; + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down) + g.NavActivateDownId = g.NavId; + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed) + g.NavActivatePressedId = g.NavId; + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputPressed(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed)) + g.NavInputId = g.NavId; + } + if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + g.NavDisableHighlight = true; + if (g.NavActivateId != 0) + IM_ASSERT(g.NavActivateDownId == g.NavActivateId); + g.NavMoveRequest = false; + + // Process programmatic activation request + if (g.NavNextActivateId != 0) + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId; + g.NavNextActivateId = 0; + + // Initiate directional inputs request + const int allowed_dir_flags = (g.ActiveId == 0) ? ~0 : g.ActiveIdAllowNavDirFlags; + if (g.NavMoveRequestForward == ImGuiNavForward_None) + { + g.NavMoveDir = ImGuiDir_None; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_None; + if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + { + if ((allowed_dir_flags & (1<Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget) + { + // *Fallback* manual-scroll with Nav directional keys when window has no navigable item + ImGuiWindow* window = g.NavWindow; + const float scroll_speed = ImFloor(window->CalcFontSize() * 100 * g.IO.DeltaTime + 0.5f); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. + if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) + { + if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) + SetWindowScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); + if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) + SetWindowScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed)); + } + + // *Normal* Manual scroll with NavScrollXXX keys + // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds. + ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f/10.0f, 10.0f); + if (scroll_dir.x != 0.0f && window->ScrollbarX) + { + SetWindowScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed)); + g.NavMoveFromClampedRefRect = true; + } + if (scroll_dir.y != 0.0f) + { + SetWindowScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed)); + g.NavMoveFromClampedRefRect = true; + } + } + + // Reset search results + g.NavMoveResultLocal.Clear(); + g.NavMoveResultLocalVisibleSet.Clear(); + g.NavMoveResultOther.Clear(); + + // When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items + if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0) + { + ImGuiWindow* window = g.NavWindow; + ImRect window_rect_rel(window->InnerMainRect.Min - window->Pos - ImVec2(1,1), window->InnerMainRect.Max - window->Pos + ImVec2(1,1)); + if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer])) + { + float pad = window->CalcFontSize() * 0.5f; + window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item + window->NavRectRel[g.NavLayer].ClipWith(window_rect_rel); + g.NavId = 0; + } + g.NavMoveFromClampedRefRect = false; + } + + // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items) + ImRect nav_rect_rel = (g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted()) ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0,0,0,0); + g.NavScoringRectScreen = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect(); + g.NavScoringRectScreen.TranslateY(nav_scoring_rect_offset_y); + g.NavScoringRectScreen.Min.x = ImMin(g.NavScoringRectScreen.Min.x + 1.0f, g.NavScoringRectScreen.Max.x); + g.NavScoringRectScreen.Max.x = g.NavScoringRectScreen.Min.x; + IM_ASSERT(!g.NavScoringRectScreen.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem(). + //GetForegroundDrawList()->AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG] + g.NavScoringCount = 0; +#if IMGUI_DEBUG_NAV_RECTS + if (g.NavWindow) + { + ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow); + if (1) { for (int layer = 0; layer < 2; layer++) draw_list->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } // [DEBUG] + if (1) { ImU32 col = (!g.NavWindow->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); } + } +#endif +} + +// Apply result from previous frame navigation directional move request +static void ImGui::NavUpdateMoveResult() +{ + ImGuiContext& g = *GImGui; + if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) + { + // In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result) + if (g.NavId != 0) + { + g.NavDisableHighlight = false; + g.NavDisableMouseHover = true; + } + return; + } + + // Select which result to use + ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; + + // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page. + if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) + if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId) + result = &g.NavMoveResultLocalVisibleSet; + + // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules. + if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) + if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter)) + result = &g.NavMoveResultOther; + IM_ASSERT(g.NavWindow && result->Window); + + // Scroll to keep newly navigated item fully into view. + if (g.NavLayer == 0) + { + ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos); + NavScrollToBringItemIntoView(result->Window, rect_abs); + + // Estimate upcoming scroll so we can offset our result position so mouse position can be applied immediately after in NavUpdate() + ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(result->Window, false); + ImVec2 delta_scroll = result->Window->Scroll - next_scroll; + result->RectRel.Translate(delta_scroll); + + // Also scroll parent window to keep us into view if necessary (we could/should technically recurse back the whole the parent hierarchy). + if (result->Window->Flags & ImGuiWindowFlags_ChildWindow) + NavScrollToBringItemIntoView(result->Window->ParentWindow, ImRect(rect_abs.Min + delta_scroll, rect_abs.Max + delta_scroll)); + } + + ClearActiveID(); + g.NavWindow = result->Window; + if (g.NavId != result->ID) + { + // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId) + g.NavJustMovedToId = result->ID; + g.NavJustMovedToSelectScopeId = result->SelectScopeId; + } + SetNavIDWithRectRel(result->ID, g.NavLayer, result->RectRel); + g.NavMoveFromClampedRefRect = false; +} + +static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags) +{ + ImGuiContext& g = *GImGui; + if (g.NavMoveDir == ImGuiDir_None && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget && g.NavLayer == 0) + { + ImGuiWindow* window = g.NavWindow; + bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && (allowed_dir_flags & (1 << ImGuiDir_Up)); + bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && (allowed_dir_flags & (1 << ImGuiDir_Down)); + if (page_up_held != page_down_held) // If either (not both) are pressed + { + if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll) + { + // Fallback manual-scroll when window has no navigable item + if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true)) + SetWindowScrollY(window, window->Scroll.y - window->InnerClipRect.GetHeight()); + else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true)) + SetWindowScrollY(window, window->Scroll.y + window->InnerClipRect.GetHeight()); + } + else + { + const ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; + const float page_offset_y = ImMax(0.0f, window->InnerClipRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); + float nav_scoring_rect_offset_y = 0.0f; + if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true)) + { + nav_scoring_rect_offset_y = -page_offset_y; + g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset, we intentionally request the opposite direction (so we can always land on the last item) + g.NavMoveClipDir = ImGuiDir_Up; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; + } + else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true)) + { + nav_scoring_rect_offset_y = +page_offset_y; + g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset, we intentionally request the opposite direction (so we can always land on the last item) + g.NavMoveClipDir = ImGuiDir_Down; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; + } + return nav_scoring_rect_offset_y; + } + } + } + return 0.0f; +} + +static int FindWindowFocusIndex(ImGuiWindow* window) // FIXME-OPT O(N) +{ + ImGuiContext& g = *GImGui; + for (int i = g.WindowsFocusOrder.Size-1; i >= 0; i--) + if (g.WindowsFocusOrder[i] == window) + return i; + return -1; +} + +static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N) +{ + ImGuiContext& g = *GImGui; + for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir) + if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i])) + return g.WindowsFocusOrder[i]; + return NULL; +} + +static void NavUpdateWindowingHighlightWindow(int focus_change_dir) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindowingTarget); + if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal) + return; + + const int i_current = FindWindowFocusIndex(g.NavWindowingTarget); + ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir); + if (!window_target) + window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir); + if (window_target) // Don't reset windowing target if there's a single window in the list + g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target; + g.NavWindowingToggleLayer = false; +} + +// Windowing management mode +// Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer) +// Gamepad: Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer) +static void ImGui::NavUpdateWindowing() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* apply_focus_window = NULL; + bool apply_toggle_layer = false; + + ImGuiWindow* modal_window = GetFrontMostPopupModal(); + if (modal_window != NULL) + { + g.NavWindowingTarget = NULL; + return; + } + + // Fade out + if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL) + { + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f); + if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f) + g.NavWindowingTargetAnim = NULL; + } + + // Start CTRL-TAB or Square+L/R window selection + bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputPressed(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); + bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard); + if (start_windowing_with_gamepad || start_windowing_with_keyboard) + if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) + { + g.NavWindowingTarget = g.NavWindowingTargetAnim = window; + g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f; + g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true; + g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad; + } + + // Gamepad update + g.NavWindowingTimer += g.IO.DeltaTime; + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad) + { + // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); + + // Select window to focus + const int focus_change_dir = (int)IsNavInputPressed(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputPressed(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow); + if (focus_change_dir != 0) + { + NavUpdateWindowingHighlightWindow(focus_change_dir); + g.NavWindowingHighlightAlpha = 1.0f; + } + + // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered front-most) + if (!IsNavInputDown(ImGuiNavInput_Menu)) + { + g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore. + if (g.NavWindowingToggleLayer && g.NavWindow) + apply_toggle_layer = true; + else if (!g.NavWindowingToggleLayer) + apply_focus_window = g.NavWindowingTarget; + g.NavWindowingTarget = NULL; + } + } + + // Keyboard: Focus + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard) + { + // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f + if (IsKeyPressedMap(ImGuiKey_Tab, true)) + NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1); + if (!g.IO.KeyCtrl) + apply_focus_window = g.NavWindowingTarget; + } + + // Keyboard: Press and Release ALT to toggle menu layer + // FIXME: We lack an explicit IO variable for "is the imgui window focused", so compare mouse validity to detect the common case of back-end clearing releases all keys on ALT-TAB + if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released)) + if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev)) + apply_toggle_layer = true; + + // Move window + if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove)) + { + ImVec2 move_delta; + if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift) + move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); + if (g.NavInputSource == ImGuiInputSource_NavGamepad) + move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down); + if (move_delta.x != 0.0f || move_delta.y != 0.0f) + { + const float NAV_MOVE_SPEED = 800.0f; + const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't code variable framerate very well + g.NavWindowingTarget->RootWindow->Pos += move_delta * move_speed; + g.NavDisableMouseHover = true; + MarkIniSettingsDirty(g.NavWindowingTarget); + } + } + + // Apply final focus + if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow)) + { + g.NavDisableHighlight = false; + g.NavDisableMouseHover = true; + apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window); + ClosePopupsOverWindow(apply_focus_window); + ClearActiveID(); + FocusWindow(apply_focus_window); + if (apply_focus_window->NavLastIds[0] == 0) + NavInitWindow(apply_focus_window, false); + + // If the window only has a menu layer, select it directly + if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu)) + g.NavLayer = ImGuiNavLayer_Menu; + } + if (apply_focus_window) + g.NavWindowingTarget = NULL; + + // Apply menu/layer toggle + if (apply_toggle_layer && g.NavWindow) + { + // Move to parent menu if necessary + ImGuiWindow* new_nav_window = g.NavWindow; + while ((new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0 + && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 + && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) + new_nav_window = new_nav_window->ParentWindow; + if (new_nav_window != g.NavWindow) + { + ImGuiWindow* old_nav_window = g.NavWindow; + FocusWindow(new_nav_window); + new_nav_window->NavLastChildNavWindow = old_nav_window; + } + g.NavDisableHighlight = false; + g.NavDisableMouseHover = true; + NavRestoreLayer((g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main); + } +} + +// Window has already passed the IsWindowNavFocusable() +static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window) +{ + if (window->Flags & ImGuiWindowFlags_Popup) + return "(Popup)"; + if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0) + return "(Main menu bar)"; + return "(Untitled)"; +} + +// Overlay displayed when using CTRL+TAB. Called by EndFrame(). +void ImGui::NavUpdateWindowingList() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindowingTarget != NULL); + + if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY) + return; + + if (g.NavWindowingList == NULL) + g.NavWindowingList = FindWindowByName("###NavWindowingList"); + SetNextWindowSizeConstraints(ImVec2(g.IO.DisplaySize.x * 0.20f, g.IO.DisplaySize.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); + SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f); + Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); + for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--) + { + ImGuiWindow* window = g.WindowsFocusOrder[n]; + if (!IsWindowNavFocusable(window)) + continue; + const char* label = window->Name; + if (label == FindRenderedTextEnd(label)) + label = GetFallbackWindowNameForWindowingList(window); + Selectable(label, g.NavWindowingTarget == window); + } + End(); + PopStyleVar(); +} + +//----------------------------------------------------------------------------- +// [SECTION] COLUMNS +// In the current version, Columns are very weak. Needs to be replaced with a more full-featured system. +//----------------------------------------------------------------------------- + +void ImGui::NextColumn() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems || window->DC.ColumnsSet == NULL) + return; + + ImGuiContext& g = *GImGui; + ImGuiColumnsSet* columns = window->DC.ColumnsSet; + + if (columns->Count == 1) + { + window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + IM_ASSERT(columns->Current == 0); + return; + } + + PopItemWidth(); + PopClipRect(); + + columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); + if (++columns->Current < columns->Count) + { + // Columns 1+ cancel out IndentX + window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + g.Style.ItemSpacing.x; + window->DrawList->ChannelsSetCurrent(columns->Current); + } + else + { + // New line + window->DC.ColumnsOffset.x = 0.0f; + window->DrawList->ChannelsSetCurrent(0); + columns->Current = 0; + columns->LineMinY = columns->LineMaxY; + } + window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + window->DC.CursorPos.y = columns->LineMinY; + window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f); + window->DC.CurrentLineTextBaseOffset = 0.0f; + + PushColumnClipRect(); + PushItemWidth(GetColumnWidth() * 0.65f); // FIXME: Move on columns setup +} + +int ImGui::GetColumnIndex() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.ColumnsSet ? window->DC.ColumnsSet->Current : 0; +} + +int ImGui::GetColumnsCount() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.ColumnsSet ? window->DC.ColumnsSet->Count : 1; +} + +static float OffsetNormToPixels(const ImGuiColumnsSet* columns, float offset_norm) +{ + return offset_norm * (columns->MaxX - columns->MinX); +} + +static float PixelsToOffsetNorm(const ImGuiColumnsSet* columns, float offset) +{ + return offset / (columns->MaxX - columns->MinX); +} + +static inline float GetColumnsRectHalfWidth() { return 4.0f; } + +static float GetDraggedColumnOffset(ImGuiColumnsSet* columns, int column_index) +{ + // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing + // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning. + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(column_index > 0); // We are not supposed to drag column 0. + IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index)); + + float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + GetColumnsRectHalfWidth() - window->Pos.x; + x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing); + if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths)) + x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing); + + return x; +} + +float ImGui::GetColumnOffset(int column_index) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiColumnsSet* columns = window->DC.ColumnsSet; + IM_ASSERT(columns != NULL); + + if (column_index < 0) + column_index = columns->Current; + IM_ASSERT(column_index < columns->Columns.Size); + + const float t = columns->Columns[column_index].OffsetNorm; + const float x_offset = ImLerp(columns->MinX, columns->MaxX, t); + return x_offset; +} + +static float GetColumnWidthEx(ImGuiColumnsSet* columns, int column_index, bool before_resize = false) +{ + if (column_index < 0) + column_index = columns->Current; + + float offset_norm; + if (before_resize) + offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize; + else + offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm; + return OffsetNormToPixels(columns, offset_norm); +} + +float ImGui::GetColumnWidth(int column_index) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiColumnsSet* columns = window->DC.ColumnsSet; + IM_ASSERT(columns != NULL); + + if (column_index < 0) + column_index = columns->Current; + return OffsetNormToPixels(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm); +} + +void ImGui::SetColumnOffset(int column_index, float offset) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiColumnsSet* columns = window->DC.ColumnsSet; + IM_ASSERT(columns != NULL); + + if (column_index < 0) + column_index = columns->Current; + IM_ASSERT(column_index < columns->Columns.Size); + + const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1); + const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; + + if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow)) + offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); + columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX); + + if (preserve_width) + SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); +} + +void ImGui::SetColumnWidth(int column_index, float width) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiColumnsSet* columns = window->DC.ColumnsSet; + IM_ASSERT(columns != NULL); + + if (column_index < 0) + column_index = columns->Current; + SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width); +} + +void ImGui::PushColumnClipRect(int column_index) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiColumnsSet* columns = window->DC.ColumnsSet; + if (column_index < 0) + column_index = columns->Current; + + PushClipRect(columns->Columns[column_index].ClipRect.Min, columns->Columns[column_index].ClipRect.Max, false); +} + +static ImGuiColumnsSet* FindOrAddColumnsSet(ImGuiWindow* window, ImGuiID id) +{ + for (int n = 0; n < window->ColumnsStorage.Size; n++) + if (window->ColumnsStorage[n].ID == id) + return &window->ColumnsStorage[n]; + + window->ColumnsStorage.push_back(ImGuiColumnsSet()); + ImGuiColumnsSet* columns = &window->ColumnsStorage.back(); + columns->ID = id; + return columns; +} + +void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + IM_ASSERT(columns_count >= 1); + IM_ASSERT(window->DC.ColumnsSet == NULL); // Nested columns are currently not supported + + // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. + // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer. + PushID(0x11223347 + (str_id ? 0 : columns_count)); + ImGuiID id = window->GetID(str_id ? str_id : "columns"); + PopID(); + + // Acquire storage for the columns set + ImGuiColumnsSet* columns = FindOrAddColumnsSet(window, id); + IM_ASSERT(columns->ID == id); + columns->Current = 0; + columns->Count = columns_count; + columns->Flags = flags; + window->DC.ColumnsSet = columns; + + // Set state for first column + const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x); + columns->MinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range + columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f); + columns->StartPosY = window->DC.CursorPos.y; + columns->StartMaxPosX = window->DC.CursorMaxPos.x; + columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; + window->DC.ColumnsOffset.x = 0.0f; + window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + + // Clear data if columns count changed + if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) + columns->Columns.resize(0); + + // Initialize defaults + columns->IsFirstFrame = (columns->Columns.Size == 0); + if (columns->Columns.Size == 0) + { + columns->Columns.reserve(columns_count + 1); + for (int n = 0; n < columns_count + 1; n++) + { + ImGuiColumnData column; + column.OffsetNorm = n / (float)columns_count; + columns->Columns.push_back(column); + } + } + + for (int n = 0; n < columns_count; n++) + { + // Compute clipping rectangle + ImGuiColumnData* column = &columns->Columns[n]; + float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n) - 1.0f); + float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f); + column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX); + column->ClipRect.ClipWith(window->ClipRect); + } + + if (columns->Count > 1) + { + window->DrawList->ChannelsSplit(columns->Count); + PushColumnClipRect(); + } + PushItemWidth(GetColumnWidth() * 0.65f); +} + +void ImGui::EndColumns() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + ImGuiColumnsSet* columns = window->DC.ColumnsSet; + IM_ASSERT(columns != NULL); + + PopItemWidth(); + if (columns->Count > 1) + { + PopClipRect(); + window->DrawList->ChannelsMerge(); + } + + columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); + window->DC.CursorPos.y = columns->LineMaxY; + if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize)) + window->DC.CursorMaxPos.x = columns->StartMaxPosX; // Restore cursor max pos, as columns don't grow parent + + // Draw columns borders and handle resize + bool is_being_resized = false; + if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) + { + const float y1 = columns->StartPosY; + const float y2 = window->DC.CursorPos.y; + int dragging_column = -1; + for (int n = 1; n < columns->Count; n++) + { + float x = window->Pos.x + GetColumnOffset(n); + const ImGuiID column_id = columns->ID + ImGuiID(n); + const float column_hw = GetColumnsRectHalfWidth(); // Half-width for interaction + const ImRect column_rect(ImVec2(x - column_hw, y1), ImVec2(x + column_hw, y2)); + KeepAliveID(column_id); + if (IsClippedEx(column_rect, column_id, false)) + continue; + + bool hovered = false, held = false; + if (!(columns->Flags & ImGuiColumnsFlags_NoResize)) + { + ButtonBehavior(column_rect, column_id, &hovered, &held); + if (hovered || held) + g.MouseCursor = ImGuiMouseCursor_ResizeEW; + if (held && !(columns->Columns[n].Flags & ImGuiColumnsFlags_NoResize)) + dragging_column = n; + } + + // Draw column (we clip the Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.) + const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); + const float xi = (float)(int)x; + window->DrawList->AddLine(ImVec2(xi, ImMax(y1 + 1.0f, window->ClipRect.Min.y)), ImVec2(xi, ImMin(y2, window->ClipRect.Max.y)), col); + } + + // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame. + if (dragging_column != -1) + { + if (!columns->IsBeingResized) + for (int n = 0; n < columns->Count + 1; n++) + columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm; + columns->IsBeingResized = is_being_resized = true; + float x = GetDraggedColumnOffset(columns, dragging_column); + SetColumnOffset(dragging_column, x); + } + } + columns->IsBeingResized = is_being_resized; + + window->DC.ColumnsSet = NULL; + window->DC.ColumnsOffset.x = 0.0f; + window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); +} + +// [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing] +void ImGui::Columns(int columns_count, const char* id, bool border) +{ + ImGuiWindow* window = GetCurrentWindow(); + IM_ASSERT(columns_count >= 1); + + ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder); + //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior + if (window->DC.ColumnsSet != NULL && window->DC.ColumnsSet->Count == columns_count && window->DC.ColumnsSet->Flags == flags) + return; + + if (window->DC.ColumnsSet != NULL) + EndColumns(); + + if (columns_count != 1) + BeginColumns(id, columns_count, flags); +} + +//----------------------------------------------------------------------------- +// [SECTION] DRAG AND DROP +//----------------------------------------------------------------------------- + +void ImGui::ClearDragDrop() +{ + ImGuiContext& g = *GImGui; + g.DragDropActive = false; + g.DragDropPayload.Clear(); + g.DragDropAcceptFlags = ImGuiDragDropFlags_None; + g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0; + g.DragDropAcceptIdCurrRectSurface = FLT_MAX; + g.DragDropAcceptFrameCount = -1; + + g.DragDropPayloadBufHeap.clear(); + memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); +} + +// Call when current ID is active. +// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource() +bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + bool source_drag_active = false; + ImGuiID source_id = 0; + ImGuiID source_parent_id = 0; + int mouse_button = 0; + if (!(flags & ImGuiDragDropFlags_SourceExtern)) + { + source_id = window->DC.LastItemId; + if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case + return false; + if (g.IO.MouseDown[mouse_button] == false) + return false; + + if (source_id == 0) + { + // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to: + // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride. + if (!(flags & ImGuiDragDropFlags_SourceAllowNullID)) + { + IM_ASSERT(0); + return false; + } + + // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image() + // We build a throwaway ID based on current ID stack + relative AABB of items in window. + // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled. + // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. + bool is_hovered = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) != 0; + if (!is_hovered && (g.ActiveId == 0 || g.ActiveIdWindow != window)) + return false; + source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect); + if (is_hovered) + SetHoveredID(source_id); + if (is_hovered && g.IO.MouseClicked[mouse_button]) + { + SetActiveID(source_id, window); + FocusWindow(window); + } + if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker. + g.ActiveIdAllowOverlap = is_hovered; + } + else + { + g.ActiveIdAllowOverlap = false; + } + if (g.ActiveId != source_id) + return false; + source_parent_id = window->IDStack.back(); + source_drag_active = IsMouseDragging(mouse_button); + } + else + { + window = NULL; + source_id = ImHashStr("#SourceExtern", 0); + source_drag_active = true; + } + + if (source_drag_active) + { + if (!g.DragDropActive) + { + IM_ASSERT(source_id != 0); + ClearDragDrop(); + ImGuiPayload& payload = g.DragDropPayload; + payload.SourceId = source_id; + payload.SourceParentId = source_parent_id; + g.DragDropActive = true; + g.DragDropSourceFlags = flags; + g.DragDropMouseButton = mouse_button; + } + g.DragDropSourceFrameCount = g.FrameCount; + g.DragDropWithinSourceOrTarget = true; + + if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + { + // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) + // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. + BeginTooltip(); + if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) + { + ImGuiWindow* tooltip_window = g.CurrentWindow; + tooltip_window->SkipItems = true; + tooltip_window->HiddenFramesRegular = 1; + } + } + + if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) + window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect; + + return true; + } + return false; +} + +void ImGui::EndDragDropSource() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DragDropActive); + IM_ASSERT(g.DragDropWithinSourceOrTarget && "Not after a BeginDragDropSource()?"); + + if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + EndTooltip(); + + // Discard the drag if have not called SetDragDropPayload() + if (g.DragDropPayload.DataFrameCount == -1) + ClearDragDrop(); + g.DragDropWithinSourceOrTarget = false; +} + +// Use 'cond' to choose to submit payload on drag start or every frame +bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + ImGuiPayload& payload = g.DragDropPayload; + if (cond == 0) + cond = ImGuiCond_Always; + + IM_ASSERT(type != NULL); + IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long"); + IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0)); + IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once); + IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource() + + if (cond == ImGuiCond_Always || payload.DataFrameCount == -1) + { + // Copy payload + ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType)); + g.DragDropPayloadBufHeap.resize(0); + if (data_size > sizeof(g.DragDropPayloadBufLocal)) + { + // Store in heap + g.DragDropPayloadBufHeap.resize((int)data_size); + payload.Data = g.DragDropPayloadBufHeap.Data; + memcpy(payload.Data, data, data_size); + } + else if (data_size > 0) + { + // Store locally + memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); + payload.Data = g.DragDropPayloadBufLocal; + memcpy(payload.Data, data, data_size); + } + else + { + payload.Data = NULL; + } + payload.DataSize = (int)data_size; + } + payload.DataFrameCount = g.FrameCount; + + return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1); +} + +bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id) +{ + ImGuiContext& g = *GImGui; + if (!g.DragDropActive) + return false; + + ImGuiWindow* window = g.CurrentWindow; + if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow) + return false; + IM_ASSERT(id != 0); + if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId)) + return false; + if (window->SkipItems) + return false; + + IM_ASSERT(g.DragDropWithinSourceOrTarget == false); + g.DragDropTargetRect = bb; + g.DragDropTargetId = id; + g.DragDropWithinSourceOrTarget = true; + return true; +} + +// We don't use BeginDragDropTargetCustom() and duplicate its code because: +// 1) we use LastItemRectHoveredRect which handles items that pushes a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them. +// 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can. +// Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case) +bool ImGui::BeginDragDropTarget() +{ + ImGuiContext& g = *GImGui; + if (!g.DragDropActive) + return false; + + ImGuiWindow* window = g.CurrentWindow; + if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) + return false; + if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow) + return false; + + const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect; + ImGuiID id = window->DC.LastItemId; + if (id == 0) + id = window->GetIDFromRectangle(display_rect); + if (g.DragDropPayload.SourceId == id) + return false; + + IM_ASSERT(g.DragDropWithinSourceOrTarget == false); + g.DragDropTargetRect = display_rect; + g.DragDropTargetId = id; + g.DragDropWithinSourceOrTarget = true; + return true; +} + +bool ImGui::IsDragDropPayloadBeingAccepted() +{ + ImGuiContext& g = *GImGui; + return g.DragDropActive && g.DragDropAcceptIdPrev != 0; +} + +const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiPayload& payload = g.DragDropPayload; + IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ? + IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ? + if (type != NULL && !payload.IsDataType(type)) + return NULL; + + // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints. + // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function! + const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId); + ImRect r = g.DragDropTargetRect; + float r_surface = r.GetWidth() * r.GetHeight(); + if (r_surface < g.DragDropAcceptIdCurrRectSurface) + { + g.DragDropAcceptFlags = flags; + g.DragDropAcceptIdCurr = g.DragDropTargetId; + g.DragDropAcceptIdCurrRectSurface = r_surface; + } + + // Render default drop visuals + payload.Preview = was_accepted_previously; + flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame) + if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview) + { + // FIXME-DRAG: Settle on a proper default visuals for drop target. + r.Expand(3.5f); + bool push_clip_rect = !window->ClipRect.Contains(r); + if (push_clip_rect) window->DrawList->PushClipRect(r.Min-ImVec2(1,1), r.Max+ImVec2(1,1)); + window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f); + if (push_clip_rect) window->DrawList->PopClipRect(); + } + + g.DragDropAcceptFrameCount = g.FrameCount; + payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting os window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased() + if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) + return NULL; + + return &payload; +} + +const ImGuiPayload* ImGui::GetDragDropPayload() +{ + ImGuiContext& g = *GImGui; + return g.DragDropActive ? &g.DragDropPayload : NULL; +} + +// We don't really use/need this now, but added it for the sake of consistency and because we might need it later. +void ImGui::EndDragDropTarget() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DragDropActive); + IM_ASSERT(g.DragDropWithinSourceOrTarget); + g.DragDropWithinSourceOrTarget = false; +} + + +//----------------------------------------------------------------------------- +// [SECTION] LOGGING/CAPTURING +//----------------------------------------------------------------------------- +// All text output from the interface can be captured into tty/file/clipboard. +// By default, tree nodes are automatically opened during logging. +//----------------------------------------------------------------------------- + +// Pass text data straight to log (without being displayed) +void ImGui::LogText(const char* fmt, ...) +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; + + va_list args; + va_start(args, fmt); + if (g.LogFile) + vfprintf(g.LogFile, fmt, args); + else + g.LogBuffer.appendfv(fmt, args); + va_end(args); +} + +// Internal version that takes a position to decide on newline placement and pad items according to their depth. +// We split text into individual lines to add current tree level padding +void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (!text_end) + text_end = FindRenderedTextEnd(text, text_end); + + const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + 1); + if (ref_pos) + g.LogLinePosY = ref_pos->y; + if (log_new_line) + g.LogLineFirstItem = true; + + const char* text_remaining = text; + if (g.LogDepthRef > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth + g.LogDepthRef = window->DC.TreeDepth; + const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef); + for (;;) + { + // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry. + // We don't add a trailing \n to allow a subsequent item on the same line to be captured. + const char* line_start = text_remaining; + const char* line_end = ImStreolRange(line_start, text_end); + const bool is_first_line = (line_start == text); + const bool is_last_line = (line_end == text_end); + if (!is_last_line || (line_start != line_end)) + { + const int char_count = (int)(line_end - line_start); + if (log_new_line || !is_first_line) + LogText(IM_NEWLINE "%*s%.*s", tree_depth * 4, "", char_count, line_start); + else if (g.LogLineFirstItem) + LogText("%*s%.*s", tree_depth * 4, "", char_count, line_start); + else + LogText(" %.*s", char_count, line_start); + g.LogLineFirstItem = false; + } + else if (log_new_line) + { + // An empty "" string at a different Y position should output a carriage return. + LogText(IM_NEWLINE); + break; + } + + if (is_last_line) + break; + text_remaining = line_end + 1; + } +} + +// Start logging/capturing text output +void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.LogEnabled == false); + IM_ASSERT(g.LogFile == NULL); + IM_ASSERT(g.LogBuffer.empty()); + g.LogEnabled = true; + g.LogType = type; + g.LogDepthRef = window->DC.TreeDepth; + g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault); + g.LogLinePosY = FLT_MAX; + g.LogLineFirstItem = true; +} + +void ImGui::LogToTTY(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + LogBegin(ImGuiLogType_TTY, auto_open_depth); + g.LogFile = stdout; +} + +// Start logging/capturing text output to given file +void ImGui::LogToFile(int auto_open_depth, const char* filename) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + + // FIXME: We could probably open the file in text mode "at", however note that clipboard/buffer logging will still + // be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE. + // By opening the file in binary mode "ab" we have consistent output everywhere. + if (!filename) + filename = g.IO.LogFilename; + if (!filename || !filename[0]) + return; + FILE* f = ImFileOpen(filename, "ab"); + if (f == NULL) + { + IM_ASSERT(0); + return; + } + + LogBegin(ImGuiLogType_File, auto_open_depth); + g.LogFile = f; +} + +// Start logging/capturing text output to clipboard +void ImGui::LogToClipboard(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + LogBegin(ImGuiLogType_Clipboard, auto_open_depth); +} + +void ImGui::LogToBuffer(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + LogBegin(ImGuiLogType_Buffer, auto_open_depth); +} + +void ImGui::LogFinish() +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; + + LogText(IM_NEWLINE); + switch (g.LogType) + { + case ImGuiLogType_TTY: + fflush(g.LogFile); + break; + case ImGuiLogType_File: + fclose(g.LogFile); + break; + case ImGuiLogType_Buffer: + break; + case ImGuiLogType_Clipboard: + if (!g.LogBuffer.empty()) + SetClipboardText(g.LogBuffer.begin()); + break; + case ImGuiLogType_None: + IM_ASSERT(0); + break; + } + + g.LogEnabled = false; + g.LogType = ImGuiLogType_None; + g.LogFile = NULL; + g.LogBuffer.clear(); +} + +// Helper to display logging buttons +// FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!) +void ImGui::LogButtons() +{ + ImGuiContext& g = *GImGui; + + PushID("LogButtons"); + const bool log_to_tty = Button("Log To TTY"); SameLine(); + const bool log_to_file = Button("Log To File"); SameLine(); + const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); + PushItemWidth(80.0f); + PushAllowKeyboardFocus(false); + SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL); + PopAllowKeyboardFocus(); + PopItemWidth(); + PopID(); + + // Start logging at the end of the function so that the buttons don't appear in the log + if (log_to_tty) + LogToTTY(); + if (log_to_file) + LogToFile(); + if (log_to_clipboard) + LogToClipboard(); +} + +//----------------------------------------------------------------------------- +// [SECTION] SETTINGS +//----------------------------------------------------------------------------- + +void ImGui::MarkIniSettingsDirty() +{ + ImGuiContext& g = *GImGui; + if (g.SettingsDirtyTimer <= 0.0f) + g.SettingsDirtyTimer = g.IO.IniSavingRate; +} + +void ImGui::MarkIniSettingsDirty(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) + if (g.SettingsDirtyTimer <= 0.0f) + g.SettingsDirtyTimer = g.IO.IniSavingRate; +} + +ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) +{ + ImGuiContext& g = *GImGui; + g.SettingsWindows.push_back(ImGuiWindowSettings()); + ImGuiWindowSettings* settings = &g.SettingsWindows.back(); + settings->Name = ImStrdup(name); + settings->ID = ImHashStr(name, 0); + return settings; +} + +ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + for (int i = 0; i != g.SettingsWindows.Size; i++) + if (g.SettingsWindows[i].ID == id) + return &g.SettingsWindows[i]; + return NULL; +} + +ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name) +{ + if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name, 0))) + return settings; + return CreateNewWindowSettings(name); +} + +void ImGui::LoadIniSettingsFromDisk(const char* ini_filename) +{ + size_t file_data_size = 0; + char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size); + if (!file_data) + return; + LoadIniSettingsFromMemory(file_data, (size_t)file_data_size); + ImGui::MemFree(file_data); +} + +ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) +{ + ImGuiContext& g = *GImGui; + const ImGuiID type_hash = ImHashStr(type_name, 0); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].TypeHash == type_hash) + return &g.SettingsHandlers[handler_n]; + return NULL; +} + +// Zero-tolerance, no error reporting, cheap .ini parsing +void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0); + + // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter). + // For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy.. + if (ini_size == 0) + ini_size = strlen(ini_data); + char* buf = (char*)ImGui::MemAlloc(ini_size + 1); + char* buf_end = buf + ini_size; + memcpy(buf, ini_data, ini_size); + buf[ini_size] = 0; + + void* entry_data = NULL; + ImGuiSettingsHandler* entry_handler = NULL; + + char* line_end = NULL; + for (char* line = buf; line < buf_end; line = line_end + 1) + { + // Skip new lines markers, then find end of the line + while (*line == '\n' || *line == '\r') + line++; + line_end = line; + while (line_end < buf_end && *line_end != '\n' && *line_end != '\r') + line_end++; + line_end[0] = 0; + if (line[0] == ';') + continue; + if (line[0] == '[' && line_end > line && line_end[-1] == ']') + { + // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code. + line_end[-1] = 0; + const char* name_end = line_end - 1; + const char* type_start = line + 1; + char* type_end = (char*)(intptr_t)ImStrchrRange(type_start, name_end, ']'); + const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; + if (!type_end || !name_start) + { + name_start = type_start; // Import legacy entries that have no type + type_start = "Window"; + } + else + { + *type_end = 0; // Overwrite first ']' + name_start++; // Skip second '[' + } + entry_handler = FindSettingsHandler(type_start); + entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL; + } + else if (entry_handler != NULL && entry_data != NULL) + { + // Let type handler parse the line + entry_handler->ReadLineFn(&g, entry_handler, entry_data, line); + } + } + ImGui::MemFree(buf); + g.SettingsLoaded = true; +} + +void ImGui::SaveIniSettingsToDisk(const char* ini_filename) +{ + ImGuiContext& g = *GImGui; + g.SettingsDirtyTimer = 0.0f; + if (!ini_filename) + return; + + size_t ini_data_size = 0; + const char* ini_data = SaveIniSettingsToMemory(&ini_data_size); + FILE* f = ImFileOpen(ini_filename, "wt"); + if (!f) + return; + fwrite(ini_data, sizeof(char), ini_data_size, f); + fclose(f); +} + +// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer +const char* ImGui::SaveIniSettingsToMemory(size_t* out_size) +{ + ImGuiContext& g = *GImGui; + g.SettingsDirtyTimer = 0.0f; + g.SettingsIniData.Buf.resize(0); + g.SettingsIniData.Buf.push_back(0); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + { + ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n]; + handler->WriteAllFn(&g, handler, &g.SettingsIniData); + } + if (out_size) + *out_size = (size_t)g.SettingsIniData.size(); + return g.SettingsIniData.c_str(); +} + +static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) +{ + ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name, 0)); + if (!settings) + settings = ImGui::CreateNewWindowSettings(name); + return (void*)settings; +} + +static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) +{ + ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry; + float x, y; + int i; + if (sscanf(line, "Pos=%f,%f", &x, &y) == 2) settings->Pos = ImVec2(x, y); + else if (sscanf(line, "Size=%f,%f", &x, &y) == 2) settings->Size = ImMax(ImVec2(x, y), GImGui->Style.WindowMinSize); + else if (sscanf(line, "Collapsed=%d", &i) == 1) settings->Collapsed = (i != 0); +} + +static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) +{ + // Gather data from windows that were active during this session + // (if a window wasn't opened in this session we preserve its settings) + ImGuiContext& g = *imgui_ctx; + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + if (window->Flags & ImGuiWindowFlags_NoSavedSettings) + continue; + + ImGuiWindowSettings* settings = (window->SettingsIdx != -1) ? &g.SettingsWindows[window->SettingsIdx] : ImGui::FindWindowSettings(window->ID); + if (!settings) + { + settings = ImGui::CreateNewWindowSettings(window->Name); + window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings); + } + IM_ASSERT(settings->ID == window->ID); + settings->Pos = window->Pos; + settings->Size = window->SizeFull; + settings->Collapsed = window->Collapsed; + } + + // Write to text buffer + buf->reserve(buf->size() + g.SettingsWindows.Size * 96); // ballpark reserve + for (int i = 0; i != g.SettingsWindows.Size; i++) + { + const ImGuiWindowSettings* settings = &g.SettingsWindows[i]; + if (settings->Pos.x == FLT_MAX) + continue; + const char* name = settings->Name; + if (const char* p = strstr(name, "###")) // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() + name = p; + buf->appendf("[%s][%s]\n", handler->TypeName, name); + buf->appendf("Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y); + buf->appendf("Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y); + buf->appendf("Collapsed=%d\n", settings->Collapsed); + buf->appendf("\n"); + } +} + + +//----------------------------------------------------------------------------- +// [SECTION] VIEWPORTS, PLATFORM WINDOWS +//----------------------------------------------------------------------------- + +// (this section is filled in the 'docking' branch) + + +//----------------------------------------------------------------------------- +// [SECTION] DOCKING +//----------------------------------------------------------------------------- + +// (this section is filled in the 'docking' branch) + + +//----------------------------------------------------------------------------- +// [SECTION] PLATFORM DEPENDENT HELPERS +//----------------------------------------------------------------------------- + +#if defined(_WIN32) && !defined(_WINDOWS_) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && (!defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) || !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef __MINGW32__ +#include +#else +#include +#endif +#endif + +// Win32 API clipboard implementation +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) + +#ifdef _MSC_VER +#pragma comment(lib, "user32") +#endif + +static const char* GetClipboardTextFn_DefaultImpl(void*) +{ + static ImVector buf_local; + buf_local.clear(); + if (!::OpenClipboard(NULL)) + return NULL; + HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT); + if (wbuf_handle == NULL) + { + ::CloseClipboard(); + return NULL; + } + if (ImWchar* wbuf_global = (ImWchar*)::GlobalLock(wbuf_handle)) + { + int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1; + buf_local.resize(buf_len); + ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL); + } + ::GlobalUnlock(wbuf_handle); + ::CloseClipboard(); + return buf_local.Data; +} + +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +{ + if (!::OpenClipboard(NULL)) + return; + const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1; + HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar)); + if (wbuf_handle == NULL) + { + ::CloseClipboard(); + return; + } + ImWchar* wbuf_global = (ImWchar*)::GlobalLock(wbuf_handle); + ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL); + ::GlobalUnlock(wbuf_handle); + ::EmptyClipboard(); + if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL) + ::GlobalFree(wbuf_handle); + ::CloseClipboard(); +} + +#else + +// Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers +static const char* GetClipboardTextFn_DefaultImpl(void*) +{ + ImGuiContext& g = *GImGui; + return g.PrivateClipboard.empty() ? NULL : g.PrivateClipboard.begin(); +} + +// Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +{ + ImGuiContext& g = *GImGui; + g.PrivateClipboard.clear(); + const char* text_end = text + strlen(text); + g.PrivateClipboard.resize((int)(text_end - text) + 1); + memcpy(&g.PrivateClipboard[0], text, (size_t)(text_end - text)); + g.PrivateClipboard[(int)(text_end - text)] = 0; +} + +#endif + +// Win32 API IME support (for Asian languages, etc.) +#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) + +#include +#ifdef _MSC_VER +#pragma comment(lib, "imm32") +#endif + +static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) +{ + // Notify OS Input Method Editor of text input position + if (HWND hwnd = (HWND)GImGui->IO.ImeWindowHandle) + if (HIMC himc = ::ImmGetContext(hwnd)) + { + COMPOSITIONFORM cf; + cf.ptCurrentPos.x = x; + cf.ptCurrentPos.y = y; + cf.dwStyle = CFS_FORCE_POSITION; + ::ImmSetCompositionWindow(himc, &cf); + ::ImmReleaseContext(hwnd, himc); + } +} + +#else + +static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} + +#endif + +//----------------------------------------------------------------------------- +// [SECTION] METRICS/DEBUG WINDOW +//----------------------------------------------------------------------------- + +void ImGui::ShowMetricsWindow(bool* p_open) +{ + if (!ImGui::Begin("ImGui Metrics", p_open)) + { + ImGui::End(); + return; + } + + static bool show_draw_cmd_clip_rects = true; + static bool show_window_begin_order = false; + ImGuiIO& io = ImGui::GetIO(); + ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + ImGui::Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); + ImGui::Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows); + ImGui::Text("%d allocations", io.MetricsActiveAllocations); + ImGui::Checkbox("Show clipping rectangles when hovering draw commands", &show_draw_cmd_clip_rects); + ImGui::Checkbox("Ctrl shows window begin order", &show_window_begin_order); + ImGui::Separator(); + + struct Funcs + { + static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label) + { + bool node_open = ImGui::TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, draw_list->CmdBuffer.Size); + if (draw_list == ImGui::GetWindowDrawList()) + { + ImGui::SameLine(); + ImGui::TextColored(ImVec4(1.0f,0.4f,0.4f,1.0f), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered) + if (node_open) ImGui::TreePop(); + return; + } + + ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list + if (window && IsItemHovered()) + fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); + if (!node_open) + return; + + int elem_offset = 0; + for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++) + { + if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0) + continue; + if (pcmd->UserCallback) + { + ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); + continue; + } + ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; + bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %4d %s vtx, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); + if (show_draw_cmd_clip_rects && ImGui::IsItemHovered()) + { + ImRect clip_rect = pcmd->ClipRect; + ImRect vtxs_rect; + for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++) + vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos); + clip_rect.Floor(); fg_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255)); + vtxs_rect.Floor(); fg_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,0,255,255)); + } + if (!pcmd_node_open) + continue; + + // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. + ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. + while (clipper.Step()) + for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) + { + char buf[300]; + char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf); + ImVec2 triangles_pos[3]; + for (int n = 0; n < 3; n++, idx_i++) + { + int vtx_i = idx_buffer ? idx_buffer[idx_i] : idx_i; + ImDrawVert& v = draw_list->VtxBuffer[vtx_i]; + triangles_pos[n] = v.pos; + buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", + (n == 0) ? "idx" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + } + ImGui::Selectable(buf, false); + if (ImGui::IsItemHovered()) + { + ImDrawListFlags backup_flags = fg_draw_list->Flags; + fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines at is more readable for very large and thin triangles. + fg_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f); + fg_draw_list->Flags = backup_flags; + } + } + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + static void NodeWindows(ImVector& windows, const char* label) + { + if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size)) + return; + for (int i = 0; i < windows.Size; i++) + Funcs::NodeWindow(windows[i], "Window"); + ImGui::TreePop(); + } + + static void NodeWindow(ImGuiWindow* window, const char* label) + { + if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window)) + return; + ImGuiWindowFlags flags = window->Flags; + NodeDrawList(window, window->DrawList, "DrawList"); + ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y); + ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags, + (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", + (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", + (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); + ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, GetWindowScrollMaxX(window), window->Scroll.y, GetWindowScrollMaxY(window)); + ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); + ImGui::BulletText("Appearing: %d, Hidden: %d (Reg %d Resize %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesRegular, window->HiddenFramesForResize, window->SkipItems); + ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask); + ImGui::BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); + if (!window->NavRectRel[0].IsInverted()) + ImGui::BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y); + else + ImGui::BulletText("NavRectRel[0]: "); + if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow"); + if (window->ParentWindow != NULL) NodeWindow(window->ParentWindow, "ParentWindow"); + if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows"); + if (window->ColumnsStorage.Size > 0 && ImGui::TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size)) + { + for (int n = 0; n < window->ColumnsStorage.Size; n++) + { + const ImGuiColumnsSet* columns = &window->ColumnsStorage[n]; + if (ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) + { + ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX); + for (int column_n = 0; column_n < columns->Columns.Size; column_n++) + ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm)); + ImGui::TreePop(); + } + } + ImGui::TreePop(); + } + ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair)); + ImGui::TreePop(); + } + + static void NodeTabBar(ImGuiTabBar* tab_bar) + { + // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings. + char buf[256]; + char* p = buf; + const char* buf_end = buf + IM_ARRAYSIZE(buf); + ImFormatString(p, buf_end - p, "TabBar (%d tabs)%s", tab_bar->Tabs.Size, (tab_bar->PrevFrameVisible < ImGui::GetFrameCount() - 2) ? " *Inactive*" : ""); + if (ImGui::TreeNode(tab_bar, "%s", buf)) + { + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + ImGui::PushID(tab); + if (ImGui::SmallButton("<")) { TabBarQueueChangeTabOrder(tab_bar, tab, -1); } ImGui::SameLine(0, 2); + if (ImGui::SmallButton(">")) { TabBarQueueChangeTabOrder(tab_bar, tab, +1); } ImGui::SameLine(); + ImGui::Text("%02d%c Tab 0x%08X", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID); + ImGui::PopID(); + } + ImGui::TreePop(); + } + } + }; + + // Access private state, we are going to display the draw lists from last frame + ImGuiContext& g = *GImGui; + Funcs::NodeWindows(g.Windows, "Windows"); + if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size)) + { + for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++) + Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList"); + ImGui::TreePop(); + } + if (ImGui::TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size)) + { + for (int i = 0; i < g.OpenPopupStack.Size; i++) + { + ImGuiWindow* window = g.OpenPopupStack[i].Window; + ImGui::BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : ""); + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.Data.Size)) + { + for (int n = 0; n < g.TabBars.Data.Size; n++) + Funcs::NodeTabBar(g.TabBars.GetByIndex(n)); + ImGui::TreePop(); + } + if (ImGui::TreeNode("Internal state")) + { + const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); + ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); + ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL"); + ImGui::Text("HoveredId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not + ImGui::Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, input_source_names[g.ActiveIdSource]); + ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); + ImGui::Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL"); + ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL"); + ImGui::Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); + ImGui::Text("NavInputSource: %s", input_source_names[g.NavInputSource]); + ImGui::Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); + ImGui::Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId); + ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); + ImGui::Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL"); + ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize); + ImGui::TreePop(); + } + + + if (g.IO.KeyCtrl && show_window_begin_order) + { + for (int n = 0; n < g.Windows.Size; n++) + { + ImGuiWindow* window = g.Windows[n]; + if ((window->Flags & ImGuiWindowFlags_ChildWindow) || !window->WasActive) + continue; + char buf[32]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext); + float font_size = ImGui::GetFontSize() * 2; + ImDrawList* fg_draw_list = GetForegroundDrawList(window); + fg_draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255)); + fg_draw_list->AddText(NULL, font_size, window->Pos, IM_COL32(255, 255, 255, 255), buf); + } + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- + +// Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed. +// Prefer just including imgui_internal.h from your code rather than using this define. If a declaration is missing from imgui_internal.h add it or request it on the github. +#ifdef IMGUI_INCLUDE_IMGUI_USER_INL +#include "imgui_user.inl" +#endif + +//----------------------------------------------------------------------------- diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui.h b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui.h new file mode 100644 index 00000000..fdbbb89e --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui.h @@ -0,0 +1,2169 @@ +// dear imgui, v1.69 +// (headers) + +// See imgui.cpp file for documentation. +// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. +// Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. +// Get latest version at /~https://github.com/ocornut/imgui + +/* + +Index of this file: +// Header mess +// Forward declarations and basic types +// ImGui API (Dear ImGui end-user API) +// Flags & Enumerations +// ImVector<> +// ImGuiStyle +// ImGuiIO +// Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload) +// Obsolete functions +// Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) +// Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListFlags, ImDrawList, ImDrawData) +// Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) + +*/ + +#pragma once + +// Configuration file with compile-time options (edit imconfig.h or define IMGUI_USER_CONFIG to your own filename) +#ifdef IMGUI_USER_CONFIG +#include IMGUI_USER_CONFIG +#endif +#if !defined(IMGUI_DISABLE_INCLUDE_IMCONFIG_H) || defined(IMGUI_INCLUDE_IMCONFIG_H) +#include "imconfig.h" +#endif + +//----------------------------------------------------------------------------- +// Header mess +//----------------------------------------------------------------------------- + +#include // FLT_MAX +#include // va_list +#include // ptrdiff_t, NULL +#include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp + +// Version +// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) +#define IMGUI_VERSION "1.69" +#define IMGUI_VERSION_NUM 16900 +#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert)) + +// Define attributes of all API symbols declarations (e.g. for DLL under Windows) +// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default bindings files (imgui_impl_xxx.h) +#ifndef IMGUI_API +#define IMGUI_API +#endif +#ifndef IMGUI_IMPL_API +#define IMGUI_IMPL_API IMGUI_API +#endif + +// Helper Macros +#ifndef IM_ASSERT +#include +#define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h +#endif +#if defined(__clang__) || defined(__GNUC__) +#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // Apply printf-style warnings to user functions. +#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) +#else +#define IM_FMTARGS(FMT) +#define IM_FMTLIST(FMT) +#endif +#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) // Size of a static C-style array. Don't use on pointers! +#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in modern C++. +#define IM_UNUSED(_VAR) ((void)_VAR) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. + +// Warnings +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +#elif defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + +//----------------------------------------------------------------------------- +// Forward declarations and basic types +//----------------------------------------------------------------------------- + +struct ImDrawChannel; // Temporary storage for ImDrawList ot output draw commands out of order, used by ImDrawList::ChannelsSplit() +struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback) +struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix. +struct ImDrawList; // A single draw command list (generally one per window, conceptually you may see this as a dynamic "mesh" builder) +struct ImDrawListSharedData; // Data shared among multiple draw lists (typically owned by parent ImGui context, but you may create one yourself) +struct ImDrawVert; // A single vertex (pos + uv + col = 20 bytes by default. Override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT) +struct ImFont; // Runtime data for a single font within a parent ImFontAtlas +struct ImFontAtlas; // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader +struct ImFontConfig; // Configuration data when adding a font or merging fonts +struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) +struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data +struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using) +struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) +struct ImGuiIO; // Main configuration and I/O between your application and ImGui +struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) +struct ImGuiListClipper; // Helper to manually clip large list of items +struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame, used by IMGUI_ONCE_UPON_A_FRAME macro +struct ImGuiPayload; // User data payload for drag and drop operations +struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use) +struct ImGuiStorage; // Helper for key->value storage +struct ImGuiStyle; // Runtime data for styling/colors +struct ImGuiTextBuffer; // Helper to hold and append into a text buffer (~string builder) +struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbb][,ccccc]") + +// Typedefs and Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file) +// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. +#ifndef ImTextureID +typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp) +#endif +typedef unsigned int ImGuiID; // Unique ID used by widgets (typically hashed from a stack of string) +typedef unsigned short ImWchar; // A single U16 character for keyboard input/display. We encode them as multi bytes UTF-8 when used in strings. +typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling +typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for Set*() +typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type +typedef int ImGuiDir; // -> enum ImGuiDir_ // Enum: A cardinal direction +typedef int ImGuiKey; // -> enum ImGuiKey_ // Enum: A key identifier (ImGui-side enum) +typedef int ImGuiNavInput; // -> enum ImGuiNavInput_ // Enum: An input identifier for navigation +typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A mouse cursor identifier +typedef int ImGuiStyleVar; // -> enum ImGuiStyleVar_ // Enum: A variable identifier for styling +typedef int ImDrawCornerFlags; // -> enum ImDrawCornerFlags_ // Flags: for ImDrawList::AddRect*() etc. +typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList +typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas +typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags +typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit*(), ColorPicker*() +typedef int ImGuiColumnsFlags; // -> enum ImGuiColumnsFlags_ // Flags: for Columns(), BeginColumns() +typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags +typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() +typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for *DragDrop*() +typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() +typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. +typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText*() +typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable() +typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar() +typedef int ImGuiTabItemFlags; // -> enum ImGuiTabItemFlags_ // Flags: for BeginTabItem() +typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode*(),CollapsingHeader() +typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin*() +typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData *data); +typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); + +// Scalar data types +typedef signed char ImS8; // 8-bit signed integer == char +typedef unsigned char ImU8; // 8-bit unsigned integer +typedef signed short ImS16; // 16-bit signed integer +typedef unsigned short ImU16; // 16-bit unsigned integer +typedef signed int ImS32; // 32-bit signed integer == int +typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors) +#if defined(_MSC_VER) && !defined(__clang__) +typedef signed __int64 ImS64; // 64-bit signed integer (pre and post C++11 with Visual Studio) +typedef unsigned __int64 ImU64; // 64-bit unsigned integer (pre and post C++11 with Visual Studio) +#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100) +#include +typedef int64_t ImS64; // 64-bit signed integer (pre C++11) +typedef uint64_t ImU64; // 64-bit unsigned integer (pre C++11) +#else +typedef signed long long ImS64; // 64-bit signed integer (post C++11) +typedef unsigned long long ImU64; // 64-bit unsigned integer (post C++11) +#endif + +// 2D vector (often used to store positions, sizes, etc.) +struct ImVec2 +{ + float x, y; + ImVec2() { x = y = 0.0f; } + ImVec2(float _x, float _y) { x = _x; y = _y; } + float operator[] (size_t idx) const { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. + float& operator[] (size_t idx) { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. +#ifdef IM_VEC2_CLASS_EXTRA + IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. +#endif +}; + +// 4D vector (often used to store floating-point colors) +struct ImVec4 +{ + float x, y, z, w; + ImVec4() { x = y = z = w = 0.0f; } + ImVec4(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; } +#ifdef IM_VEC4_CLASS_EXTRA + IM_VEC4_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4. +#endif +}; + +//----------------------------------------------------------------------------- +// ImGui: Dear ImGui end-user API +// (Inside a namespace so you can add extra functions in your own separate file. Please don't modify imgui.cpp/.h!) +//----------------------------------------------------------------------------- + +namespace ImGui +{ + // Context creation and access + // Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between imgui contexts. + // All those functions are not reliant on the current context. + IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL); + IMGUI_API void DestroyContext(ImGuiContext* ctx = NULL); // NULL = destroy current context + IMGUI_API ImGuiContext* GetCurrentContext(); + IMGUI_API void SetCurrentContext(ImGuiContext* ctx); + IMGUI_API bool DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert); + + // Main + IMGUI_API ImGuiIO& GetIO(); // access the IO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags) + IMGUI_API ImGuiStyle& GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleCol(), PushStyleVar() to modify style mid-frame. + IMGUI_API void NewFrame(); // start a new ImGui frame, you can submit any command from this point until Render()/EndFrame(). + IMGUI_API void EndFrame(); // ends the ImGui frame. automatically called by Render(), you likely don't need to call that yourself directly. If you don't need to render data (skipping rendering) you may call EndFrame() but you'll have wasted CPU already! If you don't need to render, better to not create any imgui windows and not call NewFrame() at all! + IMGUI_API void Render(); // ends the ImGui frame, finalize the draw data. (Obsolete: optionally call io.RenderDrawListsFn if set. Nowadays, prefer calling your render function yourself.) + IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). this is what you have to render. (Obsolete: this used to be passed to your io.RenderDrawListsFn() function.) + + // Demo, Debug, Information + IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create demo/test window (previously called ShowTestWindow). demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! + IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create about window. display Dear ImGui version, credits and build/system information. + IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create metrics/debug window. display Dear ImGui internals: draw commands (with individual draw calls and vertices), window list, basic internal state, etc. + IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style) + IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles. + IMGUI_API void ShowFontSelector(const char* label); // add font selector block (not a window), essentially a combo listing the loaded fonts. + IMGUI_API void ShowUserGuide(); // add basic help/info block (not a window): how to manipulate ImGui as a end-user (mouse/keyboard controls). + IMGUI_API const char* GetVersion(); // get the compiled version string e.g. "1.23" (essentially the compiled value for IMGUI_VERSION) + + // Styles + IMGUI_API void StyleColorsDark(ImGuiStyle* dst = NULL); // new, recommended style (default) + IMGUI_API void StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style + IMGUI_API void StyleColorsLight(ImGuiStyle* dst = NULL); // best used with borders and a custom, thicker font + + // Windows + // - Begin() = push window to the stack and start appending to it. End() = pop window from the stack. + // - You may append multiple times to the same window during the same frame. + // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, + // which clicking will set the boolean to false when clicked. + // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting + // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! + // [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. + // where the EndXXX call should only be called if the corresponding BeginXXX function returned true.] + // - Note that the bottom of window stack always contains a window called "Debug". + IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); + IMGUI_API void End(); + + // Child Windows + // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. + // - For each independent axis of 'size': ==0.0f: use remaining host window size / >0.0f: fixed size / <0.0f: use remaining window size minus abs(size) / Each axis can use a different mode, e.g. ImVec2(0,400). + // - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window. + // Always call a matching EndChild() for each BeginChild() call, regardless of its return value [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function returned true.] + IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags flags = 0); + IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags flags = 0); + IMGUI_API void EndChild(); + + // Windows Utilities + // - "current window" = the window we are appending into while inside a Begin()/End() block. "next window" = next window we will Begin() into. + IMGUI_API bool IsWindowAppearing(); + IMGUI_API bool IsWindowCollapsed(); + IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. + IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ! + IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives + + IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList API) + IMGUI_API ImVec2 GetWindowSize(); // get current window size + IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x) + IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y) + IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates + IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() + IMGUI_API float GetContentRegionAvailWidth(); // == GetContentRegionAvail().x + IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min (roughly (0,0)-Scroll), in window coordinates + IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates + IMGUI_API float GetWindowContentRegionWidth(); // + + IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0,0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc. + IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() + IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Use callback to apply non-trivial programmatic constraints. + IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (~ enforce the range of scrollbars). not including window decorations (title bar, menu bar, etc.). set an axis to 0.0f to leave it automatic. call before Begin() + IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // set next window collapsed state. call before Begin() + IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most. call before Begin() + IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily modify ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground. + IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects. + IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. + IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). + IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / front-most. prefer using SetNextWindowFocus(). + IMGUI_API void SetWindowFontScale(float scale); // set font scale. Adjust IO.FontGlobalScale if you want to scale all windows + IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position. + IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. + IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state + IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / front-most. use NULL to remove focus. + + // Windows Scrolling + IMGUI_API float GetScrollX(); // get scrolling amount [0..GetScrollMaxX()] + IMGUI_API float GetScrollY(); // get scrolling amount [0..GetScrollMaxY()] + IMGUI_API float GetScrollMaxX(); // get maximum scrolling amount ~~ ContentSize.X - WindowSize.X + IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.Y - WindowSize.Y + IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0..GetScrollMaxX()] + IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0..GetScrollMaxY()] + IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. + IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. + + // Parameters stacks (shared) + IMGUI_API void PushFont(ImFont* font); // use NULL as a shortcut to push default font + IMGUI_API void PopFont(); + IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); + IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); + IMGUI_API void PopStyleColor(int count = 1); + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); + IMGUI_API void PopStyleVar(int count = 1); + IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx); // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in. + IMGUI_API ImFont* GetFont(); // get current font + IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied + IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API + IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier + IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied + IMGUI_API ImU32 GetColorU32(ImU32 col); // retrieve given color with style alpha applied + + // Parameters stacks (current window) + IMGUI_API void PushItemWidth(float item_width); // width of items for the common item+label case, pixels. 0.0f = default to ~2/3 of windows width, >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side) + IMGUI_API void PopItemWidth(); + IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position + IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space + IMGUI_API void PopTextWrapPos(); + IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets + IMGUI_API void PopAllowKeyboardFocus(); + IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame. + IMGUI_API void PopButtonRepeat(); + + // Cursor / Layout + // - By "cursor" we mean the current output position. + // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. + IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. + IMGUI_API void SameLine(float local_pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates. + IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in an horizontal-layout context. + IMGUI_API void Spacing(); // add vertical spacing. + IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't take the mouse click or be navigable into. + IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by style.IndentSpacing or indent_w if != 0 + IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by style.IndentSpacing or indent_w if != 0 + IMGUI_API void BeginGroup(); // lock horizontal starting position + IMGUI_API void EndGroup(); // unlock horizontal starting position + capture the whole group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) + IMGUI_API ImVec2 GetCursorPos(); // cursor position in window coordinates (relative to window position) + IMGUI_API float GetCursorPosX(); // (some functions are using window-relative coordinates, such as: GetCursorPos, GetCursorStartPos, GetContentRegionMax, GetWindowContentRegion* etc. + IMGUI_API float GetCursorPosY(); // other functions such as GetCursorScreenPos or everything in ImDrawList:: + IMGUI_API void SetCursorPos(const ImVec2& local_pos); // are using the main, absolute coordinate system. + IMGUI_API void SetCursorPosX(float local_x); // GetWindowPos() + GetCursorPos() == GetCursorScreenPos() etc.) + IMGUI_API void SetCursorPosY(float local_y); // + IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position in window coordinates + IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates [0..io.DisplaySize] (useful to work with ImDrawList API) + IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute screen coordinates [0..io.DisplaySize] + IMGUI_API void AlignTextToFramePadding(); // vertically align upcoming text baseline to FramePadding.y so that it will align properly to regularly framed items (call if you have text on a line before a framed item) + IMGUI_API float GetTextLineHeight(); // ~ FontSize + IMGUI_API float GetTextLineHeightWithSpacing(); // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text) + IMGUI_API float GetFrameHeight(); // ~ FontSize + style.FramePadding.y * 2 + IMGUI_API float GetFrameHeightWithSpacing(); // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets) + + // ID stack/scopes + // - Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most + // likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. + // - The resulting ID are hashes of the entire stack. + // - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others. + // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID, + // whereas "str_id" denote a string that is only used as an ID and not normally displayed. + IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string). + IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string). + IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack (will hash pointer). + IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer). + IMGUI_API void PopID(); // pop from the ID stack. + IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself + IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); + IMGUI_API ImGuiID GetID(const void* ptr_id); + + // Widgets: Text + IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text. + IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // simple formatted text + IMGUI_API void TextV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...) IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor(); + IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API void TextDisabled(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); Text(fmt, ...); PopStyleColor(); + IMGUI_API void TextDisabledV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void TextWrapped(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos();. Note that this won't work on an auto-resizing window if there's no other widgets to extend the window width, yoy may need to set a size using SetNextWindowSize(). + IMGUI_API void TextWrappedV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void LabelText(const char* label, const char* fmt, ...) IM_FMTARGS(2); // display text+label aligned the same way as value+label widgets + IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text() + IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); + + // Widgets: Main + // - Most widgets return true when the value has been changed or when pressed/selected + IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0)); // button + IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text + IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); // button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.) + IMGUI_API bool ArrowButton(const char* str_id, ImGuiDir dir); // square button with an arrow shape + IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); + IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,0), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding + IMGUI_API bool Checkbox(const char* label, bool* v); + IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); + IMGUI_API bool RadioButton(const char* label, bool active); // use with e.g. if (RadioButton("one", my_value==1)) { my_value = 1; } + IMGUI_API bool RadioButton(const char* label, int* v, int v_button); // shortcut to handle the above pattern when value is an integer + IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-1,0), const char* overlay = NULL); + IMGUI_API void Bullet(); // draw a small circle and keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses + + // Widgets: Combo Box + // - The new BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items. + // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. + IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0); + IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true! + IMGUI_API bool Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1); + IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1); // Separate items with \0 within a string, end item-list with \0\0. e.g. "One\0Two\0Three\0" + IMGUI_API bool Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1); + + // Widgets: Drags + // - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped and can go off-bounds. + // - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x + // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. + // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). + IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); // If v_min >= v_max we have no bound + IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, float power = 1.0f); + IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); // If v_min >= v_max we have no bound + IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); + IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); + IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); + IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL); + IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min = NULL, const void* v_max = NULL, const char* format = NULL, float power = 1.0f); + IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min = NULL, const void* v_max = NULL, const char* format = NULL, float power = 1.0f); + + // Widgets: Sliders + // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds. + // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. + IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. Use power!=1.0 for power curve sliders + IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f, const char* format = "%.0f deg"); + IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); + IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); + IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); + + // Widgets: Input with Keyboard + // - If you want to use InputText() with a dynamic string type such as std::string or your own, see misc/cpp/imgui_stdlib.h + // - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc. + IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0,0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat4(const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0, double step_fast = 0.0, const char* format = "%.6f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); + + // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little colored preview square that can be left-clicked to open a picker, and right-clicked to open an option menu.) + // - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. + // - You can pass the address of a first float element out of a contiguous structure, e.g. &myvector.x + IMGUI_API bool ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); + IMGUI_API bool ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0); + IMGUI_API bool ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); + IMGUI_API bool ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags = 0, const float* ref_col = NULL); + IMGUI_API bool ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0)); // display a colored square/button, hover for details, return true when pressed. + IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls. + + // Widgets: Trees + // - TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents. + IMGUI_API bool TreeNode(const char* label); + IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2); // helper variation to easily decorelate the id from the displayed string. Read the FAQ about why and how to use ID. to align arbitrary text at the same level as a TreeNode() you can use Bullet(). + IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...) IM_FMTARGS(2); // " + IMGUI_API bool TreeNodeV(const char* str_id, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API bool TreeNodeV(const void* ptr_id, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API bool TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags = 0); + IMGUI_API bool TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); + IMGUI_API bool TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); + IMGUI_API bool TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); + IMGUI_API bool TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); + IMGUI_API void TreePush(const char* str_id); // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call TreePush/TreePop yourself if desired. + IMGUI_API void TreePush(const void* ptr_id = NULL); // " + IMGUI_API void TreePop(); // ~ Unindent()+PopId() + IMGUI_API void TreeAdvanceToLabelPos(); // advance cursor x position by GetTreeNodeToLabelSpacing() + IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode + IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state. + IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). + IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header + + // Widgets: Selectables + // - A selectable highlights when hovered, and can display another color when selected. + // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. + IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height + IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. + + // Widgets: List Boxes + // - FIXME: To be consistent with all the newer API, ListBoxHeader/ListBoxFooter should in reality be called BeginListBox/EndListBox. Will rename them. + IMGUI_API bool ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1); + IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); + IMGUI_API bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0,0)); // use if you want to reimplement ListBox() will custom data or interactions. if the function return true, you can output elements then call ListBoxFooter() afterwards. + IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // " + IMGUI_API void ListBoxFooter(); // terminate the scrolling region. only call ListBoxFooter() if ListBoxHeader() returned true! + + // Widgets: Data Plotting + IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); + IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); + IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); + IMGUI_API void PlotHistogram(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); + + // Widgets: Value() Helpers. + // - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) + IMGUI_API void Value(const char* prefix, bool b); + IMGUI_API void Value(const char* prefix, int v); + IMGUI_API void Value(const char* prefix, unsigned int v); + IMGUI_API void Value(const char* prefix, float v, const char* float_format = NULL); + + // Widgets: Menus + IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. + IMGUI_API void EndMainMenuBar(); // only call EndMainMenuBar() if BeginMainMenuBar() returns true! + IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window). + IMGUI_API void EndMenuBar(); // only call EndMenuBar() if BeginMenuBar() returns true! + IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true! + IMGUI_API void EndMenu(); // only call EndMenu() if BeginMenu() returns true! + IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui at the moment + IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL + + // Tooltips + IMGUI_API void BeginTooltip(); // begin/append a tooltip window. to create full-featured tooltip (with any kind of items). + IMGUI_API void EndTooltip(); + IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip, typically use with ImGui::IsItemHovered(). override any previous call to SetTooltip(). + IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); + + // Popups, Modals + // The properties of popups windows are: + // - They block normal mouse hovering detection outside them. (*) + // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. + // - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls. + // User can manipulate the visibility state by calling OpenPopup(). + // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup. + // Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time. + IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). + IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returns true! + IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! + IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, int mouse_button = 1, bool also_over_items = true); // helper to open and begin popup when clicked on current window. + IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked in void (where there are no imgui windows). + IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // modal dialog (regular window with title bar, block interactions behind the modal window, can't close the modal window by clicking outside) + IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true! + IMGUI_API bool OpenPopupOnItemClick(const char* str_id = NULL, int mouse_button = 1); // helper to open popup when clicked on last item (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors). return true when just opened. + IMGUI_API bool IsPopupOpen(const char* str_id); // return true if the popup is open at the current begin-ed level of the popup stack. + IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. + + // Columns + // - You can also use SameLine(pos_x) to mimic simplified columns. + // - The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!) + IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); + IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished + IMGUI_API int GetColumnIndex(); // get current column index + IMGUI_API float GetColumnWidth(int column_index = -1); // get column width (in pixels). pass -1 to use current column + IMGUI_API void SetColumnWidth(int column_index, float width); // set column width (in pixels). pass -1 to use current column + IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetColumnsCount() inclusive. column 0 is typically 0.0f + IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column + IMGUI_API int GetColumnsCount(); + + // Tab Bars, Tabs + // [BETA API] API may evolve! + IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar + IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true! + IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0);// create a Tab. Returns true if the Tab is selected. + IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true! + IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name. + + // Logging/Capture + // - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are automatically opened during logging. + IMGUI_API void LogToTTY(int auto_open_depth = -1); // start logging to tty (stdout) + IMGUI_API void LogToFile(int auto_open_depth = -1, const char* filename = NULL); // start logging to file + IMGUI_API void LogToClipboard(int auto_open_depth = -1); // start logging to OS clipboard + IMGUI_API void LogFinish(); // stop logging (close file, etc.) + IMGUI_API void LogButtons(); // helper to display buttons for logging to tty/file/clipboard + IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed) + + // Drag and Drop + // [BETA API] API may evolve! + IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource() + IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0); // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. + IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true! + IMGUI_API bool BeginDragDropTarget(); // call after submitting an item that may receive a payload. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget() + IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. + IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true! + IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type. + + // Clipping + IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect); + IMGUI_API void PopClipRect(); + + // Focus, Activation + // - Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item" + IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. + IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. + + // Item/Widgets Utilities + // - Most of the functions are referring to the last/previous item we submitted. + // - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions. + IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options. + IMGUI_API bool IsItemActive(); // is the last item active? (e.g. button being held, text field being edited. This will continuously return true while holding mouse button on an item. Items that don't interact will always return false) + IMGUI_API bool IsItemFocused(); // is the last item focused for keyboard/gamepad navigation? + IMGUI_API bool IsItemClicked(int mouse_button = 0); // is the last item clicked? (e.g. button/node just clicked on) == IsMouseClicked(mouse_button) && IsItemHovered() + IMGUI_API bool IsItemVisible(); // is the last item visible? (items may be out of sight because of clipping/scrolling) + IMGUI_API bool IsItemEdited(); // did the last item modify its underlying value this frame? or was pressed? This is generally the same as the "bool" return value of many widgets. + IMGUI_API bool IsItemActivated(); // was the last item just made active (item was previously inactive). + IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that requires continuous editing. + IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that requires continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item). + IMGUI_API bool IsAnyItemHovered(); // is any item hovered? + IMGUI_API bool IsAnyItemActive(); // is any item active? + IMGUI_API bool IsAnyItemFocused(); // is any item focused? + IMGUI_API ImVec2 GetItemRectMin(); // get upper-left bounding rectangle of the last item (screen space) + IMGUI_API ImVec2 GetItemRectMax(); // get lower-right bounding rectangle of the last item (screen space) + IMGUI_API ImVec2 GetItemRectSize(); // get size of last item + IMGUI_API void SetItemAllowOverlap(); // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area. + + // Miscellaneous Utilities + IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. + IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side. + IMGUI_API double GetTime(); // get global imgui time. incremented by io.DeltaTime every frame. + IMGUI_API int GetFrameCount(); // get global imgui frame count. incremented by 1 every frame. + IMGUI_API ImDrawList* GetBackgroundDrawList(); // this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. + IMGUI_API ImDrawList* GetForegroundDrawList(); // this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. + IMGUI_API ImDrawListSharedData* GetDrawListSharedData(); // you may use this when creating your own ImDrawList instances. + IMGUI_API const char* GetStyleColorName(ImGuiCol idx); // get a string corresponding to the enum value (for display, saving, etc.). + IMGUI_API void SetStateStorage(ImGuiStorage* storage); // replace current window storage with our own (if you want to manipulate it yourself, typically clear subsection of it) + IMGUI_API ImGuiStorage* GetStateStorage(); + IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); + IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // calculate coarse clipping for large list of evenly sized items. Prefer using the ImGuiListClipper higher-level helper if you can. + IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0); // helper to create a child window / scrolling region that looks like a normal widget frame + IMGUI_API void EndChildFrame(); // always call EndChildFrame() regardless of BeginChildFrame() return values (which indicates a collapsed/clipped window) + + // Color Utilities + IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in); + IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4& in); + IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v); + IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); + + // Inputs Utilities + IMGUI_API int GetKeyIndex(ImGuiKey imgui_key); // map ImGuiKey_* values into user's key index. == io.KeyMap[key] + IMGUI_API bool IsKeyDown(int user_key_index); // is key being held. == io.KeysDown[user_key_index]. note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your backend/engine stored them into io.KeysDown[]! + IMGUI_API bool IsKeyPressed(int user_key_index, bool repeat = true); // was key pressed (went from !Down to Down). if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate + IMGUI_API bool IsKeyReleased(int user_key_index); // was key released (went from Down to !Down).. + IMGUI_API int GetKeyPressedAmount(int key_index, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate + IMGUI_API bool IsMouseDown(int button); // is mouse button held (0=left, 1=right, 2=middle) + IMGUI_API bool IsAnyMouseDown(); // is any mouse button held + IMGUI_API bool IsMouseClicked(int button, bool repeat = false); // did mouse button clicked (went from !Down to Down) (0=left, 1=right, 2=middle) + IMGUI_API bool IsMouseDoubleClicked(int button); // did mouse button double-clicked. a double-click returns false in IsMouseClicked(). uses io.MouseDoubleClickTime. + IMGUI_API bool IsMouseReleased(int button); // did mouse button released (went from Down to !Down) + IMGUI_API bool IsMouseDragging(int button = 0, float lock_threshold = -1.0f); // is mouse dragging. if lock_threshold < -1.0f uses io.MouseDraggingThreshold + IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true); // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. + IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse + IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls + IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve backup of mouse position at the time of opening popup we have BeginPopup() into + IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // return the delta from the initial clicking position. This is locked and return 0.0f until the mouse moves past a distance threshold at least once. If lock_threshold < -1.0f uses io.MouseDraggingThreshold + IMGUI_API void ResetMouseDragDelta(int button = 0); // + IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you + IMGUI_API void SetMouseCursor(ImGuiMouseCursor type); // set desired cursor type + IMGUI_API void CaptureKeyboardFromApp(bool want_capture_keyboard_value = true); // attention: misleading name! manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard_value"; after the next NewFrame() call. + IMGUI_API void CaptureMouseFromApp(bool want_capture_mouse_value = true); // attention: misleading name! manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse_value;" after the next NewFrame() call. + + // Clipboard Utilities (also see the LogToClipboard() function to capture or output text data to the clipboard) + IMGUI_API const char* GetClipboardText(); + IMGUI_API void SetClipboardText(const char* text); + + // Settings/.Ini Utilities + // - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini"). + // - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually. + IMGUI_API void LoadIniSettingsFromDisk(const char* ini_filename); // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename). + IMGUI_API void LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size=0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source. + IMGUI_API void SaveIniSettingsToDisk(const char* ini_filename); // this is automatically called (if io.IniFilename is not empty) a few seconds after any modification that should be reflected in the .ini file (and also by DestroyContext). + IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings. + + // Memory Allocators + // - All those functions are not reliant on the current context. + // - If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again because we use global storage for those. + IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL); + IMGUI_API void* MemAlloc(size_t size); + IMGUI_API void MemFree(void* ptr); + +} // namespace ImGui + +//----------------------------------------------------------------------------- +// Flags & Enumerations +//----------------------------------------------------------------------------- + +// Flags for ImGui::Begin() +enum ImGuiWindowFlags_ +{ + ImGuiWindowFlags_None = 0, + ImGuiWindowFlags_NoTitleBar = 1 << 0, // Disable title-bar + ImGuiWindowFlags_NoResize = 1 << 1, // Disable user resizing with the lower-right grip + ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window + ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scrollbars (window can still scroll with mouse or programmatically) + ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set. + ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it + ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame + ImGuiWindowFlags_NoBackground = 1 << 7, // Disable drawing background color (WindowBg, etc.) and outside border. Similar as using SetNextWindowBgAlpha(0.0f). + ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file + ImGuiWindowFlags_NoMouseInputs = 1 << 9, // Disable catching mouse, hovering test with pass through. + ImGuiWindowFlags_MenuBar = 1 << 10, // Has a menu-bar + ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, // Allow horizontal scrollbar to appear (off by default). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section. + ImGuiWindowFlags_NoFocusOnAppearing = 1 << 12, // Disable taking focus when transitioning from hidden to visible state + ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus) + ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) + ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) + ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient) + ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window + ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) + ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. When used in a tab/docking context, tab is selected on closure and closure is deferred by one frame to allow code to cancel the closure (with a confirmation popup, etc.) without flicker. + ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, + ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + + // [Internal] + ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!) + ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild() + ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip() + ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() + ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal() + ImGuiWindowFlags_ChildMenu = 1 << 28 // Don't use! For internal use by BeginMenu() + + // [Obsolete] + //ImGuiWindowFlags_ShowBorders = 1 << 7, // --> Set style.FrameBorderSize=1.0f / style.WindowBorderSize=1.0f to enable borders around windows and items + //ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // --> Set io.ConfigWindowsResizeFromEdges and make sure mouse cursors are supported by back-end (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) +}; + +// Flags for ImGui::InputText() +enum ImGuiInputTextFlags_ +{ + ImGuiInputTextFlags_None = 0, + ImGuiInputTextFlags_CharsDecimal = 1 << 0, // Allow 0123456789.+-*/ + ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, // Allow 0123456789ABCDEFabcdef + ImGuiInputTextFlags_CharsUppercase = 1 << 2, // Turn a..z into A..Z + ImGuiInputTextFlags_CharsNoBlank = 1 << 3, // Filter out spaces, tabs + ImGuiInputTextFlags_AutoSelectAll = 1 << 4, // Select entire text when first taking mouse focus + ImGuiInputTextFlags_EnterReturnsTrue = 1 << 5, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider looking at the IsItemDeactivatedAfterEdit() function. + ImGuiInputTextFlags_CallbackCompletion = 1 << 6, // Callback on pressing TAB (for completion handling) + ImGuiInputTextFlags_CallbackHistory = 1 << 7, // Callback on pressing Up/Down arrows (for history handling) + ImGuiInputTextFlags_CallbackAlways = 1 << 8, // Callback on each iteration. User code may query cursor position, modify text buffer. + ImGuiInputTextFlags_CallbackCharFilter = 1 << 9, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. + ImGuiInputTextFlags_AllowTabInput = 1 << 10, // Pressing TAB input a '\t' character into the text field + ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter (default is opposite: unfocus with Ctrl+Enter, add line with Enter). + ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, // Disable following the cursor horizontally + ImGuiInputTextFlags_AlwaysInsertMode = 1 << 13, // Insert mode + ImGuiInputTextFlags_ReadOnly = 1 << 14, // Read-only mode + ImGuiInputTextFlags_Password = 1 << 15, // Password mode, display all characters as '*' + ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). + ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input) + ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) + // [Internal] + ImGuiInputTextFlags_Multiline = 1 << 20 // For internal use by InputTextMultiline() +}; + +// Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*() +enum ImGuiTreeNodeFlags_ +{ + ImGuiTreeNodeFlags_None = 0, + ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected + ImGuiTreeNodeFlags_Framed = 1 << 1, // Full colored frame (e.g. for CollapsingHeader) + ImGuiTreeNodeFlags_AllowItemOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one + ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack + ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) + ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open + ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node + ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. + ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). + ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow + ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding(). + //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 11, // FIXME: TODO: Extend hit box horizontally even if not framed + //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 12, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible + ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) + ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiTreeNodeFlags_AllowOverlapMode = ImGuiTreeNodeFlags_AllowItemOverlap +#endif +}; + +// Flags for ImGui::Selectable() +enum ImGuiSelectableFlags_ +{ + ImGuiSelectableFlags_None = 0, + ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this don't close parent popup window + ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column) + ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too + ImGuiSelectableFlags_Disabled = 1 << 3 // Cannot be selected, display greyed out text +}; + +// Flags for ImGui::BeginCombo() +enum ImGuiComboFlags_ +{ + ImGuiComboFlags_None = 0, + ImGuiComboFlags_PopupAlignLeft = 1 << 0, // Align the popup toward the left by default + ImGuiComboFlags_HeightSmall = 1 << 1, // Max ~4 items visible. Tip: If you want your combo popup to be a specific size you can use SetNextWindowSizeConstraints() prior to calling BeginCombo() + ImGuiComboFlags_HeightRegular = 1 << 2, // Max ~8 items visible (default) + ImGuiComboFlags_HeightLarge = 1 << 3, // Max ~20 items visible + ImGuiComboFlags_HeightLargest = 1 << 4, // As many fitting items as possible + ImGuiComboFlags_NoArrowButton = 1 << 5, // Display on the preview box without the square arrow button + ImGuiComboFlags_NoPreview = 1 << 6, // Display only a square arrow button + ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest +}; + +// Flags for ImGui::BeginTabBar() +enum ImGuiTabBarFlags_ +{ + ImGuiTabBarFlags_None = 0, + ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list + ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear + ImGuiTabBarFlags_TabListPopupButton = 1 << 2, + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. + ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, + ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab + ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit + ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit + ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, + ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown +}; + +// Flags for ImGui::BeginTabItem() +enum ImGuiTabItemFlags_ +{ + ImGuiTabItemFlags_None = 0, + ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. Also: tab is selected on closure and closure is deferred by one frame to allow code to undo it without flicker. + ImGuiTabItemFlags_SetSelected = 1 << 1, // Trigger flag to programmatically make the tab selected when calling BeginTabItem() + ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. + ImGuiTabItemFlags_NoPushId = 1 << 3 // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem() +}; + +// Flags for ImGui::IsWindowFocused() +enum ImGuiFocusedFlags_ +{ + ImGuiFocusedFlags_None = 0, + ImGuiFocusedFlags_ChildWindows = 1 << 0, // IsWindowFocused(): Return true if any children of the window is focused + ImGuiFocusedFlags_RootWindow = 1 << 1, // IsWindowFocused(): Test from root window (top most parent of the current hierarchy) + ImGuiFocusedFlags_AnyWindow = 1 << 2, // IsWindowFocused(): Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use ImGui::GetIO().WantCaptureMouse instead. + ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows +}; + +// Flags for ImGui::IsItemHovered(), ImGui::IsWindowHovered() +// Note: if you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that. Please read the FAQ! +// Note: windows with the ImGuiWindowFlags_NoInputs flag are ignored by IsWindowHovered() calls. +enum ImGuiHoveredFlags_ +{ + ImGuiHoveredFlags_None = 0, // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them. + ImGuiHoveredFlags_ChildWindows = 1 << 0, // IsWindowHovered() only: Return true if any children of the window is hovered + ImGuiHoveredFlags_RootWindow = 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy) + ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered + ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 3, // Return true even if a popup window is normally blocking access to this item/window + //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 4, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 5, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. + ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 6, // Return true even if the position is overlapped by another window + ImGuiHoveredFlags_AllowWhenDisabled = 1 << 7, // Return true even if the item is disabled + ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, + ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows +}; + +// Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() +enum ImGuiDragDropFlags_ +{ + ImGuiDragDropFlags_None = 0, + // BeginDragDropSource() flags + ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, // By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disable this behavior. + ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return false, to avoid subsequent user code submitting tooltips. This flag disable this behavior so you can still call IsItemHovered() on the source item. + ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item. + ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit. + ImGuiDragDropFlags_SourceExtern = 1 << 4, // External source (from outside of imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously. + ImGuiDragDropFlags_SourceAutoExpirePayload = 1 << 5, // Automatically expire the payload if the source cease to be submitted (otherwise payloads are persisting while being dragged) + // AcceptDragDropPayload() flags + ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. + ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. + ImGuiDragDropFlags_AcceptNoPreviewTooltip = 1 << 12, // Request hiding the BeginDragDropSource tooltip from the BeginDragDropTarget site. + ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect // For peeking ahead and inspecting the payload before delivery. +}; + +// Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui. +#define IMGUI_PAYLOAD_TYPE_COLOR_3F "_COL3F" // float[3]: Standard type for colors, without alpha. User code may use this type. +#define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" // float[4]: Standard type for colors. User code may use this type. + +// A primary data type +enum ImGuiDataType_ +{ + ImGuiDataType_S8, // char + ImGuiDataType_U8, // unsigned char + ImGuiDataType_S16, // short + ImGuiDataType_U16, // unsigned short + ImGuiDataType_S32, // int + ImGuiDataType_U32, // unsigned int + ImGuiDataType_S64, // long long / __int64 + ImGuiDataType_U64, // unsigned long long / unsigned __int64 + ImGuiDataType_Float, // float + ImGuiDataType_Double, // double + ImGuiDataType_COUNT +}; + +// A cardinal direction +enum ImGuiDir_ +{ + ImGuiDir_None = -1, + ImGuiDir_Left = 0, + ImGuiDir_Right = 1, + ImGuiDir_Up = 2, + ImGuiDir_Down = 3, + ImGuiDir_COUNT +}; + +// User fill ImGuiIO.KeyMap[] array with indices into the ImGuiIO.KeysDown[512] array +enum ImGuiKey_ +{ + ImGuiKey_Tab, + ImGuiKey_LeftArrow, + ImGuiKey_RightArrow, + ImGuiKey_UpArrow, + ImGuiKey_DownArrow, + ImGuiKey_PageUp, + ImGuiKey_PageDown, + ImGuiKey_Home, + ImGuiKey_End, + ImGuiKey_Insert, + ImGuiKey_Delete, + ImGuiKey_Backspace, + ImGuiKey_Space, + ImGuiKey_Enter, + ImGuiKey_Escape, + ImGuiKey_A, // for text edit CTRL+A: select all + ImGuiKey_C, // for text edit CTRL+C: copy + ImGuiKey_V, // for text edit CTRL+V: paste + ImGuiKey_X, // for text edit CTRL+X: cut + ImGuiKey_Y, // for text edit CTRL+Y: redo + ImGuiKey_Z, // for text edit CTRL+Z: undo + ImGuiKey_COUNT +}; + +// Gamepad/Keyboard directional navigation +// Keyboard: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. +// Gamepad: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. Back-end: set ImGuiBackendFlags_HasGamepad and fill the io.NavInputs[] fields before calling NewFrame(). Note that io.NavInputs[] is cleared by EndFrame(). +// Read instructions in imgui.cpp for more details. Download PNG/PSD at http://goo.gl/9LgVZW. +enum ImGuiNavInput_ +{ + // Gamepad Mapping + ImGuiNavInput_Activate, // activate / open / toggle / tweak value // e.g. Cross (PS4), A (Xbox), A (Switch), Space (Keyboard) + ImGuiNavInput_Cancel, // cancel / close / exit // e.g. Circle (PS4), B (Xbox), B (Switch), Escape (Keyboard) + ImGuiNavInput_Input, // text input / on-screen keyboard // e.g. Triang.(PS4), Y (Xbox), X (Switch), Return (Keyboard) + ImGuiNavInput_Menu, // tap: toggle menu / hold: focus, move, resize // e.g. Square (PS4), X (Xbox), Y (Switch), Alt (Keyboard) + ImGuiNavInput_DpadLeft, // move / tweak / resize window (w/ PadMenu) // e.g. D-pad Left/Right/Up/Down (Gamepads), Arrow keys (Keyboard) + ImGuiNavInput_DpadRight, // + ImGuiNavInput_DpadUp, // + ImGuiNavInput_DpadDown, // + ImGuiNavInput_LStickLeft, // scroll / move window (w/ PadMenu) // e.g. Left Analog Stick Left/Right/Up/Down + ImGuiNavInput_LStickRight, // + ImGuiNavInput_LStickUp, // + ImGuiNavInput_LStickDown, // + ImGuiNavInput_FocusPrev, // next window (w/ PadMenu) // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) + ImGuiNavInput_FocusNext, // prev window (w/ PadMenu) // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) + ImGuiNavInput_TweakSlow, // slower tweaks // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) + ImGuiNavInput_TweakFast, // faster tweaks // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) + + // [Internal] Don't use directly! This is used internally to differentiate keyboard from gamepad inputs for behaviors that require to differentiate them. + // Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from io.KeysDown[] instead of io.NavInputs[]. + ImGuiNavInput_KeyMenu_, // toggle menu // = io.KeyAlt + ImGuiNavInput_KeyTab_, // tab // = Tab key + ImGuiNavInput_KeyLeft_, // move left // = Arrow keys + ImGuiNavInput_KeyRight_, // move right + ImGuiNavInput_KeyUp_, // move up + ImGuiNavInput_KeyDown_, // move down + ImGuiNavInput_COUNT, + ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyMenu_ +}; + +// Configuration flags stored in io.ConfigFlags. Set by user/application. +enum ImGuiConfigFlags_ +{ + ImGuiConfigFlags_None = 0, + ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.KeysDown[]. + ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. This is mostly to instruct your imgui back-end to fill io.NavInputs[]. Back-end also needs to set ImGuiBackendFlags_HasGamepad. + ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your binding, otherwise ImGui will react as if the mouse is jumping around back and forth. + ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set. + ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the back-end. + ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct back-end to not alter mouse cursor shape and visibility. Use if the back-end cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead. + + // User storage (to allow your back-end/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core ImGui) + ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware. + ImGuiConfigFlags_IsTouchScreen = 1 << 21 // Application is using a touch screen instead of a mouse. +}; + +// Back-end capabilities flags stored in io.BackendFlags. Set by imgui_impl_xxx or custom back-end. +enum ImGuiBackendFlags_ +{ + ImGuiBackendFlags_None = 0, + ImGuiBackendFlags_HasGamepad = 1 << 0, // Back-end supports gamepad and currently has one connected. + ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Back-end supports honoring GetMouseCursor() value to change the OS cursor shape. + ImGuiBackendFlags_HasSetMousePos = 1 << 2 // Back-end supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set). +}; + +// Enumeration for PushStyleColor() / PopStyleColor() +enum ImGuiCol_ +{ + ImGuiCol_Text, + ImGuiCol_TextDisabled, + ImGuiCol_WindowBg, // Background of normal windows + ImGuiCol_ChildBg, // Background of child windows + ImGuiCol_PopupBg, // Background of popups, menus, tooltips windows + ImGuiCol_Border, + ImGuiCol_BorderShadow, + ImGuiCol_FrameBg, // Background of checkbox, radio button, plot, slider, text input + ImGuiCol_FrameBgHovered, + ImGuiCol_FrameBgActive, + ImGuiCol_TitleBg, + ImGuiCol_TitleBgActive, + ImGuiCol_TitleBgCollapsed, + ImGuiCol_MenuBarBg, + ImGuiCol_ScrollbarBg, + ImGuiCol_ScrollbarGrab, + ImGuiCol_ScrollbarGrabHovered, + ImGuiCol_ScrollbarGrabActive, + ImGuiCol_CheckMark, + ImGuiCol_SliderGrab, + ImGuiCol_SliderGrabActive, + ImGuiCol_Button, + ImGuiCol_ButtonHovered, + ImGuiCol_ButtonActive, + ImGuiCol_Header, + ImGuiCol_HeaderHovered, + ImGuiCol_HeaderActive, + ImGuiCol_Separator, + ImGuiCol_SeparatorHovered, + ImGuiCol_SeparatorActive, + ImGuiCol_ResizeGrip, + ImGuiCol_ResizeGripHovered, + ImGuiCol_ResizeGripActive, + ImGuiCol_Tab, + ImGuiCol_TabHovered, + ImGuiCol_TabActive, + ImGuiCol_TabUnfocused, + ImGuiCol_TabUnfocusedActive, + ImGuiCol_PlotLines, + ImGuiCol_PlotLinesHovered, + ImGuiCol_PlotHistogram, + ImGuiCol_PlotHistogramHovered, + ImGuiCol_TextSelectedBg, + ImGuiCol_DragDropTarget, + ImGuiCol_NavHighlight, // Gamepad/keyboard: current highlighted item + ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB + ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active + ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active + ImGuiCol_COUNT + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiCol_ModalWindowDarkening = ImGuiCol_ModalWindowDimBg // [renamed in 1.63] + , ImGuiCol_ChildWindowBg = ImGuiCol_ChildBg // [renamed in 1.53] + , ImGuiCol_Column = ImGuiCol_Separator, ImGuiCol_ColumnHovered = ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive = ImGuiCol_SeparatorActive // [renamed in 1.51] + //ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered, // [unused since 1.60+] the close button now uses regular button colors. + //ImGuiCol_ComboBg, // [unused since 1.53+] ComboBg has been merged with PopupBg, so a redirect isn't accurate. +#endif +}; + +// Enumeration for PushStyleVar() / PopStyleVar() to temporarily modify the ImGuiStyle structure. +// NB: the enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code. During initialization, feel free to just poke into ImGuiStyle directly. +// NB: if changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type. +enum ImGuiStyleVar_ +{ + // Enum name --------------------- // Member in ImGuiStyle structure (see ImGuiStyle for descriptions) + ImGuiStyleVar_Alpha, // float Alpha + ImGuiStyleVar_WindowPadding, // ImVec2 WindowPadding + ImGuiStyleVar_WindowRounding, // float WindowRounding + ImGuiStyleVar_WindowBorderSize, // float WindowBorderSize + ImGuiStyleVar_WindowMinSize, // ImVec2 WindowMinSize + ImGuiStyleVar_WindowTitleAlign, // ImVec2 WindowTitleAlign + ImGuiStyleVar_ChildRounding, // float ChildRounding + ImGuiStyleVar_ChildBorderSize, // float ChildBorderSize + ImGuiStyleVar_PopupRounding, // float PopupRounding + ImGuiStyleVar_PopupBorderSize, // float PopupBorderSize + ImGuiStyleVar_FramePadding, // ImVec2 FramePadding + ImGuiStyleVar_FrameRounding, // float FrameRounding + ImGuiStyleVar_FrameBorderSize, // float FrameBorderSize + ImGuiStyleVar_ItemSpacing, // ImVec2 ItemSpacing + ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ItemInnerSpacing + ImGuiStyleVar_IndentSpacing, // float IndentSpacing + ImGuiStyleVar_ScrollbarSize, // float ScrollbarSize + ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding + ImGuiStyleVar_GrabMinSize, // float GrabMinSize + ImGuiStyleVar_GrabRounding, // float GrabRounding + ImGuiStyleVar_TabRounding, // float TabRounding + ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign + ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign + ImGuiStyleVar_COUNT + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiStyleVar_Count_ = ImGuiStyleVar_COUNT, ImGuiStyleVar_ChildWindowRounding = ImGuiStyleVar_ChildRounding +#endif +}; + +// Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton() +enum ImGuiColorEditFlags_ +{ + ImGuiColorEditFlags_None = 0, + ImGuiColorEditFlags_NoAlpha = 1 << 1, // // ColorEdit, ColorPicker, ColorButton: ignore Alpha component (will only read 3 components from the input pointer). + ImGuiColorEditFlags_NoPicker = 1 << 2, // // ColorEdit: disable picker when clicking on colored square. + ImGuiColorEditFlags_NoOptions = 1 << 3, // // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview. + ImGuiColorEditFlags_NoSmallPreview = 1 << 4, // // ColorEdit, ColorPicker: disable colored square preview next to the inputs. (e.g. to show only the inputs) + ImGuiColorEditFlags_NoInputs = 1 << 5, // // ColorEdit, ColorPicker: disable inputs sliders/text widgets (e.g. to show only the small preview colored square). + ImGuiColorEditFlags_NoTooltip = 1 << 6, // // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview. + ImGuiColorEditFlags_NoLabel = 1 << 7, // // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker). + ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small colored square preview instead. + ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source. + + // User Options (right-click on widget to change some of them). + ImGuiColorEditFlags_AlphaBar = 1 << 16, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker. + ImGuiColorEditFlags_AlphaPreview = 1 << 17, // // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque. + ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 18, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque. + ImGuiColorEditFlags_HDR = 1 << 19, // // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you probably want to use ImGuiColorEditFlags_Float flag as well). + ImGuiColorEditFlags_DisplayRGB = 1 << 20, // [Display] // ColorEdit: override _display_ type among RGB/HSV/Hex. ColorPicker: select any combination using one or more of RGB/HSV/Hex. + ImGuiColorEditFlags_DisplayHSV = 1 << 21, // [Display] // " + ImGuiColorEditFlags_DisplayHex = 1 << 22, // [Display] // " + ImGuiColorEditFlags_Uint8 = 1 << 23, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0..255. + ImGuiColorEditFlags_Float = 1 << 24, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats instead of 0..255 integers. No round-trip of value via integers. + ImGuiColorEditFlags_PickerHueBar = 1 << 25, // [Picker] // ColorPicker: bar for Hue, rectangle for Sat/Value. + ImGuiColorEditFlags_PickerHueWheel = 1 << 26, // [Picker] // ColorPicker: wheel for Hue, triangle for Sat/Value. + ImGuiColorEditFlags_InputRGB = 1 << 27, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. + ImGuiColorEditFlags_InputHSV = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. + + // Defaults Options. You can set application defaults using SetColorEditOptions(). The intent is that you probably don't want to + // override them in most of your calls. Let the user choose via the option menu and/or call SetColorEditOptions() once during startup. + ImGuiColorEditFlags__OptionsDefault = ImGuiColorEditFlags_Uint8|ImGuiColorEditFlags_DisplayRGB|ImGuiColorEditFlags_InputRGB|ImGuiColorEditFlags_PickerHueBar, + + // [Internal] Masks + ImGuiColorEditFlags__DisplayMask = ImGuiColorEditFlags_DisplayRGB|ImGuiColorEditFlags_DisplayHSV|ImGuiColorEditFlags_DisplayHex, + ImGuiColorEditFlags__DataTypeMask = ImGuiColorEditFlags_Uint8|ImGuiColorEditFlags_Float, + ImGuiColorEditFlags__PickerMask = ImGuiColorEditFlags_PickerHueWheel|ImGuiColorEditFlags_PickerHueBar, + ImGuiColorEditFlags__InputMask = ImGuiColorEditFlags_InputRGB|ImGuiColorEditFlags_InputHSV + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex +#endif +}; + +// Enumeration for GetMouseCursor() +// User code may request binding to display given cursor by calling SetMouseCursor(), which is why we have some cursors that are marked unused here +enum ImGuiMouseCursor_ +{ + ImGuiMouseCursor_None = -1, + ImGuiMouseCursor_Arrow = 0, + ImGuiMouseCursor_TextInput, // When hovering over InputText, etc. + ImGuiMouseCursor_ResizeAll, // (Unused by imgui functions) + ImGuiMouseCursor_ResizeNS, // When hovering over an horizontal border + ImGuiMouseCursor_ResizeEW, // When hovering over a vertical border or a column + ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window + ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window + ImGuiMouseCursor_Hand, // (Unused by imgui functions. Use for e.g. hyperlinks) + ImGuiMouseCursor_COUNT + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiMouseCursor_Count_ = ImGuiMouseCursor_COUNT +#endif +}; + +// Enumateration for ImGui::SetWindow***(), SetNextWindow***(), SetNextTreeNode***() functions +// Represent a condition. +// Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always. +enum ImGuiCond_ +{ + ImGuiCond_Always = 1 << 0, // Set the variable + ImGuiCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call with succeed) + ImGuiCond_FirstUseEver = 1 << 2, // Set the variable if the object/window has no persistently saved data (no entry in .ini file) + ImGuiCond_Appearing = 1 << 3 // Set the variable if the object/window is appearing after being hidden/inactive (or the first time) + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiSetCond_Always = ImGuiCond_Always, ImGuiSetCond_Once = ImGuiCond_Once, ImGuiSetCond_FirstUseEver = ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing = ImGuiCond_Appearing +#endif +}; + +//----------------------------------------------------------------------------- +// Helper: ImVector<> +// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). +// You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it. +// Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. +// Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, +// do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. +//----------------------------------------------------------------------------- + +template +struct ImVector +{ + int Size; + int Capacity; + T* Data; + + // Provide standard typedefs but we don't use them ourselves. + typedef T value_type; + typedef value_type* iterator; + typedef const value_type* const_iterator; + + // Constructors, destructor + inline ImVector() { Size = Capacity = 0; Data = NULL; } + inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } + inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } + inline ~ImVector() { if (Data) ImGui::MemFree(Data); } + + inline bool empty() const { return Size == 0; } + inline int size() const { return Size; } + inline int size_in_bytes() const { return Size * (int)sizeof(T); } + inline int capacity() const { return Capacity; } + inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; } + inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; } + + inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } } + inline T* begin() { return Data; } + inline const T* begin() const { return Data; } + inline T* end() { return Data + Size; } + inline const T* end() const { return Data + Size; } + inline T& front() { IM_ASSERT(Size > 0); return Data[0]; } + inline const T& front() const { IM_ASSERT(Size > 0); return Data[0]; } + inline T& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline const T& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; T* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } + + inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; } + inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } + inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } + inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); ImGui::MemFree(Data); } Data = new_data; Capacity = new_capacity; } + + // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. + inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } + inline void pop_back() { IM_ASSERT(Size > 0); Size--; } + inline void push_front(const T& v) { if (Size == 0) push_back(v); else insert(Data, v); } + inline T* erase(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; } + inline T* erase(const T* it, const T* it_last){ IM_ASSERT(it >= Data && it < Data+Size && it_last > it && it_last <= Data+Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(T)); Size -= (int)count; return Data + off; } + inline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; } + inline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } + inline bool contains(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } + inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; return (int)off; } +}; + +//----------------------------------------------------------------------------- +// ImGuiStyle +// You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame(). +// During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values, +// and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors. +//----------------------------------------------------------------------------- + +struct ImGuiStyle +{ + float Alpha; // Global alpha applies to everything in ImGui. + ImVec2 WindowPadding; // Padding within a window. + float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. + float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constraint individual windows, use SetNextWindowSizeConstraints(). + ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. + float ChildRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows. + float ChildBorderSize; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + float PopupRounding; // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding) + float PopupBorderSize; // Thickness of border around popup/tooltip windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + ImVec2 FramePadding; // Padding within a framed rectangle (used by most widgets). + float FrameRounding; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets). + float FrameBorderSize; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines. + ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). + ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! + float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). + float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. + float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar. + float ScrollbarRounding; // Radius of grab corners for scrollbar. + float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. + float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + float TabBorderSize; // Thickness of border around tabs. + ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). + ImVec2 SelectableTextAlign; // Alignment of selectable text when selectable is larger than text. Defaults to (0.0f, 0.0f) (top-left aligned). + ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows. + ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! + float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. + bool AntiAliasedLines; // Enable anti-aliasing on lines/borders. Disable if you are really tight on CPU/GPU. + bool AntiAliasedFill; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.) + float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. + ImVec4 Colors[ImGuiCol_COUNT]; + + IMGUI_API ImGuiStyle(); + IMGUI_API void ScaleAllSizes(float scale_factor); +}; + +//----------------------------------------------------------------------------- +// ImGuiIO +// Communicate most settings and inputs/outputs to Dear ImGui using this structure. +// Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage. +//----------------------------------------------------------------------------- + +struct ImGuiIO +{ + //------------------------------------------------------------------ + // Configuration (fill once) // Default value + //------------------------------------------------------------------ + + ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc. + ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by back-end (imgui_impl_xxx files or custom back-end) to communicate features supported by the back-end. + ImVec2 DisplaySize; // // Main display size, in pixels. + float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. + float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds. + const char* IniFilename; // = "imgui.ini" // Path to .ini file. Set NULL to disable automatic .ini loading/saving, if e.g. you want to manually load/save from memory. + const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified). + float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. + float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. + float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. + int KeyMap[ImGuiKey_COUNT]; // // Map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. + float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). + float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. + void* UserData; // = NULL // Store your own data for retrieval by callbacks. + + ImFontAtlas*Fonts; // // Load, rasterize and pack one or more fonts into a single texture. + float FontGlobalScale; // = 1.0f // Global scale all fonts + bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. + ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. + ImVec2 DisplayFramebufferScale; // = (1, 1) // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale. + + // Miscellaneous options + bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations. + bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63) + bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63) + bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) + bool ConfigWindowsMoveFromTitleBarOnly; // = false // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected. + + //------------------------------------------------------------------ + // Platform Functions + // (the imgui_impl_xxxx back-end files are setting those up for you) + //------------------------------------------------------------------ + + // Optional: Platform/Renderer back-end name (informational only! will be displayed in About Window) + User data for back-end/wrappers to store their own stuff. + const char* BackendPlatformName; // = NULL + const char* BackendRendererName; // = NULL + void* BackendPlatformUserData; // = NULL + void* BackendRendererUserData; // = NULL + void* BackendLanguageUserData; // = NULL + + // Optional: Access OS clipboard + // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) + const char* (*GetClipboardTextFn)(void* user_data); + void (*SetClipboardTextFn)(void* user_data, const char* text); + void* ClipboardUserData; + + // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) + // (default to use native imm32 api on Windows) + void (*ImeSetInputScreenPosFn)(int x, int y); + void* ImeWindowHandle; // = NULL // (Windows) Set this to your HWND to get automatic IME cursor positioning. + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // [OBSOLETE since 1.60+] Rendering function, will be automatically called in Render(). Please call your rendering function yourself now! + // You can obtain the ImDrawData* by calling ImGui::GetDrawData() after Render(). See example applications if you are unsure of how to implement this. + void (*RenderDrawListsFn)(ImDrawData* data); +#else + // This is only here to keep ImGuiIO the same size/layout, so that IMGUI_DISABLE_OBSOLETE_FUNCTIONS can exceptionally be used outside of imconfig.h. + void* RenderDrawListsFnUnused; +#endif + + //------------------------------------------------------------------ + // Input - Fill before calling NewFrame() + //------------------------------------------------------------------ + + ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX,-FLT_MAX) if mouse is unavailable (on another screen, etc.) + bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras. ImGui itself mostly only uses left button (BeginPopupContext** are using right button). Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. + float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. + float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all back-ends. + bool KeyCtrl; // Keyboard modifier pressed: Control + bool KeyShift; // Keyboard modifier pressed: Shift + bool KeyAlt; // Keyboard modifier pressed: Alt + bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows + bool KeysDown[512]; // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). + float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame(). + + // Functions + IMGUI_API void AddInputCharacter(ImWchar c); // Queue new character input + IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string + IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually + + //------------------------------------------------------------------ + // Output - Retrieve after calling NewFrame() + //------------------------------------------------------------------ + + bool WantCaptureMouse; // When io.WantCaptureMouse is true, imgui will use the mouse inputs, do not dispatch them to your main game/application (in both cases, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). + bool WantCaptureKeyboard; // When io.WantCaptureKeyboard is true, imgui will use the keyboard inputs, do not dispatch them to your main game/application (in both cases, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). + bool WantTextInput; // Mobile/console: when io.WantTextInput is true, you may display an on-screen keyboard. This is set by ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). + bool WantSetMousePos; // MousePos has been altered, back-end should reposition mouse on next frame. Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled. + bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. IMPORTANT: You need to clear io.WantSaveIniSettings yourself. + bool NavActive; // Directional navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. + bool NavVisible; // Directional navigation is visible and allowed (will handle ImGuiKey_NavXXX events). + float Framerate; // Application framerate estimation, in frame per second. Solely for convenience. Rolling average estimation based on IO.DeltaTime over 120 frames + int MetricsRenderVertices; // Vertices output during last call to Render() + int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 + int MetricsRenderWindows; // Number of visible windows + int MetricsActiveWindows; // Number of active windows + int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts. + ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. + + //------------------------------------------------------------------ + // [Internal] ImGui will maintain those fields. Forward compatibility not guaranteed! + //------------------------------------------------------------------ + + ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) + ImVec2 MouseClickedPos[5]; // Position at time of clicking + double MouseClickedTime[5]; // Time of last click (used to figure out double-click) + bool MouseClicked[5]; // Mouse button went from !Down to Down + bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? + bool MouseReleased[5]; // Mouse button went from Down to !Down + bool MouseDownOwned[5]; // Track if button was clicked inside a window. We don't request mouse capture from the application if click started outside ImGui bounds. + float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) + float MouseDownDurationPrev[5]; // Previous time the mouse button has been down + ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point + float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point + float KeysDownDuration[512]; // Duration the keyboard key has been down (0.0f == just pressed) + float KeysDownDurationPrev[512]; // Previous duration the key has been down + float NavInputsDownDuration[ImGuiNavInput_COUNT]; + float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]; + ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform back-end). Fill using AddInputCharacter() helper. + + IMGUI_API ImGuiIO(); +}; + +//----------------------------------------------------------------------------- +// Misc data structures +//----------------------------------------------------------------------------- + +// Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used. +// The callback function should return 0 by default. +// Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details) +// - ImGuiInputTextFlags_CallbackCompletion: Callback on pressing TAB +// - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows +// - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration +// - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. +// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. +struct ImGuiInputTextCallbackData +{ + ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only + ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only + void* UserData; // What user passed to InputText() // Read-only + + // Arguments for the different callback events + // - To modify the text buffer in a callback, prefer using the InsertChars() / DeleteChars() function. InsertChars() will take care of calling the resize callback if necessary. + // - If you know your edits are not going to resize the underlying buffer allocation, you may modify the contents of 'Buf[]' directly. You need to update 'BufTextLen' accordingly (0 <= BufTextLen < BufSize) and set 'BufDirty'' to true so InputText can update its internal state. + ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0; + ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only // [Completion,History] + char* Buf; // Text buffer // Read-write // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer! + int BufTextLen; // Text length (in bytes) // Read-write // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length() + int BufSize; // Buffer size (in bytes) = capacity+1 // Read-only // [Resize,Completion,History,Always] Include zero-terminator storage. In C land == ARRAYSIZE(my_char_array), in C++ land: string.capacity()+1 + bool BufDirty; // Set if you modify Buf/BufTextLen! // Write // [Completion,History,Always] + int CursorPos; // // Read-write // [Completion,History,Always] + int SelectionStart; // // Read-write // [Completion,History,Always] == to SelectionEnd when no selection) + int SelectionEnd; // // Read-write // [Completion,History,Always] + + // Helper functions for text manipulation. + // Use those function to benefit from the CallbackResize behaviors. Calling those function reset the selection. + IMGUI_API ImGuiInputTextCallbackData(); + IMGUI_API void DeleteChars(int pos, int bytes_count); + IMGUI_API void InsertChars(int pos, const char* text, const char* text_end = NULL); + bool HasSelection() const { return SelectionStart != SelectionEnd; } +}; + +// Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin(). +// NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough. +struct ImGuiSizeCallbackData +{ + void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraints() + ImVec2 Pos; // Read-only. Window position, for reference. + ImVec2 CurrentSize; // Read-only. Current window size. + ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. +}; + +// Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload() +struct ImGuiPayload +{ + // Members + void* Data; // Data (copied and owned by dear imgui) + int DataSize; // Data size + + // [Internal] + ImGuiID SourceId; // Source item id + ImGuiID SourceParentId; // Source parent id (if available) + int DataFrameCount; // Data timestamp + char DataType[32+1]; // Data type tag (short user-supplied string, 32 characters max) + bool Preview; // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets) + bool Delivery; // Set when AcceptDragDropPayload() was called and mouse button is released over the target item. + + ImGuiPayload() { Clear(); } + void Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Preview = Delivery = false; } + bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; } + bool IsPreview() const { return Preview; } + bool IsDelivery() const { return Delivery; } +}; + +//----------------------------------------------------------------------------- +// Obsolete functions (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details) +// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead. +//----------------------------------------------------------------------------- + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +namespace ImGui +{ + // OBSOLETED in 1.69 (from Mar 2019) + static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } + // OBSOLETED in 1.66 (from Sep 2018) + static inline void SetScrollHere(float center_ratio=0.5f){ SetScrollHereY(center_ratio); } + // OBSOLETED in 1.63 (between Aug 2018 and Sept 2018) + static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } + // OBSOLETED in 1.61 (between Apr 2018 and Aug 2018) + IMGUI_API bool InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags flags = 0); // Use the 'const char* format' version instead of 'decimal_precision'! + IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags flags = 0); + // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) + static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } + static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } + static inline ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = 0.f) { IM_UNUSED(on_edge); IM_UNUSED(outward); IM_ASSERT(0); return pos; } + // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + static inline void ShowTestWindow() { return ShowDemoWindow(); } + static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); } + static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } + static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } + static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); } + // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017) + IMGUI_API bool Begin(const char* name, bool* p_open, const ImVec2& size_on_first_use, float bg_alpha_override = -1.0f, ImGuiWindowFlags flags = 0); // Use SetNextWindowSize(size, ImGuiCond_FirstUseEver) + SetNextWindowBgAlpha() instead. + static inline bool IsRootWindowOrAnyChildHovered() { return IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); } + static inline void AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); } + static inline void SetNextWindowPosCenter(ImGuiCond c=0) { ImGuiIO& io = GetIO(); SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), c, ImVec2(0.5f, 0.5f)); } + // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) + static inline bool IsItemHoveredRect() { return IsItemHovered(ImGuiHoveredFlags_RectOnly); } + static inline bool IsPosHoveringAnyWindow(const ImVec2&) { IM_ASSERT(0); return false; } // This was misleading and partly broken. You probably want to use the ImGui::GetIO().WantCaptureMouse flag instead. + static inline bool IsMouseHoveringAnyWindow() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } + static inline bool IsMouseHoveringWindow() { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); } +} +typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETE in 1.63 (from Aug 2018): made the names consistent +typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData; +#endif + +//----------------------------------------------------------------------------- +// Helpers +//----------------------------------------------------------------------------- + +// Helper: IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() macros to call MemAlloc + Placement New, Placement Delete + MemFree +// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. +// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions. +struct ImNewDummy {}; +inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; } +inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new() +#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR) +#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE +template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } } + +// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame. +// Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame"); +struct ImGuiOnceUponAFrame +{ + ImGuiOnceUponAFrame() { RefFrame = -1; } + mutable int RefFrame; + operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; } +}; + +// Helper: Macro for ImGuiOnceUponAFrame. Attention: The macro expands into 2 statement so make sure you don't use it within e.g. an if() statement without curly braces. +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +#define IMGUI_ONCE_UPON_A_FRAME static ImGuiOnceUponAFrame imgui_oaf; if (imgui_oaf) // OBSOLETED in 1.51, will remove! +#endif + +// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" +struct ImGuiTextFilter +{ + IMGUI_API ImGuiTextFilter(const char* default_filter = ""); + IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build + IMGUI_API bool PassFilter(const char* text, const char* text_end = NULL) const; + IMGUI_API void Build(); + void Clear() { InputBuf[0] = 0; Build(); } + bool IsActive() const { return !Filters.empty(); } + + // [Internal] + struct TextRange + { + const char* b; + const char* e; + + TextRange() { b = e = NULL; } + TextRange(const char* _b, const char* _e) { b = _b; e = _e; } + const char* begin() const { return b; } + const char* end () const { return e; } + bool empty() const { return b == e; } + IMGUI_API void split(char separator, ImVector* out) const; + }; + char InputBuf[256]; + ImVector Filters; + int CountGrep; +}; + +// Helper: Growable text buffer for logging/accumulating text +// (this could be called 'ImGuiTextBuilder' / 'ImGuiStringBuilder') +struct ImGuiTextBuffer +{ + ImVector Buf; + static char EmptyString[1]; + + ImGuiTextBuffer() { } + inline char operator[](int i) { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } + const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } + const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator + int size() const { return Buf.Size ? Buf.Size - 1 : 0; } + bool empty() { return Buf.Size <= 1; } + void clear() { Buf.clear(); } + void reserve(int capacity) { Buf.reserve(capacity); } + const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; } + IMGUI_API void append(const char* str, const char* str_end = NULL); + IMGUI_API void appendf(const char* fmt, ...) IM_FMTARGS(2); + IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2); +}; + +// Helper: Key->Value storage +// Typically you don't have to worry about this since a storage is held within each Window. +// We use it to e.g. store collapse state for a tree (Int 0/1) +// This is optimized for efficient lookup (dichotomy into a contiguous buffer) and rare insertion (typically tied to user interactions aka max once a frame) +// You can use it as custom user storage for temporary values. Declare your own storage if, for example: +// - You want to manipulate the open/close state of a particular sub-tree in your interface (tree node uses Int 0/1 to store their state). +// - You want to store custom debug data easily without adding or editing structures in your code (probably not efficient, but convenient) +// Types are NOT stored, so it is up to you to make sure your Key don't collide with different types. +struct ImGuiStorage +{ + struct Pair + { + ImGuiID key; + union { int val_i; float val_f; void* val_p; }; + Pair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; } + Pair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; } + Pair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; } + }; + ImVector Data; + + // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N) + // - Set***() functions find pair, insertion on demand if missing. + // - Sorted insertion is costly, paid once. A typical frame shouldn't need to insert any new pair. + void Clear() { Data.clear(); } + IMGUI_API int GetInt(ImGuiID key, int default_val = 0) const; + IMGUI_API void SetInt(ImGuiID key, int val); + IMGUI_API bool GetBool(ImGuiID key, bool default_val = false) const; + IMGUI_API void SetBool(ImGuiID key, bool val); + IMGUI_API float GetFloat(ImGuiID key, float default_val = 0.0f) const; + IMGUI_API void SetFloat(ImGuiID key, float val); + IMGUI_API void* GetVoidPtr(ImGuiID key) const; // default_val is NULL + IMGUI_API void SetVoidPtr(ImGuiID key, void* val); + + // - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do Get+Set. + // - References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer. + // - A typical use case where this is convenient for quick hacking (e.g. add storage during a live Edit&Continue session if you can't modify existing struct) + // float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar; + IMGUI_API int* GetIntRef(ImGuiID key, int default_val = 0); + IMGUI_API bool* GetBoolRef(ImGuiID key, bool default_val = false); + IMGUI_API float* GetFloatRef(ImGuiID key, float default_val = 0.0f); + IMGUI_API void** GetVoidPtrRef(ImGuiID key, void* default_val = NULL); + + // Use on your own storage if you know only integer are being stored (open/close all tree nodes) + IMGUI_API void SetAllInt(int val); + + // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. + IMGUI_API void BuildSortByKey(); +}; + +// Helper: Manually clip large list of items. +// If you are submitting lots of evenly spaced items and you have a random access to the list, you can perform coarse clipping based on visibility to save yourself from processing those items at all. +// The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped. +// ImGui already clip items based on their bounds but it needs to measure text size to do so. Coarse clipping before submission makes this cost and your own data fetching/submission cost null. +// Usage: +// ImGuiListClipper clipper(1000); // we have 1000 elements, evenly spaced. +// while (clipper.Step()) +// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) +// ImGui::Text("line number %d", i); +// - Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height (step skipped if we passed a known height as second arg to constructor). +// - Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element. +// - (Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user call Step(). Does nothing and switch to Step 3.) +// - Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop. +struct ImGuiListClipper +{ + float StartPosY; + float ItemsHeight; + int ItemsCount, StepNo, DisplayStart, DisplayEnd; + + // items_count: Use -1 to ignore (you can call Begin later). Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step). + // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing(). + // If you don't specify an items_height, you NEED to call Step(). If you specify items_height you may call the old Begin()/End() api directly, but prefer calling Step(). + ImGuiListClipper(int items_count = -1, float items_height = -1.0f) { Begin(items_count, items_height); } // NB: Begin() initialize every fields (as we allow user to call Begin/End multiple times on a same instance if they want). + ~ImGuiListClipper() { IM_ASSERT(ItemsCount == -1); } // Assert if user forgot to call End() or Step() until false. + + IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items. + IMGUI_API void Begin(int items_count, float items_height = -1.0f); // Automatically called by constructor if you passed 'items_count' or by Step() in Step 1. + IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. +}; + +// Helpers macros to generate 32-bits encoded colors +#ifdef IMGUI_USE_BGRA_PACKED_COLOR +#define IM_COL32_R_SHIFT 16 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 0 +#define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 +#else +#define IM_COL32_R_SHIFT 0 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 16 +#define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 +#endif +#define IM_COL32(R,G,B,A) (((ImU32)(A)<>IM_COL32_R_SHIFT)&0xFF) * sc; Value.y = (float)((rgba>>IM_COL32_G_SHIFT)&0xFF) * sc; Value.z = (float)((rgba>>IM_COL32_B_SHIFT)&0xFF) * sc; Value.w = (float)((rgba>>IM_COL32_A_SHIFT)&0xFF) * sc; } + ImColor(float r, float g, float b, float a = 1.0f) { Value.x = r; Value.y = g; Value.z = b; Value.w = a; } + ImColor(const ImVec4& col) { Value = col; } + inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } + inline operator ImVec4() const { return Value; } + + // FIXME-OBSOLETE: May need to obsolete/cleanup those helpers. + inline void SetHSV(float h, float s, float v, float a = 1.0f){ ImGui::ColorConvertHSVtoRGB(h, s, v, Value.x, Value.y, Value.z); Value.w = a; } + static ImColor HSV(float h, float s, float v, float a = 1.0f) { float r,g,b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r,g,b,a); } +}; + +//----------------------------------------------------------------------------- +// Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListFlags, ImDrawList, ImDrawData) +// Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList. +//----------------------------------------------------------------------------- + +// Draw callbacks for advanced uses. +// NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering, +// you can poke into the draw list for that! Draw callback may be useful for example to: A) Change your GPU render state, +// B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc. +// The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }' +typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); + +// Typically, 1 command = 1 GPU draw call (unless command is a callback) +struct ImDrawCmd +{ + unsigned int ElemCount; // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. + ImVec4 ClipRect; // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates + ImTextureID TextureId; // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. + ImDrawCallback UserCallback; // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. + void* UserCallbackData; // The draw callback code can access this. + + ImDrawCmd() { ElemCount = 0; ClipRect.x = ClipRect.y = ClipRect.z = ClipRect.w = 0.0f; TextureId = (ImTextureID)NULL; UserCallback = NULL; UserCallbackData = NULL; } +}; + +// Vertex index (override with '#define ImDrawIdx unsigned int' in imconfig.h) +#ifndef ImDrawIdx +typedef unsigned short ImDrawIdx; +#endif + +// Vertex layout +#ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT +struct ImDrawVert +{ + ImVec2 pos; + ImVec2 uv; + ImU32 col; +}; +#else +// You can override the vertex format layout by defining IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT in imconfig.h +// The code expect ImVec2 pos (8 bytes), ImVec2 uv (8 bytes), ImU32 col (4 bytes), but you can re-order them or add other fields as needed to simplify integration in your engine. +// The type has to be described within the macro (you can either declare the struct or use a typedef) +// NOTE: IMGUI DOESN'T CLEAR THE STRUCTURE AND DOESN'T CALL A CONSTRUCTOR SO ANY CUSTOM FIELD WILL BE UNINITIALIZED. IF YOU ADD EXTRA FIELDS (SUCH AS A 'Z' COORDINATES) YOU WILL NEED TO CLEAR THEM DURING RENDER OR TO IGNORE THEM. +IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT; +#endif + +// Draw channels are used by the Columns API to "split" the render list into different channels while building, so items of each column can be batched together. +// You can also use them to simulate drawing layers and submit primitives in a different order than how they will be rendered. +struct ImDrawChannel +{ + ImVector CmdBuffer; + ImVector IdxBuffer; +}; + +enum ImDrawCornerFlags_ +{ + ImDrawCornerFlags_TopLeft = 1 << 0, // 0x1 + ImDrawCornerFlags_TopRight = 1 << 1, // 0x2 + ImDrawCornerFlags_BotLeft = 1 << 2, // 0x4 + ImDrawCornerFlags_BotRight = 1 << 3, // 0x8 + ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight, // 0x3 + ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight, // 0xC + ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft, // 0x5 + ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight, // 0xA + ImDrawCornerFlags_All = 0xF // In your function calls you may use ~0 (= all bits sets) instead of ImDrawCornerFlags_All, as a convenience +}; + +enum ImDrawListFlags_ +{ + ImDrawListFlags_None = 0, + ImDrawListFlags_AntiAliasedLines = 1 << 0, // Lines are anti-aliased (*2 the number of triangles for 1.0f wide line, otherwise *3 the number of triangles) + ImDrawListFlags_AntiAliasedFill = 1 << 1 // Filled shapes have anti-aliased edges (*2 the number of vertices) +}; + +// Draw command list +// This is the low-level list of polygons that ImGui functions are filling. At the end of the frame, all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering. +// Each ImGui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to access the current window draw list and draw custom primitives. +// You can interleave normal ImGui:: calls and adding primitives to the current draw list. +// All positions are generally in pixel coordinates (top-left at (0,0), bottom-right at io.DisplaySize), but you are totally free to apply whatever transformation matrix to want to the data (if you apply such transformation you'll want to apply it to ClipRect as well) +// Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects. +struct ImDrawList +{ + // This is what you have to render + ImVector CmdBuffer; // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback. + ImVector IdxBuffer; // Index buffer. Each command consume ImDrawCmd::ElemCount of those + ImVector VtxBuffer; // Vertex buffer. + ImDrawListFlags Flags; // Flags, you may poke into these to adjust anti-aliasing settings per-primitive. + + // [Internal, used while building lists] + const ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context) + const char* _OwnerName; // Pointer to owner window's name for debugging + unsigned int _VtxCurrentIdx; // [Internal] == VtxBuffer.Size + ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) + ImDrawIdx* _IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) + ImVector _ClipRectStack; // [Internal] + ImVector _TextureIdStack; // [Internal] + ImVector _Path; // [Internal] current path building + int _ChannelsCurrent; // [Internal] current channel number (0) + int _ChannelsCount; // [Internal] number of active channels (1+) + ImVector _Channels; // [Internal] draw channels for columns API (not resized down so _ChannelsCount may be smaller than _Channels.Size) + + // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui) + ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; _OwnerName = NULL; Clear(); } + ~ImDrawList() { ClearFreeMemory(); } + IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) + IMGUI_API void PushClipRectFullScreen(); + IMGUI_API void PopClipRect(); + IMGUI_API void PushTextureID(ImTextureID texture_id); + IMGUI_API void PopTextureID(); + inline ImVec2 GetClipRectMin() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.x, cr.y); } + inline ImVec2 GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); } + + // Primitives + IMGUI_API void AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All, float thickness = 1.0f); // a: upper-left, b: lower-right, rounding_corners_flags: 4-bits corresponding to which corner to round + IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All); // a: upper-left, b: lower-right + IMGUI_API void AddRectFilledMultiColor(const ImVec2& a, const ImVec2& b, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); + IMGUI_API void AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col); + IMGUI_API void AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col); + IMGUI_API void AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12, float thickness = 1.0f); + IMGUI_API void AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12); + IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL); + IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); + IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,1), ImU32 col = 0xFFFFFFFF); + IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,0), const ImVec2& uv_c = ImVec2(1,1), const ImVec2& uv_d = ImVec2(0,1), ImU32 col = 0xFFFFFFFF); + IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners = ImDrawCornerFlags_All); + IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, bool closed, float thickness); + IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col); // Note: Anti-aliased filling requires points to be in clockwise order. + IMGUI_API void AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0); + + // Stateful path API, add points then finish with PathFillConvex() or PathStroke() + inline void PathClear() { _Path.Size = 0; } + inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } + inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); } + inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } // Note: Anti-aliased filling requires points to be in clockwise order. + inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); _Path.Size = 0; } + IMGUI_API void PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10); + IMGUI_API void PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle + IMGUI_API void PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0); + IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All); + + // Channels + // - Use to simulate layers. By switching channels to can render out-of-order (e.g. submit foreground primitives before background primitives) + // - Use to minimize draw calls (e.g. if going back-and-forth between multiple non-overlapping clipping rectangles, prefer to append into separate channels then merge at the end) + IMGUI_API void ChannelsSplit(int channels_count); + IMGUI_API void ChannelsMerge(); + IMGUI_API void ChannelsSetCurrent(int channel_index); + + // Advanced + IMGUI_API void AddCallback(ImDrawCallback callback, void* callback_data); // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. + IMGUI_API void AddDrawCmd(); // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible + IMGUI_API ImDrawList* CloneOutput() const; // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer. + + // Internal helpers + // NB: all primitives needs to be reserved via PrimReserve() beforehand! + IMGUI_API void Clear(); + IMGUI_API void ClearFreeMemory(); + IMGUI_API void PrimReserve(int idx_count, int vtx_count); + IMGUI_API void PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col); // Axis aligned rectangle (composed of two triangles) + IMGUI_API void PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col); + IMGUI_API void PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col); + inline void PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col){ _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; } + inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; } + inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } + IMGUI_API void UpdateClipRect(); + IMGUI_API void UpdateTextureID(); +}; + +// All draw data to render an ImGui frame +// (NB: the style and the naming convention here is a little inconsistent but we preserve them for backward compatibility purpose) +struct ImDrawData +{ + bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. + ImDrawList** CmdLists; // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here. + int CmdListsCount; // Number of ImDrawList* to render + int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size + int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size + ImVec2 DisplayPos; // Upper-left position of the viewport to render (== upper-left of the orthogonal projection matrix to use) + ImVec2 DisplaySize; // Size of the viewport to render (== io.DisplaySize for the main viewport) (DisplayPos + DisplaySize == lower-right of the orthogonal projection matrix to use) + ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. + + // Functions + ImDrawData() { Valid = false; Clear(); } + ~ImDrawData() { Clear(); } + void Clear() { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.f, 0.f); } // The ImDrawList are owned by ImGuiContext! + IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! + IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. +}; + +//----------------------------------------------------------------------------- +// Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont) +//----------------------------------------------------------------------------- + +struct ImFontConfig +{ + void* FontData; // // TTF/OTF data + int FontDataSize; // // TTF/OTF data size + bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). + int FontNo; // 0 // Index of font within TTF/OTF file + float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). + int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. Read /~https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. + bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. + ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. + ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. + const ImWchar* GlyphRanges; // NULL // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. + float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font + float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs + bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. + unsigned int RasterizerFlags; // 0x00 // Settings for custom font rasterizer (e.g. ImGuiFreeType). Leave as zero if you aren't using one. + float RasterizerMultiply; // 1.0f // Brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. + + // [Internal] + char Name[40]; // Name (strictly to ease debugging) + ImFont* DstFont; + + IMGUI_API ImFontConfig(); +}; + +struct ImFontGlyph +{ + ImWchar Codepoint; // 0x0000..0xFFFF + float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in) + float X0, Y0, X1, Y1; // Glyph corners + float U0, V0, U1, V1; // Texture coordinates +}; + +// Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges(). +// This is essentially a tightly packed of vector of 64k booleans = 8KB storage. +struct ImFontGlyphRangesBuilder +{ + ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) + + ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / sizeof(int)); memset(UsedChars.Data, 0, 0x10000 / sizeof(int)); } + bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array + void SetBit(int n) { int off = (n >> 5); int mask = 1 << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array + void AddChar(ImWchar c) { SetBit(c); } // Add character + IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) + IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext + IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges +}; + +enum ImFontAtlasFlags_ +{ + ImFontAtlasFlags_None = 0, + ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, // Don't round the height to next power of two + ImFontAtlasFlags_NoMouseCursors = 1 << 1 // Don't build software mouse cursors into the atlas +}; + +// Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding: +// - One or more fonts. +// - Custom graphics data needed to render the shapes needed by Dear ImGui. +// - Mouse cursor shapes for software cursor rendering (unless setting 'Flags |= ImFontAtlasFlags_NoMouseCursors' in the font atlas). +// It is the user-code responsibility to setup/build the atlas, then upload the pixel data into a texture accessible by your graphics api. +// - Optionally, call any of the AddFont*** functions. If you don't call any, the default font embedded in the code will be loaded for you. +// - Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. +// - Upload the pixels data into a texture within your graphics system (see imgui_impl_xxxx.cpp examples) +// - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. +// This value will be passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details. +// Common pitfalls: +// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the +// atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data. +// - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction. +// You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed, +// - Even though many functions are suffixed with "TTF", OTF data is supported just as well. +// - This is an old API and it is currently awkward for those and and various other reasons! We will address them in the future! +struct ImFontAtlas +{ + IMGUI_API ImFontAtlas(); + IMGUI_API ~ImFontAtlas(); + IMGUI_API ImFont* AddFont(const ImFontConfig* font_cfg); + IMGUI_API ImFont* AddFontDefault(const ImFontConfig* font_cfg = NULL); + IMGUI_API ImFont* AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); + IMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed. + IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. + IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. + IMGUI_API void ClearInputData(); // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. + IMGUI_API void ClearTexData(); // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. + IMGUI_API void ClearFonts(); // Clear output font data (glyphs storage, UV coordinates). + IMGUI_API void Clear(); // Clear all input and output. + + // Build atlas, retrieve pixel data. + // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). + // The pitch is always = Width * BytesPerPixels (1 or 4) + // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into + // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. + IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. + IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel + IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel + bool IsBuilt() { return Fonts.Size > 0 && (TexPixelsAlpha8 != NULL || TexPixelsRGBA32 != NULL); } + void SetTexID(ImTextureID id) { TexID = id; } + + //------------------------------------------- + // Glyph Ranges + //------------------------------------------- + + // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) + // NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details. + // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data. + IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin + IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters + IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs + IMGUI_API const ImWchar* GetGlyphRangesChineseFull(); // Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs + IMGUI_API const ImWchar* GetGlyphRangesChineseSimplifiedCommon();// Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese + IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters + IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters + IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietname characters + + //------------------------------------------- + // Custom Rectangles/Glyphs API + //------------------------------------------- + + // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. After calling Build(), you can query the rectangle position and render your pixels. + // You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), so you can render e.g. custom colorful icons and use them as regular glyphs. + struct CustomRect + { + unsigned int ID; // Input // User ID. Use <0x10000 to map into a font glyph, >=0x10000 for other/internal/custom texture data. + unsigned short Width, Height; // Input // Desired rectangle dimension + unsigned short X, Y; // Output // Packed position in Atlas + float GlyphAdvanceX; // Input // For custom font glyphs only (ID<0x10000): glyph xadvance + ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID<0x10000): glyph display offset + ImFont* Font; // Input // For custom font glyphs only (ID<0x10000): target font + CustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0,0); Font = NULL; } + bool IsPacked() const { return X != 0xFFFF; } + }; + + IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x10000. Id >= 0x80000000 are reserved for ImGui and ImDrawList + IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0,0)); // Id needs to be < 0x10000 to register a rectangle to map into a specific font. + const CustomRect* GetCustomRectByIndex(int index) const { if (index < 0) return NULL; return &CustomRects[index]; } + + // [Internal] + IMGUI_API void CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max); + IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]); + + //------------------------------------------- + // Members + //------------------------------------------- + + bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. + ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) + ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. + int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. + int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0. + + // [Internal] + // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. + unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight + unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 + int TexWidth; // Texture width calculated during Build(). + int TexHeight; // Texture height calculated during Build(). + ImVec2 TexUvScale; // = (1.0f/TexWidth, 1.0f/TexHeight) + ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel + ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. + ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. + ImVector ConfigData; // Internal data + int CustomRectIds[1]; // Identifiers of custom texture rectangle used by ImFontAtlas/ImDrawList + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETE 1.67+ +#endif +}; + +// Font runtime data and rendering +// ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32(). +struct ImFont +{ + // Members: Hot ~20/24 bytes (for CalcTextSize) + ImVector IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI). + float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX + float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading) + + // Members: Hot ~36/48 bytes (for CalcTextSize + render loop) + ImVector IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point. + ImVector Glyphs; // 12-16 // out // // All glyphs. + const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) + ImVec2 DisplayOffset; // 8 // in // = (0,0) // Offset font rendering by xx pixels + + // Members: Cold ~32/40 bytes + ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into + const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData + short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. + ImWchar FallbackChar; // 2 // in // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar() + float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() + float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] + int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) + bool DirtyLookupTables; // 1 // out // + + // Methods + IMGUI_API ImFont(); + IMGUI_API ~ImFont(); + IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const; + IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c) const; + float GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } + bool IsLoaded() const { return ContainerAtlas != NULL; } + const char* GetDebugName() const { return ConfigData ? ConfigData->Name : ""; } + + // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. + // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. + IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8 + IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; + IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const; + IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; + + // [Internal] Don't use! + IMGUI_API void BuildLookupTable(); + IMGUI_API void ClearOutputData(); + IMGUI_API void GrowIndex(int new_size); + IMGUI_API void AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); + IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. + IMGUI_API void SetFallbackChar(ImWchar c); + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + typedef ImFontGlyph Glyph; // OBSOLETE 1.52+ +#endif +}; + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif + +// Include imgui_user.h at the end of imgui.h (convenient for user to only explicitly include vanilla imgui.h) +#ifdef IMGUI_INCLUDE_IMGUI_USER_H +#include "imgui_user.h" +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_demo.cpp b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_demo.cpp new file mode 100644 index 00000000..a8fcb2a5 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_demo.cpp @@ -0,0 +1,4430 @@ +// dear imgui, v1.69 +// (demo code) + +// Message to the person tempted to delete this file when integrating Dear ImGui into their code base: +// Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other coders +// will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of +// your game/app! Removing this file from your project is hindering access to documentation for everyone in your team, +// likely leading you to poorer usage of the library. +// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow(). +// If you want to link core Dear ImGui in your shipped builds but want an easy guarantee that the demo will not be linked, +// you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. +// In other situation, whenever you have Dear ImGui available you probably want this to be available for reference. +// Thank you, +// -Your beloved friend, imgui_demo.cpp (that you won't delete) + +// Message to beginner C/C++ programmers about the meaning of the 'static' keyword: +// In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, so it is +// essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data +// in the same place, to make the demo source code faster to read, faster to write, and smaller in size. +// It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant +// or used in threads. This might be a pattern you will want to use in your code, but most of the real data you would be editing is +// likely going to be stored outside your functions. + +/* + +Index of this file: + +// [SECTION] Forward Declarations, Helpers +// [SECTION] Demo Window / ShowDemoWindow() +// [SECTION] About Window / ShowAboutWindow() +// [SECTION] Style Editor / ShowStyleEditor() +// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() +// [SECTION] Example App: Debug Console / ShowExampleAppConsole() +// [SECTION] Example App: Debug Log / ShowExampleAppLog() +// [SECTION] Example App: Simple Layout / ShowExampleAppLayout() +// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() +// [SECTION] Example App: Long Text / ShowExampleAppLongText() +// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() +// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() +// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() +// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() +// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() +// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#include // toupper, isprint +#include // INT_MIN, INT_MAX +#include // sqrtf, powf, cosf, sinf, floorf, ceilf +#include // vsnprintf, sscanf, printf +#include // NULL, malloc, free, atoi +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#endif +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning : 'xx' is deprecated: The POSIX name for this item.. // for strdup used in demo code (so user can copy & paste the code) +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' +#pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal +#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. +#pragma clang diagnostic ignored "-Wunused-macros" // warning : warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used. +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#endif +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#endif +#if __has_warning("-Wreserved-id-macro") +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // +#endif +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat-security" // warning : format string is not a string literal (potentially insecure) +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#if (__GNUC__ >= 6) +#pragma GCC diagnostic ignored "-Wmisleading-indentation" // warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. +#endif +#endif + +// Play it nice with Windows users. Notepad in 2017 still doesn't display text data with Unix-style \n. +#ifdef _WIN32 +#define IM_NEWLINE "\r\n" +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#else +#define IM_NEWLINE "\n" +#endif + +#define IM_MAX(_A,_B) (((_A) >= (_B)) ? (_A) : (_B)) + +//----------------------------------------------------------------------------- +// [SECTION] Forward Declarations, Helpers +//----------------------------------------------------------------------------- + +#if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && defined(IMGUI_DISABLE_TEST_WINDOWS) && !defined(IMGUI_DISABLE_DEMO_WINDOWS) // Obsolete name since 1.53, TEST->DEMO +#define IMGUI_DISABLE_DEMO_WINDOWS +#endif + +#if !defined(IMGUI_DISABLE_DEMO_WINDOWS) + +// Forward Declarations +static void ShowExampleAppDocuments(bool* p_open); +static void ShowExampleAppMainMenuBar(); +static void ShowExampleAppConsole(bool* p_open); +static void ShowExampleAppLog(bool* p_open); +static void ShowExampleAppLayout(bool* p_open); +static void ShowExampleAppPropertyEditor(bool* p_open); +static void ShowExampleAppLongText(bool* p_open); +static void ShowExampleAppAutoResize(bool* p_open); +static void ShowExampleAppConstrainedResize(bool* p_open); +static void ShowExampleAppSimpleOverlay(bool* p_open); +static void ShowExampleAppWindowTitles(bool* p_open); +static void ShowExampleAppCustomRendering(bool* p_open); +static void ShowExampleMenuFile(); + +// Helper to display a little (?) mark which shows a tooltip when hovered. +static void HelpMarker(const char* desc) +{ + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(desc); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } +} + +// Helper to display basic user controls. +void ImGui::ShowUserGuide() +{ + ImGui::BulletText("Double-click on title bar to collapse window."); + ImGui::BulletText("Click and drag on lower right corner to resize window\n(double-click to auto fit window to its contents)."); + ImGui::BulletText("Click and drag on any empty space to move window."); + ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); + ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); + if (ImGui::GetIO().FontAllowUserScaling) + ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); + ImGui::BulletText("Mouse Wheel to scroll."); + ImGui::BulletText("While editing text:\n"); + ImGui::Indent(); + ImGui::BulletText("Hold SHIFT or use mouse to select text."); + ImGui::BulletText("CTRL+Left/Right to word jump."); + ImGui::BulletText("CTRL+A or double-click to select all."); + ImGui::BulletText("CTRL+X,CTRL+C,CTRL+V to use clipboard."); + ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); + ImGui::BulletText("ESCAPE to revert."); + ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); + ImGui::Unindent(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Demo Window / ShowDemoWindow() +//----------------------------------------------------------------------------- + +// We split the contents of the big ShowDemoWindow() function into smaller functions (because the link time of very large functions grow non-linearly) +static void ShowDemoWindowWidgets(); +static void ShowDemoWindowLayout(); +static void ShowDemoWindowPopups(); +static void ShowDemoWindowColumns(); +static void ShowDemoWindowMisc(); + +// Demonstrate most Dear ImGui features (this is big function!) +// You may execute this function to experiment with the UI and understand what it does. You may then search for keywords in the code when you are interested by a specific feature. +void ImGui::ShowDemoWindow(bool* p_open) +{ + // Examples Apps (accessible from the "Examples" menu) + static bool show_app_documents = false; + static bool show_app_main_menu_bar = false; + static bool show_app_console = false; + static bool show_app_log = false; + static bool show_app_layout = false; + static bool show_app_property_editor = false; + static bool show_app_long_text = false; + static bool show_app_auto_resize = false; + static bool show_app_constrained_resize = false; + static bool show_app_simple_overlay = false; + static bool show_app_window_titles = false; + static bool show_app_custom_rendering = false; + + if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace() + if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); + if (show_app_console) ShowExampleAppConsole(&show_app_console); + if (show_app_log) ShowExampleAppLog(&show_app_log); + if (show_app_layout) ShowExampleAppLayout(&show_app_layout); + if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor); + if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); + if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); + if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); + if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay); + if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); + if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); + + // Dear ImGui Apps (accessible from the "Help" menu) + static bool show_app_metrics = false; + static bool show_app_style_editor = false; + static bool show_app_about = false; + + if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); } + if (show_app_style_editor) { ImGui::Begin("Style Editor", &show_app_style_editor); ImGui::ShowStyleEditor(); ImGui::End(); } + if (show_app_about) { ImGui::ShowAboutWindow(&show_app_about); } + + // Demonstrate the various window flags. Typically you would just use the default! + static bool no_titlebar = false; + static bool no_scrollbar = false; + static bool no_menu = false; + static bool no_move = false; + static bool no_resize = false; + static bool no_collapse = false; + static bool no_close = false; + static bool no_nav = false; + static bool no_background = false; + static bool no_bring_to_front = false; + + ImGuiWindowFlags window_flags = 0; + if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar; + if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar; + if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; + if (no_move) window_flags |= ImGuiWindowFlags_NoMove; + if (no_resize) window_flags |= ImGuiWindowFlags_NoResize; + if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; + if (no_nav) window_flags |= ImGuiWindowFlags_NoNav; + if (no_background) window_flags |= ImGuiWindowFlags_NoBackground; + if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + if (no_close) p_open = NULL; // Don't pass our bool* to Begin + + // We specify a default position/size in case there's no data in the .ini file. Typically this isn't required! We only do it to make the Demo applications a little more welcoming. + ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); + + // Main body of the Demo window starts here. + if (!ImGui::Begin("ImGui Demo", p_open, window_flags)) + { + // Early out if the window is collapsed, as an optimization. + ImGui::End(); + return; + } + ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION); + + // Most "big" widgets share a common width settings by default. + //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); // Use 2/3 of the space for widgets and 1/3 for labels (default) + ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // Use fixed width for labels (by passing a negative value), the rest goes to widgets. We choose a width proportional to our font size. + + // Menu + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("Menu")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Examples")) + { + ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); + ImGui::MenuItem("Console", NULL, &show_app_console); + ImGui::MenuItem("Log", NULL, &show_app_log); + ImGui::MenuItem("Simple layout", NULL, &show_app_layout); + ImGui::MenuItem("Property editor", NULL, &show_app_property_editor); + ImGui::MenuItem("Long text display", NULL, &show_app_long_text); + ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); + ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); + ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay); + ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles); + ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); + ImGui::MenuItem("Documents", NULL, &show_app_documents); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Help")) + { + ImGui::MenuItem("Metrics", NULL, &show_app_metrics); + ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor); + ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about); + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + ImGui::Spacing(); + if (ImGui::CollapsingHeader("Help")) + { + ImGui::Text("PROGRAMMER GUIDE:"); + ImGui::BulletText("Please see the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); + ImGui::BulletText("Please see the comments in imgui.cpp."); + ImGui::BulletText("Please see the examples/ in application."); + ImGui::BulletText("Enable 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls."); + ImGui::BulletText("Enable 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls."); + ImGui::Separator(); + + ImGui::Text("USER GUIDE:"); + ImGui::ShowUserGuide(); + } + + if (ImGui::CollapsingHeader("Configuration")) + { + ImGuiIO& io = ImGui::GetIO(); + + if (ImGui::TreeNode("Configuration##2")) + { + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); + ImGui::SameLine(); HelpMarker("Required back-end to feed in gamepad inputs in io.NavInputs[] and set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); + ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); + ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouse); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) // Create a way to restore this flag otherwise we could be stuck completely! + { + if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f) + { + ImGui::SameLine(); + ImGui::Text("<>"); + } + if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space))) + io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; + } + ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); + ImGui::SameLine(); HelpMarker("Instruct back-end to not alter mouse cursor shape and visibility."); + ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); + ImGui::SameLine(); HelpMarker("Set to false to disable blinking cursor, for users who consider it distracting"); + ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); + ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback."); + ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); + ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); + ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor for you. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); + ImGui::TreePop(); + ImGui::Separator(); + } + + if (ImGui::TreeNode("Backend Flags")) + { + HelpMarker("Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities."); + ImGuiBackendFlags backend_flags = io.BackendFlags; // Make a local copy to avoid modifying the back-end flags. + ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasGamepad); + ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasMouseCursors); + ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasSetMousePos); + ImGui::TreePop(); + ImGui::Separator(); + } + + if (ImGui::TreeNode("Style")) + { + ImGui::ShowStyleEditor(); + ImGui::TreePop(); + ImGui::Separator(); + } + + if (ImGui::TreeNode("Capture/Logging")) + { + ImGui::TextWrapped("The logging API redirects all text output so you can easily capture the content of a window or a block. Tree nodes can be automatically expanded."); + HelpMarker("Try opening any of the contents below in this window and then click one of the \"Log To\" button."); + ImGui::LogButtons(); + ImGui::TextWrapped("You can also call ImGui::LogText() to output directly to the log without a visual output."); + if (ImGui::Button("Copy \"Hello, world!\" to clipboard")) + { + ImGui::LogToClipboard(); + ImGui::LogText("Hello, world!"); + ImGui::LogFinish(); + } + ImGui::TreePop(); + } + } + + if (ImGui::CollapsingHeader("Window options")) + { + ImGui::Checkbox("No titlebar", &no_titlebar); ImGui::SameLine(150); + ImGui::Checkbox("No scrollbar", &no_scrollbar); ImGui::SameLine(300); + ImGui::Checkbox("No menu", &no_menu); + ImGui::Checkbox("No move", &no_move); ImGui::SameLine(150); + ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300); + ImGui::Checkbox("No collapse", &no_collapse); + ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150); + ImGui::Checkbox("No nav", &no_nav); ImGui::SameLine(300); + ImGui::Checkbox("No background", &no_background); + ImGui::Checkbox("No bring to front", &no_bring_to_front); + } + + // All demo contents + ShowDemoWindowWidgets(); + ShowDemoWindowLayout(); + ShowDemoWindowPopups(); + ShowDemoWindowColumns(); + ShowDemoWindowMisc(); + + // End of ShowDemoWindow() + ImGui::End(); +} + +static void ShowDemoWindowWidgets() +{ + if (!ImGui::CollapsingHeader("Widgets")) + return; + + if (ImGui::TreeNode("Basic")) + { + static int clicked = 0; + if (ImGui::Button("Button")) + clicked++; + if (clicked & 1) + { + ImGui::SameLine(); + ImGui::Text("Thanks for clicking me!"); + } + + static bool check = true; + ImGui::Checkbox("checkbox", &check); + + static int e = 0; + ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); + ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); + ImGui::RadioButton("radio c", &e, 2); + + // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. + for (int i = 0; i < 7; i++) + { + if (i > 0) + ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i/7.0f, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i/7.0f, 0.8f, 0.8f)); + ImGui::Button("Click"); + ImGui::PopStyleColor(3); + ImGui::PopID(); + } + + // Use AlignTextToFramePadding() to align text baseline to the baseline of framed elements (otherwise a Text+SameLine+Button sequence will have the text a little too high by default) + ImGui::AlignTextToFramePadding(); + ImGui::Text("Hold to repeat:"); + ImGui::SameLine(); + + // Arrow buttons with Repeater + static int counter = 0; + float spacing = ImGui::GetStyle().ItemInnerSpacing.x; + ImGui::PushButtonRepeat(true); + if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; } + ImGui::SameLine(0.0f, spacing); + if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; } + ImGui::PopButtonRepeat(); + ImGui::SameLine(); + ImGui::Text("%d", counter); + + ImGui::Text("Hover over me"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("I am a tooltip"); + + ImGui::SameLine(); + ImGui::Text("- or me"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("I am a fancy tooltip"); + static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); + ImGui::EndTooltip(); + } + + ImGui::Separator(); + + ImGui::LabelText("label", "Value"); + + { + // Using the _simplified_ one-liner Combo() api here + // See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api. + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; + static int item_current = 0; + ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); + ImGui::SameLine(); HelpMarker("Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, and demonstration of various flags.\n"); + } + + { + static char str0[128] = "Hello, world!"; + ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); + ImGui::SameLine(); HelpMarker("USER:\nHold SHIFT or use mouse to select text.\n" "CTRL+Left/Right to word jump.\n" "CTRL+A or double-click to select all.\n" "CTRL+X,CTRL+C,CTRL+V clipboard.\n" "CTRL+Z,CTRL+Y undo/redo.\n" "ESCAPE to revert.\n\nPROGRAMMER:\nYou can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated in imgui_demo.cpp)."); + + static char str1[128] = ""; + ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); + + static int i0 = 123; + ImGui::InputInt("input int", &i0); + ImGui::SameLine(); HelpMarker("You can apply arithmetic operators +,*,/ on numerical values.\n e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n"); + + static float f0 = 0.001f; + ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); + + static double d0 = 999999.00000001; + ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f"); + + static float f1 = 1.e10f; + ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); + ImGui::SameLine(); HelpMarker("You can input value using the scientific notation,\n e.g. \"1e+8\" becomes \"100000000\".\n"); + + static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; + ImGui::InputFloat3("input float3", vec4a); + } + + { + static int i1 = 50, i2 = 42; + ImGui::DragInt("drag int", &i1, 1); + ImGui::SameLine(); HelpMarker("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input value."); + + ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%"); + + static float f1=1.00f, f2=0.0067f; + ImGui::DragFloat("drag float", &f1, 0.005f); + ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); + } + + { + static int i1=0; + ImGui::SliderInt("slider int", &i1, -1, 3); + ImGui::SameLine(); HelpMarker("CTRL+click to input value."); + + static float f1=0.123f, f2=0.0f; + ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); + ImGui::SliderFloat("slider float (curve)", &f2, -10.0f, 10.0f, "%.4f", 2.0f); + static float angle = 0.0f; + ImGui::SliderAngle("slider angle", &angle); + } + + { + static float col1[3] = { 1.0f,0.0f,0.2f }; + static float col2[4] = { 0.4f,0.7f,0.0f,0.5f }; + ImGui::ColorEdit3("color 1", col1); + ImGui::SameLine(); HelpMarker("Click on the colored square to open a color picker.\nClick and hold to use drag and drop.\nRight-click on the colored square to show options.\nCTRL+click on individual component to input value.\n"); + + ImGui::ColorEdit4("color 2", col2); + } + + { + // List box + const char* listbox_items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; + static int listbox_item_current = 1; + ImGui::ListBox("listbox\n(single select)", &listbox_item_current, listbox_items, IM_ARRAYSIZE(listbox_items), 4); + + //static int listbox_item_current2 = 2; + //ImGui::PushItemWidth(-1); + //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4); + //ImGui::PopItemWidth(); + } + + ImGui::TreePop(); + } + + // Testing ImGuiOnceUponAFrame helper. + //static ImGuiOnceUponAFrame once; + //for (int i = 0; i < 5; i++) + // if (once) + // ImGui::Text("This will be displayed only once."); + + if (ImGui::TreeNode("Trees")) + { + if (ImGui::TreeNode("Basic trees")) + { + for (int i = 0; i < 5; i++) + if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) + { + ImGui::Text("blah blah"); + ImGui::SameLine(); + if (ImGui::SmallButton("button")) { }; + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Advanced, with Selectable nodes")) + { + HelpMarker("This is a more standard looking tree with selectable nodes.\nClick to select, CTRL+Click to toggle, click on arrows or double-click to open."); + static bool align_label_with_current_x_position = false; + ImGui::Checkbox("Align label with current X position)", &align_label_with_current_x_position); + ImGui::Text("Hello!"); + if (align_label_with_current_x_position) + ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); + + static int selection_mask = (1 << 2); // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit. + int node_clicked = -1; // Temporary storage of what node we have clicked to process selection at the end of the loop. May be a pointer to your own node type, etc. + ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, ImGui::GetFontSize()*3); // Increase spacing to differentiate leaves from expanded contents. + for (int i = 0; i < 6; i++) + { + // Disable the default open on single-click behavior and pass in Selected flag according to our selection state. + ImGuiTreeNodeFlags node_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0); + if (i < 3) + { + // Node + bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); + if (ImGui::IsItemClicked()) + node_clicked = i; + if (node_open) + { + ImGui::Text("Blah blah\nBlah Blah"); + ImGui::TreePop(); + } + } + else + { + // Leaf: The only reason we have a TreeNode at all is to allow selection of the leaf. Otherwise we can use BulletText() or TreeAdvanceToLabelPos()+Text(). + node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet + ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); + if (ImGui::IsItemClicked()) + node_clicked = i; + } + } + if (node_clicked != -1) + { + // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame. + if (ImGui::GetIO().KeyCtrl) + selection_mask ^= (1 << node_clicked); // CTRL+click to toggle + else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, this commented bit preserve selection when clicking on item that is part of the selection + selection_mask = (1 << node_clicked); // Click to single-select + } + ImGui::PopStyleVar(); + if (align_label_with_current_x_position) + ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Collapsing Headers")) + { + static bool closable_group = true; + ImGui::Checkbox("Enable extra group", &closable_group); + if (ImGui::CollapsingHeader("Header")) + { + ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); + for (int i = 0; i < 5; i++) + ImGui::Text("Some content %d", i); + } + if (ImGui::CollapsingHeader("Header with a close button", &closable_group)) + { + ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); + for (int i = 0; i < 5; i++) + ImGui::Text("More content %d", i); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Bullets")) + { + ImGui::BulletText("Bullet point 1"); + ImGui::BulletText("Bullet point 2\nOn multiple lines"); + ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); + ImGui::Bullet(); ImGui::SmallButton("Button"); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Text")) + { + if (ImGui::TreeNode("Colored Text")) + { + // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. + ImGui::TextColored(ImVec4(1.0f,0.0f,1.0f,1.0f), "Pink"); + ImGui::TextColored(ImVec4(1.0f,1.0f,0.0f,1.0f), "Yellow"); + ImGui::TextDisabled("Disabled"); + ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle."); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Word Wrapping")) + { + // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. + ImGui::TextWrapped("This text should automatically wrap on the edge of the window. The current implementation for text wrapping follows simple rules suitable for English and possibly other languages."); + ImGui::Spacing(); + + static float wrap_width = 200.0f; + ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f"); + + ImGui::Text("Test paragraph 1:"); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255,0,255,255)); + ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); + ImGui::Text("The lazy dog is a good dog. This paragraph is made to fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); + ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,255,0,255)); + ImGui::PopTextWrapPos(); + + ImGui::Text("Test paragraph 2:"); + pos = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255,0,255,255)); + ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); + ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); + ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,255,0,255)); + ImGui::PopTextWrapPos(); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("UTF-8 Text")) + { + // UTF-8 test with Japanese characters + // (Needs a suitable font, try Noto, or Arial Unicode, or M+ fonts. Read misc/fonts/README.txt for details.) + // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 + // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. Visual Studio save your file as 'UTF-8 without signature') + // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 CHARACTERS IN THIS SOURCE FILE. + // Instead we are encoding a few strings with hexadecimal constants. Don't do this in your application! + // Please use u8"text in any language" in your application! + // Note that characters values are preserved even by InputText() if the font cannot be displayed, so you can safely copy & paste garbled characters into another application. + ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. Read misc/fonts/README.txt for details."); + ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); // Normally we would use u8"blah blah" with the proper characters directly in the string. + ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); + static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; + //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis + ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf)); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Images")) + { + ImGuiIO& io = ImGui::GetIO(); + ImGui::TextWrapped("Below we are displaying the font texture (which is the only texture we have access to in this demo). Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. Hover the texture for a zoomed view!"); + + // Here we are grabbing the font texture because that's the only one we have access to inside the demo code. + // Remember that ImTextureID is just storage for whatever you want it to be, it is essentially a value that will be passed to the render function inside the ImDrawCmd structure. + // If you use one of the default imgui_impl_XXXX.cpp renderer, they all have comments at the top of their file to specify what they expect to be stored in ImTextureID. + // (for example, the imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. The imgui_impl_glfw_gl3.cpp renderer expect a GLuint OpenGL texture identifier etc.) + // If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers to ImGui::Image(), and gather width/height through your own functions, etc. + // Using ShowMetricsWindow() as a "debugger" to inspect the draw data that are being passed to your render will help you debug issues if you are confused about this. + // Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). + ImTextureID my_tex_id = io.Fonts->TexID; + float my_tex_w = (float)io.Fonts->TexWidth; + float my_tex_h = (float)io.Fonts->TexHeight; + + ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128)); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + float region_sz = 32.0f; + float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; if (region_x < 0.0f) region_x = 0.0f; else if (region_x > my_tex_w - region_sz) region_x = my_tex_w - region_sz; + float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; if (region_y < 0.0f) region_y = 0.0f; else if (region_y > my_tex_h - region_sz) region_y = my_tex_h - region_sz; + float zoom = 4.0f; + ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); + ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); + ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); + ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); + ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, ImColor(255,255,255,255), ImColor(255,255,255,128)); + ImGui::EndTooltip(); + } + ImGui::TextWrapped("And now some textured buttons.."); + static int pressed_count = 0; + for (int i = 0; i < 8; i++) + { + ImGui::PushID(i); + int frame_padding = -1 + i; // -1 = uses default padding + if (ImGui::ImageButton(my_tex_id, ImVec2(32,32), ImVec2(0,0), ImVec2(32.0f/my_tex_w,32/my_tex_h), frame_padding, ImColor(0,0,0,255))) + pressed_count += 1; + ImGui::PopID(); + ImGui::SameLine(); + } + ImGui::NewLine(); + ImGui::Text("Pressed %d times.", pressed_count); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Combo")) + { + // Expose flags as checkbox for the demo + static ImGuiComboFlags flags = 0; + ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft); + ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo"); + if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton)) + flags &= ~ImGuiComboFlags_NoPreview; // Clear the other flag, as we cannot combine both + if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", (unsigned int*)&flags, ImGuiComboFlags_NoPreview)) + flags &= ~ImGuiComboFlags_NoArrowButton; // Clear the other flag, as we cannot combine both + + // General BeginCombo() API, you have full control over your selection data and display type. + // (your selection data could be an index, a pointer to the object, an id for the object, a flag stored in the object itself, etc.) + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; + static const char* item_current = items[0]; // Here our selection is a single pointer stored outside the object. + if (ImGui::BeginCombo("combo 1", item_current, flags)) // The second parameter is the label previewed before opening the combo. + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + bool is_selected = (item_current == items[n]); + if (ImGui::Selectable(items[n], is_selected)) + item_current = items[n]; + if (is_selected) + ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch) + } + ImGui::EndCombo(); + } + + // Simplified one-liner Combo() API, using values packed in a single constant string + static int item_current_2 = 0; + ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); + + // Simplified one-liner Combo() using an array of const char* + static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview + ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); + + // Simplified one-liner Combo() using an accessor function + struct FuncHolder { static bool ItemGetter(void* data, int idx, const char** out_str) { *out_str = ((const char**)data)[idx]; return true; } }; + static int item_current_4 = 0; + ImGui::Combo("combo 4 (function)", &item_current_4, &FuncHolder::ItemGetter, items, IM_ARRAYSIZE(items)); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Selectables")) + { + // Selectable() has 2 overloads: + // - The one taking "bool selected" as a read-only selection information. When Selectable() has been clicked is returns true and you can alter selection state accordingly. + // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) + // The earlier is more flexible, as in real application your selection may be stored in a different manner (in flags within objects, as an external list, etc). + if (ImGui::TreeNode("Basic")) + { + static bool selection[5] = { false, true, false, false, false }; + ImGui::Selectable("1. I am selectable", &selection[0]); + ImGui::Selectable("2. I am selectable", &selection[1]); + ImGui::Text("3. I am not selectable"); + ImGui::Selectable("4. I am selectable", &selection[3]); + if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick)) + if (ImGui::IsMouseDoubleClicked(0)) + selection[4] = !selection[4]; + ImGui::TreePop(); + } + if (ImGui::TreeNode("Selection State: Single Selection")) + { + static int selected = -1; + for (int n = 0; n < 5; n++) + { + char buf[32]; + sprintf(buf, "Object %d", n); + if (ImGui::Selectable(buf, selected == n)) + selected = n; + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("Selection State: Multiple Selection")) + { + HelpMarker("Hold CTRL and click to select multiple items."); + static bool selection[5] = { false, false, false, false, false }; + for (int n = 0; n < 5; n++) + { + char buf[32]; + sprintf(buf, "Object %d", n); + if (ImGui::Selectable(buf, selection[n])) + { + if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held + memset(selection, 0, sizeof(selection)); + selection[n] ^= 1; + } + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("Rendering more text into the same line")) + { + // Using the Selectable() override that takes "bool* p_selected" parameter and toggle your booleans automatically. + static bool selected[3] = { false, false, false }; + ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); + ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(300); ImGui::Text("12,345 bytes"); + ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); + ImGui::TreePop(); + } + if (ImGui::TreeNode("In columns")) + { + ImGui::Columns(3, NULL, false); + static bool selected[16] = { 0 }; + for (int i = 0; i < 16; i++) + { + char label[32]; sprintf(label, "Item %d", i); + if (ImGui::Selectable(label, &selected[i])) {} + ImGui::NextColumn(); + } + ImGui::Columns(1); + ImGui::TreePop(); + } + if (ImGui::TreeNode("Grid")) + { + static bool selected[4*4] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true }; + for (int i = 0; i < 4*4; i++) + { + ImGui::PushID(i); + if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50,50))) + { + // Note: We _unnecessarily_ test for both x/y and i here only to silence some static analyzer. The second part of each test is unnecessary. + int x = i % 4; + int y = i / 4; + if (x > 0) { selected[i - 1] ^= 1; } + if (x < 3 && i < 15) { selected[i + 1] ^= 1; } + if (y > 0 && i > 3) { selected[i - 4] ^= 1; } + if (y < 3 && i < 12) { selected[i + 4] ^= 1; } + } + if ((i % 4) < 3) ImGui::SameLine(); + ImGui::PopID(); + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("Alignment")) + { + HelpMarker("Alignment applies when a selectable is larger than its text content.\nBy default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item basis using PushStyleVar()."); + static bool selected[3*3] = { true, false, true, false, true, false, true, false, true }; + for (int y = 0; y < 3; y++) + { + for (int x = 0; x < 3; x++) + { + ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f); + char name[32]; + sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y); + if (x > 0) ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment); + ImGui::Selectable(name, &selected[3*y+x], ImGuiSelectableFlags_None, ImVec2(80,80)); + ImGui::PopStyleVar(); + } + } + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Text Input")) + { + if (ImGui::TreeNode("Multi-line Text Input")) + { + // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize + // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings. + static char text[1024 * 16] = + "/*\n" + " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" + " the hexadecimal encoding of one offending instruction,\n" + " more formally, the invalid operand with locked CMPXCHG8B\n" + " instruction bug, is a design flaw in the majority of\n" + " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" + " processors (all in the P5 microarchitecture).\n" + "*/\n\n" + "label:\n" + "\tlock cmpxchg8b eax\n"; + + static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput; + HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp)"); + ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", (unsigned int*)&flags, ImGuiInputTextFlags_ReadOnly); + ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", (unsigned int*)&flags, ImGuiInputTextFlags_AllowTabInput); + ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", (unsigned int*)&flags, ImGuiInputTextFlags_CtrlEnterForNewLine); + ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16), flags); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Filtered Text Input")) + { + static char buf1[64] = ""; ImGui::InputText("default", buf1, 64); + static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal); + static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); + static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase); + static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank); + struct TextFilters { static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) { if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) return 0; return 1; } }; + static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); + + ImGui::Text("Password input"); + static char bufpass[64] = "password123"; + ImGui::InputText("password", bufpass, 64, ImGuiInputTextFlags_Password | ImGuiInputTextFlags_CharsNoBlank); + ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); + ImGui::InputTextWithHint("password (w/ hint)", "", bufpass, 64, ImGuiInputTextFlags_Password | ImGuiInputTextFlags_CharsNoBlank); + ImGui::InputText("password (clear)", bufpass, 64, ImGuiInputTextFlags_CharsNoBlank); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Resize Callback")) + { + // If you have a custom string type you would typically create a ImGui::InputText() wrapper than takes your type as input. + // See misc/cpp/imgui_stdlib.h and .cpp for an implementation of this using std::string. + HelpMarker("Demonstrate using ImGuiInputTextFlags_CallbackResize to wire your resizable string type to InputText().\n\nSee misc/cpp/imgui_stdlib.h for an implementation of this for std::string."); + struct Funcs + { + static int MyResizeCallback(ImGuiInputTextCallbackData* data) + { + if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) + { + ImVector* my_str = (ImVector*)data->UserData; + IM_ASSERT(my_str->begin() == data->Buf); + my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 + data->Buf = my_str->begin(); + } + return 0; + } + + // Tip: Because ImGui:: is a namespace you can add your own function into the namespace from your own source files. + static bool MyInputTextMultiline(const char* label, ImVector* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0) + { + IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); + return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str); + } + }; + + // For this demo we are using ImVector as a string container. + // Note that because we need to store a terminating zero character, our size/capacity are 1 more than usually reported by a typical string class. + static ImVector my_str; + if (my_str.empty()) + my_str.push_back(0); + Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16)); + ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity()); + ImGui::TreePop(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Plots Widgets")) + { + static bool animate = true; + ImGui::Checkbox("Animate", &animate); + + static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); + + // Create a dummy array of contiguous float values to plot + // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float and the sizeof() of your structure in the Stride parameter. + static float values[90] = { 0 }; + static int values_offset = 0; + static double refresh_time = 0.0; + if (!animate || refresh_time == 0.0) + refresh_time = ImGui::GetTime(); + while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 hz rate for the demo + { + static float phase = 0.0f; + values[values_offset] = cosf(phase); + values_offset = (values_offset+1) % IM_ARRAYSIZE(values); + phase += 0.10f*values_offset; + refresh_time += 1.0f/60.0f; + } + ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,80)); + ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0,80)); + + // Use functions to generate output + // FIXME: This is rather awkward because current plot API only pass in indices. We probably want an API passing floats and user provide sample rate/count. + struct Funcs + { + static float Sin(void*, int i) { return sinf(i * 0.1f); } + static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } + }; + static int func_type = 0, display_count = 70; + ImGui::Separator(); + ImGui::PushItemWidth(100); ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::PopItemWidth(); + ImGui::SameLine(); + ImGui::SliderInt("Sample count", &display_count, 1, 400); + float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; + ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80)); + ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80)); + ImGui::Separator(); + + // Animate a simple progress bar + static float progress = 0.0f, progress_dir = 1.0f; + if (animate) + { + progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime; + if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; } + if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; } + } + + // Typically we would use ImVec2(-1.0f,0.0f) to use all available width, or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. + ImGui::ProgressBar(progress, ImVec2(0.0f,0.0f)); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::Text("Progress Bar"); + + float progress_saturated = (progress < 0.0f) ? 0.0f : (progress > 1.0f) ? 1.0f : progress; + char buf[32]; + sprintf(buf, "%d/%d", (int)(progress_saturated*1753), 1753); + ImGui::ProgressBar(progress, ImVec2(0.f,0.f), buf); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Color/Picker Widgets")) + { + static ImVec4 color = ImVec4(114.0f/255.0f, 144.0f/255.0f, 154.0f/255.0f, 200.0f/255.0f); + + static bool alpha_preview = true; + static bool alpha_half_preview = false; + static bool drag_and_drop = true; + static bool options_menu = true; + static bool hdr = false; + ImGui::Checkbox("With Alpha Preview", &alpha_preview); + ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); + ImGui::Checkbox("With Drag and Drop", &drag_and_drop); + ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); + ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); + int misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions); + + ImGui::Text("Color widget:"); + ImGui::SameLine(); HelpMarker("Click on the colored square to open a color picker.\nCTRL+click on individual component to input value.\n"); + ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags); + + ImGui::Text("Color widget HSV with Alpha:"); + ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags); + + ImGui::Text("Color widget with Float Display:"); + ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags); + + ImGui::Text("Color button with Picker:"); + ImGui::SameLine(); HelpMarker("With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\nWith the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only be used for the tooltip and picker popup."); + ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags); + + ImGui::Text("Color button with Custom Picker Popup:"); + + // Generate a dummy default palette. The palette will persist and can be edited. + static bool saved_palette_init = true; + static ImVec4 saved_palette[32] = { }; + if (saved_palette_init) + { + for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) + { + ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); + saved_palette[n].w = 1.0f; // Alpha + } + saved_palette_init = false; + } + + static ImVec4 backup_color; + bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); + ImGui::SameLine(); + open_popup |= ImGui::Button("Palette"); + if (open_popup) + { + ImGui::OpenPopup("mypicker"); + backup_color = color; + } + if (ImGui::BeginPopup("mypicker")) + { + ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); + ImGui::Separator(); + ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); + ImGui::SameLine(); + + ImGui::BeginGroup(); // Lock X position + ImGui::Text("Current"); + ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40)); + ImGui::Text("Previous"); + if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40))) + color = backup_color; + ImGui::Separator(); + ImGui::Text("Palette"); + for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) + { + ImGui::PushID(n); + if ((n % 8) != 0) + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20,20))) + color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! + + // Allow user to drop colors into each palette entry + // (Note that ColorButton is already a drag source by default, unless using ImGuiColorEditFlags_NoDragDrop) + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); + ImGui::EndDragDropTarget(); + } + + ImGui::PopID(); + } + ImGui::EndGroup(); + ImGui::EndPopup(); + } + + ImGui::Text("Color button only:"); + ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags, ImVec2(80,80)); + + ImGui::Text("Color picker:"); + static bool alpha = true; + static bool alpha_bar = true; + static bool side_preview = true; + static bool ref_color = false; + static ImVec4 ref_color_v(1.0f,0.0f,1.0f,0.5f); + static int display_mode = 0; + static int picker_mode = 0; + ImGui::Checkbox("With Alpha", &alpha); + ImGui::Checkbox("With Alpha Bar", &alpha_bar); + ImGui::Checkbox("With Side Preview", &side_preview); + if (side_preview) + { + ImGui::SameLine(); + ImGui::Checkbox("With Ref Color", &ref_color); + if (ref_color) + { + ImGui::SameLine(); + ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags); + } + } + ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0"); + ImGui::SameLine(); HelpMarker("ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, but the user can change it with a right-click.\n\nColorPicker defaults to displaying RGB+HSV+Hex if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); + ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0"); + ImGui::SameLine(); HelpMarker("User can right-click the picker to change mode."); + ImGuiColorEditFlags flags = misc_flags; + if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4() + if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar; + if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview; + if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; + if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; + if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays + if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode + if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV; + if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex; + ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); + + ImGui::Text("Programmatically set defaults:"); + ImGui::SameLine(); HelpMarker("SetColorEditOptions() is designed to allow you to set boot-time default.\nWe don't have Push/Pop functions because you can force options on a per-widget basis if needed, and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid encouraging you to persistently save values that aren't forward-compatible."); + if (ImGui::Button("Default: Uint8 + HSV + Hue Bar")) + ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar); + if (ImGui::Button("Default: Float + HDR + Hue Wheel")) + ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel); + + // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) + static ImVec4 color_stored_as_hsv(0.23f, 1.0f, 1.0f, 1.0f); + ImGui::Spacing(); + ImGui::Text("HSV encoded colors"); + ImGui::SameLine(); HelpMarker("By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); + ImGui::Text("Color widget with InputHSV:"); + ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_stored_as_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); + ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_stored_as_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); + ImGui::DragFloat4("Raw HSV values", (float*)&color_stored_as_hsv, 0.01f, 0.0f, 1.0f); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Range Widgets")) + { + static float begin = 10, end = 90; + static int begin_i = 100, end_i = 1000; + ImGui::DragFloatRange2("range", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); + ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units"); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Data Types")) + { + // The DragScalar/InputScalar/SliderScalar functions allow various data types: signed/unsigned int/long long and float/double + // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum to pass the type, + // and passing all arguments by address. + // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types. + // In practice, if you frequently use a given type that is not covered by the normal API entry points, you can wrap it + // yourself inside a 1 line function which can take typed argument as value instead of void*, and then pass their address + // to the generic function. For example: + // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") + // { + // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); + // } + + // Limits (as helper variables that we can take the address of) + // Note that the SliderScalar function has a maximum usable range of half the natural type maximum, hence the /2 below. + #ifndef LLONG_MIN + ImS64 LLONG_MIN = -9223372036854775807LL - 1; + ImS64 LLONG_MAX = 9223372036854775807LL; + ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1); + #endif + const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127; + const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255; + const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767; + const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535; + const ImS32 s32_zero = 0, s32_one = 1, s32_fifty = 50, s32_min = INT_MIN/2, s32_max = INT_MAX/2, s32_hi_a = INT_MAX/2 - 100, s32_hi_b = INT_MAX/2; + const ImU32 u32_zero = 0, u32_one = 1, u32_fifty = 50, u32_min = 0, u32_max = UINT_MAX/2, u32_hi_a = UINT_MAX/2 - 100, u32_hi_b = UINT_MAX/2; + const ImS64 s64_zero = 0, s64_one = 1, s64_fifty = 50, s64_min = LLONG_MIN/2, s64_max = LLONG_MAX/2, s64_hi_a = LLONG_MAX/2 - 100, s64_hi_b = LLONG_MAX/2; + const ImU64 u64_zero = 0, u64_one = 1, u64_fifty = 50, u64_min = 0, u64_max = ULLONG_MAX/2, u64_hi_a = ULLONG_MAX/2 - 100, u64_hi_b = ULLONG_MAX/2; + const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f; + const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0; + + // State + static char s8_v = 127; + static ImU8 u8_v = 255; + static short s16_v = 32767; + static ImU16 u16_v = 65535; + static ImS32 s32_v = -1; + static ImU32 u32_v = (ImU32)-1; + static ImS64 s64_v = -1; + static ImU64 u64_v = (ImU64)-1; + static float f32_v = 0.123f; + static double f64_v = 90000.01234567890123456789; + + const float drag_speed = 0.2f; + static bool drag_clamp = false; + ImGui::Text("Drags:"); + ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); ImGui::SameLine(); HelpMarker("As with every widgets in dear imgui, we never modify values unless there is a user interaction.\nYou can override the clamping limits by using CTRL+Click to input a value."); + ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL); + ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL); + ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL); + ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL); + ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL); + ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", 1.0f); + ImGui::DragScalar("drag float ^2", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", 2.0f); ImGui::SameLine(); HelpMarker("You can use the 'power' parameter to increase tweaking precision on one side of the range."); + ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams", 1.0f); + ImGui::DragScalar("drag double ^2", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", 2.0f); + + ImGui::Text("Sliders"); + ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); + ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); + ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); + ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u"); + ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d"); + ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d"); + ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d"); + ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); + ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); + ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); + ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%I64d"); + ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%I64d"); + ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%I64d"); + ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%I64u ms"); + ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%I64u ms"); + ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%I64u ms"); + ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); + ImGui::SliderScalar("slider float low^2", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", 2.0f); + ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); + ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams", 1.0f); + ImGui::SliderScalar("slider double low^2",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", 2.0f); + ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams", 1.0f); + + static bool inputs_step = true; + ImGui::Text("Inputs"); + ImGui::Checkbox("Show step buttons", &inputs_step); + ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d"); + ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u"); + ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d"); + ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u"); + ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d"); + ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); + ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u"); + ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); + ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL); + ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL); + ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL); + ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Multi-component Widgets")) + { + static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; + static int vec4i[4] = { 1, 5, 100, 255 }; + + ImGui::InputFloat2("input float2", vec4f); + ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); + ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); + ImGui::InputInt2("input int2", vec4i); + ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); + ImGui::SliderInt2("slider int2", vec4i, 0, 255); + ImGui::Spacing(); + + ImGui::InputFloat3("input float3", vec4f); + ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); + ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); + ImGui::InputInt3("input int3", vec4i); + ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); + ImGui::SliderInt3("slider int3", vec4i, 0, 255); + ImGui::Spacing(); + + ImGui::InputFloat4("input float4", vec4f); + ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); + ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); + ImGui::InputInt4("input int4", vec4i); + ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); + ImGui::SliderInt4("slider int4", vec4i, 0, 255); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Vertical Sliders")) + { + const float spacing = 4; + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); + + static int int_value = 0; + ImGui::VSliderInt("##int", ImVec2(18,160), &int_value, 0, 5); + ImGui::SameLine(); + + static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; + ImGui::PushID("set1"); + for (int i = 0; i < 7; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i/7.0f, 0.5f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i/7.0f, 0.7f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i/7.0f, 0.9f, 0.9f)); + ImGui::VSliderFloat("##v", ImVec2(18,160), &values[i], 0.0f, 1.0f, ""); + if (ImGui::IsItemActive() || ImGui::IsItemHovered()) + ImGui::SetTooltip("%.3f", values[i]); + ImGui::PopStyleColor(4); + ImGui::PopID(); + } + ImGui::PopID(); + + ImGui::SameLine(); + ImGui::PushID("set2"); + static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f }; + const int rows = 3; + const ImVec2 small_slider_size(18, (160.0f-(rows-1)*spacing)/rows); + for (int nx = 0; nx < 4; nx++) + { + if (nx > 0) ImGui::SameLine(); + ImGui::BeginGroup(); + for (int ny = 0; ny < rows; ny++) + { + ImGui::PushID(nx*rows+ny); + ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, ""); + if (ImGui::IsItemActive() || ImGui::IsItemHovered()) + ImGui::SetTooltip("%.3f", values2[nx]); + ImGui::PopID(); + } + ImGui::EndGroup(); + } + ImGui::PopID(); + + ImGui::SameLine(); + ImGui::PushID("set3"); + for (int i = 0; i < 4; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40); + ImGui::VSliderFloat("##v", ImVec2(40,160), &values[i], 0.0f, 1.0f, "%.2f\nsec"); + ImGui::PopStyleVar(); + ImGui::PopID(); + } + ImGui::PopID(); + ImGui::PopStyleVar(); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Drag and Drop")) + { + { + // ColorEdit widgets automatically act as drag source and drag target. + // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F to allow your own widgets + // to use colors in their drag and drop interaction. Also see the demo in Color Picker -> Palette demo. + ImGui::BulletText("Drag and drop in standard widgets"); + ImGui::Indent(); + static float col1[3] = { 1.0f,0.0f,0.2f }; + static float col2[4] = { 0.4f,0.7f,0.0f,0.5f }; + ImGui::ColorEdit3("color 1", col1); + ImGui::ColorEdit4("color 2", col2); + ImGui::Unindent(); + } + + { + ImGui::BulletText("Drag and drop to copy/swap items"); + ImGui::Indent(); + enum Mode + { + Mode_Copy, + Mode_Move, + Mode_Swap + }; + static int mode = 0; + if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); + if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); + if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } + static const char* names[9] = { "Bobby", "Beatrice", "Betty", "Brianna", "Barry", "Bernard", "Bibi", "Blaine", "Bryn" }; + for (int n = 0; n < IM_ARRAYSIZE(names); n++) + { + ImGui::PushID(n); + if ((n % 3) != 0) + ImGui::SameLine(); + ImGui::Button(names[n], ImVec2(60,60)); + + // Our buttons are both drag sources and drag targets here! + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) + { + ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); // Set payload to carry the index of our item (could be anything) + if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } // Display preview (could be anything, e.g. when dragging an image we could decide to display the filename and a small preview of the image, etc.) + if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); } + if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); } + ImGui::EndDragDropSource(); + } + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL")) + { + IM_ASSERT(payload->DataSize == sizeof(int)); + int payload_n = *(const int*)payload->Data; + if (mode == Mode_Copy) + { + names[n] = names[payload_n]; + } + if (mode == Mode_Move) + { + names[n] = names[payload_n]; + names[payload_n] = ""; + } + if (mode == Mode_Swap) + { + const char* tmp = names[n]; + names[n] = names[payload_n]; + names[payload_n] = tmp; + } + } + ImGui::EndDragDropTarget(); + } + ImGui::PopID(); + } + ImGui::Unindent(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Querying Status (Active/Focused/Hovered etc.)")) + { + // Display the value of IsItemHovered() and other common item state functions. Note that the flags can be combined. + // (because BulletText is an item itself and that would affect the output of IsItemHovered() we pass all state in a single call to simplify the code). + static int item_type = 1; + static bool b = false; + static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; + static char str[16] = {}; + ImGui::RadioButton("Text", &item_type, 0); + ImGui::RadioButton("Button", &item_type, 1); + ImGui::RadioButton("Checkbox", &item_type, 2); + ImGui::RadioButton("SliderFloat", &item_type, 3); + ImGui::RadioButton("InputText", &item_type, 4); + ImGui::RadioButton("ColorEdit4", &item_type, 5); + ImGui::RadioButton("ListBox", &item_type, 6); + ImGui::Separator(); + bool ret = false; + if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction + if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button + if (item_type == 2) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox + if (item_type == 3) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item + if (item_type == 4) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) + if (item_type == 5) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 6) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } + ImGui::BulletText( + "Return value = %d\n" + "IsItemFocused() = %d\n" + "IsItemHovered() = %d\n" + "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" + "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" + "IsItemHovered(_AllowWhenOverlapped) = %d\n" + "IsItemHovered(_RectOnly) = %d\n" + "IsItemActive() = %d\n" + "IsItemEdited() = %d\n" + "IsItemActivated() = %d\n" + "IsItemDeactivated() = %d\n" + "IsItemDeactivatedEdit() = %d\n" + "IsItemVisible() = %d\n" + "GetItemRectMin() = (%.1f, %.1f)\n" + "GetItemRectMax() = (%.1f, %.1f)\n" + "GetItemRectSize() = (%.1f, %.1f)", + ret, + ImGui::IsItemFocused(), + ImGui::IsItemHovered(), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), + ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), + ImGui::IsItemActive(), + ImGui::IsItemEdited(), + ImGui::IsItemActivated(), + ImGui::IsItemDeactivated(), + ImGui::IsItemDeactivatedAfterEdit(), + ImGui::IsItemVisible(), + ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y, + ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, + ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y + ); + + static bool embed_all_inside_a_child_window = false; + ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window); + if (embed_all_inside_a_child_window) + ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20), true); + + // Testing IsWindowFocused() function with its various flags. Note that the flags can be combined. + ImGui::BulletText( + "IsWindowFocused() = %d\n" + "IsWindowFocused(_ChildWindows) = %d\n" + "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" + "IsWindowFocused(_RootWindow) = %d\n" + "IsWindowFocused(_AnyWindow) = %d\n", + ImGui::IsWindowFocused(), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); + + // Testing IsWindowHovered() function with its various flags. Note that the flags can be combined. + ImGui::BulletText( + "IsWindowHovered() = %d\n" + "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" + "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" + "IsWindowHovered(_ChildWindows) = %d\n" + "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" + "IsWindowHovered(_RootWindow) = %d\n" + "IsWindowHovered(_AnyWindow) = %d\n", + ImGui::IsWindowHovered(), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), + ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); + + ImGui::BeginChild("child", ImVec2(0, 50), true); + ImGui::Text("This is another child window for testing the _ChildWindows flag."); + ImGui::EndChild(); + if (embed_all_inside_a_child_window) + ImGui::EndChild(); + + // Calling IsItemHovered() after begin returns the hovered status of the title bar. + // This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window. + static bool test_window = false; + ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); + if (test_window) + { + ImGui::Begin("Title bar Hovered/Active tests", &test_window); + if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered() + { + if (ImGui::MenuItem("Close")) { test_window = false; } + ImGui::EndPopup(); + } + ImGui::Text( + "IsItemHovered() after begin = %d (== is title bar hovered)\n" + "IsItemActive() after begin = %d (== is window being clicked/moved)\n", + ImGui::IsItemHovered(), ImGui::IsItemActive()); + ImGui::End(); + } + + ImGui::TreePop(); + } +} + +static void ShowDemoWindowLayout() +{ + if (!ImGui::CollapsingHeader("Layout")) + return; + + if (ImGui::TreeNode("Child windows")) + { + HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); + static bool disable_mouse_wheel = false; + static bool disable_menu = false; + ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel); + ImGui::Checkbox("Disable Menu", &disable_menu); + + static int line = 50; + bool goto_line = ImGui::Button("Goto"); + ImGui::SameLine(); + ImGui::PushItemWidth(100); + goto_line |= ImGui::InputInt("##Line", &line, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue); + ImGui::PopItemWidth(); + + // Child 1: no border, enable horizontal scrollbar + { + ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar | (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0); + ImGui::BeginChild("Child1", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags); + for (int i = 0; i < 100; i++) + { + ImGui::Text("%04d: scrollable region", i); + if (goto_line && line == i) + ImGui::SetScrollHereY(); + } + if (goto_line && line >= 100) + ImGui::SetScrollHereY(); + ImGui::EndChild(); + } + + ImGui::SameLine(); + + // Child 2: rounded border + { + ImGuiWindowFlags window_flags = (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0) | (disable_menu ? 0 : ImGuiWindowFlags_MenuBar); + ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); + ImGui::BeginChild("Child2", ImVec2(0, 260), true, window_flags); + if (!disable_menu && ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("Menu")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + ImGui::Columns(2); + for (int i = 0; i < 100; i++) + { + char buf[32]; + sprintf(buf, "%03d", i); + ImGui::Button(buf, ImVec2(-1.0f, 0.0f)); + ImGui::NextColumn(); + } + ImGui::EndChild(); + ImGui::PopStyleVar(); + } + + ImGui::Separator(); + + // Demonstrate a few extra things + // - Changing ImGuiCol_ChildBg (which is transparent black in default styles) + // - Using SetCursorPos() to position the child window (because the child window is an item from the POV of the parent window) + // You can also call SetNextWindowPos() to position the child window. The parent window will effectively layout from this position. + // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from the POV of the parent window) + // See "Widgets" -> "Querying Status (Active/Focused/Hovered etc.)" section for more details about this. + { + ImGui::SetCursorPosX(50); + ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); + ImGui::BeginChild("blah", ImVec2(200, 100), true, ImGuiWindowFlags_None); + for (int n = 0; n < 50; n++) + ImGui::Text("Some test %d", n); + ImGui::EndChild(); + ImVec2 child_rect_min = ImGui::GetItemRectMin(); + ImVec2 child_rect_max = ImGui::GetItemRectMax(); + ImGui::PopStyleColor(); + ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Widgets Width")) + { + static float f = 0.0f; + ImGui::Text("PushItemWidth(100)"); + ImGui::SameLine(); HelpMarker("Fixed width."); + ImGui::PushItemWidth(100); + ImGui::DragFloat("float##1", &f); + ImGui::PopItemWidth(); + + ImGui::Text("PushItemWidth(GetWindowWidth() * 0.5f)"); + ImGui::SameLine(); HelpMarker("Half of window width."); + ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f); + ImGui::DragFloat("float##2", &f); + ImGui::PopItemWidth(); + + ImGui::Text("PushItemWidth(GetContentRegionAvailWidth() * 0.5f)"); + ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); + ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() * 0.5f); + ImGui::DragFloat("float##3", &f); + ImGui::PopItemWidth(); + + ImGui::Text("PushItemWidth(-100)"); + ImGui::SameLine(); HelpMarker("Align to right edge minus 100"); + ImGui::PushItemWidth(-100); + ImGui::DragFloat("float##4", &f); + ImGui::PopItemWidth(); + + ImGui::Text("PushItemWidth(-1)"); + ImGui::SameLine(); HelpMarker("Align to right edge"); + ImGui::PushItemWidth(-1); + ImGui::DragFloat("float##5", &f); + ImGui::PopItemWidth(); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Basic Horizontal Layout")) + { + ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)"); + + // Text + ImGui::Text("Two items: Hello"); ImGui::SameLine(); + ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); + + // Adjust spacing + ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); + ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); + + // Button + ImGui::AlignTextToFramePadding(); + ImGui::Text("Normal buttons"); ImGui::SameLine(); + ImGui::Button("Banana"); ImGui::SameLine(); + ImGui::Button("Apple"); ImGui::SameLine(); + ImGui::Button("Corniflower"); + + // Button + ImGui::Text("Small buttons"); ImGui::SameLine(); + ImGui::SmallButton("Like this one"); ImGui::SameLine(); + ImGui::Text("can fit within a text block."); + + // Aligned to arbitrary position. Easy/cheap column. + ImGui::Text("Aligned"); + ImGui::SameLine(150); ImGui::Text("x=150"); + ImGui::SameLine(300); ImGui::Text("x=300"); + ImGui::Text("Aligned"); + ImGui::SameLine(150); ImGui::SmallButton("x=150"); + ImGui::SameLine(300); ImGui::SmallButton("x=300"); + + // Checkbox + static bool c1 = false, c2 = false, c3 = false, c4 = false; + ImGui::Checkbox("My", &c1); ImGui::SameLine(); + ImGui::Checkbox("Tailor", &c2); ImGui::SameLine(); + ImGui::Checkbox("Is", &c3); ImGui::SameLine(); + ImGui::Checkbox("Rich", &c4); + + // Various + static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f; + ImGui::PushItemWidth(80); + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" }; + static int item = -1; + ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); + ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine(); + ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine(); + ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f); + ImGui::PopItemWidth(); + + ImGui::PushItemWidth(80); + ImGui::Text("Lists:"); + static int selection[4] = { 0, 1, 2, 3 }; + for (int i = 0; i < 4; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items)); + ImGui::PopID(); + //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i); + } + ImGui::PopItemWidth(); + + // Dummy + ImVec2 button_sz(40, 40); + ImGui::Button("A", button_sz); ImGui::SameLine(); + ImGui::Dummy(button_sz); ImGui::SameLine(); + ImGui::Button("B", button_sz); + + // Manually wrapping (we should eventually provide this as an automatic layout feature, but for now you can do it manually) + ImGui::Text("Manually wrapping:"); + ImGuiStyle& style = ImGui::GetStyle(); + int buttons_count = 20; + float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x; + for (int n = 0; n < buttons_count; n++) + { + ImGui::PushID(n); + ImGui::Button("Box", button_sz); + float last_button_x2 = ImGui::GetItemRectMax().x; + float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line + if (n + 1 < buttons_count && next_button_x2 < window_visible_x2) + ImGui::SameLine(); + ImGui::PopID(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Tabs")) + { + if (ImGui::TreeNode("Basic")) + { + ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + if (ImGui::BeginTabItem("Avocado")) + { + ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Broccoli")) + { + ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Cucumber")) + { + ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Advanced & Close Button")) + { + // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). + static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; + ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); + ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); + ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); + if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) + tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); + + // Tab Bar + const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; + static bool opened[4] = { true, true, true, true }; // Persistent user state + for (int n = 0; n < IM_ARRAYSIZE(opened); n++) + { + if (n > 0) { ImGui::SameLine(); } + ImGui::Checkbox(names[n], &opened[n]); + } + + // Passing a bool* to BeginTabItem() is similar to passing one to Begin(): the underlying bool will be set to false when the tab is closed. + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + for (int n = 0; n < IM_ARRAYSIZE(opened); n++) + if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n])) + { + ImGui::Text("This is the %s tab!", names[n]); + if (n & 1) + ImGui::Text("I am an odd tab."); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Groups")) + { + HelpMarker("Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it."); + ImGui::BeginGroup(); + { + ImGui::BeginGroup(); + ImGui::Button("AAA"); + ImGui::SameLine(); + ImGui::Button("BBB"); + ImGui::SameLine(); + ImGui::BeginGroup(); + ImGui::Button("CCC"); + ImGui::Button("DDD"); + ImGui::EndGroup(); + ImGui::SameLine(); + ImGui::Button("EEE"); + ImGui::EndGroup(); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("First group hovered"); + } + // Capture the group size and create widgets using the same size + ImVec2 size = ImGui::GetItemRectSize(); + const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f }; + ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size); + + ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y)); + ImGui::SameLine(); + ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y)); + ImGui::EndGroup(); + ImGui::SameLine(); + + ImGui::Button("LEVERAGE\nBUZZWORD", size); + ImGui::SameLine(); + + if (ImGui::ListBoxHeader("List", size)) + { + ImGui::Selectable("Selected", true); + ImGui::Selectable("Not Selected", false); + ImGui::ListBoxFooter(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Text Baseline Alignment")) + { + HelpMarker("This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets."); + + ImGui::Text("One\nTwo\nThree"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + + ImGui::Text("Banana"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("One\nTwo\nThree"); + + ImGui::Button("HOP##1"); ImGui::SameLine(); + ImGui::Text("Banana"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + + ImGui::Button("HOP##2"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + + ImGui::Button("TEST##1"); ImGui::SameLine(); + ImGui::Text("TEST"); ImGui::SameLine(); + ImGui::SmallButton("TEST##2"); + + ImGui::AlignTextToFramePadding(); // If your line starts with text, call this to align it to upcoming widgets. + ImGui::Text("Text aligned to Widget"); ImGui::SameLine(); + ImGui::Button("Widget##1"); ImGui::SameLine(); + ImGui::Text("Widget"); ImGui::SameLine(); + ImGui::SmallButton("Widget##2"); ImGui::SameLine(); + ImGui::Button("Widget##3"); + + // Tree + const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; + ImGui::Button("Button##1"); + ImGui::SameLine(0.0f, spacing); + if (ImGui::TreeNode("Node##1")) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data + + ImGui::AlignTextToFramePadding(); // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. Otherwise you can use SmallButton (smaller fit). + bool node_open = ImGui::TreeNode("Node##2"); // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add child content. + ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); + if (node_open) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data + + // Bullet + ImGui::Button("Button##3"); + ImGui::SameLine(0.0f, spacing); + ImGui::BulletText("Bullet text"); + + ImGui::AlignTextToFramePadding(); + ImGui::BulletText("Node"); + ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4"); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Scrolling")) + { + HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given position."); + + static bool track = true; + static int track_line = 50, scroll_to_px = 200; + ImGui::Checkbox("Track", &track); + ImGui::PushItemWidth(100); + ImGui::SameLine(130); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %d"); + bool scroll_to = ImGui::Button("Scroll To Pos"); + ImGui::SameLine(130); scroll_to |= ImGui::DragInt("##pos_y", &scroll_to_px, 1.00f, 0, 9999, "Y = %d px"); + ImGui::PopItemWidth(); + if (scroll_to) track = false; + + for (int i = 0; i < 5; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::BeginGroup(); + ImGui::Text("%s", i == 0 ? "Top" : i == 1 ? "25%" : i == 2 ? "Center" : i == 3 ? "75%" : "Bottom"); + ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(ImGui::GetWindowWidth() * 0.17f, 200.0f), true); + if (scroll_to) + ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_px, i * 0.25f); + for (int line = 0; line < 100; line++) + { + if (track && line == track_line) + { + ImGui::TextColored(ImVec4(1,1,0,1), "Line %d", line); + ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom + } + else + { + ImGui::Text("Line %d", line); + } + } + float scroll_y = ImGui::GetScrollY(), scroll_max_y = ImGui::GetScrollMaxY(); + ImGui::EndChild(); + ImGui::Text("%.0f/%0.f", scroll_y, scroll_max_y); + ImGui::EndGroup(); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Horizontal Scrolling")) + { + HelpMarker("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\nYou may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin()."); + static int lines = 7; + ImGui::SliderInt("Lines", &lines, 1, 15); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); + ImGui::BeginChild("scrolling", ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30), true, ImGuiWindowFlags_HorizontalScrollbar); + for (int line = 0; line < lines; line++) + { + // Display random stuff (for the sake of this trivial demo we are using basic Button+SameLine. If you want to create your own time line for a real application you may be better off + // manipulating the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets yourself. You may also want to use the lower-level ImDrawList API) + int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); + for (int n = 0; n < num_buttons; n++) + { + if (n > 0) ImGui::SameLine(); + ImGui::PushID(n + line * 1000); + char num_buf[16]; + sprintf(num_buf, "%d", n); + const char* label = (!(n%15)) ? "FizzBuzz" : (!(n%3)) ? "Fizz" : (!(n%5)) ? "Buzz" : num_buf; + float hue = n*0.05f; + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f)); + ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f)); + ImGui::PopStyleColor(3); + ImGui::PopID(); + } + } + float scroll_x = ImGui::GetScrollX(), scroll_max_x = ImGui::GetScrollMaxX(); + ImGui::EndChild(); + ImGui::PopStyleVar(2); + float scroll_x_delta = 0.0f; + ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) { scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine(); + ImGui::Text("Scroll from code"); ImGui::SameLine(); + ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) { scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine(); + ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); + if (scroll_x_delta != 0.0f) + { + ImGui::BeginChild("scrolling"); // Demonstrate a trick: you can use Begin to set yourself in the context of another window (here we are already out of your child window) + ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); + ImGui::EndChild(); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Clipping")) + { + static ImVec2 size(100, 100), offset(50, 20); + ImGui::TextWrapped("On a per-widget basis we are occasionally clipping text CPU-side if it won't fit in its frame. Otherwise we are doing coarser clipping + passing a scissor rectangle to the renderer. The system is designed to try minimizing both execution and CPU/GPU rendering cost."); + ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f"); + ImGui::TextWrapped("(Click and drag)"); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImVec4 clip_rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); + ImGui::InvisibleButton("##dummy", size); + if (ImGui::IsItemActive() && ImGui::IsMouseDragging()) { offset.x += ImGui::GetIO().MouseDelta.x; offset.y += ImGui::GetIO().MouseDelta.y; } + ImGui::GetWindowDrawList()->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y), IM_COL32(90, 90, 120, 255)); + ImGui::GetWindowDrawList()->AddText(ImGui::GetFont(), ImGui::GetFontSize()*2.0f, ImVec2(pos.x + offset.x, pos.y + offset.y), IM_COL32(255, 255, 255, 255), "Line 1 hello\nLine 2 clip me!", NULL, 0.0f, &clip_rect); + ImGui::TreePop(); + } +} + +static void ShowDemoWindowPopups() +{ + if (!ImGui::CollapsingHeader("Popups & Modal windows")) + return; + + // The properties of popups windows are: + // - They block normal mouse hovering detection outside them. (*) + // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. + // - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls. + // User can manipulate the visibility state by calling OpenPopup(). + // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup. + // Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time. + + // Typical use for regular windows: + // bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End(); + // Typical use for popups: + // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); } + + // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. + // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. + + if (ImGui::TreeNode("Popups")) + { + ImGui::TextWrapped("When a popup is active, it inhibits interacting with windows that are behind the popup. Clicking outside the popup closes it."); + + static int selected_fish = -1; + const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; + static bool toggles[] = { true, false, false, false, false }; + + // Simple selection popup + // (If you want to show the current selection inside the Button itself, you may want to build a string using the "###" operator to preserve a constant ID with a variable label) + if (ImGui::Button("Select..")) + ImGui::OpenPopup("my_select_popup"); + ImGui::SameLine(); + ImGui::TextUnformatted(selected_fish == -1 ? "" : names[selected_fish]); + if (ImGui::BeginPopup("my_select_popup")) + { + ImGui::Text("Aquarium"); + ImGui::Separator(); + for (int i = 0; i < IM_ARRAYSIZE(names); i++) + if (ImGui::Selectable(names[i])) + selected_fish = i; + ImGui::EndPopup(); + } + + // Showing a menu with toggles + if (ImGui::Button("Toggle..")) + ImGui::OpenPopup("my_toggle_popup"); + if (ImGui::BeginPopup("my_toggle_popup")) + { + for (int i = 0; i < IM_ARRAYSIZE(names); i++) + ImGui::MenuItem(names[i], "", &toggles[i]); + if (ImGui::BeginMenu("Sub-menu")) + { + ImGui::MenuItem("Click me"); + ImGui::EndMenu(); + } + + ImGui::Separator(); + ImGui::Text("Tooltip here"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("I am a tooltip over a popup"); + + if (ImGui::Button("Stacked Popup")) + ImGui::OpenPopup("another popup"); + if (ImGui::BeginPopup("another popup")) + { + for (int i = 0; i < IM_ARRAYSIZE(names); i++) + ImGui::MenuItem(names[i], "", &toggles[i]); + if (ImGui::BeginMenu("Sub-menu")) + { + ImGui::MenuItem("Click me"); + ImGui::EndMenu(); + } + ImGui::EndPopup(); + } + ImGui::EndPopup(); + } + + // Call the more complete ShowExampleMenuFile which we use in various places of this demo + if (ImGui::Button("File Menu..")) + ImGui::OpenPopup("my_file_popup"); + if (ImGui::BeginPopup("my_file_popup")) + { + ShowExampleMenuFile(); + ImGui::EndPopup(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Context menus")) + { + // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: + // if (IsItemHovered() && IsMouseReleased(0)) + // OpenPopup(id); + // return BeginPopup(id); + // For more advanced uses you may want to replicate and cuztomize this code. This the comments inside BeginPopupContextItem() implementation. + static float value = 0.5f; + ImGui::Text("Value = %.3f (<-- right-click here)", value); + if (ImGui::BeginPopupContextItem("item context menu")) + { + if (ImGui::Selectable("Set to zero")) value = 0.0f; + if (ImGui::Selectable("Set to PI")) value = 3.1415f; + ImGui::PushItemWidth(-1); + ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); + ImGui::PopItemWidth(); + ImGui::EndPopup(); + } + + // We can also use OpenPopupOnItemClick() which is the same as BeginPopupContextItem() but without the Begin call. + // So here we will make it that clicking on the text field with the right mouse button (1) will toggle the visibility of the popup above. + ImGui::Text("(You can also right-click me to open the same popup as above.)"); + ImGui::OpenPopupOnItemClick("item context menu", 1); + + // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem(). + // BeginPopupContextItem() will use the last item ID as the popup ID. + // In addition here, we want to include your editable label inside the button label. We use the ### operator to override the ID (read FAQ about ID for details) + static char name[32] = "Label1"; + char buf[64]; sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label + ImGui::Button(buf); + if (ImGui::BeginPopupContextItem()) + { + ImGui::Text("Edit name:"); + ImGui::InputText("##edit", name, IM_ARRAYSIZE(name)); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + ImGui::SameLine(); ImGui::Text("(<-- right-click here)"); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Modals")) + { + ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside the window."); + + if (ImGui::Button("Delete..")) + ImGui::OpenPopup("Delete?"); + + if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); + ImGui::Separator(); + + //static int dummy_i = 0; + //ImGui::Combo("Combo", &dummy_i, "Delete\0Delete harder\0"); + + static bool dont_ask_me_next_time = false; + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time); + ImGui::PopStyleVar(); + + if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } + ImGui::SetItemDefaultFocus(); + ImGui::SameLine(); + if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } + ImGui::EndPopup(); + } + + if (ImGui::Button("Stacked modals..")) + ImGui::OpenPopup("Stacked 1"); + if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar)) + { + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("Dummy menu item")) {} + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it."); + + // Testing behavior of widgets stacking their own regular popups over the modal. + static int item = 1; + static float color[4] = { 0.4f,0.7f,0.0f,0.5f }; + ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); + ImGui::ColorEdit4("color", color); + + if (ImGui::Button("Add another modal..")) + ImGui::OpenPopup("Stacked 2"); + + // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which will close the popup. + // Note that the visibility state of popups is owned by imgui, so the input value of the bool actually doesn't matter here. + bool dummy_open = true; + if (ImGui::BeginPopupModal("Stacked 2", &dummy_open)) + { + ImGui::Text("Hello from Stacked The Second!"); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Menus inside a regular window")) + { + ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); + ImGui::Separator(); + // NB: As a quirk in this very specific example, we want to differentiate the parent of this menu from the parent of the various popup menus above. + // To do so we are encloding the items in a PushID()/PopID() block to make them two different menusets. If we don't, opening any popup above and hovering our menu here + // would open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, which is the desired behavior for regular menus. + ImGui::PushID("foo"); + ImGui::MenuItem("Menu item", "CTRL+M"); + if (ImGui::BeginMenu("Menu inside a regular window")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + ImGui::PopID(); + ImGui::Separator(); + ImGui::TreePop(); + } +} + +static void ShowDemoWindowColumns() +{ + if (!ImGui::CollapsingHeader("Columns")) + return; + + ImGui::PushID("Columns"); + + // Basic columns + if (ImGui::TreeNode("Basic")) + { + ImGui::Text("Without border:"); + ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border + ImGui::Separator(); + for (int n = 0; n < 14; n++) + { + char label[32]; + sprintf(label, "Item %d", n); + if (ImGui::Selectable(label)) {} + //if (ImGui::Button(label, ImVec2(-1,0))) {} + ImGui::NextColumn(); + } + ImGui::Columns(1); + ImGui::Separator(); + + ImGui::Text("With border:"); + ImGui::Columns(4, "mycolumns"); // 4-ways, with border + ImGui::Separator(); + ImGui::Text("ID"); ImGui::NextColumn(); + ImGui::Text("Name"); ImGui::NextColumn(); + ImGui::Text("Path"); ImGui::NextColumn(); + ImGui::Text("Hovered"); ImGui::NextColumn(); + ImGui::Separator(); + const char* names[3] = { "One", "Two", "Three" }; + const char* paths[3] = { "/path/one", "/path/two", "/path/three" }; + static int selected = -1; + for (int i = 0; i < 3; i++) + { + char label[32]; + sprintf(label, "%04d", i); + if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns)) + selected = i; + bool hovered = ImGui::IsItemHovered(); + ImGui::NextColumn(); + ImGui::Text(names[i]); ImGui::NextColumn(); + ImGui::Text(paths[i]); ImGui::NextColumn(); + ImGui::Text("%d", hovered); ImGui::NextColumn(); + } + ImGui::Columns(1); + ImGui::Separator(); + ImGui::TreePop(); + } + + // Create multiple items in a same cell before switching to next column + if (ImGui::TreeNode("Mixed items")) + { + ImGui::Columns(3, "mixed"); + ImGui::Separator(); + + ImGui::Text("Hello"); + ImGui::Button("Banana"); + ImGui::NextColumn(); + + ImGui::Text("ImGui"); + ImGui::Button("Apple"); + static float foo = 1.0f; + ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f"); + ImGui::Text("An extra line here."); + ImGui::NextColumn(); + + ImGui::Text("Sailor"); + ImGui::Button("Corniflower"); + static float bar = 1.0f; + ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f"); + ImGui::NextColumn(); + + if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); + if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); + if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); + ImGui::Columns(1); + ImGui::Separator(); + ImGui::TreePop(); + } + + // Word wrapping + if (ImGui::TreeNode("Word-wrapping")) + { + ImGui::Columns(2, "word-wrapping"); + ImGui::Separator(); + ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); + ImGui::TextWrapped("Hello Left"); + ImGui::NextColumn(); + ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); + ImGui::TextWrapped("Hello Right"); + ImGui::Columns(1); + ImGui::Separator(); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Borders")) + { + // NB: Future columns API should allow automatic horizontal borders. + static bool h_borders = true; + static bool v_borders = true; + ImGui::Checkbox("horizontal", &h_borders); + ImGui::SameLine(); + ImGui::Checkbox("vertical", &v_borders); + ImGui::Columns(4, NULL, v_borders); + for (int i = 0; i < 4*3; i++) + { + if (h_borders && ImGui::GetColumnIndex() == 0) + ImGui::Separator(); + ImGui::Text("%c%c%c", 'a'+i, 'a'+i, 'a'+i); + ImGui::Text("Width %.2f\nOffset %.2f", ImGui::GetColumnWidth(), ImGui::GetColumnOffset()); + ImGui::NextColumn(); + } + ImGui::Columns(1); + if (h_borders) + ImGui::Separator(); + ImGui::TreePop(); + } + + // Scrolling columns + /* + if (ImGui::TreeNode("Vertical Scrolling")) + { + ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)); + ImGui::Columns(3); + ImGui::Text("ID"); ImGui::NextColumn(); + ImGui::Text("Name"); ImGui::NextColumn(); + ImGui::Text("Path"); ImGui::NextColumn(); + ImGui::Columns(1); + ImGui::Separator(); + ImGui::EndChild(); + ImGui::BeginChild("##scrollingregion", ImVec2(0, 60)); + ImGui::Columns(3); + for (int i = 0; i < 10; i++) + { + ImGui::Text("%04d", i); ImGui::NextColumn(); + ImGui::Text("Foobar"); ImGui::NextColumn(); + ImGui::Text("/path/foobar/%04d/", i); ImGui::NextColumn(); + } + ImGui::Columns(1); + ImGui::EndChild(); + ImGui::TreePop(); + } + */ + + if (ImGui::TreeNode("Horizontal Scrolling")) + { + ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f)); + ImGui::BeginChild("##ScrollingRegion", ImVec2(0, ImGui::GetFontSize() * 20), false, ImGuiWindowFlags_HorizontalScrollbar); + ImGui::Columns(10); + int ITEMS_COUNT = 2000; + ImGuiListClipper clipper(ITEMS_COUNT); // Also demonstrate using the clipper for large list + while (clipper.Step()) + { + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + for (int j = 0; j < 10; j++) + { + ImGui::Text("Line %d Column %d...", i, j); + ImGui::NextColumn(); + } + } + ImGui::Columns(1); + ImGui::EndChild(); + ImGui::TreePop(); + } + + bool node_open = ImGui::TreeNode("Tree within single cell"); + ImGui::SameLine(); HelpMarker("NB: Tree node must be poped before ending the cell. There's no storage of state per-cell."); + if (node_open) + { + ImGui::Columns(2, "tree items"); + ImGui::Separator(); + if (ImGui::TreeNode("Hello")) { ImGui::BulletText("Sailor"); ImGui::TreePop(); } ImGui::NextColumn(); + if (ImGui::TreeNode("Bonjour")) { ImGui::BulletText("Marin"); ImGui::TreePop(); } ImGui::NextColumn(); + ImGui::Columns(1); + ImGui::Separator(); + ImGui::TreePop(); + } + ImGui::PopID(); +} + +static void ShowDemoWindowMisc() +{ + if (ImGui::CollapsingHeader("Filtering")) + { + static ImGuiTextFilter filter; + ImGui::Text("Filter usage:\n" + " \"\" display all lines\n" + " \"xxx\" display lines containing \"xxx\"\n" + " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" + " \"-xxx\" hide lines containing \"xxx\""); + filter.Draw(); + const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; + for (int i = 0; i < IM_ARRAYSIZE(lines); i++) + if (filter.PassFilter(lines[i])) + ImGui::BulletText("%s", lines[i]); + } + + if (ImGui::CollapsingHeader("Inputs, Navigation & Focus")) + { + ImGuiIO& io = ImGui::GetIO(); + + ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse); + ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard); + ImGui::Text("WantTextInput: %d", io.WantTextInput); + ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos); + ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible); + + if (ImGui::TreeNode("Keyboard, Mouse & Navigation State")) + { + if (ImGui::IsMousePosValid()) + ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); + else + ImGui::Text("Mouse pos: "); + ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); + ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } + ImGui::Text("Mouse clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse dbl-clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); + + ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("%d (%.02f secs)", i, io.KeysDownDuration[i]); } + ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d", i); } + ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d", i); } + ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); + + ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputs[i]); } + ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); } + ImGui::Text("NavInputs duration:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]); } + + ImGui::Button("Hovering me sets the\nkeyboard capture flag"); + if (ImGui::IsItemHovered()) + ImGui::CaptureKeyboardFromApp(true); + ImGui::SameLine(); + ImGui::Button("Holding me clears the\nthe keyboard capture flag"); + if (ImGui::IsItemActive()) + ImGui::CaptureKeyboardFromApp(false); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Tabbing")) + { + ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields."); + static char buf[32] = "dummy"; + ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); + ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); + ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); + ImGui::PushAllowKeyboardFocus(false); + ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); + //ImGui::SameLine(); HelpMarker("Use ImGui::PushAllowKeyboardFocus(bool)\nto disable tabbing through certain widgets."); + ImGui::PopAllowKeyboardFocus(); + ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Focus from code")) + { + bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); + bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine(); + bool focus_3 = ImGui::Button("Focus on 3"); + int has_focus = 0; + static char buf[128] = "click on a button to set focus"; + + if (focus_1) ImGui::SetKeyboardFocusHere(); + ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); + if (ImGui::IsItemActive()) has_focus = 1; + + if (focus_2) ImGui::SetKeyboardFocusHere(); + ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); + if (ImGui::IsItemActive()) has_focus = 2; + + ImGui::PushAllowKeyboardFocus(false); + if (focus_3) ImGui::SetKeyboardFocusHere(); + ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); + if (ImGui::IsItemActive()) has_focus = 3; + ImGui::PopAllowKeyboardFocus(); + + if (has_focus) + ImGui::Text("Item with focus: %d", has_focus); + else + ImGui::Text("Item with focus: "); + + // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item + static float f3[3] = { 0.0f, 0.0f, 0.0f }; + int focus_ahead = -1; + if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine(); + if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine(); + if (ImGui::Button("Focus on Z")) { focus_ahead = 2; } + if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); + ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); + + ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code."); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Dragging")) + { + ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); + for (int button = 0; button < 3; button++) + ImGui::Text("IsMouseDragging(%d):\n w/ default threshold: %d,\n w/ zero threshold: %d\n w/ large threshold: %d", + button, ImGui::IsMouseDragging(button), ImGui::IsMouseDragging(button, 0.0f), ImGui::IsMouseDragging(button, 20.0f)); + ImGui::Button("Drag Me"); + if (ImGui::IsItemActive()) + { + // Draw a line between the button and the mouse cursor + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + draw_list->PushClipRectFullScreen(); + draw_list->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); + draw_list->PopClipRect(); + + // Drag operations gets "unlocked" when the mouse has moved past a certain threshold (the default threshold is stored in io.MouseDragThreshold) + // You can request a lower or higher threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta() + ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f); + ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0); + ImVec2 mouse_delta = io.MouseDelta; + ImGui::SameLine(); ImGui::Text("Raw (%.1f, %.1f), WithLockThresold (%.1f, %.1f), MouseDelta (%.1f, %.1f)", value_raw.x, value_raw.y, value_with_lock_threshold.x, value_with_lock_threshold.y, mouse_delta.x, mouse_delta.y); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Mouse cursors")) + { + const char* mouse_cursors_names[] = { "Arrow", "TextInput", "Move", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand" }; + IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); + + ImGui::Text("Current mouse cursor = %d: %s", ImGui::GetMouseCursor(), mouse_cursors_names[ImGui::GetMouseCursor()]); + ImGui::Text("Hover to see mouse cursors:"); + ImGui::SameLine(); HelpMarker("Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, otherwise your backend needs to handle it."); + for (int i = 0; i < ImGuiMouseCursor_COUNT; i++) + { + char label[32]; + sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); + ImGui::Bullet(); ImGui::Selectable(label, false); + if (ImGui::IsItemHovered() || ImGui::IsItemFocused()) + ImGui::SetMouseCursor(i); + } + ImGui::TreePop(); + } + } +} + +//----------------------------------------------------------------------------- +// [SECTION] About Window / ShowAboutWindow() +// Access from ImGui Demo -> Help -> About +//----------------------------------------------------------------------------- + +void ImGui::ShowAboutWindow(bool* p_open) +{ + if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::End(); + return; + } + ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); + ImGui::Separator(); + ImGui::Text("By Omar Cornut and all dear imgui contributors."); + ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information."); + + static bool show_config_info = false; + ImGui::Checkbox("Config/Build Information", &show_config_info); + if (show_config_info) + { + ImGuiIO& io = ImGui::GetIO(); + ImGuiStyle& style = ImGui::GetStyle(); + + bool copy_to_clipboard = ImGui::Button("Copy to clipboard"); + ImGui::BeginChildFrame(ImGui::GetID("cfginfos"), ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18), ImGuiWindowFlags_NoMove); + if (copy_to_clipboard) + ImGui::LogToClipboard(); + + ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); + ImGui::Separator(); + ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert)); + ImGui::Text("define: __cplusplus=%d", (int)__cplusplus); +#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_MATH_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_MATH_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS"); +#endif +#ifdef IMGUI_USE_BGRA_PACKED_COLOR + ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR"); +#endif +#ifdef _WIN32 + ImGui::Text("define: _WIN32"); +#endif +#ifdef _WIN64 + ImGui::Text("define: _WIN64"); +#endif +#ifdef __linux__ + ImGui::Text("define: __linux__"); +#endif +#ifdef __APPLE__ + ImGui::Text("define: __APPLE__"); +#endif +#ifdef _MSC_VER + ImGui::Text("define: _MSC_VER=%d", _MSC_VER); +#endif +#ifdef __MINGW32__ + ImGui::Text("define: __MINGW32__"); +#endif +#ifdef __MINGW64__ + ImGui::Text("define: __MINGW64__"); +#endif +#ifdef __GNUC__ + ImGui::Text("define: __GNUC__=%d", (int)__GNUC__); +#endif +#ifdef __clang_version__ + ImGui::Text("define: __clang_version__=%s", __clang_version__); +#endif + ImGui::Separator(); + ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL"); + ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL"); + ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard"); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad"); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(" NavEnableSetMousePos"); + if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(" NavNoCaptureKeyboard"); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse"); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange"); + if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor"); + if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors"); + if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); + if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); + if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly"); + ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags); + if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); + if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); + if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos"); + ImGui::Separator(); + ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight); + ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y); + ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); + ImGui::Separator(); + ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y); + ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize); + ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y); + ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding); + ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize); + ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y); + ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y); + + if (copy_to_clipboard) + ImGui::LogFinish(); + ImGui::EndChildFrame(); + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Style Editor / ShowStyleEditor() +//----------------------------------------------------------------------------- + +// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. +// Here we use the simplified Combo() api that packs items into a single literal string. Useful for quick combo boxes where the choices are known locally. +bool ImGui::ShowStyleSelector(const char* label) +{ + static int style_idx = -1; + if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0")) + { + switch (style_idx) + { + case 0: ImGui::StyleColorsClassic(); break; + case 1: ImGui::StyleColorsDark(); break; + case 2: ImGui::StyleColorsLight(); break; + } + return true; + } + return false; +} + +// Demo helper function to select among loaded fonts. +// Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one. +void ImGui::ShowFontSelector(const char* label) +{ + ImGuiIO& io = ImGui::GetIO(); + ImFont* font_current = ImGui::GetFont(); + if (ImGui::BeginCombo(label, font_current->GetDebugName())) + { + for (int n = 0; n < io.Fonts->Fonts.Size; n++) + { + ImFont* font = io.Fonts->Fonts[n]; + ImGui::PushID((void*)font); + if (ImGui::Selectable(font->GetDebugName(), font == font_current)) + io.FontDefault = font; + ImGui::PopID(); + } + ImGui::EndCombo(); + } + ImGui::SameLine(); + HelpMarker( + "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n" + "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" + "- Read FAQ and documentation in misc/fonts/ for more details.\n" + "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); +} + +void ImGui::ShowStyleEditor(ImGuiStyle* ref) +{ + // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it compares to an internally stored reference) + ImGuiStyle& style = ImGui::GetStyle(); + static ImGuiStyle ref_saved_style; + + // Default to using internal storage as reference + static bool init = true; + if (init && ref == NULL) + ref_saved_style = style; + init = false; + if (ref == NULL) + ref = &ref_saved_style; + + ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f); + + if (ImGui::ShowStyleSelector("Colors##Selector")) + ref_saved_style = style; + ImGui::ShowFontSelector("Fonts##Selector"); + + // Simplified Settings + if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) + style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding + { bool window_border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &window_border)) style.WindowBorderSize = window_border ? 1.0f : 0.0f; } + ImGui::SameLine(); + { bool frame_border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &frame_border)) style.FrameBorderSize = frame_border ? 1.0f : 0.0f; } + ImGui::SameLine(); + { bool popup_border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &popup_border)) style.PopupBorderSize = popup_border ? 1.0f : 0.0f; } + + // Save/Revert button + if (ImGui::Button("Save Ref")) + *ref = ref_saved_style = style; + ImGui::SameLine(); + if (ImGui::Button("Revert Ref")) + style = *ref; + ImGui::SameLine(); + HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export Colors\" below to save them somewhere."); + + ImGui::Separator(); + + if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None)) + { + if (ImGui::BeginTabItem("Sizes")) + { + ImGui::Text("Main"); + ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); + ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); + ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); + ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); + ImGui::Text("Borders"); + ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::Text("Rounding"); + ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); + ImGui::Text("Alignment"); + ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); + ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); + ImGui::Text("Safe Area Padding"); ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); + ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Colors")) + { + static int output_dest = 0; + static bool output_only_modified = true; + if (ImGui::Button("Export Unsaved")) + { + if (output_dest == 0) + ImGui::LogToClipboard(); + else + ImGui::LogToTTY(); + ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE); + for (int i = 0; i < ImGuiCol_COUNT; i++) + { + const ImVec4& col = style.Colors[i]; + const char* name = ImGui::GetStyleColorName(i); + if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) + ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); + } + ImGui::LogFinish(); + } + ImGui::SameLine(); ImGui::PushItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); ImGui::PopItemWidth(); + ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); + + static ImGuiTextFilter filter; + filter.Draw("Filter colors", ImGui::GetFontSize() * 16); + + static ImGuiColorEditFlags alpha_flags = 0; + ImGui::RadioButton("Opaque", &alpha_flags, 0); ImGui::SameLine(); + ImGui::RadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview); ImGui::SameLine(); + ImGui::RadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf); ImGui::SameLine(); + HelpMarker("In the color list:\nLeft-click on colored square to open color picker,\nRight-click to open edit options menu."); + + ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); + ImGui::PushItemWidth(-160); + for (int i = 0; i < ImGuiCol_COUNT; i++) + { + const char* name = ImGui::GetStyleColorName(i); + if (!filter.PassFilter(name)) + continue; + ImGui::PushID(i); + ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); + if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) + { + // Tips: in a real user application, you may want to merge and use an icon font into the main font, so instead of "Save"/"Revert" you'd use icons. + // Read the FAQ and misc/fonts/README.txt about using icon fonts. It's really easy and super convenient! + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i]; + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i]; + } + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); + ImGui::TextUnformatted(name); + ImGui::PopID(); + } + ImGui::PopItemWidth(); + ImGui::EndChild(); + + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Fonts")) + { + ImGuiIO& io = ImGui::GetIO(); + ImFontAtlas* atlas = io.Fonts; + HelpMarker("Read FAQ and misc/fonts/README.txt for details on font loading."); + ImGui::PushItemWidth(120); + for (int i = 0; i < atlas->Fonts.Size; i++) + { + ImFont* font = atlas->Fonts[i]; + ImGui::PushID(font); + bool font_details_opened = ImGui::TreeNode(font, "Font %d: \"%s\"\n%.2f px, %d glyphs, %d file(s)", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); + ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; } + if (font_details_opened) + { + ImGui::PushFont(font); + ImGui::Text("The quick brown fox jumps over the lazy dog"); + ImGui::PopFont(); + ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font + ImGui::SameLine(); HelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)"); + ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f"); + ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); + ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar); + const float surface_sqrt = sqrtf((float)font->MetricsTotalSurface); + ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)surface_sqrt, (int)surface_sqrt); + for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) + if (const ImFontConfig* cfg = &font->ConfigData[config_i]) + ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH); + if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) + { + // Display all glyphs of the fonts in separate pages of 256 characters + for (int base = 0; base < 0x10000; base += 256) + { + int count = 0; + for (int n = 0; n < 256; n++) + count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0; + if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) + { + float cell_size = font->FontSize * 1; + float cell_spacing = style.ItemSpacing.y; + ImVec2 base_pos = ImGui::GetCursorScreenPos(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + for (int n = 0; n < 256; n++) + { + ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); + ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); + const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); + draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); + if (glyph) + font->RenderChar(draw_list, cell_size, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base + n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string. + if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) + { + ImGui::BeginTooltip(); + ImGui::Text("Codepoint: U+%04X", base + n); + ImGui::Separator(); + ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX); + ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); + ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); + ImGui::EndTooltip(); + } + } + ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); + ImGui::TreePop(); + } + } + ImGui::TreePop(); + } + ImGui::TreePop(); + } + ImGui::PopID(); + } + if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) + { + ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128)); + ImGui::TreePop(); + } + + static float window_scale = 1.0f; + if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.2f")) // scale only this window + ImGui::SetWindowFontScale(window_scale); + ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.2f"); // scale everything + ImGui::PopItemWidth(); + + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Rendering")) + { + ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); ImGui::SameLine(); HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); + ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); + ImGui::PushItemWidth(100); + ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, "%.2f", 2.0f); + if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; + ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. + ImGui::PopItemWidth(); + + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); + } + + ImGui::PopItemWidth(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() +//----------------------------------------------------------------------------- + +// Demonstrate creating a fullscreen menu bar and populating it. +static void ShowExampleAppMainMenuBar() +{ + if (ImGui::BeginMainMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Edit")) + { + if (ImGui::MenuItem("Undo", "CTRL+Z")) {} + if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item + ImGui::Separator(); + if (ImGui::MenuItem("Cut", "CTRL+X")) {} + if (ImGui::MenuItem("Copy", "CTRL+C")) {} + if (ImGui::MenuItem("Paste", "CTRL+V")) {} + ImGui::EndMenu(); + } + ImGui::EndMainMenuBar(); + } +} + +static void ShowExampleMenuFile() +{ + ImGui::MenuItem("(dummy menu)", NULL, false, false); + if (ImGui::MenuItem("New")) {} + if (ImGui::MenuItem("Open", "Ctrl+O")) {} + if (ImGui::BeginMenu("Open Recent")) + { + ImGui::MenuItem("fish_hat.c"); + ImGui::MenuItem("fish_hat.inl"); + ImGui::MenuItem("fish_hat.h"); + if (ImGui::BeginMenu("More..")) + { + ImGui::MenuItem("Hello"); + ImGui::MenuItem("Sailor"); + if (ImGui::BeginMenu("Recurse..")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + ImGui::EndMenu(); + } + ImGui::EndMenu(); + } + if (ImGui::MenuItem("Save", "Ctrl+S")) {} + if (ImGui::MenuItem("Save As..")) {} + ImGui::Separator(); + if (ImGui::BeginMenu("Options")) + { + static bool enabled = true; + ImGui::MenuItem("Enabled", "", &enabled); + ImGui::BeginChild("child", ImVec2(0, 60), true); + for (int i = 0; i < 10; i++) + ImGui::Text("Scrolling Text %d", i); + ImGui::EndChild(); + static float f = 0.5f; + static int n = 0; + static bool b = true; + ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); + ImGui::InputFloat("Input", &f, 0.1f); + ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0"); + ImGui::Checkbox("Check", &b); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Colors")) + { + float sz = ImGui::GetTextLineHeight(); + for (int i = 0; i < ImGuiCol_COUNT; i++) + { + const char* name = ImGui::GetStyleColorName((ImGuiCol)i); + ImVec2 p = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x+sz, p.y+sz), ImGui::GetColorU32((ImGuiCol)i)); + ImGui::Dummy(ImVec2(sz, sz)); + ImGui::SameLine(); + ImGui::MenuItem(name); + } + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Disabled", false)) // Disabled + { + IM_ASSERT(0); + } + if (ImGui::MenuItem("Checked", NULL, true)) {} + if (ImGui::MenuItem("Quit", "Alt+F4")) {} +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Debug Console / ShowExampleAppConsole() +//----------------------------------------------------------------------------- + +// Demonstrate creating a simple console window, with scrolling, filtering, completion and history. +// For the console example, here we are using a more C++ like approach of declaring a class to hold the data and the functions. +struct ExampleAppConsole +{ + char InputBuf[256]; + ImVector Items; + ImVector Commands; + ImVector History; + int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. + ImGuiTextFilter Filter; + bool AutoScroll; + bool ScrollToBottom; + + ExampleAppConsole() + { + ClearLog(); + memset(InputBuf, 0, sizeof(InputBuf)); + HistoryPos = -1; + Commands.push_back("HELP"); + Commands.push_back("HISTORY"); + Commands.push_back("CLEAR"); + Commands.push_back("CLASSIFY"); // "classify" is only here to provide an example of "C"+[tab] completing to "CL" and displaying matches. + AutoScroll = true; + ScrollToBottom = true; + AddLog("Welcome to Dear ImGui!"); + } + ~ExampleAppConsole() + { + ClearLog(); + for (int i = 0; i < History.Size; i++) + free(History[i]); + } + + // Portable helpers + static int Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; } + static int Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; } + static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)str, len); } + static void Strtrim(char* str) { char* str_end = str + strlen(str); while (str_end > str && str_end[-1] == ' ') str_end--; *str_end = 0; } + + void ClearLog() + { + for (int i = 0; i < Items.Size; i++) + free(Items[i]); + Items.clear(); + ScrollToBottom = true; + } + + void AddLog(const char* fmt, ...) IM_FMTARGS(2) + { + // FIXME-OPT + char buf[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); + buf[IM_ARRAYSIZE(buf)-1] = 0; + va_end(args); + Items.push_back(Strdup(buf)); + if (AutoScroll) + ScrollToBottom = true; + } + + void Draw(const char* title, bool* p_open) + { + ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiCond_FirstUseEver); + if (!ImGui::Begin(title, p_open)) + { + ImGui::End(); + return; + } + + // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. So e.g. IsItemHovered() will return true when hovering the title bar. + // Here we create a context menu only available from the title bar. + if (ImGui::BeginPopupContextItem()) + { + if (ImGui::MenuItem("Close Console")) + *p_open = false; + ImGui::EndPopup(); + } + + ImGui::TextWrapped("This example implements a console with basic coloring, completion and history. A more elaborate implementation may want to store entries along with extra data such as timestamp, emitter, etc."); + ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion."); + + // TODO: display items starting from the bottom + + if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine(); + if (ImGui::SmallButton("Add Dummy Error")) { AddLog("[error] something went wrong"); } ImGui::SameLine(); + if (ImGui::SmallButton("Clear")) { ClearLog(); } ImGui::SameLine(); + bool copy_to_clipboard = ImGui::SmallButton("Copy"); ImGui::SameLine(); + if (ImGui::SmallButton("Scroll to bottom")) ScrollToBottom = true; + //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } + + ImGui::Separator(); + + // Options menu + if (ImGui::BeginPopup("Options")) + { + if (ImGui::Checkbox("Auto-scroll", &AutoScroll)) + if (AutoScroll) + ScrollToBottom = true; + ImGui::EndPopup(); + } + + // Options, Filter + if (ImGui::Button("Options")) + ImGui::OpenPopup("Options"); + ImGui::SameLine(); + Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); + ImGui::Separator(); + + const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); // 1 separator, 1 input text + ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); // Leave room for 1 separator + 1 InputText + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::Selectable("Clear")) ClearLog(); + ImGui::EndPopup(); + } + + // Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); + // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping to only process visible items. + // You can seek and display only the lines that are visible using the ImGuiListClipper helper, if your elements are evenly spaced and you have cheap random access to the elements. + // To use the clipper we could replace the 'for (int i = 0; i < Items.Size; i++)' loop with: + // ImGuiListClipper clipper(Items.Size); + // while (clipper.Step()) + // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + // However, note that you can not use this code as is if a filter is active because it breaks the 'cheap random-access' property. We would need random-access on the post-filtered list. + // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices that passed the filtering test, recomputing this array when user changes the filter, + // and appending newly elements as they are inserted. This is left as a task to the user until we can manage to improve this example code! + // If your items are of variable size you may want to implement code similar to what ImGuiListClipper does. Or split your data into fixed height items to allow random-seeking into your list. + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing + if (copy_to_clipboard) + ImGui::LogToClipboard(); + for (int i = 0; i < Items.Size; i++) + { + const char* item = Items[i]; + if (!Filter.PassFilter(item)) + continue; + + // Normally you would store more information in your item (e.g. make Items[] an array of structure, store color/type etc.) + bool pop_color = false; + if (strstr(item, "[error]")) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.4f, 0.4f, 1.0f)); pop_color = true; } + else if (strncmp(item, "# ", 2) == 0) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.6f, 1.0f)); pop_color = true; } + ImGui::TextUnformatted(item); + if (pop_color) + ImGui::PopStyleColor(); + } + if (copy_to_clipboard) + ImGui::LogFinish(); + if (ScrollToBottom) + ImGui::SetScrollHereY(1.0f); + ScrollToBottom = false; + ImGui::PopStyleVar(); + ImGui::EndChild(); + ImGui::Separator(); + + // Command-line + bool reclaim_focus = false; + if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), ImGuiInputTextFlags_EnterReturnsTrue|ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_CallbackHistory, &TextEditCallbackStub, (void*)this)) + { + char* s = InputBuf; + Strtrim(s); + if (s[0]) + ExecCommand(s); + strcpy(s, ""); + reclaim_focus = true; + } + + // Auto-focus on window apparition + ImGui::SetItemDefaultFocus(); + if (reclaim_focus) + ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget + + ImGui::End(); + } + + void ExecCommand(const char* command_line) + { + AddLog("# %s\n", command_line); + + // Insert into history. First find match and delete it so it can be pushed to the back. This isn't trying to be smart or optimal. + HistoryPos = -1; + for (int i = History.Size-1; i >= 0; i--) + if (Stricmp(History[i], command_line) == 0) + { + free(History[i]); + History.erase(History.begin() + i); + break; + } + History.push_back(Strdup(command_line)); + + // Process command + if (Stricmp(command_line, "CLEAR") == 0) + { + ClearLog(); + } + else if (Stricmp(command_line, "HELP") == 0) + { + AddLog("Commands:"); + for (int i = 0; i < Commands.Size; i++) + AddLog("- %s", Commands[i]); + } + else if (Stricmp(command_line, "HISTORY") == 0) + { + int first = History.Size - 10; + for (int i = first > 0 ? first : 0; i < History.Size; i++) + AddLog("%3d: %s\n", i, History[i]); + } + else + { + AddLog("Unknown command: '%s'\n", command_line); + } + + // On commad input, we scroll to bottom even if AutoScroll==false + ScrollToBottom = true; + } + + static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) // In C++11 you are better off using lambdas for this sort of forwarding callbacks + { + ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; + return console->TextEditCallback(data); + } + + int TextEditCallback(ImGuiInputTextCallbackData* data) + { + //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd); + switch (data->EventFlag) + { + case ImGuiInputTextFlags_CallbackCompletion: + { + // Example of TEXT COMPLETION + + // Locate beginning of current word + const char* word_end = data->Buf + data->CursorPos; + const char* word_start = word_end; + while (word_start > data->Buf) + { + const char c = word_start[-1]; + if (c == ' ' || c == '\t' || c == ',' || c == ';') + break; + word_start--; + } + + // Build a list of candidates + ImVector candidates; + for (int i = 0; i < Commands.Size; i++) + if (Strnicmp(Commands[i], word_start, (int)(word_end-word_start)) == 0) + candidates.push_back(Commands[i]); + + if (candidates.Size == 0) + { + // No match + AddLog("No match for \"%.*s\"!\n", (int)(word_end-word_start), word_start); + } + else if (candidates.Size == 1) + { + // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing + data->DeleteChars((int)(word_start-data->Buf), (int)(word_end-word_start)); + data->InsertChars(data->CursorPos, candidates[0]); + data->InsertChars(data->CursorPos, " "); + } + else + { + // Multiple matches. Complete as much as we can, so inputing "C" will complete to "CL" and display "CLEAR" and "CLASSIFY" + int match_len = (int)(word_end - word_start); + for (;;) + { + int c = 0; + bool all_candidates_matches = true; + for (int i = 0; i < candidates.Size && all_candidates_matches; i++) + if (i == 0) + c = toupper(candidates[i][match_len]); + else if (c == 0 || c != toupper(candidates[i][match_len])) + all_candidates_matches = false; + if (!all_candidates_matches) + break; + match_len++; + } + + if (match_len > 0) + { + data->DeleteChars((int)(word_start - data->Buf), (int)(word_end-word_start)); + data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); + } + + // List matches + AddLog("Possible matches:\n"); + for (int i = 0; i < candidates.Size; i++) + AddLog("- %s\n", candidates[i]); + } + + break; + } + case ImGuiInputTextFlags_CallbackHistory: + { + // Example of HISTORY + const int prev_history_pos = HistoryPos; + if (data->EventKey == ImGuiKey_UpArrow) + { + if (HistoryPos == -1) + HistoryPos = History.Size - 1; + else if (HistoryPos > 0) + HistoryPos--; + } + else if (data->EventKey == ImGuiKey_DownArrow) + { + if (HistoryPos != -1) + if (++HistoryPos >= History.Size) + HistoryPos = -1; + } + + // A better implementation would preserve the data on the current input line along with cursor position. + if (prev_history_pos != HistoryPos) + { + const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : ""; + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, history_str); + } + } + } + return 0; + } +}; + +static void ShowExampleAppConsole(bool* p_open) +{ + static ExampleAppConsole console; + console.Draw("Example: Console", p_open); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Debug Log / ShowExampleAppLog() +//----------------------------------------------------------------------------- + +// Usage: +// static ExampleAppLog my_log; +// my_log.AddLog("Hello %d world\n", 123); +// my_log.Draw("title"); +struct ExampleAppLog +{ + ImGuiTextBuffer Buf; + ImGuiTextFilter Filter; + ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls, allowing us to have a random access on lines + bool AutoScroll; + bool ScrollToBottom; + + ExampleAppLog() + { + AutoScroll = true; + ScrollToBottom = false; + Clear(); + } + + void Clear() + { + Buf.clear(); + LineOffsets.clear(); + LineOffsets.push_back(0); + } + + void AddLog(const char* fmt, ...) IM_FMTARGS(2) + { + int old_size = Buf.size(); + va_list args; + va_start(args, fmt); + Buf.appendfv(fmt, args); + va_end(args); + for (int new_size = Buf.size(); old_size < new_size; old_size++) + if (Buf[old_size] == '\n') + LineOffsets.push_back(old_size + 1); + if (AutoScroll) + ScrollToBottom = true; + } + + void Draw(const char* title, bool* p_open = NULL) + { + if (!ImGui::Begin(title, p_open)) + { + ImGui::End(); + return; + } + + // Options menu + if (ImGui::BeginPopup("Options")) + { + if (ImGui::Checkbox("Auto-scroll", &AutoScroll)) + if (AutoScroll) + ScrollToBottom = true; + ImGui::EndPopup(); + } + + // Main window + if (ImGui::Button("Options")) + ImGui::OpenPopup("Options"); + ImGui::SameLine(); + bool clear = ImGui::Button("Clear"); + ImGui::SameLine(); + bool copy = ImGui::Button("Copy"); + ImGui::SameLine(); + Filter.Draw("Filter", -100.0f); + + ImGui::Separator(); + ImGui::BeginChild("scrolling", ImVec2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar); + + if (clear) + Clear(); + if (copy) + ImGui::LogToClipboard(); + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + const char* buf = Buf.begin(); + const char* buf_end = Buf.end(); + if (Filter.IsActive()) + { + // In this example we don't use the clipper when Filter is enabled. + // This is because we don't have a random access on the result on our filter. + // A real application processing logs with ten of thousands of entries may want to store the result of search/filter. + // especially if the filtering function is not trivial (e.g. reg-exp). + for (int line_no = 0; line_no < LineOffsets.Size; line_no++) + { + const char* line_start = buf + LineOffsets[line_no]; + const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + if (Filter.PassFilter(line_start, line_end)) + ImGui::TextUnformatted(line_start, line_end); + } + } + else + { + // The simplest and easy way to display the entire buffer: + // ImGui::TextUnformatted(buf_begin, buf_end); + // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward to skip non-visible lines. + // Here we instead demonstrate using the clipper to only process lines that are within the visible area. + // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them on your side is recommended. + // Using ImGuiListClipper requires A) random access into your data, and B) items all being the same height, + // both of which we can handle since we an array pointing to the beginning of each line of text. + // When using the filter (in the block of code above) we don't have random access into the data to display anymore, which is why we don't use the clipper. + // Storing or skimming through the search result would make it possible (and would be recommended if you want to search through tens of thousands of entries) + ImGuiListClipper clipper; + clipper.Begin(LineOffsets.Size); + while (clipper.Step()) + { + for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) + { + const char* line_start = buf + LineOffsets[line_no]; + const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + ImGui::TextUnformatted(line_start, line_end); + } + } + clipper.End(); + } + ImGui::PopStyleVar(); + + if (ScrollToBottom) + ImGui::SetScrollHereY(1.0f); + ScrollToBottom = false; + ImGui::EndChild(); + ImGui::End(); + } +}; + +// Demonstrate creating a simple log window with basic filtering. +static void ShowExampleAppLog(bool* p_open) +{ + static ExampleAppLog log; + + // For the demo: add a debug button _BEFORE_ the normal log window contents + // We take advantage of the fact that multiple calls to Begin()/End() are appending to the same window. + // Most of the contents of the window will be added by the log.Draw() call. + ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); + ImGui::Begin("Example: Log", p_open); + if (ImGui::SmallButton("[Debug] Add 5 entries")) + { + static int counter = 0; + for (int n = 0; n < 5; n++) + { + const char* categories[3] = { "info", "warn", "error" }; + const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; + log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", + ImGui::GetFrameCount(), categories[counter % IM_ARRAYSIZE(categories)], ImGui::GetTime(), words[counter % IM_ARRAYSIZE(words)]); + counter++; + } + } + ImGui::End(); + + log.Draw("Example: Log", p_open); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Simple Layout / ShowExampleAppLayout() +//----------------------------------------------------------------------------- + +// Demonstrate create a window with multiple child windows. +static void ShowExampleAppLayout(bool* p_open) +{ + ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); + if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar)) + { + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("Close")) *p_open = false; + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + // left + static int selected = 0; + ImGui::BeginChild("left pane", ImVec2(150, 0), true); + for (int i = 0; i < 100; i++) + { + char label[128]; + sprintf(label, "MyObject %d", i); + if (ImGui::Selectable(label, selected == i)) + selected = i; + } + ImGui::EndChild(); + ImGui::SameLine(); + + // right + ImGui::BeginGroup(); + ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us + ImGui::Text("MyObject: %d", selected); + ImGui::Separator(); + if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) + { + if (ImGui::BeginTabItem("Description")) + { + ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Details")) + { + ImGui::Text("ID: 0123456789"); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::EndChild(); + if (ImGui::Button("Revert")) {} + ImGui::SameLine(); + if (ImGui::Button("Save")) {} + ImGui::EndGroup(); + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() +//----------------------------------------------------------------------------- + +// Demonstrate create a simple property editor. +static void ShowExampleAppPropertyEditor(bool* p_open) +{ + ImGui::SetNextWindowSize(ImVec2(430,450), ImGuiCond_FirstUseEver); + if (!ImGui::Begin("Example: Property editor", p_open)) + { + ImGui::End(); + return; + } + + HelpMarker("This example shows how you may implement a property editor using two columns.\nAll objects/fields data are dummies here.\nRemember that in many simple cases, you can use ImGui::SameLine(xxx) to position\nyour cursor horizontally instead of using the Columns() API."); + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2,2)); + ImGui::Columns(2); + ImGui::Separator(); + + struct funcs + { + static void ShowDummyObject(const char* prefix, int uid) + { + ImGui::PushID(uid); // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. + ImGui::AlignTextToFramePadding(); // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high. + bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid); + ImGui::NextColumn(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("my sailor is rich"); + ImGui::NextColumn(); + if (node_open) + { + static float dummy_members[8] = { 0.0f,0.0f,1.0f,3.1416f,100.0f,999.0f }; + for (int i = 0; i < 8; i++) + { + ImGui::PushID(i); // Use field index as identifier. + if (i < 2) + { + ShowDummyObject("Child", 424242); + } + else + { + // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well) + ImGui::AlignTextToFramePadding(); + ImGui::TreeNodeEx("Field", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet, "Field_%d", i); + ImGui::NextColumn(); + ImGui::PushItemWidth(-1); + if (i >= 5) + ImGui::InputFloat("##value", &dummy_members[i], 1.0f); + else + ImGui::DragFloat("##value", &dummy_members[i], 0.01f); + ImGui::PopItemWidth(); + ImGui::NextColumn(); + } + ImGui::PopID(); + } + ImGui::TreePop(); + } + ImGui::PopID(); + } + }; + + // Iterate dummy objects with dummy members (all the same data) + for (int obj_i = 0; obj_i < 3; obj_i++) + funcs::ShowDummyObject("Object", obj_i); + + ImGui::Columns(1); + ImGui::Separator(); + ImGui::PopStyleVar(); + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Long Text / ShowExampleAppLongText() +//----------------------------------------------------------------------------- + +// Demonstrate/test rendering huge amount of text, and the incidence of clipping. +static void ShowExampleAppLongText(bool* p_open) +{ + ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiCond_FirstUseEver); + if (!ImGui::Begin("Example: Long text display", p_open)) + { + ImGui::End(); + return; + } + + static int test_type = 0; + static ImGuiTextBuffer log; + static int lines = 0; + ImGui::Text("Printing unusually long amount of text."); + ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped (slow)\0"); + ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); + if (ImGui::Button("Clear")) { log.clear(); lines = 0; } + ImGui::SameLine(); + if (ImGui::Button("Add 1000 lines")) + { + for (int i = 0; i < 1000; i++) + log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines+i); + lines += 1000; + } + ImGui::BeginChild("Log"); + switch (test_type) + { + case 0: + // Single call to TextUnformatted() with a big buffer + ImGui::TextUnformatted(log.begin(), log.end()); + break; + case 1: + { + // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); + ImGuiListClipper clipper(lines); + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); + ImGui::PopStyleVar(); + break; + } + case 2: + // Multiple calls to Text(), not clipped (slow) + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); + for (int i = 0; i < lines; i++) + ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); + ImGui::PopStyleVar(); + break; + } + ImGui::EndChild(); + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() +//----------------------------------------------------------------------------- + +// Demonstrate creating a window which gets auto-resized according to its content. +static void ShowExampleAppAutoResize(bool* p_open) +{ + if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::End(); + return; + } + + static int lines = 10; + ImGui::Text("Window will resize every-frame to the size of its content.\nNote that you probably don't want to query the window size to\noutput your content because that would create a feedback loop."); + ImGui::SliderInt("Number of lines", &lines, 1, 20); + for (int i = 0; i < lines; i++) + ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() +//----------------------------------------------------------------------------- + +// Demonstrate creating a window with custom resize constraints. +static void ShowExampleAppConstrainedResize(bool* p_open) +{ + struct CustomConstraints // Helper functions to demonstrate programmatic constraints + { + static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize = ImVec2(IM_MAX(data->DesiredSize.x, data->DesiredSize.y), IM_MAX(data->DesiredSize.x, data->DesiredSize.y)); } + static void Step(ImGuiSizeCallbackData* data) { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); } + }; + + static bool auto_resize = false; + static int type = 0; + static int display_lines = 10; + if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only + if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only + if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 + if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500 + if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500 + if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square + if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step + + ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; + if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) + { + const char* desc[] = + { + "Resize vertical only", + "Resize horizontal only", + "Width > 100, Height > 100", + "Width 400-500", + "Height 400-500", + "Custom: Always Square", + "Custom: Fixed Steps (100)", + }; + if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); + if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); + if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } + ImGui::PushItemWidth(200); + ImGui::Combo("Constraint", &type, desc, IM_ARRAYSIZE(desc)); + ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); + ImGui::PopItemWidth(); + ImGui::Checkbox("Auto-resize", &auto_resize); + for (int i = 0; i < display_lines; i++) + ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() +//----------------------------------------------------------------------------- + +// Demonstrate creating a simple static window with no decoration + a context-menu to choose which corner of the screen to use. +static void ShowExampleAppSimpleOverlay(bool* p_open) +{ + const float DISTANCE = 10.0f; + static int corner = 0; + ImGuiIO& io = ImGui::GetIO(); + if (corner != -1) + { + ImVec2 window_pos = ImVec2((corner & 1) ? io.DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? io.DisplaySize.y - DISTANCE : DISTANCE); + ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f); + ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); + } + ImGui::SetNextWindowBgAlpha(0.3f); // Transparent background + if (ImGui::Begin("Example: Simple overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) + { + ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); + ImGui::Separator(); + if (ImGui::IsMousePosValid()) + ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); + else + ImGui::Text("Mouse Position: "); + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1; + if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; + if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; + if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; + if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; + if (p_open && ImGui::MenuItem("Close")) *p_open = false; + ImGui::EndPopup(); + } + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() +//----------------------------------------------------------------------------- + +// Demonstrate using "##" and "###" in identifiers to manipulate ID generation. +// This apply to all regular items as well. Read FAQ section "How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs." for details. +static void ShowExampleAppWindowTitles(bool*) +{ + // By default, Windows are uniquely identified by their title. + // You can use the "##" and "###" markers to manipulate the display/ID. + + // Using "##" to display same title but have unique identifier. + ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver); + ImGui::Begin("Same title as another window##1"); + ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); + ImGui::End(); + + ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver); + ImGui::Begin("Same title as another window##2"); + ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); + ImGui::End(); + + // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" + char buf[128]; + sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount()); + ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver); + ImGui::Begin(buf); + ImGui::Text("This window has a changing title."); + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() +//----------------------------------------------------------------------------- + +// Demonstrate using the low-level ImDrawList to draw custom shapes. +static void ShowExampleAppCustomRendering(bool* p_open) +{ + ImGui::SetNextWindowSize(ImVec2(350, 560), ImGuiCond_FirstUseEver); + if (!ImGui::Begin("Example: Custom rendering", p_open)) + { + ImGui::End(); + return; + } + + // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of overloaded operators, etc. + // Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your types and ImVec2/ImVec4. + // ImGui defines overloaded operators but they are internal to imgui.cpp and not exposed outside (to avoid messing with your types) + // In this example we are not using the maths operators! + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + + if (ImGui::BeginTabBar("##TabBar")) + { + // Primitives + if (ImGui::BeginTabItem("Primitives")) + { + static float sz = 36.0f; + static float thickness = 4.0f; + static ImVec4 col = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); + ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); + ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f"); + ImGui::ColorEdit4("Color", &col.x); + const ImVec2 p = ImGui::GetCursorScreenPos(); + const ImU32 col32 = ImColor(col); + float x = p.x + 4.0f, y = p.y + 4.0f, spacing = 8.0f; + for (int n = 0; n < 2; n++) + { + // First line uses a thickness of 1.0, second line uses the configurable thickness + float th = (n == 0) ? 1.0f : thickness; + draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col32, 6, th); x += sz + spacing; // Hexagon + draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col32, 20, th); x += sz + spacing; // Circle + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 0.0f, ImDrawCornerFlags_All, th); x += sz + spacing; + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_All, th); x += sz + spacing; + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight, th); x += sz + spacing; + draw_list->AddTriangle(ImVec2(x + sz*0.5f, y), ImVec2(x + sz, y + sz - 0.5f), ImVec2(x, y + sz - 0.5f), col32, th); x += sz + spacing; + draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col32, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) + draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col32, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) + draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, th); x += sz + spacing; // Diagonal line + draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x + sz*1.3f, y + sz*0.3f), ImVec2(x + sz - sz*1.3f, y + sz - sz*0.3f), ImVec2(x + sz, y + sz), col32, th); + x = p.x + 4; + y += sz + spacing; + } + draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col32, 6); x += sz + spacing; // Hexagon + draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col32, 32); x += sz + spacing; // Circle + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32); x += sz + spacing; + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f); x += sz + spacing; + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight); x += sz + spacing; + draw_list->AddTriangleFilled(ImVec2(x + sz*0.5f, y), ImVec2(x + sz, y + sz - 0.5f), ImVec2(x, y + sz - 0.5f), col32); x += sz + spacing; + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col32); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness) + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col32); x += spacing + spacing; // Vertical line (faster than AddLine, but only handle integer thickness) + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col32); x += sz; // Pixel (faster than AddLine) + draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)); + ImGui::Dummy(ImVec2((sz + spacing) * 9.5f, (sz + spacing) * 3)); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Canvas")) + { + static ImVector points; + static bool adding_line = false; + if (ImGui::Button("Clear")) points.clear(); + if (points.Size >= 2) { ImGui::SameLine(); if (ImGui::Button("Undo")) { points.pop_back(); points.pop_back(); } } + ImGui::Text("Left-click and drag to add lines,\nRight-click to undo"); + + // Here we are using InvisibleButton() as a convenience to 1) advance the cursor and 2) allows us to use IsItemHovered() + // But you can also draw directly and poll mouse/keyboard by yourself. You can manipulate the cursor using GetCursorPos() and SetCursorPos(). + // If you only use the ImDrawList API, you can notify the owner window of its extends by using SetCursorPos(max). + ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! + ImVec2 canvas_size = ImGui::GetContentRegionAvail(); // Resize canvas to what's available + if (canvas_size.x < 50.0f) canvas_size.x = 50.0f; + if (canvas_size.y < 50.0f) canvas_size.y = 50.0f; + draw_list->AddRectFilledMultiColor(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(50, 50, 50, 255), IM_COL32(50, 50, 60, 255), IM_COL32(60, 60, 70, 255), IM_COL32(50, 50, 60, 255)); + draw_list->AddRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(255, 255, 255, 255)); + + bool adding_preview = false; + ImGui::InvisibleButton("canvas", canvas_size); + ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y); + if (adding_line) + { + adding_preview = true; + points.push_back(mouse_pos_in_canvas); + if (!ImGui::IsMouseDown(0)) + adding_line = adding_preview = false; + } + if (ImGui::IsItemHovered()) + { + if (!adding_line && ImGui::IsMouseClicked(0)) + { + points.push_back(mouse_pos_in_canvas); + adding_line = true; + } + if (ImGui::IsMouseClicked(1) && !points.empty()) + { + adding_line = adding_preview = false; + points.pop_back(); + points.pop_back(); + } + } + draw_list->PushClipRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), true); // clip lines within the canvas (if we resize it, etc.) + for (int i = 0; i < points.Size - 1; i += 2) + draw_list->AddLine(ImVec2(canvas_pos.x + points[i].x, canvas_pos.y + points[i].y), ImVec2(canvas_pos.x + points[i + 1].x, canvas_pos.y + points[i + 1].y), IM_COL32(255, 255, 0, 255), 2.0f); + draw_list->PopClipRect(); + if (adding_preview) + points.pop_back(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("BG/FG draw lists")) + { + static bool draw_bg = true; + static bool draw_fg = true; + ImGui::Checkbox("Draw in Background draw list", &draw_bg); + ImGui::Checkbox("Draw in Foreground draw list", &draw_fg); + ImVec2 window_pos = ImGui::GetWindowPos(); + ImVec2 window_size = ImGui::GetWindowSize(); + ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f); + if (draw_bg) + ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 32, 10); + if (draw_fg) + ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 32, 10); + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); + } + + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() +//----------------------------------------------------------------------------- + +// Simplified structure to mimic a Document model +struct MyDocument +{ + const char* Name; // Document title + bool Open; // Set when the document is open (in this demo, we keep an array of all available documents to simplify the demo) + bool OpenPrev; // Copy of Open from last update. + bool Dirty; // Set when the document has been modified + bool WantClose; // Set when the document + ImVec4 Color; // An arbitrary variable associated to the document + + MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f,1.0f,1.0f,1.0f)) + { + Name = name; + Open = OpenPrev = open; + Dirty = false; + WantClose = false; + Color = color; + } + void DoOpen() { Open = true; } + void DoQueueClose() { WantClose = true; } + void DoForceClose() { Open = false; Dirty = false; } + void DoSave() { Dirty = false; } + + // Display dummy contents for the Document + static void DisplayContents(MyDocument* doc) + { + ImGui::PushID(doc); + ImGui::Text("Document \"%s\"", doc->Name); + ImGui::PushStyleColor(ImGuiCol_Text, doc->Color); + ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."); + ImGui::PopStyleColor(); + if (ImGui::Button("Modify", ImVec2(100, 0))) + doc->Dirty = true; + ImGui::SameLine(); + if (ImGui::Button("Save", ImVec2(100, 0))) + doc->DoSave(); + ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior. + ImGui::PopID(); + } + + // Display context menu for the Document + static void DisplayContextMenu(MyDocument* doc) + { + if (!ImGui::BeginPopupContextItem()) + return; + + char buf[256]; + sprintf(buf, "Save %s", doc->Name); + if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open)) + doc->DoSave(); + if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open)) + doc->DoQueueClose(); + ImGui::EndPopup(); + } +}; + +struct ExampleAppDocuments +{ + ImVector Documents; + + ExampleAppDocuments() + { + Documents.push_back(MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f))); + Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f))); + Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f))); + Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f))); + Documents.push_back(MyDocument("A Rather Long Title", false)); + Documents.push_back(MyDocument("Some Document", false)); + } +}; + +// [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. +// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, as opposed +// to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence. +// During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar +// will report no selected tab during the frame. This will effectively give the impression of a flicker for one frame. +// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. +// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag. +static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app) +{ + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (!doc->Open && doc->OpenPrev) + ImGui::SetTabItemClosed(doc->Name); + doc->OpenPrev = doc->Open; + } +} + +void ShowExampleAppDocuments(bool* p_open) +{ + static ExampleAppDocuments app; + + if (!ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar)) + { + ImGui::End(); + return; + } + + // Options + static bool opt_reorderable = true; + static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_; + + // Menu + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + int open_count = 0; + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + open_count += app.Documents[doc_n].Open ? 1 : 0; + + if (ImGui::BeginMenu("Open", open_count < app.Documents.Size)) + { + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (!doc->Open) + if (ImGui::MenuItem(doc->Name)) + doc->DoOpen(); + } + ImGui::EndMenu(); + } + if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0)) + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + app.Documents[doc_n].DoQueueClose(); + if (ImGui::MenuItem("Exit", "Alt+F4")) {} + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + // [Debug] List documents with one checkbox for each + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (doc_n > 0) + ImGui::SameLine(); + ImGui::PushID(doc); + if (ImGui::Checkbox(doc->Name, &doc->Open)) + if (!doc->Open) + doc->DoForceClose(); + ImGui::PopID(); + } + + ImGui::Separator(); + + // Submit Tab Bar and Tabs + { + ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0); + if (ImGui::BeginTabBar("##tabs", tab_bar_flags)) + { + if (opt_reorderable) + NotifyOfDocumentsClosedElsewhere(app); + + // [DEBUG] Stress tests + //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on. + //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway.. + + // Submit Tabs + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (!doc->Open) + continue; + + ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0); + bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags); + + // Cancel attempt to close when unsaved add to save queue so we can display a popup. + if (!doc->Open && doc->Dirty) + { + doc->Open = true; + doc->DoQueueClose(); + } + + MyDocument::DisplayContextMenu(doc); + if (visible) + { + MyDocument::DisplayContents(doc); + ImGui::EndTabItem(); + } + } + + ImGui::EndTabBar(); + } + } + + // Update closing queue + static ImVector close_queue; + if (close_queue.empty()) + { + // Close queue is locked once we started a popup + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (doc->WantClose) + { + doc->WantClose = false; + close_queue.push_back(doc); + } + } + } + + // Display closing confirmation UI + if (!close_queue.empty()) + { + int close_queue_unsaved_documents = 0; + for (int n = 0; n < close_queue.Size; n++) + if (close_queue[n]->Dirty) + close_queue_unsaved_documents++; + + if (close_queue_unsaved_documents == 0) + { + // Close documents when all are unsaved + for (int n = 0; n < close_queue.Size; n++) + close_queue[n]->DoForceClose(); + close_queue.clear(); + } + else + { + if (!ImGui::IsPopupOpen("Save?")) + ImGui::OpenPopup("Save?"); + if (ImGui::BeginPopupModal("Save?")) + { + ImGui::Text("Save change to the following items?"); + ImGui::PushItemWidth(-1.0f); + ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6); + for (int n = 0; n < close_queue.Size; n++) + if (close_queue[n]->Dirty) + ImGui::Text("%s", close_queue[n]->Name); + ImGui::ListBoxFooter(); + + if (ImGui::Button("Yes", ImVec2(80, 0))) + { + for (int n = 0; n < close_queue.Size; n++) + { + if (close_queue[n]->Dirty) + close_queue[n]->DoSave(); + close_queue[n]->DoForceClose(); + } + close_queue.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("No", ImVec2(80, 0))) + { + for (int n = 0; n < close_queue.Size; n++) + close_queue[n]->DoForceClose(); + close_queue.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel", ImVec2(80, 0))) + { + close_queue.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + } + } + + ImGui::End(); +} + +// End of Demo code +#else + +void ImGui::ShowAboutWindow(bool*) {} +void ImGui::ShowDemoWindow(bool*) {} +void ImGui::ShowUserGuide() {} +void ImGui::ShowStyleEditor(ImGuiStyle*) {} + +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_draw.cpp b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_draw.cpp new file mode 100644 index 00000000..be1604f8 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_draw.cpp @@ -0,0 +1,3305 @@ +// dear imgui, v1.69 +// (drawing and font code) + +/* + +Index of this file: + +// [SECTION] STB libraries implementation +// [SECTION] Style functions +// [SECTION] ImDrawList +// [SECTION] ImDrawData +// [SECTION] Helpers ShadeVertsXXX functions +// [SECTION] ImFontConfig +// [SECTION] ImFontAtlas +// [SECTION] ImFontAtlas glyph ranges helpers +// [SECTION] ImFontGlyphRangesBuilder +// [SECTION] ImFont +// [SECTION] Internal Render Helpers +// [SECTION] Decompression code +// [SECTION] Default font data (ProggyClean.ttf) + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +#include // vsnprintf, sscanf, printf +#if !defined(alloca) +#if defined(__GLIBC__) || defined(__sun) || defined(__CYGWIN__) || defined(__APPLE__) +#include // alloca (glibc uses . Note that Cygwin may have _WIN32 defined, so the order matters here) +#elif defined(_WIN32) +#include // alloca +#if !defined(alloca) +#define alloca _alloca // for clang with MS Codegen +#endif +#else +#include // alloca +#endif +#endif + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#endif + +// Clang/GCC warnings with -Weverything +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok. +#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference is. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#endif +#if __has_warning("-Wcomma") +#pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here // +#endif +#if __has_warning("-Wreserved-id-macro") +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // +#endif +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#endif +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#if __GNUC__ >= 8 +#pragma GCC diagnostic ignored "-Wclass-memaccess" // warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif +#endif + +//------------------------------------------------------------------------- +// [SECTION] STB libraries implementation +//------------------------------------------------------------------------- + +// Compile time options: +//#define IMGUI_STB_NAMESPACE ImStb +//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" +//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" +//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION + +#ifdef IMGUI_STB_NAMESPACE +namespace IMGUI_STB_NAMESPACE +{ +#endif + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wimplicit-fallthrough" +#pragma clang diagnostic ignored "-Wcast-qual" // warning : cast from 'const xxxx *' to 'xxx *' drops const qualifier // +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits] +#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#endif + +#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) +#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION +#define STBRP_STATIC +#define STBRP_ASSERT(x) IM_ASSERT(x) +#define STBRP_SORT ImQsort +#define STB_RECT_PACK_IMPLEMENTATION +#endif +#ifdef IMGUI_STB_RECT_PACK_FILENAME +#include IMGUI_STB_RECT_PACK_FILENAME +#else +#include "imstb_rectpack.h" +#endif +#endif + +#ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) +#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +#define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x)) +#define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x)) +#define STBTT_assert(x) IM_ASSERT(x) +#define STBTT_fmod(x,y) ImFmod(x,y) +#define STBTT_sqrt(x) ImSqrt(x) +#define STBTT_pow(x,y) ImPow(x,y) +#define STBTT_fabs(x) ImFabs(x) +#define STBTT_ifloor(x) ((int)ImFloorStd(x)) +#define STBTT_iceil(x) ((int)ImCeil(x)) +#define STBTT_STATIC +#define STB_TRUETYPE_IMPLEMENTATION +#else +#define STBTT_DEF extern +#endif +#ifdef IMGUI_STB_TRUETYPE_FILENAME +#include IMGUI_STB_TRUETYPE_FILENAME +#else +#include "imstb_truetype.h" +#endif +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +#ifdef IMGUI_STB_NAMESPACE +} // namespace ImStb +using namespace IMGUI_STB_NAMESPACE; +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Style functions +//----------------------------------------------------------------------------- + +void ImGui::StyleColorsDark(ImGuiStyle* dst) +{ + ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); + colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Separator] = colors[ImGuiCol_Border]; + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); +} + +void ImGui::StyleColorsClassic(ImGuiStyle* dst) +{ + ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f); + colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.47f, 0.69f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.41f, 0.64f, 0.69f); + colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); + colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f); + colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); + colors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.48f, 0.71f, 0.79f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f); + colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); +} + +// Those light colors are better suited with a thicker font than the default one + FrameBorder +void ImGui::StyleColorsLight(ImGuiStyle* dst) +{ + ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f); + colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f); + colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); +} + +//----------------------------------------------------------------------------- +// ImDrawList +//----------------------------------------------------------------------------- + +ImDrawListSharedData::ImDrawListSharedData() +{ + Font = NULL; + FontSize = 0.0f; + CurveTessellationTol = 0.0f; + ClipRectFullscreen = ImVec4(-8192.0f, -8192.0f, +8192.0f, +8192.0f); + + // Const data + for (int i = 0; i < IM_ARRAYSIZE(CircleVtx12); i++) + { + const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(CircleVtx12); + CircleVtx12[i] = ImVec2(ImCos(a), ImSin(a)); + } +} + +void ImDrawList::Clear() +{ + CmdBuffer.resize(0); + IdxBuffer.resize(0); + VtxBuffer.resize(0); + Flags = ImDrawListFlags_AntiAliasedLines | ImDrawListFlags_AntiAliasedFill; + _VtxCurrentIdx = 0; + _VtxWritePtr = NULL; + _IdxWritePtr = NULL; + _ClipRectStack.resize(0); + _TextureIdStack.resize(0); + _Path.resize(0); + _ChannelsCurrent = 0; + _ChannelsCount = 1; + // NB: Do not clear channels so our allocations are re-used after the first frame. +} + +void ImDrawList::ClearFreeMemory() +{ + CmdBuffer.clear(); + IdxBuffer.clear(); + VtxBuffer.clear(); + _VtxCurrentIdx = 0; + _VtxWritePtr = NULL; + _IdxWritePtr = NULL; + _ClipRectStack.clear(); + _TextureIdStack.clear(); + _Path.clear(); + _ChannelsCurrent = 0; + _ChannelsCount = 1; + for (int i = 0; i < _Channels.Size; i++) + { + if (i == 0) memset(&_Channels[0], 0, sizeof(_Channels[0])); // channel 0 is a copy of CmdBuffer/IdxBuffer, don't destruct again + _Channels[i].CmdBuffer.clear(); + _Channels[i].IdxBuffer.clear(); + } + _Channels.clear(); +} + +ImDrawList* ImDrawList::CloneOutput() const +{ + ImDrawList* dst = IM_NEW(ImDrawList(NULL)); + dst->CmdBuffer = CmdBuffer; + dst->IdxBuffer = IdxBuffer; + dst->VtxBuffer = VtxBuffer; + dst->Flags = Flags; + return dst; +} + +// Using macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug builds +#define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1] : _Data->ClipRectFullscreen) +#define GetCurrentTextureId() (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : (ImTextureID)NULL) + +void ImDrawList::AddDrawCmd() +{ + ImDrawCmd draw_cmd; + draw_cmd.ClipRect = GetCurrentClipRect(); + draw_cmd.TextureId = GetCurrentTextureId(); + + IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w); + CmdBuffer.push_back(draw_cmd); +} + +void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) +{ + ImDrawCmd* current_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL; + if (!current_cmd || current_cmd->ElemCount != 0 || current_cmd->UserCallback != NULL) + { + AddDrawCmd(); + current_cmd = &CmdBuffer.back(); + } + current_cmd->UserCallback = callback; + current_cmd->UserCallbackData = callback_data; + + AddDrawCmd(); // Force a new command after us (see comment below) +} + +// Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack. +// The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only. +void ImDrawList::UpdateClipRect() +{ + // If current command is used with different settings we need to add a new command + const ImVec4 curr_clip_rect = GetCurrentClipRect(); + ImDrawCmd* curr_cmd = CmdBuffer.Size > 0 ? &CmdBuffer.Data[CmdBuffer.Size-1] : NULL; + if (!curr_cmd || (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL) + { + AddDrawCmd(); + return; + } + + // Try to merge with previous command if it matches, else use current command + ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL; + if (curr_cmd->ElemCount == 0 && prev_cmd && memcmp(&prev_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) == 0 && prev_cmd->TextureId == GetCurrentTextureId() && prev_cmd->UserCallback == NULL) + CmdBuffer.pop_back(); + else + curr_cmd->ClipRect = curr_clip_rect; +} + +void ImDrawList::UpdateTextureID() +{ + // If current command is used with different settings we need to add a new command + const ImTextureID curr_texture_id = GetCurrentTextureId(); + ImDrawCmd* curr_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL; + if (!curr_cmd || (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != curr_texture_id) || curr_cmd->UserCallback != NULL) + { + AddDrawCmd(); + return; + } + + // Try to merge with previous command if it matches, else use current command + ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL; + if (curr_cmd->ElemCount == 0 && prev_cmd && prev_cmd->TextureId == curr_texture_id && memcmp(&prev_cmd->ClipRect, &GetCurrentClipRect(), sizeof(ImVec4)) == 0 && prev_cmd->UserCallback == NULL) + CmdBuffer.pop_back(); + else + curr_cmd->TextureId = curr_texture_id; +} + +#undef GetCurrentClipRect +#undef GetCurrentTextureId + +// Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) +void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect) +{ + ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y); + if (intersect_with_current_clip_rect && _ClipRectStack.Size) + { + ImVec4 current = _ClipRectStack.Data[_ClipRectStack.Size-1]; + if (cr.x < current.x) cr.x = current.x; + if (cr.y < current.y) cr.y = current.y; + if (cr.z > current.z) cr.z = current.z; + if (cr.w > current.w) cr.w = current.w; + } + cr.z = ImMax(cr.x, cr.z); + cr.w = ImMax(cr.y, cr.w); + + _ClipRectStack.push_back(cr); + UpdateClipRect(); +} + +void ImDrawList::PushClipRectFullScreen() +{ + PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w)); +} + +void ImDrawList::PopClipRect() +{ + IM_ASSERT(_ClipRectStack.Size > 0); + _ClipRectStack.pop_back(); + UpdateClipRect(); +} + +void ImDrawList::PushTextureID(ImTextureID texture_id) +{ + _TextureIdStack.push_back(texture_id); + UpdateTextureID(); +} + +void ImDrawList::PopTextureID() +{ + IM_ASSERT(_TextureIdStack.Size > 0); + _TextureIdStack.pop_back(); + UpdateTextureID(); +} + +void ImDrawList::ChannelsSplit(int channels_count) +{ + IM_ASSERT(_ChannelsCurrent == 0 && _ChannelsCount == 1); + int old_channels_count = _Channels.Size; + if (old_channels_count < channels_count) + _Channels.resize(channels_count); + _ChannelsCount = channels_count; + + // _Channels[] (24/32 bytes each) hold storage that we'll swap with this->_CmdBuffer/_IdxBuffer + // The content of _Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to. + // When we switch to the next channel, we'll copy _CmdBuffer/_IdxBuffer into _Channels[0] and then _Channels[1] into _CmdBuffer/_IdxBuffer + memset(&_Channels[0], 0, sizeof(ImDrawChannel)); + for (int i = 1; i < channels_count; i++) + { + if (i >= old_channels_count) + { + IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel(); + } + else + { + _Channels[i].CmdBuffer.resize(0); + _Channels[i].IdxBuffer.resize(0); + } + if (_Channels[i].CmdBuffer.Size == 0) + { + ImDrawCmd draw_cmd; + draw_cmd.ClipRect = _ClipRectStack.back(); + draw_cmd.TextureId = _TextureIdStack.back(); + _Channels[i].CmdBuffer.push_back(draw_cmd); + } + } +} + +void ImDrawList::ChannelsMerge() +{ + // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. + if (_ChannelsCount <= 1) + return; + + ChannelsSetCurrent(0); + if (CmdBuffer.Size && CmdBuffer.back().ElemCount == 0) + CmdBuffer.pop_back(); + + int new_cmd_buffer_count = 0, new_idx_buffer_count = 0; + for (int i = 1; i < _ChannelsCount; i++) + { + ImDrawChannel& ch = _Channels[i]; + if (ch.CmdBuffer.Size && ch.CmdBuffer.back().ElemCount == 0) + ch.CmdBuffer.pop_back(); + new_cmd_buffer_count += ch.CmdBuffer.Size; + new_idx_buffer_count += ch.IdxBuffer.Size; + } + CmdBuffer.resize(CmdBuffer.Size + new_cmd_buffer_count); + IdxBuffer.resize(IdxBuffer.Size + new_idx_buffer_count); + + ImDrawCmd* cmd_write = CmdBuffer.Data + CmdBuffer.Size - new_cmd_buffer_count; + _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size - new_idx_buffer_count; + for (int i = 1; i < _ChannelsCount; i++) + { + ImDrawChannel& ch = _Channels[i]; + if (int sz = ch.CmdBuffer.Size) { memcpy(cmd_write, ch.CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; } + if (int sz = ch.IdxBuffer.Size) { memcpy(_IdxWritePtr, ch.IdxBuffer.Data, sz * sizeof(ImDrawIdx)); _IdxWritePtr += sz; } + } + UpdateClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call. + _ChannelsCount = 1; +} + +void ImDrawList::ChannelsSetCurrent(int idx) +{ + IM_ASSERT(idx < _ChannelsCount); + if (_ChannelsCurrent == idx) return; + memcpy(&_Channels.Data[_ChannelsCurrent].CmdBuffer, &CmdBuffer, sizeof(CmdBuffer)); // copy 12 bytes, four times + memcpy(&_Channels.Data[_ChannelsCurrent].IdxBuffer, &IdxBuffer, sizeof(IdxBuffer)); + _ChannelsCurrent = idx; + memcpy(&CmdBuffer, &_Channels.Data[_ChannelsCurrent].CmdBuffer, sizeof(CmdBuffer)); + memcpy(&IdxBuffer, &_Channels.Data[_ChannelsCurrent].IdxBuffer, sizeof(IdxBuffer)); + _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size; +} + +// NB: this can be called with negative count for removing primitives (as long as the result does not underflow) +void ImDrawList::PrimReserve(int idx_count, int vtx_count) +{ + ImDrawCmd& draw_cmd = CmdBuffer.Data[CmdBuffer.Size-1]; + draw_cmd.ElemCount += idx_count; + + int vtx_buffer_old_size = VtxBuffer.Size; + VtxBuffer.resize(vtx_buffer_old_size + vtx_count); + _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size; + + int idx_buffer_old_size = IdxBuffer.Size; + IdxBuffer.resize(idx_buffer_old_size + idx_count); + _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size; +} + +// Fully unrolled with inline call to keep our debug builds decently fast. +void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col) +{ + ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel); + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); + _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); + _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + _VtxCurrentIdx += 4; + _IdxWritePtr += 6; +} + +void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col) +{ + ImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y); + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); + _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); + _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + _VtxCurrentIdx += 4; + _IdxWritePtr += 6; +} + +void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col) +{ + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); + _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); + _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + _VtxCurrentIdx += 4; + _IdxWritePtr += 6; +} + +// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superflous function calls to optimize debug/non-inlined builds. +// Those macros expects l-values. +#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } } +#define IM_NORMALIZE2F_OVER_EPSILON_CLAMP(VX,VY,EPS,INVLENMAX) { float d2 = VX*VX + VY*VY; if (d2 > EPS) { float inv_len = 1.0f / ImSqrt(d2); if (inv_len > INVLENMAX) inv_len = INVLENMAX; VX *= inv_len; VY *= inv_len; } } + +// TODO: Thickness anti-aliased lines cap are missing their AA fringe. +// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. +void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness) +{ + if (points_count < 2) + return; + + const ImVec2 uv = _Data->TexUvWhitePixel; + + int count = points_count; + if (!closed) + count = points_count-1; + + const bool thick_line = thickness > 1.0f; + if (Flags & ImDrawListFlags_AntiAliasedLines) + { + // Anti-aliased stroke + const float AA_SIZE = 1.0f; + const ImU32 col_trans = col & ~IM_COL32_A_MASK; + + const int idx_count = thick_line ? count*18 : count*12; + const int vtx_count = thick_line ? points_count*4 : points_count*3; + PrimReserve(idx_count, vtx_count); + + // Temporary buffer + ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2)); //-V630 + ImVec2* temp_points = temp_normals + points_count; + + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1+1) == points_count ? 0 : i1+1; + float dx = points[i2].x - points[i1].x; + float dy = points[i2].y - points[i1].y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + temp_normals[i1].x = dy; + temp_normals[i1].y = -dx; + } + if (!closed) + temp_normals[points_count-1] = temp_normals[points_count-2]; + + if (!thick_line) + { + if (!closed) + { + temp_points[0] = points[0] + temp_normals[0] * AA_SIZE; + temp_points[1] = points[0] - temp_normals[0] * AA_SIZE; + temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * AA_SIZE; + temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * AA_SIZE; + } + + // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. + unsigned int idx1 = _VtxCurrentIdx; + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1+1) == points_count ? 0 : i1+1; + unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3; + + // Average normals + float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; + float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; + IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f) + dm_x *= AA_SIZE; + dm_y *= AA_SIZE; + + // Add temporary vertexes + ImVec2* out_vtx = &temp_points[i2*2]; + out_vtx[0].x = points[i2].x + dm_x; + out_vtx[0].y = points[i2].y + dm_y; + out_vtx[1].x = points[i2].x - dm_x; + out_vtx[1].y = points[i2].y - dm_y; + + // Add indexes + _IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2); + _IdxWritePtr[3] = (ImDrawIdx)(idx1+2); _IdxWritePtr[4] = (ImDrawIdx)(idx2+2); _IdxWritePtr[5] = (ImDrawIdx)(idx2+0); + _IdxWritePtr[6] = (ImDrawIdx)(idx2+1); _IdxWritePtr[7] = (ImDrawIdx)(idx1+1); _IdxWritePtr[8] = (ImDrawIdx)(idx1+0); + _IdxWritePtr[9] = (ImDrawIdx)(idx1+0); _IdxWritePtr[10]= (ImDrawIdx)(idx2+0); _IdxWritePtr[11]= (ImDrawIdx)(idx2+1); + _IdxWritePtr += 12; + + idx1 = idx2; + } + + // Add vertexes + for (int i = 0; i < points_count; i++) + { + _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = temp_points[i*2+0]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; + _VtxWritePtr[2].pos = temp_points[i*2+1]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col_trans; + _VtxWritePtr += 3; + } + } + else + { + const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; + if (!closed) + { + temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE); + temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness); + temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness); + temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE); + temp_points[(points_count-1)*4+0] = points[points_count-1] + temp_normals[points_count-1] * (half_inner_thickness + AA_SIZE); + temp_points[(points_count-1)*4+1] = points[points_count-1] + temp_normals[points_count-1] * (half_inner_thickness); + temp_points[(points_count-1)*4+2] = points[points_count-1] - temp_normals[points_count-1] * (half_inner_thickness); + temp_points[(points_count-1)*4+3] = points[points_count-1] - temp_normals[points_count-1] * (half_inner_thickness + AA_SIZE); + } + + // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. + unsigned int idx1 = _VtxCurrentIdx; + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1+1) == points_count ? 0 : i1+1; + unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4; + + // Average normals + float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; + float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; + IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f); + float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE); + float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE); + float dm_in_x = dm_x * half_inner_thickness; + float dm_in_y = dm_y * half_inner_thickness; + + // Add temporary vertexes + ImVec2* out_vtx = &temp_points[i2*4]; + out_vtx[0].x = points[i2].x + dm_out_x; + out_vtx[0].y = points[i2].y + dm_out_y; + out_vtx[1].x = points[i2].x + dm_in_x; + out_vtx[1].y = points[i2].y + dm_in_y; + out_vtx[2].x = points[i2].x - dm_in_x; + out_vtx[2].y = points[i2].y - dm_in_y; + out_vtx[3].x = points[i2].x - dm_out_x; + out_vtx[3].y = points[i2].y - dm_out_y; + + // Add indexes + _IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2); + _IdxWritePtr[3] = (ImDrawIdx)(idx1+2); _IdxWritePtr[4] = (ImDrawIdx)(idx2+2); _IdxWritePtr[5] = (ImDrawIdx)(idx2+1); + _IdxWritePtr[6] = (ImDrawIdx)(idx2+1); _IdxWritePtr[7] = (ImDrawIdx)(idx1+1); _IdxWritePtr[8] = (ImDrawIdx)(idx1+0); + _IdxWritePtr[9] = (ImDrawIdx)(idx1+0); _IdxWritePtr[10] = (ImDrawIdx)(idx2+0); _IdxWritePtr[11] = (ImDrawIdx)(idx2+1); + _IdxWritePtr[12] = (ImDrawIdx)(idx2+2); _IdxWritePtr[13] = (ImDrawIdx)(idx1+2); _IdxWritePtr[14] = (ImDrawIdx)(idx1+3); + _IdxWritePtr[15] = (ImDrawIdx)(idx1+3); _IdxWritePtr[16] = (ImDrawIdx)(idx2+3); _IdxWritePtr[17] = (ImDrawIdx)(idx2+2); + _IdxWritePtr += 18; + + idx1 = idx2; + } + + // Add vertexes + for (int i = 0; i < points_count; i++) + { + _VtxWritePtr[0].pos = temp_points[i*4+0]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col_trans; + _VtxWritePtr[1].pos = temp_points[i*4+1]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = temp_points[i*4+2]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = temp_points[i*4+3]; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col_trans; + _VtxWritePtr += 4; + } + } + _VtxCurrentIdx += (ImDrawIdx)vtx_count; + } + else + { + // Non Anti-aliased Stroke + const int idx_count = count*6; + const int vtx_count = count*4; // FIXME-OPT: Not sharing edges + PrimReserve(idx_count, vtx_count); + + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1+1) == points_count ? 0 : i1+1; + const ImVec2& p1 = points[i1]; + const ImVec2& p2 = points[i2]; + + float dx = p2.x - p1.x; + float dy = p2.y - p1.y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + dx *= (thickness * 0.5f); + dy *= (thickness * 0.5f); + + _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + + _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx+1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx+2); + _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx+2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx+3); + _IdxWritePtr += 6; + _VtxCurrentIdx += 4; + } + } +} + +// We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds. +void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) +{ + if (points_count < 3) + return; + + const ImVec2 uv = _Data->TexUvWhitePixel; + + if (Flags & ImDrawListFlags_AntiAliasedFill) + { + // Anti-aliased Fill + const float AA_SIZE = 1.0f; + const ImU32 col_trans = col & ~IM_COL32_A_MASK; + const int idx_count = (points_count-2)*3 + points_count*6; + const int vtx_count = (points_count*2); + PrimReserve(idx_count, vtx_count); + + // Add indexes for fill + unsigned int vtx_inner_idx = _VtxCurrentIdx; + unsigned int vtx_outer_idx = _VtxCurrentIdx+1; + for (int i = 2; i < points_count; i++) + { + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx+((i-1)<<1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx+(i<<1)); + _IdxWritePtr += 3; + } + + // Compute normals + ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); //-V630 + for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) + { + const ImVec2& p0 = points[i0]; + const ImVec2& p1 = points[i1]; + float dx = p1.x - p0.x; + float dy = p1.y - p0.y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + temp_normals[i0].x = dy; + temp_normals[i0].y = -dx; + } + + for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) + { + // Average normals + const ImVec2& n0 = temp_normals[i0]; + const ImVec2& n1 = temp_normals[i1]; + float dm_x = (n0.x + n1.x) * 0.5f; + float dm_y = (n0.y + n1.y) * 0.5f; + IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f); + dm_x *= AA_SIZE * 0.5f; + dm_y *= AA_SIZE * 0.5f; + + // Add vertices + _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner + _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer + _VtxWritePtr += 2; + + // Add indexes for fringes + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx+(i1<<1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx+(i0<<1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx+(i0<<1)); + _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx+(i0<<1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx+(i1<<1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx+(i1<<1)); + _IdxWritePtr += 6; + } + _VtxCurrentIdx += (ImDrawIdx)vtx_count; + } + else + { + // Non Anti-aliased Fill + const int idx_count = (points_count-2)*3; + const int vtx_count = points_count; + PrimReserve(idx_count, vtx_count); + for (int i = 0; i < vtx_count; i++) + { + _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr++; + } + for (int i = 2; i < points_count; i++) + { + _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx+i-1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx+i); + _IdxWritePtr += 3; + } + _VtxCurrentIdx += (ImDrawIdx)vtx_count; + } +} + +void ImDrawList::PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12) +{ + if (radius == 0.0f || a_min_of_12 > a_max_of_12) + { + _Path.push_back(centre); + return; + } + _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1)); + for (int a = a_min_of_12; a <= a_max_of_12; a++) + { + const ImVec2& c = _Data->CircleVtx12[a % IM_ARRAYSIZE(_Data->CircleVtx12)]; + _Path.push_back(ImVec2(centre.x + c.x * radius, centre.y + c.y * radius)); + } +} + +void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments) +{ + if (radius == 0.0f) + { + _Path.push_back(centre); + return; + } + + // Note that we are adding a point at both a_min and a_max. + // If you are trying to draw a full closed circle you don't want the overlapping points! + _Path.reserve(_Path.Size + (num_segments + 1)); + for (int i = 0; i <= num_segments; i++) + { + const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min); + _Path.push_back(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius)); + } +} + +static void PathBezierToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) +{ + float dx = x4 - x1; + float dy = y4 - y1; + float d2 = ((x2 - x4) * dy - (y2 - y4) * dx); + float d3 = ((x3 - x4) * dy - (y3 - y4) * dx); + d2 = (d2 >= 0) ? d2 : -d2; + d3 = (d3 >= 0) ? d3 : -d3; + if ((d2+d3) * (d2+d3) < tess_tol * (dx*dx + dy*dy)) + { + path->push_back(ImVec2(x4, y4)); + } + else if (level < 10) + { + float x12 = (x1+x2)*0.5f, y12 = (y1+y2)*0.5f; + float x23 = (x2+x3)*0.5f, y23 = (y2+y3)*0.5f; + float x34 = (x3+x4)*0.5f, y34 = (y3+y4)*0.5f; + float x123 = (x12+x23)*0.5f, y123 = (y12+y23)*0.5f; + float x234 = (x23+x34)*0.5f, y234 = (y23+y34)*0.5f; + float x1234 = (x123+x234)*0.5f, y1234 = (y123+y234)*0.5f; + + PathBezierToCasteljau(path, x1,y1, x12,y12, x123,y123, x1234,y1234, tess_tol, level+1); + PathBezierToCasteljau(path, x1234,y1234, x234,y234, x34,y34, x4,y4, tess_tol, level+1); + } +} + +void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments) +{ + ImVec2 p1 = _Path.back(); + if (num_segments == 0) + { + // Auto-tessellated + PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); + } + else + { + float t_step = 1.0f / (float)num_segments; + for (int i_step = 1; i_step <= num_segments; i_step++) + { + float t = t_step * i_step; + float u = 1.0f - t; + float w1 = u*u*u; + float w2 = 3*u*u*t; + float w3 = 3*u*t*t; + float w4 = t*t*t; + _Path.push_back(ImVec2(w1*p1.x + w2*p2.x + w3*p3.x + w4*p4.x, w1*p1.y + w2*p2.y + w3*p3.y + w4*p4.y)); + } + } +} + +void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, int rounding_corners) +{ + rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((rounding_corners & ImDrawCornerFlags_Top) == ImDrawCornerFlags_Top) || ((rounding_corners & ImDrawCornerFlags_Bot) == ImDrawCornerFlags_Bot) ? 0.5f : 1.0f ) - 1.0f); + rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((rounding_corners & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f ) - 1.0f); + + if (rounding <= 0.0f || rounding_corners == 0) + { + PathLineTo(a); + PathLineTo(ImVec2(b.x, a.y)); + PathLineTo(b); + PathLineTo(ImVec2(a.x, b.y)); + } + else + { + const float rounding_tl = (rounding_corners & ImDrawCornerFlags_TopLeft) ? rounding : 0.0f; + const float rounding_tr = (rounding_corners & ImDrawCornerFlags_TopRight) ? rounding : 0.0f; + const float rounding_br = (rounding_corners & ImDrawCornerFlags_BotRight) ? rounding : 0.0f; + const float rounding_bl = (rounding_corners & ImDrawCornerFlags_BotLeft) ? rounding : 0.0f; + PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9); + PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12); + PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3); + PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6); + } +} + +void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + PathLineTo(a + ImVec2(0.5f,0.5f)); + PathLineTo(b + ImVec2(0.5f,0.5f)); + PathStroke(col, false, thickness); +} + +// a: upper-left, b: lower-right. we don't render 1 px sized rectangles properly. +void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + if (Flags & ImDrawListFlags_AntiAliasedLines) + PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.50f,0.50f), rounding, rounding_corners_flags); + else + PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.49f,0.49f), rounding, rounding_corners_flags); // Better looking lower-right corner and rounded non-AA shapes. + PathStroke(col, true, thickness); +} + +void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + if (rounding > 0.0f) + { + PathRect(a, b, rounding, rounding_corners_flags); + PathFillConvex(col); + } + else + { + PrimReserve(6, 4); + PrimRect(a, b, col); + } +} + +void ImDrawList::AddRectFilledMultiColor(const ImVec2& a, const ImVec2& c, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left) +{ + if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0) + return; + + const ImVec2 uv = _Data->TexUvWhitePixel; + PrimReserve(6, 4); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2)); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+3)); + PrimWriteVtx(a, uv, col_upr_left); + PrimWriteVtx(ImVec2(c.x, a.y), uv, col_upr_right); + PrimWriteVtx(c, uv, col_bot_right); + PrimWriteVtx(ImVec2(a.x, c.y), uv, col_bot_left); +} + +void ImDrawList::AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(a); + PathLineTo(b); + PathLineTo(c); + PathLineTo(d); + PathStroke(col, true, thickness); +} + +void ImDrawList::AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(a); + PathLineTo(b); + PathLineTo(c); + PathLineTo(d); + PathFillConvex(col); +} + +void ImDrawList::AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(a); + PathLineTo(b); + PathLineTo(c); + PathStroke(col, true, thickness); +} + +void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(a); + PathLineTo(b); + PathLineTo(c); + PathFillConvex(col); +} + +void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) + return; + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments - 1); + PathStroke(col, true, thickness); +} + +void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) + return; + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(centre, radius, 0.0f, a_max, num_segments - 1); + PathFillConvex(col); +} + +void ImDrawList::AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(pos0); + PathBezierCurveTo(cp0, cp1, pos1, num_segments); + PathStroke(col, false, thickness); +} + +void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + if (text_end == NULL) + text_end = text_begin + strlen(text_begin); + if (text_begin == text_end) + return; + + // Pull default font/size from the shared ImDrawListSharedData instance + if (font == NULL) + font = _Data->Font; + if (font_size == 0.0f) + font_size = _Data->FontSize; + + IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. + + ImVec4 clip_rect = _ClipRectStack.back(); + if (cpu_fine_clip_rect) + { + clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x); + clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y); + clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z); + clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w); + } + font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL); +} + +void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end) +{ + AddText(NULL, 0.0f, pos, col, text_begin, text_end); +} + +void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + if (push_texture_id) + PushTextureID(user_texture_id); + + PrimReserve(6, 4); + PrimRectUV(a, b, uv_a, uv_b, col); + + if (push_texture_id) + PopTextureID(); +} + +void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + if (push_texture_id) + PushTextureID(user_texture_id); + + PrimReserve(6, 4); + PrimQuadUV(a, b, c, d, uv_a, uv_b, uv_c, uv_d, col); + + if (push_texture_id) + PopTextureID(); +} + +void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + if (rounding <= 0.0f || (rounding_corners & ImDrawCornerFlags_All) == 0) + { + AddImage(user_texture_id, a, b, uv_a, uv_b, col); + return; + } + + const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + if (push_texture_id) + PushTextureID(user_texture_id); + + int vert_start_idx = VtxBuffer.Size; + PathRect(a, b, rounding, rounding_corners); + PathFillConvex(col); + int vert_end_idx = VtxBuffer.Size; + ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, a, b, uv_a, uv_b, true); + + if (push_texture_id) + PopTextureID(); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImDrawData +//----------------------------------------------------------------------------- + +// For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! +void ImDrawData::DeIndexAllBuffers() +{ + ImVector new_vtx_buffer; + TotalVtxCount = TotalIdxCount = 0; + for (int i = 0; i < CmdListsCount; i++) + { + ImDrawList* cmd_list = CmdLists[i]; + if (cmd_list->IdxBuffer.empty()) + continue; + new_vtx_buffer.resize(cmd_list->IdxBuffer.Size); + for (int j = 0; j < cmd_list->IdxBuffer.Size; j++) + new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]]; + cmd_list->VtxBuffer.swap(new_vtx_buffer); + cmd_list->IdxBuffer.resize(0); + TotalVtxCount += cmd_list->VtxBuffer.Size; + } +} + +// Helper to scale the ClipRect field of each ImDrawCmd. +// Use if your final output buffer is at a different scale than draw_data->DisplaySize, +// or if there is a difference between your window resolution and framebuffer resolution. +void ImDrawData::ScaleClipRects(const ImVec2& fb_scale) +{ + for (int i = 0; i < CmdListsCount; i++) + { + ImDrawList* cmd_list = CmdLists[i]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i]; + cmd->ClipRect = ImVec4(cmd->ClipRect.x * fb_scale.x, cmd->ClipRect.y * fb_scale.y, cmd->ClipRect.z * fb_scale.x, cmd->ClipRect.w * fb_scale.y); + } + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Helpers ShadeVertsXXX functions +//----------------------------------------------------------------------------- + +// Generic linear color gradient, write to RGB fields, leave A untouched. +void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1) +{ + ImVec2 gradient_extent = gradient_p1 - gradient_p0; + float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent); + ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; + ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; + for (ImDrawVert* vert = vert_start; vert < vert_end; vert++) + { + float d = ImDot(vert->pos - gradient_p0, gradient_extent); + float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f); + int r = ImLerp((int)(col0 >> IM_COL32_R_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_R_SHIFT) & 0xFF, t); + int g = ImLerp((int)(col0 >> IM_COL32_G_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_G_SHIFT) & 0xFF, t); + int b = ImLerp((int)(col0 >> IM_COL32_B_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_B_SHIFT) & 0xFF, t); + vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK); + } +} + +// Distribute UV over (a, b) rectangle +void ImGui::ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp) +{ + const ImVec2 size = b - a; + const ImVec2 uv_size = uv_b - uv_a; + const ImVec2 scale = ImVec2( + size.x != 0.0f ? (uv_size.x / size.x) : 0.0f, + size.y != 0.0f ? (uv_size.y / size.y) : 0.0f); + + ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; + ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; + if (clamp) + { + const ImVec2 min = ImMin(uv_a, uv_b); + const ImVec2 max = ImMax(uv_a, uv_b); + for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) + vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max); + } + else + { + for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) + vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFontConfig +//----------------------------------------------------------------------------- + +ImFontConfig::ImFontConfig() +{ + FontData = NULL; + FontDataSize = 0; + FontDataOwnedByAtlas = true; + FontNo = 0; + SizePixels = 0.0f; + OversampleH = 3; // FIXME: 2 may be a better default? + OversampleV = 1; + PixelSnapH = false; + GlyphExtraSpacing = ImVec2(0.0f, 0.0f); + GlyphOffset = ImVec2(0.0f, 0.0f); + GlyphRanges = NULL; + GlyphMinAdvanceX = 0.0f; + GlyphMaxAdvanceX = FLT_MAX; + MergeMode = false; + RasterizerFlags = 0x00; + RasterizerMultiply = 1.0f; + memset(Name, 0, sizeof(Name)); + DstFont = NULL; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFontAtlas +//----------------------------------------------------------------------------- + +// A work of art lies ahead! (. = white layer, X = black layer, others are blank) +// The white texels on the top left are the ones we'll use everywhere in ImGui to render filled shapes. +const int FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF = 108; +const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27; +const unsigned int FONT_ATLAS_DEFAULT_TEX_DATA_ID = 0x80000000; +static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = +{ + "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX " + "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X " + "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X " + "X - X.X - X.....X - X.....X -X...X - X...X- X..X " + "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X " + "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX " + "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX " + "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX " + "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X " + "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X" + "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X" + "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X" + "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X" + "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X" + "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X" + "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X" + "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X " + "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X " + "X.X X..X - -X.......X- X.......X - XX XX - - X..........X " + "XX X..X - - X.....X - X.....X - X.X X.X - - X........X " + " X..X - X...X - X...X - X..X X..X - - X........X " + " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX " + "------------ - X - X -X.....................X- ------------------" + " ----------------------------------- X...XXXXXXXXXXXXX...X - " + " - X..X X..X - " + " - X.X X.X - " + " - XX XX - " +}; + +static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] = +{ + // Pos ........ Size ......... Offset ...... + { ImVec2( 0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow + { ImVec2(13,0), ImVec2( 7,16), ImVec2( 1, 8) }, // ImGuiMouseCursor_TextInput + { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll + { ImVec2(21,0), ImVec2( 9,23), ImVec2( 4,11) }, // ImGuiMouseCursor_ResizeNS + { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, // ImGuiMouseCursor_ResizeEW + { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW + { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE + { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand +}; + +ImFontAtlas::ImFontAtlas() +{ + Locked = false; + Flags = ImFontAtlasFlags_None; + TexID = (ImTextureID)NULL; + TexDesiredWidth = 0; + TexGlyphPadding = 1; + + TexPixelsAlpha8 = NULL; + TexPixelsRGBA32 = NULL; + TexWidth = TexHeight = 0; + TexUvScale = ImVec2(0.0f, 0.0f); + TexUvWhitePixel = ImVec2(0.0f, 0.0f); + for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++) + CustomRectIds[n] = -1; +} + +ImFontAtlas::~ImFontAtlas() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + Clear(); +} + +void ImFontAtlas::ClearInputData() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + for (int i = 0; i < ConfigData.Size; i++) + if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas) + { + ImGui::MemFree(ConfigData[i].FontData); + ConfigData[i].FontData = NULL; + } + + // When clearing this we lose access to the font name and other information used to build the font. + for (int i = 0; i < Fonts.Size; i++) + if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size) + { + Fonts[i]->ConfigData = NULL; + Fonts[i]->ConfigDataCount = 0; + } + ConfigData.clear(); + CustomRects.clear(); + for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++) + CustomRectIds[n] = -1; +} + +void ImFontAtlas::ClearTexData() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + if (TexPixelsAlpha8) + ImGui::MemFree(TexPixelsAlpha8); + if (TexPixelsRGBA32) + ImGui::MemFree(TexPixelsRGBA32); + TexPixelsAlpha8 = NULL; + TexPixelsRGBA32 = NULL; +} + +void ImFontAtlas::ClearFonts() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + for (int i = 0; i < Fonts.Size; i++) + IM_DELETE(Fonts[i]); + Fonts.clear(); +} + +void ImFontAtlas::Clear() +{ + ClearInputData(); + ClearTexData(); + ClearFonts(); +} + +void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +{ + // Build atlas on demand + if (TexPixelsAlpha8 == NULL) + { + if (ConfigData.empty()) + AddFontDefault(); + Build(); + } + + *out_pixels = TexPixelsAlpha8; + if (out_width) *out_width = TexWidth; + if (out_height) *out_height = TexHeight; + if (out_bytes_per_pixel) *out_bytes_per_pixel = 1; +} + +void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +{ + // Convert to RGBA32 format on demand + // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp + if (!TexPixelsRGBA32) + { + unsigned char* pixels = NULL; + GetTexDataAsAlpha8(&pixels, NULL, NULL); + if (pixels) + { + TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)TexWidth * (size_t)TexHeight * 4); + const unsigned char* src = pixels; + unsigned int* dst = TexPixelsRGBA32; + for (int n = TexWidth * TexHeight; n > 0; n--) + *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++)); + } + } + + *out_pixels = (unsigned char*)TexPixelsRGBA32; + if (out_width) *out_width = TexWidth; + if (out_height) *out_height = TexHeight; + if (out_bytes_per_pixel) *out_bytes_per_pixel = 4; +} + +ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0); + IM_ASSERT(font_cfg->SizePixels > 0.0f); + + // Create new font + if (!font_cfg->MergeMode) + Fonts.push_back(IM_NEW(ImFont)); + else + IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. + + ConfigData.push_back(*font_cfg); + ImFontConfig& new_font_cfg = ConfigData.back(); + if (new_font_cfg.DstFont == NULL) + new_font_cfg.DstFont = Fonts.back(); + if (!new_font_cfg.FontDataOwnedByAtlas) + { + new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize); + new_font_cfg.FontDataOwnedByAtlas = true; + memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize); + } + + // Invalidate texture + ClearTexData(); + return new_font_cfg.DstFont; +} + +// Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder) +static unsigned int stb_decompress_length(const unsigned char *input); +static unsigned int stb_decompress(unsigned char *output, const unsigned char *input, unsigned int length); +static const char* GetDefaultCompressedFontDataTTFBase85(); +static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; } +static void Decode85(const unsigned char* src, unsigned char* dst) +{ + while (*src) + { + unsigned int tmp = Decode85Byte(src[0]) + 85*(Decode85Byte(src[1]) + 85*(Decode85Byte(src[2]) + 85*(Decode85Byte(src[3]) + 85*Decode85Byte(src[4])))); + dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness. + src += 5; + dst += 4; + } +} + +// Load embedded ProggyClean.ttf at size 13, disable oversampling +ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) +{ + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + if (!font_cfg_template) + { + font_cfg.OversampleH = font_cfg.OversampleV = 1; + font_cfg.PixelSnapH = true; + } + if (font_cfg.SizePixels <= 0.0f) + font_cfg.SizePixels = 13.0f * 1.0f; + if (font_cfg.Name[0] == '\0') + ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels); + + const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); + const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); + ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges); + font->DisplayOffset.y = 1.0f; + return font; +} + +ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + size_t data_size = 0; + void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0); + if (!data) + { + IM_ASSERT(0); // Could not load file. + return NULL; + } + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + if (font_cfg.Name[0] == '\0') + { + // Store a short copy of filename into into the font name for convenience + const char* p; + for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {} + ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels); + } + return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges); +} + +// NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build(). +ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + IM_ASSERT(font_cfg.FontData == NULL); + font_cfg.FontData = ttf_data; + font_cfg.FontDataSize = ttf_size; + font_cfg.SizePixels = size_pixels; + if (glyph_ranges) + font_cfg.GlyphRanges = glyph_ranges; + return AddFont(&font_cfg); +} + +ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +{ + const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data); + unsigned char* buf_decompressed_data = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size); + stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size); + + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + IM_ASSERT(font_cfg.FontData == NULL); + font_cfg.FontDataOwnedByAtlas = true; + return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges); +} + +ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges) +{ + int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4; + void* compressed_ttf = ImGui::MemAlloc((size_t)compressed_ttf_size); + Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf); + ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges); + ImGui::MemFree(compressed_ttf); + return font; +} + +int ImFontAtlas::AddCustomRectRegular(unsigned int id, int width, int height) +{ + IM_ASSERT(id >= 0x10000); + IM_ASSERT(width > 0 && width <= 0xFFFF); + IM_ASSERT(height > 0 && height <= 0xFFFF); + CustomRect r; + r.ID = id; + r.Width = (unsigned short)width; + r.Height = (unsigned short)height; + CustomRects.push_back(r); + return CustomRects.Size - 1; // Return index +} + +int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset) +{ + IM_ASSERT(font != NULL); + IM_ASSERT(width > 0 && width <= 0xFFFF); + IM_ASSERT(height > 0 && height <= 0xFFFF); + CustomRect r; + r.ID = id; + r.Width = (unsigned short)width; + r.Height = (unsigned short)height; + r.GlyphAdvanceX = advance_x; + r.GlyphOffset = offset; + r.Font = font; + CustomRects.push_back(r); + return CustomRects.Size - 1; // Return index +} + +void ImFontAtlas::CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) +{ + IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates + IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed + *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y); + *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y); +} + +bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]) +{ + if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT) + return false; + if (Flags & ImFontAtlasFlags_NoMouseCursors) + return false; + + IM_ASSERT(CustomRectIds[0] != -1); + ImFontAtlas::CustomRect& r = CustomRects[CustomRectIds[0]]; + IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID); + ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r.X, (float)r.Y); + ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1]; + *out_size = size; + *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2]; + out_uv_border[0] = (pos) * TexUvScale; + out_uv_border[1] = (pos + size) * TexUvScale; + pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1; + out_uv_fill[0] = (pos) * TexUvScale; + out_uv_fill[1] = (pos + size) * TexUvScale; + return true; +} + +bool ImFontAtlas::Build() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + return ImFontAtlasBuildWithStbTruetype(this); +} + +void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor) +{ + for (unsigned int i = 0; i < 256; i++) + { + unsigned int value = (unsigned int)(i * in_brighten_factor); + out_table[i] = value > 255 ? 255 : (value & 0xFF); + } +} + +void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride) +{ + unsigned char* data = pixels + x + y * stride; + for (int j = h; j > 0; j--, data += stride) + for (int i = 0; i < w; i++) + data[i] = table[data[i]]; +} + +// Temporary data for one source font (multiple source fonts can be merged into one destination ImFont) +// (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.) +struct ImFontBuildSrcData +{ + stbtt_fontinfo FontInfo; + stbtt_pack_range PackRange; // Hold the list of codepoints to pack (essentially points to Codepoints.Data) + stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position. + stbtt_packedchar* PackedChars; // Output glyphs + const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF) + int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[] + int GlyphsHighest; // Highest requested codepoint + int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font) + ImBoolVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB) + ImVector GlyphsList; // Glyph codepoints list (flattened version of GlyphsMap) +}; + +// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont) +struct ImFontBuildDstData +{ + int SrcCount; // Number of source fonts targeting this destination font. + int GlyphsHighest; + int GlyphsCount; + ImBoolVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font. +}; + +static void UnpackBoolVectorToFlatIndexList(const ImBoolVector* in, ImVector* out) +{ + IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int)); + const int* it_begin = in->Storage.begin(); + const int* it_end = in->Storage.end(); + for (const int* it = it_begin; it < it_end; it++) + if (int entries_32 = *it) + for (int bit_n = 0; bit_n < 32; bit_n++) + if (entries_32 & (1 << bit_n)) + out->push_back((int)((it - it_begin) << 5) + bit_n); +} + +bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) +{ + IM_ASSERT(atlas->ConfigData.Size > 0); + + ImFontAtlasBuildRegisterDefaultCustomRects(atlas); + + // Clear atlas + atlas->TexID = (ImTextureID)NULL; + atlas->TexWidth = atlas->TexHeight = 0; + atlas->TexUvScale = ImVec2(0.0f, 0.0f); + atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); + atlas->ClearTexData(); + + // Temporary storage for building + ImVector src_tmp_array; + ImVector dst_tmp_array; + src_tmp_array.resize(atlas->ConfigData.Size); + dst_tmp_array.resize(atlas->Fonts.Size); + memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes()); + memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes()); + + // 1. Initialize font loading structure, check font data validity + for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + ImFontConfig& cfg = atlas->ConfigData[src_i]; + IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas)); + + // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) + src_tmp.DstIndex = -1; + for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++) + if (cfg.DstFont == atlas->Fonts[output_i]) + src_tmp.DstIndex = output_i; + IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array? + if (src_tmp.DstIndex == -1) + return false; + + // Initialize helper structure for font loading and verify that the TTF/OTF data is correct + const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo); + IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found."); + if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset)) + return false; + + // Measure highest codepoints + ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; + src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); + for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) + src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); + dst_tmp.SrcCount++; + dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); + } + + // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs. + int total_glyphs_count = 0; + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; + src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1); + if (dst_tmp.GlyphsSet.Storage.empty()) + dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1); + + for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) + for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) + { + if (dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true) + continue; + if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font? + continue; + + // Add to avail set/counters + src_tmp.GlyphsCount++; + dst_tmp.GlyphsCount++; + src_tmp.GlyphsSet.SetBit(codepoint, true); + dst_tmp.GlyphsSet.SetBit(codepoint, true); + total_glyphs_count++; + } + } + + // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another) + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount); + UnpackBoolVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList); + src_tmp.GlyphsSet.Clear(); + IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount); + } + for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++) + dst_tmp_array[dst_i].GlyphsSet.Clear(); + dst_tmp_array.clear(); + + // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) + // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity) + ImVector buf_rects; + ImVector buf_packedchars; + buf_rects.resize(total_glyphs_count); + buf_packedchars.resize(total_glyphs_count); + memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes()); + memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes()); + + // 4. Gather glyphs sizes so we can pack them in our virtual canvas. + int total_surface = 0; + int buf_rects_out_n = 0; + int buf_packedchars_out_n = 0; + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + src_tmp.Rects = &buf_rects[buf_rects_out_n]; + src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n]; + buf_rects_out_n += src_tmp.GlyphsCount; + buf_packedchars_out_n += src_tmp.GlyphsCount; + + // Convert our ranges in the format stb_truetype wants + ImFontConfig& cfg = atlas->ConfigData[src_i]; + src_tmp.PackRange.font_size = cfg.SizePixels; + src_tmp.PackRange.first_unicode_codepoint_in_range = 0; + src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data; + src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size; + src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars; + src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH; + src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV; + + // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects) + const float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels); + const int padding = atlas->TexGlyphPadding; + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) + { + int x0, y0, x1, y1; + const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]); + IM_ASSERT(glyph_index_in_font != 0); + stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1); + src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1); + src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1); + total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; + } + } + + // We need a width for the skyline algorithm, any width! + // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. + // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface. + const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1; + atlas->TexHeight = 0; + if (atlas->TexDesiredWidth > 0) + atlas->TexWidth = atlas->TexDesiredWidth; + else + atlas->TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512; + + // 5. Start packing + // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). + const int TEX_HEIGHT_MAX = 1024 * 32; + stbtt_pack_context spc = {}; + stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL); + ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info); + + // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point. + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount); + + // Extend texture height and mark missing glyphs as non-packed so we won't render them. + // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?) + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) + if (src_tmp.Rects[glyph_i].was_packed) + atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h); + } + + // 7. Allocate texture + atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); + atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); + atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight); + memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); + spc.pixels = atlas->TexPixelsAlpha8; + spc.height = atlas->TexHeight; + + // 8. Render/rasterize font characters into the texture + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects); + + // Apply multiply operator + if (cfg.RasterizerMultiply != 1.0f) + { + unsigned char multiply_table[256]; + ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); + stbrp_rect* r = &src_tmp.Rects[0]; + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++) + if (r->was_packed) + ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1); + } + src_tmp.Rects = NULL; + } + + // End packing + stbtt_PackEnd(&spc); + buf_rects.clear(); + + // 9. Setup ImFont and glyphs for runtime + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true) + + const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels); + int unscaled_ascent, unscaled_descent, unscaled_line_gap; + stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); + + const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1)); + const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1)); + ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); + const float font_off_x = cfg.GlyphOffset.x; + const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f); + + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) + { + const int codepoint = src_tmp.GlyphsList[glyph_i]; + const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i]; + + const float char_advance_x_org = pc.xadvance; + const float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX); + float char_off_x = font_off_x; + if (char_advance_x_org != char_advance_x_mod) + char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f; + + // Register glyph + stbtt_aligned_quad q; + float dummy_x = 0.0f, dummy_y = 0.0f; + stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &dummy_x, &dummy_y, &q, 0); + dst_font->AddGlyph((ImWchar)codepoint, q.x0 + char_off_x, q.y0 + font_off_y, q.x1 + char_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, char_advance_x_mod); + } + } + + // Cleanup temporary (ImVector doesn't honor destructor) + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + src_tmp_array[src_i].~ImFontBuildSrcData(); + + ImFontAtlasBuildFinish(atlas); + return true; +} + +void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas) +{ + if (atlas->CustomRectIds[0] >= 0) + return; + if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) + atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_ID, FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1, FONT_ATLAS_DEFAULT_TEX_DATA_H); + else + atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_ID, 2, 2); +} + +void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent) +{ + if (!font_config->MergeMode) + { + font->ClearOutputData(); + font->FontSize = font_config->SizePixels; + font->ConfigData = font_config; + font->ContainerAtlas = atlas; + font->Ascent = ascent; + font->Descent = descent; + } + font->ConfigDataCount++; +} + +void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque) +{ + stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque; + IM_ASSERT(pack_context != NULL); + + ImVector& user_rects = atlas->CustomRects; + IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong. + + ImVector pack_rects; + pack_rects.resize(user_rects.Size); + memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes()); + for (int i = 0; i < user_rects.Size; i++) + { + pack_rects[i].w = user_rects[i].Width; + pack_rects[i].h = user_rects[i].Height; + } + stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size); + for (int i = 0; i < pack_rects.Size; i++) + if (pack_rects[i].was_packed) + { + user_rects[i].X = pack_rects[i].x; + user_rects[i].Y = pack_rects[i].y; + IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height); + atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h); + } +} + +static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) +{ + IM_ASSERT(atlas->CustomRectIds[0] >= 0); + IM_ASSERT(atlas->TexPixelsAlpha8 != NULL); + ImFontAtlas::CustomRect& r = atlas->CustomRects[atlas->CustomRectIds[0]]; + IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID); + IM_ASSERT(r.IsPacked()); + + const int w = atlas->TexWidth; + if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) + { + // Render/copy pixels + IM_ASSERT(r.Width == FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * 2 + 1 && r.Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); + for (int y = 0, n = 0; y < FONT_ATLAS_DEFAULT_TEX_DATA_H; y++) + for (int x = 0; x < FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF; x++, n++) + { + const int offset0 = (int)(r.X + x) + (int)(r.Y + y) * w; + const int offset1 = offset0 + FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1; + atlas->TexPixelsAlpha8[offset0] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == '.' ? 0xFF : 0x00; + atlas->TexPixelsAlpha8[offset1] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == 'X' ? 0xFF : 0x00; + } + } + else + { + IM_ASSERT(r.Width == 2 && r.Height == 2); + const int offset = (int)(r.X) + (int)(r.Y) * w; + atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; + } + atlas->TexUvWhitePixel = ImVec2((r.X + 0.5f) * atlas->TexUvScale.x, (r.Y + 0.5f) * atlas->TexUvScale.y); +} + +void ImFontAtlasBuildFinish(ImFontAtlas* atlas) +{ + // Render into our custom data block + ImFontAtlasBuildRenderDefaultTexData(atlas); + + // Register custom rectangle glyphs + for (int i = 0; i < atlas->CustomRects.Size; i++) + { + const ImFontAtlas::CustomRect& r = atlas->CustomRects[i]; + if (r.Font == NULL || r.ID > 0x10000) + continue; + + IM_ASSERT(r.Font->ContainerAtlas == atlas); + ImVec2 uv0, uv1; + atlas->CalcCustomRectUV(&r, &uv0, &uv1); + r.Font->AddGlyph((ImWchar)r.ID, r.GlyphOffset.x, r.GlyphOffset.y, r.GlyphOffset.x + r.Width, r.GlyphOffset.y + r.Height, uv0.x, uv0.y, uv1.x, uv1.y, r.GlyphAdvanceX); + } + + // Build all fonts lookup tables + for (int i = 0; i < atlas->Fonts.Size; i++) + if (atlas->Fonts[i]->DirtyLookupTables) + atlas->Fonts[i]->BuildLookupTable(); +} + +// Retrieve list of range (2 int per range, values are inclusive) +const ImWchar* ImFontAtlas::GetGlyphRangesDefault() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesKorean() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x3131, 0x3163, // Korean alphabets + 0xAC00, 0xD79D, // Korean characters + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x2000, 0x206F, // General Punctuation + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF, // Half-width characters + 0x4e00, 0x9FAF, // CJK Ideograms + 0, + }; + return &ranges[0]; +} + +static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* accumulative_offsets, int accumulative_offsets_count, ImWchar* out_ranges) +{ + for (int n = 0; n < accumulative_offsets_count; n++, out_ranges += 2) + { + out_ranges[0] = out_ranges[1] = (ImWchar)(base_codepoint + accumulative_offsets[n]); + base_codepoint += accumulative_offsets[n]; + } + out_ranges[0] = 0; +} + +//------------------------------------------------------------------------- +// [SECTION] ImFontAtlas glyph ranges helpers +//------------------------------------------------------------------------- + +const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() +{ + // Store 2500 regularly used characters for Simplified Chinese. + // Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8 + // This table covers 97.97% of all characters used during the month in July, 1987. + // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. + // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) + static const short accumulative_offsets_from_0x4E00[] = + { + 0,1,2,4,1,1,1,1,2,1,3,2,1,2,2,1,1,1,1,1,5,2,1,2,3,3,3,2,2,4,1,1,1,2,1,5,2,3,1,2,1,2,1,1,2,1,1,2,2,1,4,1,1,1,1,5,10,1,2,19,2,1,2,1,2,1,2,1,2, + 1,5,1,6,3,2,1,2,2,1,1,1,4,8,5,1,1,4,1,1,3,1,2,1,5,1,2,1,1,1,10,1,1,5,2,4,6,1,4,2,2,2,12,2,1,1,6,1,1,1,4,1,1,4,6,5,1,4,2,2,4,10,7,1,1,4,2,4, + 2,1,4,3,6,10,12,5,7,2,14,2,9,1,1,6,7,10,4,7,13,1,5,4,8,4,1,1,2,28,5,6,1,1,5,2,5,20,2,2,9,8,11,2,9,17,1,8,6,8,27,4,6,9,20,11,27,6,68,2,2,1,1, + 1,2,1,2,2,7,6,11,3,3,1,1,3,1,2,1,1,1,1,1,3,1,1,8,3,4,1,5,7,2,1,4,4,8,4,2,1,2,1,1,4,5,6,3,6,2,12,3,1,3,9,2,4,3,4,1,5,3,3,1,3,7,1,5,1,1,1,1,2, + 3,4,5,2,3,2,6,1,1,2,1,7,1,7,3,4,5,15,2,2,1,5,3,22,19,2,1,1,1,1,2,5,1,1,1,6,1,1,12,8,2,9,18,22,4,1,1,5,1,16,1,2,7,10,15,1,1,6,2,4,1,2,4,1,6, + 1,1,3,2,4,1,6,4,5,1,2,1,1,2,1,10,3,1,3,2,1,9,3,2,5,7,2,19,4,3,6,1,1,1,1,1,4,3,2,1,1,1,2,5,3,1,1,1,2,2,1,1,2,1,1,2,1,3,1,1,1,3,7,1,4,1,1,2,1, + 1,2,1,2,4,4,3,8,1,1,1,2,1,3,5,1,3,1,3,4,6,2,2,14,4,6,6,11,9,1,15,3,1,28,5,2,5,5,3,1,3,4,5,4,6,14,3,2,3,5,21,2,7,20,10,1,2,19,2,4,28,28,2,3, + 2,1,14,4,1,26,28,42,12,40,3,52,79,5,14,17,3,2,2,11,3,4,6,3,1,8,2,23,4,5,8,10,4,2,7,3,5,1,1,6,3,1,2,2,2,5,28,1,1,7,7,20,5,3,29,3,17,26,1,8,4, + 27,3,6,11,23,5,3,4,6,13,24,16,6,5,10,25,35,7,3,2,3,3,14,3,6,2,6,1,4,2,3,8,2,1,1,3,3,3,4,1,1,13,2,2,4,5,2,1,14,14,1,2,2,1,4,5,2,3,1,14,3,12, + 3,17,2,16,5,1,2,1,8,9,3,19,4,2,2,4,17,25,21,20,28,75,1,10,29,103,4,1,2,1,1,4,2,4,1,2,3,24,2,2,2,1,1,2,1,3,8,1,1,1,2,1,1,3,1,1,1,6,1,5,3,1,1, + 1,3,4,1,1,5,2,1,5,6,13,9,16,1,1,1,1,3,2,3,2,4,5,2,5,2,2,3,7,13,7,2,2,1,1,1,1,2,3,3,2,1,6,4,9,2,1,14,2,14,2,1,18,3,4,14,4,11,41,15,23,15,23, + 176,1,3,4,1,1,1,1,5,3,1,2,3,7,3,1,1,2,1,2,4,4,6,2,4,1,9,7,1,10,5,8,16,29,1,1,2,2,3,1,3,5,2,4,5,4,1,1,2,2,3,3,7,1,6,10,1,17,1,44,4,6,2,1,1,6, + 5,4,2,10,1,6,9,2,8,1,24,1,2,13,7,8,8,2,1,4,1,3,1,3,3,5,2,5,10,9,4,9,12,2,1,6,1,10,1,1,7,7,4,10,8,3,1,13,4,3,1,6,1,3,5,2,1,2,17,16,5,2,16,6, + 1,4,2,1,3,3,6,8,5,11,11,1,3,3,2,4,6,10,9,5,7,4,7,4,7,1,1,4,2,1,3,6,8,7,1,6,11,5,5,3,24,9,4,2,7,13,5,1,8,82,16,61,1,1,1,4,2,2,16,10,3,8,1,1, + 6,4,2,1,3,1,1,1,4,3,8,4,2,2,1,1,1,1,1,6,3,5,1,1,4,6,9,2,1,1,1,2,1,7,2,1,6,1,5,4,4,3,1,8,1,3,3,1,3,2,2,2,2,3,1,6,1,2,1,2,1,3,7,1,8,2,1,2,1,5, + 2,5,3,5,10,1,2,1,1,3,2,5,11,3,9,3,5,1,1,5,9,1,2,1,5,7,9,9,8,1,3,3,3,6,8,2,3,2,1,1,32,6,1,2,15,9,3,7,13,1,3,10,13,2,14,1,13,10,2,1,3,10,4,15, + 2,15,15,10,1,3,9,6,9,32,25,26,47,7,3,2,3,1,6,3,4,3,2,8,5,4,1,9,4,2,2,19,10,6,2,3,8,1,2,2,4,2,1,9,4,4,4,6,4,8,9,2,3,1,1,1,1,3,5,5,1,3,8,4,6, + 2,1,4,12,1,5,3,7,13,2,5,8,1,6,1,2,5,14,6,1,5,2,4,8,15,5,1,23,6,62,2,10,1,1,8,1,2,2,10,4,2,2,9,2,1,1,3,2,3,1,5,3,3,2,1,3,8,1,1,1,11,3,1,1,4, + 3,7,1,14,1,2,3,12,5,2,5,1,6,7,5,7,14,11,1,3,1,8,9,12,2,1,11,8,4,4,2,6,10,9,13,1,1,3,1,5,1,3,2,4,4,1,18,2,3,14,11,4,29,4,2,7,1,3,13,9,2,2,5, + 3,5,20,7,16,8,5,72,34,6,4,22,12,12,28,45,36,9,7,39,9,191,1,1,1,4,11,8,4,9,2,3,22,1,1,1,1,4,17,1,7,7,1,11,31,10,2,4,8,2,3,2,1,4,2,16,4,32,2, + 3,19,13,4,9,1,5,2,14,8,1,1,3,6,19,6,5,1,16,6,2,10,8,5,1,2,3,1,5,5,1,11,6,6,1,3,3,2,6,3,8,1,1,4,10,7,5,7,7,5,8,9,2,1,3,4,1,1,3,1,3,3,2,6,16, + 1,4,6,3,1,10,6,1,3,15,2,9,2,10,25,13,9,16,6,2,2,10,11,4,3,9,1,2,6,6,5,4,30,40,1,10,7,12,14,33,6,3,6,7,3,1,3,1,11,14,4,9,5,12,11,49,18,51,31, + 140,31,2,2,1,5,1,8,1,10,1,4,4,3,24,1,10,1,3,6,6,16,3,4,5,2,1,4,2,57,10,6,22,2,22,3,7,22,6,10,11,36,18,16,33,36,2,5,5,1,1,1,4,10,1,4,13,2,7, + 5,2,9,3,4,1,7,43,3,7,3,9,14,7,9,1,11,1,1,3,7,4,18,13,1,14,1,3,6,10,73,2,2,30,6,1,11,18,19,13,22,3,46,42,37,89,7,3,16,34,2,2,3,9,1,7,1,1,1,2, + 2,4,10,7,3,10,3,9,5,28,9,2,6,13,7,3,1,3,10,2,7,2,11,3,6,21,54,85,2,1,4,2,2,1,39,3,21,2,2,5,1,1,1,4,1,1,3,4,15,1,3,2,4,4,2,3,8,2,20,1,8,7,13, + 4,1,26,6,2,9,34,4,21,52,10,4,4,1,5,12,2,11,1,7,2,30,12,44,2,30,1,1,3,6,16,9,17,39,82,2,2,24,7,1,7,3,16,9,14,44,2,1,2,1,2,3,5,2,4,1,6,7,5,3, + 2,6,1,11,5,11,2,1,18,19,8,1,3,24,29,2,1,3,5,2,2,1,13,6,5,1,46,11,3,5,1,1,5,8,2,10,6,12,6,3,7,11,2,4,16,13,2,5,1,1,2,2,5,2,28,5,2,23,10,8,4, + 4,22,39,95,38,8,14,9,5,1,13,5,4,3,13,12,11,1,9,1,27,37,2,5,4,4,63,211,95,2,2,2,1,3,5,2,1,1,2,2,1,1,1,3,2,4,1,2,1,1,5,2,2,1,1,2,3,1,3,1,1,1, + 3,1,4,2,1,3,6,1,1,3,7,15,5,3,2,5,3,9,11,4,2,22,1,6,3,8,7,1,4,28,4,16,3,3,25,4,4,27,27,1,4,1,2,2,7,1,3,5,2,28,8,2,14,1,8,6,16,25,3,3,3,14,3, + 3,1,1,2,1,4,6,3,8,4,1,1,1,2,3,6,10,6,2,3,18,3,2,5,5,4,3,1,5,2,5,4,23,7,6,12,6,4,17,11,9,5,1,1,10,5,12,1,1,11,26,33,7,3,6,1,17,7,1,5,12,1,11, + 2,4,1,8,14,17,23,1,2,1,7,8,16,11,9,6,5,2,6,4,16,2,8,14,1,11,8,9,1,1,1,9,25,4,11,19,7,2,15,2,12,8,52,7,5,19,2,16,4,36,8,1,16,8,24,26,4,6,2,9, + 5,4,36,3,28,12,25,15,37,27,17,12,59,38,5,32,127,1,2,9,17,14,4,1,2,1,1,8,11,50,4,14,2,19,16,4,17,5,4,5,26,12,45,2,23,45,104,30,12,8,3,10,2,2, + 3,3,1,4,20,7,2,9,6,15,2,20,1,3,16,4,11,15,6,134,2,5,59,1,2,2,2,1,9,17,3,26,137,10,211,59,1,2,4,1,4,1,1,1,2,6,2,3,1,1,2,3,2,3,1,3,4,4,2,3,3, + 1,4,3,1,7,2,2,3,1,2,1,3,3,3,2,2,3,2,1,3,14,6,1,3,2,9,6,15,27,9,34,145,1,1,2,1,1,1,1,2,1,1,1,1,2,2,2,3,1,2,1,1,1,2,3,5,8,3,5,2,4,1,3,2,2,2,12, + 4,1,1,1,10,4,5,1,20,4,16,1,15,9,5,12,2,9,2,5,4,2,26,19,7,1,26,4,30,12,15,42,1,6,8,172,1,1,4,2,1,1,11,2,2,4,2,1,2,1,10,8,1,2,1,4,5,1,2,5,1,8, + 4,1,3,4,2,1,6,2,1,3,4,1,2,1,1,1,1,12,5,7,2,4,3,1,1,1,3,3,6,1,2,2,3,3,3,2,1,2,12,14,11,6,6,4,12,2,8,1,7,10,1,35,7,4,13,15,4,3,23,21,28,52,5, + 26,5,6,1,7,10,2,7,53,3,2,1,1,1,2,163,532,1,10,11,1,3,3,4,8,2,8,6,2,2,23,22,4,2,2,4,2,1,3,1,3,3,5,9,8,2,1,2,8,1,10,2,12,21,20,15,105,2,3,1,1, + 3,2,3,1,1,2,5,1,4,15,11,19,1,1,1,1,5,4,5,1,1,2,5,3,5,12,1,2,5,1,11,1,1,15,9,1,4,5,3,26,8,2,1,3,1,1,15,19,2,12,1,2,5,2,7,2,19,2,20,6,26,7,5, + 2,2,7,34,21,13,70,2,128,1,1,2,1,1,2,1,1,3,2,2,2,15,1,4,1,3,4,42,10,6,1,49,85,8,1,2,1,1,4,4,2,3,6,1,5,7,4,3,211,4,1,2,1,2,5,1,2,4,2,2,6,5,6, + 10,3,4,48,100,6,2,16,296,5,27,387,2,2,3,7,16,8,5,38,15,39,21,9,10,3,7,59,13,27,21,47,5,21,6 + }; + static ImWchar base_ranges[] = // not zero-terminated + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x2000, 0x206F, // General Punctuation + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF // Half-width characters + }; + static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 }; + if (!full_ranges[0]) + { + memcpy(full_ranges, base_ranges, sizeof(base_ranges)); + UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); + } + return &full_ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() +{ + // 1946 common ideograms code points for Japanese + // Sourced from http://theinstructionlimit.com/common-kanji-character-ranges-for-xna-spritefont-rendering + // FIXME: Source a list of the revised 2136 Joyo Kanji list from 2010 and rebuild this. + // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. + // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) + static const short accumulative_offsets_from_0x4E00[] = + { + 0,1,2,4,1,1,1,1,2,1,6,2,2,1,8,5,7,11,1,2,10,10,8,2,4,20,2,11,8,2,1,2,1,6,2,1,7,5,3,7,1,1,13,7,9,1,4,6,1,2,1,10,1,1,9,2,2,4,5,6,14,1,1,9,3,18, + 5,4,2,2,10,7,1,1,1,3,2,4,3,23,2,10,12,2,14,2,4,13,1,6,10,3,1,7,13,6,4,13,5,2,3,17,2,2,5,7,6,4,1,7,14,16,6,13,9,15,1,1,7,16,4,7,1,19,9,2,7,15, + 2,6,5,13,25,4,14,13,11,25,1,1,1,2,1,2,2,3,10,11,3,3,1,1,4,4,2,1,4,9,1,4,3,5,5,2,7,12,11,15,7,16,4,5,16,2,1,1,6,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1, + 2,1,12,3,3,9,5,8,1,11,1,2,3,18,20,4,1,3,6,1,7,3,5,5,7,2,2,12,3,1,4,2,3,2,3,11,8,7,4,17,1,9,25,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,6,16,1,2,1,1,3,12, + 20,2,5,20,8,7,6,2,1,1,1,1,6,2,1,2,10,1,1,6,1,3,1,2,1,4,1,12,4,1,3,1,1,1,1,1,10,4,7,5,13,1,15,1,1,30,11,9,1,15,38,14,1,32,17,20,1,9,31,2,21,9, + 4,49,22,2,1,13,1,11,45,35,43,55,12,19,83,1,3,2,3,13,2,1,7,3,18,3,13,8,1,8,18,5,3,7,25,24,9,24,40,3,17,24,2,1,6,2,3,16,15,6,7,3,12,1,9,7,3,3, + 3,15,21,5,16,4,5,12,11,11,3,6,3,2,31,3,2,1,1,23,6,6,1,4,2,6,5,2,1,1,3,3,22,2,6,2,3,17,3,2,4,5,1,9,5,1,1,6,15,12,3,17,2,14,2,8,1,23,16,4,2,23, + 8,15,23,20,12,25,19,47,11,21,65,46,4,3,1,5,6,1,2,5,26,2,1,1,3,11,1,1,1,2,1,2,3,1,1,10,2,3,1,1,1,3,6,3,2,2,6,6,9,2,2,2,6,2,5,10,2,4,1,2,1,2,2, + 3,1,1,3,1,2,9,23,9,2,1,1,1,1,5,3,2,1,10,9,6,1,10,2,31,25,3,7,5,40,1,15,6,17,7,27,180,1,3,2,2,1,1,1,6,3,10,7,1,3,6,17,8,6,2,2,1,3,5,5,8,16,14, + 15,1,1,4,1,2,1,1,1,3,2,7,5,6,2,5,10,1,4,2,9,1,1,11,6,1,44,1,3,7,9,5,1,3,1,1,10,7,1,10,4,2,7,21,15,7,2,5,1,8,3,4,1,3,1,6,1,4,2,1,4,10,8,1,4,5, + 1,5,10,2,7,1,10,1,1,3,4,11,10,29,4,7,3,5,2,3,33,5,2,19,3,1,4,2,6,31,11,1,3,3,3,1,8,10,9,12,11,12,8,3,14,8,6,11,1,4,41,3,1,2,7,13,1,5,6,2,6,12, + 12,22,5,9,4,8,9,9,34,6,24,1,1,20,9,9,3,4,1,7,2,2,2,6,2,28,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,8,8,3,2,1,5,1,2,2,3,1,11,11,7,3,6,10,8,6,16,16, + 22,7,12,6,21,5,4,6,6,3,6,1,3,2,1,2,8,29,1,10,1,6,13,6,6,19,31,1,13,4,4,22,17,26,33,10,4,15,12,25,6,67,10,2,3,1,6,10,2,6,2,9,1,9,4,4,1,2,16,2, + 5,9,2,3,8,1,8,3,9,4,8,6,4,8,11,3,2,1,1,3,26,1,7,5,1,11,1,5,3,5,2,13,6,39,5,1,5,2,11,6,10,5,1,15,5,3,6,19,21,22,2,4,1,6,1,8,1,4,8,2,4,2,2,9,2, + 1,1,1,4,3,6,3,12,7,1,14,2,4,10,2,13,1,17,7,3,2,1,3,2,13,7,14,12,3,1,29,2,8,9,15,14,9,14,1,3,1,6,5,9,11,3,38,43,20,7,7,8,5,15,12,19,15,81,8,7, + 1,5,73,13,37,28,8,8,1,15,18,20,165,28,1,6,11,8,4,14,7,15,1,3,3,6,4,1,7,14,1,1,11,30,1,5,1,4,14,1,4,2,7,52,2,6,29,3,1,9,1,21,3,5,1,26,3,11,14, + 11,1,17,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,7,7,5,17,3,3,3,1,23,10,4,4,6,3,1,16,17,22,3,10,21,16,16,6,4,10,2,1,1,2,8,8,6,5,3,3,3,39,25, + 15,1,1,16,6,7,25,15,6,6,12,1,22,13,1,4,9,5,12,2,9,1,12,28,8,3,5,10,22,60,1,2,40,4,61,63,4,1,13,12,1,4,31,12,1,14,89,5,16,6,29,14,2,5,49,18,18, + 5,29,33,47,1,17,1,19,12,2,9,7,39,12,3,7,12,39,3,1,46,4,12,3,8,9,5,31,15,18,3,2,2,66,19,13,17,5,3,46,124,13,57,34,2,5,4,5,8,1,1,1,4,3,1,17,5, + 3,5,3,1,8,5,6,3,27,3,26,7,12,7,2,17,3,7,18,78,16,4,36,1,2,1,6,2,1,39,17,7,4,13,4,4,4,1,10,4,2,4,6,3,10,1,19,1,26,2,4,33,2,73,47,7,3,8,2,4,15, + 18,1,29,2,41,14,1,21,16,41,7,39,25,13,44,2,2,10,1,13,7,1,7,3,5,20,4,8,2,49,1,10,6,1,6,7,10,7,11,16,3,12,20,4,10,3,1,2,11,2,28,9,2,4,7,2,15,1, + 27,1,28,17,4,5,10,7,3,24,10,11,6,26,3,2,7,2,2,49,16,10,16,15,4,5,27,61,30,14,38,22,2,7,5,1,3,12,23,24,17,17,3,3,2,4,1,6,2,7,5,1,1,5,1,1,9,4, + 1,3,6,1,8,2,8,4,14,3,5,11,4,1,3,32,1,19,4,1,13,11,5,2,1,8,6,8,1,6,5,13,3,23,11,5,3,16,3,9,10,1,24,3,198,52,4,2,2,5,14,5,4,22,5,20,4,11,6,41, + 1,5,2,2,11,5,2,28,35,8,22,3,18,3,10,7,5,3,4,1,5,3,8,9,3,6,2,16,22,4,5,5,3,3,18,23,2,6,23,5,27,8,1,33,2,12,43,16,5,2,3,6,1,20,4,2,9,7,1,11,2, + 10,3,14,31,9,3,25,18,20,2,5,5,26,14,1,11,17,12,40,19,9,6,31,83,2,7,9,19,78,12,14,21,76,12,113,79,34,4,1,1,61,18,85,10,2,2,13,31,11,50,6,33,159, + 179,6,6,7,4,4,2,4,2,5,8,7,20,32,22,1,3,10,6,7,28,5,10,9,2,77,19,13,2,5,1,4,4,7,4,13,3,9,31,17,3,26,2,6,6,5,4,1,7,11,3,4,2,1,6,2,20,4,1,9,2,6, + 3,7,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,5,13,8,4,11,23,1,10,6,2,1,3,21,2,2,4,24,31,4,10,10,2,5,192,15,4,16,7,9,51,1,2,1,1,5,1,1,2,1,3,5,3,1,3,4,1, + 3,1,3,3,9,8,1,2,2,2,4,4,18,12,92,2,10,4,3,14,5,25,16,42,4,14,4,2,21,5,126,30,31,2,1,5,13,3,22,5,6,6,20,12,1,14,12,87,3,19,1,8,2,9,9,3,3,23,2, + 3,7,6,3,1,2,3,9,1,3,1,6,3,2,1,3,11,3,1,6,10,3,2,3,1,2,1,5,1,1,11,3,6,4,1,7,2,1,2,5,5,34,4,14,18,4,19,7,5,8,2,6,79,1,5,2,14,8,2,9,2,1,36,28,16, + 4,1,1,1,2,12,6,42,39,16,23,7,15,15,3,2,12,7,21,64,6,9,28,8,12,3,3,41,59,24,51,55,57,294,9,9,2,6,2,15,1,2,13,38,90,9,9,9,3,11,7,1,1,1,5,6,3,2, + 1,2,2,3,8,1,4,4,1,5,7,1,4,3,20,4,9,1,1,1,5,5,17,1,5,2,6,2,4,1,4,5,7,3,18,11,11,32,7,5,4,7,11,127,8,4,3,3,1,10,1,1,6,21,14,1,16,1,7,1,3,6,9,65, + 51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39, + }; + static ImWchar base_ranges[] = // not zero-terminated + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF // Half-width characters + }; + static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 }; + if (!full_ranges[0]) + { + memcpy(full_ranges, base_ranges, sizeof(base_ranges)); + UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); + } + return &full_ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x0400, 0x052F, // Cyrillic + Cyrillic Supplement + 0x2DE0, 0x2DFF, // Cyrillic Extended-A + 0xA640, 0xA69F, // Cyrillic Extended-B + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesThai() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + 0x2010, 0x205E, // Punctuations + 0x0E00, 0x0E7F, // Thai + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesVietnamese() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + 0x0102, 0x0103, + 0x0110, 0x0111, + 0x0128, 0x0129, + 0x0168, 0x0169, + 0x01A0, 0x01A1, + 0x01AF, 0x01B0, + 0x1EA0, 0x1EF9, + 0, + }; + return &ranges[0]; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFontGlyphRangesBuilder +//----------------------------------------------------------------------------- + +void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end) +{ + while (text_end ? (text < text_end) : *text) + { + unsigned int c = 0; + int c_len = ImTextCharFromUtf8(&c, text, text_end); + text += c_len; + if (c_len == 0) + break; + if (c < 0x10000) + AddChar((ImWchar)c); + } +} + +void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges) +{ + for (; ranges[0]; ranges += 2) + for (ImWchar c = ranges[0]; c <= ranges[1]; c++) + AddChar(c); +} + +void ImFontGlyphRangesBuilder::BuildRanges(ImVector* out_ranges) +{ + for (int n = 0; n < 0x10000; n++) + if (GetBit(n)) + { + out_ranges->push_back((ImWchar)n); + while (n < 0x10000 && GetBit(n + 1)) + n++; + out_ranges->push_back((ImWchar)n); + } + out_ranges->push_back(0); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFont +//----------------------------------------------------------------------------- + +ImFont::ImFont() +{ + FontSize = 0.0f; + FallbackAdvanceX = 0.0f; + FallbackChar = (ImWchar)'?'; + DisplayOffset = ImVec2(0.0f, 0.0f); + FallbackGlyph = NULL; + ContainerAtlas = NULL; + ConfigData = NULL; + ConfigDataCount = 0; + DirtyLookupTables = false; + Scale = 1.0f; + Ascent = Descent = 0.0f; + MetricsTotalSurface = 0; +} + +ImFont::~ImFont() +{ + ClearOutputData(); +} + +void ImFont::ClearOutputData() +{ + FontSize = 0.0f; + FallbackAdvanceX = 0.0f; + Glyphs.clear(); + IndexAdvanceX.clear(); + IndexLookup.clear(); + FallbackGlyph = NULL; + ContainerAtlas = NULL; + DirtyLookupTables = true; + Ascent = Descent = 0.0f; + MetricsTotalSurface = 0; +} + +void ImFont::BuildLookupTable() +{ + int max_codepoint = 0; + for (int i = 0; i != Glyphs.Size; i++) + max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint); + + IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved + IndexAdvanceX.clear(); + IndexLookup.clear(); + DirtyLookupTables = false; + GrowIndex(max_codepoint + 1); + for (int i = 0; i < Glyphs.Size; i++) + { + int codepoint = (int)Glyphs[i].Codepoint; + IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX; + IndexLookup[codepoint] = (ImWchar)i; + } + + // Create a glyph to handle TAB + // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) + if (FindGlyph((ImWchar)' ')) + { + if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times + Glyphs.resize(Glyphs.Size + 1); + ImFontGlyph& tab_glyph = Glyphs.back(); + tab_glyph = *FindGlyph((ImWchar)' '); + tab_glyph.Codepoint = '\t'; + tab_glyph.AdvanceX *= 4; + IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX; + IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size-1); + } + + FallbackGlyph = FindGlyphNoFallback(FallbackChar); + FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f; + for (int i = 0; i < max_codepoint + 1; i++) + if (IndexAdvanceX[i] < 0.0f) + IndexAdvanceX[i] = FallbackAdvanceX; +} + +void ImFont::SetFallbackChar(ImWchar c) +{ + FallbackChar = c; + BuildLookupTable(); +} + +void ImFont::GrowIndex(int new_size) +{ + IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size); + if (new_size <= IndexLookup.Size) + return; + IndexAdvanceX.resize(new_size, -1.0f); + IndexLookup.resize(new_size, (ImWchar)-1); +} + +// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. +// Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis). +void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) +{ + Glyphs.resize(Glyphs.Size + 1); + ImFontGlyph& glyph = Glyphs.back(); + glyph.Codepoint = (ImWchar)codepoint; + glyph.X0 = x0; + glyph.Y0 = y0; + glyph.X1 = x1; + glyph.Y1 = y1; + glyph.U0 = u0; + glyph.V0 = v0; + glyph.U1 = u1; + glyph.V1 = v1; + glyph.AdvanceX = advance_x + ConfigData->GlyphExtraSpacing.x; // Bake spacing into AdvanceX + + if (ConfigData->PixelSnapH) + glyph.AdvanceX = (float)(int)(glyph.AdvanceX + 0.5f); + + // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round) + DirtyLookupTables = true; + MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + 1.99f); +} + +void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) +{ + IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. + int index_size = IndexLookup.Size; + + if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists + return; + if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op + return; + + GrowIndex(dst + 1); + IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImWchar)-1; + IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f; +} + +const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const +{ + if (c >= IndexLookup.Size) + return FallbackGlyph; + const ImWchar i = IndexLookup.Data[c]; + if (i == (ImWchar)-1) + return FallbackGlyph; + return &Glyphs.Data[i]; +} + +const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const +{ + if (c >= IndexLookup.Size) + return NULL; + const ImWchar i = IndexLookup.Data[c]; + if (i == (ImWchar)-1) + return NULL; + return &Glyphs.Data[i]; +} + +const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const +{ + // Simple word-wrapping for English, not full-featured. Please submit failing cases! + // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) + + // For references, possible wrap point marked with ^ + // "aaa bbb, ccc,ddd. eee fff. ggg!" + // ^ ^ ^ ^ ^__ ^ ^ + + // List of hardcoded separators: .,;!?'" + + // Skip extra blanks after a line returns (that includes not counting them in width computation) + // e.g. "Hello world" --> "Hello" "World" + + // Cut words that cannot possibly fit within one line. + // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish" + + float line_width = 0.0f; + float word_width = 0.0f; + float blank_width = 0.0f; + wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters + + const char* word_end = text; + const char* prev_word_end = NULL; + bool inside_word = true; + + const char* s = text; + while (s < text_end) + { + unsigned int c = (unsigned int)*s; + const char* next_s; + if (c < 0x80) + next_s = s + 1; + else + next_s = s + ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) + break; + + if (c < 32) + { + if (c == '\n') + { + line_width = word_width = blank_width = 0.0f; + inside_word = true; + s = next_s; + continue; + } + if (c == '\r') + { + s = next_s; + continue; + } + } + + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX); + if (ImCharIsBlankW(c)) + { + if (inside_word) + { + line_width += blank_width; + blank_width = 0.0f; + word_end = s; + } + blank_width += char_width; + inside_word = false; + } + else + { + word_width += char_width; + if (inside_word) + { + word_end = next_s; + } + else + { + prev_word_end = word_end; + line_width += word_width + blank_width; + word_width = blank_width = 0.0f; + } + + // Allow wrapping after punctuation. + inside_word = !(c == '.' || c == ',' || c == ';' || c == '!' || c == '?' || c == '\"'); + } + + // We ignore blank width at the end of the line (they can be skipped) + if (line_width + word_width >= wrap_width) + { + // Words that cannot possibly fit within an entire line will be cut anywhere. + if (word_width < wrap_width) + s = prev_word_end ? prev_word_end : word_end; + break; + } + + s = next_s; + } + + return s; +} + +ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const +{ + if (!text_end) + text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this. + + const float line_height = size; + const float scale = size / FontSize; + + ImVec2 text_size = ImVec2(0,0); + float line_width = 0.0f; + + const bool word_wrap_enabled = (wrap_width > 0.0f); + const char* word_wrap_eol = NULL; + + const char* s = text_begin; + while (s < text_end) + { + if (word_wrap_enabled) + { + // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. + if (!word_wrap_eol) + { + word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width); + if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. + word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below + } + + if (s >= word_wrap_eol) + { + if (text_size.x < line_width) + text_size.x = line_width; + text_size.y += line_height; + line_width = 0.0f; + word_wrap_eol = NULL; + + // Wrapping skips upcoming blanks + while (s < text_end) + { + const char c = *s; + if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } + } + continue; + } + } + + // Decode and advance source + const char* prev_s = s; + unsigned int c = (unsigned int)*s; + if (c < 0x80) + { + s += 1; + } + else + { + s += ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) // Malformed UTF-8? + break; + } + + if (c < 32) + { + if (c == '\n') + { + text_size.x = ImMax(text_size.x, line_width); + text_size.y += line_height; + line_width = 0.0f; + continue; + } + if (c == '\r') + continue; + } + + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale; + if (line_width + char_width >= max_width) + { + s = prev_s; + break; + } + + line_width += char_width; + } + + if (text_size.x < line_width) + text_size.x = line_width; + + if (line_width > 0 || text_size.y == 0.0f) + text_size.y += line_height; + + if (remaining) + *remaining = s; + + return text_size; +} + +void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const +{ + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded. + return; + if (const ImFontGlyph* glyph = FindGlyph(c)) + { + float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; + pos.x = (float)(int)pos.x + DisplayOffset.x; + pos.y = (float)(int)pos.y + DisplayOffset.y; + draw_list->PrimReserve(6, 4); + draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col); + } +} + +void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const +{ + if (!text_end) + text_end = text_begin + strlen(text_begin); // ImGui functions generally already provides a valid text_end, so this is merely to handle direct calls. + + // Align to be pixel perfect + pos.x = (float)(int)pos.x + DisplayOffset.x; + pos.y = (float)(int)pos.y + DisplayOffset.y; + float x = pos.x; + float y = pos.y; + if (y > clip_rect.w) + return; + + const float scale = size / FontSize; + const float line_height = FontSize * scale; + const bool word_wrap_enabled = (wrap_width > 0.0f); + const char* word_wrap_eol = NULL; + + // Fast-forward to first visible line + const char* s = text_begin; + if (y + line_height < clip_rect.y && !word_wrap_enabled) + while (y + line_height < clip_rect.y && s < text_end) + { + s = (const char*)memchr(s, '\n', text_end - s); + s = s ? s + 1 : text_end; + y += line_height; + } + + // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve() + // Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer without a newline will likely crash atm) + if (text_end - s > 10000 && !word_wrap_enabled) + { + const char* s_end = s; + float y_end = y; + while (y_end < clip_rect.w && s_end < text_end) + { + s_end = (const char*)memchr(s_end, '\n', text_end - s_end); + s_end = s_end ? s_end + 1 : text_end; + y_end += line_height; + } + text_end = s_end; + } + if (s == text_end) + return; + + // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized) + const int vtx_count_max = (int)(text_end - s) * 4; + const int idx_count_max = (int)(text_end - s) * 6; + const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; + draw_list->PrimReserve(idx_count_max, vtx_count_max); + + ImDrawVert* vtx_write = draw_list->_VtxWritePtr; + ImDrawIdx* idx_write = draw_list->_IdxWritePtr; + unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; + + while (s < text_end) + { + if (word_wrap_enabled) + { + // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. + if (!word_wrap_eol) + { + word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x)); + if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. + word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below + } + + if (s >= word_wrap_eol) + { + x = pos.x; + y += line_height; + word_wrap_eol = NULL; + + // Wrapping skips upcoming blanks + while (s < text_end) + { + const char c = *s; + if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } + } + continue; + } + } + + // Decode and advance source + unsigned int c = (unsigned int)*s; + if (c < 0x80) + { + s += 1; + } + else + { + s += ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) // Malformed UTF-8? + break; + } + + if (c < 32) + { + if (c == '\n') + { + x = pos.x; + y += line_height; + if (y > clip_rect.w) + break; // break out of main loop + continue; + } + if (c == '\r') + continue; + } + + float char_width = 0.0f; + if (const ImFontGlyph* glyph = FindGlyph((ImWchar)c)) + { + char_width = glyph->AdvanceX * scale; + + // Arbitrarily assume that both space and tabs are empty glyphs as an optimization + if (c != ' ' && c != '\t') + { + // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w + float x1 = x + glyph->X0 * scale; + float x2 = x + glyph->X1 * scale; + float y1 = y + glyph->Y0 * scale; + float y2 = y + glyph->Y1 * scale; + if (x1 <= clip_rect.z && x2 >= clip_rect.x) + { + // Render a character + float u1 = glyph->U0; + float v1 = glyph->V0; + float u2 = glyph->U1; + float v2 = glyph->V1; + + // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads. + if (cpu_fine_clip) + { + if (x1 < clip_rect.x) + { + u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1); + x1 = clip_rect.x; + } + if (y1 < clip_rect.y) + { + v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1); + y1 = clip_rect.y; + } + if (x2 > clip_rect.z) + { + u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1); + x2 = clip_rect.z; + } + if (y2 > clip_rect.w) + { + v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1); + y2 = clip_rect.w; + } + if (y1 >= y2) + { + x += char_width; + continue; + } + } + + // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here: + { + idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2); + idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3); + vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; + vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; + vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; + vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; + vtx_write += 4; + vtx_current_idx += 4; + idx_write += 6; + } + } + } + } + + x += char_width; + } + + // Give back unused vertices + draw_list->VtxBuffer.resize((int)(vtx_write - draw_list->VtxBuffer.Data)); + draw_list->IdxBuffer.resize((int)(idx_write - draw_list->IdxBuffer.Data)); + draw_list->CmdBuffer[draw_list->CmdBuffer.Size-1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size); + draw_list->_VtxWritePtr = vtx_write; + draw_list->_IdxWritePtr = idx_write; + draw_list->_VtxCurrentIdx = (unsigned int)draw_list->VtxBuffer.Size; +} + +//----------------------------------------------------------------------------- +// [SECTION] Internal Render Helpers +// (progressively moved from imgui.cpp to here when they are redesigned to stop accessing ImGui global state) +//----------------------------------------------------------------------------- +// - RenderMouseCursor() +// - RenderArrowPointingAt() +// - RenderRectFilledRangeH() +// - RenderPixelEllipsis() +//----------------------------------------------------------------------------- + +void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor) +{ + if (mouse_cursor == ImGuiMouseCursor_None) + return; + IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT); + + const ImU32 col_shadow = IM_COL32(0, 0, 0, 48); + const ImU32 col_border = IM_COL32(0, 0, 0, 255); // Black + const ImU32 col_fill = IM_COL32(255, 255, 255, 255); // White + + ImFontAtlas* font_atlas = draw_list->_Data->Font->ContainerAtlas; + ImVec2 offset, size, uv[4]; + if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2])) + { + pos -= offset; + const ImTextureID tex_id = font_atlas->TexID; + draw_list->PushTextureID(tex_id); + draw_list->AddImage(tex_id, pos + ImVec2(1,0)*scale, pos + ImVec2(1,0)*scale + size*scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_id, pos + ImVec2(2,0)*scale, pos + ImVec2(2,0)*scale + size*scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_id, pos, pos + size*scale, uv[2], uv[3], col_border); + draw_list->AddImage(tex_id, pos, pos + size*scale, uv[0], uv[1], col_fill); + draw_list->PopTextureID(); + } +} + +// Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side. +void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col) +{ + switch (direction) + { + case ImGuiDir_Left: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col); return; + case ImGuiDir_Right: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); return; + case ImGuiDir_Up: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); return; + case ImGuiDir_Down: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); return; + case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings + } +} + +static inline float ImAcos01(float x) +{ + if (x <= 0.0f) return IM_PI * 0.5f; + if (x >= 1.0f) return 0.0f; + return ImAcos(x); + //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do. +} + +// FIXME: Cleanup and move code to ImDrawList. +void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding) +{ + if (x_end_norm == x_start_norm) + return; + if (x_start_norm > x_end_norm) + ImSwap(x_start_norm, x_end_norm); + + ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y); + ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y); + if (rounding == 0.0f) + { + draw_list->AddRectFilled(p0, p1, col, 0.0f); + return; + } + + rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding); + const float inv_rounding = 1.0f / rounding; + const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding); + const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding); + const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return. + const float x0 = ImMax(p0.x, rect.Min.x + rounding); + if (arc0_b == arc0_e) + { + draw_list->PathLineTo(ImVec2(x0, p1.y)); + draw_list->PathLineTo(ImVec2(x0, p0.y)); + } + else if (arc0_b == 0.0f && arc0_e == half_pi) + { + draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL + draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR + } + else + { + draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b, 3); // BL + draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e, 3); // TR + } + if (p1.x > rect.Min.x + rounding) + { + const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding); + const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding); + const float x1 = ImMin(p1.x, rect.Max.x - rounding); + if (arc1_b == arc1_e) + { + draw_list->PathLineTo(ImVec2(x1, p0.y)); + draw_list->PathLineTo(ImVec2(x1, p1.y)); + } + else if (arc1_b == 0.0f && arc1_e == half_pi) + { + draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR + draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR + } + else + { + draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b, 3); // TR + draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e, 3); // BR + } + } + draw_list->PathFillConvex(col); +} + +// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it, +// and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match +// the boldness or positioning of what the font uses... +void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col) +{ + ImFont* font = draw_list->_Data->Font; + const float font_scale = draw_list->_Data->FontSize / font->FontSize; + pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent * font_scale + 0.5f - 1.0f); + for (int dot_n = 0; dot_n < count; dot_n++) + draw_list->AddRectFilled(ImVec2(pos.x + dot_n * 2.0f, pos.y), ImVec2(pos.x + dot_n * 2.0f + 1.0f, pos.y + 1.0f), col); +} + +//----------------------------------------------------------------------------- +// [SECTION] Decompression code +//----------------------------------------------------------------------------- +// Compressed with stb_compress() then converted to a C array and encoded as base85. +// Use the program in misc/fonts/binary_to_compressed_c.cpp to create the array from a TTF file. +// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. +// Decompression from stb.h (public domain) by Sean Barrett /~https://github.com/nothings/stb/blob/master/stb.h +//----------------------------------------------------------------------------- + +static unsigned int stb_decompress_length(const unsigned char *input) +{ + return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]; +} + +static unsigned char *stb__barrier_out_e, *stb__barrier_out_b; +static const unsigned char *stb__barrier_in_b; +static unsigned char *stb__dout; +static void stb__match(const unsigned char *data, unsigned int length) +{ + // INVERSE of memmove... write each byte before copying the next... + IM_ASSERT(stb__dout + length <= stb__barrier_out_e); + if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; } + if (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e+1; return; } + while (length--) *stb__dout++ = *data++; +} + +static void stb__lit(const unsigned char *data, unsigned int length) +{ + IM_ASSERT(stb__dout + length <= stb__barrier_out_e); + if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; } + if (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e+1; return; } + memcpy(stb__dout, data, length); + stb__dout += length; +} + +#define stb__in2(x) ((i[x] << 8) + i[(x)+1]) +#define stb__in3(x) ((i[x] << 16) + stb__in2((x)+1)) +#define stb__in4(x) ((i[x] << 24) + stb__in3((x)+1)) + +static const unsigned char *stb_decompress_token(const unsigned char *i) +{ + if (*i >= 0x20) { // use fewer if's for cases that expand small + if (*i >= 0x80) stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2; + else if (*i >= 0x40) stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3; + else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); + } else { // more ifs for cases that expand large, since overhead is amortized + if (*i >= 0x18) stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4; + else if (*i >= 0x10) stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5; + else if (*i >= 0x08) stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1); + else if (*i == 0x07) stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1); + else if (*i == 0x06) stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5; + else if (*i == 0x04) stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6; + } + return i; +} + +static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen) +{ + const unsigned long ADLER_MOD = 65521; + unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; + unsigned long blocklen, i; + + blocklen = buflen % 5552; + while (buflen) { + for (i=0; i + 7 < blocklen; i += 8) { + s1 += buffer[0], s2 += s1; + s1 += buffer[1], s2 += s1; + s1 += buffer[2], s2 += s1; + s1 += buffer[3], s2 += s1; + s1 += buffer[4], s2 += s1; + s1 += buffer[5], s2 += s1; + s1 += buffer[6], s2 += s1; + s1 += buffer[7], s2 += s1; + + buffer += 8; + } + + for (; i < blocklen; ++i) + s1 += *buffer++, s2 += s1; + + s1 %= ADLER_MOD, s2 %= ADLER_MOD; + buflen -= blocklen; + blocklen = 5552; + } + return (unsigned int)(s2 << 16) + (unsigned int)s1; +} + +static unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/) +{ + unsigned int olen; + if (stb__in4(0) != 0x57bC0000) return 0; + if (stb__in4(4) != 0) return 0; // error! stream is > 4GB + olen = stb_decompress_length(i); + stb__barrier_in_b = i; + stb__barrier_out_e = output + olen; + stb__barrier_out_b = output; + i += 16; + + stb__dout = output; + for (;;) { + const unsigned char *old_i = i; + i = stb_decompress_token(i); + if (i == old_i) { + if (*i == 0x05 && i[1] == 0xfa) { + IM_ASSERT(stb__dout == output + olen); + if (stb__dout != output + olen) return 0; + if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2)) + return 0; + return olen; + } else { + IM_ASSERT(0); /* NOTREACHED */ + return 0; + } + } + IM_ASSERT(stb__dout <= output + olen); + if (stb__dout > output + olen) + return 0; + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Default font data (ProggyClean.ttf) +//----------------------------------------------------------------------------- +// ProggyClean.ttf +// Copyright (c) 2004, 2005 Tristan Grimmer +// MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip) +// Download and more information at http://upperbounds.net +//----------------------------------------------------------------------------- +// File: 'ProggyClean.ttf' (41208 bytes) +// Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding). +// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. +//----------------------------------------------------------------------------- +static const char proggy_clean_ttf_compressed_data_base85[11980+1] = + "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/" + "2*>]b(MC;$jPfY.;h^`IWM9Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1=Ke$$'5F%)]0^#0X@U.a$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;--VsM.M0rJfLH2eTM`*oJMHRC`N" + "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`�j@'DbG&#^$PG.Ll+DNa&VZ>1i%h1S9u5o@YaaW$e+bROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc." + "x]Ip.PH^'/aqUO/$1WxLoW0[iLAw=4h(9.`G" + "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?Ggv:[7MI2k).'2($5FNP&EQ(,)" + "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#" + "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM" + "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu" + "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/" + "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[Ket`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO" + "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%" + "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$MhLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]" + "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et" + "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:" + "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VBpqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<-+k?'(^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M" + "D?@f&1'BW-)Ju#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(" + "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs" + "bIu)'Z,*[>br5fX^:FPAWr-m2KgLQ_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q" + "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aege0jT6'N#(q%.O=?2S]u*(m<-" + "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i" + "sZ88+dKQ)W6>J%CL`.d*(B`-n8D9oK-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P r+$%CE=68>K8r0=dSC%%(@p7" + ".m7jilQ02'0-VWAgTlGW'b)Tq7VT9q^*^$$.:&N@@" + "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*" + "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u" + "@-W$U%VEQ/,,>>#)D#%8cY#YZ?=,`Wdxu/ae&#" + "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$so8lKN%5/$(vdfq7+ebA#" + "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoFDoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8" + "6e%B/:=>)N4xeW.*wft-;$'58-ESqr#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#" + "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjLV#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#SfD07&6D@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5" + "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%" + "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;" + "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmLq9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:" + "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3$U4O]GKx'm9)b@p7YsvK3w^YR-" + "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*" + "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdFTi1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IXSsDiWP,##P`%/L-" + "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdFl*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj" + "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#$(>.Z-I&J(Q0Hd5Q%7Co-b`-cP)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8WlA2);Sa" + ">gXm8YB`1d@K#n]76-a$U,mF%Ul:#/'xoFM9QX-$.QN'>" + "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I" + "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-uW%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)" + "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo" + "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P" + "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*'IAO" + "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#" + ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T" + "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4" + "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#" + "/QHC#3^ZC#7jmC#;v)D#?,)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP" + "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp" + "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#"; + +static const char* GetDefaultCompressedFontDataTTFBase85() +{ + return proggy_clean_ttf_compressed_data_base85; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_impl_glfw.cpp b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_impl_glfw.cpp new file mode 100644 index 00000000..0ed40cde --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_impl_glfw.cpp @@ -0,0 +1,330 @@ +// dear imgui: Platform Binding for GLFW +// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) +// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) +// (Requires: GLFW 3.1+) + +// Implemented features: +// [X] Platform: Clipboard support. +// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW. +// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). + +// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. +// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. +// /~https://github.com/ocornut/imgui + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized. +// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. +// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them. +// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls. +// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. +// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples. +// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag. +// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()). +// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. +// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. +// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set. +// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set). +// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. +// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert. +// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1). +// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers. + +#include "imgui.h" +#include "imgui_impl_glfw.h" + +// GLFW +#include +#ifdef _WIN32 +#undef APIENTRY +#define GLFW_EXPOSE_NATIVE_WIN32 +#include // for glfwGetWin32Window +#endif +#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING +#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED +#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity +#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale +#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface + +// Data +enum GlfwClientApi +{ + GlfwClientApi_Unknown, + GlfwClientApi_OpenGL, + GlfwClientApi_Vulkan +}; +static GLFWwindow* g_Window = NULL; +static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown; +static double g_Time = 0.0; +static bool g_MouseJustPressed[5] = { false, false, false, false, false }; +static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 }; + +// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. +static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL; +static GLFWscrollfun g_PrevUserCallbackScroll = NULL; +static GLFWkeyfun g_PrevUserCallbackKey = NULL; +static GLFWcharfun g_PrevUserCallbackChar = NULL; + +static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) +{ + return glfwGetClipboardString((GLFWwindow*)user_data); +} + +static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text) +{ + glfwSetClipboardString((GLFWwindow*)user_data, text); +} + +void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) +{ + if (g_PrevUserCallbackMousebutton != NULL) + g_PrevUserCallbackMousebutton(window, button, action, mods); + + if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed)) + g_MouseJustPressed[button] = true; +} + +void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) +{ + if (g_PrevUserCallbackScroll != NULL) + g_PrevUserCallbackScroll(window, xoffset, yoffset); + + ImGuiIO& io = ImGui::GetIO(); + io.MouseWheelH += (float)xoffset; + io.MouseWheel += (float)yoffset; +} + +void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (g_PrevUserCallbackKey != NULL) + g_PrevUserCallbackKey(window, key, scancode, action, mods); + + ImGuiIO& io = ImGui::GetIO(); + if (action == GLFW_PRESS) + io.KeysDown[key] = true; + if (action == GLFW_RELEASE) + io.KeysDown[key] = false; + + // Modifiers are not reliable across systems + io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; + io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; + io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; + io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; +} + +void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) +{ + if (g_PrevUserCallbackChar != NULL) + g_PrevUserCallbackChar(window, c); + + ImGuiIO& io = ImGui::GetIO(); + if (c > 0 && c < 0x10000) + io.AddInputCharacter((unsigned short)c); +} + +static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) +{ + g_Window = window; + g_Time = 0.0; + + // Setup back-end capabilities flags + ImGuiIO& io = ImGui::GetIO(); + io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) + io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) + io.BackendPlatformName = "imgui_impl_glfw"; + + // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. + io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; + io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; + io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; + io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; + io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; + io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; + io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; + io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; + io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; + io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT; + io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; + io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; + io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE; + io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; + io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; + io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; + io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; + io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; + io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; + io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; + io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; + + io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; + io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; + io.ClipboardUserData = g_Window; +#if defined(_WIN32) + io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window); +#endif + + g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. + g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. + g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. + g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR); + + // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. + g_PrevUserCallbackMousebutton = NULL; + g_PrevUserCallbackScroll = NULL; + g_PrevUserCallbackKey = NULL; + g_PrevUserCallbackChar = NULL; + if (install_callbacks) + { + g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); + g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); + g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); + g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); + } + + g_ClientApi = client_api; + return true; +} + +bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks) +{ + return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL); +} + +bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks) +{ + return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan); +} + +void ImGui_ImplGlfw_Shutdown() +{ + for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) + { + glfwDestroyCursor(g_MouseCursors[cursor_n]); + g_MouseCursors[cursor_n] = NULL; + } + g_ClientApi = GlfwClientApi_Unknown; +} + +static void ImGui_ImplGlfw_UpdateMousePosAndButtons() +{ + // Update buttons + ImGuiIO& io = ImGui::GetIO(); + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) + { + // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0; + g_MouseJustPressed[i] = false; + } + + // Update mouse position + const ImVec2 mouse_pos_backup = io.MousePos; + io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); +#ifdef __EMSCRIPTEN__ + const bool focused = true; // Emscripten +#else + const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0; +#endif + if (focused) + { + if (io.WantSetMousePos) + { + glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y); + } + else + { + double mouse_x, mouse_y; + glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); + } + } +} + +static void ImGui_ImplGlfw_UpdateMouseCursor() +{ + ImGuiIO& io = ImGui::GetIO(); + if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) + return; + + ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); + if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + } + else + { + // Show OS mouse cursor + // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here. + glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]); + glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } +} + +static void ImGui_ImplGlfw_UpdateGamepads() +{ + ImGuiIO& io = ImGui::GetIO(); + memset(io.NavInputs, 0, sizeof(io.NavInputs)); + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + return; + + // Update gamepad inputs + #define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; } + #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; } + int axes_count = 0, buttons_count = 0; + const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count); + const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count); + MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A + MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B + MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X + MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y + MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left + MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right + MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up + MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down + MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB + MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB + MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB + MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB + MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f); + MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f); + MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f); + MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f); + #undef MAP_BUTTON + #undef MAP_ANALOG + if (axes_count > 0 && buttons_count > 0) + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + else + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; +} + +void ImGui_ImplGlfw_NewFrame() +{ + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); + + // Setup display size (every frame to accommodate for window resizing) + int w, h; + int display_w, display_h; + glfwGetWindowSize(g_Window, &w, &h); + glfwGetFramebufferSize(g_Window, &display_w, &display_h); + io.DisplaySize = ImVec2((float)w, (float)h); + if (w > 0 && h > 0) + io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); + + // Setup time step + double current_time = glfwGetTime(); + io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); + g_Time = current_time; + + ImGui_ImplGlfw_UpdateMousePosAndButtons(); + ImGui_ImplGlfw_UpdateMouseCursor(); + + // Gamepad navigation mapping + ImGui_ImplGlfw_UpdateGamepads(); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_impl_glfw.h b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_impl_glfw.h new file mode 100644 index 00000000..ccbe840d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_impl_glfw.h @@ -0,0 +1,33 @@ +// dear imgui: Platform Binding for GLFW +// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) +// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) + +// Implemented features: +// [X] Platform: Clipboard support. +// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW. +// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). + +// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. +// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. +// /~https://github.com/ocornut/imgui + +// About GLSL version: +// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL. +// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure! + +#pragma once + +struct GLFWwindow; + +IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks); +IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks); +IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame(); + +// InitXXX function with 'install_callbacks=true': install GLFW callbacks. They will call user's previously installed callbacks, if any. +// InitXXX function with 'install_callbacks=false': do not install GLFW callbacks. You will need to call them yourself from your own GLFW callbacks. +IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); +IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); +IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); +IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_impl_opengl3.cpp b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_impl_opengl3.cpp new file mode 100644 index 00000000..84b87775 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_impl_opengl3.cpp @@ -0,0 +1,588 @@ +// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline +// - Desktop GL: 3.x 4.x +// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) +// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. + +// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. +// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. +// /~https://github.com/ocornut/imgui + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0). +// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader. +// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display. +// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450). +// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. +// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN. +// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used. +// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES". +// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation. +// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link. +// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples. +// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. +// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state. +// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer. +// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150". +// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context. +// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself. +// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150. +// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode. +// 2017-05-01: OpenGL: Fixed save and restore of current blend func state. +// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE. +// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle. +// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752) + +//---------------------------------------- +// OpenGL GLSL GLSL +// version version string +//---------------------------------------- +// 2.0 110 "#version 110" +// 2.1 120 "#version 120" +// 3.0 130 "#version 130" +// 3.1 140 "#version 140" +// 3.2 150 "#version 150" +// 3.3 330 "#version 330 core" +// 4.0 400 "#version 400 core" +// 4.1 410 "#version 410 core" +// 4.2 420 "#version 410 core" +// 4.3 430 "#version 430 core" +// ES 2.0 100 "#version 100" = WebGL 1.0 +// ES 3.0 300 "#version 300 es" = WebGL 2.0 +//---------------------------------------- + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#include "imgui_impl_opengl3.h" +#include +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif +#if defined(__APPLE__) +#include "TargetConditionals.h" +#endif + +// Auto-detect GL version +#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) +#if (defined(__APPLE__) && TARGET_OS_IOS) || (defined(__ANDROID__)) +#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es" +#elif defined(__EMSCRIPTEN__) +#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100" +#endif +#endif + +#if defined(IMGUI_IMPL_OPENGL_ES2) +#include +#elif defined(IMGUI_IMPL_OPENGL_ES3) +#include // Use GL ES 3 +#else +// About Desktop OpenGL function loaders: +// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. +// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). +// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. +#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) +#include +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) +#include +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) +#include +#else +#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM +#endif +#endif + +// OpenGL Data +static char g_GlslVersionString[32] = ""; +static GLuint g_FontTexture = 0; +static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; +static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; +static int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0; +static unsigned int g_VboHandle = 0, g_ElementsHandle = 0; + +// Functions +bool ImGui_ImplOpenGL3_Init(const char* glsl_version) +{ + ImGuiIO& io = ImGui::GetIO(); + io.BackendRendererName = "imgui_impl_opengl3"; + + // Store GLSL version string so we can refer to it later in case we recreate shaders. Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure. +#if defined(IMGUI_IMPL_OPENGL_ES2) + if (glsl_version == NULL) + glsl_version = "#version 100"; +#elif defined(IMGUI_IMPL_OPENGL_ES3) + if (glsl_version == NULL) + glsl_version = "#version 300 es"; +#else + if (glsl_version == NULL) + glsl_version = "#version 130"; +#endif + IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString)); + strcpy(g_GlslVersionString, glsl_version); + strcat(g_GlslVersionString, "\n"); + + return true; +} + +void ImGui_ImplOpenGL3_Shutdown() +{ + ImGui_ImplOpenGL3_DestroyDeviceObjects(); +} + +void ImGui_ImplOpenGL3_NewFrame() +{ + if (!g_FontTexture) + ImGui_ImplOpenGL3_CreateDeviceObjects(); +} + +// OpenGL3 Render function. +// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) +// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. +void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) +{ + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + if (fb_width <= 0 || fb_height <= 0) + return; + + // Backup GL state + GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture); + glActiveTexture(GL_TEXTURE0); + GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); + GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); +#ifdef GL_SAMPLER_BINDING + GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler); +#endif + GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); +#ifndef IMGUI_IMPL_OPENGL_ES2 + GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); +#endif +#ifdef GL_POLYGON_MODE + GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); +#endif + GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); + GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); + GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb); + GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb); + GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha); + GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha); + GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb); + GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha); + GLboolean last_enable_blend = glIsEnabled(GL_BLEND); + GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); + GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); + GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + bool clip_origin_lower_left = true; +#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__) + GLenum last_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT) + if (last_clip_origin == GL_UPPER_LEFT) + clip_origin_lower_left = false; +#endif + + // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glEnable(GL_SCISSOR_TEST); +#ifdef GL_POLYGON_MODE + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +#endif + + // Setup viewport, orthographic projection matrix + // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps. + glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); + float L = draw_data->DisplayPos.x; + float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; + float T = draw_data->DisplayPos.y; + float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; + const float ortho_projection[4][4] = + { + { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, + { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, + { 0.0f, 0.0f, -1.0f, 0.0f }, + { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, + }; + glUseProgram(g_ShaderHandle); + glUniform1i(g_AttribLocationTex, 0); + glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); +#ifdef GL_SAMPLER_BINDING + glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise. +#endif + +#ifndef IMGUI_IMPL_OPENGL_ES2 + // Recreate the VAO every time + // (This is to easily allow multiple GL contexts. VAO are not shared among GL contexts, and we don't track creation/deletion of windows so we don't have an obvious key to use to cache them.) + GLuint vao_handle = 0; + glGenVertexArrays(1, &vao_handle); + glBindVertexArray(vao_handle); +#endif + glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); + glEnableVertexAttribArray(g_AttribLocationPosition); + glEnableVertexAttribArray(g_AttribLocationUV); + glEnableVertexAttribArray(g_AttribLocationColor); + glVertexAttribPointer(g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)); + glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); + glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)); + + // Will project scissor/clipping rectangles into framebuffer space + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + + // Render command lists + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + size_t idx_buffer_offset = 0; + + glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); + + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback) + { + // User callback (registered via ImDrawList::AddCallback) + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + ImVec4 clip_rect; + clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; + clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; + clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; + clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; + + if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) + { + // Apply scissor/clipping rectangle + if (clip_origin_lower_left) + glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)); + else + glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT) + + // Bind texture, Draw + glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); + glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)idx_buffer_offset); + } + } + idx_buffer_offset += pcmd->ElemCount * sizeof(ImDrawIdx); + } + } +#ifndef IMGUI_IMPL_OPENGL_ES2 + glDeleteVertexArrays(1, &vao_handle); +#endif + + // Restore modified GL state + glUseProgram(last_program); + glBindTexture(GL_TEXTURE_2D, last_texture); +#ifdef GL_SAMPLER_BINDING + glBindSampler(0, last_sampler); +#endif + glActiveTexture(last_active_texture); +#ifndef IMGUI_IMPL_OPENGL_ES2 + glBindVertexArray(last_vertex_array); +#endif + glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); + glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); + glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha); + if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); + if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); + if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); + if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); +#ifdef GL_POLYGON_MODE + glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); +#endif + glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); + glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); +} + +bool ImGui_ImplOpenGL3_CreateFontsTexture() +{ + // Build texture atlas + ImGuiIO& io = ImGui::GetIO(); + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. + + // Upload texture to graphics system + GLint last_texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + glGenTextures(1, &g_FontTexture); + glBindTexture(GL_TEXTURE_2D, g_FontTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#ifdef GL_UNPACK_ROW_LENGTH + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); +#endif + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + // Store our identifier + io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture; + + // Restore state + glBindTexture(GL_TEXTURE_2D, last_texture); + + return true; +} + +void ImGui_ImplOpenGL3_DestroyFontsTexture() +{ + if (g_FontTexture) + { + ImGuiIO& io = ImGui::GetIO(); + glDeleteTextures(1, &g_FontTexture); + io.Fonts->TexID = 0; + g_FontTexture = 0; + } +} + +// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file. +static bool CheckShader(GLuint handle, const char* desc) +{ + GLint status = 0, log_length = 0; + glGetShaderiv(handle, GL_COMPILE_STATUS, &status); + glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length); + if ((GLboolean)status == GL_FALSE) + fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc); + if (log_length > 0) + { + ImVector buf; + buf.resize((int)(log_length + 1)); + glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); + fprintf(stderr, "%s\n", buf.begin()); + } + return (GLboolean)status == GL_TRUE; +} + +// If you get an error please report on GitHub. You may try different GL context version or GLSL version. +static bool CheckProgram(GLuint handle, const char* desc) +{ + GLint status = 0, log_length = 0; + glGetProgramiv(handle, GL_LINK_STATUS, &status); + glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length); + if ((GLboolean)status == GL_FALSE) + fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString); + if (log_length > 0) + { + ImVector buf; + buf.resize((int)(log_length + 1)); + glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); + fprintf(stderr, "%s\n", buf.begin()); + } + return (GLboolean)status == GL_TRUE; +} + +bool ImGui_ImplOpenGL3_CreateDeviceObjects() +{ + // Backup GL state + GLint last_texture, last_array_buffer; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); +#ifndef IMGUI_IMPL_OPENGL_ES2 + GLint last_vertex_array; + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); +#endif + + // Parse GLSL version string + int glsl_version = 130; + sscanf(g_GlslVersionString, "#version %d", &glsl_version); + + const GLchar* vertex_shader_glsl_120 = + "uniform mat4 ProjMtx;\n" + "attribute vec2 Position;\n" + "attribute vec2 UV;\n" + "attribute vec4 Color;\n" + "varying vec2 Frag_UV;\n" + "varying vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " Frag_UV = UV;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + "}\n"; + + const GLchar* vertex_shader_glsl_130 = + "uniform mat4 ProjMtx;\n" + "in vec2 Position;\n" + "in vec2 UV;\n" + "in vec4 Color;\n" + "out vec2 Frag_UV;\n" + "out vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " Frag_UV = UV;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + "}\n"; + + const GLchar* vertex_shader_glsl_300_es = + "precision mediump float;\n" + "layout (location = 0) in vec2 Position;\n" + "layout (location = 1) in vec2 UV;\n" + "layout (location = 2) in vec4 Color;\n" + "uniform mat4 ProjMtx;\n" + "out vec2 Frag_UV;\n" + "out vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " Frag_UV = UV;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + "}\n"; + + const GLchar* vertex_shader_glsl_410_core = + "layout (location = 0) in vec2 Position;\n" + "layout (location = 1) in vec2 UV;\n" + "layout (location = 2) in vec4 Color;\n" + "uniform mat4 ProjMtx;\n" + "out vec2 Frag_UV;\n" + "out vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " Frag_UV = UV;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + "}\n"; + + const GLchar* fragment_shader_glsl_120 = + "#ifdef GL_ES\n" + " precision mediump float;\n" + "#endif\n" + "uniform sampler2D Texture;\n" + "varying vec2 Frag_UV;\n" + "varying vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n" + "}\n"; + + const GLchar* fragment_shader_glsl_130 = + "uniform sampler2D Texture;\n" + "in vec2 Frag_UV;\n" + "in vec4 Frag_Color;\n" + "out vec4 Out_Color;\n" + "void main()\n" + "{\n" + " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" + "}\n"; + + const GLchar* fragment_shader_glsl_300_es = + "precision mediump float;\n" + "uniform sampler2D Texture;\n" + "in vec2 Frag_UV;\n" + "in vec4 Frag_Color;\n" + "layout (location = 0) out vec4 Out_Color;\n" + "void main()\n" + "{\n" + " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" + "}\n"; + + const GLchar* fragment_shader_glsl_410_core = + "in vec2 Frag_UV;\n" + "in vec4 Frag_Color;\n" + "uniform sampler2D Texture;\n" + "layout (location = 0) out vec4 Out_Color;\n" + "void main()\n" + "{\n" + " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" + "}\n"; + + // Select shaders matching our GLSL versions + const GLchar* vertex_shader = NULL; + const GLchar* fragment_shader = NULL; + if (glsl_version < 130) + { + vertex_shader = vertex_shader_glsl_120; + fragment_shader = fragment_shader_glsl_120; + } + else if (glsl_version >= 410) + { + vertex_shader = vertex_shader_glsl_410_core; + fragment_shader = fragment_shader_glsl_410_core; + } + else if (glsl_version == 300) + { + vertex_shader = vertex_shader_glsl_300_es; + fragment_shader = fragment_shader_glsl_300_es; + } + else + { + vertex_shader = vertex_shader_glsl_130; + fragment_shader = fragment_shader_glsl_130; + } + + // Create shaders + const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader }; + g_VertHandle = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL); + glCompileShader(g_VertHandle); + CheckShader(g_VertHandle, "vertex shader"); + + const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader }; + g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL); + glCompileShader(g_FragHandle); + CheckShader(g_FragHandle, "fragment shader"); + + g_ShaderHandle = glCreateProgram(); + glAttachShader(g_ShaderHandle, g_VertHandle); + glAttachShader(g_ShaderHandle, g_FragHandle); + glLinkProgram(g_ShaderHandle); + CheckProgram(g_ShaderHandle, "shader program"); + + g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); + g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); + g_AttribLocationPosition = glGetAttribLocation(g_ShaderHandle, "Position"); + g_AttribLocationUV = glGetAttribLocation(g_ShaderHandle, "UV"); + g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color"); + + // Create buffers + glGenBuffers(1, &g_VboHandle); + glGenBuffers(1, &g_ElementsHandle); + + ImGui_ImplOpenGL3_CreateFontsTexture(); + + // Restore modified GL state + glBindTexture(GL_TEXTURE_2D, last_texture); + glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); +#ifndef IMGUI_IMPL_OPENGL_ES2 + glBindVertexArray(last_vertex_array); +#endif + + return true; +} + +void ImGui_ImplOpenGL3_DestroyDeviceObjects() +{ + if (g_VboHandle) glDeleteBuffers(1, &g_VboHandle); + if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle); + g_VboHandle = g_ElementsHandle = 0; + + if (g_ShaderHandle && g_VertHandle) glDetachShader(g_ShaderHandle, g_VertHandle); + if (g_VertHandle) glDeleteShader(g_VertHandle); + g_VertHandle = 0; + + if (g_ShaderHandle && g_FragHandle) glDetachShader(g_ShaderHandle, g_FragHandle); + if (g_FragHandle) glDeleteShader(g_FragHandle); + g_FragHandle = 0; + + if (g_ShaderHandle) glDeleteProgram(g_ShaderHandle); + g_ShaderHandle = 0; + + ImGui_ImplOpenGL3_DestroyFontsTexture(); +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_impl_opengl3.h b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_impl_opengl3.h new file mode 100644 index 00000000..9fe2a88d --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_impl_opengl3.h @@ -0,0 +1,46 @@ +// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline +// - Desktop GL: 3.x 4.x +// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) +// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. + +// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. +// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. +// /~https://github.com/ocornut/imgui + +// About Desktop OpenGL function loaders: +// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. +// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). +// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. + +// About GLSL version: +// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string. +// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es" +// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp. + +#pragma once + +// Specific OpenGL versions +//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten +//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android + +// Set default OpenGL3 loader to be gl3w +#if !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \ + && !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \ + && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \ + && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) +#define IMGUI_IMPL_OPENGL_LOADER_GL3W +#endif + +IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL); +IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); +IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); + +// Called by Init/NewFrame/Shutdown +IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); +IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); +IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_internal.h b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_internal.h new file mode 100644 index 00000000..9cd39490 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_internal.h @@ -0,0 +1,1593 @@ +// dear imgui, v1.69 +// (internal structures/api) + +// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! +// Set: +// #define IMGUI_DEFINE_MATH_OPERATORS +// To implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators) + +/* + +Index of this file: +// Header mess +// Forward declarations +// STB libraries includes +// Context pointer +// Generic helpers +// Misc data structures +// Main imgui context +// Tab bar, tab item +// Internal API + +*/ + +#pragma once + +//----------------------------------------------------------------------------- +// Header mess +//----------------------------------------------------------------------------- + +#ifndef IMGUI_VERSION +#error Must include imgui.h before imgui_internal.h +#endif + +#include // FILE* +#include // NULL, malloc, free, qsort, atoi, atof +#include // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf +#include // INT_MIN, INT_MAX + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport) +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wold-style-cast" +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" +#endif +#endif + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- + +struct ImRect; // An axis-aligned rectangle (2 points) +struct ImDrawDataBuilder; // Helper to build a ImDrawData instance +struct ImDrawListSharedData; // Data shared between all ImDrawList instances +struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it +struct ImGuiColumnData; // Storage data for a single column +struct ImGuiColumnsSet; // Storage data for a columns set +struct ImGuiContext; // Main imgui context +struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup() +struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box +struct ImGuiItemHoveredDataBackup; // Backup and restore IsItemHovered() internal data +struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only +struct ImGuiNavMoveResult; // Result of a directional navigation move query result +struct ImGuiNextWindowData; // Storage for SetNexWindow** functions +struct ImGuiPopupRef; // Storage for current popup stack +struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file +struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it +struct ImGuiTabBar; // Storage for a tab bar +struct ImGuiTabItem; // Storage for a tab item (within a tab bar) +struct ImGuiWindow; // Storage for one window +struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame) +struct ImGuiWindowSettings; // Storage for window settings stored in .ini file (we keep one of those even if the actual window wasn't instanced during this session) + +// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. +typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical +typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for ButtonEx(), ButtonBehavior() +typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags: for DragBehavior() +typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag() +typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for DC.LastItemStatusFlags +typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() +typedef int ImGuiNavDirSourceFlags; // -> enum ImGuiNavDirSourceFlags_ // Flags: for GetNavInputAmount2d() +typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests +typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for Separator() - internal +typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for SliderBehavior() +typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx() + +//------------------------------------------------------------------------- +// STB libraries includes +//------------------------------------------------------------------------- + +namespace ImStb +{ + +#undef STB_TEXTEDIT_STRING +#undef STB_TEXTEDIT_CHARTYPE +#define STB_TEXTEDIT_STRING ImGuiInputTextState +#define STB_TEXTEDIT_CHARTYPE ImWchar +#define STB_TEXTEDIT_GETWIDTH_NEWLINE -1.0f +#define STB_TEXTEDIT_UNDOSTATECOUNT 99 +#define STB_TEXTEDIT_UNDOCHARCOUNT 999 +#include "imstb_textedit.h" + +} // namespace ImStb + +//----------------------------------------------------------------------------- +// Context pointer +//----------------------------------------------------------------------------- + +#ifndef GImGui +extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointer +#endif + +//----------------------------------------------------------------------------- +// Generic helpers +//----------------------------------------------------------------------------- + +#define IM_PI 3.14159265358979323846f +#ifdef _WIN32 +#define IM_NEWLINE "\r\n" // Play it nice with Windows users (2018/05 news: Microsoft announced that Notepad will finally display Unix-style carriage returns!) +#else +#define IM_NEWLINE "\n" +#endif + +#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__) +#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] +#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose +#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 + +// Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall +#ifdef _MSC_VER +#define IMGUI_CDECL __cdecl +#else +#define IMGUI_CDECL +#endif + +// Helpers: UTF-8 <> wchar +IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count +IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count +IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count +IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count) +IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8 +IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8 + +// Helpers: Misc +IMGUI_API ImU32 ImHashData(const void* data, size_t data_size, ImU32 seed = 0); +IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size, ImU32 seed = 0); +IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size = NULL, int padding_bytes = 0); +IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode); +static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } +static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } +static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } +static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } +#define ImQsort qsort +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +static inline ImU32 ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } // [moved to ImHashStr/ImHashData in 1.68] +#endif + +// Helpers: Geometry +IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); +IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); +IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); +IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w); +IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy); + +// Helpers: String +IMGUI_API int ImStricmp(const char* str1, const char* str2); +IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); +IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); +IMGUI_API char* ImStrdup(const char* str); +IMGUI_API char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* str); +IMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end, char c); +IMGUI_API int ImStrlenW(const ImWchar* str); +IMGUI_API const char* ImStreolRange(const char* str, const char* str_end); // End end-of-line +IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line +IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end); +IMGUI_API void ImStrTrimBlanks(char* str); +IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3); +IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3); +IMGUI_API const char* ImParseFormatFindStart(const char* format); +IMGUI_API const char* ImParseFormatFindEnd(const char* format); +IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size); +IMGUI_API int ImParseFormatPrecision(const char* format, int default_value); + +// Helpers: ImVec2/ImVec4 operators +// We are keeping those disabled by default so they don't leak in user space, to allow user enabling implicit cast operators between ImVec2 and their own types (using IM_VEC2_CLASS_EXTRA etc.) +// We unfortunately don't have a unary- operator for ImVec2 because this would needs to be defined inside the class itself. +#ifdef IMGUI_DEFINE_MATH_OPERATORS +static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x*rhs, lhs.y*rhs); } +static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x/rhs, lhs.y/rhs); } +static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x+rhs.x, lhs.y+rhs.y); } +static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x-rhs.x, lhs.y-rhs.y); } +static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x*rhs.x, lhs.y*rhs.y); } +static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x/rhs.x, lhs.y/rhs.y); } +static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } +static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } +static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } +static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } +static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x+rhs.x, lhs.y+rhs.y, lhs.z+rhs.z, lhs.w+rhs.w); } +static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x-rhs.x, lhs.y-rhs.y, lhs.z-rhs.z, lhs.w-rhs.w); } +static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x*rhs.x, lhs.y*rhs.y, lhs.z*rhs.z, lhs.w*rhs.w); } +#endif + +// Helpers: Maths +// - Wrapper for standard libs functions. (Note that imgui_demo.cpp does _not_ use them to keep the code easy to copy) +#ifndef IMGUI_DISABLE_MATH_FUNCTIONS +static inline float ImFabs(float x) { return fabsf(x); } +static inline float ImSqrt(float x) { return sqrtf(x); } +static inline float ImPow(float x, float y) { return powf(x, y); } +static inline double ImPow(double x, double y) { return pow(x, y); } +static inline float ImFmod(float x, float y) { return fmodf(x, y); } +static inline double ImFmod(double x, double y) { return fmod(x, y); } +static inline float ImCos(float x) { return cosf(x); } +static inline float ImSin(float x) { return sinf(x); } +static inline float ImAcos(float x) { return acosf(x); } +static inline float ImAtan2(float y, float x) { return atan2f(y, x); } +static inline double ImAtof(const char* s) { return atof(s); } +static inline float ImFloorStd(float x) { return floorf(x); } // we already uses our own ImFloor() { return (float)(int)v } internally so the standard one wrapper is named differently (it's used by stb_truetype) +static inline float ImCeil(float x) { return ceilf(x); } +#endif +// - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support for variety of types: signed/unsigned int/long long float/double +// (Exceptionally using templates here but we could also redefine them for variety of types) +template static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; } +template static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; } +template static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } +template static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); } +template static inline void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; } +template static inline T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; } +template static inline T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; } +// - Misc maths helpers +static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); } +static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); } +static inline ImVec2 ImClamp(const ImVec2& v, const ImVec2& mn, ImVec2 mx) { return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); } +static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); } +static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); } +static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); } +static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; } +static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; } +static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; } +static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / ImSqrt(d); return fail_value; } +static inline float ImFloor(float f) { return (float)(int)f; } +static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)v.x, (float)(int)v.y); } +static inline int ImModPositive(int a, int b) { return (a + b) % b; } +static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } +static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } +static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } +static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } + +// Helper: ImBoolVector. Store 1-bit per value. +// Note that Resize() currently clears the whole vector. +struct ImBoolVector +{ + ImVector Storage; + ImBoolVector() { } + void Resize(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); } + void Clear() { Storage.clear(); } + bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (Storage[off] & mask) != 0; } + void SetBit(int n, bool v) { int off = (n >> 5); int mask = 1 << (n & 31); if (v) Storage[off] |= mask; else Storage[off] &= ~mask; } +}; + +// Helper: ImPool<>. Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer, +// Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object. +typedef int ImPoolIdx; +template +struct IMGUI_API ImPool +{ + ImVector Data; // Contiguous data + ImGuiStorage Map; // ID->Index + ImPoolIdx FreeIdx; // Next free idx to use + + ImPool() { FreeIdx = 0; } + ~ImPool() { Clear(); } + T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Data[idx] : NULL; } + T* GetByIndex(ImPoolIdx n) { return &Data[n]; } + ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Data.Data && p < Data.Data + Data.Size); return (ImPoolIdx)(p - Data.Data); } + T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Data[*p_idx]; *p_idx = FreeIdx; return Add(); } + bool Contains(const T* p) const { return (p >= Data.Data && p < Data.Data + Data.Size); } + void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Data[idx].~T(); } Map.Clear(); Data.clear(); FreeIdx = 0; } + T* Add() { int idx = FreeIdx; if (idx == Data.Size) { Data.resize(Data.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Data[idx]; } IM_PLACEMENT_NEW(&Data[idx]) T(); return &Data[idx]; } + void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); } + void Remove(ImGuiID key, ImPoolIdx idx) { Data[idx].~T(); *(int*)&Data[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); } + void Reserve(int capacity) { Data.reserve(capacity); Map.Data.reserve(capacity); } + int GetSize() const { return Data.Size; } +}; + +//----------------------------------------------------------------------------- +// Misc data structures +//----------------------------------------------------------------------------- + +enum ImGuiButtonFlags_ +{ + ImGuiButtonFlags_None = 0, + ImGuiButtonFlags_Repeat = 1 << 0, // hold to repeat + ImGuiButtonFlags_PressedOnClickRelease = 1 << 1, // return true on click + release on same item [DEFAULT if no PressedOn* flag is set] + ImGuiButtonFlags_PressedOnClick = 1 << 2, // return true on click (default requires click+release) + ImGuiButtonFlags_PressedOnRelease = 1 << 3, // return true on release (default requires click+release) + ImGuiButtonFlags_PressedOnDoubleClick = 1 << 4, // return true on double-click (default requires click+release) + ImGuiButtonFlags_FlattenChildren = 1 << 5, // allow interactions even if a child window is overlapping + ImGuiButtonFlags_AllowItemOverlap = 1 << 6, // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap() + ImGuiButtonFlags_DontClosePopups = 1 << 7, // disable automatically closing parent popup on press // [UNUSED] + ImGuiButtonFlags_Disabled = 1 << 8, // disable interactions + ImGuiButtonFlags_AlignTextBaseLine = 1 << 9, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine + ImGuiButtonFlags_NoKeyModifiers = 1 << 10, // disable interaction if a key modifier is held + ImGuiButtonFlags_NoHoldingActiveID = 1 << 11, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) + ImGuiButtonFlags_PressedOnDragDropHold = 1 << 12, // press when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) + ImGuiButtonFlags_NoNavFocus = 1 << 13 // don't override navigation focus when activated +}; + +enum ImGuiSliderFlags_ +{ + ImGuiSliderFlags_None = 0, + ImGuiSliderFlags_Vertical = 1 << 0 +}; + +enum ImGuiDragFlags_ +{ + ImGuiDragFlags_None = 0, + ImGuiDragFlags_Vertical = 1 << 0 +}; + +enum ImGuiColumnsFlags_ +{ + // Default: 0 + ImGuiColumnsFlags_None = 0, + ImGuiColumnsFlags_NoBorder = 1 << 0, // Disable column dividers + ImGuiColumnsFlags_NoResize = 1 << 1, // Disable resizing columns when clicking on the dividers + ImGuiColumnsFlags_NoPreserveWidths = 1 << 2, // Disable column width preservation when adjusting columns + ImGuiColumnsFlags_NoForceWithinWindow = 1 << 3, // Disable forcing columns to fit within window + ImGuiColumnsFlags_GrowParentContentsSize= 1 << 4 // (WIP) Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove. +}; + +enum ImGuiSelectableFlagsPrivate_ +{ + // NB: need to be in sync with last value of ImGuiSelectableFlags_ + ImGuiSelectableFlags_NoHoldingActiveID = 1 << 10, + ImGuiSelectableFlags_PressedOnClick = 1 << 11, + ImGuiSelectableFlags_PressedOnRelease = 1 << 12, + ImGuiSelectableFlags_DrawFillAvailWidth = 1 << 13 +}; + +enum ImGuiSeparatorFlags_ +{ + ImGuiSeparatorFlags_None = 0, + ImGuiSeparatorFlags_Horizontal = 1 << 0, // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar + ImGuiSeparatorFlags_Vertical = 1 << 1 +}; + +// Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin(). +// This is going to be exposed in imgui.h when stabilized enough. +enum ImGuiItemFlags_ +{ + ImGuiItemFlags_NoTabStop = 1 << 0, // false + ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings. + ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211 + ImGuiItemFlags_NoNav = 1 << 3, // false + ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false + ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window + ImGuiItemFlags_Default_ = 0 +}; + +// Storage for LastItem data +enum ImGuiItemStatusFlags_ +{ + ImGuiItemStatusFlags_None = 0, + ImGuiItemStatusFlags_HoveredRect = 1 << 0, + ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, + ImGuiItemStatusFlags_Edited = 1 << 2 // Value exposed by item was edited in the current frame (should match the bool return value of most widgets) + +#ifdef IMGUI_ENABLE_TEST_ENGINE + , // [imgui-test only] + ImGuiItemStatusFlags_Openable = 1 << 10, // + ImGuiItemStatusFlags_Opened = 1 << 11, // + ImGuiItemStatusFlags_Checkable = 1 << 12, // + ImGuiItemStatusFlags_Checked = 1 << 13 // +#endif +}; + +enum ImGuiTextFlags_ +{ + ImGuiTextFlags_None = 0, + ImGuiTextFlags_NoWidthForLargeClippedText = 1 << 0 +}; + +// FIXME: this is in development, not exposed/functional as a generic feature yet. +// Horizontal/Vertical enums are fixed to 0/1 so they may be used to index ImVec2 +enum ImGuiLayoutType_ +{ + ImGuiLayoutType_Horizontal = 0, + ImGuiLayoutType_Vertical = 1 +}; + +enum ImGuiLogType +{ + ImGuiLogType_None = 0, + ImGuiLogType_TTY, + ImGuiLogType_File, + ImGuiLogType_Buffer, + ImGuiLogType_Clipboard +}; + +// X/Y enums are fixed to 0/1 so they may be used to index ImVec2 +enum ImGuiAxis +{ + ImGuiAxis_None = -1, + ImGuiAxis_X = 0, + ImGuiAxis_Y = 1 +}; + +enum ImGuiPlotType +{ + ImGuiPlotType_Lines, + ImGuiPlotType_Histogram +}; + +enum ImGuiInputSource +{ + ImGuiInputSource_None = 0, + ImGuiInputSource_Mouse, + ImGuiInputSource_Nav, + ImGuiInputSource_NavKeyboard, // Only used occasionally for storage, not tested/handled by most code + ImGuiInputSource_NavGamepad, // " + ImGuiInputSource_COUNT +}; + +// FIXME-NAV: Clarify/expose various repeat delay/rate +enum ImGuiInputReadMode +{ + ImGuiInputReadMode_Down, + ImGuiInputReadMode_Pressed, + ImGuiInputReadMode_Released, + ImGuiInputReadMode_Repeat, + ImGuiInputReadMode_RepeatSlow, + ImGuiInputReadMode_RepeatFast +}; + +enum ImGuiNavHighlightFlags_ +{ + ImGuiNavHighlightFlags_None = 0, + ImGuiNavHighlightFlags_TypeDefault = 1 << 0, + ImGuiNavHighlightFlags_TypeThin = 1 << 1, + ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse. + ImGuiNavHighlightFlags_NoRounding = 1 << 3 +}; + +enum ImGuiNavDirSourceFlags_ +{ + ImGuiNavDirSourceFlags_None = 0, + ImGuiNavDirSourceFlags_Keyboard = 1 << 0, + ImGuiNavDirSourceFlags_PadDPad = 1 << 1, + ImGuiNavDirSourceFlags_PadLStick = 1 << 2 +}; + +enum ImGuiNavMoveFlags_ +{ + ImGuiNavMoveFlags_None = 0, + ImGuiNavMoveFlags_LoopX = 1 << 0, // On failed request, restart from opposite side + ImGuiNavMoveFlags_LoopY = 1 << 1, + ImGuiNavMoveFlags_WrapX = 1 << 2, // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left) + ImGuiNavMoveFlags_WrapY = 1 << 3, // This is not super useful for provided for completeness + ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place) + ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5 // Store alternate result in NavMoveResultLocalVisibleSet that only comprise elements that are already fully visible. +}; + +enum ImGuiNavForward +{ + ImGuiNavForward_None, + ImGuiNavForward_ForwardQueued, + ImGuiNavForward_ForwardActive +}; + +enum ImGuiNavLayer +{ + ImGuiNavLayer_Main = 0, // Main scrolling layer + ImGuiNavLayer_Menu = 1, // Menu layer (access with Alt/ImGuiNavInput_Menu) + ImGuiNavLayer_COUNT +}; + +enum ImGuiPopupPositionPolicy +{ + ImGuiPopupPositionPolicy_Default, + ImGuiPopupPositionPolicy_ComboBox +}; + +// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches) +struct ImVec1 +{ + float x; + ImVec1() { x = 0.0f; } + ImVec1(float _x) { x = _x; } +}; + + +// 2D axis aligned bounding-box +// NB: we can't rely on ImVec2 math operators being available here +struct IMGUI_API ImRect +{ + ImVec2 Min; // Upper-left + ImVec2 Max; // Lower-right + + ImRect() : Min(FLT_MAX,FLT_MAX), Max(-FLT_MAX,-FLT_MAX) {} + ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} + ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} + ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {} + + ImVec2 GetCenter() const { return ImVec2((Min.x + Max.x) * 0.5f, (Min.y + Max.y) * 0.5f); } + ImVec2 GetSize() const { return ImVec2(Max.x - Min.x, Max.y - Min.y); } + float GetWidth() const { return Max.x - Min.x; } + float GetHeight() const { return Max.y - Min.y; } + ImVec2 GetTL() const { return Min; } // Top-left + ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } // Top-right + ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } // Bottom-left + ImVec2 GetBR() const { return Max; } // Bottom-right + bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } + bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } + bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } + void Add(const ImVec2& p) { if (Min.x > p.x) Min.x = p.x; if (Min.y > p.y) Min.y = p.y; if (Max.x < p.x) Max.x = p.x; if (Max.y < p.y) Max.y = p.y; } + void Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; } + void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } + void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } + void Translate(const ImVec2& d) { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; } + void TranslateX(float dx) { Min.x += dx; Max.x += dx; } + void TranslateY(float dy) { Min.y += dy; Max.y += dy; } + void ClipWith(const ImRect& r) { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); } // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display. + void ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped. + void Floor() { Min.x = (float)(int)Min.x; Min.y = (float)(int)Min.y; Max.x = (float)(int)Max.x; Max.y = (float)(int)Max.y; } + bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } +}; + +// Stacked color modifier, backup of modified data so we can restore it +struct ImGuiColorMod +{ + ImGuiCol Col; + ImVec4 BackupValue; +}; + +// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable. +struct ImGuiStyleMod +{ + ImGuiStyleVar VarIdx; + union { int BackupInt[2]; float BackupFloat[2]; }; + ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; } +}; + +// Stacked storage data for BeginGroup()/EndGroup() +struct ImGuiGroupData +{ + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + ImVec1 BackupIndent; + ImVec1 BackupGroupOffset; + ImVec2 BackupCurrentLineSize; + float BackupCurrentLineTextBaseOffset; + ImGuiID BackupActiveIdIsAlive; + bool BackupActiveIdPreviousFrameIsAlive; + bool AdvanceCursor; +}; + +// Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper. +struct IMGUI_API ImGuiMenuColumns +{ + float Spacing; + float Width, NextWidth; + float Pos[3], NextWidths[3]; + + ImGuiMenuColumns(); + void Update(int count, float spacing, bool clear); + float DeclColumns(float w0, float w1, float w2); + float CalcExtraSpace(float avail_w); +}; + +// Internal state of the currently focused/edited text input box +struct IMGUI_API ImGuiInputTextState +{ + ImGuiID ID; // widget id owning the text state + int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 len is valid even if TextA is not. + ImVector TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. + ImVector TextA; // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity. + ImVector InitialTextA; // backup of end-user buffer at the time of focus (in UTF-8, unaltered) + bool TextAIsValid; // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument) + int BufCapacityA; // end-user buffer capacity + float ScrollX; // horizontal scrolling/offset + ImStb::STB_TexteditState Stb; // state for stb_textedit.h + float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately + bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) + bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection + + // Temporarily set when active + ImGuiInputTextFlags UserFlags; + ImGuiInputTextCallback UserCallback; + void* UserCallbackData; + + ImGuiInputTextState() { memset(this, 0, sizeof(*this)); } + void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); } + void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking + void CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); } + bool HasSelection() const { return Stb.select_start != Stb.select_end; } + void ClearSelection() { Stb.select_start = Stb.select_end = Stb.cursor; } + void SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; } + int GetUndoAvailCount() const { return Stb.undostate.undo_point; } + int GetRedoAvailCount() const { return STB_TEXTEDIT_UNDOSTATECOUNT - Stb.undostate.redo_point; } + void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation +}; + +// Windows data saved in imgui.ini file +struct ImGuiWindowSettings +{ + char* Name; + ImGuiID ID; + ImVec2 Pos; + ImVec2 Size; + bool Collapsed; + + ImGuiWindowSettings() { Name = NULL; ID = 0; Pos = Size = ImVec2(0,0); Collapsed = false; } +}; + +struct ImGuiSettingsHandler +{ + const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']' + ImGuiID TypeHash; // == ImHashStr(TypeName, 0, 0) + void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]" + void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry + void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf' + void* UserData; + + ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); } +}; + +// Storage for current popup stack +struct ImGuiPopupRef +{ + ImGuiID PopupId; // Set on OpenPopup() + ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() + ImGuiWindow* ParentWindow; // Set on OpenPopup() + int OpenFrameCount; // Set on OpenPopup() + ImGuiID OpenParentId; // Set on OpenPopup(), we need this to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items) + ImVec2 OpenPopupPos; // Set on OpenPopup(), preferred popup position (typically == OpenMousePos when using mouse) + ImVec2 OpenMousePos; // Set on OpenPopup(), copy of mouse position at the time of opening popup +}; + +struct ImGuiColumnData +{ + float OffsetNorm; // Column start offset, normalized 0.0 (far left) -> 1.0 (far right) + float OffsetNormBeforeResize; + ImGuiColumnsFlags Flags; // Not exposed + ImRect ClipRect; + + ImGuiColumnData() { OffsetNorm = OffsetNormBeforeResize = 0.0f; Flags = 0; } +}; + +struct ImGuiColumnsSet +{ + ImGuiID ID; + ImGuiColumnsFlags Flags; + bool IsFirstFrame; + bool IsBeingResized; + int Current; + int Count; + float MinX, MaxX; + float LineMinY, LineMaxY; + float StartPosY; // Copy of CursorPos + float StartMaxPosX; // Copy of CursorMaxPos + ImVector Columns; + + ImGuiColumnsSet() { Clear(); } + void Clear() + { + ID = 0; + Flags = 0; + IsFirstFrame = false; + IsBeingResized = false; + Current = 0; + Count = 1; + MinX = MaxX = 0.0f; + LineMinY = LineMaxY = 0.0f; + StartPosY = 0.0f; + StartMaxPosX = 0.0f; + Columns.clear(); + } +}; + +// Data shared between all ImDrawList instances +struct IMGUI_API ImDrawListSharedData +{ + ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas + ImFont* Font; // Current/default font (optional, for simplified AddText overload) + float FontSize; // Current/default font size (optional, for simplified AddText overload) + float CurveTessellationTol; + ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() + + // Const data + // FIXME: Bake rounded corners fill/borders in atlas + ImVec2 CircleVtx12[12]; + + ImDrawListSharedData(); +}; + +struct ImDrawDataBuilder +{ + ImVector Layers[2]; // Global layers for: regular, tooltip + + void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); } + void ClearFreeMemory() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); } + IMGUI_API void FlattenIntoSingleLayer(); +}; + +struct ImGuiNavMoveResult +{ + ImGuiID ID; // Best candidate + ImGuiID SelectScopeId;// Best candidate window current selectable group ID + ImGuiWindow* Window; // Best candidate window + float DistBox; // Best candidate box distance to current NavId + float DistCenter; // Best candidate center distance to current NavId + float DistAxial; + ImRect RectRel; // Best candidate bounding box in window relative space + + ImGuiNavMoveResult() { Clear(); } + void Clear() { ID = SelectScopeId = 0; Window = NULL; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); } +}; + +// Storage for SetNexWindow** functions +struct ImGuiNextWindowData +{ + ImGuiCond PosCond; + ImGuiCond SizeCond; + ImGuiCond ContentSizeCond; + ImGuiCond CollapsedCond; + ImGuiCond SizeConstraintCond; + ImGuiCond FocusCond; + ImGuiCond BgAlphaCond; + ImVec2 PosVal; + ImVec2 PosPivotVal; + ImVec2 SizeVal; + ImVec2 ContentSizeVal; + bool CollapsedVal; + ImRect SizeConstraintRect; + ImGuiSizeCallback SizeCallback; + void* SizeCallbackUserData; + float BgAlphaVal; + ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it. + + ImGuiNextWindowData() + { + PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0; + PosVal = PosPivotVal = SizeVal = ImVec2(0.0f, 0.0f); + ContentSizeVal = ImVec2(0.0f, 0.0f); + CollapsedVal = false; + SizeConstraintRect = ImRect(); + SizeCallback = NULL; + SizeCallbackUserData = NULL; + BgAlphaVal = FLT_MAX; + MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); + } + + void Clear() + { + PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0; + } +}; + +//----------------------------------------------------------------------------- +// Tabs +//----------------------------------------------------------------------------- + +struct ImGuiTabBarSortItem +{ + int Index; + float Width; +}; + +struct ImGuiTabBarRef +{ + ImGuiTabBar* Ptr; // Either field can be set, not both. Dock node tab bars are loose while BeginTabBar() ones are in a pool. + int IndexInMainPool; + + ImGuiTabBarRef(ImGuiTabBar* ptr) { Ptr = ptr; IndexInMainPool = -1; } + ImGuiTabBarRef(int index_in_main_pool) { Ptr = NULL; IndexInMainPool = index_in_main_pool; } +}; + +//----------------------------------------------------------------------------- +// Main imgui context +//----------------------------------------------------------------------------- + +struct ImGuiContext +{ + bool Initialized; + bool FrameScopeActive; // Set by NewFrame(), cleared by EndFrame() + bool FrameScopePushedImplicitWindow; // Set by NewFrame(), cleared by EndFrame() + bool FontAtlasOwnedByContext; // Io.Fonts-> is owned by the ImGuiContext and will be destructed along with it. + ImGuiIO IO; + ImGuiStyle Style; + ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() + float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. + float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height. + ImDrawListSharedData DrawListSharedData; + + double Time; + int FrameCount; + int FrameCountEnded; + int FrameCountRendered; + ImVector Windows; // Windows, sorted in display order, back to front + ImVector WindowsFocusOrder; // Windows, sorted in focus order, back to front + ImVector WindowsSortBuffer; + ImVector CurrentWindowStack; + ImGuiStorage WindowsById; + int WindowsActiveCount; + ImGuiWindow* CurrentWindow; // Being drawn into + ImGuiWindow* HoveredWindow; // Will catch mouse inputs + ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) + ImGuiID HoveredId; // Hovered widget + bool HoveredIdAllowOverlap; + ImGuiID HoveredIdPreviousFrame; + float HoveredIdTimer; // Measure contiguous hovering time + float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active + ImGuiID ActiveId; // Active widget + ImGuiID ActiveIdPreviousFrame; + ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame) + float ActiveIdTimer; + bool ActiveIdIsJustActivated; // Set at the time of activation for one frame + bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) + bool ActiveIdHasBeenPressed; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch. + bool ActiveIdHasBeenEdited; // Was the value associated to the widget Edited over the course of the Active state. + bool ActiveIdPreviousFrameIsAlive; + bool ActiveIdPreviousFrameHasBeenEdited; + int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it) + int ActiveIdBlockNavInputFlags; + ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) + ImGuiWindow* ActiveIdWindow; + ImGuiWindow* ActiveIdPreviousFrameWindow; + ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) + ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. + float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. + ImVec2 LastValidMousePos; + ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow. + ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() + ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() + ImVector FontStack; // Stack for PushFont()/PopFont() + ImVector OpenPopupStack; // Which popups are open (persistent) + ImVector BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) + ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions + bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions + ImGuiCond NextTreeNodeOpenCond; + + // Navigation data (for gamepad/keyboard) + ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusWindow' + ImGuiID NavId; // Focused item for navigation + ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0, also set when calling ActivateItem() + ImGuiID NavActivateDownId; // ~~ IsNavInputDown(ImGuiNavInput_Activate) ? NavId : 0 + ImGuiID NavActivatePressedId; // ~~ IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0 + ImGuiID NavInputId; // ~~ IsNavInputPressed(ImGuiNavInput_Input) ? NavId : 0 + ImGuiID NavJustTabbedId; // Just tabbed to this id. + ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest). + ImGuiID NavJustMovedToSelectScopeId; // Just navigated to this select scope id (result of a successfully MoveRequest). + ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame. + ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard. + ImRect NavScoringRectScreen; // Rectangle used for scoring, in screen space. Based of window->DC.NavRefRectRel[], modified for directional navigation scoring. + int NavScoringCount; // Metrics for debugging + ImGuiWindow* NavWindowingTarget; // When selecting a window (holding Menu+FocusPrev/Next, or equivalent of CTRL-TAB) this window is temporarily displayed front-most. + ImGuiWindow* NavWindowingTargetAnim; // Record of last valid NavWindowingTarget until DimBgRatio and NavWindowingHighlightAlpha becomes 0.0f + ImGuiWindow* NavWindowingList; + float NavWindowingTimer; + float NavWindowingHighlightAlpha; + bool NavWindowingToggleLayer; + ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later. + int NavIdTabCounter; // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing + bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRefRectRel is valid + bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default) + bool NavDisableHighlight; // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover) + bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again. + bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest + bool NavInitRequest; // Init request for appearing window to select first item + bool NavInitRequestFromMove; + ImGuiID NavInitResultId; + ImRect NavInitResultRectRel; + bool NavMoveFromClampedRefRect; // Set by manual scrolling, if we scroll to a point where NavId isn't visible we reset navigation from visible items + bool NavMoveRequest; // Move request for this frame + ImGuiNavMoveFlags NavMoveRequestFlags; + ImGuiNavForward NavMoveRequestForward; // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu) + ImGuiDir NavMoveDir, NavMoveDirLast; // Direction of the move request (left/right/up/down), direction of the previous move request + ImGuiDir NavMoveClipDir; + ImGuiNavMoveResult NavMoveResultLocal; // Best move request candidate within NavWindow + ImGuiNavMoveResult NavMoveResultLocalVisibleSet; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag) + ImGuiNavMoveResult NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag) + + // Tabbing system (older than Nav, active even if Nav is disabled. FIXME-NAV: This needs a redesign!) + ImGuiWindow* FocusRequestCurrWindow; // + ImGuiWindow* FocusRequestNextWindow; // + int FocusRequestCurrCounterAll; // Any item being requested for focus, stored as an index (we on layout to be stable between the frame pressing TAB and the next frame, semi-ouch) + int FocusRequestCurrCounterTab; // Tab item being requested for focus, stored as an index + int FocusRequestNextCounterAll; // Stored for next frame + int FocusRequestNextCounterTab; // " + bool FocusTabPressed; // + + // Render + ImDrawData DrawData; // Main ImDrawData instance to pass render information to the user + ImDrawDataBuilder DrawDataBuilder; + float DimBgRatio; // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list) + ImDrawList BackgroundDrawList; // First draw list to be rendered. + ImDrawList ForegroundDrawList; // Last draw list to be rendered. This is where we the render software mouse cursor (if io.MouseDrawCursor is set) and most debug overlays. + ImGuiMouseCursor MouseCursor; + + // Drag and Drop + bool DragDropActive; + bool DragDropWithinSourceOrTarget; + ImGuiDragDropFlags DragDropSourceFlags; + int DragDropSourceFrameCount; + int DragDropMouseButton; + ImGuiPayload DragDropPayload; + ImRect DragDropTargetRect; + ImGuiID DragDropTargetId; + ImGuiDragDropFlags DragDropAcceptFlags; + float DragDropAcceptIdCurrRectSurface; // Target item surface (we resolve overlapping targets by prioritizing the smaller surface) + ImGuiID DragDropAcceptIdCurr; // Target item id (set at the time of accepting the payload) + ImGuiID DragDropAcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets) + int DragDropAcceptFrameCount; // Last time a target expressed a desire to accept the source + ImVector DragDropPayloadBufHeap; // We don't expose the ImVector<> directly + unsigned char DragDropPayloadBufLocal[8]; // Local buffer for small payloads + + // Tab bars + ImPool TabBars; + ImGuiTabBar* CurrentTabBar; + ImVector CurrentTabBarStack; + ImVector TabSortByWidthBuffer; + + // Widget state + ImGuiInputTextState InputTextState; + ImFont InputTextPasswordFont; + ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. + ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets + ImVec4 ColorPickerRef; + bool DragCurrentAccumDirty; + float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings + float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio + ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? + int TooltipOverrideCount; + ImVector PrivateClipboard; // If no custom clipboard handler is defined + + // Range-Select/Multi-Select + // [This is unused in this branch, but left here to facilitate merging/syncing multiple branches] + ImGuiID MultiSelectScopeId; + + // Platform support + ImVec2 PlatformImePos; // Cursor position request & last passed to the OS Input Method Editor + ImVec2 PlatformImeLastPos; + + // Settings + bool SettingsLoaded; + float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero + ImGuiTextBuffer SettingsIniData; // In memory .ini settings + ImVector SettingsHandlers; // List of .ini settings handlers + ImVector SettingsWindows; // ImGuiWindow .ini settings entries (parsed from the last loaded .ini file and maintained on saving) + + // Logging + bool LogEnabled; + ImGuiLogType LogType; + FILE* LogFile; // If != NULL log to stdout/ file + ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. + float LogLinePosY; + bool LogLineFirstItem; + int LogDepthRef; + int LogDepthToExpand; + int LogDepthToExpandDefault; // Default/stored value for LogDepthMaxExpand if not specified in the LogXXX function call. + + // Misc + float FramerateSecPerFrame[120]; // Calculate estimate of framerate for user over the last 2 seconds. + int FramerateSecPerFrameIdx; + float FramerateSecPerFrameAccum; + int WantCaptureMouseNextFrame; // Explicit capture via CaptureKeyboardFromApp()/CaptureMouseFromApp() sets those flags + int WantCaptureKeyboardNextFrame; + int WantTextInputNextFrame; + char TempBuffer[1024*3+1]; // Temporary text buffer + + ImGuiContext(ImFontAtlas* shared_font_atlas) : BackgroundDrawList(NULL), ForegroundDrawList(NULL) + { + Initialized = false; + FrameScopeActive = FrameScopePushedImplicitWindow = false; + Font = NULL; + FontSize = FontBaseSize = 0.0f; + FontAtlasOwnedByContext = shared_font_atlas ? false : true; + IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); + + Time = 0.0f; + FrameCount = 0; + FrameCountEnded = FrameCountRendered = -1; + WindowsActiveCount = 0; + CurrentWindow = NULL; + HoveredWindow = NULL; + HoveredRootWindow = NULL; + HoveredId = 0; + HoveredIdAllowOverlap = false; + HoveredIdPreviousFrame = 0; + HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f; + ActiveId = 0; + ActiveIdPreviousFrame = 0; + ActiveIdIsAlive = 0; + ActiveIdTimer = 0.0f; + ActiveIdIsJustActivated = false; + ActiveIdAllowOverlap = false; + ActiveIdHasBeenPressed = false; + ActiveIdHasBeenEdited = false; + ActiveIdPreviousFrameIsAlive = false; + ActiveIdPreviousFrameHasBeenEdited = false; + ActiveIdAllowNavDirFlags = 0x00; + ActiveIdBlockNavInputFlags = 0x00; + ActiveIdClickOffset = ImVec2(-1,-1); + ActiveIdWindow = ActiveIdPreviousFrameWindow = NULL; + ActiveIdSource = ImGuiInputSource_None; + LastActiveId = 0; + LastActiveIdTimer = 0.0f; + LastValidMousePos = ImVec2(0.0f, 0.0f); + MovingWindow = NULL; + NextTreeNodeOpenVal = false; + NextTreeNodeOpenCond = 0; + + NavWindow = NULL; + NavId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0; + NavJustTabbedId = NavJustMovedToId = NavJustMovedToSelectScopeId = NavNextActivateId = 0; + NavInputSource = ImGuiInputSource_None; + NavScoringRectScreen = ImRect(); + NavScoringCount = 0; + NavWindowingTarget = NavWindowingTargetAnim = NavWindowingList = NULL; + NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; + NavWindowingToggleLayer = false; + NavLayer = ImGuiNavLayer_Main; + NavIdTabCounter = INT_MAX; + NavIdIsAlive = false; + NavMousePosDirty = false; + NavDisableHighlight = true; + NavDisableMouseHover = false; + NavAnyRequest = false; + NavInitRequest = false; + NavInitRequestFromMove = false; + NavInitResultId = 0; + NavMoveFromClampedRefRect = false; + NavMoveRequest = false; + NavMoveRequestFlags = 0; + NavMoveRequestForward = ImGuiNavForward_None; + NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None; + + FocusRequestCurrWindow = FocusRequestNextWindow = NULL; + FocusRequestCurrCounterAll = FocusRequestCurrCounterTab = INT_MAX; + FocusRequestNextCounterAll = FocusRequestNextCounterTab = INT_MAX; + FocusTabPressed = false; + + DimBgRatio = 0.0f; + BackgroundDrawList._Data = &DrawListSharedData; + BackgroundDrawList._OwnerName = "##Background"; // Give it a name for debugging + ForegroundDrawList._Data = &DrawListSharedData; + ForegroundDrawList._OwnerName = "##Foreground"; // Give it a name for debugging + MouseCursor = ImGuiMouseCursor_Arrow; + + DragDropActive = DragDropWithinSourceOrTarget = false; + DragDropSourceFlags = 0; + DragDropSourceFrameCount = -1; + DragDropMouseButton = -1; + DragDropTargetId = 0; + DragDropAcceptFlags = 0; + DragDropAcceptIdCurrRectSurface = 0.0f; + DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0; + DragDropAcceptFrameCount = -1; + memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); + + CurrentTabBar = NULL; + + ScalarAsInputTextId = 0; + ColorEditOptions = ImGuiColorEditFlags__OptionsDefault; + DragCurrentAccumDirty = false; + DragCurrentAccum = 0.0f; + DragSpeedDefaultRatio = 1.0f / 100.0f; + ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f); + TooltipOverrideCount = 0; + + MultiSelectScopeId = 0; + + PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX); + + SettingsLoaded = false; + SettingsDirtyTimer = 0.0f; + + LogEnabled = false; + LogType = ImGuiLogType_None; + LogFile = NULL; + LogLinePosY = FLT_MAX; + LogLineFirstItem = false; + LogDepthRef = 0; + LogDepthToExpand = LogDepthToExpandDefault = 2; + + memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); + FramerateSecPerFrameIdx = 0; + FramerateSecPerFrameAccum = 0.0f; + WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1; + memset(TempBuffer, 0, sizeof(TempBuffer)); + } +}; + +//----------------------------------------------------------------------------- +// ImGuiWindow +//----------------------------------------------------------------------------- + +// Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow. +// FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered. +struct IMGUI_API ImGuiWindowTempData +{ + ImVec2 CursorPos; + ImVec2 CursorPosPrevLine; + ImVec2 CursorStartPos; // Initial position in client area with padding + ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Turned into window->SizeContents at the beginning of next frame + ImVec2 CurrentLineSize; + float CurrentLineTextBaseOffset; + ImVec2 PrevLineSize; + float PrevLineTextBaseOffset; + int TreeDepth; + ImU32 TreeDepthMayJumpToParentOnPop; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31 + ImGuiID LastItemId; + ImGuiItemStatusFlags LastItemStatusFlags; + ImRect LastItemRect; // Interaction rect + ImRect LastItemDisplayRect; // End-user display rect (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) + ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) + int NavLayerCurrentMask; // = (1 << NavLayerCurrent) used by ItemAdd prior to clipping. + int NavLayerActiveMask; // Which layer have been written to (result from previous frame) + int NavLayerActiveMaskNext; // Which layer have been written to (buffer for current frame) + bool NavHideHighlightOneFrame; + bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f) + bool MenuBarAppending; // FIXME: Remove this + ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs. + ImVector ChildWindows; + ImGuiStorage* StateStorage; + ImGuiLayoutType LayoutType; + ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin() + int FocusCounterAll; // Counter for focus/tabbing system. Start at -1 and increase as assigned via FocusableItemRegister() (FIXME-NAV: Needs redesign) + int FocusCounterTab; // (same, but only count widgets which you can Tab through) + + // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. + ImGuiItemFlags ItemFlags; // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default] + float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window + float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] + ImVectorItemFlagsStack; + ImVector ItemWidthStack; + ImVector TextWrapPosStack; + ImVectorGroupStack; + short StackSizesBackup[6]; // Store size of various stacks for asserting + + ImVec1 Indent; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) + ImVec1 GroupOffset; + ImVec1 ColumnsOffset; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. + ImGuiColumnsSet* ColumnsSet; // Current columns set + + ImGuiWindowTempData() + { + CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f); + CurrentLineSize = PrevLineSize = ImVec2(0.0f, 0.0f); + CurrentLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; + TreeDepth = 0; + TreeDepthMayJumpToParentOnPop = 0x00; + LastItemId = 0; + LastItemStatusFlags = 0; + LastItemRect = LastItemDisplayRect = ImRect(); + NavLayerActiveMask = NavLayerActiveMaskNext = 0x00; + NavLayerCurrent = ImGuiNavLayer_Main; + NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); + NavHideHighlightOneFrame = false; + NavHasScroll = false; + MenuBarAppending = false; + MenuBarOffset = ImVec2(0.0f, 0.0f); + StateStorage = NULL; + LayoutType = ParentLayoutType = ImGuiLayoutType_Vertical; + FocusCounterAll = FocusCounterTab = -1; + + ItemFlags = ImGuiItemFlags_Default_; + ItemWidth = 0.0f; + TextWrapPos = -1.0f; + memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); + + Indent = ImVec1(0.0f); + GroupOffset = ImVec1(0.0f); + ColumnsOffset = ImVec1(0.0f); + ColumnsSet = NULL; + } +}; + +// Storage for one window +struct IMGUI_API ImGuiWindow +{ + char* Name; + ImGuiID ID; // == ImHash(Name) + ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_ + ImVec2 Pos; // Position (always rounded-up to nearest pixel) + ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) + ImVec2 SizeFull; // Size when non collapsed + ImVec2 SizeFullAtLastBegin; // Copy of SizeFull at the end of Begin. This is the reference value we'll use on the next frame to decide if we need scrollbars. + ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame. Include decoration, window title, border, menu, etc. + ImVec2 SizeContentsExplicit; // Size of contents explicitly set by the user via SetNextWindowContentSize() + ImVec2 WindowPadding; // Window padding at the time of begin. + float WindowRounding; // Window rounding at the time of begin. + float WindowBorderSize; // Window border size at the time of begin. + int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)! + ImGuiID MoveId; // == window->GetID("#MOVE") + ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window) + ImVec2 Scroll; + ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) + ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered + ImVec2 ScrollbarSizes; // Size taken by scrollbars on each axis + bool ScrollbarX, ScrollbarY; + bool Active; // Set to true on Begin(), unless Collapsed + bool WasActive; + bool WriteAccessed; // Set to true when any widget access the current window + bool Collapsed; // Set when collapsing window to become only title-bar + bool WantCollapseToggle; + bool SkipItems; // Set when items can safely be all clipped (e.g. window not visible or collapsed) + bool Appearing; // Set during the frame where the window is appearing (or re-appearing) + bool Hidden; // Do not display (== (HiddenFramesForResize > 0) || + bool HasCloseButton; // Set when the window has a close button (p_open != NULL) + signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3) + short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) + short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. + short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues. + ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) + int AutoFitFramesX, AutoFitFramesY; + bool AutoFitOnlyGrows; + int AutoFitChildAxises; + ImGuiDir AutoPosLastDirection; + int HiddenFramesRegular; // Hide the window for N frames + int HiddenFramesForResize; // Hide the window for N frames while allowing items to be submitted so we can measure their size + ImGuiCond SetWindowPosAllowFlags; // store acceptable condition flags for SetNextWindowPos() use. + ImGuiCond SetWindowSizeAllowFlags; // store acceptable condition flags for SetNextWindowSize() use. + ImGuiCond SetWindowCollapsedAllowFlags; // store acceptable condition flags for SetNextWindowCollapsed() use. + ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size) + ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0,0) when positioning from top-left corner; ImVec2(0.5f,0.5f) for centering; ImVec2(1,1) for bottom right. + + ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name. + ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack + ImRect ClipRect; // Current clipping rectangle. = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2. + ImRect OuterRectClipped; // = WindowRect just after setup in Begin(). == window->Rect() for root window. + ImRect InnerMainRect, InnerClipRect; + ImRect ContentsRegionRect; // FIXME: This is currently confusing/misleading. Maximum visible content position ~~ Pos + (SizeContentsExplicit ? SizeContentsExplicit : Size - ScrollbarSizes) - CursorStartPos, per axis + int LastFrameActive; // Last frame number the window was Active. + float ItemWidthDefault; + ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items + ImGuiStorage StateStorage; + ImVector ColumnsStorage; + float FontWindowScale; // User scale multiplier per-window + int SettingsIdx; // Index into SettingsWindow[] (indices are always valid as we only grow the array from the back) + + ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) + ImDrawList DrawListInst; + ImGuiWindow* ParentWindow; // If we are a child _or_ popup window, this is pointing to our parent. Otherwise NULL. + ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window. + ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active. + ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag. + + ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.) + ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1) + ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space + +public: + ImGuiWindow(ImGuiContext* context, const char* name); + ~ImGuiWindow(); + + ImGuiID GetID(const char* str, const char* str_end = NULL); + ImGuiID GetID(const void* ptr); + ImGuiID GetIDNoKeepAlive(const char* str, const char* str_end = NULL); + ImGuiID GetIDNoKeepAlive(const void* ptr); + ImGuiID GetIDFromRectangle(const ImRect& r_abs); + + // We don't use g.FontSize because the window may be != g.CurrentWidow. + ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); } + float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; } + float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; } + ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); } + float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; } + ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } +}; + +// Backup and restore just enough data to be able to use IsItemHovered() on item A after another B in the same window has overwritten the data. +struct ImGuiItemHoveredDataBackup +{ + ImGuiID LastItemId; + ImGuiItemStatusFlags LastItemStatusFlags; + ImRect LastItemRect; + ImRect LastItemDisplayRect; + + ImGuiItemHoveredDataBackup() { Backup(); } + void Backup() { ImGuiWindow* window = GImGui->CurrentWindow; LastItemId = window->DC.LastItemId; LastItemStatusFlags = window->DC.LastItemStatusFlags; LastItemRect = window->DC.LastItemRect; LastItemDisplayRect = window->DC.LastItemDisplayRect; } + void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; } +}; + +//----------------------------------------------------------------------------- +// Tab bar, tab item +//----------------------------------------------------------------------------- + +enum ImGuiTabBarFlagsPrivate_ +{ + ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node [we don't use this in the master branch but it facilitate branch syncing to keep this around] + ImGuiTabBarFlags_IsFocused = 1 << 21, + ImGuiTabBarFlags_SaveSettings = 1 << 22 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs +}; + +enum ImGuiTabItemFlagsPrivate_ +{ + ImGuiTabItemFlags_NoCloseButton = 1 << 20 // Store whether p_open is set or not, which we need to recompute WidthContents during layout. +}; + +// Storage for one active tab item (sizeof() 26~32 bytes) +struct ImGuiTabItem +{ + ImGuiID ID; + ImGuiTabItemFlags Flags; + int LastFrameVisible; + int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance + int NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames + float Offset; // Position relative to beginning of tab + float Width; // Width currently displayed + float WidthContents; // Width of actual contents, stored during BeginTabItem() call + + ImGuiTabItem() { ID = Flags = 0; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = WidthContents = 0.0f; } +}; + +// Storage for a tab bar (sizeof() 92~96 bytes) +struct ImGuiTabBar +{ + ImVector Tabs; + ImGuiID ID; // Zero for tab-bars used by docking + ImGuiID SelectedTabId; // Selected tab + ImGuiID NextSelectedTabId; + ImGuiID VisibleTabId; // Can occasionally be != SelectedTabId (e.g. when previewing contents for CTRL+TAB preview) + int CurrFrameVisible; + int PrevFrameVisible; + ImRect BarRect; + float ContentsHeight; + float OffsetMax; // Distance from BarRect.Min.x, locked during layout + float OffsetNextTab; // Distance from BarRect.Min.x, incremented with each BeginTabItem() call, not used if ImGuiTabBarFlags_Reorderable if set. + float ScrollingAnim; + float ScrollingTarget; + float ScrollingTargetDistToVisibility; + float ScrollingSpeed; + ImGuiTabBarFlags Flags; + ImGuiID ReorderRequestTabId; + int ReorderRequestDir; + bool WantLayout; + bool VisibleTabWasSubmitted; + short LastTabItemIdx; // For BeginTabItem()/EndTabItem() + ImVec2 FramePadding; // style.FramePadding locked at the time of BeginTabBar() + ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer. + + ImGuiTabBar(); + int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); } + const char* GetTabName(const ImGuiTabItem* tab) const + { + IM_ASSERT(tab->NameOffset != -1 && tab->NameOffset < TabsNames.Buf.Size); + return TabsNames.Buf.Data + tab->NameOffset; + } +}; + +//----------------------------------------------------------------------------- +// Internal API +// No guarantee of forward compatibility here. +//----------------------------------------------------------------------------- + +namespace ImGui +{ + // We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) + // If this ever crash because g.CurrentWindow is NULL it means that either + // - ImGui::NewFrame() has never been called, which is illegal. + // - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. + inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } + inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } + IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id); + IMGUI_API ImGuiWindow* FindWindowByName(const char* name); + IMGUI_API void FocusWindow(ImGuiWindow* window); + IMGUI_API void FocusPreviousWindowIgnoringOne(ImGuiWindow* ignore_window); + IMGUI_API void BringWindowToFocusFront(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayFront(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayBack(ImGuiWindow* window); + IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window); + IMGUI_API ImVec2 CalcWindowExpectedSize(ImGuiWindow* window); + IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent); + IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window); + IMGUI_API void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x); + IMGUI_API void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y); + IMGUI_API float GetWindowScrollMaxX(ImGuiWindow* window); + IMGUI_API float GetWindowScrollMaxY(ImGuiWindow* window); + IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window); + IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond); + IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond); + IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond); + + IMGUI_API void SetCurrentFont(ImFont* font); + inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } + + // Init + IMGUI_API void Initialize(ImGuiContext* context); + IMGUI_API void Shutdown(ImGuiContext* context); // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext(). + + // NewFrame + IMGUI_API void UpdateHoveredWindowAndCaptureFlags(); + IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); + IMGUI_API void UpdateMouseMovingWindowNewFrame(); + IMGUI_API void UpdateMouseMovingWindowEndFrame(); + + // Settings + IMGUI_API void MarkIniSettingsDirty(); + IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window); + IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); + IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id); + IMGUI_API ImGuiWindowSettings* FindOrCreateWindowSettings(const char* name); + IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); + + // Basic Accessors + inline ImGuiID GetItemID() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemId; } + inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } + inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } + IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); + IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow* window); + IMGUI_API void ClearActiveID(); + IMGUI_API ImGuiID GetHoveredID(); + IMGUI_API void SetHoveredID(ImGuiID id); + IMGUI_API void KeepAliveID(ImGuiID id); + IMGUI_API void MarkItemEdited(ImGuiID id); + + // Basic Helpers for widget code + IMGUI_API void ItemSize(const ImVec2& size, float text_offset_y = 0.0f); + IMGUI_API void ItemSize(const ImRect& bb, float text_offset_y = 0.0f); + IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL); + IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); + IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); + IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id); // Return true if focus is requested + IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); + IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y); + IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); + IMGUI_API void PushMultiItemsWidths(int components, float width_full = 0.0f); + IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); + IMGUI_API void PopItemFlag(); + + // Logging/Capture + IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. + IMGUI_API void LogToBuffer(int auto_open_depth = -1); // Start logging/capturing to internal buffer + + // Popups, Modals, Tooltips + IMGUI_API void OpenPopupEx(ImGuiID id); + IMGUI_API void ClosePopupToLevel(int remaining, bool apply_focus_to_window_under); + IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window); + IMGUI_API bool IsPopupOpen(ImGuiID id); // Test for id within current popup stack level (currently begin-ed into); this doesn't scan the whole popup stack! + IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); + IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip = true); + IMGUI_API ImGuiWindow* GetFrontMostPopupModal(); + IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window); + IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy = ImGuiPopupPositionPolicy_Default); + + // Navigation + IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); + IMGUI_API bool NavMoveRequestButNoResultYet(); + IMGUI_API void NavMoveRequestCancel(); + IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags); + IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); + IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode); + IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f); + IMGUI_API int CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate); + IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again. + IMGUI_API void SetNavID(ImGuiID id, int nav_layer); + IMGUI_API void SetNavIDWithRectRel(ImGuiID id, int nav_layer, const ImRect& rect_rel); + + // Inputs + inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { const int key_index = GImGui->IO.KeyMap[key]; return (key_index >= 0) ? IsKeyPressed(key_index, repeat) : false; } + inline bool IsNavInputDown(ImGuiNavInput n) { return GImGui->IO.NavInputs[n] > 0.0f; } + inline bool IsNavInputPressed(ImGuiNavInput n, ImGuiInputReadMode mode) { return GetNavInputAmount(n, mode) > 0.0f; } + inline bool IsNavInputPressedAnyOfTwo(ImGuiNavInput n1, ImGuiNavInput n2, ImGuiInputReadMode mode) { return (GetNavInputAmount(n1, mode) + GetNavInputAmount(n2, mode)) > 0.0f; } + + // Drag and Drop + IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id); + IMGUI_API void ClearDragDrop(); + IMGUI_API bool IsDragDropPayloadBeingAccepted(); + + // New Columns API (FIXME-WIP) + IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiColumnsFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). + IMGUI_API void EndColumns(); // close columns + IMGUI_API void PushColumnClipRect(int column_index = -1); + + // Tab Bars + IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags); + IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + IMGUI_API void TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir); + IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags); + IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button); + IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col); + IMGUI_API bool TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id); + + // Render helpers + // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT. + // NB: All position are in absolute pixels coordinates (we are never using window coordinates internally) + IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); + IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); + IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0,0), const ImRect* clip_rect = NULL); + IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); + IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); + IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); + IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0); + IMGUI_API void RenderArrow(ImVec2 pos, ImGuiDir dir, float scale = 1.0f); + IMGUI_API void RenderBullet(ImVec2 pos); + IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col, float sz); + IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight + IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. + IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); + + // Render helpers (those functions don't access any ImGui state!) + IMGUI_API void RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor = ImGuiMouseCursor_Arrow); + IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col); + IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding); + IMGUI_API void RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col); + + // Widgets + IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); + IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); + IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius); + IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); + IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags); + IMGUI_API void Scrollbar(ImGuiAxis axis); + IMGUI_API ImGuiID GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis); + IMGUI_API void VerticalSeparator(); // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. + + // Widgets low-level behaviors + IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); + IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power, ImGuiDragFlags flags); + IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb); + IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f); + IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); + IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging + IMGUI_API void TreePushRawID(ImGuiID id); + + // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. + // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036). + // e.g. " extern template IMGUI_API float RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, float v); " + template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, float power, ImGuiDragFlags flags); + template IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb); + template IMGUI_API float SliderCalcRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, float power, float linear_zero_pos); + template IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v); + + // InputText + IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format); + + // Color + IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags); + IMGUI_API void ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags); + IMGUI_API void ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags); + + // Plot + IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size); + + // Shade functions (write over already created vertices) + IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1); + IMGUI_API void ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp); + +} // namespace ImGui + +// ImFontAtlas internals +IMGUI_API bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); +IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); +IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); +IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); + +// Test engine hooks (imgui-test) +//#define IMGUI_ENABLE_TEST_ENGINE +#ifdef IMGUI_ENABLE_TEST_ENGINE +extern void ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx); +extern void ImGuiTestEngineHook_PostNewFrame(ImGuiContext* ctx); +extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); +extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags); +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register status flags +#else +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) do { } while (0) +#endif + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#ifdef _MSC_VER +#pragma warning (pop) +#endif diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_widgets.cpp b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_widgets.cpp new file mode 100644 index 00000000..23411258 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imgui_widgets.cpp @@ -0,0 +1,6935 @@ +// dear imgui, v1.69 +// (widgets code) + +/* + +Index of this file: + +// [SECTION] Forward Declarations +// [SECTION] Widgets: Text, etc. +// [SECTION] Widgets: Main (Button, Image, Checkbox, RadioButton, ProgressBar, Bullet, etc.) +// [SECTION] Widgets: Low-level Layout helpers (Spacing, Dummy, NewLine, Separator, etc.) +// [SECTION] Widgets: ComboBox +// [SECTION] Data Type and Data Formatting Helpers +// [SECTION] Widgets: DragScalar, DragFloat, DragInt, etc. +// [SECTION] Widgets: SliderScalar, SliderFloat, SliderInt, etc. +// [SECTION] Widgets: InputScalar, InputFloat, InputInt, etc. +// [SECTION] Widgets: InputText, InputTextMultiline +// [SECTION] Widgets: ColorEdit, ColorPicker, ColorButton, etc. +// [SECTION] Widgets: TreeNode, CollapsingHeader, etc. +// [SECTION] Widgets: Selectable +// [SECTION] Widgets: ListBox +// [SECTION] Widgets: PlotLines, PlotHistogram +// [SECTION] Widgets: Value helpers +// [SECTION] Widgets: MenuItem, BeginMenu, EndMenu, etc. +// [SECTION] Widgets: BeginTabBar, EndTabBar, etc. +// [SECTION] Widgets: BeginTabItem, EndTabItem, etc. + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +#include // toupper, isprint +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#endif + +// Clang/GCC warnings with -Weverything +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#endif +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#endif +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#if __GNUC__ >= 8 +#pragma GCC diagnostic ignored "-Wclass-memaccess" // warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif +#endif + +//------------------------------------------------------------------------- +// Data +//------------------------------------------------------------------------- + +// Those MIN/MAX values are not define because we need to point to them +static const signed char IM_S8_MIN = -128; +static const signed char IM_S8_MAX = 127; +static const unsigned char IM_U8_MIN = 0; +static const unsigned char IM_U8_MAX = 0xFF; +static const signed short IM_S16_MIN = -32768; +static const signed short IM_S16_MAX = 32767; +static const unsigned short IM_U16_MIN = 0; +static const unsigned short IM_U16_MAX = 0xFFFF; +static const ImS32 IM_S32_MIN = INT_MIN; // (-2147483647 - 1), (0x80000000); +static const ImS32 IM_S32_MAX = INT_MAX; // (2147483647), (0x7FFFFFFF) +static const ImU32 IM_U32_MIN = 0; +static const ImU32 IM_U32_MAX = UINT_MAX; // (0xFFFFFFFF) +#ifdef LLONG_MIN +static const ImS64 IM_S64_MIN = LLONG_MIN; // (-9223372036854775807ll - 1ll); +static const ImS64 IM_S64_MAX = LLONG_MAX; // (9223372036854775807ll); +#else +static const ImS64 IM_S64_MIN = -9223372036854775807LL - 1; +static const ImS64 IM_S64_MAX = 9223372036854775807LL; +#endif +static const ImU64 IM_U64_MIN = 0; +#ifdef ULLONG_MAX +static const ImU64 IM_U64_MAX = ULLONG_MAX; // (0xFFFFFFFFFFFFFFFFull); +#else +static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); +#endif + +//------------------------------------------------------------------------- +// [SECTION] Forward Declarations +//------------------------------------------------------------------------- + +// Data Type helpers +static inline int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* data_ptr, const char* format); +static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg_1, const void* arg_2); +static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* format); + +// For InputTextEx() +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data); +static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); +static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Text, etc. +//------------------------------------------------------------------------- +// - TextUnformatted() +// - Text() +// - TextV() +// - TextColored() +// - TextColoredV() +// - TextDisabled() +// - TextDisabledV() +// - TextWrapped() +// - TextWrappedV() +// - LabelText() +// - LabelTextV() +// - BulletText() +// - BulletTextV() +//------------------------------------------------------------------------- + +void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + IM_ASSERT(text != NULL); + const char* text_begin = text; + if (text_end == NULL) + text_end = text + strlen(text); // FIXME-OPT + + const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrentLineTextBaseOffset); + const float wrap_pos_x = window->DC.TextWrapPos; + const bool wrap_enabled = (wrap_pos_x >= 0.0f); + if (text_end - text > 2000 && !wrap_enabled) + { + // Long text! + // Perform manual coarse clipping to optimize for long multi-line text + // - From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled. + // - We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line. + // - We use memchr(), pay attention that well optimized versions of those str/mem functions are much faster than a casually written loop. + const char* line = text; + const float line_height = GetTextLineHeight(); + ImVec2 text_size(0,0); + + // Lines to skip (can't skip when logging text) + ImVec2 pos = text_pos; + if (!g.LogEnabled) + { + int lines_skippable = (int)((window->ClipRect.Min.y - text_pos.y) / line_height); + if (lines_skippable > 0) + { + int lines_skipped = 0; + while (line < text_end && lines_skipped < lines_skippable) + { + const char* line_end = (const char*)memchr(line, '\n', text_end - line); + if (!line_end) + line_end = text_end; + if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0) + text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); + line = line_end + 1; + lines_skipped++; + } + pos.y += lines_skipped * line_height; + } + } + + // Lines to render + if (line < text_end) + { + ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height)); + while (line < text_end) + { + if (IsClippedEx(line_rect, 0, false)) + break; + + const char* line_end = (const char*)memchr(line, '\n', text_end - line); + if (!line_end) + line_end = text_end; + text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); + RenderText(pos, line, line_end, false); + line = line_end + 1; + line_rect.Min.y += line_height; + line_rect.Max.y += line_height; + pos.y += line_height; + } + + // Count remaining lines + int lines_skipped = 0; + while (line < text_end) + { + const char* line_end = (const char*)memchr(line, '\n', text_end - line); + if (!line_end) + line_end = text_end; + if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0) + text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); + line = line_end + 1; + lines_skipped++; + } + pos.y += lines_skipped * line_height; + } + text_size.y = (pos - text_pos).y; + + ImRect bb(text_pos, text_pos + text_size); + ItemSize(text_size); + ItemAdd(bb, 0); + } + else + { + const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f; + const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width); + + ImRect bb(text_pos, text_pos + text_size); + ItemSize(text_size); + if (!ItemAdd(bb, 0)) + return; + + // Render (we don't hide text after ## in this end-user function) + RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width); + } +} + +void ImGui::TextUnformatted(const char* text, const char* text_end) +{ + TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); +} + +void ImGui::Text(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextV(fmt, args); + va_end(args); +} + +void ImGui::TextV(const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + TextEx(g.TempBuffer, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); +} + +void ImGui::TextColored(const ImVec4& col, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextColoredV(col, fmt, args); + va_end(args); +} + +void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args) +{ + PushStyleColor(ImGuiCol_Text, col); + TextV(fmt, args); + PopStyleColor(); +} + +void ImGui::TextDisabled(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextDisabledV(fmt, args); + va_end(args); +} + +void ImGui::TextDisabledV(const char* fmt, va_list args) +{ + PushStyleColor(ImGuiCol_Text, GImGui->Style.Colors[ImGuiCol_TextDisabled]); + TextV(fmt, args); + PopStyleColor(); +} + +void ImGui::TextWrapped(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextWrappedV(fmt, args); + va_end(args); +} + +void ImGui::TextWrappedV(const char* fmt, va_list args) +{ + bool need_backup = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set + if (need_backup) + PushTextWrapPos(0.0f); + TextV(fmt, args); + if (need_backup) + PopTextWrapPos(); +} + +void ImGui::LabelText(const char* label, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + LabelTextV(label, fmt, args); + va_end(args); +} + +// Add a label+text combo aligned to other label+value widgets +void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const float w = CalcItemWidth(); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2)); + const ImRect total_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), style.FramePadding.y*2) + label_size); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, 0)) + return; + + // Render + const char* value_text_begin = &g.TempBuffer[0]; + const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImVec2(0.0f,0.5f)); + if (label_size.x > 0.0f) + RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label); +} + +void ImGui::BulletText(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + BulletTextV(fmt, args); + va_end(args); +} + +// Text with a little bullet aligned to the typical tree node. +void ImGui::BulletTextV(const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + const char* text_begin = g.TempBuffer; + const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + const ImVec2 label_size = CalcTextSize(text_begin, text_end, false); + const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it + const float line_height = ImMax(ImMin(window->DC.CurrentLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding + ItemSize(bb); + if (!ItemAdd(bb, 0)) + return; + + // Render + RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f)); + RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end, false); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Main +//------------------------------------------------------------------------- +// - ButtonBehavior() [Internal] +// - Button() +// - SmallButton() +// - InvisibleButton() +// - ArrowButton() +// - CloseButton() [Internal] +// - CollapseButton() [Internal] +// - Scrollbar() [Internal] +// - Image() +// - ImageButton() +// - Checkbox() +// - CheckboxFlags() +// - RadioButton() +// - ProgressBar() +// - Bullet() +//------------------------------------------------------------------------- + +bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + if (flags & ImGuiButtonFlags_Disabled) + { + if (out_hovered) *out_hovered = false; + if (out_held) *out_held = false; + if (g.ActiveId == id) ClearActiveID(); + return false; + } + + // Default behavior requires click+release on same spot + if ((flags & (ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick)) == 0) + flags |= ImGuiButtonFlags_PressedOnClickRelease; + + ImGuiWindow* backup_hovered_window = g.HoveredWindow; + if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window) + g.HoveredWindow = window; + +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (id != 0 && window->DC.LastItemId != id) + ImGuiTestEngineHook_ItemAdd(&g, bb, id); +#endif + + bool pressed = false; + bool hovered = ItemHoverable(bb, id); + + // Drag source doesn't report as hovered + if (hovered && g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover)) + hovered = false; + + // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button + if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) + if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + { + hovered = true; + SetHoveredID(id); + if (CalcTypematicPressedRepeatAmount(g.HoveredIdTimer + 0.0001f, g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, 0.01f, 0.70f)) // FIXME: Our formula for CalcTypematicPressedRepeatAmount() is fishy + { + pressed = true; + FocusWindow(window); + } + } + + if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window) + g.HoveredWindow = backup_hovered_window; + + // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. + if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0)) + hovered = false; + + // Mouse + if (hovered) + { + if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) + { + // | CLICKING | HOLDING with ImGuiButtonFlags_Repeat + // PressedOnClickRelease | * | .. (NOT on release) <-- MOST COMMON! (*) only if both click/release were over bounds + // PressedOnClick | | .. + // PressedOnRelease | | .. (NOT on release) + // PressedOnDoubleClick | | .. + // FIXME-NAV: We don't honor those different behaviors. + if ((flags & ImGuiButtonFlags_PressedOnClickRelease) && g.IO.MouseClicked[0]) + { + SetActiveID(id, window); + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + FocusWindow(window); + } + if (((flags & ImGuiButtonFlags_PressedOnClick) && g.IO.MouseClicked[0]) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDoubleClicked[0])) + { + pressed = true; + if (flags & ImGuiButtonFlags_NoHoldingActiveID) + ClearActiveID(); + else + SetActiveID(id, window); // Hold on ID + FocusWindow(window); + } + if ((flags & ImGuiButtonFlags_PressedOnRelease) && g.IO.MouseReleased[0]) + { + if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps + pressed = true; + ClearActiveID(); + } + + // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). + // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. + if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && g.IO.MouseDownDuration[0] > 0.0f && IsMouseClicked(0, true)) + pressed = true; + } + + if (pressed) + g.NavDisableHighlight = true; + } + + // Gamepad/Keyboard navigation + // We report navigated item as hovered but we don't set g.HoveredId to not interfere with mouse. + if (g.NavId == id && !g.NavDisableHighlight && g.NavDisableMouseHover && (g.ActiveId == 0 || g.ActiveId == id || g.ActiveId == window->MoveId)) + hovered = true; + + if (g.NavActivateDownId == id) + { + bool nav_activated_by_code = (g.NavActivateId == id); + bool nav_activated_by_inputs = IsNavInputPressed(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed); + if (nav_activated_by_code || nav_activated_by_inputs) + pressed = true; + if (nav_activated_by_code || nav_activated_by_inputs || g.ActiveId == id) + { + // Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button. + g.NavActivateId = id; // This is so SetActiveId assign a Nav source + SetActiveID(id, window); + if ((nav_activated_by_code || nav_activated_by_inputs) && !(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right) | (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + } + } + + bool held = false; + if (g.ActiveId == id) + { + if (pressed) + g.ActiveIdHasBeenPressed = true; + if (g.ActiveIdSource == ImGuiInputSource_Mouse) + { + if (g.ActiveIdIsJustActivated) + g.ActiveIdClickOffset = g.IO.MousePos - bb.Min; + if (g.IO.MouseDown[0]) + { + held = true; + } + else + { + if (hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease)) + if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps + if (!g.DragDropActive) + pressed = true; + ClearActiveID(); + } + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + g.NavDisableHighlight = true; + } + else if (g.ActiveIdSource == ImGuiInputSource_Nav) + { + if (g.NavActivateDownId != id) + ClearActiveID(); + } + } + + if (out_hovered) *out_hovered = hovered; + if (out_held) *out_held = held; + + return pressed; +} + +bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + ImVec2 pos = window->DC.CursorPos; + if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag) + pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y; + ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f); + + const ImRect bb(pos, pos + size); + ItemSize(size, style.FramePadding.y); + if (!ItemAdd(bb, id)) + return false; + + if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) + flags |= ImGuiButtonFlags_Repeat; + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + if (pressed) + MarkItemEdited(id); + + // Render + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); + RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); + + // Automatically close popups + //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) + // CloseCurrentPopup(); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); + return pressed; +} + +bool ImGui::Button(const char* label, const ImVec2& size_arg) +{ + return ButtonEx(label, size_arg, 0); +} + +// Small buttons fits within text without additional vertical spacing. +bool ImGui::SmallButton(const char* label) +{ + ImGuiContext& g = *GImGui; + float backup_padding_y = g.Style.FramePadding.y; + g.Style.FramePadding.y = 0.0f; + bool pressed = ButtonEx(label, ImVec2(0, 0), ImGuiButtonFlags_AlignTextBaseLine); + g.Style.FramePadding.y = backup_padding_y; + return pressed; +} + +// Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack. +// Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id) +bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + // Cannot use zero-size for InvisibleButton(). Unlike Button() there is not way to fallback using the label size. + IM_ASSERT(size_arg.x != 0.0f && size_arg.y != 0.0f); + + const ImGuiID id = window->GetID(str_id); + ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(size); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + + return pressed; +} + +bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiButtonFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiID id = window->GetID(str_id); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + const float default_size = GetFrameHeight(); + ItemSize(bb, (size.y >= default_size) ? g.Style.FramePadding.y : 0.0f); + if (!ItemAdd(bb, id)) + return false; + + if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) + flags |= ImGuiButtonFlags_Repeat; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + + // Render + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, col, true, g.Style.FrameRounding); + RenderArrow(bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), dir); + + return pressed; +} + +bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir) +{ + float sz = GetFrameHeight(); + return ArrowButtonEx(str_id, dir, ImVec2(sz, sz), 0); +} + +// Button to close a window +bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // We intentionally allow interaction when clipped so that a mechanical Alt,Right,Validate sequence close a window. + // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible). + const ImRect bb(pos - ImVec2(radius,radius), pos + ImVec2(radius,radius)); + bool is_clipped = !ItemAdd(bb, id); + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + if (is_clipped) + return pressed; + + // Render + ImVec2 center = bb.GetCenter(); + if (hovered) + window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9); + + float cross_extent = (radius * 0.7071f) - 1.0f; + ImU32 cross_col = GetColorU32(ImGuiCol_Text); + center -= ImVec2(0.5f, 0.5f); + window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), cross_col, 1.0f); + window->DrawList->AddLine(center + ImVec2(+cross_extent,-cross_extent), center + ImVec2(-cross_extent,+cross_extent), cross_col, 1.0f); + + return pressed; +} + +bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); + ItemAdd(bb, id); + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None); + + ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + if (hovered || held) + window->DrawList->AddCircleFilled(bb.GetCenter() + ImVec2(0.0f, -0.5f), g.FontSize * 0.5f + 1.0f, col, 9); + RenderArrow(bb.Min + g.Style.FramePadding, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); + + // Switch to moving the window after mouse is moved beyond the initial drag threshold + if (IsItemActive() && IsMouseDragging()) + StartMouseMovingWindow(window); + + return pressed; +} + +ImGuiID ImGui::GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis) +{ + return window->GetIDNoKeepAlive(axis == ImGuiAxis_X ? "#SCROLLX" : "#SCROLLY"); +} + +// Vertical/Horizontal scrollbar +// The entire piece of code below is rather confusing because: +// - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab) +// - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar +// - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal. +void ImGui::Scrollbar(ImGuiAxis axis) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const bool horizontal = (axis == ImGuiAxis_X); + const ImGuiStyle& style = g.Style; + const ImGuiID id = GetScrollbarID(window, axis); + KeepAliveID(id); + + // Render background + bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX); + float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f; + const ImRect window_rect = window->Rect(); + const float border_size = window->WindowBorderSize; + ImRect bb = horizontal + ? ImRect(window->Pos.x + border_size, window_rect.Max.y - style.ScrollbarSize, window_rect.Max.x - other_scrollbar_size_w - border_size, window_rect.Max.y - border_size) + : ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size); + if (!horizontal) + bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f); + + const float bb_height = bb.GetHeight(); + if (bb.GetWidth() <= 0.0f || bb_height <= 0.0f) + return; + + // When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the resize grab) + float alpha = 1.0f; + if ((axis == ImGuiAxis_Y) && bb_height < g.FontSize + g.Style.FramePadding.y * 2.0f) + { + alpha = ImSaturate((bb_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f)); + if (alpha <= 0.0f) + return; + } + const bool allow_interaction = (alpha >= 1.0f); + + int window_rounding_corners; + if (horizontal) + window_rounding_corners = ImDrawCornerFlags_BotLeft | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight); + else + window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0) | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight); + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_ScrollbarBg), window->WindowRounding, window_rounding_corners); + bb.Expand(ImVec2(-ImClamp((float)(int)((bb.Max.x - bb.Min.x - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp((float)(int)((bb.Max.y - bb.Min.y - 2.0f) * 0.5f), 0.0f, 3.0f))); + + // V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar) + float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight(); + float scroll_v = horizontal ? window->Scroll.x : window->Scroll.y; + float win_size_avail_v = (horizontal ? window->SizeFull.x : window->SizeFull.y) - other_scrollbar_size_w; + float win_size_contents_v = horizontal ? window->SizeContents.x : window->SizeContents.y; + + // Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount) + // But we maintain a minimum size in pixel to allow for the user to still aim inside. + IM_ASSERT(ImMax(win_size_contents_v, win_size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers. + const float win_size_v = ImMax(ImMax(win_size_contents_v, win_size_avail_v), 1.0f); + const float grab_h_pixels = ImClamp(scrollbar_size_v * (win_size_avail_v / win_size_v), style.GrabMinSize, scrollbar_size_v); + const float grab_h_norm = grab_h_pixels / scrollbar_size_v; + + // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar(). + bool held = false; + bool hovered = false; + const bool previously_held = (g.ActiveId == id); + ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus); + + float scroll_max = ImMax(1.0f, win_size_contents_v - win_size_avail_v); + float scroll_ratio = ImSaturate(scroll_v / scroll_max); + float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; + if (held && allow_interaction && grab_h_norm < 1.0f) + { + float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y; + float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y; + float* click_delta_to_grab_center_v = horizontal ? &g.ScrollbarClickDeltaToGrabCenter.x : &g.ScrollbarClickDeltaToGrabCenter.y; + + // Click position in scrollbar normalized space (0.0f->1.0f) + const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v); + SetHoveredID(id); + + bool seek_absolute = false; + if (!previously_held) + { + // On initial click calculate the distance between mouse and the center of the grab + if (clicked_v_norm >= grab_v_norm && clicked_v_norm <= grab_v_norm + grab_h_norm) + { + *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f; + } + else + { + seek_absolute = true; + *click_delta_to_grab_center_v = 0.0f; + } + } + + // Apply scroll + // It is ok to modify Scroll here because we are being called in Begin() after the calculation of SizeContents and before setting up our starting position + const float scroll_v_norm = ImSaturate((clicked_v_norm - *click_delta_to_grab_center_v - grab_h_norm*0.5f) / (1.0f - grab_h_norm)); + scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v)); + if (horizontal) + window->Scroll.x = scroll_v; + else + window->Scroll.y = scroll_v; + + // Update values for rendering + scroll_ratio = ImSaturate(scroll_v / scroll_max); + grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; + + // Update distance to grab now that we have seeked and saturated + if (seek_absolute) + *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f; + } + + // Render grab + const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha); + ImRect grab_rect; + if (horizontal) + grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImMin(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, window_rect.Max.x), bb.Max.y); + else + grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImMin(ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels, window_rect.Max.y)); + window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding); +} + +void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + if (border_col.w > 0.0f) + bb.Max += ImVec2(2, 2); + ItemSize(bb); + if (!ItemAdd(bb, 0)) + return; + + if (border_col.w > 0.0f) + { + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f); + window->DrawList->AddImage(user_texture_id, bb.Min + ImVec2(1, 1), bb.Max - ImVec2(1, 1), uv0, uv1, GetColorU32(tint_col)); + } + else + { + window->DrawList->AddImage(user_texture_id, bb.Min, bb.Max, uv0, uv1, GetColorU32(tint_col)); + } +} + +// frame_padding < 0: uses FramePadding from style (default) +// frame_padding = 0: no framing +// frame_padding > 0: set framing size +// The color used are the button colors. +bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + // Default to using texture ID as ID. User can still push string/integer prefixes. + // We could hash the size/uv to create a unique ID but that would prevent the user from animating UV. + PushID((void*)(intptr_t)user_texture_id); + const ImGuiID id = window->GetID("#image"); + PopID(); + + const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding; + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2); + const ImRect image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size); + ItemSize(bb); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + + // Render + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, style.FrameRounding)); + if (bg_col.w > 0.0f) + window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, GetColorU32(bg_col)); + window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1, GetColorU32(tint_col)); + + return pressed; +} + +bool ImGui::Checkbox(const char* label, bool* v) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + const float square_sz = GetFrameHeight(); + const ImVec2 pos = window->DC.CursorPos; + const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); + if (pressed) + { + *v = !(*v); + MarkItemEdited(id); + } + + const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); + RenderNavHighlight(total_bb, id); + RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); + if (*v) + { + const float pad = ImMax(1.0f, (float)(int)(square_sz / 6.0f)); + RenderCheckMark(check_bb.Min + ImVec2(pad, pad), GetColorU32(ImGuiCol_CheckMark), square_sz - pad*2.0f); + } + + if (g.LogEnabled) + LogRenderedText(&total_bb.Min, *v ? "[x]" : "[ ]"); + if (label_size.x > 0.0f) + RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + return pressed; +} + +bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value) +{ + bool v = ((*flags & flags_value) == flags_value); + bool pressed = Checkbox(label, &v); + if (pressed) + { + if (v) + *flags |= flags_value; + else + *flags &= ~flags_value; + } + + return pressed; +} + +bool ImGui::RadioButton(const char* label, bool active) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + const float square_sz = GetFrameHeight(); + const ImVec2 pos = window->DC.CursorPos; + const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); + const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id)) + return false; + + ImVec2 center = check_bb.GetCenter(); + center.x = (float)(int)center.x + 0.5f; + center.y = (float)(int)center.y + 0.5f; + const float radius = (square_sz - 1.0f) * 0.5f; + + bool hovered, held; + bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); + if (pressed) + MarkItemEdited(id); + + RenderNavHighlight(total_bb, id); + window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16); + if (active) + { + const float pad = ImMax(1.0f, (float)(int)(square_sz / 6.0f)); + window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark), 16); + } + + if (style.FrameBorderSize > 0.0f) + { + window->DrawList->AddCircle(center + ImVec2(1,1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize); + window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize); + } + + if (g.LogEnabled) + LogRenderedText(&total_bb.Min, active ? "(x)" : "( )"); + if (label_size.x > 0.0f) + RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label); + + return pressed; +} + +bool ImGui::RadioButton(const char* label, int* v, int v_button) +{ + const bool pressed = RadioButton(label, *v == v_button); + if (pressed) + *v = v_button; + return pressed; +} + +// size_arg (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size +void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* overlay) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + ImVec2 pos = window->DC.CursorPos; + ImRect bb(pos, pos + CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y*2.0f)); + ItemSize(bb, style.FramePadding.y); + if (!ItemAdd(bb, 0)) + return; + + // Render + fraction = ImSaturate(fraction); + RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize)); + const ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y); + RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), 0.0f, fraction, style.FrameRounding); + + // Default displaying the fraction as percentage string, but user can override it + char overlay_buf[32]; + if (!overlay) + { + ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction*100+0.01f); + overlay = overlay_buf; + } + + ImVec2 overlay_size = CalcTextSize(overlay, NULL); + if (overlay_size.x > 0.0f) + RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f,0.5f), &bb); +} + +void ImGui::Bullet() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const float line_height = ImMax(ImMin(window->DC.CurrentLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height)); + ItemSize(bb); + if (!ItemAdd(bb, 0)) + { + SameLine(0, style.FramePadding.x*2); + return; + } + + // Render and stay on same line + RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f)); + SameLine(0, style.FramePadding.x*2); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Low-level Layout helpers +//------------------------------------------------------------------------- +// - Spacing() +// - Dummy() +// - NewLine() +// - AlignTextToFramePadding() +// - Separator() +// - VerticalSeparator() [Internal] +// - SplitterBehavior() [Internal] +//------------------------------------------------------------------------- + +void ImGui::Spacing() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ItemSize(ImVec2(0,0)); +} + +void ImGui::Dummy(const ImVec2& size) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(bb); + ItemAdd(bb, 0); +} + +void ImGui::NewLine() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiLayoutType backup_layout_type = window->DC.LayoutType; + window->DC.LayoutType = ImGuiLayoutType_Vertical; + if (window->DC.CurrentLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height. + ItemSize(ImVec2(0,0)); + else + ItemSize(ImVec2(0.0f, g.FontSize)); + window->DC.LayoutType = backup_layout_type; +} + +void ImGui::AlignTextToFramePadding() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + window->DC.CurrentLineSize.y = ImMax(window->DC.CurrentLineSize.y, g.FontSize + g.Style.FramePadding.y * 2); + window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, g.Style.FramePadding.y); +} + +// Horizontal/vertical separating line +void ImGui::Separator() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ImGuiContext& g = *GImGui; + + // Those flags should eventually be overridable by the user + ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; + IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected + if (flags & ImGuiSeparatorFlags_Vertical) + { + VerticalSeparator(); + return; + } + + // Horizontal Separator + if (window->DC.ColumnsSet) + PopClipRect(); + + float x1 = window->Pos.x; + float x2 = window->Pos.x + window->Size.x; + if (!window->DC.GroupStack.empty()) + x1 += window->DC.Indent.x; + + const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y+1.0f)); + ItemSize(ImVec2(0.0f, 0.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit, we don't provide height to not alter layout. + if (!ItemAdd(bb, 0)) + { + if (window->DC.ColumnsSet) + PushColumnClipRect(); + return; + } + + window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x,bb.Min.y), GetColorU32(ImGuiCol_Separator)); + + if (g.LogEnabled) + LogRenderedText(&bb.Min, "--------------------------------"); + + if (window->DC.ColumnsSet) + { + PushColumnClipRect(); + window->DC.ColumnsSet->LineMinY = window->DC.CursorPos.y; + } +} + +void ImGui::VerticalSeparator() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ImGuiContext& g = *GImGui; + + float y1 = window->DC.CursorPos.y; + float y2 = window->DC.CursorPos.y + window->DC.CurrentLineSize.y; + const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + 1.0f, y2)); + ItemSize(ImVec2(bb.GetWidth(), 0.0f)); + if (!ItemAdd(bb, 0)) + return; + + window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator)); + if (g.LogEnabled) + LogText(" |"); +} + +// Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise. +bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend, float hover_visibility_delay) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; + window->DC.ItemFlags |= ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus; + bool item_add = ItemAdd(bb, id); + window->DC.ItemFlags = item_flags_backup; + if (!item_add) + return false; + + bool hovered, held; + ImRect bb_interact = bb; + bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f)); + ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap); + if (g.ActiveId != id) + SetItemAllowOverlap(); + + if (held || (g.HoveredId == id && g.HoveredIdPreviousFrame == id && g.HoveredIdTimer >= hover_visibility_delay)) + SetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW); + + ImRect bb_render = bb; + if (held) + { + ImVec2 mouse_delta_2d = g.IO.MousePos - g.ActiveIdClickOffset - bb_interact.Min; + float mouse_delta = (axis == ImGuiAxis_Y) ? mouse_delta_2d.y : mouse_delta_2d.x; + + // Minimum pane size + float size_1_maximum_delta = ImMax(0.0f, *size1 - min_size1); + float size_2_maximum_delta = ImMax(0.0f, *size2 - min_size2); + if (mouse_delta < -size_1_maximum_delta) + mouse_delta = -size_1_maximum_delta; + if (mouse_delta > size_2_maximum_delta) + mouse_delta = size_2_maximum_delta; + + // Apply resize + if (mouse_delta != 0.0f) + { + if (mouse_delta < 0.0f) + IM_ASSERT(*size1 + mouse_delta >= min_size1); + if (mouse_delta > 0.0f) + IM_ASSERT(*size2 - mouse_delta >= min_size2); + *size1 += mouse_delta; + *size2 -= mouse_delta; + bb_render.Translate((axis == ImGuiAxis_X) ? ImVec2(mouse_delta, 0.0f) : ImVec2(0.0f, mouse_delta)); + MarkItemEdited(id); + } + } + + // Render + const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : (hovered && g.HoveredIdTimer >= hover_visibility_delay) ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); + window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, g.Style.FrameRounding); + + return held; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: ComboBox +//------------------------------------------------------------------------- +// - BeginCombo() +// - EndCombo() +// - Combo() +//------------------------------------------------------------------------- + +static float CalcMaxPopupHeightFromItemCount(int items_count) +{ + ImGuiContext& g = *GImGui; + if (items_count <= 0) + return FLT_MAX; + return (g.FontSize + g.Style.ItemSpacing.y) * items_count - g.Style.ItemSpacing.y + (g.Style.WindowPadding.y * 2); +} + +bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags) +{ + // Always consume the SetNextWindowSizeConstraint() call in our early return paths + ImGuiContext& g = *GImGui; + ImGuiCond backup_next_window_size_constraint = g.NextWindowData.SizeConstraintCond; + g.NextWindowData.SizeConstraintCond = 0; + + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together + + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + + const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : CalcItemWidth(); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(frame_bb, id, &hovered, &held); + bool popup_open = IsPopupOpen(id); + + const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f)); + const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + if (!(flags & ImGuiComboFlags_NoPreview)) + window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(frame_bb.Max.x - arrow_size, frame_bb.Max.y), frame_col, style.FrameRounding, ImDrawCornerFlags_Left); + if (!(flags & ImGuiComboFlags_NoArrowButton)) + { + window->DrawList->AddRectFilled(ImVec2(frame_bb.Max.x - arrow_size, frame_bb.Min.y), frame_bb.Max, GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button), style.FrameRounding, (w <= arrow_size) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Right); + RenderArrow(ImVec2(frame_bb.Max.x - arrow_size + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), ImGuiDir_Down); + } + RenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding); + if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview)) + RenderTextClipped(frame_bb.Min + style.FramePadding, value_bb.Max, preview_value, NULL, NULL, ImVec2(0.0f,0.0f)); + if (label_size.x > 0) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + if ((pressed || g.NavActivateId == id) && !popup_open) + { + if (window->DC.NavLayerCurrent == 0) + window->NavLastIds[0] = id; + OpenPopupEx(id); + popup_open = true; + } + + if (!popup_open) + return false; + + if (backup_next_window_size_constraint) + { + g.NextWindowData.SizeConstraintCond = backup_next_window_size_constraint; + g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w); + } + else + { + if ((flags & ImGuiComboFlags_HeightMask_) == 0) + flags |= ImGuiComboFlags_HeightRegular; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_)); // Only one + int popup_max_height_in_items = -1; + if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8; + else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4; + else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20; + SetNextWindowSizeConstraints(ImVec2(w, 0.0f), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); + } + + char name[16]; + ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth + + // Peak into expected window size so we can position it + if (ImGuiWindow* popup_window = FindWindowByName(name)) + if (popup_window->WasActive) + { + ImVec2 size_expected = CalcWindowExpectedSize(popup_window); + if (flags & ImGuiComboFlags_PopupAlignLeft) + popup_window->AutoPosLastDirection = ImGuiDir_Left; + ImRect r_outer = GetWindowAllowedExtentRect(popup_window); + ImVec2 pos = FindBestWindowPosForPopupEx(frame_bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, frame_bb, ImGuiPopupPositionPolicy_ComboBox); + SetNextWindowPos(pos); + } + + // Horizontally align ourselves with the framed text + ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings; + PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(style.FramePadding.x, style.WindowPadding.y)); + bool ret = Begin(name, NULL, window_flags); + PopStyleVar(); + if (!ret) + { + EndPopup(); + IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above + return false; + } + return true; +} + +void ImGui::EndCombo() +{ + EndPopup(); +} + +// Getter for the old Combo() API: const char*[] +static bool Items_ArrayGetter(void* data, int idx, const char** out_text) +{ + const char* const* items = (const char* const*)data; + if (out_text) + *out_text = items[idx]; + return true; +} + +// Getter for the old Combo() API: "item1\0item2\0item3\0" +static bool Items_SingleStringGetter(void* data, int idx, const char** out_text) +{ + // FIXME-OPT: we could pre-compute the indices to fasten this. But only 1 active combo means the waste is limited. + const char* items_separated_by_zeros = (const char*)data; + int items_count = 0; + const char* p = items_separated_by_zeros; + while (*p) + { + if (idx == items_count) + break; + p += strlen(p) + 1; + items_count++; + } + if (!*p) + return false; + if (out_text) + *out_text = p; + return true; +} + +// Old API, prefer using BeginCombo() nowadays if you can. +bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int popup_max_height_in_items) +{ + ImGuiContext& g = *GImGui; + + // Call the getter to obtain the preview string which is a parameter to BeginCombo() + const char* preview_value = NULL; + if (*current_item >= 0 && *current_item < items_count) + items_getter(data, *current_item, &preview_value); + + // The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here. + if (popup_max_height_in_items != -1 && !g.NextWindowData.SizeConstraintCond) + SetNextWindowSizeConstraints(ImVec2(0,0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); + + if (!BeginCombo(label, preview_value, ImGuiComboFlags_None)) + return false; + + // Display items + // FIXME-OPT: Use clipper (but we need to disable it on the appearing frame to make sure our call to SetItemDefaultFocus() is processed) + bool value_changed = false; + for (int i = 0; i < items_count; i++) + { + PushID((void*)(intptr_t)i); + const bool item_selected = (i == *current_item); + const char* item_text; + if (!items_getter(data, i, &item_text)) + item_text = "*Unknown item*"; + if (Selectable(item_text, item_selected)) + { + value_changed = true; + *current_item = i; + } + if (item_selected) + SetItemDefaultFocus(); + PopID(); + } + + EndCombo(); + return value_changed; +} + +// Combo box helper allowing to pass an array of strings. +bool ImGui::Combo(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items) +{ + const bool value_changed = Combo(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_in_items); + return value_changed; +} + +// Combo box helper allowing to pass all items in a single string literal holding multiple zero-terminated items "item1\0item2\0" +bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items) +{ + int items_count = 0; + const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open + while (*p) + { + p += strlen(p) + 1; + items_count++; + } + bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items); + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Data Type and Data Formatting Helpers [Internal] +//------------------------------------------------------------------------- +// - PatchFormatStringFloatToInt() +// - DataTypeFormatString() +// - DataTypeApplyOp() +// - DataTypeApplyOpFromText() +// - GetMinimumStepAtDecimalPrecision +// - RoundScalarWithFormat<>() +//------------------------------------------------------------------------- + +struct ImGuiDataTypeInfo +{ + size_t Size; + const char* PrintFmt; // Unused + const char* ScanFmt; +}; + +static const ImGuiDataTypeInfo GDataTypeInfo[] = +{ + { sizeof(char), "%d", "%d" }, // ImGuiDataType_S8 + { sizeof(unsigned char), "%u", "%u" }, + { sizeof(short), "%d", "%d" }, // ImGuiDataType_S16 + { sizeof(unsigned short), "%u", "%u" }, + { sizeof(int), "%d", "%d" }, // ImGuiDataType_S32 + { sizeof(unsigned int), "%u", "%u" }, +#ifdef _MSC_VER + { sizeof(ImS64), "%I64d","%I64d" }, // ImGuiDataType_S64 + { sizeof(ImU64), "%I64u","%I64u" }, +#else + { sizeof(ImS64), "%lld", "%lld" }, // ImGuiDataType_S64 + { sizeof(ImU64), "%llu", "%llu" }, +#endif + { sizeof(float), "%f", "%f" }, // ImGuiDataType_Float (float are promoted to double in va_arg) + { sizeof(double), "%f", "%lf" }, // ImGuiDataType_Double +}; +IM_STATIC_ASSERT(IM_ARRAYSIZE(GDataTypeInfo) == ImGuiDataType_COUNT); + +// FIXME-LEGACY: Prior to 1.61 our DragInt() function internally used floats and because of this the compile-time default value for format was "%.0f". +// Even though we changed the compile-time default, we expect users to have carried %f around, which would break the display of DragInt() calls. +// To honor backward compatibility we are rewriting the format string, unless IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. What could possibly go wrong?! +static const char* PatchFormatStringFloatToInt(const char* fmt) +{ + if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '0' && fmt[3] == 'f' && fmt[4] == 0) // Fast legacy path for "%.0f" which is expected to be the most common case. + return "%d"; + const char* fmt_start = ImParseFormatFindStart(fmt); // Find % (if any, and ignore %%) + const char* fmt_end = ImParseFormatFindEnd(fmt_start); // Find end of format specifier, which itself is an exercise of confidence/recklessness (because snprintf is dependent on libc or user). + if (fmt_end > fmt_start && fmt_end[-1] == 'f') + { +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (fmt_start == fmt && fmt_end[0] == 0) + return "%d"; + ImGuiContext& g = *GImGui; + ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); // Honor leading and trailing decorations, but lose alignment/precision. + return g.TempBuffer; +#else + IM_ASSERT(0 && "DragInt(): Invalid format string!"); // Old versions used a default parameter of "%.0f", please replace with e.g. "%d" +#endif + } + return fmt; +} + +static inline int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* data_ptr, const char* format) +{ + // Signedness doesn't matter when pushing integer arguments + if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32) + return ImFormatString(buf, buf_size, format, *(const ImU32*)data_ptr); + if (data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) + return ImFormatString(buf, buf_size, format, *(const ImU64*)data_ptr); + if (data_type == ImGuiDataType_Float) + return ImFormatString(buf, buf_size, format, *(const float*)data_ptr); + if (data_type == ImGuiDataType_Double) + return ImFormatString(buf, buf_size, format, *(const double*)data_ptr); + if (data_type == ImGuiDataType_S8) + return ImFormatString(buf, buf_size, format, *(const ImS8*)data_ptr); + if (data_type == ImGuiDataType_U8) + return ImFormatString(buf, buf_size, format, *(const ImU8*)data_ptr); + if (data_type == ImGuiDataType_S16) + return ImFormatString(buf, buf_size, format, *(const ImS16*)data_ptr); + if (data_type == ImGuiDataType_U16) + return ImFormatString(buf, buf_size, format, *(const ImU16*)data_ptr); + IM_ASSERT(0); + return 0; +} + +static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg1, const void* arg2) +{ + IM_ASSERT(op == '+' || op == '-'); + switch (data_type) + { + case ImGuiDataType_S8: + if (op == '+') { *(ImS8*)output = ImAddClampOverflow(*(const ImS8*)arg1, *(const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); } + if (op == '-') { *(ImS8*)output = ImSubClampOverflow(*(const ImS8*)arg1, *(const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); } + return; + case ImGuiDataType_U8: + if (op == '+') { *(ImU8*)output = ImAddClampOverflow(*(const ImU8*)arg1, *(const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); } + if (op == '-') { *(ImU8*)output = ImSubClampOverflow(*(const ImU8*)arg1, *(const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); } + return; + case ImGuiDataType_S16: + if (op == '+') { *(ImS16*)output = ImAddClampOverflow(*(const ImS16*)arg1, *(const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); } + if (op == '-') { *(ImS16*)output = ImSubClampOverflow(*(const ImS16*)arg1, *(const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); } + return; + case ImGuiDataType_U16: + if (op == '+') { *(ImU16*)output = ImAddClampOverflow(*(const ImU16*)arg1, *(const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); } + if (op == '-') { *(ImU16*)output = ImSubClampOverflow(*(const ImU16*)arg1, *(const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); } + return; + case ImGuiDataType_S32: + if (op == '+') { *(ImS32*)output = ImAddClampOverflow(*(const ImS32*)arg1, *(const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); } + if (op == '-') { *(ImS32*)output = ImSubClampOverflow(*(const ImS32*)arg1, *(const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); } + return; + case ImGuiDataType_U32: + if (op == '+') { *(ImU32*)output = ImAddClampOverflow(*(const ImU32*)arg1, *(const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); } + if (op == '-') { *(ImU32*)output = ImSubClampOverflow(*(const ImU32*)arg1, *(const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); } + return; + case ImGuiDataType_S64: + if (op == '+') { *(ImS64*)output = ImAddClampOverflow(*(const ImS64*)arg1, *(const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); } + if (op == '-') { *(ImS64*)output = ImSubClampOverflow(*(const ImS64*)arg1, *(const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); } + return; + case ImGuiDataType_U64: + if (op == '+') { *(ImU64*)output = ImAddClampOverflow(*(const ImU64*)arg1, *(const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); } + if (op == '-') { *(ImU64*)output = ImSubClampOverflow(*(const ImU64*)arg1, *(const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); } + return; + case ImGuiDataType_Float: + if (op == '+') { *(float*)output = *(const float*)arg1 + *(const float*)arg2; } + if (op == '-') { *(float*)output = *(const float*)arg1 - *(const float*)arg2; } + return; + case ImGuiDataType_Double: + if (op == '+') { *(double*)output = *(const double*)arg1 + *(const double*)arg2; } + if (op == '-') { *(double*)output = *(const double*)arg1 - *(const double*)arg2; } + return; + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); +} + +// User can input math operators (e.g. +100) to edit a numerical values. +// NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess.. +static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* format) +{ + while (ImCharIsBlankA(*buf)) + buf++; + + // We don't support '-' op because it would conflict with inputing negative value. + // Instead you can use +-100 to subtract from an existing value + char op = buf[0]; + if (op == '+' || op == '*' || op == '/') + { + buf++; + while (ImCharIsBlankA(*buf)) + buf++; + } + else + { + op = 0; + } + if (!buf[0]) + return false; + + // Copy the value in an opaque buffer so we can compare at the end of the function if it changed at all. + IM_ASSERT(data_type < ImGuiDataType_COUNT); + int data_backup[2]; + IM_ASSERT(GDataTypeInfo[data_type].Size <= sizeof(data_backup)); + memcpy(data_backup, data_ptr, GDataTypeInfo[data_type].Size); + + if (format == NULL) + format = GDataTypeInfo[data_type].ScanFmt; + + // FIXME-LEGACY: The aim is to remove those operators and write a proper expression evaluator at some point.. + int arg1i = 0; + if (data_type == ImGuiDataType_S32) + { + int* v = (int*)data_ptr; + int arg0i = *v; + float arg1f = 0.0f; + if (op && sscanf(initial_value_buf, format, &arg0i) < 1) + return false; + // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision + if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (int)(arg0i + arg1i); } // Add (use "+-" to subtract) + else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (int)(arg0i * arg1f); } // Multiply + else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (int)(arg0i / arg1f); } // Divide + else { if (sscanf(buf, format, &arg1i) == 1) *v = arg1i; } // Assign constant + } + else if (data_type == ImGuiDataType_Float) + { + // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in + format = "%f"; + float* v = (float*)data_ptr; + float arg0f = *v, arg1f = 0.0f; + if (op && sscanf(initial_value_buf, format, &arg0f) < 1) + return false; + if (sscanf(buf, format, &arg1f) < 1) + return false; + if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) + else if (op == '*') { *v = arg0f * arg1f; } // Multiply + else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide + else { *v = arg1f; } // Assign constant + } + else if (data_type == ImGuiDataType_Double) + { + format = "%lf"; // scanf differentiate float/double unlike printf which forces everything to double because of ellipsis + double* v = (double*)data_ptr; + double arg0f = *v, arg1f = 0.0; + if (op && sscanf(initial_value_buf, format, &arg0f) < 1) + return false; + if (sscanf(buf, format, &arg1f) < 1) + return false; + if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) + else if (op == '*') { *v = arg0f * arg1f; } // Multiply + else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide + else { *v = arg1f; } // Assign constant + } + else if (data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) + { + // All other types assign constant + // We don't bother handling support for legacy operators since they are a little too crappy. Instead we will later implement a proper expression evaluator in the future. + sscanf(buf, format, data_ptr); + } + else + { + // Small types need a 32-bit buffer to receive the result from scanf() + int v32; + sscanf(buf, format, &v32); + if (data_type == ImGuiDataType_S8) + *(ImS8*)data_ptr = (ImS8)ImClamp(v32, (int)IM_S8_MIN, (int)IM_S8_MAX); + else if (data_type == ImGuiDataType_U8) + *(ImU8*)data_ptr = (ImU8)ImClamp(v32, (int)IM_U8_MIN, (int)IM_U8_MAX); + else if (data_type == ImGuiDataType_S16) + *(ImS16*)data_ptr = (ImS16)ImClamp(v32, (int)IM_S16_MIN, (int)IM_S16_MAX); + else if (data_type == ImGuiDataType_U16) + *(ImU16*)data_ptr = (ImU16)ImClamp(v32, (int)IM_U16_MIN, (int)IM_U16_MAX); + else + IM_ASSERT(0); + } + + return memcmp(data_backup, data_ptr, GDataTypeInfo[data_type].Size) != 0; +} + +static float GetMinimumStepAtDecimalPrecision(int decimal_precision) +{ + static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f }; + if (decimal_precision < 0) + return FLT_MIN; + return (decimal_precision < IM_ARRAYSIZE(min_steps)) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision); +} + +template +static const char* ImAtoi(const char* src, TYPE* output) +{ + int negative = 0; + if (*src == '-') { negative = 1; src++; } + if (*src == '+') { src++; } + TYPE v = 0; + while (*src >= '0' && *src <= '9') + v = (v * 10) + (*src++ - '0'); + *output = negative ? -v : v; + return src; +} + +template +TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, TYPE v) +{ + const char* fmt_start = ImParseFormatFindStart(format); + if (fmt_start[0] != '%' || fmt_start[1] == '%') // Don't apply if the value is not visible in the format string + return v; + char v_str[64]; + ImFormatString(v_str, IM_ARRAYSIZE(v_str), fmt_start, v); + const char* p = v_str; + while (*p == ' ') + p++; + if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) + v = (TYPE)ImAtof(p); + else + ImAtoi(p, (SIGNEDTYPE*)&v); + return v; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: DragScalar, DragFloat, DragInt, etc. +//------------------------------------------------------------------------- +// - DragBehaviorT<>() [Internal] +// - DragBehavior() [Internal] +// - DragScalar() +// - DragScalarN() +// - DragFloat() +// - DragFloat2() +// - DragFloat3() +// - DragFloat4() +// - DragFloatRange2() +// - DragInt() +// - DragInt2() +// - DragInt3() +// - DragInt4() +// - DragIntRange2() +//------------------------------------------------------------------------- + +// This is called by DragBehavior() when the widget is active (held by mouse or being manipulated with Nav controls) +template +bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiDragFlags flags) +{ + ImGuiContext& g = *GImGui; + const ImGuiAxis axis = (flags & ImGuiDragFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; + const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + const bool has_min_max = (v_min != v_max); + const bool is_power = (power != 1.0f && is_decimal && has_min_max && (v_max - v_min < FLT_MAX)); + + // Default tweak speed + if (v_speed == 0.0f && has_min_max && (v_max - v_min < FLT_MAX)) + v_speed = (float)((v_max - v_min) * g.DragSpeedDefaultRatio); + + // Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings + float adjust_delta = 0.0f; + if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && g.IO.MouseDragMaxDistanceSqr[0] > 1.0f*1.0f) + { + adjust_delta = g.IO.MouseDelta[axis]; + if (g.IO.KeyAlt) + adjust_delta *= 1.0f / 100.0f; + if (g.IO.KeyShift) + adjust_delta *= 10.0f; + } + else if (g.ActiveIdSource == ImGuiInputSource_Nav) + { + int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 0; + adjust_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 1.0f / 10.0f, 10.0f)[axis]; + v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)); + } + adjust_delta *= v_speed; + + // For vertical drag we currently assume that Up=higher value (like we do with vertical sliders). This may become a parameter. + if (axis == ImGuiAxis_Y) + adjust_delta = -adjust_delta; + + // Clear current value on activation + // Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300. + bool is_just_activated = g.ActiveIdIsJustActivated; + bool is_already_past_limits_and_pushing_outward = has_min_max && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f)); + bool is_drag_direction_change_with_power = is_power && ((adjust_delta < 0 && g.DragCurrentAccum > 0) || (adjust_delta > 0 && g.DragCurrentAccum < 0)); + if (is_just_activated || is_already_past_limits_and_pushing_outward || is_drag_direction_change_with_power) + { + g.DragCurrentAccum = 0.0f; + g.DragCurrentAccumDirty = false; + } + else if (adjust_delta != 0.0f) + { + g.DragCurrentAccum += adjust_delta; + g.DragCurrentAccumDirty = true; + } + + if (!g.DragCurrentAccumDirty) + return false; + + TYPE v_cur = *v; + FLOATTYPE v_old_ref_for_accum_remainder = (FLOATTYPE)0.0f; + + if (is_power) + { + // Offset + round to user desired precision, with a curve on the v_min..v_max range to get more precision on one side of the range + FLOATTYPE v_old_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); + FLOATTYPE v_new_norm_curved = v_old_norm_curved + (g.DragCurrentAccum / (v_max - v_min)); + v_cur = v_min + (TYPE)ImPow(ImSaturate((float)v_new_norm_curved), power) * (v_max - v_min); + v_old_ref_for_accum_remainder = v_old_norm_curved; + } + else + { + v_cur += (TYPE)g.DragCurrentAccum; + } + + // Round to user desired precision based on format string + v_cur = RoundScalarWithFormatT(format, data_type, v_cur); + + // Preserve remainder after rounding has been applied. This also allow slow tweaking of values. + g.DragCurrentAccumDirty = false; + if (is_power) + { + FLOATTYPE v_cur_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); + g.DragCurrentAccum -= (float)(v_cur_norm_curved - v_old_ref_for_accum_remainder); + } + else + { + g.DragCurrentAccum -= (float)((SIGNEDTYPE)v_cur - (SIGNEDTYPE)*v); + } + + // Lose zero sign for float/double + if (v_cur == (TYPE)-0) + v_cur = (TYPE)0; + + // Clamp values (+ handle overflow/wrap-around for integer types) + if (*v != v_cur && has_min_max) + { + if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_decimal)) + v_cur = v_min; + if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_decimal)) + v_cur = v_max; + } + + // Apply result + if (*v == v_cur) + return false; + *v = v_cur; + return true; +} + +bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power, ImGuiDragFlags flags) +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId == id) + { + if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0]) + ClearActiveID(); + else if (g.ActiveIdSource == ImGuiInputSource_Nav && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + ClearActiveID(); + } + if (g.ActiveId != id) + return false; + + switch (data_type) + { + case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, v_min ? *(const ImS8*) v_min : IM_S8_MIN, v_max ? *(const ImS8*)v_max : IM_S8_MAX, format, power, flags); if (r) *(ImS8*)v = (ImS8)v32; return r; } + case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, v_min ? *(const ImU8*) v_min : IM_U8_MIN, v_max ? *(const ImU8*)v_max : IM_U8_MAX, format, power, flags); if (r) *(ImU8*)v = (ImU8)v32; return r; } + case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, v_min ? *(const ImS16*)v_min : IM_S16_MIN, v_max ? *(const ImS16*)v_max : IM_S16_MAX, format, power, flags); if (r) *(ImS16*)v = (ImS16)v32; return r; } + case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, v_min ? *(const ImU16*)v_min : IM_U16_MIN, v_max ? *(const ImU16*)v_max : IM_U16_MAX, format, power, flags); if (r) *(ImU16*)v = (ImU16)v32; return r; } + case ImGuiDataType_S32: return DragBehaviorT(data_type, (ImS32*)v, v_speed, v_min ? *(const ImS32* )v_min : IM_S32_MIN, v_max ? *(const ImS32* )v_max : IM_S32_MAX, format, power, flags); + case ImGuiDataType_U32: return DragBehaviorT(data_type, (ImU32*)v, v_speed, v_min ? *(const ImU32* )v_min : IM_U32_MIN, v_max ? *(const ImU32* )v_max : IM_U32_MAX, format, power, flags); + case ImGuiDataType_S64: return DragBehaviorT(data_type, (ImS64*)v, v_speed, v_min ? *(const ImS64* )v_min : IM_S64_MIN, v_max ? *(const ImS64* )v_max : IM_S64_MAX, format, power, flags); + case ImGuiDataType_U64: return DragBehaviorT(data_type, (ImU64*)v, v_speed, v_min ? *(const ImU64* )v_min : IM_U64_MIN, v_max ? *(const ImU64* )v_max : IM_U64_MAX, format, power, flags); + case ImGuiDataType_Float: return DragBehaviorT(data_type, (float*)v, v_speed, v_min ? *(const float* )v_min : -FLT_MAX, v_max ? *(const float* )v_max : FLT_MAX, format, power, flags); + case ImGuiDataType_Double: return DragBehaviorT(data_type, (double*)v, v_speed, v_min ? *(const double*)v_min : -DBL_MAX, v_max ? *(const double*)v_max : DBL_MAX, format, power, flags); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return false; +} + +bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + if (power != 1.0f) + IM_ASSERT(v_min != NULL && v_max != NULL); // When using a power curve the drag needs to have known bounds + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const float w = CalcItemWidth(); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb)) + return false; + + const bool hovered = ItemHoverable(frame_bb, id); + + // Default format string when passing NULL + // Patch old "%.0f" format string to use "%d", read function comments for more details. + IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); + if (format == NULL) + format = GDataTypeInfo[data_type].PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) + format = PatchFormatStringFloatToInt(format); + + // Tabbing or CTRL-clicking on Drag turns it into an input box + bool start_text_input = false; + const bool focus_requested = FocusableItemRegister(window, id); + if (focus_requested || (hovered && (g.IO.MouseClicked[0] || g.IO.MouseDoubleClicked[0])) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id)) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + if (focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0] || g.NavInputId == id) + { + start_text_input = true; + g.ScalarAsInputTextId = 0; + } + } + if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) + { + window->DC.CursorPos = frame_bb.Min; + FocusableItemUnregister(window); + return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format); + } + + // Actual drag behavior + const bool value_changed = DragBehavior(id, data_type, v, v_speed, v_min, v_max, format, power, ImGuiDragFlags_None); + if (value_changed) + MarkItemEdited(id); + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); + + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + return value_changed; +} + +bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min, const void* v_max, const char* format, float power) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + PushMultiItemsWidths(components); + size_t type_size = GDataTypeInfo[data_type].Size; + for (int i = 0; i < components; i++) + { + PushID(i); + value_changed |= DragScalar("", data_type, v, v_speed, v_min, v_max, format, power); + SameLine(0, g.Style.ItemInnerSpacing.x); + PopID(); + PopItemWidth(); + v = (void*)((char*)v + type_size); + } + PopID(); + + TextEx(label, FindRenderedTextEnd(label)); + EndGroup(); + return value_changed; +} + +bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) +{ + return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); +} + +bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) +{ + return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); +} + +bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) +{ + return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); +} + +bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) +{ + return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); +} + +bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, float power) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + PushID(label); + BeginGroup(); + PushMultiItemsWidths(2); + + bool value_changed = DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format, power); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= DragFloat("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? FLT_MAX : v_max, format_max ? format_max : format, power); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + + TextEx(label, FindRenderedTextEnd(label)); + EndGroup(); + PopID(); + return value_changed; +} + +// NB: v_speed is float to allow adjusting the drag speed with more precision +bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format) +{ + return DragScalar(label, ImGuiDataType_S32, v, v_speed, &v_min, &v_max, format); +} + +bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format) +{ + return DragScalarN(label, ImGuiDataType_S32, v, 2, v_speed, &v_min, &v_max, format); +} + +bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format) +{ + return DragScalarN(label, ImGuiDataType_S32, v, 3, v_speed, &v_min, &v_max, format); +} + +bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format) +{ + return DragScalarN(label, ImGuiDataType_S32, v, 4, v_speed, &v_min, &v_max, format); +} + +bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + PushID(label); + BeginGroup(); + PushMultiItemsWidths(2); + + bool value_changed = DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= DragInt("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? INT_MAX : v_max, format_max ? format_max : format); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + + TextEx(label, FindRenderedTextEnd(label)); + EndGroup(); + PopID(); + + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: SliderScalar, SliderFloat, SliderInt, etc. +//------------------------------------------------------------------------- +// - SliderBehaviorT<>() [Internal] +// - SliderBehavior() [Internal] +// - SliderScalar() +// - SliderScalarN() +// - SliderFloat() +// - SliderFloat2() +// - SliderFloat3() +// - SliderFloat4() +// - SliderAngle() +// - SliderInt() +// - SliderInt2() +// - SliderInt3() +// - SliderInt4() +// - VSliderScalar() +// - VSliderFloat() +// - VSliderInt() +//------------------------------------------------------------------------- + +template +float ImGui::SliderCalcRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, float power, float linear_zero_pos) +{ + if (v_min == v_max) + return 0.0f; + + const bool is_power = (power != 1.0f) && (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double); + const TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); + if (is_power) + { + if (v_clamped < 0.0f) + { + const float f = 1.0f - (float)((v_clamped - v_min) / (ImMin((TYPE)0, v_max) - v_min)); + return (1.0f - ImPow(f, 1.0f/power)) * linear_zero_pos; + } + else + { + const float f = (float)((v_clamped - ImMax((TYPE)0, v_min)) / (v_max - ImMax((TYPE)0, v_min))); + return linear_zero_pos + ImPow(f, 1.0f/power) * (1.0f - linear_zero_pos); + } + } + + // Linear slider + return (float)((FLOATTYPE)(v_clamped - v_min) / (FLOATTYPE)(v_max - v_min)); +} + +// FIXME: Move some of the code into SliderBehavior(). Current responsability is larger than what the equivalent DragBehaviorT<> does, we also do some rendering, etc. +template +bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb) +{ + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; + const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + const bool is_power = (power != 1.0f) && is_decimal; + + const float grab_padding = 2.0f; + const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f; + float grab_sz = style.GrabMinSize; + SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max); + if (!is_decimal && v_range >= 0) // v_range < 0 may happen on integer overflows + grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit + grab_sz = ImMin(grab_sz, slider_sz); + const float slider_usable_sz = slider_sz - grab_sz; + const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz*0.5f; + const float slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz*0.5f; + + // For power curve sliders that cross over sign boundary we want the curve to be symmetric around 0.0f + float linear_zero_pos; // 0.0->1.0f + if (is_power && v_min * v_max < 0.0f) + { + // Different sign + const FLOATTYPE linear_dist_min_to_0 = ImPow(v_min >= 0 ? (FLOATTYPE)v_min : -(FLOATTYPE)v_min, (FLOATTYPE)1.0f/power); + const FLOATTYPE linear_dist_max_to_0 = ImPow(v_max >= 0 ? (FLOATTYPE)v_max : -(FLOATTYPE)v_max, (FLOATTYPE)1.0f/power); + linear_zero_pos = (float)(linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0)); + } + else + { + // Same sign + linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f; + } + + // Process interacting with the slider + bool value_changed = false; + if (g.ActiveId == id) + { + bool set_new_value = false; + float clicked_t = 0.0f; + if (g.ActiveIdSource == ImGuiInputSource_Mouse) + { + if (!g.IO.MouseDown[0]) + { + ClearActiveID(); + } + else + { + const float mouse_abs_pos = g.IO.MousePos[axis]; + clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f; + if (axis == ImGuiAxis_Y) + clicked_t = 1.0f - clicked_t; + set_new_value = true; + } + } + else if (g.ActiveIdSource == ImGuiInputSource_Nav) + { + const ImVec2 delta2 = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 0.0f, 0.0f); + float delta = (axis == ImGuiAxis_X) ? delta2.x : -delta2.y; + if (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + { + ClearActiveID(); + } + else if (delta != 0.0f) + { + clicked_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, power, linear_zero_pos); + const int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 0; + if ((decimal_precision > 0) || is_power) + { + delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds + if (IsNavInputDown(ImGuiNavInput_TweakSlow)) + delta /= 10.0f; + } + else + { + if ((v_range >= -100.0f && v_range <= 100.0f) || IsNavInputDown(ImGuiNavInput_TweakSlow)) + delta = ((delta < 0.0f) ? -1.0f : +1.0f) / (float)v_range; // Gamepad/keyboard tweak speeds in integer steps + else + delta /= 100.0f; + } + if (IsNavInputDown(ImGuiNavInput_TweakFast)) + delta *= 10.0f; + set_new_value = true; + if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits + set_new_value = false; + else + clicked_t = ImSaturate(clicked_t + delta); + } + } + + if (set_new_value) + { + TYPE v_new; + if (is_power) + { + // Account for power curve scale on both sides of the zero + if (clicked_t < linear_zero_pos) + { + // Negative: rescale to the negative range before powering + float a = 1.0f - (clicked_t / linear_zero_pos); + a = ImPow(a, power); + v_new = ImLerp(ImMin(v_max, (TYPE)0), v_min, a); + } + else + { + // Positive: rescale to the positive range before powering + float a; + if (ImFabs(linear_zero_pos - 1.0f) > 1.e-6f) + a = (clicked_t - linear_zero_pos) / (1.0f - linear_zero_pos); + else + a = clicked_t; + a = ImPow(a, power); + v_new = ImLerp(ImMax(v_min, (TYPE)0), v_max, a); + } + } + else + { + // Linear slider + if (is_decimal) + { + v_new = ImLerp(v_min, v_max, clicked_t); + } + else + { + // For integer values we want the clicking position to match the grab box so we round above + // This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property.. + FLOATTYPE v_new_off_f = (v_max - v_min) * clicked_t; + TYPE v_new_off_floor = (TYPE)(v_new_off_f); + TYPE v_new_off_round = (TYPE)(v_new_off_f + (FLOATTYPE)0.5); + if (!is_decimal && v_new_off_floor < v_new_off_round) + v_new = v_min + v_new_off_round; + else + v_new = v_min + v_new_off_floor; + } + } + + // Round to user desired precision based on format string + v_new = RoundScalarWithFormatT(format, data_type, v_new); + + // Apply result + if (*v != v_new) + { + *v = v_new; + value_changed = true; + } + } + } + + // Output grab position so it can be displayed by the caller + float grab_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, power, linear_zero_pos); + if (axis == ImGuiAxis_Y) + grab_t = 1.0f - grab_t; + const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); + if (axis == ImGuiAxis_X) + *out_grab_bb = ImRect(grab_pos - grab_sz*0.5f, bb.Min.y + grab_padding, grab_pos + grab_sz*0.5f, bb.Max.y - grab_padding); + else + *out_grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz*0.5f, bb.Max.x - grab_padding, grab_pos + grab_sz*0.5f); + + return value_changed; +} + +// For 32-bits and larger types, slider bounds are limited to half the natural type range. +// So e.g. an integer Slider between INT_MAX-10 and INT_MAX will fail, but an integer Slider between INT_MAX/2-10 and INT_MAX/2 will be ok. +// It would be possible to lift that limitation with some work but it doesn't seem to be worth it for sliders. +bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb) +{ + switch (data_type) + { + case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)v_min, *(const ImS8*)v_max, format, power, flags, out_grab_bb); if (r) *(ImS8*)v = (ImS8)v32; return r; } + case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)v_min, *(const ImU8*)v_max, format, power, flags, out_grab_bb); if (r) *(ImU8*)v = (ImU8)v32; return r; } + case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)v_min, *(const ImS16*)v_max, format, power, flags, out_grab_bb); if (r) *(ImS16*)v = (ImS16)v32; return r; } + case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)v_min, *(const ImU16*)v_max, format, power, flags, out_grab_bb); if (r) *(ImU16*)v = (ImU16)v32; return r; } + case ImGuiDataType_S32: + IM_ASSERT(*(const ImS32*)v_min >= IM_S32_MIN/2 && *(const ImS32*)v_max <= IM_S32_MAX/2); + return SliderBehaviorT(bb, id, data_type, (ImS32*)v, *(const ImS32*)v_min, *(const ImS32*)v_max, format, power, flags, out_grab_bb); + case ImGuiDataType_U32: + IM_ASSERT(*(const ImU32*)v_min <= IM_U32_MAX/2); + return SliderBehaviorT(bb, id, data_type, (ImU32*)v, *(const ImU32*)v_min, *(const ImU32*)v_max, format, power, flags, out_grab_bb); + case ImGuiDataType_S64: + IM_ASSERT(*(const ImS64*)v_min >= IM_S64_MIN/2 && *(const ImS64*)v_max <= IM_S64_MAX/2); + return SliderBehaviorT(bb, id, data_type, (ImS64*)v, *(const ImS64*)v_min, *(const ImS64*)v_max, format, power, flags, out_grab_bb); + case ImGuiDataType_U64: + IM_ASSERT(*(const ImU64*)v_min <= IM_U64_MAX/2); + return SliderBehaviorT(bb, id, data_type, (ImU64*)v, *(const ImU64*)v_min, *(const ImU64*)v_max, format, power, flags, out_grab_bb); + case ImGuiDataType_Float: + IM_ASSERT(*(const float*)v_min >= -FLT_MAX/2.0f && *(const float*)v_max <= FLT_MAX/2.0f); + return SliderBehaviorT(bb, id, data_type, (float*)v, *(const float*)v_min, *(const float*)v_max, format, power, flags, out_grab_bb); + case ImGuiDataType_Double: + IM_ASSERT(*(const double*)v_min >= -DBL_MAX/2.0f && *(const double*)v_max <= DBL_MAX/2.0f); + return SliderBehaviorT(bb, id, data_type, (double*)v, *(const double*)v_min, *(const double*)v_max, format, power, flags, out_grab_bb); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return false; +} + +bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const float w = CalcItemWidth(); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb)) + return false; + + // Default format string when passing NULL + // Patch old "%.0f" format string to use "%d", read function comments for more details. + IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); + if (format == NULL) + format = GDataTypeInfo[data_type].PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) + format = PatchFormatStringFloatToInt(format); + + // Tabbing or CTRL-clicking on Slider turns it into an input box + bool start_text_input = false; + const bool focus_requested = FocusableItemRegister(window, id); + const bool hovered = ItemHoverable(frame_bb, id); + if (focus_requested || (hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id)) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + if (focus_requested || g.IO.KeyCtrl || g.NavInputId == id) + { + start_text_input = true; + g.ScalarAsInputTextId = 0; + } + } + if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) + { + window->DC.CursorPos = frame_bb.Min; + FocusableItemUnregister(window); + return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format); + } + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); + + // Slider behavior + ImRect grab_bb; + const bool value_changed = SliderBehavior(frame_bb, id, data_type, v, v_min, v_max, format, power, ImGuiSliderFlags_None, &grab_bb); + if (value_changed) + MarkItemEdited(id); + + // Render grab + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + return value_changed; +} + +// Add multiple sliders on 1 line for compact edition of multiple components +bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, float power) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + PushMultiItemsWidths(components); + size_t type_size = GDataTypeInfo[data_type].Size; + for (int i = 0; i < components; i++) + { + PushID(i); + value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, power); + SameLine(0, g.Style.ItemInnerSpacing.x); + PopID(); + PopItemWidth(); + v = (void*)((char*)v + type_size); + } + PopID(); + + TextEx(label, FindRenderedTextEnd(label)); + EndGroup(); + return value_changed; +} + +bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) +{ + return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); +} + +bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) +{ + return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); +} + +bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) +{ + return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); +} + +bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) +{ + return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); +} + +bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max, const char* format) +{ + if (format == NULL) + format = "%.0f deg"; + float v_deg = (*v_rad) * 360.0f / (2*IM_PI); + bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, format, 1.0f); + *v_rad = v_deg * (2*IM_PI) / 360.0f; + return value_changed; +} + +bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format) +{ + return SliderScalar(label, ImGuiDataType_S32, v, &v_min, &v_max, format); +} + +bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format) +{ + return SliderScalarN(label, ImGuiDataType_S32, v, 2, &v_min, &v_max, format); +} + +bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format) +{ + return SliderScalarN(label, ImGuiDataType_S32, v, 3, &v_min, &v_max, format); +} + +bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format) +{ + return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format); +} + +bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); + const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + ItemSize(bb, style.FramePadding.y); + if (!ItemAdd(frame_bb, id)) + return false; + + // Default format string when passing NULL + // Patch old "%.0f" format string to use "%d", read function comments for more details. + IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); + if (format == NULL) + format = GDataTypeInfo[data_type].PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) + format = PatchFormatStringFloatToInt(format); + + const bool hovered = ItemHoverable(frame_bb, id); + if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + } + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); + + // Slider behavior + ImRect grab_bb; + const bool value_changed = SliderBehavior(frame_bb, id, data_type, v, v_min, v_max, format, power, ImGuiSliderFlags_Vertical, &grab_bb); + if (value_changed) + MarkItemEdited(id); + + // Render grab + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + // For the vertical slider we allow centered text to overlap the frame padding + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.0f)); + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + return value_changed; +} + +bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, float power) +{ + return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, power); +} + +bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format) +{ + return VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: InputScalar, InputFloat, InputInt, etc. +//------------------------------------------------------------------------- +// - ImParseFormatFindStart() [Internal] +// - ImParseFormatFindEnd() [Internal] +// - ImParseFormatTrimDecorations() [Internal] +// - ImParseFormatPrecision() [Internal] +// - InputScalarAsWidgetReplacement() [Internal] +// - InputScalar() +// - InputScalarN() +// - InputFloat() +// - InputFloat2() +// - InputFloat3() +// - InputFloat4() +// - InputInt() +// - InputInt2() +// - InputInt3() +// - InputInt4() +// - InputDouble() +//------------------------------------------------------------------------- + +// We don't use strchr() because our strings are usually very short and often start with '%' +const char* ImParseFormatFindStart(const char* fmt) +{ + while (char c = fmt[0]) + { + if (c == '%' && fmt[1] != '%') + return fmt; + else if (c == '%') + fmt++; + fmt++; + } + return fmt; +} + +const char* ImParseFormatFindEnd(const char* fmt) +{ + // Printf/scanf types modifiers: I/L/h/j/l/t/w/z. Other uppercase letters qualify as types aka end of the format. + if (fmt[0] != '%') + return fmt; + const unsigned int ignored_uppercase_mask = (1 << ('I'-'A')) | (1 << ('L'-'A')); + const unsigned int ignored_lowercase_mask = (1 << ('h'-'a')) | (1 << ('j'-'a')) | (1 << ('l'-'a')) | (1 << ('t'-'a')) | (1 << ('w'-'a')) | (1 << ('z'-'a')); + for (char c; (c = *fmt) != 0; fmt++) + { + if (c >= 'A' && c <= 'Z' && ((1 << (c - 'A')) & ignored_uppercase_mask) == 0) + return fmt + 1; + if (c >= 'a' && c <= 'z' && ((1 << (c - 'a')) & ignored_lowercase_mask) == 0) + return fmt + 1; + } + return fmt; +} + +// Extract the format out of a format string with leading or trailing decorations +// fmt = "blah blah" -> return fmt +// fmt = "%.3f" -> return fmt +// fmt = "hello %.3f" -> return fmt + 6 +// fmt = "%.3f hello" -> return buf written with "%.3f" +const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_size) +{ + const char* fmt_start = ImParseFormatFindStart(fmt); + if (fmt_start[0] != '%') + return fmt; + const char* fmt_end = ImParseFormatFindEnd(fmt_start); + if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data. + return fmt_start; + ImStrncpy(buf, fmt_start, ImMin((size_t)(fmt_end - fmt_start) + 1, buf_size)); + return buf; +} + +// Parse display precision back from the display format string +// FIXME: This is still used by some navigation code path to infer a minimum tweak step, but we should aim to rework widgets so it isn't needed. +int ImParseFormatPrecision(const char* fmt, int default_precision) +{ + fmt = ImParseFormatFindStart(fmt); + if (fmt[0] != '%') + return default_precision; + fmt++; + while (*fmt >= '0' && *fmt <= '9') + fmt++; + int precision = INT_MAX; + if (*fmt == '.') + { + fmt = ImAtoi(fmt + 1, &precision); + if (precision < 0 || precision > 99) + precision = default_precision; + } + if (*fmt == 'e' || *fmt == 'E') // Maximum precision with scientific notation + precision = -1; + if ((*fmt == 'g' || *fmt == 'G') && precision == INT_MAX) + precision = -1; + return (precision == INT_MAX) ? default_precision : precision; +} + +// Create text input in place of an active drag/slider (used when doing a CTRL+Click on drag/slider widgets) +// FIXME: Facilitate using this in variety of other situations. +bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format) +{ + IM_UNUSED(id); + ImGuiContext& g = *GImGui; + + // On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id. + // We clear ActiveID on the first frame to allow the InputText() taking it back. + if (g.ScalarAsInputTextId == 0) + ClearActiveID(); + + char fmt_buf[32]; + char data_buf[32]; + format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); + DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, data_ptr, format); + ImStrTrimBlanks(data_buf); + ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); + bool value_changed = InputTextEx(label, NULL, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags); + if (g.ScalarAsInputTextId == 0) + { + // First frame we started displaying the InputText widget, we expect it to take the active id. + IM_ASSERT(g.ActiveId == id); + g.ScalarAsInputTextId = g.ActiveId; + } + if (value_changed) + return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, NULL); + return false; +} + +bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + + IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); + if (format == NULL) + format = GDataTypeInfo[data_type].PrintFmt; + + char buf[64]; + DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, data_ptr, format); + + bool value_changed = false; + if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) + flags |= ImGuiInputTextFlags_CharsDecimal; + flags |= ImGuiInputTextFlags_AutoSelectAll; + + if (step != NULL) + { + const float button_size = GetFrameHeight(); + + BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive() + PushID(label); + PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); + if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view + value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format); + PopItemWidth(); + + // Step buttons + const ImVec2 backup_frame_padding = style.FramePadding; + style.FramePadding.x = style.FramePadding.y; + ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups; + if (flags & ImGuiInputTextFlags_ReadOnly) + button_flags |= ImGuiButtonFlags_Disabled; + SameLine(0, style.ItemInnerSpacing.x); + if (ButtonEx("-", ImVec2(button_size, button_size), button_flags)) + { + DataTypeApplyOp(data_type, '-', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step); + value_changed = true; + } + SameLine(0, style.ItemInnerSpacing.x); + if (ButtonEx("+", ImVec2(button_size, button_size), button_flags)) + { + DataTypeApplyOp(data_type, '+', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step); + value_changed = true; + } + SameLine(0, style.ItemInnerSpacing.x); + TextEx(label, FindRenderedTextEnd(label)); + style.FramePadding = backup_frame_padding; + + PopID(); + EndGroup(); + } + else + { + if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) + value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format); + } + + return value_changed; +} + +bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + PushMultiItemsWidths(components); + size_t type_size = GDataTypeInfo[data_type].Size; + for (int i = 0; i < components; i++) + { + PushID(i); + value_changed |= InputScalar("", data_type, v, step, step_fast, format, flags); + SameLine(0, g.Style.ItemInnerSpacing.x); + PopID(); + PopItemWidth(); + v = (void*)((char*)v + type_size); + } + PopID(); + + TextEx(label, FindRenderedTextEnd(label)); + EndGroup(); + return value_changed; +} + +bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags flags) +{ + flags |= ImGuiInputTextFlags_CharsScientific; + return InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), format, flags); +} + +bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags); +} + +bool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags); +} + +bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags); +} + +// Prefer using "const char* format" directly, which is more flexible and consistent with other API. +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags flags) +{ + char format[16] = "%f"; + if (decimal_precision >= 0) + ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); + return InputFloat(label, v, step, step_fast, format, flags); +} + +bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags flags) +{ + char format[16] = "%f"; + if (decimal_precision >= 0) + ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); + return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags); +} + +bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags flags) +{ + char format[16] = "%f"; + if (decimal_precision >= 0) + ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); + return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags); +} + +bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags flags) +{ + char format[16] = "%f"; + if (decimal_precision >= 0) + ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); + return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags); +} +#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags flags) +{ + // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes. + const char* format = (flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d"; + return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, flags); +} + +bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_S32, v, 2, NULL, NULL, "%d", flags); +} + +bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_S32, v, 3, NULL, NULL, "%d", flags); +} + +bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL, "%d", flags); +} + +bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags flags) +{ + flags |= ImGuiInputTextFlags_CharsScientific; + return InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step>0.0 ? &step : NULL), (void*)(step_fast>0.0 ? &step_fast : NULL), format, flags); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: InputText, InputTextMultiline, InputTextWithHint +//------------------------------------------------------------------------- +// - InputText() +// - InputTextWithHint() +// - InputTextMultiline() +// - InputTextEx() [Internal] +//------------------------------------------------------------------------- + +bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() + return InputTextEx(label, NULL, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data); +} + +bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + return InputTextEx(label, NULL, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data); +} + +bool ImGui::InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() + return InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data); +} + +static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end) +{ + int line_count = 0; + const char* s = text_begin; + while (char c = *s++) // We are only matching for \n so we can ignore UTF-8 decoding + if (c == '\n') + line_count++; + s--; + if (s[0] != '\n' && s[0] != '\r') + line_count++; + *out_text_end = s; + return line_count; +} + +static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) +{ + ImGuiContext& g = *GImGui; + ImFont* font = g.Font; + const float line_height = g.FontSize; + const float scale = line_height / font->FontSize; + + ImVec2 text_size = ImVec2(0,0); + float line_width = 0.0f; + + const ImWchar* s = text_begin; + while (s < text_end) + { + unsigned int c = (unsigned int)(*s++); + if (c == '\n') + { + text_size.x = ImMax(text_size.x, line_width); + text_size.y += line_height; + line_width = 0.0f; + if (stop_on_new_line) + break; + continue; + } + if (c == '\r') + continue; + + const float char_width = font->GetCharAdvance((ImWchar)c) * scale; + line_width += char_width; + } + + if (text_size.x < line_width) + text_size.x = line_width; + + if (out_offset) + *out_offset = ImVec2(line_width, text_size.y + line_height); // offset allow for the possibility of sitting after a trailing \n + + if (line_width > 0 || text_size.y == 0.0f) // whereas size.y will ignore the trailing \n + text_size.y += line_height; + + if (remaining) + *remaining = s; + + return text_size; +} + +// Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar) +namespace ImStb +{ + +static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; } +static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->TextW[idx]; } +static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx+char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; return GImGui->Font->GetCharAdvance(c) * (GImGui->FontSize / GImGui->Font->FontSize); } +static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : key; } +static ImWchar STB_TEXTEDIT_NEWLINE = '\n'; +static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx) +{ + const ImWchar* text = obj->TextW.Data; + const ImWchar* text_remaining = NULL; + const ImVec2 size = InputTextCalcTextSizeW(text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true); + r->x0 = 0.0f; + r->x1 = size.x; + r->baseline_y_delta = size.y; + r->ymin = 0.0f; + r->ymax = size.y; + r->num_chars = (int)(text_remaining - (text + line_start_idx)); +} + +static bool is_separator(unsigned int c) { return ImCharIsBlankW(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; } +static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator( obj->TextW[idx-1] ) && !is_separator( obj->TextW[idx] ) ) : 1; } +static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } +#ifdef __APPLE__ // FIXME: Move setting to IO structure +static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator( obj->TextW[idx-1] ) && is_separator( obj->TextW[idx] ) ) : 1; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } +#else +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } +#endif +#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h +#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL + +static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) +{ + ImWchar* dst = obj->TextW.Data + pos; + + // We maintain our buffer length in both UTF-8 and wchar formats + obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n); + obj->CurLenW -= n; + + // Offset remaining text (FIXME-OPT: Use memmove) + const ImWchar* src = obj->TextW.Data + pos + n; + while (ImWchar c = *src++) + *dst++ = c; + *dst = '\0'; +} + +static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len) +{ + const bool is_resizable = (obj->UserFlags & ImGuiInputTextFlags_CallbackResize) != 0; + const int text_len = obj->CurLenW; + IM_ASSERT(pos <= text_len); + + const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len); + if (!is_resizable && (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufCapacityA)) + return false; + + // Grow internal buffer if needed + if (new_text_len + text_len + 1 > obj->TextW.Size) + { + if (!is_resizable) + return false; + IM_ASSERT(text_len < obj->TextW.Size); + obj->TextW.resize(text_len + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1); + } + + ImWchar* text = obj->TextW.Data; + if (pos != text_len) + memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar)); + memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar)); + + obj->CurLenW += new_text_len; + obj->CurLenA += new_text_len_utf8; + obj->TextW[obj->CurLenW] = '\0'; + + return true; +} + +// We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their STB_TEXTEDIT_K_* symbols) +#define STB_TEXTEDIT_K_LEFT 0x10000 // keyboard input to move cursor left +#define STB_TEXTEDIT_K_RIGHT 0x10001 // keyboard input to move cursor right +#define STB_TEXTEDIT_K_UP 0x10002 // keyboard input to move cursor up +#define STB_TEXTEDIT_K_DOWN 0x10003 // keyboard input to move cursor down +#define STB_TEXTEDIT_K_LINESTART 0x10004 // keyboard input to move cursor to start of line +#define STB_TEXTEDIT_K_LINEEND 0x10005 // keyboard input to move cursor to end of line +#define STB_TEXTEDIT_K_TEXTSTART 0x10006 // keyboard input to move cursor to start of text +#define STB_TEXTEDIT_K_TEXTEND 0x10007 // keyboard input to move cursor to end of text +#define STB_TEXTEDIT_K_DELETE 0x10008 // keyboard input to delete selection or character under cursor +#define STB_TEXTEDIT_K_BACKSPACE 0x10009 // keyboard input to delete selection or character left of cursor +#define STB_TEXTEDIT_K_UNDO 0x1000A // keyboard input to perform undo +#define STB_TEXTEDIT_K_REDO 0x1000B // keyboard input to perform redo +#define STB_TEXTEDIT_K_WORDLEFT 0x1000C // keyboard input to move cursor left one word +#define STB_TEXTEDIT_K_WORDRIGHT 0x1000D // keyboard input to move cursor right one word +#define STB_TEXTEDIT_K_SHIFT 0x20000 + +#define STB_TEXTEDIT_IMPLEMENTATION +#include "imstb_textedit.h" + +} + +void ImGuiInputTextState::OnKeyPressed(int key) +{ + stb_textedit_key(this, &Stb, key); + CursorFollow = true; + CursorAnimReset(); +} + +ImGuiInputTextCallbackData::ImGuiInputTextCallbackData() +{ + memset(this, 0, sizeof(*this)); +} + +// Public API to manipulate UTF-8 text +// We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar) +// FIXME: The existence of this rarely exercised code path is a bit of a nuisance. +void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count) +{ + IM_ASSERT(pos + bytes_count <= BufTextLen); + char* dst = Buf + pos; + const char* src = Buf + pos + bytes_count; + while (char c = *src++) + *dst++ = c; + *dst = '\0'; + + if (CursorPos + bytes_count >= pos) + CursorPos -= bytes_count; + else if (CursorPos >= pos) + CursorPos = pos; + SelectionStart = SelectionEnd = CursorPos; + BufDirty = true; + BufTextLen -= bytes_count; +} + +void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end) +{ + const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0; + const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text); + if (new_text_len + BufTextLen >= BufSize) + { + if (!is_resizable) + return; + + // Contrary to STB_TEXTEDIT_INSERTCHARS() this is working in the UTF8 buffer, hence the midly similar code (until we remove the U16 buffer alltogether!) + ImGuiContext& g = *GImGui; + ImGuiInputTextState* edit_state = &g.InputTextState; + IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID); + IM_ASSERT(Buf == edit_state->TextA.Data); + int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1; + edit_state->TextA.reserve(new_buf_size + 1); + Buf = edit_state->TextA.Data; + BufSize = edit_state->BufCapacityA = new_buf_size; + } + + if (BufTextLen != pos) + memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos)); + memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char)); + Buf[BufTextLen + new_text_len] = '\0'; + + if (CursorPos >= pos) + CursorPos += new_text_len; + SelectionStart = SelectionEnd = CursorPos; + BufDirty = true; + BufTextLen += new_text_len; +} + +// Return false to discard a character. +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + unsigned int c = *p_char; + + if (c < 128 && c != ' ' && !isprint((int)(c & 0xFF))) + { + bool pass = false; + pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline)); + pass |= (c == '\t' && (flags & ImGuiInputTextFlags_AllowTabInput)); + if (!pass) + return false; + } + + if (c >= 0xE000 && c <= 0xF8FF) // Filter private Unicode range. I don't imagine anybody would want to input them. GLFW on OSX seems to send private characters for special keys like arrow keys. + return false; + + if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific)) + { + if (flags & ImGuiInputTextFlags_CharsDecimal) + if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/')) + return false; + + if (flags & ImGuiInputTextFlags_CharsScientific) + if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/') && (c != 'e') && (c != 'E')) + return false; + + if (flags & ImGuiInputTextFlags_CharsHexadecimal) + if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F')) + return false; + + if (flags & ImGuiInputTextFlags_CharsUppercase) + if (c >= 'a' && c <= 'z') + *p_char = (c += (unsigned int)('A'-'a')); + + if (flags & ImGuiInputTextFlags_CharsNoBlank) + if (ImCharIsBlankW(c)) + return false; + } + + if (flags & ImGuiInputTextFlags_CallbackCharFilter) + { + ImGuiInputTextCallbackData callback_data; + memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData)); + callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter; + callback_data.EventChar = (ImWchar)c; + callback_data.Flags = flags; + callback_data.UserData = user_data; + if (callback(&callback_data) != 0) + return false; + *p_char = callback_data.EventChar; + if (!callback_data.EventChar) + return false; + } + + return true; +} + +// Edit a string of text +// - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!". +// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match +// Note that in std::string world, capacity() would omit 1 byte used by the zero-terminator. +// - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the InputText is active has no effect. +// - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h +// (FIXME: Rather confusing and messy function, among the worse part of our codebase, expecting to rewrite a V2 at some point.. Partly because we are +// doing UTF8 > U16 > UTF8 conversions on the go to easily interface with stb_textedit. Ideally should stay in UTF-8 all the time. See /~https://github.com/nothings/stb/issues/188) +bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) + IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) + + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + const ImGuiStyle& style = g.Style; + + const bool RENDER_SELECTION_WHEN_INACTIVE = false; + const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; + const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0; + const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; + const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0; + const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0; + if (is_resizable) + IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! + + if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope, + BeginGroup(); + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f)); + + ImGuiWindow* draw_window = window; + if (is_multiline) + { + if (!ItemAdd(total_bb, id, &frame_bb)) + { + ItemSize(total_bb, style.FramePadding.y); + EndGroup(); + return false; + } + if (!BeginChildFrame(id, frame_bb.GetSize())) + { + EndChildFrame(); + EndGroup(); + return false; + } + draw_window = GetCurrentWindow(); + draw_window->DC.NavLayerActiveMaskNext |= draw_window->DC.NavLayerCurrentMask; // This is to ensure that EndChild() will display a navigation highlight + size.x -= draw_window->ScrollbarSizes.x; + } + else + { + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb)) + return false; + } + const bool hovered = ItemHoverable(frame_bb, id); + if (hovered) + g.MouseCursor = ImGuiMouseCursor_TextInput; + + // NB: we are only allowed to access 'edit_state' if we are the active widget. + ImGuiInputTextState* state = NULL; + if (g.InputTextState.ID == id) + state = &g.InputTextState; + + const bool focus_requested = FocusableItemRegister(window, id); + const bool focus_requested_by_code = focus_requested && (g.FocusRequestCurrWindow == window && g.FocusRequestCurrCounterAll == window->DC.FocusCounterAll); + const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code; + + const bool user_clicked = hovered && io.MouseClicked[0]; + const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard)); + const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetScrollbarID(draw_window, ImGuiAxis_Y); + const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetScrollbarID(draw_window, ImGuiAxis_Y); + + bool clear_active_id = false; + bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline); + + const bool init_make_active = (focus_requested || user_clicked || user_scroll_finish || user_nav_input_start); + const bool init_state = (init_make_active || user_scroll_active); + if (init_state && g.ActiveId != id) + { + // Access state even if we don't own it yet. + state = &g.InputTextState; + state->CursorAnimReset(); + + // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar) + // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode) + const int buf_len = (int)strlen(buf); + state->InitialTextA.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. + memcpy(state->InitialTextA.Data, buf, buf_len + 1); + + // Start edition + const char* buf_end = NULL; + state->TextW.resize(buf_size + 1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data is always pointing to at least an empty string. + state->TextA.resize(0); + state->TextAIsValid = false; // TextA is not valid yet (we will display buf until then) + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end); + state->CurLenA = (int)(buf_end - buf); // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. + + // Preserve cursor position and undo/redo stack if we come back to same widget + // FIXME: For non-readonly widgets we might be able to require that TextAIsValid && TextA == buf ? (untested) and discard undo stack if user buffer has changed. + const bool recycle_state = (state->ID == id); + if (recycle_state) + { + // Recycle existing cursor/selection/undo stack but clamp position + // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler. + state->CursorClamp(); + } + else + { + state->ID = id; + state->ScrollX = 0.0f; + stb_textedit_initialize_state(&state->Stb, !is_multiline); + if (!is_multiline && focus_requested_by_code) + select_all = true; + } + if (flags & ImGuiInputTextFlags_AlwaysInsertMode) + state->Stb.insert_mode = 1; + if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl))) + select_all = true; + } + + if (g.ActiveId != id && init_make_active) + { + IM_ASSERT(state && state->ID == id); + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + IM_ASSERT(ImGuiNavInput_COUNT < 32); + g.ActiveIdBlockNavInputFlags = (1 << ImGuiNavInput_Cancel); + if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out + g.ActiveIdBlockNavInputFlags |= (1 << ImGuiNavInput_KeyTab_); + if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory)) + g.ActiveIdAllowNavDirFlags = ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down)); + } + + // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function) + if (g.ActiveId == id && state == NULL) + ClearActiveID(); + + // Release focus when we click outside + if (g.ActiveId == id && io.MouseClicked[0] && !init_state && !init_make_active) //-V560 + clear_active_id = true; + + // When read-only we always use the live data passed to the function + // FIXME-OPT: Because our selection/cursor code currently needs the wide text we need to convert it when active, which is not ideal :( + if (is_readonly && state != NULL) + { + const bool will_render_cursor = (g.ActiveId == id) || (user_scroll_active); + const bool will_render_selection = state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || will_render_cursor); + if (will_render_cursor || will_render_selection) + { + const char* buf_end = NULL; + state->TextW.resize(buf_size + 1); + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, buf, NULL, &buf_end); + state->CurLenA = (int)(buf_end - buf); + state->CursorClamp(); + } + } + + // Lock the decision of whether we are going to take the path displaying the cursor or selection + const bool render_cursor = (g.ActiveId == id) || (state && user_scroll_active); + const bool render_selection = state && state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); + bool value_changed = false; + bool enter_pressed = false; + + // Select the buffer to render. + const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state && state->TextAIsValid; + const bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0); + + // Password pushes a temporary font with only a fallback glyph + if (is_password && !is_displaying_hint) + { + const ImFontGlyph* glyph = g.Font->FindGlyph('*'); + ImFont* password_font = &g.InputTextPasswordFont; + password_font->FontSize = g.Font->FontSize; + password_font->Scale = g.Font->Scale; + password_font->DisplayOffset = g.Font->DisplayOffset; + password_font->Ascent = g.Font->Ascent; + password_font->Descent = g.Font->Descent; + password_font->ContainerAtlas = g.Font->ContainerAtlas; + password_font->FallbackGlyph = glyph; + password_font->FallbackAdvanceX = glyph->AdvanceX; + IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty()); + PushFont(password_font); + } + + // Process mouse inputs and character inputs + int backup_current_text_length = 0; + if (g.ActiveId == id) + { + IM_ASSERT(state != NULL); + backup_current_text_length = state->CurLenA; + state->BufCapacityA = buf_size; + state->UserFlags = flags; + state->UserCallback = callback; + state->UserCallbackData = callback_user_data; + + // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. + // Down the line we should have a cleaner library-wide concept of Selected vs Active. + g.ActiveIdAllowOverlap = !io.MouseDown[0]; + g.WantTextInputNextFrame = 1; + + // Edit in progress + const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX; + const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f)); + + const bool is_osx = io.ConfigMacOSXBehaviors; + if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0])) + { + state->SelectAll(); + state->SelectedAllMouseLock = true; + } + else if (hovered && is_osx && io.MouseDoubleClicked[0]) + { + // Double-click select a word only, OS X style (by simulating keystrokes) + state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); + state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); + } + else if (io.MouseClicked[0] && !state->SelectedAllMouseLock) + { + if (hovered) + { + stb_textedit_click(state, &state->Stb, mouse_x, mouse_y); + state->CursorAnimReset(); + } + } + else if (io.MouseDown[0] && !state->SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)) + { + stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y); + state->CursorAnimReset(); + state->CursorFollow = true; + } + if (state->SelectedAllMouseLock && !io.MouseDown[0]) + state->SelectedAllMouseLock = false; + + if (io.InputQueueCharacters.Size > 0) + { + // Process text input (before we check for Return because using some IME will effectively send a Return?) + // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. + bool ignore_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); + if (!ignore_inputs && !is_readonly && !user_nav_input_start) + for (int n = 0; n < io.InputQueueCharacters.Size; n++) + { + // Insert character if they pass filtering + unsigned int c = (unsigned int)io.InputQueueCharacters[n]; + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + state->OnKeyPressed((int)c); + } + + // Consume characters + io.InputQueueCharacters.resize(0); + } + } + + // Process other shortcuts/key-presses + bool cancel_edit = false; + if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id) + { + IM_ASSERT(state != NULL); + const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); + const bool is_osx = io.ConfigMacOSXBehaviors; + const bool is_shortcut_key = (is_osx ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl + const bool is_osx_shift_shortcut = is_osx && io.KeySuper && io.KeyShift && !io.KeyCtrl && !io.KeyAlt; + const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl + const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End + const bool is_ctrl_key_only = io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !io.KeySuper; + const bool is_shift_key_only = io.KeyShift && !io.KeyCtrl && !io.KeyAlt && !io.KeySuper; + + const bool is_cut = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && !is_readonly && !is_password && (!is_multiline || state->HasSelection()); + const bool is_copy = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || state->HasSelection()); + const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_readonly; + const bool is_undo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && !is_readonly && is_undoable); + const bool is_redo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && !is_readonly && is_undoable; + + if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_Delete) && !is_readonly) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_Backspace) && !is_readonly) + { + if (!state->HasSelection()) + { + if (is_wordmove_key_down) + state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT); + else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) + state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT); + } + state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); + } + else if (IsKeyPressedMap(ImGuiKey_Enter)) + { + bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; + if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl)) + { + enter_pressed = clear_active_id = true; + } + else if (!is_readonly) + { + unsigned int c = '\n'; // Insert new line + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + state->OnKeyPressed((int)c); + } + } + else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !is_readonly) + { + unsigned int c = '\t'; // Insert TAB + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + state->OnKeyPressed((int)c); + } + else if (IsKeyPressedMap(ImGuiKey_Escape)) + { + clear_active_id = cancel_edit = true; + } + else if (is_undo || is_redo) + { + state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO); + state->ClearSelection(); + } + else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A)) + { + state->SelectAll(); + state->CursorFollow = true; + } + else if (is_cut || is_copy) + { + // Cut, Copy + if (io.SetClipboardTextFn) + { + const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0; + const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW; + const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1; + char* clipboard_data = (char*)MemAlloc(clipboard_data_len * sizeof(char)); + ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie); + SetClipboardText(clipboard_data); + MemFree(clipboard_data); + } + if (is_cut) + { + if (!state->HasSelection()) + state->SelectAll(); + state->CursorFollow = true; + stb_textedit_cut(state, &state->Stb); + } + } + else if (is_paste) + { + if (const char* clipboard = GetClipboardText()) + { + // Filter pasted buffer + const int clipboard_len = (int)strlen(clipboard); + ImWchar* clipboard_filtered = (ImWchar*)MemAlloc((clipboard_len+1) * sizeof(ImWchar)); + int clipboard_filtered_len = 0; + for (const char* s = clipboard; *s; ) + { + unsigned int c; + s += ImTextCharFromUtf8(&c, s, NULL); + if (c == 0) + break; + if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + continue; + clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; + } + clipboard_filtered[clipboard_filtered_len] = 0; + if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation + { + stb_textedit_paste(state, &state->Stb, clipboard_filtered, clipboard_filtered_len); + state->CursorFollow = true; + } + MemFree(clipboard_filtered); + } + } + } + + // Process callbacks and apply result back to user's buffer. + if (g.ActiveId == id) + { + IM_ASSERT(state != NULL); + const char* apply_new_text = NULL; + int apply_new_text_length = 0; + if (cancel_edit) + { + // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents. + if (!is_readonly && strcmp(buf, state->InitialTextA.Data) != 0) + { + apply_new_text = state->InitialTextA.Data; + apply_new_text_length = state->InitialTextA.Size - 1; + } + } + + // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer before clearing ActiveId, even though strictly speaking it wasn't modified on this frame. + // If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail. Also this allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage. + bool apply_edit_back_to_user_buffer = !cancel_edit || (enter_pressed && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); + if (apply_edit_back_to_user_buffer) + { + // Apply new value immediately - copy modified buffer back + // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer + // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect. + // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks. + if (!is_readonly) + { + state->TextAIsValid = true; + state->TextA.resize(state->TextW.Size * 4 + 1); + ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->TextW.Data, NULL); + } + + // User callback + if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackAlways)) != 0) + { + IM_ASSERT(callback != NULL); + + // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment. + ImGuiInputTextFlags event_flag = 0; + ImGuiKey event_key = ImGuiKey_COUNT; + if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab)) + { + event_flag = ImGuiInputTextFlags_CallbackCompletion; + event_key = ImGuiKey_Tab; + } + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow)) + { + event_flag = ImGuiInputTextFlags_CallbackHistory; + event_key = ImGuiKey_UpArrow; + } + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_DownArrow)) + { + event_flag = ImGuiInputTextFlags_CallbackHistory; + event_key = ImGuiKey_DownArrow; + } + else if (flags & ImGuiInputTextFlags_CallbackAlways) + event_flag = ImGuiInputTextFlags_CallbackAlways; + + if (event_flag) + { + ImGuiInputTextCallbackData callback_data; + memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData)); + callback_data.EventFlag = event_flag; + callback_data.Flags = flags; + callback_data.UserData = callback_user_data; + + callback_data.EventKey = event_key; + callback_data.Buf = state->TextA.Data; + callback_data.BufTextLen = state->CurLenA; + callback_data.BufSize = state->BufCapacityA; + callback_data.BufDirty = false; + + // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see /~https://github.com/nothings/stb/issues/188) + ImWchar* text = state->TextW.Data; + const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + state->Stb.cursor); + const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_start); + const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_end); + + // Call user code + callback(&callback_data); + + // Read back what user may have modified + IM_ASSERT(callback_data.Buf == state->TextA.Data); // Invalid to modify those fields + IM_ASSERT(callback_data.BufSize == state->BufCapacityA); + IM_ASSERT(callback_data.Flags == flags); + if (callback_data.CursorPos != utf8_cursor_pos) { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; } + if (callback_data.SelectionStart != utf8_selection_start) { state->Stb.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } + if (callback_data.SelectionEnd != utf8_selection_end) { state->Stb.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } + if (callback_data.BufDirty) + { + IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! + if (callback_data.BufTextLen > backup_current_text_length && is_resizable) + state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length)); + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL); + state->CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() + state->CursorAnimReset(); + } + } + } + + // Will copy result string if modified + if (!is_readonly && strcmp(state->TextA.Data, buf) != 0) + { + apply_new_text = state->TextA.Data; + apply_new_text_length = state->CurLenA; + } + } + + // Copy result to user buffer + if (apply_new_text) + { + IM_ASSERT(apply_new_text_length >= 0); + if (backup_current_text_length != apply_new_text_length && is_resizable) + { + ImGuiInputTextCallbackData callback_data; + callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; + callback_data.Flags = flags; + callback_data.Buf = buf; + callback_data.BufTextLen = apply_new_text_length; + callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1); + callback_data.UserData = callback_user_data; + callback(&callback_data); + buf = callback_data.Buf; + buf_size = callback_data.BufSize; + apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1); + IM_ASSERT(apply_new_text_length <= buf_size); + } + + // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. + ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); + value_changed = true; + } + + // Clear temporary user storage + state->UserFlags = 0; + state->UserCallback = NULL; + state->UserCallbackData = NULL; + } + + // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value) + if (clear_active_id && g.ActiveId == id) + ClearActiveID(); + + // Render frame + if (!is_multiline) + { + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + } + + const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size + ImVec2 draw_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding; + ImVec2 text_size(0.0f, 0.0f); + + // Set upper limit of single-line InputTextEx() at 2 million characters strings. The current pathological worst case is a long line + // without any carriage return, which would makes ImFont::RenderText() reserve too many vertices and probably crash. Avoid it altogether. + // Note that we only use this limit on single-line InputText(), so a pathologically large line on a InputTextMultiline() would still crash. + const int buf_display_max_length = 2 * 1024 * 1024; + const char* buf_display = buf_display_from_state ? state->TextA.Data : buf; //-V595 + const char* buf_display_end = NULL; // We have specialized paths below for setting the length + if (is_displaying_hint) + { + buf_display = hint; + buf_display_end = hint + strlen(hint); + } + + // Render text. We currently only render selection when the widget is active or while scrolling. + // FIXME: We could remove the '&& render_cursor' to keep rendering selection when inactive. + if (render_cursor || render_selection) + { + IM_ASSERT(state != NULL); + if (!is_displaying_hint) + buf_display_end = buf_display + state->CurLenA; + + // Render text (with cursor and selection) + // This is going to be messy. We need to: + // - Display the text (this alone can be more easily clipped) + // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation) + // - Measure text height (for scrollbar) + // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort) + // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8. + const ImWchar* text_begin = state->TextW.Data; + ImVec2 cursor_offset, select_start_offset; + + { + // Find lines numbers straddling 'cursor' (slot 0) and 'select_start' (slot 1) positions. + const ImWchar* searches_input_ptr[2] = { NULL, NULL }; + int searches_result_line_no[2] = { -1000, -1000 }; + int searches_remaining = 0; + if (render_cursor) + { + searches_input_ptr[0] = text_begin + state->Stb.cursor; + searches_result_line_no[0] = -1; + searches_remaining++; + } + if (render_selection) + { + searches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); + searches_result_line_no[1] = -1; + searches_remaining++; + } + + // Iterate all lines to find our line numbers + // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter. + searches_remaining += is_multiline ? 1 : 0; + int line_count = 0; + //for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++) // FIXME-OPT: Could use this when wchar_t are 16-bits + for (const ImWchar* s = text_begin; *s != 0; s++) + if (*s == '\n') + { + line_count++; + if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; } + if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; } + } + line_count++; + if (searches_result_line_no[0] == -1) + searches_result_line_no[0] = line_count; + if (searches_result_line_no[1] == -1) + searches_result_line_no[1] = line_count; + + // Calculate 2d position by finding the beginning of the line and measuring distance + cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; + cursor_offset.y = searches_result_line_no[0] * g.FontSize; + if (searches_result_line_no[1] >= 0) + { + select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; + select_start_offset.y = searches_result_line_no[1] * g.FontSize; + } + + // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224) + if (is_multiline) + text_size = ImVec2(size.x, line_count * g.FontSize); + } + + // Scroll + if (render_cursor && state->CursorFollow) + { + // Horizontal scroll in chunks of quarter width + if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll)) + { + const float scroll_increment_x = size.x * 0.25f; + if (cursor_offset.x < state->ScrollX) + state->ScrollX = (float)(int)ImMax(0.0f, cursor_offset.x - scroll_increment_x); + else if (cursor_offset.x - size.x >= state->ScrollX) + state->ScrollX = (float)(int)(cursor_offset.x - size.x + scroll_increment_x); + } + else + { + state->ScrollX = 0.0f; + } + + // Vertical scroll + if (is_multiline) + { + float scroll_y = draw_window->Scroll.y; + if (cursor_offset.y - g.FontSize < scroll_y) + scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize); + else if (cursor_offset.y - size.y >= scroll_y) + scroll_y = cursor_offset.y - size.y; + draw_window->DC.CursorPos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag + draw_window->Scroll.y = scroll_y; + draw_pos.y = draw_window->DC.CursorPos.y; + } + + state->CursorFollow = false; + } + + // Draw selection + const ImVec2 draw_scroll = ImVec2(state->ScrollX, 0.0f); + if (render_selection) + { + const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); + const ImWchar* text_selected_end = text_begin + ImMax(state->Stb.select_start, state->Stb.select_end); + + ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests. + float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection. + float bg_offy_dn = is_multiline ? 0.0f : 2.0f; + ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll; + for (const ImWchar* p = text_selected_begin; p < text_selected_end; ) + { + if (rect_pos.y > clip_rect.w + g.FontSize) + break; + if (rect_pos.y < clip_rect.y) + { + //p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p); // FIXME-OPT: Could use this when wchar_t are 16-bits + //p = p ? p + 1 : text_selected_end; + while (p < text_selected_end) + if (*p++ == '\n') + break; + } + else + { + ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true); + if (rect_size.x <= 0.0f) rect_size.x = (float)(int)(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines + ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos +ImVec2(rect_size.x, bg_offy_dn)); + rect.ClipWith(clip_rect); + if (rect.Overlaps(clip_rect)) + draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color); + } + rect_pos.x = draw_pos.x - draw_scroll.x; + rect_pos.y += g.FontSize; + } + } + + // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash. + if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) + { + ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + } + + // Draw blinking cursor + if (render_cursor) + { + state->CursorAnim += io.DeltaTime; + bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f; + ImVec2 cursor_screen_pos = draw_pos + cursor_offset - draw_scroll; + ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); + if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) + draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text)); + + // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) + if (!is_readonly) + g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); + } + } + else + { + // Render text only (no selection, no cursor) + if (is_multiline) + text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontSize); // We don't need width + else if (!is_displaying_hint && g.ActiveId == id) + buf_display_end = buf_display + state->CurLenA; + else if (!is_displaying_hint) + buf_display_end = buf_display + strlen(buf_display); + + if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) + { + ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + } + } + + if (is_multiline) + { + Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line + EndChildFrame(); + EndGroup(); + } + + if (is_password && !is_displaying_hint) + PopFont(); + + // Log as text + if (g.LogEnabled && !(is_password && !is_displaying_hint)) + LogRenderedText(&draw_pos, buf_display, buf_display_end); + + if (label_size.x > 0) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + if (value_changed) + MarkItemEdited(id); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0) + return enter_pressed; + else + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: ColorEdit, ColorPicker, ColorButton, etc. +//------------------------------------------------------------------------- +// - ColorEdit3() +// - ColorEdit4() +// - ColorPicker3() +// - RenderColorRectWithAlphaCheckerboard() [Internal] +// - ColorPicker4() +// - ColorButton() +// - SetColorEditOptions() +// - ColorTooltip() [Internal] +// - ColorEditOptionsPopup() [Internal] +// - ColorPickerOptionsPopup() [Internal] +//------------------------------------------------------------------------- + +bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags) +{ + return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha); +} + +// Edit colors components (each component in 0.0f..1.0f range). +// See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. +// With typical options: Left-click on colored square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item. +bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const float square_sz = GetFrameHeight(); + const float w_extra = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x); + const float w_items_all = CalcItemWidth() - w_extra; + const char* label_display_end = FindRenderedTextEnd(label); + + BeginGroup(); + PushID(label); + + // If we're not showing any slider there's no point in doing any HSV conversions + const ImGuiColorEditFlags flags_untouched = flags; + if (flags & ImGuiColorEditFlags_NoInputs) + flags = (flags & (~ImGuiColorEditFlags__DisplayMask)) | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_NoOptions; + + // Context menu: display and modify options (before defaults are applied) + if (!(flags & ImGuiColorEditFlags_NoOptions)) + ColorEditOptionsPopup(col, flags); + + // Read stored options + if (!(flags & ImGuiColorEditFlags__DisplayMask)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags__DisplayMask); + if (!(flags & ImGuiColorEditFlags__DataTypeMask)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags__DataTypeMask); + if (!(flags & ImGuiColorEditFlags__PickerMask)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags__PickerMask); + if (!(flags & ImGuiColorEditFlags__InputMask)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags__InputMask); + flags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags__DisplayMask | ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask | ImGuiColorEditFlags__InputMask)); + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__DisplayMask)); // Check that only 1 is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__InputMask)); // Check that only 1 is selected + + const bool alpha = (flags & ImGuiColorEditFlags_NoAlpha) == 0; + const bool hdr = (flags & ImGuiColorEditFlags_HDR) != 0; + const int components = alpha ? 4 : 3; + + // Convert to the formats we need + float f[4] = { col[0], col[1], col[2], alpha ? col[3] : 1.0f }; + if ((flags & ImGuiColorEditFlags_InputHSV) && (flags & ImGuiColorEditFlags_DisplayRGB)) + ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); + else if ((flags & ImGuiColorEditFlags_InputRGB) && (flags & ImGuiColorEditFlags_DisplayHSV)) + ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); + int i[4] = { IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]) }; + + bool value_changed = false; + bool value_changed_as_float = false; + + if ((flags & (ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) + { + // RGB/HSV 0..255 Sliders + const float w_item_one = ImMax(1.0f, (float)(int)((w_items_all - (style.ItemInnerSpacing.x) * (components-1)) / (float)components)); + const float w_item_last = ImMax(1.0f, (float)(int)(w_items_all - (w_item_one + style.ItemInnerSpacing.x) * (components-1))); + + const bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x); + static const char* ids[4] = { "##X", "##Y", "##Z", "##W" }; + static const char* fmt_table_int[3][4] = + { + { "%3d", "%3d", "%3d", "%3d" }, // Short display + { "R:%3d", "G:%3d", "B:%3d", "A:%3d" }, // Long display for RGBA + { "H:%3d", "S:%3d", "V:%3d", "A:%3d" } // Long display for HSVA + }; + static const char* fmt_table_float[3][4] = + { + { "%0.3f", "%0.3f", "%0.3f", "%0.3f" }, // Short display + { "R:%0.3f", "G:%0.3f", "B:%0.3f", "A:%0.3f" }, // Long display for RGBA + { "H:%0.3f", "S:%0.3f", "V:%0.3f", "A:%0.3f" } // Long display for HSVA + }; + const int fmt_idx = hide_prefix ? 0 : (flags & ImGuiColorEditFlags_DisplayHSV) ? 2 : 1; + + PushItemWidth(w_item_one); + for (int n = 0; n < components; n++) + { + if (n > 0) + SameLine(0, style.ItemInnerSpacing.x); + if (n + 1 == components) + PushItemWidth(w_item_last); + if (flags & ImGuiColorEditFlags_Float) + { + value_changed |= DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); + value_changed_as_float |= value_changed; + } + else + { + value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + } + PopItemWidth(); + PopItemWidth(); + } + else if ((flags & ImGuiColorEditFlags_DisplayHex) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) + { + // RGB Hexadecimal Input + char buf[64]; + if (alpha) + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255), ImClamp(i[3],0,255)); + else + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255)); + PushItemWidth(w_items_all); + if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase)) + { + value_changed = true; + char* p = buf; + while (*p == '#' || ImCharIsBlankA(*p)) + p++; + i[0] = i[1] = i[2] = i[3] = 0; + if (alpha) + sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned) + else + sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]); + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + PopItemWidth(); + } + + ImGuiWindow* picker_active_window = NULL; + if (!(flags & ImGuiColorEditFlags_NoSmallPreview)) + { + if (!(flags & ImGuiColorEditFlags_NoInputs)) + SameLine(0, style.ItemInnerSpacing.x); + + const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f); + if (ColorButton("##ColorButton", col_v4, flags)) + { + if (!(flags & ImGuiColorEditFlags_NoPicker)) + { + // Store current color and open a picker + g.ColorPickerRef = col_v4; + OpenPopup("picker"); + SetNextWindowPos(window->DC.LastItemRect.GetBL() + ImVec2(-1,style.ItemSpacing.y)); + } + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + + if (BeginPopup("picker")) + { + picker_active_window = g.CurrentWindow; + if (label != label_display_end) + { + TextEx(label, label_display_end); + Spacing(); + } + ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask | ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar; + ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf; + PushItemWidth(square_sz * 12.0f); // Use 256 + bar sizes? + value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x); + PopItemWidth(); + EndPopup(); + } + } + + if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel)) + { + SameLine(0, style.ItemInnerSpacing.x); + TextEx(label, label_display_end); + } + + // Convert back + if (value_changed && picker_active_window == NULL) + { + if (!value_changed_as_float) + for (int n = 0; n < 4; n++) + f[n] = i[n] / 255.0f; + if ((flags & ImGuiColorEditFlags_DisplayHSV) && (flags & ImGuiColorEditFlags_InputRGB)) + ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); + if ((flags & ImGuiColorEditFlags_DisplayRGB) && (flags & ImGuiColorEditFlags_InputHSV)) + ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); + + col[0] = f[0]; + col[1] = f[1]; + col[2] = f[2]; + if (alpha) + col[3] = f[3]; + } + + PopID(); + EndGroup(); + + // Drag and Drop Target + // NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test. + if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget()) + { + bool accepted_drag_drop = false; + if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + { + memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512 + value_changed = accepted_drag_drop = true; + } + if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + { + memcpy((float*)col, payload->Data, sizeof(float) * components); + value_changed = accepted_drag_drop = true; + } + + // Drag-drop payloads are always RGB + if (accepted_drag_drop && (flags & ImGuiColorEditFlags_InputHSV)) + ColorConvertRGBtoHSV(col[0], col[1], col[2], col[0], col[1], col[2]); + EndDragDropTarget(); + } + + // When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4(). + if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window) + window->DC.LastItemId = g.ActiveId; + + if (value_changed) + MarkItemEdited(window->DC.LastItemId); + + return value_changed; +} + +bool ImGui::ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags) +{ + float col4[4] = { col[0], col[1], col[2], 1.0f }; + if (!ColorPicker4(label, col4, flags | ImGuiColorEditFlags_NoAlpha)) + return false; + col[0] = col4[0]; col[1] = col4[1]; col[2] = col4[2]; + return true; +} + +static inline ImU32 ImAlphaBlendColor(ImU32 col_a, ImU32 col_b) +{ + float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f; + int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t); + int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t); + int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t); + return IM_COL32(r, g, b, 0xFF); +} + +// Helper for ColorPicker4() +// NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that. +// I spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding alltogether. +void ImGui::RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, int rounding_corners_flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF) + { + ImU32 col_bg1 = GetColorU32(ImAlphaBlendColor(IM_COL32(204,204,204,255), col)); + ImU32 col_bg2 = GetColorU32(ImAlphaBlendColor(IM_COL32(128,128,128,255), col)); + window->DrawList->AddRectFilled(p_min, p_max, col_bg1, rounding, rounding_corners_flags); + + int yi = 0; + for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++) + { + float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y); + if (y2 <= y1) + continue; + for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f) + { + float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x); + if (x2 <= x1) + continue; + int rounding_corners_flags_cell = 0; + if (y1 <= p_min.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopRight; } + if (y2 >= p_max.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotRight; } + rounding_corners_flags_cell &= rounding_corners_flags; + window->DrawList->AddRectFilled(ImVec2(x1,y1), ImVec2(x2,y2), col_bg2, rounding_corners_flags_cell ? rounding : 0.0f, rounding_corners_flags_cell); + } + } + } + else + { + window->DrawList->AddRectFilled(p_min, p_max, col, rounding, rounding_corners_flags); + } +} + +// Helper for ColorPicker4() +static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w) +{ + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32_BLACK); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32_WHITE); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32_BLACK); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32_WHITE); +} + +// Note: ColorPicker4() only accesses 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. +// (In C++ the 'float col[4]' notation for a function argument is equivalent to 'float* col', we only specify a size to facilitate understanding of the code.) +// FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if automatic height makes a vertical scrollbar appears, affecting automatic width..) +bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags, const float* ref_col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImDrawList* draw_list = window->DrawList; + ImGuiStyle& style = g.Style; + ImGuiIO& io = g.IO; + + PushID(label); + BeginGroup(); + + if (!(flags & ImGuiColorEditFlags_NoSidePreview)) + flags |= ImGuiColorEditFlags_NoSmallPreview; + + // Context menu: display and store options. + if (!(flags & ImGuiColorEditFlags_NoOptions)) + ColorPickerOptionsPopup(col, flags); + + // Read stored options + if (!(flags & ImGuiColorEditFlags__PickerMask)) + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags__PickerMask) ? g.ColorEditOptions : ImGuiColorEditFlags__OptionsDefault) & ImGuiColorEditFlags__PickerMask; + if (!(flags & ImGuiColorEditFlags__InputMask)) + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags__InputMask) ? g.ColorEditOptions : ImGuiColorEditFlags__OptionsDefault) & ImGuiColorEditFlags__InputMask; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__PickerMask)); // Check that only 1 is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__InputMask)); // Check that only 1 is selected + if (!(flags & ImGuiColorEditFlags_NoOptions)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_AlphaBar); + + // Setup + int components = (flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4; + bool alpha_bar = (flags & ImGuiColorEditFlags_AlphaBar) && !(flags & ImGuiColorEditFlags_NoAlpha); + ImVec2 picker_pos = window->DC.CursorPos; + float square_sz = GetFrameHeight(); + float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars + float sv_picker_size = ImMax(bars_width * 1, CalcItemWidth() - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box + float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x; + float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x; + float bars_triangles_half_sz = (float)(int)(bars_width * 0.20f); + + float backup_initial_col[4]; + memcpy(backup_initial_col, col, components * sizeof(float)); + + float wheel_thickness = sv_picker_size * 0.08f; + float wheel_r_outer = sv_picker_size * 0.50f; + float wheel_r_inner = wheel_r_outer - wheel_thickness; + ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size*0.5f); + + // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic. + float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f); + ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point. + ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point. + ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point. + + float H = col[0], S = col[1], V = col[2]; + float R = col[0], G = col[1], B = col[2]; + if (flags & ImGuiColorEditFlags_InputRGB) + ColorConvertRGBtoHSV(R, G, B, H, S, V); + else if (flags & ImGuiColorEditFlags_InputHSV) + ColorConvertHSVtoRGB(H, S, V, R, G, B); + + bool value_changed = false, value_changed_h = false, value_changed_sv = false; + + PushItemFlag(ImGuiItemFlags_NoNav, true); + if (flags & ImGuiColorEditFlags_PickerHueWheel) + { + // Hue wheel + SV triangle logic + InvisibleButton("hsv", ImVec2(sv_picker_size + style.ItemInnerSpacing.x + bars_width, sv_picker_size)); + if (IsItemActive()) + { + ImVec2 initial_off = g.IO.MouseClickedPos[0] - wheel_center; + ImVec2 current_off = g.IO.MousePos - wheel_center; + float initial_dist2 = ImLengthSqr(initial_off); + if (initial_dist2 >= (wheel_r_inner-1)*(wheel_r_inner-1) && initial_dist2 <= (wheel_r_outer+1)*(wheel_r_outer+1)) + { + // Interactive with Hue wheel + H = ImAtan2(current_off.y, current_off.x) / IM_PI*0.5f; + if (H < 0.0f) + H += 1.0f; + value_changed = value_changed_h = true; + } + float cos_hue_angle = ImCos(-H * 2.0f * IM_PI); + float sin_hue_angle = ImSin(-H * 2.0f * IM_PI); + if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle))) + { + // Interacting with SV triangle + ImVec2 current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle); + if (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated)) + current_off_unrotated = ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated); + float uu, vv, ww; + ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated, uu, vv, ww); + V = ImClamp(1.0f - vv, 0.0001f, 1.0f); + S = ImClamp(uu / V, 0.0001f, 1.0f); + value_changed = value_changed_sv = true; + } + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + } + else if (flags & ImGuiColorEditFlags_PickerHueBar) + { + // SV rectangle logic + InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size)); + if (IsItemActive()) + { + S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size-1)); + V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1)); + value_changed = value_changed_sv = true; + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + + // Hue bar logic + SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y)); + InvisibleButton("hue", ImVec2(bars_width, sv_picker_size)); + if (IsItemActive()) + { + H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1)); + value_changed = value_changed_h = true; + } + } + + // Alpha bar logic + if (alpha_bar) + { + SetCursorScreenPos(ImVec2(bar1_pos_x, picker_pos.y)); + InvisibleButton("alpha", ImVec2(bars_width, sv_picker_size)); + if (IsItemActive()) + { + col[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1)); + value_changed = true; + } + } + PopItemFlag(); // ImGuiItemFlags_NoNav + + if (!(flags & ImGuiColorEditFlags_NoSidePreview)) + { + SameLine(0, style.ItemInnerSpacing.x); + BeginGroup(); + } + + if (!(flags & ImGuiColorEditFlags_NoLabel)) + { + const char* label_display_end = FindRenderedTextEnd(label); + if (label != label_display_end) + { + if ((flags & ImGuiColorEditFlags_NoSidePreview)) + SameLine(0, style.ItemInnerSpacing.x); + TextEx(label, label_display_end); + } + } + + if (!(flags & ImGuiColorEditFlags_NoSidePreview)) + { + PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true); + ImVec4 col_v4(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); + if ((flags & ImGuiColorEditFlags_NoLabel)) + Text("Current"); + + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip; + ColorButton("##current", col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2)); + if (ref_col != NULL) + { + Text("Original"); + ImVec4 ref_col_v4(ref_col[0], ref_col[1], ref_col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[3]); + if (ColorButton("##original", ref_col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2))) + { + memcpy(col, ref_col, components * sizeof(float)); + value_changed = true; + } + } + PopItemFlag(); + EndGroup(); + } + + // Convert back color to RGB + if (value_changed_h || value_changed_sv) + { + if (flags & ImGuiColorEditFlags_InputRGB) + { + ColorConvertHSVtoRGB(H >= 1.0f ? H - 10 * 1e-6f : H, S > 0.0f ? S : 10*1e-6f, V > 0.0f ? V : 1e-6f, col[0], col[1], col[2]); + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + col[0] = H; + col[1] = S; + col[2] = V; + } + } + + // R,G,B and H,S,V slider color editor + bool value_changed_fix_hue_wrap = false; + if ((flags & ImGuiColorEditFlags_NoInputs) == 0) + { + PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x); + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf; + ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker; + if (flags & ImGuiColorEditFlags_DisplayRGB || (flags & ImGuiColorEditFlags__DisplayMask) == 0) + if (ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_DisplayRGB)) + { + // FIXME: Hackily differenciating using the DragInt (ActiveId != 0 && !ActiveIdAllowOverlap) vs. using the InputText or DropTarget. + // For the later we don't want to run the hue-wrap canceling code. If you are well versed in HSV picker please provide your input! (See #2050) + value_changed_fix_hue_wrap = (g.ActiveId != 0 && !g.ActiveIdAllowOverlap); + value_changed = true; + } + if (flags & ImGuiColorEditFlags_DisplayHSV || (flags & ImGuiColorEditFlags__DisplayMask) == 0) + value_changed |= ColorEdit4("##hsv", col, sub_flags | ImGuiColorEditFlags_DisplayHSV); + if (flags & ImGuiColorEditFlags_DisplayHex || (flags & ImGuiColorEditFlags__DisplayMask) == 0) + value_changed |= ColorEdit4("##hex", col, sub_flags | ImGuiColorEditFlags_DisplayHex); + PopItemWidth(); + } + + // Try to cancel hue wrap (after ColorEdit4 call), if any + if (value_changed_fix_hue_wrap && (flags & ImGuiColorEditFlags_InputRGB)) + { + float new_H, new_S, new_V; + ColorConvertRGBtoHSV(col[0], col[1], col[2], new_H, new_S, new_V); + if (new_H <= 0 && H > 0) + { + if (new_V <= 0 && V != new_V) + ColorConvertHSVtoRGB(H, S, new_V <= 0 ? V * 0.5f : new_V, col[0], col[1], col[2]); + else if (new_S <= 0) + ColorConvertHSVtoRGB(H, new_S <= 0 ? S * 0.5f : new_S, new_V, col[0], col[1], col[2]); + } + } + + if (value_changed) + { + if (flags & ImGuiColorEditFlags_InputRGB) + { + R = col[0]; + G = col[1]; + B = col[2]; + ColorConvertRGBtoHSV(R, G, B, H, S, V); + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + H = col[0]; + S = col[1]; + V = col[2]; + ColorConvertHSVtoRGB(H, S, V, R, G, B); + } + } + + ImVec4 hue_color_f(1, 1, 1, 1); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z); + ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f); + ImU32 col32_no_alpha = ColorConvertFloat4ToU32(ImVec4(R, G, B, 1.0f)); + + const ImU32 hue_colors[6+1] = { IM_COL32(255,0,0,255), IM_COL32(255,255,0,255), IM_COL32(0,255,0,255), IM_COL32(0,255,255,255), IM_COL32(0,0,255,255), IM_COL32(255,0,255,255), IM_COL32(255,0,0,255) }; + ImVec2 sv_cursor_pos; + + if (flags & ImGuiColorEditFlags_PickerHueWheel) + { + // Render Hue Wheel + const float aeps = 1.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out). + const int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12); + for (int n = 0; n < 6; n++) + { + const float a0 = (n) /6.0f * 2.0f * IM_PI - aeps; + const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps; + const int vert_start_idx = draw_list->VtxBuffer.Size; + draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc); + draw_list->PathStroke(IM_COL32_WHITE, false, wheel_thickness); + const int vert_end_idx = draw_list->VtxBuffer.Size; + + // Paint colors over existing vertices + ImVec2 gradient_p0(wheel_center.x + ImCos(a0) * wheel_r_inner, wheel_center.y + ImSin(a0) * wheel_r_inner); + ImVec2 gradient_p1(wheel_center.x + ImCos(a1) * wheel_r_inner, wheel_center.y + ImSin(a1) * wheel_r_inner); + ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, hue_colors[n], hue_colors[n+1]); + } + + // Render Cursor + preview on Hue Wheel + float cos_hue_angle = ImCos(H * 2.0f * IM_PI); + float sin_hue_angle = ImSin(H * 2.0f * IM_PI); + ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner+wheel_r_outer)*0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner+wheel_r_outer)*0.5f); + float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f; + int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32); + draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments); + draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad+1, IM_COL32(128,128,128,255), hue_cursor_segments); + draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, IM_COL32_WHITE, hue_cursor_segments); + + // Render SV triangle (rotated according to hue) + ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle); + ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle); + ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle); + ImVec2 uv_white = GetFontTexUvWhitePixel(); + draw_list->PrimReserve(6, 6); + draw_list->PrimVtx(tra, uv_white, hue_color32); + draw_list->PrimVtx(trb, uv_white, hue_color32); + draw_list->PrimVtx(trc, uv_white, IM_COL32_WHITE); + draw_list->PrimVtx(tra, uv_white, IM_COL32_BLACK_TRANS); + draw_list->PrimVtx(trb, uv_white, IM_COL32_BLACK); + draw_list->PrimVtx(trc, uv_white, IM_COL32_BLACK_TRANS); + draw_list->AddTriangle(tra, trb, trc, IM_COL32(128,128,128,255), 1.5f); + sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V)); + } + else if (flags & ImGuiColorEditFlags_PickerHueBar) + { + // Render SV Square + draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), IM_COL32_WHITE, hue_color32, hue_color32, IM_COL32_WHITE); + draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), IM_COL32_BLACK_TRANS, IM_COL32_BLACK_TRANS, IM_COL32_BLACK, IM_COL32_BLACK); + RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), 0.0f); + sv_cursor_pos.x = ImClamp((float)(int)(picker_pos.x + ImSaturate(S) * sv_picker_size + 0.5f), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much + sv_cursor_pos.y = ImClamp((float)(int)(picker_pos.y + ImSaturate(1 - V) * sv_picker_size + 0.5f), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2); + + // Render Hue Bar + for (int i = 0; i < 6; ++i) + draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), hue_colors[i], hue_colors[i], hue_colors[i + 1], hue_colors[i + 1]); + float bar0_line_y = (float)(int)(picker_pos.y + H * sv_picker_size + 0.5f); + RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f); + RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f); + } + + // Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range) + float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f; + draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, col32_no_alpha, 12); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad+1, IM_COL32(128,128,128,255), 12); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, IM_COL32_WHITE, 12); + + // Render alpha bar + if (alpha_bar) + { + float alpha = ImSaturate(col[3]); + ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size); + RenderColorRectWithAlphaCheckerboard(bar1_bb.Min, bar1_bb.Max, IM_COL32(0,0,0,0), bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f)); + draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, col32_no_alpha, col32_no_alpha, col32_no_alpha & ~IM_COL32_A_MASK, col32_no_alpha & ~IM_COL32_A_MASK); + float bar1_line_y = (float)(int)(picker_pos.y + (1.0f - alpha) * sv_picker_size + 0.5f); + RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f); + RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f); + } + + EndGroup(); + + if (value_changed && memcmp(backup_initial_col, col, components * sizeof(float)) == 0) + value_changed = false; + if (value_changed) + MarkItemEdited(window->DC.LastItemId); + + PopID(); + + return value_changed; +} + +// A little colored square. Return true when clicked. +// FIXME: May want to display/ignore the alpha component in the color display? Yet show it in the tooltip. +// 'desc_id' is not called 'label' because we don't display it next to the button, but only in the tooltip. +// Note that 'col' may be encoded in HSV if ImGuiColorEditFlags_InputHSV is set. +bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, ImVec2 size) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiID id = window->GetID(desc_id); + float default_size = GetFrameHeight(); + if (size.x == 0.0f) + size.x = default_size; + if (size.y == 0.0f) + size.y = default_size; + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(bb, (size.y >= default_size) ? g.Style.FramePadding.y : 0.0f); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + + if (flags & ImGuiColorEditFlags_NoAlpha) + flags &= ~(ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf); + + ImVec4 col_rgb = col; + if (flags & ImGuiColorEditFlags_InputHSV) + ColorConvertHSVtoRGB(col_rgb.x, col_rgb.y, col_rgb.z, col_rgb.x, col_rgb.y, col_rgb.z); + + ImVec4 col_rgb_without_alpha(col_rgb.x, col_rgb.y, col_rgb.z, 1.0f); + float grid_step = ImMin(size.x, size.y) / 2.99f; + float rounding = ImMin(g.Style.FrameRounding, grid_step * 0.5f); + ImRect bb_inner = bb; + float off = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is enabled. This offset seemed like a good middle ground to reduce those artifacts. + bb_inner.Expand(off); + if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f) + { + float mid_x = (float)(int)((bb_inner.Min.x + bb_inner.Max.x) * 0.5f + 0.5f); + RenderColorRectWithAlphaCheckerboard(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawCornerFlags_TopRight| ImDrawCornerFlags_BotRight); + window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotLeft); + } + else + { + // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha + ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col_rgb : col_rgb_without_alpha; + if (col_source.w < 1.0f) + RenderColorRectWithAlphaCheckerboard(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding); + else + window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding, ImDrawCornerFlags_All); + } + RenderNavHighlight(bb, id); + if (g.Style.FrameBorderSize > 0.0f) + RenderFrameBorder(bb.Min, bb.Max, rounding); + else + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border + + // Drag and Drop Source + // NB: The ActiveId test is merely an optional micro-optimization, BeginDragDropSource() does the same test. + if (g.ActiveId == id && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropSource()) + { + if (flags & ImGuiColorEditFlags_NoAlpha) + SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F, &col_rgb, sizeof(float) * 3, ImGuiCond_Once); + else + SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, &col_rgb, sizeof(float) * 4, ImGuiCond_Once); + ColorButton(desc_id, col, flags); + SameLine(); + TextEx("Color"); + EndDragDropSource(); + } + + // Tooltip + if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered) + ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); + + if (pressed) + MarkItemEdited(id); + + return pressed; +} + +// Initialize/override default color options +void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags) +{ + ImGuiContext& g = *GImGui; + if ((flags & ImGuiColorEditFlags__DisplayMask) == 0) + flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__DisplayMask; + if ((flags & ImGuiColorEditFlags__DataTypeMask) == 0) + flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__DataTypeMask; + if ((flags & ImGuiColorEditFlags__PickerMask) == 0) + flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__PickerMask; + if ((flags & ImGuiColorEditFlags__InputMask) == 0) + flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__InputMask; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__DisplayMask)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__DataTypeMask)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__PickerMask)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__InputMask)); // Check only 1 option is selected + g.ColorEditOptions = flags; +} + +// Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. +void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags) +{ + ImGuiContext& g = *GImGui; + + BeginTooltipEx(0, true); + const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text; + if (text_end > text) + { + TextEx(text, text_end); + Separator(); + } + + ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2); + ImVec4 cf(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); + int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); + ColorButton("##preview", cf, (flags & (ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)) | ImGuiColorEditFlags_NoTooltip, sz); + SameLine(); + if ((flags & ImGuiColorEditFlags_InputRGB) || !(flags & ImGuiColorEditFlags__InputMask)) + { + if (flags & ImGuiColorEditFlags_NoAlpha) + Text("#%02X%02X%02X\nR: %d, G: %d, B: %d\n(%.3f, %.3f, %.3f)", cr, cg, cb, cr, cg, cb, col[0], col[1], col[2]); + else + Text("#%02X%02X%02X%02X\nR:%d, G:%d, B:%d, A:%d\n(%.3f, %.3f, %.3f, %.3f)", cr, cg, cb, ca, cr, cg, cb, ca, col[0], col[1], col[2], col[3]); + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + if (flags & ImGuiColorEditFlags_NoAlpha) + Text("H: %.3f, S: %.3f, V: %.3f", col[0], col[1], col[2]); + else + Text("H: %.3f, S: %.3f, V: %.3f, A: %.3f", col[0], col[1], col[2], col[3]); + } + EndTooltip(); +} + +void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) +{ + bool allow_opt_inputs = !(flags & ImGuiColorEditFlags__DisplayMask); + bool allow_opt_datatype = !(flags & ImGuiColorEditFlags__DataTypeMask); + if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context")) + return; + ImGuiContext& g = *GImGui; + ImGuiColorEditFlags opts = g.ColorEditOptions; + if (allow_opt_inputs) + { + if (RadioButton("RGB", (opts & ImGuiColorEditFlags_DisplayRGB) != 0)) opts = (opts & ~ImGuiColorEditFlags__DisplayMask) | ImGuiColorEditFlags_DisplayRGB; + if (RadioButton("HSV", (opts & ImGuiColorEditFlags_DisplayHSV) != 0)) opts = (opts & ~ImGuiColorEditFlags__DisplayMask) | ImGuiColorEditFlags_DisplayHSV; + if (RadioButton("Hex", (opts & ImGuiColorEditFlags_DisplayHex) != 0)) opts = (opts & ~ImGuiColorEditFlags__DisplayMask) | ImGuiColorEditFlags_DisplayHex; + } + if (allow_opt_datatype) + { + if (allow_opt_inputs) Separator(); + if (RadioButton("0..255", (opts & ImGuiColorEditFlags_Uint8) != 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Uint8; + if (RadioButton("0.00..1.00", (opts & ImGuiColorEditFlags_Float) != 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Float; + } + + if (allow_opt_inputs || allow_opt_datatype) + Separator(); + if (Button("Copy as..", ImVec2(-1,0))) + OpenPopup("Copy"); + if (BeginPopup("Copy")) + { + int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); + char buf[64]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%.3ff, %.3ff, %.3ff, %.3ff)", col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); + if (Selectable(buf)) + SetClipboardText(buf); + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%d,%d,%d,%d)", cr, cg, cb, ca); + if (Selectable(buf)) + SetClipboardText(buf); + if (flags & ImGuiColorEditFlags_NoAlpha) + ImFormatString(buf, IM_ARRAYSIZE(buf), "0x%02X%02X%02X", cr, cg, cb); + else + ImFormatString(buf, IM_ARRAYSIZE(buf), "0x%02X%02X%02X%02X", cr, cg, cb, ca); + if (Selectable(buf)) + SetClipboardText(buf); + EndPopup(); + } + + g.ColorEditOptions = opts; + EndPopup(); +} + +void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags) +{ + bool allow_opt_picker = !(flags & ImGuiColorEditFlags__PickerMask); + bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar); + if ((!allow_opt_picker && !allow_opt_alpha_bar) || !BeginPopup("context")) + return; + ImGuiContext& g = *GImGui; + if (allow_opt_picker) + { + ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function + PushItemWidth(picker_size.x); + for (int picker_type = 0; picker_type < 2; picker_type++) + { + // Draw small/thumbnail version of each picker type (over an invisible button for selection) + if (picker_type > 0) Separator(); + PushID(picker_type); + ImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoInputs|ImGuiColorEditFlags_NoOptions|ImGuiColorEditFlags_NoLabel|ImGuiColorEditFlags_NoSidePreview|(flags & ImGuiColorEditFlags_NoAlpha); + if (picker_type == 0) picker_flags |= ImGuiColorEditFlags_PickerHueBar; + if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel; + ImVec2 backup_pos = GetCursorScreenPos(); + if (Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup + g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags__PickerMask) | (picker_flags & ImGuiColorEditFlags__PickerMask); + SetCursorScreenPos(backup_pos); + ImVec4 dummy_ref_col; + memcpy(&dummy_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4)); + ColorPicker4("##dummypicker", &dummy_ref_col.x, picker_flags); + PopID(); + } + PopItemWidth(); + } + if (allow_opt_alpha_bar) + { + if (allow_opt_picker) Separator(); + CheckboxFlags("Alpha Bar", (unsigned int*)&g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); + } + EndPopup(); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: TreeNode, CollapsingHeader, etc. +//------------------------------------------------------------------------- +// - TreeNode() +// - TreeNodeV() +// - TreeNodeEx() +// - TreeNodeExV() +// - TreeNodeBehavior() [Internal] +// - TreePush() +// - TreePop() +// - TreeAdvanceToLabelPos() +// - GetTreeNodeToLabelSpacing() +// - SetNextTreeNodeOpen() +// - CollapsingHeader() +//------------------------------------------------------------------------- + +bool ImGui::TreeNode(const char* str_id, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(str_id, 0, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(ptr_id, 0, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNode(const char* label) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + return TreeNodeBehavior(window->GetID(label), 0, label, NULL); +} + +bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) +{ + return TreeNodeExV(str_id, 0, fmt, args); +} + +bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args) +{ + return TreeNodeExV(ptr_id, 0, fmt, args); +} + +bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + return TreeNodeBehavior(window->GetID(label), flags, label, NULL); +} + +bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(str_id, flags, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(ptr_id, flags, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end); +} + +bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end); +} + +bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) +{ + if (flags & ImGuiTreeNodeFlags_Leaf) + return true; + + // We only write to the tree storage if the user clicks (or explicitly use SetNextTreeNode*** functions) + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiStorage* storage = window->DC.StateStorage; + + bool is_open; + if (g.NextTreeNodeOpenCond != 0) + { + if (g.NextTreeNodeOpenCond & ImGuiCond_Always) + { + is_open = g.NextTreeNodeOpenVal; + storage->SetInt(id, is_open); + } + else + { + // We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved persistently. + const int stored_value = storage->GetInt(id, -1); + if (stored_value == -1) + { + is_open = g.NextTreeNodeOpenVal; + storage->SetInt(id, is_open); + } + else + { + is_open = stored_value != 0; + } + } + g.NextTreeNodeOpenCond = 0; + } + else + { + is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0; + } + + // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior). + // NB- If we are above max depth we still allow manually opened nodes to be logged. + if (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && (window->DC.TreeDepth - g.LogDepthRef) < g.LogDepthToExpand) + is_open = true; + + return is_open; +} + +bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0; + const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, 0.0f); + + if (!label_end) + label_end = FindRenderedTextEnd(label); + const ImVec2 label_size = CalcTextSize(label, label_end, false); + + // We vertically grow up to current line height up the typical widget height. + const float text_base_offset_y = ImMax(padding.y, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it + const float frame_height = ImMax(ImMin(window->DC.CurrentLineSize.y, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2); + ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(window->Pos.x + GetContentRegionMax().x, window->DC.CursorPos.y + frame_height)); + if (display_frame) + { + // Framed header expand a little outside the default padding + frame_bb.Min.x -= (float)(int)(window->WindowPadding.x*0.5f) - 1; + frame_bb.Max.x += (float)(int)(window->WindowPadding.x*0.5f) - 1; + } + + const float text_offset_x = (g.FontSize + (display_frame ? padding.x*3 : padding.x*2)); // Collapser arrow width + Spacing + const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser + ItemSize(ImVec2(text_width, frame_height), text_base_offset_y); + + // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing + // (Ideally we'd want to add a flag for the user to specify if we want the hit test to be done up to the right side of the content or not) + const ImRect interact_bb = display_frame ? frame_bb : ImRect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + text_width + style.ItemSpacing.x*2, frame_bb.Max.y); + bool is_open = TreeNodeBehaviorIsOpen(id, flags); + bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; + + // Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child. + // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). + // This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero. + if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + window->DC.TreeDepthMayJumpToParentOnPop |= (1 << window->DC.TreeDepth); + + bool item_add = ItemAdd(interact_bb, id); + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; + window->DC.LastItemDisplayRect = frame_bb; + + if (!item_add) + { + if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + TreePushRawID(id); + IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + return is_open; + } + + // Flags that affects opening behavior: + // - 0 (default) .................... single-click anywhere to open + // - OpenOnDoubleClick .............. double-click anywhere to open + // - OpenOnArrow .................... single-click on arrow to open + // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open + ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers; + if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) + button_flags |= ImGuiButtonFlags_AllowItemOverlap; + if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) + button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0); + if (!is_leaf) + button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; + + bool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0; + bool hovered, held; + bool pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); + bool toggled = false; + if (!is_leaf) + { + if (pressed) + { + toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) || (g.NavActivateId == id); + if (flags & ImGuiTreeNodeFlags_OpenOnArrow) + toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + text_offset_x, interact_bb.Max.y)) && (!g.NavDisableMouseHover); + if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) + toggled |= g.IO.MouseDoubleClicked[0]; + if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. + toggled = false; + } + + if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Left && is_open) + { + toggled = true; + NavMoveRequestCancel(); + } + if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority? + { + toggled = true; + NavMoveRequestCancel(); + } + + if (toggled) + { + is_open = !is_open; + window->DC.StateStorage->SetInt(id, is_open); + } + } + if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) + SetItemAllowOverlap(); + + // Render + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + const ImVec2 text_pos = frame_bb.Min + ImVec2(text_offset_x, text_base_offset_y); + ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_TypeThin; + if (display_frame) + { + // Framed type + RenderFrame(frame_bb.Min, frame_bb.Max, col, true, style.FrameRounding); + RenderNavHighlight(frame_bb, id, nav_highlight_flags); + RenderArrow(frame_bb.Min + ImVec2(padding.x, text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f); + if (g.LogEnabled) + { + // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here. + const char log_prefix[] = "\n##"; + const char log_suffix[] = "##"; + LogRenderedText(&text_pos, log_prefix, log_prefix+3); + RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); + LogRenderedText(&text_pos, log_suffix, log_suffix+2); + } + else + { + RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); + } + } + else + { + // Unframed typed for tree nodes + if (hovered || selected) + { + RenderFrame(frame_bb.Min, frame_bb.Max, col, false); + RenderNavHighlight(frame_bb, id, nav_highlight_flags); + } + + if (flags & ImGuiTreeNodeFlags_Bullet) + RenderBullet(frame_bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y)); + else if (!is_leaf) + RenderArrow(frame_bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f); + if (g.LogEnabled) + LogRenderedText(&text_pos, ">"); + RenderText(text_pos, label, label_end, false); + } + + if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + TreePushRawID(id); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + return is_open; +} + +void ImGui::TreePush(const char* str_id) +{ + ImGuiWindow* window = GetCurrentWindow(); + Indent(); + window->DC.TreeDepth++; + PushID(str_id ? str_id : "#TreePush"); +} + +void ImGui::TreePush(const void* ptr_id) +{ + ImGuiWindow* window = GetCurrentWindow(); + Indent(); + window->DC.TreeDepth++; + PushID(ptr_id ? ptr_id : (const void*)"#TreePush"); +} + +void ImGui::TreePushRawID(ImGuiID id) +{ + ImGuiWindow* window = GetCurrentWindow(); + Indent(); + window->DC.TreeDepth++; + window->IDStack.push_back(id); +} + +void ImGui::TreePop() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + Unindent(); + + window->DC.TreeDepth--; + if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) + if (g.NavIdIsAlive && (window->DC.TreeDepthMayJumpToParentOnPop & (1 << window->DC.TreeDepth))) + { + SetNavID(window->IDStack.back(), g.NavLayer); + NavMoveRequestCancel(); + } + window->DC.TreeDepthMayJumpToParentOnPop &= (1 << window->DC.TreeDepth) - 1; + + IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much. + PopID(); +} + +void ImGui::TreeAdvanceToLabelPos() +{ + ImGuiContext& g = *GImGui; + g.CurrentWindow->DC.CursorPos.x += GetTreeNodeToLabelSpacing(); +} + +// Horizontal distance preceding label when using TreeNode() or Bullet() +float ImGui::GetTreeNodeToLabelSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + (g.Style.FramePadding.x * 2.0f); +} + +void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + if (g.CurrentWindow->SkipItems) + return; + g.NextTreeNodeOpenVal = is_open; + g.NextTreeNodeOpenCond = cond ? cond : ImGuiCond_Always; +} + +// CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag). +// This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode(). +bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + return TreeNodeBehavior(window->GetID(label), flags | ImGuiTreeNodeFlags_CollapsingHeader, label); +} + +bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + if (p_open && !*p_open) + return false; + + ImGuiID id = window->GetID(label); + bool is_open = TreeNodeBehavior(id, flags | ImGuiTreeNodeFlags_CollapsingHeader | (p_open ? ImGuiTreeNodeFlags_AllowItemOverlap : 0), label); + if (p_open) + { + // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. + ImGuiContext& g = *GImGui; + ImGuiItemHoveredDataBackup last_item_backup; + float button_radius = g.FontSize * 0.5f; + ImVec2 button_center = ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_radius, window->DC.LastItemRect.GetCenter().y); + if (CloseButton(window->GetID((void*)((intptr_t)id+1)), button_center, button_radius)) + *p_open = false; + last_item_backup.Restore(); + } + + return is_open; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Selectable +//------------------------------------------------------------------------- +// - Selectable() +//------------------------------------------------------------------------- + +// Tip: pass a non-visible label (e.g. "##dummy") then you can use the space to draw other text or image. +// But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID or use ##unique_id. +bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) // FIXME-OPT: Avoid if vertically clipped. + PopClipRect(); + + ImGuiID id = window->GetID(label); + ImVec2 label_size = CalcTextSize(label, NULL, true); + ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); + ImVec2 pos = window->DC.CursorPos; + pos.y += window->DC.CurrentLineTextBaseOffset; + ImRect bb_inner(pos, pos + size); + ItemSize(bb_inner); + + // Fill horizontal space. + ImVec2 window_padding = window->WindowPadding; + float max_x = (flags & ImGuiSelectableFlags_SpanAllColumns) ? GetWindowContentRegionMax().x : GetContentRegionMax().x; + float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - pos.x); + ImVec2 size_draw((size_arg.x != 0 && !(flags & ImGuiSelectableFlags_DrawFillAvailWidth)) ? size_arg.x : w_draw, size_arg.y != 0.0f ? size_arg.y : size.y); + ImRect bb(pos, pos + size_draw); + if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_DrawFillAvailWidth)) + bb.Max.x += window_padding.x; + + // Selectables are tightly packed together, we extend the box to cover spacing between selectable. + float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f); + float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f); + float spacing_R = style.ItemSpacing.x - spacing_L; + float spacing_D = style.ItemSpacing.y - spacing_U; + bb.Min.x -= spacing_L; + bb.Min.y -= spacing_U; + bb.Max.x += spacing_R; + bb.Max.y += spacing_D; + + bool item_add; + if (flags & ImGuiSelectableFlags_Disabled) + { + ImGuiItemFlags backup_item_flags = window->DC.ItemFlags; + window->DC.ItemFlags |= ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNavDefaultFocus; + item_add = ItemAdd(bb, id); + window->DC.ItemFlags = backup_item_flags; + } + else + { + item_add = ItemAdd(bb, id); + } + if (!item_add) + { + if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) + PushColumnClipRect(); + return false; + } + + // We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries + ImGuiButtonFlags button_flags = 0; + if (flags & ImGuiSelectableFlags_NoHoldingActiveID) button_flags |= ImGuiButtonFlags_NoHoldingActiveID; + if (flags & ImGuiSelectableFlags_PressedOnClick) button_flags |= ImGuiButtonFlags_PressedOnClick; + if (flags & ImGuiSelectableFlags_PressedOnRelease) button_flags |= ImGuiButtonFlags_PressedOnRelease; + if (flags & ImGuiSelectableFlags_Disabled) button_flags |= ImGuiButtonFlags_Disabled; + if (flags & ImGuiSelectableFlags_AllowDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; + if (flags & ImGuiSelectableFlags_Disabled) + selected = false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + // Hovering selectable with mouse updates NavId accordingly so navigation can be resumed with gamepad/keyboard (this doesn't happen on most widgets) + if (pressed || hovered) + if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) + { + g.NavDisableHighlight = true; + SetNavID(id, window->DC.NavLayerCurrent); + } + if (pressed) + MarkItemEdited(id); + + // Render + if (hovered || selected) + { + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(bb.Min, bb.Max, col, false, 0.0f); + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); + } + + if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) + { + PushColumnClipRect(); + bb.Max.x -= (GetContentRegionMax().x - max_x); + } + + if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); + RenderTextClipped(bb_inner.Min, bb_inner.Max, label, NULL, &label_size, style.SelectableTextAlign, &bb); + if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); + + // Automatically close popups + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(window->DC.ItemFlags & ImGuiItemFlags_SelectableDontClosePopup)) + CloseCurrentPopup(); + return pressed; +} + +bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) +{ + if (Selectable(label, *p_selected, flags, size_arg)) + { + *p_selected = !*p_selected; + return true; + } + return false; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: ListBox +//------------------------------------------------------------------------- +// - ListBox() +// - ListBoxHeader() +// - ListBoxFooter() +//------------------------------------------------------------------------- + +// FIXME: In principle this function should be called BeginListBox(). We should rename it after re-evaluating if we want to keep the same signature. +// Helper to calculate the size of a listbox and display a label on the right. +// Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an non-visible label e.g. "##empty" +bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImGuiStyle& style = GetStyle(); + const ImGuiID id = GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); + ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); + ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); + ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy. + + if (!IsRectVisible(bb.Min, bb.Max)) + { + ItemSize(bb.GetSize(), style.FramePadding.y); + ItemAdd(bb, 0, &frame_bb); + return false; + } + + BeginGroup(); + if (label_size.x > 0) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + BeginChildFrame(id, frame_bb.GetSize()); + return true; +} + +// FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. +bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items) +{ + // Size default to hold ~7.25 items. + // We add +25% worth of item height to allow the user to see at a glance if there are more items up/down, without looking at the scrollbar. + // We don't add this extra bit if items_count <= height_in_items. It is slightly dodgy, because it means a dynamic list of items will make the widget resize occasionally when it crosses that size. + // I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution. + if (height_in_items < 0) + height_in_items = ImMin(items_count, 7); + const ImGuiStyle& style = GetStyle(); + float height_in_items_f = (height_in_items < items_count) ? (height_in_items + 0.25f) : (height_in_items + 0.00f); + + // We include ItemSpacing.y so that a list sized for the exact number of items doesn't make a scrollbar appears. We could also enforce that by passing a flag to BeginChild(). + ImVec2 size; + size.x = 0.0f; + size.y = GetTextLineHeightWithSpacing() * height_in_items_f + style.FramePadding.y * 2.0f; + return ListBoxHeader(label, size); +} + +// FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. +void ImGui::ListBoxFooter() +{ + ImGuiWindow* parent_window = GetCurrentWindow()->ParentWindow; + const ImRect bb = parent_window->DC.LastItemRect; + const ImGuiStyle& style = GetStyle(); + + EndChildFrame(); + + // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect) + // We call SameLine() to restore DC.CurrentLine* data + SameLine(); + parent_window->DC.CursorPos = bb.Min; + ItemSize(bb, style.FramePadding.y); + EndGroup(); +} + +bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items) +{ + const bool value_changed = ListBox(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_items); + return value_changed; +} + +bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items) +{ + if (!ListBoxHeader(label, items_count, height_in_items)) + return false; + + // Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper. + ImGuiContext& g = *GImGui; + bool value_changed = false; + ImGuiListClipper clipper(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to. + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + { + const bool item_selected = (i == *current_item); + const char* item_text; + if (!items_getter(data, i, &item_text)) + item_text = "*Unknown item*"; + + PushID(i); + if (Selectable(item_text, item_selected)) + { + *current_item = i; + value_changed = true; + } + if (item_selected) + SetItemDefaultFocus(); + PopID(); + } + ListBoxFooter(); + if (value_changed) + MarkItemEdited(g.CurrentWindow->DC.LastItemId); + + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: PlotLines, PlotHistogram +//------------------------------------------------------------------------- +// - PlotEx() [Internal] +// - PlotLines() +// - PlotHistogram() +//------------------------------------------------------------------------- + +void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + if (frame_size.x == 0.0f) + frame_size.x = CalcItemWidth(); + if (frame_size.y == 0.0f) + frame_size.y = label_size.y + (style.FramePadding.y * 2); + + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); + const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, 0, &frame_bb)) + return; + const bool hovered = ItemHoverable(frame_bb, id); + + // Determine scale from values if not specified + if (scale_min == FLT_MAX || scale_max == FLT_MAX) + { + float v_min = FLT_MAX; + float v_max = -FLT_MAX; + for (int i = 0; i < values_count; i++) + { + const float v = values_getter(data, i); + v_min = ImMin(v_min, v); + v_max = ImMax(v_max, v); + } + if (scale_min == FLT_MAX) + scale_min = v_min; + if (scale_max == FLT_MAX) + scale_max = v_max; + } + + RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + + const int values_count_min = (plot_type == ImGuiPlotType_Lines) ? 2 : 1; + if (values_count >= values_count_min) + { + int res_w = ImMin((int)frame_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); + int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); + + // Tooltip on hover + int v_hovered = -1; + if (hovered && inner_bb.Contains(g.IO.MousePos)) + { + const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); + const int v_idx = (int)(t * item_count); + IM_ASSERT(v_idx >= 0 && v_idx < values_count); + + const float v0 = values_getter(data, (v_idx + values_offset) % values_count); + const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count); + if (plot_type == ImGuiPlotType_Lines) + SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx+1, v1); + else if (plot_type == ImGuiPlotType_Histogram) + SetTooltip("%d: %8.4g", v_idx, v0); + v_hovered = v_idx; + } + + const float t_step = 1.0f / (float)res_w; + const float inv_scale = (scale_min == scale_max) ? 0.0f : (1.0f / (scale_max - scale_min)); + + float v0 = values_getter(data, (0 + values_offset) % values_count); + float t0 = 0.0f; + ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale) ); // Point in the normalized space of our target rectangle + float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (-scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands + + const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram); + const ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered); + + for (int n = 0; n < res_w; n++) + { + const float t1 = t0 + t_step; + const int v1_idx = (int)(t0 * item_count + 0.5f); + IM_ASSERT(v1_idx >= 0 && v1_idx < values_count); + const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count); + const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale) ); + + // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU. + ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0); + ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t)); + if (plot_type == ImGuiPlotType_Lines) + { + window->DrawList->AddLine(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base); + } + else if (plot_type == ImGuiPlotType_Histogram) + { + if (pos1.x >= pos0.x + 2.0f) + pos1.x -= 1.0f; + window->DrawList->AddRectFilled(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base); + } + + t0 = t1; + tp0 = tp1; + } + } + + // Text overlay + if (overlay_text) + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f,0.0f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); +} + +struct ImGuiPlotArrayGetterData +{ + const float* Values; + int Stride; + + ImGuiPlotArrayGetterData(const float* values, int stride) { Values = values; Stride = stride; } +}; + +static float Plot_ArrayGetter(void* data, int idx) +{ + ImGuiPlotArrayGetterData* plot_data = (ImGuiPlotArrayGetterData*)data; + const float v = *(const float*)(const void*)((const unsigned char*)plot_data->Values + (size_t)idx * plot_data->Stride); + return v; +} + +void ImGui::PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) +{ + ImGuiPlotArrayGetterData data(values, stride); + PlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +void ImGui::PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) +{ + PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +void ImGui::PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) +{ + ImGuiPlotArrayGetterData data(values, stride); + PlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +void ImGui::PlotHistogram(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) +{ + PlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Value helpers +// Those is not very useful, legacy API. +//------------------------------------------------------------------------- +// - Value() +//------------------------------------------------------------------------- + +void ImGui::Value(const char* prefix, bool b) +{ + Text("%s: %s", prefix, (b ? "true" : "false")); +} + +void ImGui::Value(const char* prefix, int v) +{ + Text("%s: %d", prefix, v); +} + +void ImGui::Value(const char* prefix, unsigned int v) +{ + Text("%s: %d", prefix, v); +} + +void ImGui::Value(const char* prefix, float v, const char* float_format) +{ + if (float_format) + { + char fmt[64]; + ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format); + Text(fmt, prefix, v); + } + else + { + Text("%s: %.3f", prefix, v); + } +} + +//------------------------------------------------------------------------- +// [SECTION] MenuItem, BeginMenu, EndMenu, etc. +//------------------------------------------------------------------------- +// - ImGuiMenuColumns [Internal] +// - BeginMainMenuBar() +// - EndMainMenuBar() +// - BeginMenuBar() +// - EndMenuBar() +// - BeginMenu() +// - EndMenu() +// - MenuItem() +//------------------------------------------------------------------------- + +// Helpers for internal use +ImGuiMenuColumns::ImGuiMenuColumns() +{ + Spacing = Width = NextWidth = 0.0f; + memset(Pos, 0, sizeof(Pos)); + memset(NextWidths, 0, sizeof(NextWidths)); +} + +void ImGuiMenuColumns::Update(int count, float spacing, bool clear) +{ + IM_ASSERT(count == IM_ARRAYSIZE(Pos)); + Width = NextWidth = 0.0f; + Spacing = spacing; + if (clear) + memset(NextWidths, 0, sizeof(NextWidths)); + for (int i = 0; i < IM_ARRAYSIZE(Pos); i++) + { + if (i > 0 && NextWidths[i] > 0.0f) + Width += Spacing; + Pos[i] = (float)(int)Width; + Width += NextWidths[i]; + NextWidths[i] = 0.0f; + } +} + +float ImGuiMenuColumns::DeclColumns(float w0, float w1, float w2) // not using va_arg because they promote float to double +{ + NextWidth = 0.0f; + NextWidths[0] = ImMax(NextWidths[0], w0); + NextWidths[1] = ImMax(NextWidths[1], w1); + NextWidths[2] = ImMax(NextWidths[2], w2); + for (int i = 0; i < IM_ARRAYSIZE(Pos); i++) + NextWidth += NextWidths[i] + ((i > 0 && NextWidths[i] > 0.0f) ? Spacing : 0.0f); + return ImMax(Width, NextWidth); +} + +float ImGuiMenuColumns::CalcExtraSpace(float avail_w) +{ + return ImMax(0.0f, avail_w - Width); +} + +// For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. +bool ImGui::BeginMainMenuBar() +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); + SetNextWindowPos(ImVec2(0.0f, 0.0f)); + SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y)); + PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0,0)); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; + bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar(); + PopStyleVar(2); + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); + if (!is_open) + { + End(); + return false; + } + return true; //-V1020 +} + +void ImGui::EndMainMenuBar() +{ + EndMenuBar(); + + // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window + ImGuiContext& g = *GImGui; + if (g.CurrentWindow == g.NavWindow && g.NavLayer == 0) + FocusPreviousWindowIgnoringOne(g.NavWindow); + + End(); +} + +bool ImGui::BeginMenuBar() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + if (!(window->Flags & ImGuiWindowFlags_MenuBar)) + return false; + + IM_ASSERT(!window->DC.MenuBarAppending); + BeginGroup(); // Backup position on layer 0 + PushID("##menubar"); + + // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. + // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. + ImRect bar_rect = window->MenuBarRect(); + ImRect clip_rect(ImFloor(bar_rect.Min.x + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f)); + clip_rect.ClipWith(window->OuterRectClipped); + PushClipRect(clip_rect.Min, clip_rect.Max, false); + + window->DC.CursorPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y); + window->DC.LayoutType = ImGuiLayoutType_Horizontal; + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); + window->DC.MenuBarAppending = true; + AlignTextToFramePadding(); + return true; +} + +void ImGui::EndMenuBar() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ImGuiContext& g = *GImGui; + + // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings. + if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) + { + ImGuiWindow* nav_earliest_child = g.NavWindow; + while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu)) + nav_earliest_child = nav_earliest_child->ParentWindow; + if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && g.NavMoveRequestForward == ImGuiNavForward_None) + { + // To do so we claim focus back, restore NavId and then process the movement request for yet another frame. + // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth the hassle/cost) + IM_ASSERT(window->DC.NavLayerActiveMaskNext & 0x02); // Sanity check + FocusWindow(window); + SetNavIDWithRectRel(window->NavLastIds[1], 1, window->NavRectRel[1]); + g.NavLayer = ImGuiNavLayer_Menu; + g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection. + g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; + NavMoveRequestCancel(); + } + } + + IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); + IM_ASSERT(window->DC.MenuBarAppending); + PopClipRect(); + PopID(); + window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. + window->DC.GroupStack.back().AdvanceCursor = false; + EndGroup(); // Restore position on layer 0 + window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); + window->DC.MenuBarAppending = false; +} + +bool ImGui::BeginMenu(const char* label, bool enabled) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + + ImVec2 label_size = CalcTextSize(label, NULL, true); + + bool pressed; + bool menu_is_open = IsPopupOpen(id); + bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].OpenParentId == window->IDStack.back()); + ImGuiWindow* backed_nav_window = g.NavWindow; + if (menuset_is_open) + g.NavWindow = window; // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent) + + // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu, + // However the final position is going to be different! It is choosen by FindBestWindowPosForPopup(). + // e.g. Menus tend to overlap each other horizontally to amplify relative Z-ordering. + ImVec2 popup_pos, pos = window->DC.CursorPos; + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + { + // Menu inside an horizontal menu bar + // Selectable extend their highlight by half ItemSpacing in each direction. + // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() + popup_pos = ImVec2(pos.x - 1.0f - (float)(int)(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight()); + window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); + PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); + float w = label_size.x; + pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_PressedOnClick | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); + PopStyleVar(); + window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). + } + else + { + // Menu inside a menu + popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); + float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame + float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w); + pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_PressedOnClick | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_DrawFillAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); + if (!enabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); + RenderArrow(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.30f, 0.0f), ImGuiDir_Right); + if (!enabled) PopStyleColor(); + } + + const bool hovered = enabled && ItemHoverable(window->DC.LastItemRect, id); + if (menuset_is_open) + g.NavWindow = backed_nav_window; + + bool want_open = false, want_close = false; + if (window->DC.LayoutType == ImGuiLayoutType_Vertical) // (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) + { + // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. + bool moving_within_opened_triangle = false; + if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].ParentWindow == window && !(window->Flags & ImGuiWindowFlags_MenuBar)) + { + if (ImGuiWindow* next_window = g.OpenPopupStack[g.BeginPopupStack.Size].Window) + { + // FIXME-DPI: Values should be derived from a master "scale" factor. + ImRect next_window_rect = next_window->Rect(); + ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta; + ImVec2 tb = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR(); + ImVec2 tc = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR(); + float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack. + ta.x += (window->Pos.x < next_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues + tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale? + tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f); + moving_within_opened_triangle = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos); + //window->DrawList->PushClipRectFullScreen(); window->DrawList->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); window->DrawList->PopClipRect(); // Debug + } + } + + want_close = (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_within_opened_triangle); + want_open = (!menu_is_open && hovered && !moving_within_opened_triangle) || (!menu_is_open && hovered && pressed); + + if (g.NavActivateId == id) + { + want_close = menu_is_open; + want_open = !menu_is_open; + } + if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open + { + want_open = true; + NavMoveRequestCancel(); + } + } + else + { + // Menu bar + if (menu_is_open && pressed && menuset_is_open) // Click an open menu again to close it + { + want_close = true; + want_open = menu_is_open = false; + } + else if (pressed || (hovered && menuset_is_open && !menu_is_open)) // First click to open, then hover to open others + { + want_open = true; + } + else if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open + { + want_open = true; + NavMoveRequestCancel(); + } + } + + if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }' + want_close = true; + if (want_close && IsPopupOpen(id)) + ClosePopupToLevel(g.BeginPopupStack.Size, true); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); + + if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size) + { + // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame. + OpenPopup(label); + return false; + } + + menu_is_open |= want_open; + if (want_open) + OpenPopup(label); + + if (menu_is_open) + { + // Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu) + SetNextWindowPos(popup_pos, ImGuiCond_Always); + ImGuiWindowFlags flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus; + if (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) + flags |= ImGuiWindowFlags_ChildWindow; + menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + } + + return menu_is_open; +} + +void ImGui::EndMenu() +{ + // Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu). + // A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs. + // However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction. + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical) + { + ClosePopupToLevel(g.BeginPopupStack.Size, true); + NavMoveRequestCancel(); + } + + EndPopup(); +} + +bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImVec2 pos = window->DC.CursorPos; + ImVec2 label_size = CalcTextSize(label, NULL, true); + + ImGuiSelectableFlags flags = ImGuiSelectableFlags_PressedOnRelease | (enabled ? 0 : ImGuiSelectableFlags_Disabled); + bool pressed; + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + { + // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful + // Note that in this situation we render neither the shortcut neither the selected tick mark + float w = label_size.x; + window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); + PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); + pressed = Selectable(label, false, flags, ImVec2(w, 0.0f)); + PopStyleVar(); + window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). + } + else + { + ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f); + float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame + float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w); + pressed = Selectable(label, false, flags | ImGuiSelectableFlags_DrawFillAvailWidth, ImVec2(w, 0.0f)); + if (shortcut_size.x > 0.0f) + { + PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); + RenderText(pos + ImVec2(window->MenuColumns.Pos[1] + extra_w, 0.0f), shortcut, NULL, false); + PopStyleColor(); + } + if (selected) + RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled), g.FontSize * 0.866f); + } + + IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); + return pressed; +} + +bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled) +{ + if (MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled)) + { + if (p_selected) + *p_selected = !*p_selected; + return true; + } + return false; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: BeginTabBar, EndTabBar, etc. +//------------------------------------------------------------------------- +// [BETA API] API may evolve! This code has been extracted out of the Docking branch, +// and some of the construct which are not used in Master may be left here to facilitate merging. +//------------------------------------------------------------------------- +// - BeginTabBar() +// - BeginTabBarEx() [Internal] +// - EndTabBar() +// - TabBarLayout() [Internal] +// - TabBarCalcTabID() [Internal] +// - TabBarCalcMaxTabWidth() [Internal] +// - TabBarFindTabById() [Internal] +// - TabBarRemoveTab() [Internal] +// - TabBarCloseTab() [Internal] +// - TabBarScrollClamp()v +// - TabBarScrollToTab() [Internal] +// - TabBarQueueChangeTabOrder() [Internal] +// - TabBarScrollingButtons() [Internal] +// - TabBarTabListPopupButton() [Internal] +//------------------------------------------------------------------------- + +namespace ImGui +{ + static void TabBarLayout(ImGuiTabBar* tab_bar); + static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label); + static float TabBarCalcMaxTabWidth(); + static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling); + static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar); + static ImGuiTabItem* TabBarTabListPopupButton(ImGuiTabBar* tab_bar); +} + +ImGuiTabBar::ImGuiTabBar() +{ + ID = 0; + SelectedTabId = NextSelectedTabId = VisibleTabId = 0; + CurrFrameVisible = PrevFrameVisible = -1; + ContentsHeight = 0.0f; + OffsetMax = OffsetNextTab = 0.0f; + ScrollingAnim = ScrollingTarget = ScrollingTargetDistToVisibility = ScrollingSpeed = 0.0f; + Flags = ImGuiTabBarFlags_None; + ReorderRequestTabId = 0; + ReorderRequestDir = 0; + WantLayout = VisibleTabWasSubmitted = false; + LastTabItemIdx = -1; +} + +static int IMGUI_CDECL TabItemComparerByVisibleOffset(const void* lhs, const void* rhs) +{ + const ImGuiTabItem* a = (const ImGuiTabItem*)lhs; + const ImGuiTabItem* b = (const ImGuiTabItem*)rhs; + return (int)(a->Offset - b->Offset); +} + +static int IMGUI_CDECL TabBarSortItemComparer(const void* lhs, const void* rhs) +{ + const ImGuiTabBarSortItem* a = (const ImGuiTabBarSortItem*)lhs; + const ImGuiTabBarSortItem* b = (const ImGuiTabBarSortItem*)rhs; + if (int d = (int)(b->Width - a->Width)) + return d; + return (b->Index - a->Index); +} + +static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiTabBarRef& ref) +{ + ImGuiContext& g = *GImGui; + return ref.Ptr ? ref.Ptr : g.TabBars.GetByIndex(ref.IndexInMainPool); +} + +static ImGuiTabBarRef GetTabBarRefFromTabBar(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + if (g.TabBars.Contains(tab_bar)) + return ImGuiTabBarRef(g.TabBars.GetIndex(tab_bar)); + return ImGuiTabBarRef(tab_bar); +} + +bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + ImGuiID id = window->GetID(str_id); + ImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id); + ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->InnerClipRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2); + tab_bar->ID = id; + return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused); +} + +bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + if ((flags & ImGuiTabBarFlags_DockNode) == 0) + window->IDStack.push_back(tab_bar->ID); + + // Add to stack + g.CurrentTabBarStack.push_back(GetTabBarRefFromTabBar(tab_bar)); + g.CurrentTabBar = tab_bar; + + if (tab_bar->CurrFrameVisible == g.FrameCount) + { + //IMGUI_DEBUG_LOG("BeginTabBarEx already called this frame\n", g.FrameCount); + IM_ASSERT(0); + return true; + } + + // When toggling back from ordered to manually-reorderable, shuffle tabs to enforce the last visible order. + // Otherwise, the most recently inserted tabs would move at the end of visible list which can be a little too confusing or magic for the user. + if ((flags & ImGuiTabBarFlags_Reorderable) && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable) && tab_bar->Tabs.Size > 1 && tab_bar->PrevFrameVisible != -1) + ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByVisibleOffset); + + // Flags + if ((flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) + flags |= ImGuiTabBarFlags_FittingPolicyDefault_; + + tab_bar->Flags = flags; + tab_bar->BarRect = tab_bar_bb; + tab_bar->WantLayout = true; // Layout will be done on the first call to ItemTab() + tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible; + tab_bar->CurrFrameVisible = g.FrameCount; + tab_bar->FramePadding = g.Style.FramePadding; + + // Layout + ItemSize(ImVec2(tab_bar->OffsetMax, tab_bar->BarRect.GetHeight())); + window->DC.CursorPos.x = tab_bar->BarRect.Min.x; + + // Draw separator + const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_Tab); + const float y = tab_bar->BarRect.Max.y - 1.0f; + { + const float separator_min_x = tab_bar->BarRect.Min.x - window->WindowPadding.x; + const float separator_max_x = tab_bar->BarRect.Max.x + window->WindowPadding.x; + window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); + } + return true; +} + +void ImGui::EndTabBar() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT(tab_bar != NULL && "Mismatched BeginTabBar()/EndTabBar()!"); + return; // FIXME-ERRORHANDLING + } + if (tab_bar->WantLayout) + TabBarLayout(tab_bar); + + // Restore the last visible height if no tab is visible, this reduce vertical flicker/movement when a tabs gets removed without calling SetTabItemClosed(). + const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); + if (tab_bar->VisibleTabWasSubmitted || tab_bar->VisibleTabId == 0 || tab_bar_appearing) + tab_bar->ContentsHeight = ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, 0.0f); + else + window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->ContentsHeight; + + if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) + PopID(); + + g.CurrentTabBarStack.pop_back(); + g.CurrentTabBar = g.CurrentTabBarStack.empty() ? NULL : GetTabBarFromTabBarRef(g.CurrentTabBarStack.back()); +} + +// This is called only once a frame before by the first call to ItemTab() +// The reason we're not calling it in BeginTabBar() is to leave a chance to the user to call the SetTabItemClosed() functions. +static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + tab_bar->WantLayout = false; + + // Garbage collect + int tab_dst_n = 0; + for (int tab_src_n = 0; tab_src_n < tab_bar->Tabs.Size; tab_src_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_src_n]; + if (tab->LastFrameVisible < tab_bar->PrevFrameVisible) + { + if (tab->ID == tab_bar->SelectedTabId) + tab_bar->SelectedTabId = 0; + continue; + } + if (tab_dst_n != tab_src_n) + tab_bar->Tabs[tab_dst_n] = tab_bar->Tabs[tab_src_n]; + tab_dst_n++; + } + if (tab_bar->Tabs.Size != tab_dst_n) + tab_bar->Tabs.resize(tab_dst_n); + + // Setup next selected tab + ImGuiID scroll_track_selected_tab_id = 0; + if (tab_bar->NextSelectedTabId) + { + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId; + tab_bar->NextSelectedTabId = 0; + scroll_track_selected_tab_id = tab_bar->SelectedTabId; + } + + // Process order change request (we could probably process it when requested but it's just saner to do it in a single spot). + if (tab_bar->ReorderRequestTabId != 0) + { + if (ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId)) + { + //IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools + int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestDir; + if (tab2_order >= 0 && tab2_order < tab_bar->Tabs.Size) + { + ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order]; + ImGuiTabItem item_tmp = *tab1; + *tab1 = *tab2; + *tab2 = item_tmp; + if (tab2->ID == tab_bar->SelectedTabId) + scroll_track_selected_tab_id = tab2->ID; + tab1 = tab2 = NULL; + } + if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings) + MarkIniSettingsDirty(); + } + tab_bar->ReorderRequestTabId = 0; + } + + // Tab List Popup (will alter tab_bar->BarRect and therefore the available width!) + const bool tab_list_popup_button = (tab_bar->Flags & ImGuiTabBarFlags_TabListPopupButton) != 0; + if (tab_list_popup_button) + if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Max.x! + scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; + + ImVector& width_sort_buffer = g.TabSortByWidthBuffer; + width_sort_buffer.resize(tab_bar->Tabs.Size); + + // Compute ideal widths + float width_total_contents = 0.0f; + ImGuiTabItem* most_recently_selected_tab = NULL; + bool found_selected_tab_id = false; + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + IM_ASSERT(tab->LastFrameVisible >= tab_bar->PrevFrameVisible); + + if (most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) + most_recently_selected_tab = tab; + if (tab->ID == tab_bar->SelectedTabId) + found_selected_tab_id = true; + + // Refresh tab width immediately, otherwise changes of style e.g. style.FramePadding.x would noticeably lag in the tab bar. + // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet, + // and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window. + const char* tab_name = tab_bar->GetTabName(tab); + tab->WidthContents = TabItemCalcSize(tab_name, (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true).x; + + width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->WidthContents; + + // Store data so we can build an array sorted by width if we need to shrink tabs down + width_sort_buffer[tab_n].Index = tab_n; + width_sort_buffer[tab_n].Width = tab->WidthContents; + } + + // Compute width + const float width_avail = tab_bar->BarRect.GetWidth(); + float width_excess = (width_avail < width_total_contents) ? (width_total_contents - width_avail) : 0.0f; + if (width_excess > 0.0f && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown)) + { + // If we don't have enough room, resize down the largest tabs first + if (tab_bar->Tabs.Size > 1) + ImQsort(width_sort_buffer.Data, (size_t)width_sort_buffer.Size, sizeof(ImGuiTabBarSortItem), TabBarSortItemComparer); + int tab_count_same_width = 1; + while (width_excess > 0.0f && tab_count_same_width < tab_bar->Tabs.Size) + { + while (tab_count_same_width < tab_bar->Tabs.Size && width_sort_buffer[0].Width == width_sort_buffer[tab_count_same_width].Width) + tab_count_same_width++; + float width_to_remove_per_tab_max = (tab_count_same_width < tab_bar->Tabs.Size) ? (width_sort_buffer[0].Width - width_sort_buffer[tab_count_same_width].Width) : (width_sort_buffer[0].Width - 1.0f); + float width_to_remove_per_tab = ImMin(width_excess / tab_count_same_width, width_to_remove_per_tab_max); + for (int tab_n = 0; tab_n < tab_count_same_width; tab_n++) + width_sort_buffer[tab_n].Width -= width_to_remove_per_tab; + width_excess -= width_to_remove_per_tab * tab_count_same_width; + } + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + tab_bar->Tabs[width_sort_buffer[tab_n].Index].Width = (float)(int)width_sort_buffer[tab_n].Width; + } + else + { + const float tab_max_width = TabBarCalcMaxTabWidth(); + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + tab->Width = ImMin(tab->WidthContents, tab_max_width); + } + } + + // Layout all active tabs + float offset_x = 0.0f; + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + tab->Offset = offset_x; + if (scroll_track_selected_tab_id == 0 && g.NavJustMovedToId == tab->ID) + scroll_track_selected_tab_id = tab->ID; + offset_x += tab->Width + g.Style.ItemInnerSpacing.x; + } + tab_bar->OffsetMax = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f); + tab_bar->OffsetNextTab = 0.0f; + + // Horizontal scrolling buttons + const bool scrolling_buttons = (tab_bar->OffsetMax > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll); + if (scrolling_buttons) + if (ImGuiTabItem* tab_to_select = TabBarScrollingButtons(tab_bar)) // NB: Will alter BarRect.Max.x! + scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; + + // If we have lost the selected tab, select the next most recently active one + if (found_selected_tab_id == false) + tab_bar->SelectedTabId = 0; + if (tab_bar->SelectedTabId == 0 && tab_bar->NextSelectedTabId == 0 && most_recently_selected_tab != NULL) + scroll_track_selected_tab_id = tab_bar->SelectedTabId = most_recently_selected_tab->ID; + + // Lock in visible tab + tab_bar->VisibleTabId = tab_bar->SelectedTabId; + tab_bar->VisibleTabWasSubmitted = false; + + // Update scrolling + if (scroll_track_selected_tab_id) + if (ImGuiTabItem* scroll_track_selected_tab = TabBarFindTabByID(tab_bar, scroll_track_selected_tab_id)) + TabBarScrollToTab(tab_bar, scroll_track_selected_tab); + tab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim); + tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget); + if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget) + { + // Scrolling speed adjust itself so we can always reach our target in 1/3 seconds. + // Teleport if we are aiming far off the visible line + tab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, 70.0f * g.FontSize); + tab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, ImFabs(tab_bar->ScrollingTarget - tab_bar->ScrollingAnim) / 0.3f); + const bool teleport = (tab_bar->PrevFrameVisible + 1 < g.FrameCount) || (tab_bar->ScrollingTargetDistToVisibility > 10.0f * g.FontSize); + tab_bar->ScrollingAnim = teleport ? tab_bar->ScrollingTarget : ImLinearSweep(tab_bar->ScrollingAnim, tab_bar->ScrollingTarget, g.IO.DeltaTime * tab_bar->ScrollingSpeed); + } + else + { + tab_bar->ScrollingSpeed = 0.0f; + } + + // Clear name buffers + if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) + tab_bar->TabsNames.Buf.resize(0); +} + +// Dockables uses Name/ID in the global namespace. Non-dockable items use the ID stack. +static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label) +{ + if (tab_bar->Flags & ImGuiTabBarFlags_DockNode) + { + ImGuiID id = ImHashStr(label, 0); + KeepAliveID(id); + return id; + } + else + { + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(label); + } +} + +static float ImGui::TabBarCalcMaxTabWidth() +{ + ImGuiContext& g = *GImGui; + return g.FontSize * 20.0f; +} + +ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id) +{ + if (tab_id != 0) + for (int n = 0; n < tab_bar->Tabs.Size; n++) + if (tab_bar->Tabs[n].ID == tab_id) + return &tab_bar->Tabs[n]; + return NULL; +} + +// The *TabId fields be already set by the docking system _before_ the actual TabItem was created, so we clear them regardless. +void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id) +{ + if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) + tab_bar->Tabs.erase(tab); + if (tab_bar->VisibleTabId == tab_id) { tab_bar->VisibleTabId = 0; } + if (tab_bar->SelectedTabId == tab_id) { tab_bar->SelectedTabId = 0; } + if (tab_bar->NextSelectedTabId == tab_id) { tab_bar->NextSelectedTabId = 0; } +} + +// Called on manual closure attempt +void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +{ + if ((tab_bar->VisibleTabId == tab->ID) && !(tab->Flags & ImGuiTabItemFlags_UnsavedDocument)) + { + // This will remove a frame of lag for selecting another tab on closure. + // However we don't run it in the case where the 'Unsaved' flag is set, so user gets a chance to fully undo the closure + tab->LastFrameVisible = -1; + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = 0; + } + else if ((tab_bar->VisibleTabId != tab->ID) && (tab->Flags & ImGuiTabItemFlags_UnsavedDocument)) + { + // Actually select before expecting closure + tab_bar->NextSelectedTabId = tab->ID; + } +} + +static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling) +{ + scrolling = ImMin(scrolling, tab_bar->OffsetMax - tab_bar->BarRect.GetWidth()); + return ImMax(scrolling, 0.0f); +} + +static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +{ + ImGuiContext& g = *GImGui; + float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar) + int order = tab_bar->GetTabOrder(tab); + float tab_x1 = tab->Offset + (order > 0 ? -margin : 0.0f); + float tab_x2 = tab->Offset + tab->Width + (order + 1 < tab_bar->Tabs.Size ? margin : 1.0f); + tab_bar->ScrollingTargetDistToVisibility = 0.0f; + if (tab_bar->ScrollingTarget > tab_x1) + { + tab_bar->ScrollingTargetDistToVisibility = ImMax(tab_bar->ScrollingAnim - tab_x2, 0.0f); + tab_bar->ScrollingTarget = tab_x1; + } + else if (tab_bar->ScrollingTarget < tab_x2 - tab_bar->BarRect.GetWidth()) + { + tab_bar->ScrollingTargetDistToVisibility = ImMax((tab_x1 - tab_bar->BarRect.GetWidth()) - tab_bar->ScrollingAnim, 0.0f); + tab_bar->ScrollingTarget = tab_x2 - tab_bar->BarRect.GetWidth(); + } +} + +void ImGui::TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir) +{ + IM_ASSERT(dir == -1 || dir == +1); + IM_ASSERT(tab_bar->ReorderRequestTabId == 0); + tab_bar->ReorderRequestTabId = tab->ID; + tab_bar->ReorderRequestDir = dir; +} + +static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImVec2 arrow_button_size(g.FontSize - 2.0f, g.FontSize + g.Style.FramePadding.y * 2.0f); + const float scrolling_buttons_width = arrow_button_size.x * 2.0f; + + const ImVec2 backup_cursor_pos = window->DC.CursorPos; + //window->DrawList->AddRect(ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Max.x, tab_bar->BarRect.Max.y), IM_COL32(255,0,0,255)); + + const ImRect avail_bar_rect = tab_bar->BarRect; + bool want_clip_rect = !avail_bar_rect.Contains(ImRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(scrolling_buttons_width, 0.0f))); + if (want_clip_rect) + PushClipRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max + ImVec2(g.Style.ItemInnerSpacing.x, 0.0f), true); + + ImGuiTabItem* tab_to_select = NULL; + + int select_dir = 0; + ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text]; + arrow_col.w *= 0.5f; + + PushStyleColor(ImGuiCol_Text, arrow_col); + PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + const float backup_repeat_delay = g.IO.KeyRepeatDelay; + const float backup_repeat_rate = g.IO.KeyRepeatRate; + g.IO.KeyRepeatDelay = 0.250f; + g.IO.KeyRepeatRate = 0.200f; + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y); + if (ArrowButtonEx("##<", ImGuiDir_Left, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) + select_dir = -1; + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width + arrow_button_size.x, tab_bar->BarRect.Min.y); + if (ArrowButtonEx("##>", ImGuiDir_Right, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) + select_dir = +1; + PopStyleColor(2); + g.IO.KeyRepeatRate = backup_repeat_rate; + g.IO.KeyRepeatDelay = backup_repeat_delay; + + if (want_clip_rect) + PopClipRect(); + + if (select_dir != 0) + if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId)) + { + int selected_order = tab_bar->GetTabOrder(tab_item); + int target_order = selected_order + select_dir; + tab_to_select = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order]; // If we are at the end of the list, still scroll to make our tab visible + } + window->DC.CursorPos = backup_cursor_pos; + tab_bar->BarRect.Max.x -= scrolling_buttons_width + 1.0f; + + return tab_to_select; +} + +static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // We use g.Style.FramePadding.y to match the square ArrowButton size + const float tab_list_popup_button_width = g.FontSize + g.Style.FramePadding.y; + const ImVec2 backup_cursor_pos = window->DC.CursorPos; + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x - g.Style.FramePadding.y, tab_bar->BarRect.Min.y); + tab_bar->BarRect.Min.x += tab_list_popup_button_width; + + ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text]; + arrow_col.w *= 0.5f; + PushStyleColor(ImGuiCol_Text, arrow_col); + PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + bool open = BeginCombo("##v", NULL, ImGuiComboFlags_NoPreview); + PopStyleColor(2); + + ImGuiTabItem* tab_to_select = NULL; + if (open) + { + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + const char* tab_name = tab_bar->GetTabName(tab); + if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID)) + tab_to_select = tab; + } + EndCombo(); + } + + window->DC.CursorPos = backup_cursor_pos; + return tab_to_select; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: BeginTabItem, EndTabItem, etc. +//------------------------------------------------------------------------- +// [BETA API] API may evolve! This code has been extracted out of the Docking branch, +// and some of the construct which are not used in Master may be left here to facilitate merging. +//------------------------------------------------------------------------- +// - BeginTabItem() +// - EndTabItem() +// - TabItemEx() [Internal] +// - SetTabItemClosed() +// - TabItemCalcSize() [Internal] +// - TabItemBackground() [Internal] +// - TabItemLabelAndCloseButton() [Internal] +//------------------------------------------------------------------------- + +bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags flags) +{ + ImGuiContext& g = *GImGui; + if (g.CurrentWindow->SkipItems) + return false; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT(tab_bar && "Needs to be called between BeginTabBar() and EndTabBar()!"); + return false; // FIXME-ERRORHANDLING + } + bool ret = TabItemEx(tab_bar, label, p_open, flags); + if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; + g.CurrentWindow->IDStack.push_back(tab->ID); // We already hashed 'label' so push into the ID stack directly instead of doing another hash through PushID(label) + } + return ret; +} + +void ImGui::EndTabItem() +{ + ImGuiContext& g = *GImGui; + if (g.CurrentWindow->SkipItems) + return; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT(tab_bar != NULL && "Needs to be called between BeginTabBar() and EndTabBar()!"); + return; + } + IM_ASSERT(tab_bar->LastTabItemIdx >= 0); + ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; + if (!(tab->Flags & ImGuiTabItemFlags_NoPushId)) + g.CurrentWindow->IDStack.pop_back(); +} + +bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags) +{ + // Layout whole tab bar if not already done + if (tab_bar->WantLayout) + TabBarLayout(tab_bar); + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = TabBarCalcTabID(tab_bar, label); + + // If the user called us with *p_open == false, we early out and don't render. We make a dummy call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID. + if (p_open && !*p_open) + { + PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true); + ItemAdd(ImRect(), id); + PopItemFlag(); + return false; + } + + // Calculate tab contents size + ImVec2 size = TabItemCalcSize(label, p_open != NULL); + + // Acquire tab data + ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, id); + bool tab_is_new = false; + if (tab == NULL) + { + tab_bar->Tabs.push_back(ImGuiTabItem()); + tab = &tab_bar->Tabs.back(); + tab->ID = id; + tab->Width = size.x; + tab_is_new = true; + } + tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_ptr(tab); + tab->WidthContents = size.x; + + if (p_open == NULL) + flags |= ImGuiTabItemFlags_NoCloseButton; + + const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); + const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0; + const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount); + tab->LastFrameVisible = g.FrameCount; + tab->Flags = flags; + + // Append name with zero-terminator + tab->NameOffset = tab_bar->TabsNames.size(); + tab_bar->TabsNames.append(label, label + strlen(label) + 1); + + // If we are not reorderable, always reset offset based on submission order. + // (We already handled layout and sizing using the previous known order, but sizing is not affected by order!) + if (!tab_appearing && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable)) + { + tab->Offset = tab_bar->OffsetNextTab; + tab_bar->OffsetNextTab += tab->Width + g.Style.ItemInnerSpacing.x; + } + + // Update selected tab + if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0) + if (!tab_bar_appearing || tab_bar->SelectedTabId == 0) + tab_bar->NextSelectedTabId = id; // New tabs gets activated + if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // SetSelected can only be passed on explicit tab bar + tab_bar->NextSelectedTabId = id; + + // Lock visibility + bool tab_contents_visible = (tab_bar->VisibleTabId == id); + if (tab_contents_visible) + tab_bar->VisibleTabWasSubmitted = true; + + // On the very first frame of a tab bar we let first tab contents be visible to minimize appearing glitches + if (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing) + if (tab_bar->Tabs.Size == 1 && !(tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs)) + tab_contents_visible = true; + + if (tab_appearing && !(tab_bar_appearing && !tab_is_new)) + { + PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true); + ItemAdd(ImRect(), id); + PopItemFlag(); + return tab_contents_visible; + } + + if (tab_bar->SelectedTabId == id) + tab->LastFrameSelected = g.FrameCount; + + // Backup current layout position + const ImVec2 backup_main_cursor_pos = window->DC.CursorPos; + + // Layout + size.x = tab->Width; + window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2((float)(int)tab->Offset - tab_bar->ScrollingAnim, 0.0f); + ImVec2 pos = window->DC.CursorPos; + ImRect bb(pos, pos + size); + + // We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation) + bool want_clip_rect = (bb.Min.x < tab_bar->BarRect.Min.x) || (bb.Max.x >= tab_bar->BarRect.Max.x); + if (want_clip_rect) + PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->BarRect.Min.x), bb.Min.y - 1), ImVec2(tab_bar->BarRect.Max.x, bb.Max.y), true); + + ItemSize(bb, style.FramePadding.y); + if (!ItemAdd(bb, id)) + { + if (want_clip_rect) + PopClipRect(); + window->DC.CursorPos = backup_main_cursor_pos; + return tab_contents_visible; + } + + // Click to Select a tab + ImGuiButtonFlags button_flags = (ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_AllowItemOverlap); + if (g.DragDropActive) + button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + if (pressed) + tab_bar->NextSelectedTabId = id; + hovered |= (g.HoveredId == id); + + // Allow the close button to overlap unless we are dragging (in which case we don't want any overlapping tabs to be hovered) + if (!held) + SetItemAllowOverlap(); + + // Drag and drop: re-order tabs + if (held && !tab_appearing && IsMouseDragging(0)) + { + if (!g.DragDropActive && (tab_bar->Flags & ImGuiTabBarFlags_Reorderable)) + { + // While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x + if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x) + { + if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) + TabBarQueueChangeTabOrder(tab_bar, tab, -1); + } + else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x) + { + if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) + TabBarQueueChangeTabOrder(tab_bar, tab, +1); + } + } + } + +#if 0 + if (hovered && g.HoveredIdNotActiveTimer > 0.50f && bb.GetWidth() < tab->WidthContents) + { + // Enlarge tab display when hovering + bb.Max.x = bb.Min.x + (float)(int)ImLerp(bb.GetWidth(), tab->WidthContents, ImSaturate((g.HoveredIdNotActiveTimer - 0.40f) * 6.0f)); + display_draw_list = GetForegroundDrawList(window); + TabItemBackground(display_draw_list, bb, flags, GetColorU32(ImGuiCol_TitleBgActive)); + } +#endif + + // Render tab shape + ImDrawList* display_draw_list = window->DrawList; + const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabUnfocused)); + TabItemBackground(display_draw_list, bb, flags, tab_col); + RenderNavHighlight(bb, id); + + // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. + const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); + if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1))) + tab_bar->NextSelectedTabId = id; + + if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) + flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; + + // Render tab label, process close button + const ImGuiID close_button_id = p_open ? window->GetID((void*)((intptr_t)id + 1)) : 0; + bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, tab_bar->FramePadding, label, id, close_button_id); + if (just_closed && p_open != NULL) + { + *p_open = false; + TabBarCloseTab(tab_bar, tab); + } + + // Restore main window position so user can draw there + if (want_clip_rect) + PopClipRect(); + window->DC.CursorPos = backup_main_cursor_pos; + + // Tooltip (FIXME: Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer) + // We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar (which g.HoveredId ignores) + if (g.HoveredId == id && !held && g.HoveredIdNotActiveTimer > 0.50f && IsItemHovered()) + if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip)) + SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); + + return tab_contents_visible; +} + +// [Public] This is call is 100% optional but it allows to remove some one-frame glitches when a tab has been unexpectedly removed. +// To use it to need to call the function SetTabItemClosed() after BeginTabBar() and before any call to BeginTabItem() +void ImGui::SetTabItemClosed(const char* label) +{ + ImGuiContext& g = *GImGui; + bool is_within_manual_tab_bar = g.CurrentTabBar && !(g.CurrentTabBar->Flags & ImGuiTabBarFlags_DockNode); + if (is_within_manual_tab_bar) + { + ImGuiTabBar* tab_bar = g.CurrentTabBar; + IM_ASSERT(tab_bar->WantLayout); // Needs to be called AFTER BeginTabBar() and BEFORE the first call to BeginTabItem() + ImGuiID tab_id = TabBarCalcTabID(tab_bar, label); + TabBarRemoveTab(tab_bar, tab_id); + } +} + +ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button) +{ + ImGuiContext& g = *GImGui; + ImVec2 label_size = CalcTextSize(label, NULL, true); + ImVec2 size = ImVec2(label_size.x + g.Style.FramePadding.x, label_size.y + g.Style.FramePadding.y * 2.0f); + if (has_close_button) + size.x += g.Style.FramePadding.x + (g.Style.ItemInnerSpacing.x + g.FontSize); // We use Y intentionally to fit the close button circle. + else + size.x += g.Style.FramePadding.x + 1.0f; + return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y); +} + +void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col) +{ + // While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it. + ImGuiContext& g = *GImGui; + const float width = bb.GetWidth(); + IM_UNUSED(flags); + IM_ASSERT(width > 0.0f); + const float rounding = ImMax(0.0f, ImMin(g.Style.TabRounding, width * 0.5f - 1.0f)); + const float y1 = bb.Min.y + 1.0f; + const float y2 = bb.Max.y - 1.0f; + draw_list->PathLineTo(ImVec2(bb.Min.x, y2)); + draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9); + draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12); + draw_list->PathLineTo(ImVec2(bb.Max.x, y2)); + draw_list->PathFillConvex(col); + if (g.Style.TabBorderSize > 0.0f) + { + draw_list->PathLineTo(ImVec2(bb.Min.x + 0.5f, y2)); + draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding + 0.5f, y1 + rounding + 0.5f), rounding, 6, 9); + draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding - 0.5f, y1 + rounding + 0.5f), rounding, 9, 12); + draw_list->PathLineTo(ImVec2(bb.Max.x - 0.5f, y2)); + draw_list->PathStroke(GetColorU32(ImGuiCol_Border), false, g.Style.TabBorderSize); + } +} + +// Render text label (with custom clipping) + Unsaved Document marker + Close Button logic +// We tend to lock style.FramePadding for a given tab-bar, hence the 'frame_padding' parameter. +bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id) +{ + ImGuiContext& g = *GImGui; + ImVec2 label_size = CalcTextSize(label, NULL, true); + if (bb.GetWidth() <= 1.0f) + return false; + + // Render text label (with clipping + alpha gradient) + unsaved marker + const char* TAB_UNSAVED_MARKER = "*"; + ImRect text_pixel_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y); + if (flags & ImGuiTabItemFlags_UnsavedDocument) + { + text_pixel_clip_bb.Max.x -= CalcTextSize(TAB_UNSAVED_MARKER, NULL, false).x; + ImVec2 unsaved_marker_pos(ImMin(bb.Min.x + frame_padding.x + label_size.x + 2, text_pixel_clip_bb.Max.x), bb.Min.y + frame_padding.y + (float)(int)(-g.FontSize * 0.25f)); + RenderTextClippedEx(draw_list, unsaved_marker_pos, bb.Max - frame_padding, TAB_UNSAVED_MARKER, NULL, NULL); + } + ImRect text_ellipsis_clip_bb = text_pixel_clip_bb; + + // Close Button + // We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap() + // 'hovered' will be true when hovering the Tab but NOT when hovering the close button + // 'g.HoveredId==id' will be true when hovering the Tab including when hovering the close button + // 'g.ActiveId==close_button_id' will be true when we are holding on the close button, in which case both hovered booleans are false + bool close_button_pressed = false; + bool close_button_visible = false; + if (close_button_id != 0) + if (g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == close_button_id) + close_button_visible = true; + if (close_button_visible) + { + ImGuiItemHoveredDataBackup last_item_backup; + const float close_button_sz = g.FontSize * 0.5f; + if (CloseButton(close_button_id, ImVec2(bb.Max.x - frame_padding.x - close_button_sz, bb.Min.y + frame_padding.y + close_button_sz), close_button_sz)) + close_button_pressed = true; + last_item_backup.Restore(); + + // Close with middle mouse button + if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2)) + close_button_pressed = true; + + text_pixel_clip_bb.Max.x -= close_button_sz * 2.0f; + } + + // Label with ellipsis + // FIXME: This should be extracted into a helper but the use of text_pixel_clip_bb and !close_button_visible makes it tricky to abstract at the moment + const char* label_display_end = FindRenderedTextEnd(label); + if (label_size.x > text_ellipsis_clip_bb.GetWidth()) + { + const int ellipsis_dot_count = 3; + const float ellipsis_width = (1.0f + 1.0f) * ellipsis_dot_count - 1.0f; + const char* label_end = NULL; + float label_size_clipped_x = g.Font->CalcTextSizeA(g.FontSize, text_ellipsis_clip_bb.GetWidth() - ellipsis_width + 1.0f, 0.0f, label, label_display_end, &label_end).x; + if (label_end == label && label_end < label_display_end) // Always display at least 1 character if there's no room for character + ellipsis + { + label_end = label + ImTextCountUtf8BytesFromChar(label, label_display_end); + label_size_clipped_x = g.Font->CalcTextSizeA(g.FontSize, FLT_MAX, 0.0f, label, label_end).x; + } + while (label_end > label && ImCharIsBlankA(label_end[-1])) // Trim trailing space + { + label_end--; + label_size_clipped_x -= g.Font->CalcTextSizeA(g.FontSize, FLT_MAX, 0.0f, label_end, label_end + 1).x; // Ascii blanks are always 1 byte + } + RenderTextClippedEx(draw_list, text_pixel_clip_bb.Min, text_pixel_clip_bb.Max, label, label_end, &label_size, ImVec2(0.0f, 0.0f)); + + const float ellipsis_x = text_pixel_clip_bb.Min.x + label_size_clipped_x + 1.0f; + if (!close_button_visible && ellipsis_x + ellipsis_width <= bb.Max.x) + RenderPixelEllipsis(draw_list, ImVec2(ellipsis_x, text_pixel_clip_bb.Min.y), ellipsis_dot_count, GetColorU32(ImGuiCol_Text)); + } + else + { + RenderTextClippedEx(draw_list, text_pixel_clip_bb.Min, text_pixel_clip_bb.Max, label, label_display_end, &label_size, ImVec2(0.0f, 0.0f)); + } + + return close_button_pressed; +} diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imstb_rectpack.h b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imstb_rectpack.h new file mode 100644 index 00000000..23f922a5 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imstb_rectpack.h @@ -0,0 +1,630 @@ +// [DEAR IMGUI] +// This is a slightly modified version of stb_rect_pack.h 0.99. +// Those changes would need to be pushed into nothings/stb: +// - Added STBRP__CDECL +// Grep for [DEAR IMGUI] to find the changes. + +// stb_rect_pack.h - v0.99 - public domain - rectangle packing +// Sean Barrett 2014 +// +// Useful for e.g. packing rectangular textures into an atlas. +// Does not do rotation. +// +// Not necessarily the awesomest packing method, but better than +// the totally naive one in stb_truetype (which is primarily what +// this is meant to replace). +// +// Has only had a few tests run, may have issues. +// +// More docs to come. +// +// No memory allocations; uses qsort() and assert() from stdlib. +// Can override those by defining STBRP_SORT and STBRP_ASSERT. +// +// This library currently uses the Skyline Bottom-Left algorithm. +// +// Please note: better rectangle packers are welcome! Please +// implement them to the same API, but with a different init +// function. +// +// Credits +// +// Library +// Sean Barrett +// Minor features +// Martins Mozeiko +// github:IntellectualKitty +// +// Bugfixes / warning fixes +// Jeremy Jaussaud +// +// Version history: +// +// 0.99 (2019-02-07) warning fixes +// 0.11 (2017-03-03) return packing success/fail result +// 0.10 (2016-10-25) remove cast-away-const to avoid warnings +// 0.09 (2016-08-27) fix compiler warnings +// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) +// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) +// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort +// 0.05: added STBRP_ASSERT to allow replacing assert +// 0.04: fixed minor bug in STBRP_LARGE_RECTS support +// 0.01: initial release +// +// LICENSE +// +// See end of file for license information. + +////////////////////////////////////////////////////////////////////////////// +// +// INCLUDE SECTION +// + +#ifndef STB_INCLUDE_STB_RECT_PACK_H +#define STB_INCLUDE_STB_RECT_PACK_H + +#define STB_RECT_PACK_VERSION 1 + +#ifdef STBRP_STATIC +#define STBRP_DEF static +#else +#define STBRP_DEF extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct stbrp_context stbrp_context; +typedef struct stbrp_node stbrp_node; +typedef struct stbrp_rect stbrp_rect; + +#ifdef STBRP_LARGE_RECTS +typedef int stbrp_coord; +#else +typedef unsigned short stbrp_coord; +#endif + +STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); +// Assign packed locations to rectangles. The rectangles are of type +// 'stbrp_rect' defined below, stored in the array 'rects', and there +// are 'num_rects' many of them. +// +// Rectangles which are successfully packed have the 'was_packed' flag +// set to a non-zero value and 'x' and 'y' store the minimum location +// on each axis (i.e. bottom-left in cartesian coordinates, top-left +// if you imagine y increasing downwards). Rectangles which do not fit +// have the 'was_packed' flag set to 0. +// +// You should not try to access the 'rects' array from another thread +// while this function is running, as the function temporarily reorders +// the array while it executes. +// +// To pack into another rectangle, you need to call stbrp_init_target +// again. To continue packing into the same rectangle, you can call +// this function again. Calling this multiple times with multiple rect +// arrays will probably produce worse packing results than calling it +// a single time with the full rectangle array, but the option is +// available. +// +// The function returns 1 if all of the rectangles were successfully +// packed and 0 otherwise. + +struct stbrp_rect +{ + // reserved for your use: + int id; + + // input: + stbrp_coord w, h; + + // output: + stbrp_coord x, y; + int was_packed; // non-zero if valid packing + +}; // 16 bytes, nominally + + +STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); +// Initialize a rectangle packer to: +// pack a rectangle that is 'width' by 'height' in dimensions +// using temporary storage provided by the array 'nodes', which is 'num_nodes' long +// +// You must call this function every time you start packing into a new target. +// +// There is no "shutdown" function. The 'nodes' memory must stay valid for +// the following stbrp_pack_rects() call (or calls), but can be freed after +// the call (or calls) finish. +// +// Note: to guarantee best results, either: +// 1. make sure 'num_nodes' >= 'width' +// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' +// +// If you don't do either of the above things, widths will be quantized to multiples +// of small integers to guarantee the algorithm doesn't run out of temporary storage. +// +// If you do #2, then the non-quantized algorithm will be used, but the algorithm +// may run out of temporary storage and be unable to pack some rectangles. + +STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); +// Optionally call this function after init but before doing any packing to +// change the handling of the out-of-temp-memory scenario, described above. +// If you call init again, this will be reset to the default (false). + + +STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); +// Optionally select which packing heuristic the library should use. Different +// heuristics will produce better/worse results for different data sets. +// If you call init again, this will be reset to the default. + +enum +{ + STBRP_HEURISTIC_Skyline_default=0, + STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, + STBRP_HEURISTIC_Skyline_BF_sortHeight +}; + + +////////////////////////////////////////////////////////////////////////////// +// +// the details of the following structures don't matter to you, but they must +// be visible so you can handle the memory allocations for them + +struct stbrp_node +{ + stbrp_coord x,y; + stbrp_node *next; +}; + +struct stbrp_context +{ + int width; + int height; + int align; + int init_mode; + int heuristic; + int num_nodes; + stbrp_node *active_head; + stbrp_node *free_head; + stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' +}; + +#ifdef __cplusplus +} +#endif + +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// IMPLEMENTATION SECTION +// + +#ifdef STB_RECT_PACK_IMPLEMENTATION +#ifndef STBRP_SORT +#include +#define STBRP_SORT qsort +#endif + +#ifndef STBRP_ASSERT +#include +#define STBRP_ASSERT assert +#endif + +// [DEAR IMGUI] Added STBRP__CDECL +#ifdef _MSC_VER +#define STBRP__NOTUSED(v) (void)(v) +#define STBRP__CDECL __cdecl +#else +#define STBRP__NOTUSED(v) (void)sizeof(v) +#define STBRP__CDECL +#endif + +enum +{ + STBRP__INIT_skyline = 1 +}; + +STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) +{ + switch (context->init_mode) { + case STBRP__INIT_skyline: + STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); + context->heuristic = heuristic; + break; + default: + STBRP_ASSERT(0); + } +} + +STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) +{ + if (allow_out_of_mem) + // if it's ok to run out of memory, then don't bother aligning them; + // this gives better packing, but may fail due to OOM (even though + // the rectangles easily fit). @TODO a smarter approach would be to only + // quantize once we've hit OOM, then we could get rid of this parameter. + context->align = 1; + else { + // if it's not ok to run out of memory, then quantize the widths + // so that num_nodes is always enough nodes. + // + // I.e. num_nodes * align >= width + // align >= width / num_nodes + // align = ceil(width/num_nodes) + + context->align = (context->width + context->num_nodes-1) / context->num_nodes; + } +} + +STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) +{ + int i; +#ifndef STBRP_LARGE_RECTS + STBRP_ASSERT(width <= 0xffff && height <= 0xffff); +#endif + + for (i=0; i < num_nodes-1; ++i) + nodes[i].next = &nodes[i+1]; + nodes[i].next = NULL; + context->init_mode = STBRP__INIT_skyline; + context->heuristic = STBRP_HEURISTIC_Skyline_default; + context->free_head = &nodes[0]; + context->active_head = &context->extra[0]; + context->width = width; + context->height = height; + context->num_nodes = num_nodes; + stbrp_setup_allow_out_of_mem(context, 0); + + // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) + context->extra[0].x = 0; + context->extra[0].y = 0; + context->extra[0].next = &context->extra[1]; + context->extra[1].x = (stbrp_coord) width; +#ifdef STBRP_LARGE_RECTS + context->extra[1].y = (1<<30); +#else + context->extra[1].y = 65535; +#endif + context->extra[1].next = NULL; +} + +// find minimum y position if it starts at x1 +static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) +{ + stbrp_node *node = first; + int x1 = x0 + width; + int min_y, visited_width, waste_area; + + STBRP__NOTUSED(c); + + STBRP_ASSERT(first->x <= x0); + + #if 0 + // skip in case we're past the node + while (node->next->x <= x0) + ++node; + #else + STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency + #endif + + STBRP_ASSERT(node->x <= x0); + + min_y = 0; + waste_area = 0; + visited_width = 0; + while (node->x < x1) { + if (node->y > min_y) { + // raise min_y higher. + // we've accounted for all waste up to min_y, + // but we'll now add more waste for everything we've visted + waste_area += visited_width * (node->y - min_y); + min_y = node->y; + // the first time through, visited_width might be reduced + if (node->x < x0) + visited_width += node->next->x - x0; + else + visited_width += node->next->x - node->x; + } else { + // add waste area + int under_width = node->next->x - node->x; + if (under_width + visited_width > width) + under_width = width - visited_width; + waste_area += under_width * (min_y - node->y); + visited_width += under_width; + } + node = node->next; + } + + *pwaste = waste_area; + return min_y; +} + +typedef struct +{ + int x,y; + stbrp_node **prev_link; +} stbrp__findresult; + +static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) +{ + int best_waste = (1<<30), best_x, best_y = (1 << 30); + stbrp__findresult fr; + stbrp_node **prev, *node, *tail, **best = NULL; + + // align to multiple of c->align + width = (width + c->align - 1); + width -= width % c->align; + STBRP_ASSERT(width % c->align == 0); + + node = c->active_head; + prev = &c->active_head; + while (node->x + width <= c->width) { + int y,waste; + y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); + if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL + // bottom left + if (y < best_y) { + best_y = y; + best = prev; + } + } else { + // best-fit + if (y + height <= c->height) { + // can only use it if it first vertically + if (y < best_y || (y == best_y && waste < best_waste)) { + best_y = y; + best_waste = waste; + best = prev; + } + } + } + prev = &node->next; + node = node->next; + } + + best_x = (best == NULL) ? 0 : (*best)->x; + + // if doing best-fit (BF), we also have to try aligning right edge to each node position + // + // e.g, if fitting + // + // ____________________ + // |____________________| + // + // into + // + // | | + // | ____________| + // |____________| + // + // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned + // + // This makes BF take about 2x the time + + if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { + tail = c->active_head; + node = c->active_head; + prev = &c->active_head; + // find first node that's admissible + while (tail->x < width) + tail = tail->next; + while (tail) { + int xpos = tail->x - width; + int y,waste; + STBRP_ASSERT(xpos >= 0); + // find the left position that matches this + while (node->next->x <= xpos) { + prev = &node->next; + node = node->next; + } + STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); + y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); + if (y + height < c->height) { + if (y <= best_y) { + if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { + best_x = xpos; + STBRP_ASSERT(y <= best_y); + best_y = y; + best_waste = waste; + best = prev; + } + } + } + tail = tail->next; + } + } + + fr.prev_link = best; + fr.x = best_x; + fr.y = best_y; + return fr; +} + +static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) +{ + // find best position according to heuristic + stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); + stbrp_node *node, *cur; + + // bail if: + // 1. it failed + // 2. the best node doesn't fit (we don't always check this) + // 3. we're out of memory + if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { + res.prev_link = NULL; + return res; + } + + // on success, create new node + node = context->free_head; + node->x = (stbrp_coord) res.x; + node->y = (stbrp_coord) (res.y + height); + + context->free_head = node->next; + + // insert the new node into the right starting point, and + // let 'cur' point to the remaining nodes needing to be + // stiched back in + + cur = *res.prev_link; + if (cur->x < res.x) { + // preserve the existing one, so start testing with the next one + stbrp_node *next = cur->next; + cur->next = node; + cur = next; + } else { + *res.prev_link = node; + } + + // from here, traverse cur and free the nodes, until we get to one + // that shouldn't be freed + while (cur->next && cur->next->x <= res.x + width) { + stbrp_node *next = cur->next; + // move the current node to the free list + cur->next = context->free_head; + context->free_head = cur; + cur = next; + } + + // stitch the list back in + node->next = cur; + + if (cur->x < res.x + width) + cur->x = (stbrp_coord) (res.x + width); + +#ifdef _DEBUG + cur = context->active_head; + while (cur->x < context->width) { + STBRP_ASSERT(cur->x < cur->next->x); + cur = cur->next; + } + STBRP_ASSERT(cur->next == NULL); + + { + int count=0; + cur = context->active_head; + while (cur) { + cur = cur->next; + ++count; + } + cur = context->free_head; + while (cur) { + cur = cur->next; + ++count; + } + STBRP_ASSERT(count == context->num_nodes+2); + } +#endif + + return res; +} + +// [DEAR IMGUI] Added STBRP__CDECL +static int STBRP__CDECL rect_height_compare(const void *a, const void *b) +{ + const stbrp_rect *p = (const stbrp_rect *) a; + const stbrp_rect *q = (const stbrp_rect *) b; + if (p->h > q->h) + return -1; + if (p->h < q->h) + return 1; + return (p->w > q->w) ? -1 : (p->w < q->w); +} + +// [DEAR IMGUI] Added STBRP__CDECL +static int STBRP__CDECL rect_original_order(const void *a, const void *b) +{ + const stbrp_rect *p = (const stbrp_rect *) a; + const stbrp_rect *q = (const stbrp_rect *) b; + return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); +} + +#ifdef STBRP_LARGE_RECTS +#define STBRP__MAXVAL 0xffffffff +#else +#define STBRP__MAXVAL 0xffff +#endif + +STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) +{ + int i, all_rects_packed = 1; + + // we use the 'was_packed' field internally to allow sorting/unsorting + for (i=0; i < num_rects; ++i) { + rects[i].was_packed = i; + } + + // sort according to heuristic + STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); + + for (i=0; i < num_rects; ++i) { + if (rects[i].w == 0 || rects[i].h == 0) { + rects[i].x = rects[i].y = 0; // empty rect needs no space + } else { + stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); + if (fr.prev_link) { + rects[i].x = (stbrp_coord) fr.x; + rects[i].y = (stbrp_coord) fr.y; + } else { + rects[i].x = rects[i].y = STBRP__MAXVAL; + } + } + } + + // unsort + STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); + + // set was_packed flags and all_rects_packed status + for (i=0; i < num_rects; ++i) { + rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); + if (!rects[i].was_packed) + all_rects_packed = 0; + } + + // return the all_rects_packed status + return all_rects_packed; +} +#endif + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imstb_textedit.h b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imstb_textedit.h new file mode 100644 index 00000000..d7fcbd62 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imstb_textedit.h @@ -0,0 +1,1417 @@ +// [DEAR IMGUI] +// This is a slightly modified version of stb_textedit.h 1.13. +// Those changes would need to be pushed into nothings/stb: +// - Fix in stb_textedit_discard_redo (see /~https://github.com/nothings/stb/issues/321) +// Grep for [DEAR IMGUI] to find the changes. + +// stb_textedit.h - v1.13 - public domain - Sean Barrett +// Development of this library was sponsored by RAD Game Tools +// +// This C header file implements the guts of a multi-line text-editing +// widget; you implement display, word-wrapping, and low-level string +// insertion/deletion, and stb_textedit will map user inputs into +// insertions & deletions, plus updates to the cursor position, +// selection state, and undo state. +// +// It is intended for use in games and other systems that need to build +// their own custom widgets and which do not have heavy text-editing +// requirements (this library is not recommended for use for editing large +// texts, as its performance does not scale and it has limited undo). +// +// Non-trivial behaviors are modelled after Windows text controls. +// +// +// LICENSE +// +// See end of file for license information. +// +// +// DEPENDENCIES +// +// Uses the C runtime function 'memmove', which you can override +// by defining STB_TEXTEDIT_memmove before the implementation. +// Uses no other functions. Performs no runtime allocations. +// +// +// VERSION HISTORY +// +// 1.13 (2019-02-07) fix bug in undo size management +// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash +// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield +// 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual +// 1.9 (2016-08-27) customizable move-by-word +// 1.8 (2016-04-02) better keyboard handling when mouse button is down +// 1.7 (2015-09-13) change y range handling in case baseline is non-0 +// 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove +// 1.5 (2014-09-10) add support for secondary keys for OS X +// 1.4 (2014-08-17) fix signed/unsigned warnings +// 1.3 (2014-06-19) fix mouse clicking to round to nearest char boundary +// 1.2 (2014-05-27) fix some RAD types that had crept into the new code +// 1.1 (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE ) +// 1.0 (2012-07-26) improve documentation, initial public release +// 0.3 (2012-02-24) bugfixes, single-line mode; insert mode +// 0.2 (2011-11-28) fixes to undo/redo +// 0.1 (2010-07-08) initial version +// +// ADDITIONAL CONTRIBUTORS +// +// Ulf Winklemann: move-by-word in 1.1 +// Fabian Giesen: secondary key inputs in 1.5 +// Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6 +// +// Bugfixes: +// Scott Graham +// Daniel Keller +// Omar Cornut +// Dan Thompson +// +// USAGE +// +// This file behaves differently depending on what symbols you define +// before including it. +// +// +// Header-file mode: +// +// If you do not define STB_TEXTEDIT_IMPLEMENTATION before including this, +// it will operate in "header file" mode. In this mode, it declares a +// single public symbol, STB_TexteditState, which encapsulates the current +// state of a text widget (except for the string, which you will store +// separately). +// +// To compile in this mode, you must define STB_TEXTEDIT_CHARTYPE to a +// primitive type that defines a single character (e.g. char, wchar_t, etc). +// +// To save space or increase undo-ability, you can optionally define the +// following things that are used by the undo system: +// +// STB_TEXTEDIT_POSITIONTYPE small int type encoding a valid cursor position +// STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow +// STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer +// +// If you don't define these, they are set to permissive types and +// moderate sizes. The undo system does no memory allocations, so +// it grows STB_TexteditState by the worst-case storage which is (in bytes): +// +// [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT +// + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT +// +// +// Implementation mode: +// +// If you define STB_TEXTEDIT_IMPLEMENTATION before including this, it +// will compile the implementation of the text edit widget, depending +// on a large number of symbols which must be defined before the include. +// +// The implementation is defined only as static functions. You will then +// need to provide your own APIs in the same file which will access the +// static functions. +// +// The basic concept is that you provide a "string" object which +// behaves like an array of characters. stb_textedit uses indices to +// refer to positions in the string, implicitly representing positions +// in the displayed textedit. This is true for both plain text and +// rich text; even with rich text stb_truetype interacts with your +// code as if there was an array of all the displayed characters. +// +// Symbols that must be the same in header-file and implementation mode: +// +// STB_TEXTEDIT_CHARTYPE the character type +// STB_TEXTEDIT_POSITIONTYPE small type that is a valid cursor position +// STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow +// STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer +// +// Symbols you must define for implementation mode: +// +// STB_TEXTEDIT_STRING the type of object representing a string being edited, +// typically this is a wrapper object with other data you need +// +// STB_TEXTEDIT_STRINGLEN(obj) the length of the string (ideally O(1)) +// STB_TEXTEDIT_LAYOUTROW(&r,obj,n) returns the results of laying out a line of characters +// starting from character #n (see discussion below) +// STB_TEXTEDIT_GETWIDTH(obj,n,i) returns the pixel delta from the xpos of the i'th character +// to the xpos of the i+1'th char for a line of characters +// starting at character #n (i.e. accounts for kerning +// with previous char) +// STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character +// (return type is int, -1 means not valid to insert) +// STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based +// STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize +// as manually wordwrapping for end-of-line positioning +// +// STB_TEXTEDIT_DELETECHARS(obj,i,n) delete n characters starting at i +// STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n) insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*) +// +// STB_TEXTEDIT_K_SHIFT a power of two that is or'd in to a keyboard input to represent the shift key +// +// STB_TEXTEDIT_K_LEFT keyboard input to move cursor left +// STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right +// STB_TEXTEDIT_K_UP keyboard input to move cursor up +// STB_TEXTEDIT_K_DOWN keyboard input to move cursor down +// STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME +// STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END +// STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME +// STB_TEXTEDIT_K_TEXTEND keyboard input to move cursor to end of text // e.g. ctrl-END +// STB_TEXTEDIT_K_DELETE keyboard input to delete selection or character under cursor +// STB_TEXTEDIT_K_BACKSPACE keyboard input to delete selection or character left of cursor +// STB_TEXTEDIT_K_UNDO keyboard input to perform undo +// STB_TEXTEDIT_K_REDO keyboard input to perform redo +// +// Optional: +// STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode +// STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'), +// required for default WORDLEFT/WORDRIGHT handlers +// STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to +// STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to +// STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT +// STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT +// STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line +// STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line +// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text +// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text +// +// Todo: +// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page +// STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page +// +// Keyboard input must be encoded as a single integer value; e.g. a character code +// and some bitflags that represent shift states. to simplify the interface, SHIFT must +// be a bitflag, so we can test the shifted state of cursor movements to allow selection, +// i.e. (STB_TEXTED_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. +// +// You can encode other things, such as CONTROL or ALT, in additional bits, and +// then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example, +// my Windows implementations add an additional CONTROL bit, and an additional KEYDOWN +// bit. Then all of the STB_TEXTEDIT_K_ values bitwise-or in the KEYDOWN bit, +// and I pass both WM_KEYDOWN and WM_CHAR events to the "key" function in the +// API below. The control keys will only match WM_KEYDOWN events because of the +// keydown bit I add, and STB_TEXTEDIT_KEYTOTEXT only tests for the KEYDOWN +// bit so it only decodes WM_CHAR events. +// +// STB_TEXTEDIT_LAYOUTROW returns information about the shape of one displayed +// row of characters assuming they start on the i'th character--the width and +// the height and the number of characters consumed. This allows this library +// to traverse the entire layout incrementally. You need to compute word-wrapping +// here. +// +// Each textfield keeps its own insert mode state, which is not how normal +// applications work. To keep an app-wide insert mode, update/copy the +// "insert_mode" field of STB_TexteditState before/after calling API functions. +// +// API +// +// void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) +// +// void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +// void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +// int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +// int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) +// void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key) +// +// Each of these functions potentially updates the string and updates the +// state. +// +// initialize_state: +// set the textedit state to a known good default state when initially +// constructing the textedit. +// +// click: +// call this with the mouse x,y on a mouse down; it will update the cursor +// and reset the selection start/end to the cursor point. the x,y must +// be relative to the text widget, with (0,0) being the top left. +// +// drag: +// call this with the mouse x,y on a mouse drag/up; it will update the +// cursor and the selection end point +// +// cut: +// call this to delete the current selection; returns true if there was +// one. you should FIRST copy the current selection to the system paste buffer. +// (To copy, just copy the current selection out of the string yourself.) +// +// paste: +// call this to paste text at the current cursor point or over the current +// selection if there is one. +// +// key: +// call this for keyboard inputs sent to the textfield. you can use it +// for "key down" events or for "translated" key events. if you need to +// do both (as in Win32), or distinguish Unicode characters from control +// inputs, set a high bit to distinguish the two; then you can define the +// various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit +// set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is +// clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to +// anything other type you wante before including. +// +// +// When rendering, you can read the cursor position and selection state from +// the STB_TexteditState. +// +// +// Notes: +// +// This is designed to be usable in IMGUI, so it allows for the possibility of +// running in an IMGUI that has NOT cached the multi-line layout. For this +// reason, it provides an interface that is compatible with computing the +// layout incrementally--we try to make sure we make as few passes through +// as possible. (For example, to locate the mouse pointer in the text, we +// could define functions that return the X and Y positions of characters +// and binary search Y and then X, but if we're doing dynamic layout this +// will run the layout algorithm many times, so instead we manually search +// forward in one pass. Similar logic applies to e.g. up-arrow and +// down-arrow movement.) +// +// If it's run in a widget that *has* cached the layout, then this is less +// efficient, but it's not horrible on modern computers. But you wouldn't +// want to edit million-line files with it. + + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//// +//// Header-file mode +//// +//// + +#ifndef INCLUDE_STB_TEXTEDIT_H +#define INCLUDE_STB_TEXTEDIT_H + +//////////////////////////////////////////////////////////////////////// +// +// STB_TexteditState +// +// Definition of STB_TexteditState which you should store +// per-textfield; it includes cursor position, selection state, +// and undo state. +// + +#ifndef STB_TEXTEDIT_UNDOSTATECOUNT +#define STB_TEXTEDIT_UNDOSTATECOUNT 99 +#endif +#ifndef STB_TEXTEDIT_UNDOCHARCOUNT +#define STB_TEXTEDIT_UNDOCHARCOUNT 999 +#endif +#ifndef STB_TEXTEDIT_CHARTYPE +#define STB_TEXTEDIT_CHARTYPE int +#endif +#ifndef STB_TEXTEDIT_POSITIONTYPE +#define STB_TEXTEDIT_POSITIONTYPE int +#endif + +typedef struct +{ + // private data + STB_TEXTEDIT_POSITIONTYPE where; + STB_TEXTEDIT_POSITIONTYPE insert_length; + STB_TEXTEDIT_POSITIONTYPE delete_length; + int char_storage; +} StbUndoRecord; + +typedef struct +{ + // private data + StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT]; + STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT]; + short undo_point, redo_point; + int undo_char_point, redo_char_point; +} StbUndoState; + +typedef struct +{ + ///////////////////// + // + // public data + // + + int cursor; + // position of the text cursor within the string + + int select_start; // selection start point + int select_end; + // selection start and end point in characters; if equal, no selection. + // note that start may be less than or greater than end (e.g. when + // dragging the mouse, start is where the initial click was, and you + // can drag in either direction) + + unsigned char insert_mode; + // each textfield keeps its own insert mode state. to keep an app-wide + // insert mode, copy this value in/out of the app state + + ///////////////////// + // + // private data + // + unsigned char cursor_at_end_of_line; // not implemented yet + unsigned char initialized; + unsigned char has_preferred_x; + unsigned char single_line; + unsigned char padding1, padding2, padding3; + float preferred_x; // this determines where the cursor up/down tries to seek to along x + StbUndoState undostate; +} STB_TexteditState; + + +//////////////////////////////////////////////////////////////////////// +// +// StbTexteditRow +// +// Result of layout query, used by stb_textedit to determine where +// the text in each row is. + +// result of layout query +typedef struct +{ + float x0,x1; // starting x location, end x location (allows for align=right, etc) + float baseline_y_delta; // position of baseline relative to previous row's baseline + float ymin,ymax; // height of row above and below baseline + int num_chars; +} StbTexteditRow; +#endif //INCLUDE_STB_TEXTEDIT_H + + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//// +//// Implementation mode +//// +//// + + +// implementation isn't include-guarded, since it might have indirectly +// included just the "header" portion +#ifdef STB_TEXTEDIT_IMPLEMENTATION + +#ifndef STB_TEXTEDIT_memmove +#include +#define STB_TEXTEDIT_memmove memmove +#endif + + +///////////////////////////////////////////////////////////////////////////// +// +// Mouse input handling +// + +// traverse the layout to locate the nearest character to a display position +static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y) +{ + StbTexteditRow r; + int n = STB_TEXTEDIT_STRINGLEN(str); + float base_y = 0, prev_x; + int i=0, k; + + r.x0 = r.x1 = 0; + r.ymin = r.ymax = 0; + r.num_chars = 0; + + // search rows to find one that straddles 'y' + while (i < n) { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + if (r.num_chars <= 0) + return n; + + if (i==0 && y < base_y + r.ymin) + return 0; + + if (y < base_y + r.ymax) + break; + + i += r.num_chars; + base_y += r.baseline_y_delta; + } + + // below all text, return 'after' last character + if (i >= n) + return n; + + // check if it's before the beginning of the line + if (x < r.x0) + return i; + + // check if it's before the end of the line + if (x < r.x1) { + // search characters in row for one that straddles 'x' + prev_x = r.x0; + for (k=0; k < r.num_chars; ++k) { + float w = STB_TEXTEDIT_GETWIDTH(str, i, k); + if (x < prev_x+w) { + if (x < prev_x+w/2) + return k+i; + else + return k+i+1; + } + prev_x += w; + } + // shouldn't happen, but if it does, fall through to end-of-line case + } + + // if the last character is a newline, return that. otherwise return 'after' the last character + if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE) + return i+r.num_chars-1; + else + return i+r.num_chars; +} + +// API click: on mouse down, move the cursor to the clicked location, and reset the selection +static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +{ + // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse + // goes off the top or bottom of the text + if( state->single_line ) + { + StbTexteditRow r; + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + y = r.ymin; + } + + state->cursor = stb_text_locate_coord(str, x, y); + state->select_start = state->cursor; + state->select_end = state->cursor; + state->has_preferred_x = 0; +} + +// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location +static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +{ + int p = 0; + + // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse + // goes off the top or bottom of the text + if( state->single_line ) + { + StbTexteditRow r; + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + y = r.ymin; + } + + if (state->select_start == state->select_end) + state->select_start = state->cursor; + + p = stb_text_locate_coord(str, x, y); + state->cursor = state->select_end = p; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Keyboard input handling +// + +// forward declarations +static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); +static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); +static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length); +static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length); +static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length); + +typedef struct +{ + float x,y; // position of n'th character + float height; // height of line + int first_char, length; // first char of row, and length + int prev_first; // first char of previous row +} StbFindState; + +// find the x/y location of a character, and remember info about the previous row in +// case we get a move-up event (for page up, we'll have to rescan) +static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line) +{ + StbTexteditRow r; + int prev_start = 0; + int z = STB_TEXTEDIT_STRINGLEN(str); + int i=0, first; + + if (n == z) { + // if it's at the end, then find the last line -- simpler than trying to + // explicitly handle this case in the regular code + if (single_line) { + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + find->y = 0; + find->first_char = 0; + find->length = z; + find->height = r.ymax - r.ymin; + find->x = r.x1; + } else { + find->y = 0; + find->x = 0; + find->height = 1; + while (i < z) { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + prev_start = i; + i += r.num_chars; + } + find->first_char = i; + find->length = 0; + find->prev_first = prev_start; + } + return; + } + + // search rows to find the one that straddles character n + find->y = 0; + + for(;;) { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + if (n < i + r.num_chars) + break; + prev_start = i; + i += r.num_chars; + find->y += r.baseline_y_delta; + } + + find->first_char = first = i; + find->length = r.num_chars; + find->height = r.ymax - r.ymin; + find->prev_first = prev_start; + + // now scan to find xpos + find->x = r.x0; + for (i=0; first+i < n; ++i) + find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); +} + +#define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) + +// make the selection/cursor state valid if client altered the string +static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + int n = STB_TEXTEDIT_STRINGLEN(str); + if (STB_TEXT_HAS_SELECTION(state)) { + if (state->select_start > n) state->select_start = n; + if (state->select_end > n) state->select_end = n; + // if clamping forced them to be equal, move the cursor to match + if (state->select_start == state->select_end) + state->cursor = state->select_start; + } + if (state->cursor > n) state->cursor = n; +} + +// delete characters while updating undo +static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len) +{ + stb_text_makeundo_delete(str, state, where, len); + STB_TEXTEDIT_DELETECHARS(str, where, len); + state->has_preferred_x = 0; +} + +// delete the section +static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + stb_textedit_clamp(str, state); + if (STB_TEXT_HAS_SELECTION(state)) { + if (state->select_start < state->select_end) { + stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start); + state->select_end = state->cursor = state->select_start; + } else { + stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end); + state->select_start = state->cursor = state->select_end; + } + state->has_preferred_x = 0; + } +} + +// canoncialize the selection so start <= end +static void stb_textedit_sortselection(STB_TexteditState *state) +{ + if (state->select_end < state->select_start) { + int temp = state->select_end; + state->select_end = state->select_start; + state->select_start = temp; + } +} + +// move cursor to first character of selection +static void stb_textedit_move_to_first(STB_TexteditState *state) +{ + if (STB_TEXT_HAS_SELECTION(state)) { + stb_textedit_sortselection(state); + state->cursor = state->select_start; + state->select_end = state->select_start; + state->has_preferred_x = 0; + } +} + +// move cursor to last character of selection +static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + if (STB_TEXT_HAS_SELECTION(state)) { + stb_textedit_sortselection(state); + stb_textedit_clamp(str, state); + state->cursor = state->select_end; + state->select_start = state->select_end; + state->has_preferred_x = 0; + } +} + +#ifdef STB_TEXTEDIT_IS_SPACE +static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx ) +{ + return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1; +} + +#ifndef STB_TEXTEDIT_MOVEWORDLEFT +static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c ) +{ + --c; // always move at least one character + while( c >= 0 && !is_word_boundary( str, c ) ) + --c; + + if( c < 0 ) + c = 0; + + return c; +} +#define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous +#endif + +#ifndef STB_TEXTEDIT_MOVEWORDRIGHT +static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c ) +{ + const int len = STB_TEXTEDIT_STRINGLEN(str); + ++c; // always move at least one character + while( c < len && !is_word_boundary( str, c ) ) + ++c; + + if( c > len ) + c = len; + + return c; +} +#define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next +#endif + +#endif + +// update selection and cursor to match each other +static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state) +{ + if (!STB_TEXT_HAS_SELECTION(state)) + state->select_start = state->select_end = state->cursor; + else + state->cursor = state->select_end; +} + +// API cut: delete selection +static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + if (STB_TEXT_HAS_SELECTION(state)) { + stb_textedit_delete_selection(str,state); // implicitly clamps + state->has_preferred_x = 0; + return 1; + } + return 0; +} + +// API paste: replace existing selection with passed-in text +static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) +{ + // if there's a selection, the paste should delete it + stb_textedit_clamp(str, state); + stb_textedit_delete_selection(str,state); + // try to insert the characters + if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) { + stb_text_makeundo_insert(state, state->cursor, len); + state->cursor += len; + state->has_preferred_x = 0; + return 1; + } + // remove the undo since we didn't actually insert the characters + if (state->undostate.undo_point) + --state->undostate.undo_point; + return 0; +} + +#ifndef STB_TEXTEDIT_KEYTYPE +#define STB_TEXTEDIT_KEYTYPE int +#endif + +// API key: process a keyboard input +static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key) +{ +retry: + switch (key) { + default: { + int c = STB_TEXTEDIT_KEYTOTEXT(key); + if (c > 0) { + STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c; + + // can't add newline in single-line mode + if (c == '\n' && state->single_line) + break; + + if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { + stb_text_makeundo_replace(str, state, state->cursor, 1, 1); + STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); + if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { + ++state->cursor; + state->has_preferred_x = 0; + } + } else { + stb_textedit_delete_selection(str,state); // implicitly clamps + if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { + stb_text_makeundo_insert(state, state->cursor, 1); + ++state->cursor; + state->has_preferred_x = 0; + } + } + } + break; + } + +#ifdef STB_TEXTEDIT_K_INSERT + case STB_TEXTEDIT_K_INSERT: + state->insert_mode = !state->insert_mode; + break; +#endif + + case STB_TEXTEDIT_K_UNDO: + stb_text_undo(str, state); + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_REDO: + stb_text_redo(str, state); + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_LEFT: + // if currently there's a selection, move cursor to start of selection + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_first(state); + else + if (state->cursor > 0) + --state->cursor; + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_RIGHT: + // if currently there's a selection, move cursor to end of selection + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_last(str, state); + else + ++state->cursor; + stb_textedit_clamp(str, state); + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: + stb_textedit_clamp(str, state); + stb_textedit_prep_selection_at_cursor(state); + // move selection left + if (state->select_end > 0) + --state->select_end; + state->cursor = state->select_end; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_MOVEWORDLEFT + case STB_TEXTEDIT_K_WORDLEFT: + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_first(state); + else { + state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); + stb_textedit_clamp( str, state ); + } + break; + + case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT: + if( !STB_TEXT_HAS_SELECTION( state ) ) + stb_textedit_prep_selection_at_cursor(state); + + state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); + state->select_end = state->cursor; + + stb_textedit_clamp( str, state ); + break; +#endif + +#ifdef STB_TEXTEDIT_MOVEWORDRIGHT + case STB_TEXTEDIT_K_WORDRIGHT: + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_last(str, state); + else { + state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); + stb_textedit_clamp( str, state ); + } + break; + + case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: + if( !STB_TEXT_HAS_SELECTION( state ) ) + stb_textedit_prep_selection_at_cursor(state); + + state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); + state->select_end = state->cursor; + + stb_textedit_clamp( str, state ); + break; +#endif + + case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: + stb_textedit_prep_selection_at_cursor(state); + // move selection right + ++state->select_end; + stb_textedit_clamp(str, state); + state->cursor = state->select_end; + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_DOWN: + case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: { + StbFindState find; + StbTexteditRow row; + int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; + + if (state->single_line) { + // on windows, up&down in single-line behave like left&right + key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); + goto retry; + } + + if (sel) + stb_textedit_prep_selection_at_cursor(state); + else if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_last(str,state); + + // compute current position of cursor point + stb_textedit_clamp(str, state); + stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); + + // now find character position down a row + if (find.length) { + float goal_x = state->has_preferred_x ? state->preferred_x : find.x; + float x; + int start = find.first_char + find.length; + state->cursor = start; + STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); + x = row.x0; + for (i=0; i < row.num_chars; ++i) { + float dx = STB_TEXTEDIT_GETWIDTH(str, start, i); + #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE + if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) + break; + #endif + x += dx; + if (x > goal_x) + break; + ++state->cursor; + } + stb_textedit_clamp(str, state); + + state->has_preferred_x = 1; + state->preferred_x = goal_x; + + if (sel) + state->select_end = state->cursor; + } + break; + } + + case STB_TEXTEDIT_K_UP: + case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: { + StbFindState find; + StbTexteditRow row; + int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; + + if (state->single_line) { + // on windows, up&down become left&right + key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); + goto retry; + } + + if (sel) + stb_textedit_prep_selection_at_cursor(state); + else if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_first(state); + + // compute current position of cursor point + stb_textedit_clamp(str, state); + stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); + + // can only go up if there's a previous row + if (find.prev_first != find.first_char) { + // now find character position up a row + float goal_x = state->has_preferred_x ? state->preferred_x : find.x; + float x; + state->cursor = find.prev_first; + STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); + x = row.x0; + for (i=0; i < row.num_chars; ++i) { + float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i); + #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE + if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) + break; + #endif + x += dx; + if (x > goal_x) + break; + ++state->cursor; + } + stb_textedit_clamp(str, state); + + state->has_preferred_x = 1; + state->preferred_x = goal_x; + + if (sel) + state->select_end = state->cursor; + } + break; + } + + case STB_TEXTEDIT_K_DELETE: + case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT: + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_delete_selection(str, state); + else { + int n = STB_TEXTEDIT_STRINGLEN(str); + if (state->cursor < n) + stb_textedit_delete(str, state, state->cursor, 1); + } + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_BACKSPACE: + case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT: + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_delete_selection(str, state); + else { + stb_textedit_clamp(str, state); + if (state->cursor > 0) { + stb_textedit_delete(str, state, state->cursor-1, 1); + --state->cursor; + } + } + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_TEXTSTART2 + case STB_TEXTEDIT_K_TEXTSTART2: +#endif + case STB_TEXTEDIT_K_TEXTSTART: + state->cursor = state->select_start = state->select_end = 0; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_TEXTEND2 + case STB_TEXTEDIT_K_TEXTEND2: +#endif + case STB_TEXTEDIT_K_TEXTEND: + state->cursor = STB_TEXTEDIT_STRINGLEN(str); + state->select_start = state->select_end = 0; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_TEXTSTART2 + case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT: +#endif + case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT: + stb_textedit_prep_selection_at_cursor(state); + state->cursor = state->select_end = 0; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_TEXTEND2 + case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT: +#endif + case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT: + stb_textedit_prep_selection_at_cursor(state); + state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str); + state->has_preferred_x = 0; + break; + + +#ifdef STB_TEXTEDIT_K_LINESTART2 + case STB_TEXTEDIT_K_LINESTART2: +#endif + case STB_TEXTEDIT_K_LINESTART: + stb_textedit_clamp(str, state); + stb_textedit_move_to_first(state); + if (state->single_line) + state->cursor = 0; + else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) + --state->cursor; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_LINEEND2 + case STB_TEXTEDIT_K_LINEEND2: +#endif + case STB_TEXTEDIT_K_LINEEND: { + int n = STB_TEXTEDIT_STRINGLEN(str); + stb_textedit_clamp(str, state); + stb_textedit_move_to_first(state); + if (state->single_line) + state->cursor = n; + else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) + ++state->cursor; + state->has_preferred_x = 0; + break; + } + +#ifdef STB_TEXTEDIT_K_LINESTART2 + case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: +#endif + case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: + stb_textedit_clamp(str, state); + stb_textedit_prep_selection_at_cursor(state); + if (state->single_line) + state->cursor = 0; + else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) + --state->cursor; + state->select_end = state->cursor; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_LINEEND2 + case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: +#endif + case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { + int n = STB_TEXTEDIT_STRINGLEN(str); + stb_textedit_clamp(str, state); + stb_textedit_prep_selection_at_cursor(state); + if (state->single_line) + state->cursor = n; + else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) + ++state->cursor; + state->select_end = state->cursor; + state->has_preferred_x = 0; + break; + } + +// @TODO: +// STB_TEXTEDIT_K_PGUP - move cursor up a page +// STB_TEXTEDIT_K_PGDOWN - move cursor down a page + } +} + +///////////////////////////////////////////////////////////////////////////// +// +// Undo processing +// +// @OPTIMIZE: the undo/redo buffer should be circular + +static void stb_textedit_flush_redo(StbUndoState *state) +{ + state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; + state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; +} + +// discard the oldest entry in the undo list +static void stb_textedit_discard_undo(StbUndoState *state) +{ + if (state->undo_point > 0) { + // if the 0th undo state has characters, clean those up + if (state->undo_rec[0].char_storage >= 0) { + int n = state->undo_rec[0].insert_length, i; + // delete n characters from all other records + state->undo_char_point -= n; + STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); + for (i=0; i < state->undo_point; ++i) + if (state->undo_rec[i].char_storage >= 0) + state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it + } + --state->undo_point; + STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0]))); + } +} + +// discard the oldest entry in the redo list--it's bad if this +// ever happens, but because undo & redo have to store the actual +// characters in different cases, the redo character buffer can +// fill up even though the undo buffer didn't +static void stb_textedit_discard_redo(StbUndoState *state) +{ + int k = STB_TEXTEDIT_UNDOSTATECOUNT-1; + + if (state->redo_point <= k) { + // if the k'th undo state has characters, clean those up + if (state->undo_rec[k].char_storage >= 0) { + int n = state->undo_rec[k].insert_length, i; + // move the remaining redo character data to the end of the buffer + state->redo_char_point += n; + STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); + // adjust the position of all the other records to account for above memmove + for (i=state->redo_point; i < k; ++i) + if (state->undo_rec[i].char_storage >= 0) + state->undo_rec[i].char_storage += n; + } + // now move all the redo records towards the end of the buffer; the first one is at 'redo_point' + // {DEAR IMGUI] + size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0])); + const char* buf_begin = (char*)state->undo_rec; (void)buf_begin; + const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end; + IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin); + IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end); + STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size); + + // now move redo_point to point to the new one + ++state->redo_point; + } +} + +static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numchars) +{ + // any time we create a new undo record, we discard redo + stb_textedit_flush_redo(state); + + // if we have no free records, we have to make room, by sliding the + // existing records down + if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT) + stb_textedit_discard_undo(state); + + // if the characters to store won't possibly fit in the buffer, we can't undo + if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) { + state->undo_point = 0; + state->undo_char_point = 0; + return NULL; + } + + // if we don't have enough free characters in the buffer, we have to make room + while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT) + stb_textedit_discard_undo(state); + + return &state->undo_rec[state->undo_point++]; +} + +static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len) +{ + StbUndoRecord *r = stb_text_create_undo_record(state, insert_len); + if (r == NULL) + return NULL; + + r->where = pos; + r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len; + r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len; + + if (insert_len == 0) { + r->char_storage = -1; + return NULL; + } else { + r->char_storage = state->undo_char_point; + state->undo_char_point += insert_len; + return &state->undo_char[r->char_storage]; + } +} + +static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + StbUndoState *s = &state->undostate; + StbUndoRecord u, *r; + if (s->undo_point == 0) + return; + + // we need to do two things: apply the undo record, and create a redo record + u = s->undo_rec[s->undo_point-1]; + r = &s->undo_rec[s->redo_point-1]; + r->char_storage = -1; + + r->insert_length = u.delete_length; + r->delete_length = u.insert_length; + r->where = u.where; + + if (u.delete_length) { + // if the undo record says to delete characters, then the redo record will + // need to re-insert the characters that get deleted, so we need to store + // them. + + // there are three cases: + // there's enough room to store the characters + // characters stored for *redoing* don't leave room for redo + // characters stored for *undoing* don't leave room for redo + // if the last is true, we have to bail + + if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) { + // the undo records take up too much character space; there's no space to store the redo characters + r->insert_length = 0; + } else { + int i; + + // there's definitely room to store the characters eventually + while (s->undo_char_point + u.delete_length > s->redo_char_point) { + // should never happen: + if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) + return; + // there's currently not enough room, so discard a redo record + stb_textedit_discard_redo(s); + } + r = &s->undo_rec[s->redo_point-1]; + + r->char_storage = s->redo_char_point - u.delete_length; + s->redo_char_point = s->redo_char_point - u.delete_length; + + // now save the characters + for (i=0; i < u.delete_length; ++i) + s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i); + } + + // now we can carry out the deletion + STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length); + } + + // check type of recorded action: + if (u.insert_length) { + // easy case: was a deletion, so we need to insert n characters + STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length); + s->undo_char_point -= u.insert_length; + } + + state->cursor = u.where + u.insert_length; + + s->undo_point--; + s->redo_point--; +} + +static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + StbUndoState *s = &state->undostate; + StbUndoRecord *u, r; + if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) + return; + + // we need to do two things: apply the redo record, and create an undo record + u = &s->undo_rec[s->undo_point]; + r = s->undo_rec[s->redo_point]; + + // we KNOW there must be room for the undo record, because the redo record + // was derived from an undo record + + u->delete_length = r.insert_length; + u->insert_length = r.delete_length; + u->where = r.where; + u->char_storage = -1; + + if (r.delete_length) { + // the redo record requires us to delete characters, so the undo record + // needs to store the characters + + if (s->undo_char_point + u->insert_length > s->redo_char_point) { + u->insert_length = 0; + u->delete_length = 0; + } else { + int i; + u->char_storage = s->undo_char_point; + s->undo_char_point = s->undo_char_point + u->insert_length; + + // now save the characters + for (i=0; i < u->insert_length; ++i) + s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i); + } + + STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length); + } + + if (r.insert_length) { + // easy case: need to insert n characters + STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); + s->redo_char_point += r.insert_length; + } + + state->cursor = r.where + r.insert_length; + + s->undo_point++; + s->redo_point++; +} + +static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length) +{ + stb_text_createundo(&state->undostate, where, 0, length); +} + +static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length) +{ + int i; + STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0); + if (p) { + for (i=0; i < length; ++i) + p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); + } +} + +static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length) +{ + int i; + STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length); + if (p) { + for (i=0; i < old_length; ++i) + p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); + } +} + +// reset the state to default +static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_line) +{ + state->undostate.undo_point = 0; + state->undostate.undo_char_point = 0; + state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; + state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; + state->select_end = state->select_start = 0; + state->cursor = 0; + state->has_preferred_x = 0; + state->preferred_x = 0; + state->cursor_at_end_of_line = 0; + state->initialized = 1; + state->single_line = (unsigned char) is_single_line; + state->insert_mode = 0; +} + +// API initialize +static void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) +{ + stb_textedit_clear_state(state, is_single_line); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len) +{ + return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#endif//STB_TEXTEDIT_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imstb_truetype.h b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imstb_truetype.h new file mode 100644 index 00000000..c1cdb180 --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/imgui/imstb_truetype.h @@ -0,0 +1,4903 @@ +// [DEAR IMGUI] +// This is a slightly modified version of stb_truetype.h 1.20. +// Mostly fixing for compiler and static analyzer warnings. +// Grep for [DEAR IMGUI] to find the changes. + +// stb_truetype.h - v1.20 - public domain +// authored from 2009-2016 by Sean Barrett / RAD Game Tools +// +// This library processes TrueType files: +// parse files +// extract glyph metrics +// extract glyph shapes +// render glyphs to one-channel bitmaps with antialiasing (box filter) +// render glyphs to one-channel SDF bitmaps (signed-distance field/function) +// +// Todo: +// non-MS cmaps +// crashproof on bad data +// hinting? (no longer patented) +// cleartype-style AA? +// optimize: use simple memory allocator for intermediates +// optimize: build edge-list directly from curves +// optimize: rasterize directly from curves? +// +// ADDITIONAL CONTRIBUTORS +// +// Mikko Mononen: compound shape support, more cmap formats +// Tor Andersson: kerning, subpixel rendering +// Dougall Johnson: OpenType / Type 2 font handling +// Daniel Ribeiro Maciel: basic GPOS-based kerning +// +// Misc other: +// Ryan Gordon +// Simon Glass +// github:IntellectualKitty +// Imanol Celaya +// Daniel Ribeiro Maciel +// +// Bug/warning reports/fixes: +// "Zer" on mollyrocket Fabian "ryg" Giesen +// Cass Everitt Martins Mozeiko +// stoiko (Haemimont Games) Cap Petschulat +// Brian Hook Omar Cornut +// Walter van Niftrik github:aloucks +// David Gow Peter LaValle +// David Given Sergey Popov +// Ivan-Assen Ivanov Giumo X. Clanjor +// Anthony Pesch Higor Euripedes +// Johan Duparc Thomas Fields +// Hou Qiming Derek Vinyard +// Rob Loach Cort Stratton +// Kenney Phillis Jr. github:oyvindjam +// Brian Costabile github:vassvik +// +// VERSION HISTORY +// +// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() +// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// variant PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// +// Full history can be found at the end of this file. +// +// LICENSE +// +// See end of file for license information. +// +// USAGE +// +// Include this file in whatever places need to refer to it. In ONE C/C++ +// file, write: +// #define STB_TRUETYPE_IMPLEMENTATION +// before the #include of this file. This expands out the actual +// implementation into that C/C++ file. +// +// To make the implementation private to the file that generates the implementation, +// #define STBTT_STATIC +// +// Simple 3D API (don't ship this, but it's fine for tools and quick start) +// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture +// stbtt_GetBakedQuad() -- compute quad to draw for a given char +// +// Improved 3D API (more shippable): +// #include "stb_rect_pack.h" -- optional, but you really want it +// stbtt_PackBegin() +// stbtt_PackSetOversampling() -- for improved quality on small fonts +// stbtt_PackFontRanges() -- pack and renders +// stbtt_PackEnd() +// stbtt_GetPackedQuad() +// +// "Load" a font file from a memory buffer (you have to keep the buffer loaded) +// stbtt_InitFont() +// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections +// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections +// +// Render a unicode codepoint to a bitmap +// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap +// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide +// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be +// +// Character advance/positioning +// stbtt_GetCodepointHMetrics() +// stbtt_GetFontVMetrics() +// stbtt_GetFontVMetricsOS2() +// stbtt_GetCodepointKernAdvance() +// +// Starting with version 1.06, the rasterizer was replaced with a new, +// faster and generally-more-precise rasterizer. The new rasterizer more +// accurately measures pixel coverage for anti-aliasing, except in the case +// where multiple shapes overlap, in which case it overestimates the AA pixel +// coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If +// this turns out to be a problem, you can re-enable the old rasterizer with +// #define STBTT_RASTERIZER_VERSION 1 +// which will incur about a 15% speed hit. +// +// ADDITIONAL DOCUMENTATION +// +// Immediately after this block comment are a series of sample programs. +// +// After the sample programs is the "header file" section. This section +// includes documentation for each API function. +// +// Some important concepts to understand to use this library: +// +// Codepoint +// Characters are defined by unicode codepoints, e.g. 65 is +// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is +// the hiragana for "ma". +// +// Glyph +// A visual character shape (every codepoint is rendered as +// some glyph) +// +// Glyph index +// A font-specific integer ID representing a glyph +// +// Baseline +// Glyph shapes are defined relative to a baseline, which is the +// bottom of uppercase characters. Characters extend both above +// and below the baseline. +// +// Current Point +// As you draw text to the screen, you keep track of a "current point" +// which is the origin of each character. The current point's vertical +// position is the baseline. Even "baked fonts" use this model. +// +// Vertical Font Metrics +// The vertical qualities of the font, used to vertically position +// and space the characters. See docs for stbtt_GetFontVMetrics. +// +// Font Size in Pixels or Points +// The preferred interface for specifying font sizes in stb_truetype +// is to specify how tall the font's vertical extent should be in pixels. +// If that sounds good enough, skip the next paragraph. +// +// Most font APIs instead use "points", which are a common typographic +// measurement for describing font size, defined as 72 points per inch. +// stb_truetype provides a point API for compatibility. However, true +// "per inch" conventions don't make much sense on computer displays +// since different monitors have different number of pixels per +// inch. For example, Windows traditionally uses a convention that +// there are 96 pixels per inch, thus making 'inch' measurements have +// nothing to do with inches, and thus effectively defining a point to +// be 1.333 pixels. Additionally, the TrueType font data provides +// an explicit scale factor to scale a given font's glyphs to points, +// but the author has observed that this scale factor is often wrong +// for non-commercial fonts, thus making fonts scaled in points +// according to the TrueType spec incoherently sized in practice. +// +// DETAILED USAGE: +// +// Scale: +// Select how high you want the font to be, in points or pixels. +// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute +// a scale factor SF that will be used by all other functions. +// +// Baseline: +// You need to select a y-coordinate that is the baseline of where +// your text will appear. Call GetFontBoundingBox to get the baseline-relative +// bounding box for all characters. SF*-y0 will be the distance in pixels +// that the worst-case character could extend above the baseline, so if +// you want the top edge of characters to appear at the top of the +// screen where y=0, then you would set the baseline to SF*-y0. +// +// Current point: +// Set the current point where the first character will appear. The +// first character could extend left of the current point; this is font +// dependent. You can either choose a current point that is the leftmost +// point and hope, or add some padding, or check the bounding box or +// left-side-bearing of the first character to be displayed and set +// the current point based on that. +// +// Displaying a character: +// Compute the bounding box of the character. It will contain signed values +// relative to . I.e. if it returns x0,y0,x1,y1, +// then the character should be displayed in the rectangle from +// to = 32 && *text < 128) { + stbtt_aligned_quad q; + stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 + glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); + glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); + glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); + glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1); + } + ++text; + } + glEnd(); +} +#endif +// +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program (this compiles): get a single bitmap, print as ASCII art +// +#if 0 +#include +#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation +#include "stb_truetype.h" + +char ttf_buffer[1<<25]; + +int main(int argc, char **argv) +{ + stbtt_fontinfo font; + unsigned char *bitmap; + int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); + + fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); + + stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); + bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); + + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) + putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); + putchar('\n'); + } + return 0; +} +#endif +// +// Output: +// +// .ii. +// @@@@@@. +// V@Mio@@o +// :i. V@V +// :oM@@M +// :@@@MM@M +// @@o o@M +// :@@. M@M +// @@@o@@@@ +// :M@@V:@@. +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program: print "Hello World!" banner, with bugs +// +#if 0 +char buffer[24<<20]; +unsigned char screen[20][79]; + +int main(int arg, char **argv) +{ + stbtt_fontinfo font; + int i,j,ascent,baseline,ch=0; + float scale, xpos=2; // leave a little padding in case the character extends left + char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness + + fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); + stbtt_InitFont(&font, buffer, 0); + + scale = stbtt_ScaleForPixelHeight(&font, 15); + stbtt_GetFontVMetrics(&font, &ascent,0,0); + baseline = (int) (ascent*scale); + + while (text[ch]) { + int advance,lsb,x0,y0,x1,y1; + float x_shift = xpos - (float) floor(xpos); + stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); + stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); + stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); + // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong + // because this API is really for baking character bitmaps into textures. if you want to render + // a sequence of characters, you really need to render each bitmap to a temp buffer, then + // "alpha blend" that into the working buffer + xpos += (advance * scale); + if (text[ch+1]) + xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); + ++ch; + } + + for (j=0; j < 20; ++j) { + for (i=0; i < 78; ++i) + putchar(" .:ioVM@"[screen[j][i]>>5]); + putchar('\n'); + } + + return 0; +} +#endif + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +//// +//// INTEGRATION WITH YOUR CODEBASE +//// +//// The following sections allow you to supply alternate definitions +//// of C library functions used by stb_truetype, e.g. if you don't +//// link with the C runtime library. + +#ifdef STB_TRUETYPE_IMPLEMENTATION + // #define your own (u)stbtt_int8/16/32 before including to override this + #ifndef stbtt_uint8 + typedef unsigned char stbtt_uint8; + typedef signed char stbtt_int8; + typedef unsigned short stbtt_uint16; + typedef signed short stbtt_int16; + typedef unsigned int stbtt_uint32; + typedef signed int stbtt_int32; + #endif + + typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; + typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; + + // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h + #ifndef STBTT_ifloor + #include + #define STBTT_ifloor(x) ((int) floor(x)) + #define STBTT_iceil(x) ((int) ceil(x)) + #endif + + #ifndef STBTT_sqrt + #include + #define STBTT_sqrt(x) sqrt(x) + #define STBTT_pow(x,y) pow(x,y) + #endif + + #ifndef STBTT_fmod + #include + #define STBTT_fmod(x,y) fmod(x,y) + #endif + + #ifndef STBTT_cos + #include + #define STBTT_cos(x) cos(x) + #define STBTT_acos(x) acos(x) + #endif + + #ifndef STBTT_fabs + #include + #define STBTT_fabs(x) fabs(x) + #endif + + // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h + #ifndef STBTT_malloc + #include + #define STBTT_malloc(x,u) ((void)(u),malloc(x)) + #define STBTT_free(x,u) ((void)(u),free(x)) + #endif + + #ifndef STBTT_assert + #include + #define STBTT_assert(x) assert(x) + #endif + + #ifndef STBTT_strlen + #include + #define STBTT_strlen(x) strlen(x) + #endif + + #ifndef STBTT_memcpy + #include + #define STBTT_memcpy memcpy + #define STBTT_memset memset + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// INTERFACE +//// +//// + +#ifndef __STB_INCLUDE_STB_TRUETYPE_H__ +#define __STB_INCLUDE_STB_TRUETYPE_H__ + +#ifdef STBTT_STATIC +#define STBTT_DEF static +#else +#define STBTT_DEF extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// private structure +typedef struct +{ + unsigned char *data; + int cursor; + int size; +} stbtt__buf; + +////////////////////////////////////////////////////////////////////////////// +// +// TEXTURE BAKING API +// +// If you use this API, you only have to call two functions ever. +// + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; +} stbtt_bakedchar; + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata); // you allocate this, it's num_chars long +// if return is positive, the first unused row of the bitmap +// if return is negative, returns the negative of the number of characters that fit +// if return is 0, no characters fit and no rows were used +// This uses a very crappy packing. + +typedef struct +{ + float x0,y0,s0,t0; // top-left + float x1,y1,s1,t1; // bottom-right +} stbtt_aligned_quad; + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier +// Call GetBakedQuad with char_index = 'character - first_char', and it +// creates the quad you need to draw and advances the current position. +// +// The coordinate system used assumes y increases downwards. +// +// Characters will extend both above and below the current position; +// see discussion of "BASELINE" above. +// +// It's inefficient; you might want to c&p it and optimize it. + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); +// Query the font vertical metrics without having to create a font first. + + +////////////////////////////////////////////////////////////////////////////// +// +// NEW TEXTURE BAKING API +// +// This provides options for packing multiple fonts into one atlas, not +// perfectly but better than nothing. + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; + float xoff2,yoff2; +} stbtt_packedchar; + +typedef struct stbtt_pack_context stbtt_pack_context; +typedef struct stbtt_fontinfo stbtt_fontinfo; +#ifndef STB_RECT_PACK_VERSION +typedef struct stbrp_rect stbrp_rect; +#endif + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); +// Initializes a packing context stored in the passed-in stbtt_pack_context. +// Future calls using this context will pack characters into the bitmap passed +// in here: a 1-channel bitmap that is width * height. stride_in_bytes is +// the distance from one row to the next (or 0 to mean they are packed tightly +// together). "padding" is the amount of padding to leave between each +// character (normally you want '1' for bitmaps you'll use as textures with +// bilinear filtering). +// +// Returns 0 on failure, 1 on success. + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); +// Cleans up the packing context and frees all memory. + +#define STBTT_POINT_SIZE(x) (-(x)) + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); +// Creates character bitmaps from the font_index'th font found in fontdata (use +// font_index=0 if you don't know what that is). It creates num_chars_in_range +// bitmaps for characters with unicode values starting at first_unicode_char_in_range +// and increasing. Data for how to render them is stored in chardata_for_range; +// pass these to stbtt_GetPackedQuad to get back renderable quads. +// +// font_size is the full height of the character from ascender to descender, +// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed +// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() +// and pass that result as 'font_size': +// ..., 20 , ... // font max minus min y is 20 pixels tall +// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall + +typedef struct +{ + float font_size; + int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint + int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints + int num_chars; + stbtt_packedchar *chardata_for_range; // output + unsigned char h_oversample, v_oversample; // don't set these, they're used internally +} stbtt_pack_range; + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); +// Creates character bitmaps from multiple ranges of characters stored in +// ranges. This will usually create a better-packed bitmap than multiple +// calls to stbtt_PackFontRange. Note that you can call this multiple +// times within a single PackBegin/PackEnd. + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); +// Oversampling a font increases the quality by allowing higher-quality subpixel +// positioning, and is especially valuable at smaller text sizes. +// +// This function sets the amount of oversampling for all following calls to +// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given +// pack context. The default (no oversampling) is achieved by h_oversample=1 +// and v_oversample=1. The total number of pixels required is +// h_oversample*v_oversample larger than the default; for example, 2x2 +// oversampling requires 4x the storage of 1x1. For best results, render +// oversampled textures with bilinear filtering. Look at the readme in +// stb/tests/oversample for information about oversampled fonts +// +// To use with PackFontRangesGather etc., you must set it before calls +// call to PackFontRangesGatherRects. + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); +// If skip != 0, this tells stb_truetype to skip any codepoints for which +// there is no corresponding glyph. If skip=0, which is the default, then +// codepoints without a glyph recived the font's "missing character" glyph, +// typically an empty box by convention. + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int align_to_integer); + +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +// Calling these functions in sequence is roughly equivalent to calling +// stbtt_PackFontRanges(). If you more control over the packing of multiple +// fonts, or if you want to pack custom data into a font texture, take a look +// at the source to of stbtt_PackFontRanges() and create a custom version +// using these functions, e.g. call GatherRects multiple times, +// building up a single array of rects, then call PackRects once, +// then call RenderIntoRects repeatedly. This may result in a +// better packing than calling PackFontRanges multiple times +// (or it may not). + +// this is an opaque structure that you shouldn't mess with which holds +// all the context needed from PackBegin to PackEnd. +struct stbtt_pack_context { + void *user_allocator_context; + void *pack_info; + int width; + int height; + int stride_in_bytes; + int padding; + int skip_missing; + unsigned int h_oversample, v_oversample; + unsigned char *pixels; + void *nodes; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// FONT LOADING +// +// + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); +// This function will determine the number of fonts in a font file. TrueType +// collection (.ttc) files may contain multiple fonts, while TrueType font +// (.ttf) files only contain one font. The number of fonts can be used for +// indexing with the previous function where the index is between zero and one +// less than the total fonts. If an error occurs, -1 is returned. + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); +// Each .ttf/.ttc file may have more than one font. Each font has a sequential +// index number starting from 0. Call this function to get the font offset for +// a given index; it returns -1 if the index is out of range. A regular .ttf +// file will only define one font and it always be at offset 0, so it will +// return '0' for index 0, and -1 for all other indices. + +// The following structure is defined publicly so you can declare one on +// the stack or as a global or etc, but you should treat it as opaque. +struct stbtt_fontinfo +{ + void * userdata; + unsigned char * data; // pointer to .ttf file + int fontstart; // offset of start of font + + int numGlyphs; // number of glyphs, needed for range checking + + int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf + int index_map; // a cmap mapping for our chosen character encoding + int indexToLocFormat; // format needed to map from glyph index to glyph + + stbtt__buf cff; // cff font data + stbtt__buf charstrings; // the charstring index + stbtt__buf gsubrs; // global charstring subroutines index + stbtt__buf subrs; // private charstring subroutines index + stbtt__buf fontdicts; // array of font dicts + stbtt__buf fdselect; // map from glyph to fontdict +}; + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); +// Given an offset into the file that defines a font, this function builds +// the necessary cached info for the rest of the system. You must allocate +// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't +// need to do anything special to free it, because the contents are pure +// value data with no additional data structures. Returns 0 on failure. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER TO GLYPH-INDEX CONVERSIOn + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); +// If you're going to perform multiple operations on the same character +// and you want a speed-up, call this function with the character you're +// going to process, then use glyph-based functions instead of the +// codepoint-based functions. +// Returns 0 if the character codepoint is not defined in the font. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER PROPERTIES +// + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose "height" is 'pixels' tall. +// Height is measured as the distance from the highest ascender to the lowest +// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics +// and computing: +// scale = pixels / (ascent - descent) +// so if you prefer to measure height by the ascent only, use a similar calculation. + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose EM size is mapped to +// 'pixels' tall. This is probably what traditional APIs compute, but +// I'm not positive. + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); +// ascent is the coordinate above the baseline the font extends; descent +// is the coordinate below the baseline the font extends (i.e. it is typically negative) +// lineGap is the spacing between one row's descent and the next row's ascent... +// so you should advance the vertical position by "*ascent - *descent + *lineGap" +// these are expressed in unscaled coordinates, so you must multiply by +// the scale factor for a given size + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); +// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 +// table (specific to MS/Windows TTF files). +// +// Returns 1 on success (table present), 0 on failure. + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); +// the bounding box around all possible characters + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); +// leftSideBearing is the offset from the current horizontal position to the left edge of the character +// advanceWidth is the offset from the current horizontal position to the next horizontal position +// these are expressed in unscaled coordinates + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); +// an additional amount to add to the 'advance' value between ch1 and ch2 + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); +// Gets the bounding box of the visible part of the glyph, in unscaled coordinates + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); +// as above, but takes one or more glyph indices for greater efficiency + + +////////////////////////////////////////////////////////////////////////////// +// +// GLYPH SHAPES (you probably don't need these, but they have to go before +// the bitmaps for C declaration-order reasons) +// + +#ifndef STBTT_vmove // you can predefine these to use different values (but why?) + enum { + STBTT_vmove=1, + STBTT_vline, + STBTT_vcurve, + STBTT_vcubic + }; +#endif + +#ifndef stbtt_vertex // you can predefine this to use different values + // (we share this with other code at RAD) + #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file + typedef struct + { + stbtt_vertex_type x,y,cx,cy,cx1,cy1; + unsigned char type,padding; + } stbtt_vertex; +#endif + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); +// returns non-zero if nothing is drawn for this glyph + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); +// returns # of vertices and fills *vertices with the pointer to them +// these are expressed in "unscaled" coordinates +// +// The shape is a series of contours. Each one starts with +// a STBTT_moveto, then consists of a series of mixed +// STBTT_lineto and STBTT_curveto segments. A lineto +// draws a line from previous endpoint to its x,y; a curveto +// draws a quadratic bezier from previous endpoint to +// its x,y, using cx,cy as the bezier control point. + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); +// frees the data allocated above + +////////////////////////////////////////////////////////////////////////////// +// +// BITMAP RENDERING +// + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); +// frees the bitmap allocated below + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// allocates a large-enough single-channel 8bpp bitmap and renders the +// specified character/glyph at the specified scale into it, with +// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). +// *width & *height are filled out with the width & height of the bitmap, +// which is stored left-to-right, top-to-bottom. +// +// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); +// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap +// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap +// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the +// width and height and positioning info for it first. + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); +// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); +// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering +// is performed (see stbtt_PackSetOversampling) + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +// get the bbox of the bitmap centered around the glyph origin; so the +// bitmap width is ix1-ix0, height is iy1-iy0, and location to place +// the bitmap top left is (leftSideBearing*scale,iy0). +// (Note that the bitmap uses y-increases-down, but the shape uses +// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); +// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel +// shift for the character + +// the following functions are equivalent to the above functions, but operate +// on glyph indices instead of Unicode codepoints (for efficiency) +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); + + +// @TODO: don't expose this structure +typedef struct +{ + int w,h,stride; + unsigned char *pixels; +} stbtt__bitmap; + +// rasterize a shape with quadratic beziers into a bitmap +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into + float flatness_in_pixels, // allowable error of curve in pixels + stbtt_vertex *vertices, // array of vertices defining shape + int num_verts, // number of vertices in above array + float scale_x, float scale_y, // scale applied to input vertices + float shift_x, float shift_y, // translation applied to input vertices + int x_off, int y_off, // another translation applied to input + int invert, // if non-zero, vertically flip shape + void *userdata); // context for to STBTT_MALLOC + +////////////////////////////////////////////////////////////////////////////// +// +// Signed Distance Function (or Field) rendering + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); +// frees the SDF bitmap allocated below + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +// These functions compute a discretized SDF field for a single character, suitable for storing +// in a single-channel texture, sampling with bilinear filtering, and testing against +// larger than some threshold to produce scalable fonts. +// info -- the font +// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap +// glyph/codepoint -- the character to generate the SDF for +// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), +// which allows effects like bit outlines +// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) +// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) +// if positive, > onedge_value is inside; if negative, < onedge_value is inside +// width,height -- output height & width of the SDF bitmap (including padding) +// xoff,yoff -- output origin of the character +// return value -- a 2D array of bytes 0..255, width*height in size +// +// pixel_dist_scale & onedge_value are a scale & bias that allows you to make +// optimal use of the limited 0..255 for your application, trading off precision +// and special effects. SDF values outside the range 0..255 are clamped to 0..255. +// +// Example: +// scale = stbtt_ScaleForPixelHeight(22) +// padding = 5 +// onedge_value = 180 +// pixel_dist_scale = 180/5.0 = 36.0 +// +// This will create an SDF bitmap in which the character is about 22 pixels +// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled +// shape, sample the SDF at each pixel and fill the pixel if the SDF value +// is greater than or equal to 180/255. (You'll actually want to antialias, +// which is beyond the scope of this example.) Additionally, you can compute +// offset outlines (e.g. to stroke the character border inside & outside, +// or only outside). For example, to fill outside the character up to 3 SDF +// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above +// choice of variables maps a range from 5 pixels outside the shape to +// 2 pixels inside the shape to 0..255; this is intended primarily for apply +// outside effects only (the interior range is needed to allow proper +// antialiasing of the font at *smaller* sizes) +// +// The function computes the SDF analytically at each SDF pixel, not by e.g. +// building a higher-res bitmap and approximating it. In theory the quality +// should be as high as possible for an SDF of this size & representation, but +// unclear if this is true in practice (perhaps building a higher-res bitmap +// and computing from that can allow drop-out prevention). +// +// The algorithm has not been optimized at all, so expect it to be slow +// if computing lots of characters or very large sizes. + + + +////////////////////////////////////////////////////////////////////////////// +// +// Finding the right font... +// +// You should really just solve this offline, keep your own tables +// of what font is what, and don't try to get it out of the .ttf file. +// That's because getting it out of the .ttf file is really hard, because +// the names in the file can appear in many possible encodings, in many +// possible languages, and e.g. if you need a case-insensitive comparison, +// the details of that depend on the encoding & language in a complex way +// (actually underspecified in truetype, but also gigantic). +// +// But you can use the provided functions in two possible ways: +// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on +// unicode-encoded names to try to find the font you want; +// you can run this before calling stbtt_InitFont() +// +// stbtt_GetFontNameString() lets you get any of the various strings +// from the file yourself and do your own comparisons on them. +// You have to have called stbtt_InitFont() first. + + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); +// returns the offset (not index) of the font that matches, or -1 if none +// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". +// if you use any other flag, use a font name like "Arial"; this checks +// the 'macStyle' header field; i don't know if fonts set this consistently +#define STBTT_MACSTYLE_DONTCARE 0 +#define STBTT_MACSTYLE_BOLD 1 +#define STBTT_MACSTYLE_ITALIC 2 +#define STBTT_MACSTYLE_UNDERSCORE 4 +#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); +// returns 1/0 whether the first string interpreted as utf8 is identical to +// the second string interpreted as big-endian utf16... useful for strings from next func + +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); +// returns the string (which may be big-endian double byte, e.g. for unicode) +// and puts the length in bytes in *length. +// +// some of the values for the IDs are below; for more see the truetype spec: +// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html +// http://www.microsoft.com/typography/otspec/name.htm + +enum { // platformID + STBTT_PLATFORM_ID_UNICODE =0, + STBTT_PLATFORM_ID_MAC =1, + STBTT_PLATFORM_ID_ISO =2, + STBTT_PLATFORM_ID_MICROSOFT =3 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_UNICODE + STBTT_UNICODE_EID_UNICODE_1_0 =0, + STBTT_UNICODE_EID_UNICODE_1_1 =1, + STBTT_UNICODE_EID_ISO_10646 =2, + STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, + STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT + STBTT_MS_EID_SYMBOL =0, + STBTT_MS_EID_UNICODE_BMP =1, + STBTT_MS_EID_SHIFTJIS =2, + STBTT_MS_EID_UNICODE_FULL =10 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes + STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, + STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, + STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, + STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 +}; + +enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... + // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs + STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, + STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, + STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, + STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, + STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, + STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D +}; + +enum { // languageID for STBTT_PLATFORM_ID_MAC + STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, + STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, + STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, + STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , + STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , + STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, + STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 +}; + +#ifdef __cplusplus +} +#endif + +#endif // __STB_INCLUDE_STB_TRUETYPE_H__ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// IMPLEMENTATION +//// +//// + +#ifdef STB_TRUETYPE_IMPLEMENTATION + +#ifndef STBTT_MAX_OVERSAMPLE +#define STBTT_MAX_OVERSAMPLE 8 +#endif + +#if STBTT_MAX_OVERSAMPLE > 255 +#error "STBTT_MAX_OVERSAMPLE cannot be > 255" +#endif + +typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; + +#ifndef STBTT_RASTERIZER_VERSION +#define STBTT_RASTERIZER_VERSION 2 +#endif + +#ifdef _MSC_VER +#define STBTT__NOTUSED(v) (void)(v) +#else +#define STBTT__NOTUSED(v) (void)sizeof(v) +#endif + +////////////////////////////////////////////////////////////////////////// +// +// stbtt__buf helpers to parse data from file +// + +static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor++]; +} + +static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor]; +} + +static void stbtt__buf_seek(stbtt__buf *b, int o) +{ + STBTT_assert(!(o > b->size || o < 0)); + b->cursor = (o > b->size || o < 0) ? b->size : o; +} + +static void stbtt__buf_skip(stbtt__buf *b, int o) +{ + stbtt__buf_seek(b, b->cursor + o); +} + +static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) +{ + stbtt_uint32 v = 0; + int i; + STBTT_assert(n >= 1 && n <= 4); + for (i = 0; i < n; i++) + v = (v << 8) | stbtt__buf_get8(b); + return v; +} + +static stbtt__buf stbtt__new_buf(const void *p, size_t size) +{ + stbtt__buf r; + STBTT_assert(size < 0x40000000); + r.data = (stbtt_uint8*) p; + r.size = (int) size; + r.cursor = 0; + return r; +} + +#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) +#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) + +static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) +{ + stbtt__buf r = stbtt__new_buf(NULL, 0); + if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; + r.data = b->data + o; + r.size = s; + return r; +} + +static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) +{ + int count, start, offsize; + start = b->cursor; + count = stbtt__buf_get16(b); + if (count) { + offsize = stbtt__buf_get8(b); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(b, offsize * count); + stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); + } + return stbtt__buf_range(b, start, b->cursor - start); +} + +static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) +{ + int b0 = stbtt__buf_get8(b); + if (b0 >= 32 && b0 <= 246) return b0 - 139; + else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; + else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; + else if (b0 == 28) return stbtt__buf_get16(b); + else if (b0 == 29) return stbtt__buf_get32(b); + STBTT_assert(0); + return 0; +} + +static void stbtt__cff_skip_operand(stbtt__buf *b) { + int v, b0 = stbtt__buf_peek8(b); + STBTT_assert(b0 >= 28); + if (b0 == 30) { + stbtt__buf_skip(b, 1); + while (b->cursor < b->size) { + v = stbtt__buf_get8(b); + if ((v & 0xF) == 0xF || (v >> 4) == 0xF) + break; + } + } else { + stbtt__cff_int(b); + } +} + +static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) +{ + stbtt__buf_seek(b, 0); + while (b->cursor < b->size) { + int start = b->cursor, end, op; + while (stbtt__buf_peek8(b) >= 28) + stbtt__cff_skip_operand(b); + end = b->cursor; + op = stbtt__buf_get8(b); + if (op == 12) op = stbtt__buf_get8(b) | 0x100; + if (op == key) return stbtt__buf_range(b, start, end-start); + } + return stbtt__buf_range(b, 0, 0); +} + +static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) +{ + int i; + stbtt__buf operands = stbtt__dict_get(b, key); + for (i = 0; i < outcount && operands.cursor < operands.size; i++) + out[i] = stbtt__cff_int(&operands); +} + +static int stbtt__cff_index_count(stbtt__buf *b) +{ + stbtt__buf_seek(b, 0); + return stbtt__buf_get16(b); +} + +static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) +{ + int count, offsize, start, end; + stbtt__buf_seek(&b, 0); + count = stbtt__buf_get16(&b); + offsize = stbtt__buf_get8(&b); + STBTT_assert(i >= 0 && i < count); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(&b, i*offsize); + start = stbtt__buf_get(&b, offsize); + end = stbtt__buf_get(&b, offsize); + return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); +} + +////////////////////////////////////////////////////////////////////////// +// +// accessors to parse data from file +// + +// on platforms that don't allow misaligned reads, if we want to allow +// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE + +#define ttBYTE(p) (* (stbtt_uint8 *) (p)) +#define ttCHAR(p) (* (stbtt_int8 *) (p)) +#define ttFixed(p) ttLONG(p) + +static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } +static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } + +#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) +#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) + +static int stbtt__isfont(stbtt_uint8 *font) +{ + // check the version number + if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 + if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! + if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF + if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 + if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts + return 0; +} + +// @OPTIMIZE: binary search +static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) +{ + stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); + stbtt_uint32 tabledir = fontstart + 12; + stbtt_int32 i; + for (i=0; i < num_tables; ++i) { + stbtt_uint32 loc = tabledir + 16*i; + if (stbtt_tag(data+loc+0, tag)) + return ttULONG(data+loc+8); + } + return 0; +} + +static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) +{ + // if it's just a font, there's only one valid index + if (stbtt__isfont(font_collection)) + return index == 0 ? 0 : -1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + stbtt_int32 n = ttLONG(font_collection+8); + if (index >= n) + return -1; + return ttULONG(font_collection+12+index*4); + } + } + return -1; +} + +static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) +{ + // if it's just a font, there's only one valid font + if (stbtt__isfont(font_collection)) + return 1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + return ttLONG(font_collection+8); + } + } + return 0; +} + +static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) +{ + stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; + stbtt__buf pdict; + stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); + if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); + pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); + stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); + if (!subrsoff) return stbtt__new_buf(NULL, 0); + stbtt__buf_seek(&cff, private_loc[1]+subrsoff); + return stbtt__cff_get_index(&cff); +} + +static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) +{ + stbtt_uint32 cmap, t; + stbtt_int32 i,numTables; + + info->data = data; + info->fontstart = fontstart; + info->cff = stbtt__new_buf(NULL, 0); + + cmap = stbtt__find_table(data, fontstart, "cmap"); // required + info->loca = stbtt__find_table(data, fontstart, "loca"); // required + info->head = stbtt__find_table(data, fontstart, "head"); // required + info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required + info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required + info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required + info->kern = stbtt__find_table(data, fontstart, "kern"); // not required + info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required + + if (!cmap || !info->head || !info->hhea || !info->hmtx) + return 0; + if (info->glyf) { + // required for truetype + if (!info->loca) return 0; + } else { + // initialization for CFF / Type2 fonts (OTF) + stbtt__buf b, topdict, topdictidx; + stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; + stbtt_uint32 cff; + + cff = stbtt__find_table(data, fontstart, "CFF "); + if (!cff) return 0; + + info->fontdicts = stbtt__new_buf(NULL, 0); + info->fdselect = stbtt__new_buf(NULL, 0); + + // @TODO this should use size from table (not 512MB) + info->cff = stbtt__new_buf(data+cff, 512*1024*1024); + b = info->cff; + + // read the header + stbtt__buf_skip(&b, 2); + stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize + + // @TODO the name INDEX could list multiple fonts, + // but we just use the first one. + stbtt__cff_get_index(&b); // name INDEX + topdictidx = stbtt__cff_get_index(&b); + topdict = stbtt__cff_index_get(topdictidx, 0); + stbtt__cff_get_index(&b); // string INDEX + info->gsubrs = stbtt__cff_get_index(&b); + + stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); + stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); + stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); + stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); + info->subrs = stbtt__get_subrs(b, topdict); + + // we only support Type 2 charstrings + if (cstype != 2) return 0; + if (charstrings == 0) return 0; + + if (fdarrayoff) { + // looks like a CID font + if (!fdselectoff) return 0; + stbtt__buf_seek(&b, fdarrayoff); + info->fontdicts = stbtt__cff_get_index(&b); + info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); + } + + stbtt__buf_seek(&b, charstrings); + info->charstrings = stbtt__cff_get_index(&b); + } + + t = stbtt__find_table(data, fontstart, "maxp"); + if (t) + info->numGlyphs = ttUSHORT(data+t+4); + else + info->numGlyphs = 0xffff; + + // find a cmap encoding table we understand *now* to avoid searching + // later. (todo: could make this installable) + // the same regardless of glyph. + numTables = ttUSHORT(data + cmap + 2); + info->index_map = 0; + for (i=0; i < numTables; ++i) { + stbtt_uint32 encoding_record = cmap + 4 + 8 * i; + // find an encoding we understand: + switch(ttUSHORT(data+encoding_record)) { + case STBTT_PLATFORM_ID_MICROSOFT: + switch (ttUSHORT(data+encoding_record+2)) { + case STBTT_MS_EID_UNICODE_BMP: + case STBTT_MS_EID_UNICODE_FULL: + // MS/Unicode + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + break; + case STBTT_PLATFORM_ID_UNICODE: + // Mac/iOS has these + // all the encodingIDs are unicode, so we don't bother to check it + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + } + if (info->index_map == 0) + return 0; + + info->indexToLocFormat = ttUSHORT(data+info->head + 50); + return 1; +} + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) +{ + stbtt_uint8 *data = info->data; + stbtt_uint32 index_map = info->index_map; + + stbtt_uint16 format = ttUSHORT(data + index_map + 0); + if (format == 0) { // apple byte encoding + stbtt_int32 bytes = ttUSHORT(data + index_map + 2); + if (unicode_codepoint < bytes-6) + return ttBYTE(data + index_map + 6 + unicode_codepoint); + return 0; + } else if (format == 6) { + stbtt_uint32 first = ttUSHORT(data + index_map + 6); + stbtt_uint32 count = ttUSHORT(data + index_map + 8); + if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) + return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); + return 0; + } else if (format == 2) { + STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean + return 0; + } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges + stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; + stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; + stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); + stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; + + // do a binary search of the segments + stbtt_uint32 endCount = index_map + 14; + stbtt_uint32 search = endCount; + + if (unicode_codepoint > 0xffff) + return 0; + + // they lie from endCount .. endCount + segCount + // but searchRange is the nearest power of two, so... + if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) + search += rangeShift*2; + + // now decrement to bias correctly to find smallest + search -= 2; + while (entrySelector) { + stbtt_uint16 end; + searchRange >>= 1; + end = ttUSHORT(data + search + searchRange*2); + if (unicode_codepoint > end) + search += searchRange*2; + --entrySelector; + } + search += 2; + + { + stbtt_uint16 offset, start; + stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); + + STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); + start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); + if (unicode_codepoint < start) + return 0; + + offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); + if (offset == 0) + return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); + + return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); + } + } else if (format == 12 || format == 13) { + stbtt_uint32 ngroups = ttULONG(data+index_map+12); + stbtt_int32 low,high; + low = 0; high = (stbtt_int32)ngroups; + // Binary search the right group. + while (low < high) { + stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high + stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); + stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); + if ((stbtt_uint32) unicode_codepoint < start_char) + high = mid; + else if ((stbtt_uint32) unicode_codepoint > end_char) + low = mid+1; + else { + stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); + if (format == 12) + return start_glyph + unicode_codepoint-start_char; + else // format == 13 + return start_glyph; + } + } + return 0; // not found + } + // @TODO + STBTT_assert(0); + return 0; +} + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) +{ + return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); +} + +static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) +{ + v->type = type; + v->x = (stbtt_int16) x; + v->y = (stbtt_int16) y; + v->cx = (stbtt_int16) cx; + v->cy = (stbtt_int16) cy; +} + +static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) +{ + int g1,g2; + + STBTT_assert(!info->cff.size); + + if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range + if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format + + if (info->indexToLocFormat == 0) { + g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; + g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; + } else { + g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); + g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); + } + + return g1==g2 ? -1 : g1; // if length is 0, return -1 +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); + +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + if (info->cff.size) { + stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); + } else { + int g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 0; + + if (x0) *x0 = ttSHORT(info->data + g + 2); + if (y0) *y0 = ttSHORT(info->data + g + 4); + if (x1) *x1 = ttSHORT(info->data + g + 6); + if (y1) *y1 = ttSHORT(info->data + g + 8); + } + return 1; +} + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) +{ + return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); +} + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt_int16 numberOfContours; + int g; + if (info->cff.size) + return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; + g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 1; + numberOfContours = ttSHORT(info->data + g); + return numberOfContours == 0; +} + +static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, + stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) +{ + if (start_off) { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); + } + return num_vertices; +} + +static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + stbtt_int16 numberOfContours; + stbtt_uint8 *endPtsOfContours; + stbtt_uint8 *data = info->data; + stbtt_vertex *vertices=0; + int num_vertices=0; + int g = stbtt__GetGlyfOffset(info, glyph_index); + + *pvertices = NULL; + + if (g < 0) return 0; + + numberOfContours = ttSHORT(data + g); + + if (numberOfContours > 0) { + stbtt_uint8 flags=0,flagcount; + stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; + stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; + stbtt_uint8 *points; + endPtsOfContours = (data + g + 10); + ins = ttUSHORT(data + g + 10 + numberOfContours * 2); + points = data + g + 10 + numberOfContours * 2 + 2 + ins; + + n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); + + m = n + 2*numberOfContours; // a loose bound on how many vertices we might need + vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); + if (vertices == 0) + return 0; + + next_move = 0; + flagcount=0; + + // in first pass, we load uninterpreted data into the allocated array + // above, shifted to the end of the array so we won't overwrite it when + // we create our final data starting from the front + + off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated + + // first load flags + + for (i=0; i < n; ++i) { + if (flagcount == 0) { + flags = *points++; + if (flags & 8) + flagcount = *points++; + } else + --flagcount; + vertices[off+i].type = flags; + } + + // now load x coordinates + x=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 2) { + stbtt_int16 dx = *points++; + x += (flags & 16) ? dx : -dx; // ??? + } else { + if (!(flags & 16)) { + x = x + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].x = (stbtt_int16) x; + } + + // now load y coordinates + y=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 4) { + stbtt_int16 dy = *points++; + y += (flags & 32) ? dy : -dy; // ??? + } else { + if (!(flags & 32)) { + y = y + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].y = (stbtt_int16) y; + } + + // now convert them to our format + num_vertices=0; + sx = sy = cx = cy = scx = scy = 0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + x = (stbtt_int16) vertices[off+i].x; + y = (stbtt_int16) vertices[off+i].y; + + if (next_move == i) { + if (i != 0) + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + + // now start the new one + start_off = !(flags & 1); + if (start_off) { + // if we start off with an off-curve point, then when we need to find a point on the curve + // where we can start, and we need to save some state for when we wraparound. + scx = x; + scy = y; + if (!(vertices[off+i+1].type & 1)) { + // next point is also a curve point, so interpolate an on-point curve + sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; + sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; + } else { + // otherwise just use the next point as our start point + sx = (stbtt_int32) vertices[off+i+1].x; + sy = (stbtt_int32) vertices[off+i+1].y; + ++i; // we're using point i+1 as the starting point, so skip it + } + } else { + sx = x; + sy = y; + } + stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); + was_off = 0; + next_move = 1 + ttUSHORT(endPtsOfContours+j*2); + ++j; + } else { + if (!(flags & 1)) { // if it's a curve + if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); + cx = x; + cy = y; + was_off = 1; + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); + was_off = 0; + } + } + } + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + } else if (numberOfContours == -1) { + // Compound shapes. + int more = 1; + stbtt_uint8 *comp = data + g + 10; + num_vertices = 0; + vertices = 0; + while (more) { + stbtt_uint16 flags, gidx; + int comp_num_verts = 0, i; + stbtt_vertex *comp_verts = 0, *tmp = 0; + float mtx[6] = {1,0,0,1,0,0}, m, n; + + flags = ttSHORT(comp); comp+=2; + gidx = ttSHORT(comp); comp+=2; + + if (flags & 2) { // XY values + if (flags & 1) { // shorts + mtx[4] = ttSHORT(comp); comp+=2; + mtx[5] = ttSHORT(comp); comp+=2; + } else { + mtx[4] = ttCHAR(comp); comp+=1; + mtx[5] = ttCHAR(comp); comp+=1; + } + } + else { + // @TODO handle matching point + STBTT_assert(0); + } + if (flags & (1<<3)) { // WE_HAVE_A_SCALE + mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } + + // Find transformation scales. + m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); + n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); + + // Get indexed glyph. + comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); + if (comp_num_verts > 0) { + // Transform vertices. + for (i = 0; i < comp_num_verts; ++i) { + stbtt_vertex* v = &comp_verts[i]; + stbtt_vertex_type x,y; + x=v->x; y=v->y; + v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + x=v->cx; y=v->cy; + v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + } + // Append vertices. + tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); + if (!tmp) { + if (vertices) STBTT_free(vertices, info->userdata); + if (comp_verts) STBTT_free(comp_verts, info->userdata); + return 0; + } + if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); //-V595 + STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); + if (vertices) STBTT_free(vertices, info->userdata); + vertices = tmp; + STBTT_free(comp_verts, info->userdata); + num_vertices += comp_num_verts; + } + // More components ? + more = flags & (1<<5); + } + } else if (numberOfContours < 0) { + // @TODO other compound variations? + STBTT_assert(0); + } else { + // numberOfCounters == 0, do nothing + } + + *pvertices = vertices; + return num_vertices; +} + +typedef struct +{ + int bounds; + int started; + float first_x, first_y; + float x, y; + stbtt_int32 min_x, max_x, min_y, max_y; + + stbtt_vertex *pvertices; + int num_vertices; +} stbtt__csctx; + +#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} + +static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) +{ + if (x > c->max_x || !c->started) c->max_x = x; + if (y > c->max_y || !c->started) c->max_y = y; + if (x < c->min_x || !c->started) c->min_x = x; + if (y < c->min_y || !c->started) c->min_y = y; + c->started = 1; +} + +static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) +{ + if (c->bounds) { + stbtt__track_vertex(c, x, y); + if (type == STBTT_vcubic) { + stbtt__track_vertex(c, cx, cy); + stbtt__track_vertex(c, cx1, cy1); + } + } else { + stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); + c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; + c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; + } + c->num_vertices++; +} + +static void stbtt__csctx_close_shape(stbtt__csctx *ctx) +{ + if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) +{ + stbtt__csctx_close_shape(ctx); + ctx->first_x = ctx->x = ctx->x + dx; + ctx->first_y = ctx->y = ctx->y + dy; + stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) +{ + ctx->x += dx; + ctx->y += dy; + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) +{ + float cx1 = ctx->x + dx1; + float cy1 = ctx->y + dy1; + float cx2 = cx1 + dx2; + float cy2 = cy1 + dy2; + ctx->x = cx2 + dx3; + ctx->y = cy2 + dy3; + stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); +} + +static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) +{ + int count = stbtt__cff_index_count(&idx); + int bias = 107; + if (count >= 33900) + bias = 32768; + else if (count >= 1240) + bias = 1131; + n += bias; + if (n < 0 || n >= count) + return stbtt__new_buf(NULL, 0); + return stbtt__cff_index_get(idx, n); +} + +static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt__buf fdselect = info->fdselect; + int nranges, start, end, v, fmt, fdselector = -1, i; + + stbtt__buf_seek(&fdselect, 0); + fmt = stbtt__buf_get8(&fdselect); + if (fmt == 0) { + // untested + stbtt__buf_skip(&fdselect, glyph_index); + fdselector = stbtt__buf_get8(&fdselect); + } else if (fmt == 3) { + nranges = stbtt__buf_get16(&fdselect); + start = stbtt__buf_get16(&fdselect); + for (i = 0; i < nranges; i++) { + v = stbtt__buf_get8(&fdselect); + end = stbtt__buf_get16(&fdselect); + if (glyph_index >= start && glyph_index < end) { + fdselector = v; + break; + } + start = end; + } + } + if (fdselector == -1) stbtt__new_buf(NULL, 0); + return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); +} + +static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) +{ + int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; + int has_subrs = 0, clear_stack; + float s[48]; + stbtt__buf subr_stack[10], subrs = info->subrs, b; + float f; + +#define STBTT__CSERR(s) (0) + + // this currently ignores the initial width value, which isn't needed if we have hmtx + b = stbtt__cff_index_get(info->charstrings, glyph_index); + while (b.cursor < b.size) { + i = 0; + clear_stack = 1; + b0 = stbtt__buf_get8(&b); + switch (b0) { + // @TODO implement hinting + case 0x13: // hintmask + case 0x14: // cntrmask + if (in_header) + maskbits += (sp / 2); // implicit "vstem" + in_header = 0; + stbtt__buf_skip(&b, (maskbits + 7) / 8); + break; + + case 0x01: // hstem + case 0x03: // vstem + case 0x12: // hstemhm + case 0x17: // vstemhm + maskbits += (sp / 2); + break; + + case 0x15: // rmoveto + in_header = 0; + if (sp < 2) return STBTT__CSERR("rmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); + break; + case 0x04: // vmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("vmoveto stack"); + stbtt__csctx_rmove_to(c, 0, s[sp-1]); + break; + case 0x16: // hmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("hmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-1], 0); + break; + + case 0x05: // rlineto + if (sp < 2) return STBTT__CSERR("rlineto stack"); + for (; i + 1 < sp; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical + // starting from a different place. + + case 0x07: // vlineto + if (sp < 1) return STBTT__CSERR("vlineto stack"); + goto vlineto; + case 0x06: // hlineto + if (sp < 1) return STBTT__CSERR("hlineto stack"); + for (;;) { + if (i >= sp) break; + stbtt__csctx_rline_to(c, s[i], 0); + i++; + vlineto: + if (i >= sp) break; + stbtt__csctx_rline_to(c, 0, s[i]); + i++; + } + break; + + case 0x1F: // hvcurveto + if (sp < 4) return STBTT__CSERR("hvcurveto stack"); + goto hvcurveto; + case 0x1E: // vhcurveto + if (sp < 4) return STBTT__CSERR("vhcurveto stack"); + for (;;) { + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); + i += 4; + hvcurveto: + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); + i += 4; + } + break; + + case 0x08: // rrcurveto + if (sp < 6) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x18: // rcurveline + if (sp < 8) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp - 2; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + case 0x19: // rlinecurve + if (sp < 8) return STBTT__CSERR("rlinecurve stack"); + for (; i + 1 < sp - 6; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x1A: // vvcurveto + case 0x1B: // hhcurveto + if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); + f = 0.0; + if (sp & 1) { f = s[i]; i++; } + for (; i + 3 < sp; i += 4) { + if (b0 == 0x1B) + stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); + else + stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); + f = 0.0; + } + break; + + case 0x0A: // callsubr + if (!has_subrs) { + if (info->fdselect.size) + subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); + has_subrs = 1; + } + // fallthrough + case 0x1D: // callgsubr + if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); + v = (int) s[--sp]; + if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); + subr_stack[subr_stack_height++] = b; + b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); + if (b.size == 0) return STBTT__CSERR("subr not found"); + b.cursor = 0; + clear_stack = 0; + break; + + case 0x0B: // return + if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); + b = subr_stack[--subr_stack_height]; + clear_stack = 0; + break; + + case 0x0E: // endchar + stbtt__csctx_close_shape(c); + return 1; + + case 0x0C: { // two-byte escape + float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; + float dx, dy; + int b1 = stbtt__buf_get8(&b); + switch (b1) { + // @TODO These "flex" implementations ignore the flex-depth and resolution, + // and always draw beziers. + case 0x22: // hflex + if (sp < 7) return STBTT__CSERR("hflex stack"); + dx1 = s[0]; + dx2 = s[1]; + dy2 = s[2]; + dx3 = s[3]; + dx4 = s[4]; + dx5 = s[5]; + dx6 = s[6]; + stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); + break; + + case 0x23: // flex + if (sp < 13) return STBTT__CSERR("flex stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = s[10]; + dy6 = s[11]; + //fd is s[12] + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + case 0x24: // hflex1 + if (sp < 9) return STBTT__CSERR("hflex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dx4 = s[5]; + dx5 = s[6]; + dy5 = s[7]; + dx6 = s[8]; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); + break; + + case 0x25: // flex1 + if (sp < 11) return STBTT__CSERR("flex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = dy6 = s[10]; + dx = dx1+dx2+dx3+dx4+dx5; + dy = dy1+dy2+dy3+dy4+dy5; + if (STBTT_fabs(dx) > STBTT_fabs(dy)) + dy6 = -dy; + else + dx6 = -dx; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + default: + return STBTT__CSERR("unimplemented"); + } + } break; + + default: + if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) //-V560 + return STBTT__CSERR("reserved operator"); + + // push immediate + if (b0 == 255) { + f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; + } else { + stbtt__buf_skip(&b, -1); + f = (float)(stbtt_int16)stbtt__cff_int(&b); + } + if (sp >= 48) return STBTT__CSERR("push stack overflow"); + s[sp++] = f; + clear_stack = 0; + break; + } + if (clear_stack) sp = 0; + } + return STBTT__CSERR("no endchar"); + +#undef STBTT__CSERR +} + +static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + // runs the charstring twice, once to count and once to output (to avoid realloc) + stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); + stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); + if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { + *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); + output_ctx.pvertices = *pvertices; + if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { + STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); + return output_ctx.num_vertices; + } + } + *pvertices = NULL; + return 0; +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + stbtt__csctx c = STBTT__CSCTX_INIT(1); + int r = stbtt__run_charstring(info, glyph_index, &c); + if (x0) *x0 = r ? c.min_x : 0; + if (y0) *y0 = r ? c.min_y : 0; + if (x1) *x1 = r ? c.max_x : 0; + if (y1) *y1 = r ? c.max_y : 0; + return r ? c.num_vertices : 0; +} + +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + if (!info->cff.size) + return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); + else + return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); +} + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) +{ + stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); + if (glyph_index < numOfLongHorMetrics) { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); + } else { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); + } +} + +static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint8 *data = info->data + info->kern; + stbtt_uint32 needle, straw; + int l, r, m; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + l = 0; + r = ttUSHORT(data+10) - 1; + needle = glyph1 << 16 | glyph2; + while (l <= r) { + m = (l + r) >> 1; + straw = ttULONG(data+18+(m*6)); // note: unaligned read + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else + return ttSHORT(data+22+(m*6)); + } + return 0; +} + +static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) +{ + stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); + switch(coverageFormat) { + case 1: { + stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); + + // Binary search. + stbtt_int32 l=0, r=glyphCount-1, m; + int straw, needle=glyph; + while (l <= r) { + stbtt_uint8 *glyphArray = coverageTable + 4; + stbtt_uint16 glyphID; + m = (l + r) >> 1; + glyphID = ttUSHORT(glyphArray + 2 * m); + straw = glyphID; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + return m; + } + } + } break; + + case 2: { + stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); + stbtt_uint8 *rangeArray = coverageTable + 4; + + // Binary search. + stbtt_int32 l=0, r=rangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *rangeRecord; + m = (l + r) >> 1; + rangeRecord = rangeArray + 6 * m; + strawStart = ttUSHORT(rangeRecord); + strawEnd = ttUSHORT(rangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else { + stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); + return startCoverageIndex + glyph - strawStart; + } + } + } break; + + default: { + // There are no other cases. + STBTT_assert(0); + } break; + } + + return -1; +} + +static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) +{ + stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); + switch(classDefFormat) + { + case 1: { + stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); + stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); + stbtt_uint8 *classDef1ValueArray = classDefTable + 6; + + if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) + return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); + + // [DEAR IMGUI] Commented to fix static analyzer warning + //classDefTable = classDef1ValueArray + 2 * glyphCount; + } break; + + case 2: { + stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); + stbtt_uint8 *classRangeRecords = classDefTable + 4; + + // Binary search. + stbtt_int32 l=0, r=classRangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *classRangeRecord; + m = (l + r) >> 1; + classRangeRecord = classRangeRecords + 6 * m; + strawStart = ttUSHORT(classRangeRecord); + strawEnd = ttUSHORT(classRangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else + return (stbtt_int32)ttUSHORT(classRangeRecord + 4); + } + + // [DEAR IMGUI] Commented to fix static analyzer warning + //classDefTable = classRangeRecords + 6 * classRangeCount; + } break; + + default: { + // There are no other cases. + STBTT_assert(0); + } break; + } + + return -1; +} + +// Define to STBTT_assert(x) if you want to break on unimplemented formats. +#define STBTT_GPOS_TODO_assert(x) + +static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint16 lookupListOffset; + stbtt_uint8 *lookupList; + stbtt_uint16 lookupCount; + stbtt_uint8 *data; + stbtt_int32 i; + + if (!info->gpos) return 0; + + data = info->data + info->gpos; + + if (ttUSHORT(data+0) != 1) return 0; // Major version 1 + if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 + + lookupListOffset = ttUSHORT(data+8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); + + for (i=0; i> 1; + pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; + secondGlyph = ttUSHORT(pairValue); + straw = secondGlyph; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + stbtt_int16 xAdvance = ttSHORT(pairValue + 2); + return xAdvance; + } + } + } break; + + case 2: { + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + + stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); + stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); + int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); + int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); + + stbtt_uint16 class1Count = ttUSHORT(table + 12); + stbtt_uint16 class2Count = ttUSHORT(table + 14); + STBTT_assert(glyph1class < class1Count); + STBTT_assert(glyph2class < class2Count); + + // TODO: Support more formats. + STBTT_GPOS_TODO_assert(valueFormat1 == 4); + if (valueFormat1 != 4) return 0; + STBTT_GPOS_TODO_assert(valueFormat2 == 0); + if (valueFormat2 != 0) return 0; + + if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) { + stbtt_uint8 *class1Records = table + 16; + stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count); + stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } + } break; + + default: { + // There are no other cases. + STBTT_assert(0); + break; + }; + } + } + break; + }; + + default: + // TODO: Implement other stuff. + break; + } + } + + return 0; +} + +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) +{ + int xAdvance = 0; + + if (info->gpos) + xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); + + if (info->kern) + xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); + + return xAdvance; +} + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) +{ + if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs + return 0; + return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); +} + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) +{ + stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); +} + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) +{ + if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); + if (descent) *descent = ttSHORT(info->data+info->hhea + 6); + if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); +} + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) +{ + int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); + if (!tab) + return 0; + if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); + if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); + if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); + return 1; +} + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) +{ + *x0 = ttSHORT(info->data + info->head + 36); + *y0 = ttSHORT(info->data + info->head + 38); + *x1 = ttSHORT(info->data + info->head + 40); + *y1 = ttSHORT(info->data + info->head + 42); +} + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) +{ + int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); + return (float) height / fheight; +} + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) +{ + int unitsPerEm = ttUSHORT(info->data + info->head + 18); + return pixels / unitsPerEm; +} + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) +{ + STBTT_free(v, info->userdata); +} + +////////////////////////////////////////////////////////////////////////////// +// +// antialiasing software rasterizer +// + +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning + if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { + // e.g. space character + if (ix0) *ix0 = 0; + if (iy0) *iy0 = 0; + if (ix1) *ix1 = 0; + if (iy1) *iy1 = 0; + } else { + // move to integral bboxes (treating pixels as little squares, what pixels get touched)? + if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); + if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); + if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); + if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); + } +} + +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); +} + +////////////////////////////////////////////////////////////////////////////// +// +// Rasterizer + +typedef struct stbtt__hheap_chunk +{ + struct stbtt__hheap_chunk *next; +} stbtt__hheap_chunk; + +typedef struct stbtt__hheap +{ + struct stbtt__hheap_chunk *head; + void *first_free; + int num_remaining_in_head_chunk; +} stbtt__hheap; + +static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) +{ + if (hh->first_free) { + void *p = hh->first_free; + hh->first_free = * (void **) p; + return p; + } else { + if (hh->num_remaining_in_head_chunk == 0) { + int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); + stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); + if (c == NULL) + return NULL; + c->next = hh->head; + hh->head = c; + hh->num_remaining_in_head_chunk = count; + } + --hh->num_remaining_in_head_chunk; + return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; + } +} + +static void stbtt__hheap_free(stbtt__hheap *hh, void *p) +{ + *(void **) p = hh->first_free; + hh->first_free = p; +} + +static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) +{ + stbtt__hheap_chunk *c = hh->head; + while (c) { + stbtt__hheap_chunk *n = c->next; + STBTT_free(c, userdata); + c = n; + } +} + +typedef struct stbtt__edge { + float x0,y0, x1,y1; + int invert; +} stbtt__edge; + + +typedef struct stbtt__active_edge +{ + struct stbtt__active_edge *next; + #if STBTT_RASTERIZER_VERSION==1 + int x,dx; + float ey; + int direction; + #elif STBTT_RASTERIZER_VERSION==2 + float fx,fdx,fdy; + float direction; + float sy; + float ey; + #else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" + #endif +} stbtt__active_edge; + +#if STBTT_RASTERIZER_VERSION == 1 +#define STBTT_FIXSHIFT 10 +#define STBTT_FIX (1 << STBTT_FIXSHIFT) +#define STBTT_FIXMASK (STBTT_FIX-1) + +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + if (!z) return z; + + // round dx down to avoid overshooting + if (dxdy < 0) + z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); + else + z->dx = STBTT_ifloor(STBTT_FIX * dxdy); + + z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount + z->x -= off_x * STBTT_FIX; + + z->ey = e->y1; + z->next = 0; + z->direction = e->invert ? 1 : -1; + return z; +} +#elif STBTT_RASTERIZER_VERSION == 2 +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + //STBTT_assert(e->y0 <= start_point); + if (!z) return z; + z->fdx = dxdy; + z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; + z->fx = e->x0 + dxdy * (start_point - e->y0); + z->fx -= off_x; + z->direction = e->invert ? 1.0f : -1.0f; + z->sy = e->y0; + z->ey = e->y1; + z->next = 0; + return z; +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#if STBTT_RASTERIZER_VERSION == 1 +// note: this routine clips fills that extend off the edges... ideally this +// wouldn't happen, but it could happen if the truetype glyph bounding boxes +// are wrong, or if the user supplies a too-small bitmap +static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) +{ + // non-zero winding fill + int x0=0, w=0; + + while (e) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; w += e->direction; + } else { + int x1 = e->x; w += e->direction; + // if we went to zero, we need to draw + if (w == 0) { + int i = x0 >> STBTT_FIXSHIFT; + int j = x1 >> STBTT_FIXSHIFT; + + if (i < len && j >= 0) { + if (i == j) { + // x0,x1 are the same pixel, so compute combined coverage + scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); + } else { + if (i >= 0) // add antialiasing for x0 + scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); + else + i = -1; // clip + + if (j < len) // add antialiasing for x1 + scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); + else + j = len; // clip + + for (++i; i < j; ++i) // fill pixels between x0 and x1 + scanline[i] = scanline[i] + (stbtt_uint8) max_weight; + } + } + } + } + + e = e->next; + } +} + +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0; + int max_weight = (255 / vsubsample); // weight per vertical scanline + int s; // vertical subsample index + unsigned char scanline_data[512], *scanline; + + if (result->w > 512) + scanline = (unsigned char *) STBTT_malloc(result->w, userdata); + else + scanline = scanline_data; + + y = off_y * vsubsample; + e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; + + while (j < result->h) { + STBTT_memset(scanline, 0, result->w); + for (s=0; s < vsubsample; ++s) { + // find center of pixel for this scanline + float scan_y = y + 0.5f; + stbtt__active_edge **step = &active; + + // update all active edges; + // remove all active edges that terminate before the center of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + z->x += z->dx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + } + + // resort the list if needed + for(;;) { + int changed=0; + step = &active; + while (*step && (*step)->next) { + if ((*step)->x > (*step)->next->x) { + stbtt__active_edge *t = *step; + stbtt__active_edge *q = t->next; + + t->next = q->next; + q->next = t; + *step = q; + changed = 1; + } + step = &(*step)->next; + } + if (!changed) break; + } + + // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline + while (e->y0 <= scan_y) { + if (e->y1 > scan_y) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); + if (z != NULL) { + // find insertion point + if (active == NULL) + active = z; + else if (z->x < active->x) { + // insert at front + z->next = active; + active = z; + } else { + // find thing to insert AFTER + stbtt__active_edge *p = active; + while (p->next && p->next->x < z->x) + p = p->next; + // at this point, p->next->x is NOT < z->x + z->next = p->next; + p->next = z; + } + } + } + ++e; + } + + // now process all active edges in XOR fashion + if (active) + stbtt__fill_active_edges(scanline, result->w, active, max_weight); + + ++y; + } + STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} + +#elif STBTT_RASTERIZER_VERSION == 2 + +// the edge passed in here does not cross the vertical line at x or the vertical line at x+1 +// (i.e. it has already been clipped to those) +static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) +{ + if (y0 == y1) return; + STBTT_assert(y0 < y1); + STBTT_assert(e->sy <= e->ey); + if (y0 > e->ey) return; + if (y1 < e->sy) return; + if (y0 < e->sy) { + x0 += (x1-x0) * (e->sy - y0) / (y1-y0); + y0 = e->sy; + } + if (y1 > e->ey) { + x1 += (x1-x0) * (e->ey - y1) / (y1-y0); + y1 = e->ey; + } + + if (x0 == x) + STBTT_assert(x1 <= x+1); + else if (x0 == x+1) + STBTT_assert(x1 >= x); + else if (x0 <= x) + STBTT_assert(x1 <= x); + else if (x0 >= x+1) + STBTT_assert(x1 >= x+1); + else + STBTT_assert(x1 >= x && x1 <= x+1); + + if (x0 <= x && x1 <= x) + scanline[x] += e->direction * (y1-y0); + else if (x0 >= x+1 && x1 >= x+1) + ; + else { + STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); + scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position + } +} + +static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) +{ + float y_bottom = y_top+1; + + while (e) { + // brute force every pixel + + // compute intersection points with top & bottom + STBTT_assert(e->ey >= y_top); + + if (e->fdx == 0) { + float x0 = e->fx; + if (x0 < len) { + if (x0 >= 0) { + stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); + stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); + } else { + stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); + } + } + } else { + float x0 = e->fx; + float dx = e->fdx; + float xb = x0 + dx; + float x_top, x_bottom; + float sy0,sy1; + float dy = e->fdy; + STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); + + // compute endpoints of line segment clipped to this scanline (if the + // line segment starts on this scanline. x0 is the intersection of the + // line with y_top, but that may be off the line segment. + if (e->sy > y_top) { + x_top = x0 + dx * (e->sy - y_top); + sy0 = e->sy; + } else { + x_top = x0; + sy0 = y_top; + } + if (e->ey < y_bottom) { + x_bottom = x0 + dx * (e->ey - y_top); + sy1 = e->ey; + } else { + x_bottom = xb; + sy1 = y_bottom; + } + + if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { + // from here on, we don't have to range check x values + + if ((int) x_top == (int) x_bottom) { + float height; + // simple case, only spans one pixel + int x = (int) x_top; + height = sy1 - sy0; + STBTT_assert(x >= 0 && x < len); + scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height; + scanline_fill[x] += e->direction * height; // everything right of this pixel is filled + } else { + int x,x1,x2; + float y_crossing, step, sign, area; + // covers 2+ pixels + if (x_top > x_bottom) { + // flip scanline vertically; signed area is the same + float t; + sy0 = y_bottom - (sy0 - y_top); + sy1 = y_bottom - (sy1 - y_top); + t = sy0, sy0 = sy1, sy1 = t; + t = x_bottom, x_bottom = x_top, x_top = t; + dx = -dx; + dy = -dy; + t = x0, x0 = xb, xb = t; + // [DEAR IMGUI] Fix static analyzer warning + (void)dx; // [ImGui: fix static analyzer warning] + } + + x1 = (int) x_top; + x2 = (int) x_bottom; + // compute intersection with y axis at x1+1 + y_crossing = (x1+1 - x0) * dy + y_top; + + sign = e->direction; + // area of the rectangle covered from y0..y_crossing + area = sign * (y_crossing-sy0); + // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) + scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2); + + step = sign * dy; + for (x = x1+1; x < x2; ++x) { + scanline[x] += area + step/2; + area += step; + } + y_crossing += dy * (x2 - (x1+1)); + + STBTT_assert(STBTT_fabs(area) <= 1.01f); + + scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing); + + scanline_fill[x2] += sign * (sy1-sy0); + } + } else { + // if edge goes outside of box we're drawing, we require + // clipping logic. since this does not match the intended use + // of this library, we use a different, very slow brute + // force implementation + int x; + for (x=0; x < len; ++x) { + // cases: + // + // there can be up to two intersections with the pixel. any intersection + // with left or right edges can be handled by splitting into two (or three) + // regions. intersections with top & bottom do not necessitate case-wise logic. + // + // the old way of doing this found the intersections with the left & right edges, + // then used some simple logic to produce up to three segments in sorted order + // from top-to-bottom. however, this had a problem: if an x edge was epsilon + // across the x border, then the corresponding y position might not be distinct + // from the other y segment, and it might ignored as an empty segment. to avoid + // that, we need to explicitly produce segments based on x positions. + + // rename variables to clearly-defined pairs + float y0 = y_top; + float x1 = (float) (x); + float x2 = (float) (x+1); + float x3 = xb; + float y3 = y_bottom; + + // x = e->x + e->dx * (y-y_top) + // (y-y_top) = (x - e->x) / e->dx + // y = (x - e->x) / e->dx + y_top + float y1 = (x - x0) / dx + y_top; + float y2 = (x+1 - x0) / dx + y_top; + + if (x0 < x1 && x3 > x2) { // three segments descending down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x1 && x0 > x2) { // three segments descending down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else { // one segment + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); + } + } + } + } + e = e->next; + } +} + +// directly AA rasterize edges w/o supersampling +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0, i; + float scanline_data[129], *scanline, *scanline2; + + STBTT__NOTUSED(vsubsample); + + if (result->w > 64) + scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); + else + scanline = scanline_data; + + scanline2 = scanline + result->w; + + y = off_y; + e[n].y0 = (float) (off_y + result->h) + 1; + + while (j < result->h) { + // find center of pixel for this scanline + float scan_y_top = y + 0.0f; + float scan_y_bottom = y + 1.0f; + stbtt__active_edge **step = &active; + + STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); + STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); + + // update all active edges; + // remove all active edges that terminate before the top of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y_top) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + step = &((*step)->next); // advance through list + } + } + + // insert all edges that start before the bottom of this scanline + while (e->y0 <= scan_y_bottom) { + if (e->y0 != e->y1) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); + if (z != NULL) { + if (j == 0 && off_y != 0) { + if (z->ey < scan_y_top) { + // this can happen due to subpixel positioning and some kind of fp rounding error i think + z->ey = scan_y_top; + } + } + STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds + // insert at front + z->next = active; + active = z; + } + } + ++e; + } + + // now process all active edges + if (active) + stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); + + { + float sum = 0; + for (i=0; i < result->w; ++i) { + float k; + int m; + sum += scanline2[i]; + k = scanline[i] + sum; + k = (float) STBTT_fabs(k)*255 + 0.5f; + m = (int) k; + if (m > 255) m = 255; + result->pixels[j*result->stride + i] = (unsigned char) m; + } + } + // advance all the edges + step = &active; + while (*step) { + stbtt__active_edge *z = *step; + z->fx += z->fdx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + + ++y; + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) + +static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) +{ + int i,j; + for (i=1; i < n; ++i) { + stbtt__edge t = p[i], *a = &t; + j = i; + while (j > 0) { + stbtt__edge *b = &p[j-1]; + int c = STBTT__COMPARE(a,b); + if (!c) break; + p[j] = p[j-1]; + --j; + } + if (i != j) + p[j] = t; + } +} + +static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) +{ + /* threshold for transitioning to insertion sort */ + while (n > 12) { + stbtt__edge t; + int c01,c12,c,m,i,j; + + /* compute median of three */ + m = n >> 1; + c01 = STBTT__COMPARE(&p[0],&p[m]); + c12 = STBTT__COMPARE(&p[m],&p[n-1]); + /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ + if (c01 != c12) { + /* otherwise, we'll need to swap something else to middle */ + int z; + c = STBTT__COMPARE(&p[0],&p[n-1]); + /* 0>mid && midn => n; 0 0 */ + /* 0n: 0>n => 0; 0 n */ + z = (c == c12) ? 0 : n-1; + t = p[z]; + p[z] = p[m]; + p[m] = t; + } + /* now p[m] is the median-of-three */ + /* swap it to the beginning so it won't move around */ + t = p[0]; + p[0] = p[m]; + p[m] = t; + + /* partition loop */ + i=1; + j=n-1; + for(;;) { + /* handling of equality is crucial here */ + /* for sentinels & efficiency with duplicates */ + for (;;++i) { + if (!STBTT__COMPARE(&p[i], &p[0])) break; + } + for (;;--j) { + if (!STBTT__COMPARE(&p[0], &p[j])) break; + } + /* make sure we haven't crossed */ + if (i >= j) break; + t = p[i]; + p[i] = p[j]; + p[j] = t; + + ++i; + --j; + } + /* recurse on smaller side, iterate on larger */ + if (j < (n-i)) { + stbtt__sort_edges_quicksort(p,j); + p = p+i; + n = n-i; + } else { + stbtt__sort_edges_quicksort(p+i, n-i); + n = j; + } + } +} + +static void stbtt__sort_edges(stbtt__edge *p, int n) +{ + stbtt__sort_edges_quicksort(p, n); + stbtt__sort_edges_ins_sort(p, n); +} + +typedef struct +{ + float x,y; +} stbtt__point; + +static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) +{ + float y_scale_inv = invert ? -scale_y : scale_y; + stbtt__edge *e; + int n,i,j,k,m; +#if STBTT_RASTERIZER_VERSION == 1 + int vsubsample = result->h < 8 ? 15 : 5; +#elif STBTT_RASTERIZER_VERSION == 2 + int vsubsample = 1; +#else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + // vsubsample should divide 255 evenly; otherwise we won't reach full opacity + + // now we have to blow out the windings into explicit edge lists + n = 0; + for (i=0; i < windings; ++i) + n += wcount[i]; + + e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel + if (e == 0) return; + n = 0; + + m=0; + for (i=0; i < windings; ++i) { + stbtt__point *p = pts + m; + m += wcount[i]; + j = wcount[i]-1; + for (k=0; k < wcount[i]; j=k++) { + int a=k,b=j; + // skip the edge if horizontal + if (p[j].y == p[k].y) + continue; + // add edge from j to k to the list + e[n].invert = 0; + if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { + e[n].invert = 1; + a=j,b=k; + } + e[n].x0 = p[a].x * scale_x + shift_x; + e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; + e[n].x1 = p[b].x * scale_x + shift_x; + e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; + ++n; + } + } + + // now sort the edges by their highest point (should snap to integer, and then by x) + //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); + stbtt__sort_edges(e, n); + + // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule + stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); + + STBTT_free(e, userdata); +} + +static void stbtt__add_point(stbtt__point *points, int n, float x, float y) +{ + if (!points) return; // during first pass, it's unallocated + points[n].x = x; + points[n].y = y; +} + +// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching +static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) +{ + // midpoint + float mx = (x0 + 2*x1 + x2)/4; + float my = (y0 + 2*y1 + y2)/4; + // versus directly drawn line + float dx = (x0+x2)/2 - mx; + float dy = (y0+y2)/2 - my; + if (n > 16) // 65536 segments on one curve better be enough! + return 1; + if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA + stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x2,y2); + *num_points = *num_points+1; + } + return 1; +} + +static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) +{ + // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough + float dx0 = x1-x0; + float dy0 = y1-y0; + float dx1 = x2-x1; + float dy1 = y2-y1; + float dx2 = x3-x2; + float dy2 = y3-y2; + float dx = x3-x0; + float dy = y3-y0; + float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); + float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); + float flatness_squared = longlen*longlen-shortlen*shortlen; + + if (n > 16) // 65536 segments on one curve better be enough! + return; + + if (flatness_squared > objspace_flatness_squared) { + float x01 = (x0+x1)/2; + float y01 = (y0+y1)/2; + float x12 = (x1+x2)/2; + float y12 = (y1+y2)/2; + float x23 = (x2+x3)/2; + float y23 = (y2+y3)/2; + + float xa = (x01+x12)/2; + float ya = (y01+y12)/2; + float xb = (x12+x23)/2; + float yb = (y12+y23)/2; + + float mx = (xa+xb)/2; + float my = (ya+yb)/2; + + stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x3,y3); + *num_points = *num_points+1; + } +} + +// returns number of contours +static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) +{ + stbtt__point *points=0; + int num_points=0; + + float objspace_flatness_squared = objspace_flatness * objspace_flatness; + int i,n=0,start=0, pass; + + // count how many "moves" there are to get the contour count + for (i=0; i < num_verts; ++i) + if (vertices[i].type == STBTT_vmove) + ++n; + + *num_contours = n; + if (n == 0) return 0; + + *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); + + if (*contour_lengths == 0) { + *num_contours = 0; + return 0; + } + + // make two passes through the points so we don't need to realloc + for (pass=0; pass < 2; ++pass) { + float x=0,y=0; + if (pass == 1) { + points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); + if (points == NULL) goto error; + } + num_points = 0; + n= -1; + for (i=0; i < num_verts; ++i) { + switch (vertices[i].type) { + case STBTT_vmove: + // start the next contour + if (n >= 0) + (*contour_lengths)[n] = num_points - start; + ++n; + start = num_points; + + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x,y); + break; + case STBTT_vline: + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x, y); + break; + case STBTT_vcurve: + stbtt__tesselate_curve(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + case STBTT_vcubic: + stbtt__tesselate_cubic(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].cx1, vertices[i].cy1, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + } + } + (*contour_lengths)[n] = num_points - start; + } + + return points; +error: + STBTT_free(points, userdata); + STBTT_free(*contour_lengths, userdata); + *contour_lengths = 0; + *num_contours = 0; + return NULL; +} + +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) +{ + float scale = scale_x > scale_y ? scale_y : scale_x; + int winding_count = 0; + int *winding_lengths = NULL; + stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); + if (windings) { + stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); + STBTT_free(winding_lengths, userdata); + STBTT_free(windings, userdata); + } +} + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + int ix0,iy0,ix1,iy1; + stbtt__bitmap gbm; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + + if (scale_x == 0) scale_x = scale_y; + if (scale_y == 0) { + if (scale_x == 0) { + STBTT_free(vertices, info->userdata); + return NULL; + } + scale_y = scale_x; + } + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); + + // now we get the size + gbm.w = (ix1 - ix0); + gbm.h = (iy1 - iy0); + gbm.pixels = NULL; // in case we error + + if (width ) *width = gbm.w; + if (height) *height = gbm.h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + if (gbm.w && gbm.h) { + gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); + if (gbm.pixels) { + gbm.stride = gbm.w; + + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); + } + } + STBTT_free(vertices, info->userdata); + return gbm.pixels; +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) +{ + int ix0,iy0; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + stbtt__bitmap gbm; + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); + gbm.pixels = output; + gbm.w = out_w; + gbm.h = out_h; + gbm.stride = out_stride; + + if (gbm.w && gbm.h) + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); + + STBTT_free(vertices, info->userdata); +} + +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) +{ + stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); +} + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-CRAPPY packing to keep source code small + +static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata) +{ + float scale; + int x,y,bottom_y, i; + stbtt_fontinfo f; + f.userdata = NULL; + if (!stbtt_InitFont(&f, data, offset)) + return -1; + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + x=y=1; + bottom_y = 1; + + scale = stbtt_ScaleForPixelHeight(&f, pixel_height); + + for (i=0; i < num_chars; ++i) { + int advance, lsb, x0,y0,x1,y1,gw,gh; + int g = stbtt_FindGlyphIndex(&f, first_char + i); + stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); + stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); + gw = x1-x0; + gh = y1-y0; + if (x + gw + 1 >= pw) + y = bottom_y, x = 1; // advance to next row + if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row + return -i; + STBTT_assert(x+gw < pw); + STBTT_assert(y+gh < ph); + stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); + chardata[i].x0 = (stbtt_int16) x; + chardata[i].y0 = (stbtt_int16) y; + chardata[i].x1 = (stbtt_int16) (x + gw); + chardata[i].y1 = (stbtt_int16) (y + gh); + chardata[i].xadvance = scale * advance; + chardata[i].xoff = (float) x0; + chardata[i].yoff = (float) y0; + x = x + gw + 1; + if (y+gh+1 > bottom_y) + bottom_y = y+gh+1; + } + return bottom_y; +} + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) +{ + float d3d_bias = opengl_fillrule ? 0 : -0.5f; + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_bakedchar *b = chardata + char_index; + int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); + int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); + + q->x0 = round_x + d3d_bias; + q->y0 = round_y + d3d_bias; + q->x1 = round_x + b->x1 - b->x0 + d3d_bias; + q->y1 = round_y + b->y1 - b->y0 + d3d_bias; + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// rectangle packing replacement routines if you don't have stb_rect_pack.h +// + +#ifndef STB_RECT_PACK_VERSION + +typedef int stbrp_coord; + +//////////////////////////////////////////////////////////////////////////////////// +// // +// // +// COMPILER WARNING ?!?!? // +// // +// // +// if you get a compile warning due to these symbols being defined more than // +// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // +// // +//////////////////////////////////////////////////////////////////////////////////// + +typedef struct +{ + int width,height; + int x,y,bottom_y; +} stbrp_context; + +typedef struct +{ + unsigned char x; +} stbrp_node; + +struct stbrp_rect +{ + stbrp_coord x,y; + int id,w,h,was_packed; +}; + +static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) +{ + con->width = pw; + con->height = ph; + con->x = 0; + con->y = 0; + con->bottom_y = 0; + STBTT__NOTUSED(nodes); + STBTT__NOTUSED(num_nodes); +} + +static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) +{ + int i; + for (i=0; i < num_rects; ++i) { + if (con->x + rects[i].w > con->width) { + con->x = 0; + con->y = con->bottom_y; + } + if (con->y + rects[i].h > con->height) + break; + rects[i].x = con->x; + rects[i].y = con->y; + rects[i].was_packed = 1; + con->x += rects[i].w; + if (con->y + rects[i].h > con->bottom_y) + con->bottom_y = con->y + rects[i].h; + } + for ( ; i < num_rects; ++i) + rects[i].was_packed = 0; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If +// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) +{ + stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); + int num_nodes = pw - padding; + stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); + + if (context == NULL || nodes == NULL) { + if (context != NULL) STBTT_free(context, alloc_context); + if (nodes != NULL) STBTT_free(nodes , alloc_context); + return 0; + } + + spc->user_allocator_context = alloc_context; + spc->width = pw; + spc->height = ph; + spc->pixels = pixels; + spc->pack_info = context; + spc->nodes = nodes; + spc->padding = padding; + spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; + spc->h_oversample = 1; + spc->v_oversample = 1; + spc->skip_missing = 0; + + stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); + + if (pixels) + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + + return 1; +} + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) +{ + STBTT_free(spc->nodes , spc->user_allocator_context); + STBTT_free(spc->pack_info, spc->user_allocator_context); +} + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) +{ + STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); + STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); + if (h_oversample <= STBTT_MAX_OVERSAMPLE) + spc->h_oversample = h_oversample; + if (v_oversample <= STBTT_MAX_OVERSAMPLE) + spc->v_oversample = v_oversample; +} + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) +{ + spc->skip_missing = skip; +} + +#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) + +static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_w = w - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < h; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < w; ++i) { + STBTT_assert(pixels[i] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i] = (unsigned char) (total / kernel_width); + } + + pixels += stride_in_bytes; + } +} + +static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_h = h - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < w; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < h; ++i) { + STBTT_assert(pixels[i*stride_in_bytes] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + + pixels += 1; + } +} + +static float stbtt__oversample_shift(int oversample) +{ + if (!oversample) + return 0.0f; + + // The prefilter is a box filter of width "oversample", + // which shifts phase by (oversample - 1)/2 pixels in + // oversampled space. We want to shift in the opposite + // direction to counter this. + return (float)-(oversample - 1) / (2.0f * (float)oversample); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k; + + k=0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + ranges[i].h_oversample = (unsigned char) spc->h_oversample; + ranges[i].v_oversample = (unsigned char) spc->v_oversample; + for (j=0; j < ranges[i].num_chars; ++j) { + int x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + if (glyph == 0 && spc->skip_missing) { + rects[k].w = rects[k].h = 0; + } else { + stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + &x0,&y0,&x1,&y1); + rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); + rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); + } + ++k; + } + } + + return k; +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, + output, + out_w - (prefilter_x - 1), + out_h - (prefilter_y - 1), + out_stride, + scale_x, + scale_y, + shift_x, + shift_y, + glyph); + + if (prefilter_x > 1) + stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); + + if (prefilter_y > 1) + stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); + + *sub_x = stbtt__oversample_shift(prefilter_x); + *sub_y = stbtt__oversample_shift(prefilter_y); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k, return_value = 1; + + // save current values + int old_h_over = spc->h_oversample; + int old_v_over = spc->v_oversample; + + k = 0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + float recip_h,recip_v,sub_x,sub_y; + spc->h_oversample = ranges[i].h_oversample; + spc->v_oversample = ranges[i].v_oversample; + recip_h = 1.0f / spc->h_oversample; + recip_v = 1.0f / spc->v_oversample; + sub_x = stbtt__oversample_shift(spc->h_oversample); + sub_y = stbtt__oversample_shift(spc->v_oversample); + for (j=0; j < ranges[i].num_chars; ++j) { + stbrp_rect *r = &rects[k]; + if (r->was_packed && r->w != 0 && r->h != 0) { + stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; + int advance, lsb, x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + stbrp_coord pad = (stbrp_coord) spc->padding; + + // pad on left and top + r->x += pad; + r->y += pad; + r->w -= pad; + r->h -= pad; + stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); + stbtt_GetGlyphBitmapBox(info, glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + &x0,&y0,&x1,&y1); + stbtt_MakeGlyphBitmapSubpixel(info, + spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w - spc->h_oversample+1, + r->h - spc->v_oversample+1, + spc->stride_in_bytes, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + glyph); + + if (spc->h_oversample > 1) + stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->h_oversample); + + if (spc->v_oversample > 1) + stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->v_oversample); + + bc->x0 = (stbtt_int16) r->x; + bc->y0 = (stbtt_int16) r->y; + bc->x1 = (stbtt_int16) (r->x + r->w); + bc->y1 = (stbtt_int16) (r->y + r->h); + bc->xadvance = scale * advance; + bc->xoff = (float) x0 * recip_h + sub_x; + bc->yoff = (float) y0 * recip_v + sub_y; + bc->xoff2 = (x0 + r->w) * recip_h + sub_x; + bc->yoff2 = (y0 + r->h) * recip_v + sub_y; + } else { + return_value = 0; // if any fail, report failure + } + + ++k; + } + } + + // restore original values + spc->h_oversample = old_h_over; + spc->v_oversample = old_v_over; + + return return_value; +} + +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) +{ + stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); +} + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) +{ + stbtt_fontinfo info; + int i,j,n, return_value = 1; + //stbrp_context *context = (stbrp_context *) spc->pack_info; + stbrp_rect *rects; + + // flag all characters as NOT packed + for (i=0; i < num_ranges; ++i) + for (j=0; j < ranges[i].num_chars; ++j) + ranges[i].chardata_for_range[j].x0 = + ranges[i].chardata_for_range[j].y0 = + ranges[i].chardata_for_range[j].x1 = + ranges[i].chardata_for_range[j].y1 = 0; + + n = 0; + for (i=0; i < num_ranges; ++i) + n += ranges[i].num_chars; + + rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); + if (rects == NULL) + return 0; + + info.userdata = spc->user_allocator_context; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); + + n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); + + stbtt_PackFontRangesPackRects(spc, rects, n); + + return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); + + STBTT_free(rects, spc->user_allocator_context); + return return_value; +} + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) +{ + stbtt_pack_range range; + range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; + range.array_of_unicode_codepoints = NULL; + range.num_chars = num_chars_in_range; + range.chardata_for_range = chardata_for_range; + range.font_size = font_size; + return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); +} + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) +{ + int i_ascent, i_descent, i_lineGap; + float scale; + stbtt_fontinfo info; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); + scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); + stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); + *ascent = (float) i_ascent * scale; + *descent = (float) i_descent * scale; + *lineGap = (float) i_lineGap * scale; +} + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) +{ + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_packedchar *b = chardata + char_index; + + if (align_to_integer) { + float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); + float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); + q->x0 = x; + q->y0 = y; + q->x1 = x + b->xoff2 - b->xoff; + q->y1 = y + b->yoff2 - b->yoff; + } else { + q->x0 = *xpos + b->xoff; + q->y0 = *ypos + b->yoff; + q->x1 = *xpos + b->xoff2; + q->y1 = *ypos + b->yoff2; + } + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// sdf computation +// + +#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) +#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) + +static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) +{ + float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; + float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; + float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; + float roperp = orig[1]*ray[0] - orig[0]*ray[1]; + + float a = q0perp - 2*q1perp + q2perp; + float b = q1perp - q0perp; + float c = q0perp - roperp; + + float s0 = 0., s1 = 0.; + int num_s = 0; + + if (a != 0.0) { + float discr = b*b - a*c; + if (discr > 0.0) { + float rcpna = -1 / a; + float d = (float) STBTT_sqrt(discr); + s0 = (b+d) * rcpna; + s1 = (b-d) * rcpna; + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { + if (num_s == 0) s0 = s1; + ++num_s; + } + } + } else { + // 2*b*s + c = 0 + // s = -c / (2*b) + s0 = c / (-2 * b); + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + } + + if (num_s == 0) + return 0; + else { + float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); + float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; + + float q0d = q0[0]*rayn_x + q0[1]*rayn_y; + float q1d = q1[0]*rayn_x + q1[1]*rayn_y; + float q2d = q2[0]*rayn_x + q2[1]*rayn_y; + float rod = orig[0]*rayn_x + orig[1]*rayn_y; + + float q10d = q1d - q0d; + float q20d = q2d - q0d; + float q0rd = q0d - rod; + + hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; + hits[0][1] = a*s0+b; + + if (num_s > 1) { + hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; + hits[1][1] = a*s1+b; + return 2; + } else { + return 1; + } + } +} + +static int equal(float *a, float *b) +{ + return (a[0] == b[0] && a[1] == b[1]); +} + +static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) +{ + int i; + float orig[2], ray[2] = { 1, 0 }; + float y_frac; + int winding = 0; + + orig[0] = x; + //orig[1] = y; // [DEAR IMGUI] commmented double assignment + + // make sure y never passes through a vertex of the shape + y_frac = (float) STBTT_fmod(y, 1.0f); + if (y_frac < 0.01f) + y += 0.01f; + else if (y_frac > 0.99f) + y -= 0.01f; + orig[1] = y; + + // test a ray from (-infinity,y) to (x,y) + for (i=0; i < nverts; ++i) { + if (verts[i].type == STBTT_vline) { + int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; + int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } + if (verts[i].type == STBTT_vcurve) { + int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; + int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; + int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; + int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); + int by = STBTT_max(y0,STBTT_max(y1,y2)); + if (y > ay && y < by && x > ax) { + float q0[2],q1[2],q2[2]; + float hits[2][2]; + q0[0] = (float)x0; + q0[1] = (float)y0; + q1[0] = (float)x1; + q1[1] = (float)y1; + q2[0] = (float)x2; + q2[1] = (float)y2; + if (equal(q0,q1) || equal(q1,q2)) { + x0 = (int)verts[i-1].x; + y0 = (int)verts[i-1].y; + x1 = (int)verts[i ].x; + y1 = (int)verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } else { + int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); + if (num_hits >= 1) + if (hits[0][0] < 0) + winding += (hits[0][1] < 0 ? -1 : 1); + if (num_hits >= 2) + if (hits[1][0] < 0) + winding += (hits[1][1] < 0 ? -1 : 1); + } + } + } + } + return winding; +} + +static float stbtt__cuberoot( float x ) +{ + if (x<0) + return -(float) STBTT_pow(-x,1.0f/3.0f); + else + return (float) STBTT_pow( x,1.0f/3.0f); +} + +// x^3 + c*x^2 + b*x + a = 0 +static int stbtt__solve_cubic(float a, float b, float c, float* r) +{ + float s = -a / 3; + float p = b - a*a / 3; + float q = a * (2*a*a - 9*b) / 27 + c; + float p3 = p*p*p; + float d = q*q + 4*p3 / 27; + if (d >= 0) { + float z = (float) STBTT_sqrt(d); + float u = (-q + z) / 2; + float v = (-q - z) / 2; + u = stbtt__cuberoot(u); + v = stbtt__cuberoot(v); + r[0] = s + u + v; + return 1; + } else { + float u = (float) STBTT_sqrt(-p/3); + float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative + float m = (float) STBTT_cos(v); + float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; + r[0] = s + u * 2 * m; + r[1] = s - u * (m + n); + r[2] = s - u * (m - n); + + //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? + //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); + //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); + return 3; + } +} + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + float scale_x = scale, scale_y = scale; + int ix0,iy0,ix1,iy1; + int w,h; + unsigned char *data; + + // if one scale is 0, use same scale for both + if (scale_x == 0) scale_x = scale_y; + if (scale_y == 0) { + if (scale_x == 0) return NULL; // if both scales are 0, return NULL + scale_y = scale_x; + } + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); + + // if empty, return NULL + if (ix0 == ix1 || iy0 == iy1) + return NULL; + + ix0 -= padding; + iy0 -= padding; + ix1 += padding; + iy1 += padding; + + w = (ix1 - ix0); + h = (iy1 - iy0); + + if (width ) *width = w; + if (height) *height = h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + // invert for y-downwards bitmaps + scale_y = -scale_y; + + { + int x,y,i,j; + float *precompute; + stbtt_vertex *verts; + int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); + data = (unsigned char *) STBTT_malloc(w * h, info->userdata); + precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); + + for (i=0,j=num_verts-1; i < num_verts; j=i++) { + if (verts[i].type == STBTT_vline) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; + float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); + precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; + float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; + float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float len2 = bx*bx + by*by; + if (len2 != 0.0f) + precompute[i] = 1.0f / (bx*bx + by*by); + else + precompute[i] = 0.0f; + } else + precompute[i] = 0.0f; + } + + for (y=iy0; y < iy1; ++y) { + for (x=ix0; x < ix1; ++x) { + float val; + float min_dist = 999999.0f; + float sx = (float) x + 0.5f; + float sy = (float) y + 0.5f; + float x_gspace = (sx / scale_x); + float y_gspace = (sy / scale_y); + + int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path + + for (i=0; i < num_verts; ++i) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + + // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve + float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + if (verts[i].type == STBTT_vline) { + float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; + + // coarse culling against bbox + //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && + // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) + float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; + STBTT_assert(i != 0); + if (dist < min_dist) { + // check position along line + // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) + // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) + float dx = x1-x0, dy = y1-y0; + float px = x0-sx, py = y0-sy; + // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy + // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve + float t = -(px*dx + py*dy) / (dx*dx + dy*dy); + if (t >= 0.0f && t <= 1.0f) + min_dist = dist; + } + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; + float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; + float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); + float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); + float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); + float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); + // coarse culling against bbox to avoid computing cubic unnecessarily + if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { + int num=0; + float ax = x1-x0, ay = y1-y0; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float mx = x0 - sx, my = y0 - sy; + float res[3],px,py,t,it; + float a_inv = precompute[i]; + if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula + float a = 3*(ax*bx + ay*by); + float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); + float c = mx*ax+my*ay; + if (a == 0.0) { // if a is 0, it's linear + if (b != 0.0) { + res[num++] = -c/b; + } + } else { + float discriminant = b*b - 4*a*c; + if (discriminant < 0) + num = 0; + else { + float root = (float) STBTT_sqrt(discriminant); + res[0] = (-b - root)/(2*a); + res[1] = (-b + root)/(2*a); + num = 2; // don't bother distinguishing 1-solution case, as code below will still work + } + } + } else { + float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point + float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; + float d = (mx*ax+my*ay) * a_inv; + num = stbtt__solve_cubic(b, c, d, res); + } + if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { + t = res[0], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { + t = res[1], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { + t = res[2], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + } + } + } + if (winding == 0) + min_dist = -min_dist; // if outside the shape, value is negative + val = onedge_value + pixel_dist_scale * min_dist; + if (val < 0) + val = 0; + else if (val > 255) + val = 255; + data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; + } + } + STBTT_free(precompute, info->userdata); + STBTT_free(verts, info->userdata); + } + return data; +} + +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +////////////////////////////////////////////////////////////////////////////// +// +// font name matching -- recommended not to use this +// + +// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string +static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) +{ + stbtt_int32 i=0; + + // convert utf16 to utf8 and compare the results while converting + while (len2) { + stbtt_uint16 ch = s2[0]*256 + s2[1]; + if (ch < 0x80) { + if (i >= len1) return -1; + if (s1[i++] != ch) return -1; + } else if (ch < 0x800) { + if (i+1 >= len1) return -1; + if (s1[i++] != 0xc0 + (ch >> 6)) return -1; + if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; + } else if (ch >= 0xd800 && ch < 0xdc00) { + stbtt_uint32 c; + stbtt_uint16 ch2 = s2[2]*256 + s2[3]; + if (i+3 >= len1) return -1; + c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; + if (s1[i++] != 0xf0 + (c >> 18)) return -1; + if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; + s2 += 2; // plus another 2 below + len2 -= 2; + } else if (ch >= 0xdc00 && ch < 0xe000) { + return -1; + } else { + if (i+2 >= len1) return -1; + if (s1[i++] != 0xe0 + (ch >> 12)) return -1; + if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; + } + s2 += 2; + len2 -= 2; + } + return i; +} + +static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) +{ + return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); +} + +// returns results in whatever encoding you request... but note that 2-byte encodings +// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) +{ + stbtt_int32 i,count,stringOffset; + stbtt_uint8 *fc = font->data; + stbtt_uint32 offset = font->fontstart; + stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return NULL; + + count = ttUSHORT(fc+nm+2); + stringOffset = nm + ttUSHORT(fc+nm+4); + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) + && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { + *length = ttUSHORT(fc+loc+8); + return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); + } + } + return NULL; +} + +static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) +{ + stbtt_int32 i; + stbtt_int32 count = ttUSHORT(fc+nm+2); + stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); + + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + stbtt_int32 id = ttUSHORT(fc+loc+6); + if (id == target_id) { + // find the encoding + stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); + + // is this a Unicode encoding? + if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { + stbtt_int32 slen = ttUSHORT(fc+loc+8); + stbtt_int32 off = ttUSHORT(fc+loc+10); + + // check if there's a prefix match + stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); + if (matchlen >= 0) { + // check for target_id+1 immediately following, with same encoding & language + if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { + slen = ttUSHORT(fc+loc+12+8); + off = ttUSHORT(fc+loc+12+10); + if (slen == 0) { + if (matchlen == nlen) + return 1; + } else if (matchlen < nlen && name[matchlen] == ' ') { + ++matchlen; + if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) + return 1; + } + } else { + // if nothing immediately following + if (matchlen == nlen) + return 1; + } + } + } + + // @TODO handle other encodings + } + } + return 0; +} + +static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) +{ + stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); + stbtt_uint32 nm,hd; + if (!stbtt__isfont(fc+offset)) return 0; + + // check italics/bold/underline flags in macStyle... + if (flags) { + hd = stbtt__find_table(fc, offset, "head"); + if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; + } + + nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return 0; + + if (flags) { + // if we checked the macStyle flags, then just check the family and ignore the subfamily + if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } else { + if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } + + return 0; +} + +static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) +{ + stbtt_int32 i; + for (i=0;;++i) { + stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); + if (off < 0) return off; + if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) + return off; + } +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, + float pixel_height, unsigned char *pixels, int pw, int ph, + int first_char, int num_chars, stbtt_bakedchar *chardata) +{ + return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); +} + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) +{ + return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); +} + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) +{ + return stbtt_GetNumberOfFonts_internal((unsigned char *) data); +} + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) +{ + return stbtt_InitFont_internal(info, (unsigned char *) data, offset); +} + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) +{ + return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); +} + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) +{ + return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#endif // STB_TRUETYPE_IMPLEMENTATION + + +// FULL VERSION HISTORY +// +// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) allow user-defined fabs() replacement +// fix memory leak if fontsize=0.0 +// fix warning from duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// allow PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) +// also more precise AA rasterizer, except if shapes overlap +// remove need for STBTT_sort +// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC +// 1.04 (2015-04-15) typo in example +// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes +// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ +// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match +// non-oversampled; STBTT_POINT_SIZE for packed case only +// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling +// 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) +// 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID +// 0.8b (2014-07-07) fix a warning +// 0.8 (2014-05-25) fix a few more warnings +// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back +// 0.6c (2012-07-24) improve documentation +// 0.6b (2012-07-20) fix a few more warnings +// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, +// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty +// 0.5 (2011-12-09) bugfixes: +// subpixel glyph renderer computed wrong bounding box +// first vertex of shape can be off-curve (FreeSans) +// 0.4b (2011-12-03) fixed an error in the font baking example +// 0.4 (2011-12-01) kerning, subpixel rendering (tor) +// bugfixes for: +// codepoint-to-glyph conversion using table fmt=12 +// codepoint-to-glyph conversion using table fmt=4 +// stbtt_GetBakedQuad with non-square texture (Zer) +// updated Hello World! sample to use kerning and subpixel +// fixed some warnings +// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) +// userdata, malloc-from-userdata, non-zero fill (stb) +// 0.2 (2009-03-11) Fix unsigned/signed char warnings +// 0.1 (2009-03-09) First public release +// + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/tinyexr/tinyexr.h b/Extern/3rdParty/OptiX/Linux/SDK/support/tinyexr/tinyexr.h new file mode 100644 index 00000000..20adfeff --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/tinyexr/tinyexr.h @@ -0,0 +1,13315 @@ +/* +Copyright (c) 2014 - 2019, Syoyo Fujita and many contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Syoyo Fujita nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// TinyEXR contains some OpenEXR code, which is licensed under ------------ + +/////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas +// Digital Ltd. LLC +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Industrial Light & Magic nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////// + +// End of OpenEXR license ------------------------------------------------- + +#ifndef TINYEXR_H_ +#define TINYEXR_H_ + +// +// +// Do this: +// #define TINYEXR_IMPLEMENTATION +// before you include this file in *one* C or C++ file to create the +// implementation. +// +// // i.e. it should look like this: +// #include ... +// #include ... +// #include ... +// #define TINYEXR_IMPLEMENTATION +// #include "tinyexr.h" +// +// + +#include // for size_t +#include // guess stdint.h is available(C99) + +#ifdef __cplusplus +extern "C" { +#endif + +// Use embedded miniz or not to decode ZIP format pixel. Linking with zlib +// required if this flas is 0. +#ifndef TINYEXR_USE_MINIZ +#define TINYEXR_USE_MINIZ (1) +#endif + +// Disable PIZ comporession when applying cpplint. +#ifndef TINYEXR_USE_PIZ +#define TINYEXR_USE_PIZ (1) +#endif + +#ifndef TINYEXR_USE_ZFP +#define TINYEXR_USE_ZFP (0) // TinyEXR extension. +// http://computation.llnl.gov/projects/floating-point-compression +#endif + +#define TINYEXR_SUCCESS (0) +#define TINYEXR_ERROR_INVALID_MAGIC_NUMBER (-1) +#define TINYEXR_ERROR_INVALID_EXR_VERSION (-2) +#define TINYEXR_ERROR_INVALID_ARGUMENT (-3) +#define TINYEXR_ERROR_INVALID_DATA (-4) +#define TINYEXR_ERROR_INVALID_FILE (-5) +#define TINYEXR_ERROR_INVALID_PARAMETER (-6) +#define TINYEXR_ERROR_CANT_OPEN_FILE (-7) +#define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-8) +#define TINYEXR_ERROR_INVALID_HEADER (-9) +#define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-10) +#define TINYEXR_ERROR_CANT_WRITE_FILE (-11) +#define TINYEXR_ERROR_SERIALZATION_FAILED (-12) + +// @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf } + +// pixel type: possible values are: UINT = 0 HALF = 1 FLOAT = 2 +#define TINYEXR_PIXELTYPE_UINT (0) +#define TINYEXR_PIXELTYPE_HALF (1) +#define TINYEXR_PIXELTYPE_FLOAT (2) + +#define TINYEXR_MAX_HEADER_ATTRIBUTES (1024) +#define TINYEXR_MAX_CUSTOM_ATTRIBUTES (128) + +#define TINYEXR_COMPRESSIONTYPE_NONE (0) +#define TINYEXR_COMPRESSIONTYPE_RLE (1) +#define TINYEXR_COMPRESSIONTYPE_ZIPS (2) +#define TINYEXR_COMPRESSIONTYPE_ZIP (3) +#define TINYEXR_COMPRESSIONTYPE_PIZ (4) +#define TINYEXR_COMPRESSIONTYPE_ZFP (128) // TinyEXR extension + +#define TINYEXR_ZFP_COMPRESSIONTYPE_RATE (0) +#define TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION (1) +#define TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY (2) + +#define TINYEXR_TILE_ONE_LEVEL (0) +#define TINYEXR_TILE_MIPMAP_LEVELS (1) +#define TINYEXR_TILE_RIPMAP_LEVELS (2) + +#define TINYEXR_TILE_ROUND_DOWN (0) +#define TINYEXR_TILE_ROUND_UP (1) + +typedef struct _EXRVersion { + int version; // this must be 2 + int tiled; // tile format image + int long_name; // long name attribute + int non_image; // deep image(EXR 2.0) + int multipart; // multi-part(EXR 2.0) +} EXRVersion; + +typedef struct _EXRAttribute { + char name[256]; // name and type are up to 255 chars long. + char type[256]; + unsigned char *value; // uint8_t* + int size; + int pad0; +} EXRAttribute; + +typedef struct _EXRChannelInfo { + char name[256]; // less than 255 bytes long + int pixel_type; + int x_sampling; + int y_sampling; + unsigned char p_linear; + unsigned char pad[3]; +} EXRChannelInfo; + +typedef struct _EXRTile { + int offset_x; + int offset_y; + int level_x; + int level_y; + + int width; // actual width in a tile. + int height; // actual height int a tile. + + unsigned char **images; // image[channels][pixels] +} EXRTile; + +typedef struct _EXRHeader { + float pixel_aspect_ratio; + int line_order; + int data_window[4]; + int display_window[4]; + float screen_window_center[2]; + float screen_window_width; + + int chunk_count; + + // Properties for tiled format(`tiledesc`). + int tiled; + int tile_size_x; + int tile_size_y; + int tile_level_mode; + int tile_rounding_mode; + + int long_name; + int non_image; + int multipart; + unsigned int header_len; + + // Custom attributes(exludes required attributes(e.g. `channels`, + // `compression`, etc) + int num_custom_attributes; + EXRAttribute *custom_attributes; // array of EXRAttribute. size = + // `num_custom_attributes`. + + EXRChannelInfo *channels; // [num_channels] + + int *pixel_types; // Loaded pixel type(TINYEXR_PIXELTYPE_*) of `images` for + // each channel. This is overwritten with `requested_pixel_types` when + // loading. + int num_channels; + + int compression_type; // compression type(TINYEXR_COMPRESSIONTYPE_*) + int *requested_pixel_types; // Filled initially by + // ParseEXRHeaderFrom(Meomory|File), then users + // can edit it(only valid for HALF pixel type + // channel) + +} EXRHeader; + +typedef struct _EXRMultiPartHeader { + int num_headers; + EXRHeader *headers; + +} EXRMultiPartHeader; + +typedef struct _EXRImage { + EXRTile *tiles; // Tiled pixel data. The application must reconstruct image + // from tiles manually. NULL if scanline format. + unsigned char **images; // image[channels][pixels]. NULL if tiled format. + + int width; + int height; + int num_channels; + + // Properties for tile format. + int num_tiles; + +} EXRImage; + +typedef struct _EXRMultiPartImage { + int num_images; + EXRImage *images; + +} EXRMultiPartImage; + +typedef struct _DeepImage { + const char **channel_names; + float ***image; // image[channels][scanlines][samples] + int **offset_table; // offset_table[scanline][offsets] + int num_channels; + int width; + int height; + int pad0; +} DeepImage; + +// @deprecated { to be removed. } +// Loads single-frame OpenEXR image. Assume EXR image contains A(single channel +// alpha) or RGB(A) channels. +// Application must free image data as returned by `out_rgba` +// Result image format is: float x RGBA x width x hight +// Returns negative value and may set error string in `err` when there's an +// error +extern int LoadEXR(float **out_rgba, int *width, int *height, + const char *filename, const char **err); + +// @deprecated { to be removed. } +// Simple wrapper API for ParseEXRHeaderFromFile. +// checking given file is a EXR file(by just look up header) +// @return TINYEXR_SUCCEES for EXR image, TINYEXR_ERROR_INVALID_HEADER for +// others +extern int IsEXR(const char *filename); + +// @deprecated { to be removed. } +// Saves single-frame OpenEXR image. Assume EXR image contains RGB(A) channels. +// components must be 1(Grayscale), 3(RGB) or 4(RGBA). +// Input image format is: `float x width x height`, or `float x RGB(A) x width x +// hight` +// Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero +// value. +// Save image as fp32(FLOAT) format when `save_as_fp16` is 0. +// Use ZIP compression by default. +// Returns negative value and may set error string in `err` when there's an +// error +extern int SaveEXR(const float *data, const int width, const int height, + const int components, const int save_as_fp16, + const char *filename, const char **err); + +// Initialize EXRHeader struct +extern void InitEXRHeader(EXRHeader *exr_header); + +// Initialize EXRImage struct +extern void InitEXRImage(EXRImage *exr_image); + +// Free's internal data of EXRHeader struct +extern int FreeEXRHeader(EXRHeader *exr_header); + +// Free's internal data of EXRImage struct +extern int FreeEXRImage(EXRImage *exr_image); + +// Free's error message +extern void FreeEXRErrorMessage(const char *msg); + +// Parse EXR version header of a file. +extern int ParseEXRVersionFromFile(EXRVersion *version, const char *filename); + +// Parse EXR version header from memory-mapped EXR data. +extern int ParseEXRVersionFromMemory(EXRVersion *version, + const unsigned char *memory, size_t size); + +// Parse single-part OpenEXR header from a file and initialize `EXRHeader`. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int ParseEXRHeaderFromFile(EXRHeader *header, const EXRVersion *version, + const char *filename, const char **err); + +// Parse single-part OpenEXR header from a memory and initialize `EXRHeader`. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int ParseEXRHeaderFromMemory(EXRHeader *header, + const EXRVersion *version, + const unsigned char *memory, size_t size, + const char **err); + +// Parse multi-part OpenEXR headers from a file and initialize `EXRHeader*` +// array. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers, + int *num_headers, + const EXRVersion *version, + const char *filename, + const char **err); + +// Parse multi-part OpenEXR headers from a memory and initialize `EXRHeader*` +// array +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers, + int *num_headers, + const EXRVersion *version, + const unsigned char *memory, + size_t size, const char **err); + +// Loads single-part OpenEXR image from a file. +// Application must setup `ParseEXRHeaderFromFile` before calling this function. +// Application can free EXRImage using `FreeEXRImage` +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header, + const char *filename, const char **err); + +// Loads single-part OpenEXR image from a memory. +// Application must setup `EXRHeader` with +// `ParseEXRHeaderFromMemory` before calling this function. +// Application can free EXRImage using `FreeEXRImage` +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header, + const unsigned char *memory, + const size_t size, const char **err); + +// Loads multi-part OpenEXR image from a file. +// Application must setup `ParseEXRMultipartHeaderFromFile` before calling this +// function. +// Application can free EXRImage using `FreeEXRImage` +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRMultipartImageFromFile(EXRImage *images, + const EXRHeader **headers, + unsigned int num_parts, + const char *filename, + const char **err); + +// Loads multi-part OpenEXR image from a memory. +// Application must setup `EXRHeader*` array with +// `ParseEXRMultipartHeaderFromMemory` before calling this function. +// Application can free EXRImage using `FreeEXRImage` +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRMultipartImageFromMemory(EXRImage *images, + const EXRHeader **headers, + unsigned int num_parts, + const unsigned char *memory, + const size_t size, const char **err); + +// Saves multi-channel, single-frame OpenEXR image to a file. +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int SaveEXRImageToFile(const EXRImage *image, + const EXRHeader *exr_header, const char *filename, + const char **err); + +// Saves multi-channel, single-frame OpenEXR image to a memory. +// Image is compressed using EXRImage.compression value. +// Return the number of bytes if success. +// Return zero and will set error string in `err` when there's an +// error. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern size_t SaveEXRImageToMemory(const EXRImage *image, + const EXRHeader *exr_header, + unsigned char **memory, const char **err); + +// Loads single-frame OpenEXR deep image. +// Application must free memory of variables in DeepImage(image, offset_table) +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadDeepEXR(DeepImage *out_image, const char *filename, + const char **err); + +// NOT YET IMPLEMENTED: +// Saves single-frame OpenEXR deep image. +// Returns negative value and may set error string in `err` when there's an +// error +// extern int SaveDeepEXR(const DeepImage *in_image, const char *filename, +// const char **err); + +// NOT YET IMPLEMENTED: +// Loads multi-part OpenEXR deep image. +// Application must free memory of variables in DeepImage(image, offset_table) +// extern int LoadMultiPartDeepEXR(DeepImage **out_image, int num_parts, const +// char *filename, +// const char **err); + +// For emscripten. +// Loads single-frame OpenEXR image from memory. Assume EXR image contains +// RGB(A) channels. +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height, + const unsigned char *memory, size_t size, + const char **err); + +#ifdef __cplusplus +} +#endif + +#endif // TINYEXR_H_ + +#ifdef TINYEXR_IMPLEMENTATION +#ifndef TINYEXR_IMPLEMENTATION_DEIFNED +#define TINYEXR_IMPLEMENTATION_DEIFNED + +#include +#include +#include +#include +#include +#include + +//#include // debug + +#include +#include +#include + +#if __cplusplus > 199711L +// C++11 +#include +#endif // __cplusplus > 199711L + +#ifdef _OPENMP +#include +#endif + +#if TINYEXR_USE_MINIZ +#else +// Issue #46. Please include your own zlib-compatible API header before +// including `tinyexr.h` +//#include "zlib.h" +#endif + +#if TINYEXR_USE_ZFP +#include "zfp.h" +#endif + +namespace tinyexr { + +#if __cplusplus > 199711L +// C++11 +typedef uint64_t tinyexr_uint64; +typedef int64_t tinyexr_int64; +#else +// Although `long long` is not a standard type pre C++11, assume it is defined +// as a compiler's extension. +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif +typedef unsigned long long tinyexr_uint64; +typedef long long tinyexr_int64; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#endif + +#if TINYEXR_USE_MINIZ + +namespace miniz { + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wc++11-extensions" +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#pragma clang diagnostic ignored "-Wundef" + +#if __has_warning("-Wcomma") +#pragma clang diagnostic ignored "-Wcomma" +#endif + +#if __has_warning("-Wmacro-redefined") +#pragma clang diagnostic ignored "-Wmacro-redefined" +#endif + +#if __has_warning("-Wcast-qual") +#pragma clang diagnostic ignored "-Wcast-qual" +#endif + +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#if __has_warning("-Wtautological-constant-compare") +#pragma clang diagnostic ignored "-Wtautological-constant-compare" +#endif + +#endif + +/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP + reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated Oct. 13, 2013 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: + http://www.ietf.org/rfc/rfc1951.txt + + Most API's defined in miniz.c are optional. For example, to disable the + archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO + (see the list below for more macros). + + * Change History + 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major + release with Zip64 support (almost there!): + - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug + (thanks kahmyong.moon@hp.com) which could cause locate files to not find + files. This bug + would only have occured in earlier versions if you explicitly used this + flag, OR if you used mz_zip_extract_archive_file_to_heap() or + mz_zip_add_mem_to_archive_file_in_place() + (which used this flag). If you can't switch to v1.15 but want to fix + this bug, just remove the uses of this flag from both helper funcs (and of + course don't use the flag). + - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when + pUser_read_buf is not NULL and compressed size is > uncompressed size + - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract + compressed data from directory entries, to account for weird zipfiles which + contain zero-size compressed data on dir entries. + Hopefully this fix won't cause any issues on weird zip archives, + because it assumes the low 16-bits of zip external attributes are DOS + attributes (which I believe they always are in practice). + - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the + internal attributes, just the filename and external attributes + - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed + - Added cmake support for Linux builds which builds all the examples, + tested with clang v3.3 and gcc v4.6. + - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti + - Merged MZ_FORCEINLINE fix from hdeanclark + - Fix include before config #ifdef, thanks emil.brink + - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping + (super useful for OpenGL apps), and explicit control over the compression + level (so you can + set it to 1 for real-time compression). + - Merged in some compiler fixes from paulharris's github repro. + - Retested this build under Windows (VS 2010, including static analysis), + tcc 0.9.26, gcc v4.6 and clang v3.3. + - Added example6.c, which dumps an image of the mandelbrot set to a PNG + file. + - Modified example2 to help test the + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more. + - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix + possible src file fclose() leak if alignment bytes+local header file write + faiiled + - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): + Was pushing the wrong central dir header offset, appears harmless in this + release, but it became a problem in the zip64 branch + 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, + #include (thanks fermtect). + 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix + mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. + - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and + re-ran a randomized regression test on ~500k files. + - Eliminated a bunch of warnings when compiling with GCC 32-bit/64. + - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze + (static analysis) option and fixed all warnings (except for the silly + "Use of the comma-operator in a tested expression.." analysis warning, + which I purposely use to work around a MSVC compiler warning). + - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and + tested Linux executables. The codeblocks workspace is compatible with + Linux+Win32/x64. + - Added miniz_tester solution/project, which is a useful little app + derived from LZHAM's tester app that I use as part of the regression test. + - Ran miniz.c and tinfl.c through another series of regression testing on + ~500,000 files and archives. + - Modified example5.c so it purposely disables a bunch of high-level + functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the + MINIZ_NO_STDIO bug report.) + - Fix ftell() usage in examples so they exit with an error on files which + are too large (a limitation of the examples, not miniz itself). + 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple + minor level_and_flags issues in the archive API's. + level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce + Dawson for the feedback/bug report. + 5/28/11 v1.11 - Added statement from unlicense.org + 5/27/11 v1.10 - Substantial compressor optimizations: + - Level 1 is now ~4x faster than before. The L1 compressor's throughput + now varies between 70-110MB/sec. on a + - Core i7 (actual throughput varies depending on the type of data, and x64 + vs. x86). + - Improved baseline L2-L9 compression perf. Also, greatly improved + compression perf. issues on some file types. + - Refactored the compression code for better readability and + maintainability. + - Added level 10 compression level (L10 has slightly better ratio than + level 9, but could have a potentially large + drop in throughput on some files). + 5/15/11 v1.09 - Initial stable release. + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, + and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. + It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is + implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB + (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory + allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough + functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly + routines. + Supports raw deflate streams or standard zlib streams with adler-32 + checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or + zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing + and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, + originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * ZIP archive API notes: + + The ZIP archive API's where designed with simplicity and efficiency in + mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file + information, read files from + existing archives, create new archives, append new files to existing + archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, + on disk (using stdio.h), + or you can specify custom file read/write callbacks. + + - Archive reading: Just call this function to read a single file from a + disk archive: + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const + char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + + For more complex cases, use the "mz_zip_reader" functions. Upon opening an + archive, the entire central + directory is located and read as-is into memory, and subsequent file access + only occurs when reading individual files. + + - Archives file scanning: The simple way is to use this function to scan a + loaded archive for a specific file: + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, + const char *pComment, mz_uint flags); + + The locate operation can optionally check file comments too, which (as one + example) can be used to identify + multiple versions of the same file in an archive. This function uses a + simple linear search through the central + directory, so it's not very fast. + + Alternately, you can iterate through all the files in an archive (using + mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer + immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The + central directory image is written + all at once at the end of the archive file when the archive is finalized. + + The archive writer can optionally align each file's local header and file + data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, + the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives + written using either feature are still + readable by any ZIP tool. + + - Archive appending: The simple way to add a single file to an archive is + to call this function: + + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, + const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 + comment_size, mz_uint level_and_flags); + + The archive will be created if it doesn't already exist, otherwise it'll be + appended to. + Note the appending is done in-place and is not an atomic operation, so if + something goes wrong + during the operation it's possible the archive could be left without a + central directory (although the local + file headers and file data will be fine, so the archive will be + recoverable). + + For more complex archive modification scenarios: + 1. The safest way is to use a mz_zip_reader to read the existing archive, + cloning only those bits you want to + preserve into a new archive using using the + mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and + rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or + heap memory. + + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using + mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an + updated central directory to the + original archive. (This is basically what + mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this + method if anything goes wrong, though. + + - ZIP archive support limitations: + No zip64 or spanning support. Extraction functions can only handle + unencrypted, stored or deflated files. + Requires streams capable of seeking. + + * This is a header file library, like stb_image.c. To get only a header file, + either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then + include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your + target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 + + * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before + including miniz.c to ensure miniz + uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be + able to process large files + (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). +*/ + +#ifndef MINIZ_HEADER_INCLUDED +#define MINIZ_HEADER_INCLUDED + +//#include + +// Defines to completely disable specific portions of miniz.c: +// If all macros here are defined the only functionality remaining will be +// CRC-32, adler-32, tinfl, and tdefl. + +// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on +// stdio for file I/O. +//#define MINIZ_NO_STDIO + +// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able +// to get the current time, or +// get/set file times, and the C run-time funcs that get/set times won't be +// called. +// The current downside is the times written to your archives will be from 1979. +#define MINIZ_NO_TIME + +// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. +#define MINIZ_NO_ARCHIVE_APIS + +// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive +// API's. +//#define MINIZ_NO_ARCHIVE_WRITING_APIS + +// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression +// API's. +//#define MINIZ_NO_ZLIB_APIS + +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent +// conflicts against stock zlib. +//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. +// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom +// user alloc/free/realloc +// callbacks to the zlib and archive API's, and a few stand-alone helper API's +// which don't provide custom user +// functions (such as tdefl_compress_mem_to_heap() and +// tinfl_decompress_mem_to_heap()) won't work. +//#define MINIZ_NO_MALLOC + +#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) +// TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc +// on Linux +#define MINIZ_NO_TIME +#endif + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) +//#include +#endif + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \ + defined(__i386) || defined(__i486__) || defined(__i486) || \ + defined(i386) || defined(__ia64__) || defined(__x86_64__) +// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. +#define MINIZ_X86_OR_X64_CPU 1 +#endif + +#if defined(__sparcv9) +// Big endian +#else +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#endif +#endif + +#if MINIZ_X86_OR_X64_CPU +// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient +// integer loads and stores from unaligned addresses. +//#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES \ + 0 // disable to suppress compiler warnings +#endif + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || \ + defined(_LP64) || defined(__LP64__) || defined(__ia64__) || \ + defined(__x86_64__) +// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are +// reasonably fast (and don't involve compiler generated calls to helper +// functions). +#define MINIZ_HAS_64BIT_REGISTERS 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ------------------- zlib-style API Definitions. + +// For more compatibility with zlib, miniz.c uses unsigned long for some +// parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! +typedef unsigned long mz_ulong; + +// mz_free() internally uses the MZ_FREE() macro (which by default calls free() +// unless you've modified the MZ_MALLOC macro) to release a block allocated from +// the heap. +void mz_free(void *p); + +#define MZ_ADLER32_INIT (1) +// mz_adler32() returns the initial adler-32 value to use when called with +// ptr==NULL. +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) +// mz_crc32() returns the initial CRC-32 value to use when called with +// ptr==NULL. +mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + +// Compression strategies. +enum { + MZ_DEFAULT_STRATEGY = 0, + MZ_FILTERED = 1, + MZ_HUFFMAN_ONLY = 2, + MZ_RLE = 3, + MZ_FIXED = 4 +}; + +// Method +#define MZ_DEFLATED 8 + +#ifndef MINIZ_NO_ZLIB_APIS + +// Heap allocation callbacks. +// Note that mz_alloc_func parameter types purpsosely differ from zlib's: +// items/size is size_t, not unsigned long. +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, + size_t size); + +#define MZ_VERSION "9.1.15" +#define MZ_VERNUM 0x91F0 +#define MZ_VER_MAJOR 9 +#define MZ_VER_MINOR 1 +#define MZ_VER_REVISION 15 +#define MZ_VER_SUBREVISION 0 + +// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The +// other values are for advanced use (refer to the zlib docs). +enum { + MZ_NO_FLUSH = 0, + MZ_PARTIAL_FLUSH = 1, + MZ_SYNC_FLUSH = 2, + MZ_FULL_FLUSH = 3, + MZ_FINISH = 4, + MZ_BLOCK = 5 +}; + +// Return status codes. MZ_PARAM_ERROR is non-standard. +enum { + MZ_OK = 0, + MZ_STREAM_END = 1, + MZ_NEED_DICT = 2, + MZ_ERRNO = -1, + MZ_STREAM_ERROR = -2, + MZ_DATA_ERROR = -3, + MZ_MEM_ERROR = -4, + MZ_BUF_ERROR = -5, + MZ_VERSION_ERROR = -6, + MZ_PARAM_ERROR = -10000 +}; + +// Compression levels: 0-9 are the standard zlib-style levels, 10 is best +// possible compression (not zlib compatible, and may be very slow), +// MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. +enum { + MZ_NO_COMPRESSION = 0, + MZ_BEST_SPEED = 1, + MZ_BEST_COMPRESSION = 9, + MZ_UBER_COMPRESSION = 10, + MZ_DEFAULT_LEVEL = 6, + MZ_DEFAULT_COMPRESSION = -1 +}; + +// Window bits +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +// Compression/decompression stream struct. +typedef struct mz_stream_s { + const unsigned char *next_in; // pointer to next byte to read + unsigned int avail_in; // number of bytes available at next_in + mz_ulong total_in; // total number of bytes consumed so far + + unsigned char *next_out; // pointer to next byte to write + unsigned int avail_out; // number of bytes that can be written to next_out + mz_ulong total_out; // total number of bytes produced so far + + char *msg; // error msg (unused) + struct mz_internal_state *state; // internal state, allocated by zalloc/zfree + + mz_alloc_func + zalloc; // optional heap allocation function (defaults to malloc) + mz_free_func zfree; // optional heap free function (defaults to free) + void *opaque; // heap alloc function user pointer + + int data_type; // data_type (unused) + mz_ulong adler; // adler32 of the source or uncompressed data + mz_ulong reserved; // not used +} mz_stream; + +typedef mz_stream *mz_streamp; + +// Returns the version string of miniz.c. +const char *mz_version(void); + +// mz_deflateInit() initializes a compressor with default options: +// Parameters: +// pStream must point to an initialized mz_stream struct. +// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. +// level 1 enables a specially optimized compression function that's been +// optimized purely for performance, not ratio. +// (This special func. is currently only enabled when +// MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if the input parameters are bogus. +// MZ_MEM_ERROR on out of memory. +int mz_deflateInit(mz_streamp pStream, int level); + +// mz_deflateInit2() is like mz_deflate(), except with more control: +// Additional parameters: +// method must be MZ_DEFLATED +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with +// zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no +// header or footer) +// mem_level must be between [1, 9] (it's checked but ignored by miniz.c) +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, + int mem_level, int strategy); + +// Quickly resets a compressor without having to reallocate anything. Same as +// calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). +int mz_deflateReset(mz_streamp pStream); + +// mz_deflate() compresses the input to output, consuming as much of the input +// and producing as much output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update +// the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or +// MZ_FINISH. +// Return values: +// MZ_OK on success (when flushing, or if more input is needed but not +// available, and/or there's more output to be written but the output buffer +// is full). +// MZ_STREAM_END if all input has been consumed and all output bytes have been +// written. Don't call mz_deflate() on the stream anymore. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input and/or +// output buffers are empty. (Fill up the input buffer or free up some output +// space and try again.) +int mz_deflate(mz_streamp pStream, int flush); + +// mz_deflateEnd() deinitializes a compressor: +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +int mz_deflateEnd(mz_streamp pStream); + +// mz_deflateBound() returns a (very) conservative upper bound on the amount of +// data that could be generated by deflate(), assuming flush is set to only +// MZ_NO_FLUSH or MZ_FINISH. +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + +// Single-call compression functions mz_compress() and mz_compress2(): +// Returns MZ_OK on success, or one of the error codes from mz_deflate() on +// failure. +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len); +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len, int level); + +// mz_compressBound() returns a (very) conservative upper bound on the amount of +// data that could be generated by calling mz_compress(). +mz_ulong mz_compressBound(mz_ulong source_len); + +// Initializes a decompressor. +int mz_inflateInit(mz_streamp pStream); + +// mz_inflateInit2() is like mz_inflateInit() with an additional option that +// controls the window size and whether or not the stream has been wrapped with +// a zlib header/footer: +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or +// -MZ_DEFAULT_WINDOW_BITS (raw deflate). +int mz_inflateInit2(mz_streamp pStream, int window_bits); + +// Decompresses the input stream to the output, consuming only as much of the +// input as needed, and writing as much to the output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update +// the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. +// On the first call, if flush is MZ_FINISH it's assumed the input and output +// buffers are both sized large enough to decompress the entire stream in a +// single call (this is slightly faster). +// MZ_FINISH implies that there are no more source bytes available beside +// what's already in the input buffer, and that the output buffer is large +// enough to hold the rest of the decompressed data. +// Return values: +// MZ_OK on success. Either more input is needed but not available, and/or +// there's more output to be written but the output buffer is full. +// MZ_STREAM_END if all needed input has been consumed and all output bytes +// have been written. For zlib streams, the adler-32 of the decompressed data +// has also been verified. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_DATA_ERROR if the deflate stream is invalid. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input buffer is +// empty but the inflater needs more input to continue, or if the output +// buffer is not large enough. Call mz_inflate() again +// with more input data, or with more room in the output buffer (except when +// using single call decompression, described above). +int mz_inflate(mz_streamp pStream, int flush); + +// Deinitializes a decompressor. +int mz_inflateEnd(mz_streamp pStream); + +// Single-call decompression. +// Returns MZ_OK on success, or one of the error codes from mz_inflate() on +// failure. +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len); + +// Returns a string description of the specified error code, or NULL if the +// error code is invalid. +const char *mz_error(int err); + +// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used +// as a drop-in replacement for the subset of zlib that miniz.c supports. +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you +// use zlib in the same project. +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES +typedef unsigned char Byte; +typedef unsigned int uInt; +typedef mz_ulong uLong; +typedef Byte Bytef; +typedef uInt uIntf; +typedef char charf; +typedef int intf; +typedef void *voidpf; +typedef uLong uLongf; +typedef void *voidp; +typedef void *const voidpc; +#define Z_NULL 0 +#define Z_NO_FLUSH MZ_NO_FLUSH +#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH +#define Z_SYNC_FLUSH MZ_SYNC_FLUSH +#define Z_FULL_FLUSH MZ_FULL_FLUSH +#define Z_FINISH MZ_FINISH +#define Z_BLOCK MZ_BLOCK +#define Z_OK MZ_OK +#define Z_STREAM_END MZ_STREAM_END +#define Z_NEED_DICT MZ_NEED_DICT +#define Z_ERRNO MZ_ERRNO +#define Z_STREAM_ERROR MZ_STREAM_ERROR +#define Z_DATA_ERROR MZ_DATA_ERROR +#define Z_MEM_ERROR MZ_MEM_ERROR +#define Z_BUF_ERROR MZ_BUF_ERROR +#define Z_VERSION_ERROR MZ_VERSION_ERROR +#define Z_PARAM_ERROR MZ_PARAM_ERROR +#define Z_NO_COMPRESSION MZ_NO_COMPRESSION +#define Z_BEST_SPEED MZ_BEST_SPEED +#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION +#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION +#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY +#define Z_FILTERED MZ_FILTERED +#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY +#define Z_RLE MZ_RLE +#define Z_FIXED MZ_FIXED +#define Z_DEFLATED MZ_DEFLATED +#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS +#define alloc_func mz_alloc_func +#define free_func mz_free_func +#define internal_state mz_internal_state +#define z_stream mz_stream +#define deflateInit mz_deflateInit +#define deflateInit2 mz_deflateInit2 +#define deflateReset mz_deflateReset +#define deflate mz_deflate +#define deflateEnd mz_deflateEnd +#define deflateBound mz_deflateBound +#define compress mz_compress +#define compress2 mz_compress2 +#define compressBound mz_compressBound +#define inflateInit mz_inflateInit +#define inflateInit2 mz_inflateInit2 +#define inflate mz_inflate +#define inflateEnd mz_inflateEnd +#define uncompress mz_uncompress +#define crc32 mz_crc32 +#define adler32 mz_adler32 +#define MAX_WBITS 15 +#define MAX_MEM_LEVEL 9 +#define zError mz_error +#define ZLIB_VERSION MZ_VERSION +#define ZLIB_VERNUM MZ_VERNUM +#define ZLIB_VER_MAJOR MZ_VER_MAJOR +#define ZLIB_VER_MINOR MZ_VER_MINOR +#define ZLIB_VER_REVISION MZ_VER_REVISION +#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +#define zlibVersion mz_version +#define zlib_version mz_version() +#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +#endif // MINIZ_NO_ZLIB_APIS + +// ------------------- Types and macros + +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef long long mz_int64; +typedef unsigned long long mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +// An attempt to work around MSVC's spammy "warning C4127: conditional +// expression is constant" message. +#ifdef _MSC_VER +#define MZ_MACRO_END while (0, 0) +#else +#define MZ_MACRO_END while (0) +#endif + +// ------------------- ZIP archive reading/writing + +#ifndef MINIZ_NO_ARCHIVE_APIS + +enum { + MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, + MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, + MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 +}; + +typedef struct { + mz_uint32 m_file_index; + mz_uint32 m_central_dir_ofs; + mz_uint16 m_version_made_by; + mz_uint16 m_version_needed; + mz_uint16 m_bit_flag; + mz_uint16 m_method; +#ifndef MINIZ_NO_TIME + time_t m_time; +#endif + mz_uint32 m_crc32; + mz_uint64 m_comp_size; + mz_uint64 m_uncomp_size; + mz_uint16 m_internal_attr; + mz_uint32 m_external_attr; + mz_uint64 m_local_header_ofs; + mz_uint32 m_comment_size; + char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; +} mz_zip_archive_file_stat; + +typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, + void *pBuf, size_t n); +typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, + const void *pBuf, size_t n); + +struct mz_zip_internal_state_tag; +typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +typedef enum { + MZ_ZIP_MODE_INVALID = 0, + MZ_ZIP_MODE_READING = 1, + MZ_ZIP_MODE_WRITING = 2, + MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +} mz_zip_mode; + +typedef struct mz_zip_archive_tag { + mz_uint64 m_archive_size; + mz_uint64 m_central_directory_file_ofs; + mz_uint m_total_files; + mz_zip_mode m_zip_mode; + + mz_uint m_file_offset_alignment; + + mz_alloc_func m_pAlloc; + mz_free_func m_pFree; + mz_realloc_func m_pRealloc; + void *m_pAlloc_opaque; + + mz_file_read_func m_pRead; + mz_file_write_func m_pWrite; + void *m_pIO_opaque; + + mz_zip_internal_state *m_pState; + +} mz_zip_archive; + +typedef enum { + MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, + MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, + MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 +} mz_zip_flags; + +// ZIP archive reading + +// Inits a ZIP archive reader. +// These functions read and validate the archive's central directory. +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, + mz_uint32 flags); +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, + size_t size, mz_uint32 flags); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint32 flags); +#endif + +// Returns the total number of files in the archive. +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +// Returns detailed information about an archive file entry. +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, + mz_zip_archive_file_stat *pStat); + +// Determines if an archive file entry is a directory entry. +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, + mz_uint file_index); +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, + mz_uint file_index); + +// Retrieves the filename of an archive file entry. +// Returns the number of bytes written to pFilename, or if filename_buf_size is +// 0 this function returns the number of bytes needed to fully store the +// filename. +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, + char *pFilename, mz_uint filename_buf_size); + +// Attempts to locates a file in the archive's central directory. +// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH +// Returns -1 if the file cannot be found. +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, + const char *pComment, mz_uint flags); + +// Extracts a archive file to a memory buffer using no memory allocation. +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, + mz_uint file_index, void *pBuf, + size_t buf_size, mz_uint flags, + void *pUser_read_buf, + size_t user_read_buf_size); +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc( + mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, + mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + +// Extracts a archive file to a memory buffer. +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, + void *pBuf, size_t buf_size, + mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, + const char *pFilename, void *pBuf, + size_t buf_size, mz_uint flags); + +// Extracts a archive file to a dynamically allocated heap buffer. +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, + size_t *pSize, mz_uint flags); +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, + const char *pFilename, size_t *pSize, + mz_uint flags); + +// Extracts a archive file using a callback function to output the file's data. +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, + mz_uint file_index, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, + const char *pFilename, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +// Extracts a archive file to a disk file and sets its last accessed and +// modified times. +// This function only extracts files, not archive directory records. +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, + const char *pDst_filename, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, + const char *pArchive_filename, + const char *pDst_filename, + mz_uint flags); +#endif + +// Ends archive reading, freeing all allocations, and closing the input archive +// file if mz_zip_reader_init_file() was used. +mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + +// ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +// Inits a ZIP archive writer. +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, + size_t size_to_reserve_at_beginning, + size_t initial_allocation_size); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint64 size_to_reserve_at_beginning); +#endif + +// Converts a ZIP archive reader object into a writer object, to allow efficient +// in-place file appends to occur on an existing archive. +// For archives opened using mz_zip_reader_init_file, pFilename must be the +// archive's filename so it can be reopened for writing. If the file can't be +// reopened, mz_zip_reader_end() will be called. +// For archives opened using mz_zip_reader_init_mem, the memory block must be +// growable using the realloc callback (which defaults to realloc unless you've +// overridden it). +// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's +// user provided m_pWrite function cannot be NULL. +// Note: In-place archive modification is not recommended unless you know what +// you're doing, because if execution stops or something goes wrong before +// the archive is finalized the file's central directory will be hosed. +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, + const char *pFilename); + +// Adds the contents of a memory buffer to an archive. These functions record +// the current local time into the archive. +// To add a directory entry, call this method with an archive name ending in a +// forwardslash with empty buffer. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or +// just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, + const void *pBuf, size_t buf_size, + mz_uint level_and_flags); +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, + const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, + mz_uint16 comment_size, + mz_uint level_and_flags, mz_uint64 uncomp_size, + mz_uint32 uncomp_crc32); + +#ifndef MINIZ_NO_STDIO +// Adds the contents of a disk file to an archive. This function also records +// the disk file's modified time into the archive. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or +// just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, + const char *pSrc_filename, const void *pComment, + mz_uint16 comment_size, mz_uint level_and_flags); +#endif + +// Adds a file to an archive by fully cloning the data from another archive. +// This function fully clones the source file's compressed data (no +// recompression), along with its full filename, extra data, and comment fields. +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, + mz_zip_archive *pSource_zip, + mz_uint file_index); + +// Finalizes the archive by writing the central directory records followed by +// the end of central directory record. +// After an archive is finalized, the only valid call on the mz_zip_archive +// struct is mz_zip_writer_end(). +// An archive must be manually finalized by calling this function for it to be +// valid. +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, + size_t *pSize); + +// Ends archive writing, freeing all allocations, and closing the output file if +// mz_zip_writer_init_file() was used. +// Note for the archive to be valid, it must have been finalized before ending. +mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + +// Misc. high-level helper functions: + +// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) +// appends a memory blob to a ZIP archive. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or +// just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_add_mem_to_archive_file_in_place( + const char *pZip_filename, const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, mz_uint16 comment_size, + mz_uint level_and_flags); + +// Reads a single file from an archive into a heap block. +// Returns NULL on failure. +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, + const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + +// ------------------- Low-level Decompression API Definitions + +// Decompression flags used by tinfl_decompress(). +// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and +// ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the +// input is a raw deflate stream. +// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available +// beyond the end of the supplied input buffer. If clear, the input buffer +// contains all remaining input. +// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large +// enough to hold the entire decompressed stream. If clear, the output buffer is +// at least the size of the dictionary (typically 32KB). +// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the +// decompressed bytes. +enum { + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +// High level decompression functions: +// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block +// allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data +// to decompress. +// On return: +// Function returns a pointer to the decompressed data, or NULL on failure. +// *pOut_len will be set to the decompressed data's size, which could be larger +// than src_buf_len on uncompressible data. +// The caller must call mz_free() on the returned block when it's no longer +// needed. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags); + +// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block +// in memory. +// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes +// written on success. +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags); + +// tinfl_decompress_mem_to_callback() decompresses a block in memory to an +// internal 32KB buffer, and a user provided callback function will be called to +// flush the buffer. +// Returns 1 on success or 0 on failure. +typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, + tinfl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; +typedef struct tinfl_decompressor_tag tinfl_decompressor; + +// Max size of LZ dictionary. +#define TINFL_LZ_DICT_SIZE 32768 + +// Return status. +typedef enum { + TINFL_STATUS_BAD_PARAM = -3, + TINFL_STATUS_ADLER32_MISMATCH = -2, + TINFL_STATUS_FAILED = -1, + TINFL_STATUS_DONE = 0, + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +// Initializes the decompressor to its initial state. +#define tinfl_init(r) \ + do { \ + (r)->m_state = 0; \ + } \ + MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +// Main low-level decompressor coroutine function. This is the only function +// actually needed for decompression. All the other functions are just +// high-level helpers for improved usability. +// This is a universal API, i.e. it can be used as a building block to build any +// desired higher level decompression API. In the limit case, it can be called +// once per every byte input or output. +tinfl_status tinfl_decompress(tinfl_decompressor *r, + const mz_uint8 *pIn_buf_next, + size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, + mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, + const mz_uint32 decomp_flags); + +// Internal/private bits follow. +enum { + TINFL_MAX_HUFF_TABLES = 3, + TINFL_MAX_HUFF_SYMBOLS_0 = 288, + TINFL_MAX_HUFF_SYMBOLS_1 = 32, + TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, + TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct { + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], + m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS +#define TINFL_USE_64BIT_BITBUF 1 +#endif + +#if TINFL_USE_64BIT_BITBUF +typedef mz_uint64 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (64) +#else +typedef mz_uint32 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag { + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, + m_check_adler32, m_dist, m_counter, m_num_extra, + m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], + m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +// ------------------- Low-level Compression API Definitions + +// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly +// slower, and raw/dynamic blocks will be output more frequently). +#define TDEFL_LESS_MEMORY 0 + +// tdefl_init() compression flags logically OR'd together (low 12 bits contain +// the max. number of probes per dictionary search): +// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes +// per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap +// compression), 4095=Huffman+LZ (slowest/best compression). +enum { + TDEFL_HUFFMAN_ONLY = 0, + TDEFL_DEFAULT_MAX_PROBES = 128, + TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before +// the deflate data, and the Adler-32 of the source data at the end. Otherwise, +// you'll get raw deflate data. +// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even +// when not writing zlib headers). +// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more +// efficient lazy parsing. +// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's +// initialization time to the minimum, but the output may vary from run to run +// given the same input (depending on the contents of memory). +// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) +// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. +// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. +// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. +// The low 12 bits are reserved to control the max # of hash probes per +// dictionary lookup (see TDEFL_MAX_PROBES_MASK). +enum { + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 +}; + +// High level compression functions: +// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block +// allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of source block to compress. +// flags: The max match finder probes (default is 128) logically OR'd against +// the above flags. Higher probes are slower but improve compression. +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pOut_len will be set to the compressed data's size, which could be larger +// than src_buf_len on uncompressible data. +// The caller must free() the returned block when it's no longer needed. +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags); + +// tdefl_compress_mem_to_mem() compresses a block in memory to another block in +// memory. +// Returns 0 on failure. +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags); + +// Compresses an image to a compressed PNG file in memory. +// On entry: +// pImage, w, h, and num_chans describe the image to compress. num_chans may be +// 1, 2, 3, or 4. +// The image pitch in bytes per scanline will be w*num_chans. The leftmost +// pixel on the top scanline is stored first in memory. +// level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL +// If flip is true, the image will be flipped on the Y axis (useful for OpenGL +// apps). +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pLen_out will be set to the size of the PNG image file. +// The caller must mz_free() the returned heap block (which will typically be +// larger than *pLen_out) when it's no longer needed. +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, + int h, int num_chans, + size_t *pLen_out, + mz_uint level, mz_bool flip); +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, + int num_chans, size_t *pLen_out); + +// Output stream interface. The compressor uses this interface to write +// compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, + void *pUser); + +// tdefl_compress_mem_to_output() compresses a block to an output stream. The +// above helpers use this function internally. +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags); + +enum { + TDEFL_MAX_HUFF_TABLES = 3, + TDEFL_MAX_HUFF_SYMBOLS_0 = 288, + TDEFL_MAX_HUFF_SYMBOLS_1 = 32, + TDEFL_MAX_HUFF_SYMBOLS_2 = 19, + TDEFL_LZ_DICT_SIZE = 32768, + TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, + TDEFL_MIN_MATCH_LEN = 3, + TDEFL_MAX_MATCH_LEN = 258 +}; + +// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed +// output block (using static/fixed Huffman codes). +#if TDEFL_LESS_MEMORY +enum { + TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 12, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#else +enum { + TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 15, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#endif + +// The low-level tdefl functions below may be used directly if the above helper +// functions aren't flexible enough. The low-level functions don't make any heap +// allocations, unlike the above helper functions. +typedef enum { + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1 +} tdefl_status; + +// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums +typedef enum { + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +// tdefl's compression state structure. +typedef struct { + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, + m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, + m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, + m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +// Initializes the compressor. +// There is no corresponding deinit() function because the tdefl API's do not +// dynamically allocate memory. +// pBut_buf_func: If NULL, output data will be supplied to the specified +// callback. In this case, the user should call the tdefl_compress_buffer() API +// for compression. +// If pBut_buf_func is NULL the user should always call the tdefl_compress() +// API. +// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, +// etc.) +tdefl_status tdefl_init(tdefl_compressor *d, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags); + +// Compresses a block of data, consuming as much of the specified input buffer +// as possible, and writing as much compressed data to the specified output +// buffer as possible. +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, + size_t *pIn_buf_size, void *pOut_buf, + size_t *pOut_buf_size, tdefl_flush flush); + +// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a +// non-NULL tdefl_put_buf_func_ptr. +// tdefl_compress_buffer() always consumes the entire input buffer. +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, + size_t in_buf_size, tdefl_flush flush); + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); +mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + +// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't +// defined, because it uses some of its macros. +#ifndef MINIZ_NO_ZLIB_APIS +// Create tdefl_compress() flags given zlib-style compression parameters. +// level may range from [0,10] (where 10 is absolute max compression, but may be +// much slower on some files) +// window_bits may be -15 (raw deflate) or 15 (zlib) +// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, +// MZ_RLE, or MZ_FIXED +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, + int strategy); +#endif // #ifndef MINIZ_NO_ZLIB_APIS + +#ifdef __cplusplus +} +#endif + +#endif // MINIZ_HEADER_INCLUDED + +// ------------------- End of Header: Implementation follows. (If you only want +// the header, define MINIZ_HEADER_FILE_ONLY.) + +#ifndef MINIZ_HEADER_FILE_ONLY + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; + +//#include +//#include + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC +#define MZ_MALLOC(x) NULL +#define MZ_FREE(x) (void)x, ((void)0) +#define MZ_REALLOC(p, x) NULL +#else +#define MZ_MALLOC(x) malloc(x) +#define MZ_FREE(x) free(x) +#define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) +#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else +#define MZ_READ_LE16(p) \ + ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) +#define MZ_READ_LE32(p) \ + ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#ifdef _MSC_VER +#define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) +#define MZ_FORCEINLINE inline __attribute__((__always_inline__)) +#else +#define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ------------------- zlib-style API's + +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); + size_t block_len = buf_len % 5552; + if (!ptr) return MZ_ADLER32_INIT; + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + return (s2 << 16) + s1; +} + +// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C +// implementation that balances processor cache usage against speed": +// http://www.geocities.com/malbrain/ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { + static const mz_uint32 s_crc32[16] = { + 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, + 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c}; + mz_uint32 crcu32 = (mz_uint32)crc; + if (!ptr) return MZ_CRC32_INIT; + crcu32 = ~crcu32; + while (buf_len--) { + mz_uint8 b = *ptr++; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; + } + return ~crcu32; +} + +void mz_free(void *p) { MZ_FREE(p); } + +#ifndef MINIZ_NO_ZLIB_APIS + +static void *def_alloc_func(void *opaque, size_t items, size_t size) { + (void)opaque, (void)items, (void)size; + return MZ_MALLOC(items * size); +} +static void def_free_func(void *opaque, void *address) { + (void)opaque, (void)address; + MZ_FREE(address); +} +// static void *def_realloc_func(void *opaque, void *address, size_t items, +// size_t size) { +// (void)opaque, (void)address, (void)items, (void)size; +// return MZ_REALLOC(address, items * size); +//} + +const char *mz_version(void) { return MZ_VERSION; } + +int mz_deflateInit(mz_streamp pStream, int level) { + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, + MZ_DEFAULT_STRATEGY); +} + +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, + int mem_level, int strategy) { + tdefl_compressor *pComp; + mz_uint comp_flags = + TDEFL_COMPUTE_ADLER32 | + tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || + ((window_bits != MZ_DEFAULT_WINDOW_BITS) && + (-window_bits != MZ_DEFAULT_WINDOW_BITS))) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, + sizeof(tdefl_compressor)); + if (!pComp) return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +int mz_deflateReset(mz_streamp pStream) { + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || + (!pStream->zfree)) + return MZ_STREAM_ERROR; + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, + ((tdefl_compressor *)pStream->state)->m_flags); + return MZ_OK; +} + +int mz_deflate(mz_streamp pStream, int flush) { + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || + (!pStream->next_out)) + return MZ_STREAM_ERROR; + if (!pStream->avail_out) return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor *)pStream->state)->m_prev_return_status == + TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; + orig_total_out = pStream->total_out; + for (;;) { + tdefl_status defl_status; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor *)pStream->state, + pStream->next_in, &in_bytes, pStream->next_out, + &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) { + mz_status = MZ_STREAM_ERROR; + break; + } else if (defl_status == TDEFL_STATUS_DONE) { + mz_status = MZ_STREAM_END; + break; + } else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) { + if ((flush) || (pStream->total_in != orig_total_in) || + (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; // Can't make forward progress without some input. + } + } + return mz_status; +} + +int mz_deflateEnd(mz_streamp pStream) { + if (!pStream) return MZ_STREAM_ERROR; + if (pStream->state) { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) { + (void)pStream; + // This is really over conservative. (And lame, but it's actually pretty + // tricky to compute a true upper bound given the way tdefl's blocking works.) + return MZ_MAX(128 + (source_len * 110) / 100, + 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +} + +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len, int level) { + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) return status; + + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); +} + +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len) { + return mz_compress2(pDest, pDest_len, pSource, source_len, + MZ_DEFAULT_COMPRESSION); +} + +mz_ulong mz_compressBound(mz_ulong source_len) { + return mz_deflateBound(NULL, source_len); +} + +typedef struct { + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; + int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +int mz_inflateInit2(mz_streamp pStream, int window_bits) { + inflate_state *pDecomp; + if (!pStream) return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && + (-window_bits != MZ_DEFAULT_WINDOW_BITS)) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, + sizeof(inflate_state)); + if (!pDecomp) return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +int mz_inflateInit(mz_streamp pStream) { + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +int mz_inflate(mz_streamp pStream, int flush) { + inflate_state *pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + + pState = (inflate_state *)pStream->state; + if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; + pState->m_first_call = 0; + if (pState->m_last_status < 0) return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) { + // MZ_FINISH on the first call implies that the input and output buffers are + // large enough to hold the entire compressed/decompressed file. + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, + pStream->next_out, pStream->next_out, &out_bytes, + decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + // flush != MZ_FINISH then we must assume there's more input. + if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && + (!pState->m_dict_avail)) + ? MZ_STREAM_END + : MZ_OK; + } + + for (;;) { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress( + &pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, + pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; // Stream is corrupted (there could be some + // uncompressed data left in the output dictionary - + // oh well). + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; // Signal caller that we can't make forward progress + // without supplying more input or by setting flush + // to MZ_FINISH. + else if (flush == MZ_FINISH) { + // The output buffer MUST be large to hold the remaining uncompressed data + // when flush==MZ_FINISH. + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's + // at least 1 more byte on the way. If there's no more room left in the + // output buffer then something is wrong. + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || + (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) + ? MZ_STREAM_END + : MZ_OK; +} + +int mz_inflateEnd(mz_streamp pStream) { + if (!pStream) return MZ_STREAM_ERROR; + if (pStream->state) { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len) { + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_inflateInit(&stream); + if (status != MZ_OK) return status; + + status = mz_inflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR + : status; + } + *pDest_len = stream.total_out; + + return mz_inflateEnd(&stream); +} + +const char *mz_error(int err) { + static struct { + int m_err; + const char *m_pDesc; + } s_error_descs[] = {{MZ_OK, ""}, + {MZ_STREAM_END, "stream end"}, + {MZ_NEED_DICT, "need dictionary"}, + {MZ_ERRNO, "file error"}, + {MZ_STREAM_ERROR, "stream error"}, + {MZ_DATA_ERROR, "data error"}, + {MZ_MEM_ERROR, "out of memory"}, + {MZ_BUF_ERROR, "buf error"}, + {MZ_VERSION_ERROR, "version error"}, + {MZ_PARAM_ERROR, "parameter error"}}; + mz_uint i; + for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) + if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; + return NULL; +} + +#endif // MINIZ_NO_ZLIB_APIS + +// ------------------- Low-level Decompression (completely independent from all +// compression API's) + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN \ + switch (r->m_state) { \ + case 0: +#define TINFL_CR_RETURN(state_index, result) \ + do { \ + status = result; \ + r->m_state = state_index; \ + goto common_exit; \ + case state_index:; \ + } \ + MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) \ + do { \ + for (;;) { \ + TINFL_CR_RETURN(state_index, result); \ + } \ + } \ + MZ_MACRO_END +#define TINFL_CR_FINISH } + +// TODO: If the caller has indicated that there's no more input, and we attempt +// to read beyond the input buf, then something is wrong with the input because +// the inflator never +// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of +// the stream with 0's in this scenario. +#define TINFL_GET_BYTE(state_index, c) \ + do { \ + if (pIn_buf_cur >= pIn_buf_end) { \ + for (;;) { \ + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ + TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ + if (pIn_buf_cur < pIn_buf_end) { \ + c = *pIn_buf_cur++; \ + break; \ + } \ + } else { \ + c = 0; \ + break; \ + } \ + } \ + } else \ + c = *pIn_buf_cur++; \ + } \ + MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) \ + do { \ + mz_uint c; \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) \ + do { \ + if (num_bits < (mz_uint)(n)) { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) \ + do { \ + if (num_bits < (mz_uint)(n)) { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + b = bit_buf & ((1 << (n)) - 1); \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END + +// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes +// remaining in the input buffer falls below 2. +// It reads just enough bytes from the input stream that are needed to decode +// the next Huffman code (and absolutely no more). It works by trying to fully +// decode a +// Huffman code by using whatever bits are currently present in the bit buffer. +// If this fails, it reads another byte, and tries again until it succeeds or +// until the +// bit buffer contains >=15 bits (deflate's max. Huffman code size). +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) break; \ + } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); \ + if (temp >= 0) break; \ + } \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < 15); + +// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex +// than you would initially expect because the zlib API expects the decompressor +// to never read +// beyond the final byte of the deflate stream. (In other words, when this macro +// wants to read another byte from the input, it REALLY needs another byte in +// order to fully +// decode the next Huffman code.) Handling this properly is particularly +// important on raw deflate (non-zlib) streams, which aren't followed by a byte +// aligned adler-32. +// The slow path is only executed at the very end of the input buffer. +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ + do { \ + int temp; \ + mz_uint code_len, c; \ + if (num_bits < 15) { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } else { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | \ + (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ + pIn_buf_cur += 2; \ + num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= \ + 0) \ + code_len = temp >> 9, temp &= 511; \ + else { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while (temp < 0); \ + } \ + sym = temp; \ + bit_buf >>= code_len; \ + num_bits -= code_len; \ + } \ + MZ_MACRO_END + +tinfl_status tinfl_decompress(tinfl_decompressor *r, + const mz_uint8 *pIn_buf_next, + size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, + mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, + const mz_uint32 decomp_flags) { + static const int s_length_base[31] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const int s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, + 4, 4, 5, 5, 5, 5, 0, 0, 0}; + static const int s_dist_base[32] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, + 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, + 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; + static const int s_dist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + static const mz_uint8 s_length_dezigzag[19] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + static const int s_min_table_sizes[3] = {257, 1, 4}; + + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; + tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = + pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = + pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = + (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) + ? (size_t)-1 + : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, + dist_from_out_buf_start; + + // Ensure the output buffer's size is a power of 2, unless the output buffer + // is large enough to hold the entire output file (in which case it doesn't + // matter). + if (((out_buf_size_mask + 1) & out_buf_size_mask) || + (pOut_buf_next < pOut_buf_start)) { + *pIn_buf_size = *pOut_buf_size = 0; + return TINFL_STATUS_BAD_PARAM; + } + + num_bits = r->m_num_bits; + bit_buf = r->m_bit_buf; + dist = r->m_dist; + counter = r->m_counter; + num_extra = r->m_num_extra; + dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; + r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { + TINFL_GET_BYTE(1, r->m_zhdr0); + TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || + (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || + ((out_buf_size_mask + 1) < + (size_t)(1ULL << (8U + (r->m_zhdr0 >> 4))))); + if (counter) { + TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); + } + } + + do { + TINFL_GET_BITS(3, r->m_final, 3); + r->m_type = r->m_final >> 1; + if (r->m_type == 0) { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { + if (num_bits) + TINFL_GET_BITS(6, r->m_raw_header[counter], 8); + else + TINFL_GET_BYTE(7, r->m_raw_header[counter]); + } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != + (mz_uint)(0xFFFF ^ + (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { + TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); + } + while ((counter) && (num_bits)) { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) { + size_t n; + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); + } + while (pIn_buf_cur >= pIn_buf_end) { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { + TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); + } else { + TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); + } + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), + (size_t)(pIn_buf_end - pIn_buf_cur)), + counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); + pIn_buf_cur += n; + pOut_buf_cur += n; + counter -= (mz_uint)n; + } + } else if (r->m_type == 3) { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } else { + if (r->m_type == 1) { + mz_uint8 *p = r->m_tables[0].m_code_size; + mz_uint i; + r->m_table_sizes[0] = 288; + r->m_table_sizes[1] = 32; + TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for (i = 0; i <= 143; ++i) *p++ = 8; + for (; i <= 255; ++i) *p++ = 9; + for (; i <= 279; ++i) *p++ = 7; + for (; i <= 287; ++i) *p++ = 8; + } else { + for (counter = 0; counter < 3; counter++) { + TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); + r->m_table_sizes[counter] += s_min_table_sizes[counter]; + } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); + for (counter = 0; counter < r->m_table_sizes[2]; counter++) { + mz_uint s; + TINFL_GET_BITS(14, s, 3); + r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; + } + r->m_table_sizes[2] = 19; + } + for (; (int)r->m_type >= 0; r->m_type--) { + int tree_next, tree_cur; + tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], + total_syms[16]; + pTable = &r->m_tables[r->m_type]; + MZ_CLEAR_OBJ(total_syms); + MZ_CLEAR_OBJ(pTable->m_look_up); + MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) + total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; + next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) { + used_syms += total_syms[i]; + next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); + } + if ((65536 != total) && (used_syms > 1)) { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; + sym_index < r->m_table_sizes[r->m_type]; ++sym_index) { + mz_uint rev_code = 0, l, cur_code, + code_size = pTable->m_code_size[sym_index]; + if (!code_size) continue; + cur_code = next_code[code_size]++; + for (l = code_size; l > 0; l--, cur_code >>= 1) + rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) { + mz_int16 k = (mz_int16)((code_size << 9) | sym_index); + while (rev_code < TINFL_FAST_LOOKUP_SIZE) { + pTable->m_look_up[rev_code] = k; + rev_code += (1 << code_size); + } + continue; + } + if (0 == + (tree_cur = pTable->m_look_up[rev_code & + (TINFL_FAST_LOOKUP_SIZE - 1)])) { + pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = + (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) { + pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } else + tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); + pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) { + for (counter = 0; + counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) { + mz_uint s; + TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); + if (dist < 16) { + r->m_len_codes[counter++] = (mz_uint8)dist; + continue; + } + if ((dist == 16) && (!counter)) { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; + TINFL_GET_BITS(18, s, num_extra); + s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, + (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); + counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, + r->m_table_sizes[0]); + TINFL_MEMCPY(r->m_tables[1].m_code_size, + r->m_len_codes + r->m_table_sizes[0], + r->m_table_sizes[1]); + } + } + for (;;) { + mz_uint8 *pSrc; + for (;;) { + if (((pIn_buf_end - pIn_buf_cur) < 4) || + ((pOut_buf_end - pOut_buf_cur) < 2)) { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) break; + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)counter; + } else { + int sym2; + mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) { + bit_buf |= + (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 4; + num_bits += 32; + } +#else + if (num_bits < 15) { + bit_buf |= + (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = + r->m_tables[0] + .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= + 0) + code_len = sym2 >> 9; + else { + code_len = TINFL_FAST_LOOKUP_BITS; + do { + sym2 = r->m_tables[0] + .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + counter = sym2; + bit_buf >>= code_len; + num_bits -= code_len; + if (counter & 256) break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) { + bit_buf |= + (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = + r->m_tables[0] + .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= + 0) + code_len = sym2 >> 9; + else { + code_len = TINFL_FAST_LOOKUP_BITS; + do { + sym2 = r->m_tables[0] + .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + bit_buf >>= code_len; + num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) break; + + num_extra = s_length_extra[counter - 257]; + counter = s_length_base[counter - 257]; + if (num_extra) { + mz_uint extra_bits; + TINFL_GET_BITS(25, extra_bits, num_extra); + counter += extra_bits; + } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; + dist = s_dist_base[dist]; + if (num_extra) { + mz_uint extra_bits; + TINFL_GET_BITS(27, extra_bits, num_extra); + dist += extra_bits; + } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && + (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) { + while (counter--) { + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = + pOut_buf_start[(dist_from_out_buf_start++ - dist) & + out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) { + if (counter) { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; + pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { + TINFL_SKIP_BITS(32, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { + mz_uint s; + if (num_bits) + TINFL_GET_BITS(41, s, 8); + else + TINFL_GET_BYTE(42, s); + r->m_z_adler32 = (r->m_z_adler32 << 8) | s; + } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + TINFL_CR_FINISH + +common_exit: + r->m_num_bits = num_bits; + r->m_bit_buf = bit_buf; + r->m_dist = dist; + r->m_counter = counter; + r->m_num_extra = num_extra; + r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; + *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & + (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && + (status >= 0)) { + const mz_uint8 *ptr = pOut_buf_next; + size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, + s2 = r->m_check_adler32 >> 16; + size_t block_len = buf_len % 5552; + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; + if ((status == TINFL_STATUS_DONE) && + (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && + (r->m_check_adler32 != r->m_z_adler32)) + status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +// Higher level helper functions. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags) { + tinfl_decompressor decomp; + void *pBuf = NULL, *pNew_buf; + size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for (;;) { + size_t src_buf_size = src_buf_len - src_buf_ofs, + dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress( + &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, + (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, + &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) break; + new_out_buf_capacity = out_buf_capacity * 2; + if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + pBuf = pNew_buf; + out_buf_capacity = new_out_buf_capacity; + } + return pBuf; +} + +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags) { + tinfl_decompressor decomp; + tinfl_status status; + tinfl_init(&decomp); + status = + tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, + (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED + : out_buf_len; +} + +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, + tinfl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags) { + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); + size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) return TINFL_STATUS_FAILED; + tinfl_init(&decomp); + for (;;) { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, + dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = + tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, + &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && + (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; +} + +// ------------------- Low-level Compression (independent from all decompression +// API's) + +// Purposely making these tables static for faster init and thread safety. +static const mz_uint16 s_tdefl_len_sym[256] = { + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, + 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, + 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, + 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, + 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279, + 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 285}; + +static const mz_uint8 s_tdefl_len_extra[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0}; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17}; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = { + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = { + 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, + 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29}; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = { + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; + +// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted +// values. +typedef struct { + mz_uint16 m_key, m_sym_index; +} tdefl_sym_freq; +static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, + tdefl_sym_freq *pSyms0, + tdefl_sym_freq *pSyms1) { + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; + tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; + MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) { + mz_uint freq = pSyms0[i].m_key; + hist[freq & 0xFF]++; + hist[256 + ((freq >> 8) & 0xFF)]++; + } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) + total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) { + const mz_uint32 *pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) { + offsets[i] = cur_ofs; + cur_ofs += pHist[i]; + } + for (i = 0; i < num_syms; i++) + pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = + pCur_syms[i]; + { + tdefl_sym_freq *t = pCur_syms; + pCur_syms = pNew_syms; + pNew_syms = t; + } + } + return pCur_syms; +} + +// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, +// alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) { + int root, leaf, next, avbl, used, dpth; + if (n == 0) + return; + else if (n == 1) { + A[0].m_key = 1; + return; + } + A[0].m_key += A[1].m_key; + root = 0; + leaf = 2; + for (next = 1; next < n - 1; next++) { + if (leaf >= n || A[root].m_key < A[leaf].m_key) { + A[next].m_key = A[root].m_key; + A[root++].m_key = (mz_uint16)next; + } else + A[next].m_key = A[leaf++].m_key; + if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) { + A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); + A[root++].m_key = (mz_uint16)next; + } else + A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); + } + A[n - 2].m_key = 0; + for (next = n - 3; next >= 0; next--) + A[next].m_key = A[A[next].m_key].m_key + 1; + avbl = 1; + used = dpth = 0; + root = n - 2; + next = n - 1; + while (avbl > 0) { + while (root >= 0 && (int)A[root].m_key == dpth) { + used++; + root--; + } + while (avbl > used) { + A[next--].m_key = (mz_uint16)(dpth); + avbl--; + } + avbl = 2 * used; + dpth++; + used = 0; + } +} + +// Limits canonical Huffman code table's max code size. +enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, + int code_list_len, + int max_code_size) { + int i; + mz_uint32 total = 0; + if (code_list_len <= 1) return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) + pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) + total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) + if (pNum_codes[i]) { + pNum_codes[i]--; + pNum_codes[i + 1] += 2; + break; + } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, + int table_len, int code_size_limit, + int static_table) { + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; + mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; + MZ_CLEAR_OBJ(num_codes); + if (static_table) { + for (i = 0; i < table_len; i++) + num_codes[d->m_huff_code_sizes[table_num][i]]++; + } else { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], + *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) + if (pSym_count[i]) { + syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; + syms0[num_used_syms++].m_sym_index = (mz_uint16)i; + } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); + tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, + code_size_limit); + + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); + MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) + d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; + for (j = 0, i = 2; i <= code_size_limit; i++) + next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) { + mz_uint rev_code = 0, code, code_size; + if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; + code = next_code[code_size]++; + for (l = code_size; l > 0; l--, code >>= 1) + rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) \ + do { \ + mz_uint bits = b; \ + mz_uint len = l; \ + MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); \ + d->m_bits_in += len; \ + while (d->m_bits_in >= 8) { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ + } \ + MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() \ + { \ + if (rle_repeat_count) { \ + if (rle_repeat_count < 3) { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)( \ + d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) \ + packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } else { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 16; \ + packed_code_sizes[num_packed_code_sizes++] = \ + (mz_uint8)(rle_repeat_count - 3); \ + } \ + rle_repeat_count = 0; \ + } \ + } + +#define TDEFL_RLE_ZERO_CODE_SIZE() \ + { \ + if (rle_z_count) { \ + if (rle_z_count < 3) { \ + d->m_huff_count[2][0] = \ + (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ + while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ + } else if (rle_z_count <= 10) { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 17; \ + packed_code_sizes[num_packed_code_sizes++] = \ + (mz_uint8)(rle_z_count - 3); \ + } else { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 18; \ + packed_code_sizes[num_packed_code_sizes++] = \ + (mz_uint8)(rle_z_count - 11); \ + } \ + rle_z_count = 0; \ + } \ + } + +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) { + int num_lit_codes, num_dist_codes, num_bit_lengths; + mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, + rle_repeat_count, packed_code_sizes_index; + mz_uint8 + code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], + packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], + prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) + if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) + if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], + num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; + num_packed_code_sizes = 0; + rle_z_count = 0; + rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, + sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + } else { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = + (mz_uint16)(d->m_huff_count[2][code_size] + 1); + packed_code_sizes[num_packed_code_sizes++] = code_size; + } else if (++rle_repeat_count == 6) { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) { + TDEFL_RLE_PREV_CODE_SIZE(); + } else { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) + if (d->m_huff_code_sizes + [2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) + break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); + TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) + TDEFL_PUT_BITS( + d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; + packed_code_sizes_index < num_packed_code_sizes;) { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; + MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) + TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], + "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) { + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) *p++ = 8; + for (; i <= 255; ++i) *p++ = 9; + for (; i <= 279; ++i) *p++ = 7; + for (; i <= 287; ++i) *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint mz_bitmasks[17] = { + 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, + 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF}; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \ + MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) \ + { \ + bit_buffer |= (((mz_uint64)(b)) << bits_in); \ + bits_in += (l); \ + } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; + flags >>= 1) { + if (flags == 1) flags = *pLZ_codes++ | 0x100; + + if (flags & 1) { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], + match_dist = *(const mz_uint16 *)(pLZ_codes + 1); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], + d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], + s_tdefl_len_extra[match_len]); + + // This sequence coaxes MSVC into using cmov's vs. jmp's. + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], + d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], + num_extra_bits); + } else { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], + d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], + d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], + d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE; + + *(mz_uint64 *)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; + flags >>= 1) { + if (flags == 1) flags = *pLZ_codes++ | 0x100; + if (flags & 1) { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], + match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], + d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], + s_tdefl_len_extra[match_len]); + + if (match_dist < 512) { + sym = s_tdefl_small_dist_sym[match_dist]; + num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } else { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; + num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } else { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && + // MINIZ_HAS_64BIT_REGISTERS + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) { + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static int tdefl_flush_block(tdefl_compressor *d, int flush) { + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = + ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && + (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = + ((d->m_pPut_buf_func == NULL) && + ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) + ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) + : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { + TDEFL_PUT_BITS(0x78, 8); + TDEFL_PUT_BITS(0x01, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; + saved_bit_buf = d->m_bit_buffer; + saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = + tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || + (d->m_total_lz_bytes < 48)); + + // If the block gets expanded, forget the current contents of the output + // buffer and send a raw block instead. + if (((use_raw_block) || + ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= + d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) { + mz_uint i; + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) { + TDEFL_PUT_BITS( + d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], + 8); + } + } + // Check for the extremely unlikely (if not impossible) case of the compressed + // block not fitting into the output buffer when using dynamic codes. + else if (!comp_block_succeeded) { + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) { + if (flush == TDEFL_FINISH) { + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { + mz_uint i, a = d->m_adler32; + for (i = 0; i < 4; i++) { + TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); + a <<= 8; + } + } + } else { + mz_uint i, z = 0; + TDEFL_PUT_BITS(0, 3); + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, z ^= 0xFFFF) { + TDEFL_PUT_BITS(z & 0xFFFF, 16); + } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, + sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, + sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; + d->m_total_lz_bytes = 0; + d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) { + if (d->m_pPut_buf_func) { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } else if (pOutput_buf_start == d->m_output_buf) { + int bytes_to_copy = (int)MZ_MIN( + (size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, + bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } else { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) +static MZ_FORCEINLINE void tdefl_find_match( + tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, + mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, + match_len = *pMatch_len, probe_pos = pos, next_probe_pos, + probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), + s01 = TDEFL_READ_UNALIGNED_WORD(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) return; + for (;;) { + for (;;) { + if (--num_probes_left == 0) return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || \ + ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) break; + q = (const mz_uint16 *)(d->m_dict + probe_pos); + if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; + p = s; + probe_len = 32; + do { + } while ( + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (--probe_len > 0)); + if (!probe_len) { + *pMatch_dist = dist; + *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); + break; + } else if ((probe_len = ((mz_uint)(p - s) * 2) + + (mz_uint)(*(const mz_uint8 *)p == + *(const mz_uint8 *)q)) > match_len) { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == + max_match_len) + break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} +#else +static MZ_FORCEINLINE void tdefl_find_match( + tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, + mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, + match_len = *pMatch_len, probe_pos = pos, next_probe_pos, + probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) return; + for (;;) { + for (;;) { + if (--num_probes_left == 0) return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || \ + ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && \ + (d->m_dict[probe_pos + match_len - 1] == c1)) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) break; + p = s; + q = d->m_dict + probe_pos; + for (probe_len = 0; probe_len < max_match_len; probe_len++) + if (*p++ != *q++) break; + if (probe_len > match_len) { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = probe_len) == max_match_len) return; + c0 = d->m_dict[pos + match_len]; + c1 = d->m_dict[pos + match_len - 1]; + } + } +} +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +static mz_bool tdefl_compress_fast(tdefl_compressor *d) { + // Faster, minimally featured LZRW1-style match+parse loop with better + // register utilization. Intended for applications where raw throughput is + // valued more highly than ratio. + mz_uint lookahead_pos = d->m_lookahead_pos, + lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, + total_lz_bytes = d->m_total_lz_bytes, + num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = + (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN( + d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; + + while (num_bytes_to_process) { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, + MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } + + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) + break; + + while (lookahead_size >= 4) { + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8 *pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; + mz_uint hash = + (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & + TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; + + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= + dict_size) && + ((*(const mz_uint32 *)(d->m_dict + + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & + 0xFFFFFF) == first_trigram)) { + const mz_uint16 *p = (const mz_uint16 *)pCur_dict; + const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do { + } while ((TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && + (--probe_len > 0)); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + if (!probe_len) + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || + ((cur_match_len == TDEFL_MIN_MATCH_LEN) && + (cur_match_dist >= 8U * 1024U))) { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } else { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && + (cur_match_dist >= 1) && + (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + + cur_match_dist--; + + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); + *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - + TDEFL_MIN_MATCH_LEN]]++; + } + } else { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + + if (--num_flags_left == 0) { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + + while (lookahead_size) { + mz_uint8 lit = d->m_dict[cur_pos]; + + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + d->m_huff_count[0][lit]++; + + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + } + + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + return MZ_TRUE; +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, + mz_uint8 lit) { + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); + if (--d->m_num_flags_left == 0) { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + d->m_huff_count[0][lit]++; +} + +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, + mz_uint match_len, + mz_uint match_dist) { + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && + (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); + d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); + if (--d->m_num_flags_left == 0) { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + + if (match_len >= TDEFL_MIN_MATCH_LEN) + d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) { + const mz_uint8 *pSrc = d->m_pSrc; + size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + // Update dictionary and hash chains. Keeps the lookahead size equal to + // TDEFL_MAX_MATCH_LEN. + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & + TDEFL_LZ_DICT_SIZE_MASK, + ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] + << TDEFL_LZ_HASH_SHIFT) ^ + d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN( + src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) { + mz_uint8 c = *pSrc++; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + ins_pos++; + } + } else { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & + TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] + << (TDEFL_LZ_HASH_SHIFT * 2)) ^ + (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] + << TDEFL_LZ_HASH_SHIFT) ^ + c) & + (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = + MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break; + + // Simple lazy/greedy parsing state machine. + len_to_move = 1; + cur_match_dist = 0; + cur_match_len = + d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); + cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; + while (cur_match_len < d->m_lookahead_size) { + if (d->m_dict[cur_pos + cur_match_len] != c) break; + cur_match_len++; + } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) + cur_match_len = 0; + else + cur_match_dist = 1; + } + } else { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, + d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && + (cur_match_dist >= 8U * 1024U)) || + (cur_pos == cur_match_dist) || + ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) { + if (cur_match_len > d->m_saved_match_len) { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; + len_to_move = cur_match_len; + } else { + d->m_saved_lit = d->m_dict[cur_pos]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + } else { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; + d->m_saved_match_len = 0; + } + } else if (!cur_match_dist) + tdefl_record_literal(d, + d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || + (cur_match_len >= 128)) { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } else { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + // Move the lookahead forward by len_to_move bytes. + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = + MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); + // Check if it's time to flush the current LZ codes to the internal output + // buffer. + if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ((d->m_total_lz_bytes > 31 * 1024) && + (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= + d->m_total_lz_bytes) || + (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) { + int n; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) { + if (d->m_pIn_buf_size) { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, + d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, + d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE + : TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, + size_t *pIn_buf_size, void *pOut_buf, + size_t *pOut_buf_size, tdefl_flush flush) { + if (!d) { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; + d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; + d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); + d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if (((d->m_pPut_buf_func != NULL) == + ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || + (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || + (pIn_buf_size && *pIn_buf_size && !pIn_buf) || + (pOut_buf_size && *pOut_buf_size && !pOut_buf)) { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | + TDEFL_RLE_MATCHES)) == 0)) { + if (!tdefl_compress_fast(d)) return d->m_prev_return_status; + } else +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + { + if (!tdefl_compress_normal(d)) return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && + (pIn_buf)) + d->m_adler32 = + (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, + d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && + (!d->m_output_flush_remaining)) { + if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) { + MZ_CLEAR_OBJ(d->m_hash); + MZ_CLEAR_OBJ(d->m_next); + d->m_dict_size = 0; + } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, + size_t in_buf_size, tdefl_flush flush) { + MZ_ASSERT(d->m_pPut_buf_func); + return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +} + +tdefl_status tdefl_init(tdefl_compressor *d, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags) { + d->m_pPut_buf_func = pPut_buf_func; + d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); + d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; + d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = + d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = + d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; + d->m_pOutput_buf_end = d->m_output_buf; + d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; + d->m_adler32 = 1; + d->m_pIn_buf = NULL; + d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; + d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; + memset(&d->m_huff_count[0][0], 0, + sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, + sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) { + return d->m_prev_return_status; +} + +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; } + +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags) { + tdefl_compressor *pComp; + mz_bool succeeded; + if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; + pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + if (!pComp) return MZ_FALSE; + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == + TDEFL_STATUS_OKAY); + succeeded = + succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == + TDEFL_STATUS_DONE); + MZ_FREE(pComp); + return succeeded; +} + +typedef struct { + size_t m_size, m_capacity; + mz_uint8 *m_pBuf; + mz_bool m_expandable; +} tdefl_output_buffer; + +static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, + void *pUser) { + tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; + size_t new_size = p->m_size + len; + if (new_size > p->m_capacity) { + size_t new_capacity = p->m_capacity; + mz_uint8 *pNew_buf; + if (!p->m_expandable) return MZ_FALSE; + do { + new_capacity = MZ_MAX(128U, new_capacity << 1U); + } while (new_size > new_capacity); + pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); + if (!pNew_buf) return MZ_FALSE; + p->m_pBuf = pNew_buf; + p->m_capacity = new_capacity; + } + memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); + p->m_size = new_size; + return MZ_TRUE; +} + +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags) { + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) + return MZ_FALSE; + else + *pOut_len = 0; + out_buf.m_expandable = MZ_TRUE; + if (!tdefl_compress_mem_to_output( + pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return NULL; + *pOut_len = out_buf.m_size; + return out_buf.m_pBuf; +} + +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags) { + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) return 0; + out_buf.m_pBuf = (mz_uint8 *)pOut_buf; + out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output( + pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return 0; + return out_buf.m_size; +} + +#ifndef MINIZ_NO_ZLIB_APIS +static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32, + 128, 256, 512, 768, 1500}; + +// level may actually range from [0,10] (10 is a "hidden" max level, where we +// want a bit more compression and it's fine if throughput to fall off a cliff +// on some files). +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, + int strategy) { + mz_uint comp_flags = + s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | + ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) + comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) + comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) + comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) + comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) + comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} +#endif // MINIZ_NO_ZLIB_APIS + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) // nonstandard extension used : non-constant + // aggregate initializer (also supported by GNU + // C and C99, so no big deal) +#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is + // deprecated. Instead, use the ISO C and C++ + // conformant name: _strdup. +#endif + +// Simple PNG writer function by Alex Evans, 2011. Released into the public +// domain: https://gist.github.com/908299, more context at +// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. +// This is actually a modification of Alex's original code so PNG files +// generated by this function pass pngcheck. +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, + int h, int num_chans, + size_t *pLen_out, + mz_uint level, mz_bool flip) { + // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was + // defined. + static const mz_uint s_tdefl_png_num_probes[11] = { + 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; + tdefl_compressor *pComp = + (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + tdefl_output_buffer out_buf; + int i, bpl = w * num_chans, y, z; + mz_uint32 c; + *pLen_out = 0; + if (!pComp) return NULL; + MZ_CLEAR_OBJ(out_buf); + out_buf.m_expandable = MZ_TRUE; + out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); + if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) { + MZ_FREE(pComp); + return NULL; + } + // write dummy header + for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); + // compress image data + tdefl_init( + pComp, tdefl_output_buffer_putter, &out_buf, + s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) { + tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); + tdefl_compress_buffer(pComp, + (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, + bpl, TDEFL_NO_FLUSH); + } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != + TDEFL_STATUS_DONE) { + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + // write real header + *pLen_out = out_buf.m_size - 41; + { + static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; + mz_uint8 pnghdr[41] = {0x89, + 0x50, + 0x4e, + 0x47, + 0x0d, + 0x0a, + 0x1a, + 0x0a, + 0x00, + 0x00, + 0x00, + 0x0d, + 0x49, + 0x48, + 0x44, + 0x52, + 0, + 0, + (mz_uint8)(w >> 8), + (mz_uint8)w, + 0, + 0, + (mz_uint8)(h >> 8), + (mz_uint8)h, + 8, + chans[num_chans], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + (mz_uint8)(*pLen_out >> 24), + (mz_uint8)(*pLen_out >> 16), + (mz_uint8)(*pLen_out >> 8), + (mz_uint8)*pLen_out, + 0x49, + 0x44, + 0x41, + 0x54}; + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); + for (i = 0; i < 4; ++i, c <<= 8) + ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); + memcpy(out_buf.m_pBuf, pnghdr, 41); + } + // write footer (IDAT CRC-32, followed by IEND chunk) + if (!tdefl_output_buffer_putter( + "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { + *pLen_out = 0; + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, + *pLen_out + 4); + for (i = 0; i < 4; ++i, c <<= 8) + (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); + // compute final size of file, grab compressed data buffer and return + *pLen_out += 57; + MZ_FREE(pComp); + return out_buf.m_pBuf; +} +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, + int num_chans, size_t *pLen_out) { + // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we + // can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's + // where #defined out) + return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, + pLen_out, 6, MZ_FALSE); +} + +// ------------------- .ZIP archive reading + +#ifndef MINIZ_NO_ARCHIVE_APIS +#error "No arvhive APIs" + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include +#include + +#if defined(_MSC_VER) || defined(__MINGW64__) +static FILE *mz_fopen(const char *pFilename, const char *pMode) { + FILE *pFile = NULL; + fopen_s(&pFile, pFilename, pMode); + return pFile; +} +static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { + FILE *pFile = NULL; + if (freopen_s(&pFile, pPath, pMode, pStream)) return NULL; + return pFile; +} +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN mz_fopen +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 _ftelli64 +#define MZ_FSEEK64 _fseeki64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN mz_freopen +#define MZ_DELETE_FILE remove +#elif defined(__MINGW32__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__TINYC__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE) && _LARGEFILE64_SOURCE +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen64(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT stat64 +#define MZ_FILE_STAT stat64 +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) +#define MZ_DELETE_FILE remove +#else +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello +#define MZ_FSEEK64 fseeko +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#endif // #ifdef _MSC_VER +#endif // #ifdef MINIZ_NO_STDIO + +#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +// Various ZIP archive enums. To completely avoid cross platform compiler +// alignment and platform endian issues, miniz.c doesn't use structs for any of +// this stuff. +enum { + // ZIP archive identifiers and record sizes + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, + MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + // Central directory header record offsets + MZ_ZIP_CDH_SIG_OFS = 0, + MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, + MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, + MZ_ZIP_CDH_BIT_FLAG_OFS = 8, + MZ_ZIP_CDH_METHOD_OFS = 10, + MZ_ZIP_CDH_FILE_TIME_OFS = 12, + MZ_ZIP_CDH_FILE_DATE_OFS = 14, + MZ_ZIP_CDH_CRC32_OFS = 16, + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, + MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, + MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, + MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, + MZ_ZIP_CDH_DISK_START_OFS = 34, + MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, + MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + // Local directory header offsets + MZ_ZIP_LDH_SIG_OFS = 0, + MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, + MZ_ZIP_LDH_BIT_FLAG_OFS = 6, + MZ_ZIP_LDH_METHOD_OFS = 8, + MZ_ZIP_LDH_FILE_TIME_OFS = 10, + MZ_ZIP_LDH_FILE_DATE_OFS = 12, + MZ_ZIP_LDH_CRC32_OFS = 14, + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, + MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, + MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, + // End of central directory offsets + MZ_ZIP_ECDH_SIG_OFS = 0, + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, + MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, + MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, + MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, +}; + +typedef struct { + void *m_p; + size_t m_size, m_capacity; + mz_uint m_element_size; +} mz_zip_array; + +struct mz_zip_internal_state_tag { + mz_zip_array m_central_dir; + mz_zip_array m_central_dir_offsets; + mz_zip_array m_sorted_central_dir_offsets; + MZ_FILE *m_pFile; + void *m_pMem; + size_t m_mem_size; + size_t m_mem_capacity; +}; + +#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) \ + (array_ptr)->m_element_size = element_size +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \ + ((element_type *)((array_ptr)->m_p))[index] + +static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, + mz_zip_array *pArray) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); + memset(pArray, 0, sizeof(mz_zip_array)); +} + +static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t min_new_capacity, + mz_uint growing) { + void *pNew_p; + size_t new_capacity = min_new_capacity; + MZ_ASSERT(pArray->m_element_size); + if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; + if (growing) { + new_capacity = MZ_MAX(1, pArray->m_capacity); + while (new_capacity < min_new_capacity) new_capacity *= 2; + } + if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, + pArray->m_element_size, new_capacity))) + return MZ_FALSE; + pArray->m_p = pNew_p; + pArray->m_capacity = new_capacity; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t new_capacity, + mz_uint growing) { + if (new_capacity > pArray->m_capacity) { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) + return MZ_FALSE; + } + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t new_size, + mz_uint growing) { + if (new_size > pArray->m_capacity) { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) + return MZ_FALSE; + } + pArray->m_size = new_size; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t n) { + return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, + mz_zip_array *pArray, + const void *pElements, + size_t n) { + size_t orig_size = pArray->m_size; + if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) + return MZ_FALSE; + memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, + pElements, n * pArray->m_element_size); + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) { + struct tm tm; + memset(&tm, 0, sizeof(tm)); + tm.tm_isdst = -1; + tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; + tm.tm_mon = ((dos_date >> 5) & 15) - 1; + tm.tm_mday = dos_date & 31; + tm.tm_hour = (dos_time >> 11) & 31; + tm.tm_min = (dos_time >> 5) & 63; + tm.tm_sec = (dos_time << 1) & 62; + return mktime(&tm); +} + +static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, + mz_uint16 *pDOS_date) { +#ifdef _MSC_VER + struct tm tm_struct; + struct tm *tm = &tm_struct; + errno_t err = localtime_s(tm, &time); + if (err) { + *pDOS_date = 0; + *pDOS_time = 0; + return; + } +#else + struct tm *tm = localtime(&time); +#endif + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + + ((tm->tm_sec) >> 1)); + *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +} +#endif + +#ifndef MINIZ_NO_STDIO +static mz_bool mz_zip_get_file_modified_time(const char *pFilename, + mz_uint16 *pDOS_time, + mz_uint16 *pDOS_date) { +#ifdef MINIZ_NO_TIME + (void)pFilename; + *pDOS_date = *pDOS_time = 0; +#else + struct MZ_FILE_STAT_STRUCT file_stat; + // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 + // bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. + if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; + mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); +#endif // #ifdef MINIZ_NO_TIME + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, + time_t modified_time) { + struct utimbuf t; + t.actime = access_time; + t.modtime = modified_time; + return !utime(pFilename, &t); +} +#endif // #ifndef MINIZ_NO_TIME +#endif // #ifndef MINIZ_NO_STDIO + +static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, + mz_uint32 flags) { + (void)flags; + if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; + + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + + pZip->m_zip_mode = MZ_ZIP_MODE_READING; + pZip->m_archive_size = 0; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, + sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, + sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, + sizeof(mz_uint32)); + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool +mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, + const mz_zip_array *pCentral_dir_offsets, + mz_uint l_index, mz_uint r_index) { + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT( + pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, + l_index)), + *pE; + const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT( + pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), + r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; + pL++; + pR++; + } + return (pL == pE) ? (l_len < r_len) : (l < r); +} + +#define MZ_SWAP_UINT32(a, b) \ + do { \ + mz_uint32 t = a; \ + a = b; \ + b = t; \ + } \ + MZ_MACRO_END + +// Heap sort of lowercased filenames, used to help accelerate plain central +// directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), +// but it could allocate memory.) +static void mz_zip_reader_sort_central_dir_offsets_by_filename( + mz_zip_archive *pZip) { + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT( + &pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + int start = (size - 2) >> 1, end; + while (start >= 0) { + int child, root = start; + for (;;) { + if ((child = (root << 1) + 1) >= size) break; + child += + (((child + 1) < size) && + (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[child], pIndices[child + 1]))); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + start--; + } + + end = size - 1; + while (end > 0) { + int child, root = 0; + MZ_SWAP_UINT32(pIndices[end], pIndices[0]); + for (;;) { + if ((child = (root << 1) + 1) >= end) break; + child += + (((child + 1) < end) && + mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[child], pIndices[child + 1])); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + end--; + } +} + +static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, + mz_uint32 flags) { + mz_uint cdir_size, num_this_disk, cdir_disk_index; + mz_uint64 cdir_ofs; + mz_int64 cur_file_ofs; + const mz_uint8 *p; + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + mz_bool sort_central_dir = + ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); + // Basic sanity checks - reject files which are too small, and check the first + // 4 bytes of the file to make sure a local header is there. + if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + // Find the end of central directory record by scanning the file from the end + // towards the beginning. + cur_file_ofs = + MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); + for (;;) { + int i, + n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) + return MZ_FALSE; + for (i = n - 4; i >= 0; --i) + if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) break; + if (i >= 0) { + cur_file_ofs += i; + break; + } + if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= + (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) + return MZ_FALSE; + cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); + } + // Read and verify the end of central directory record. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || + ((pZip->m_total_files = + MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != + MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) + return MZ_FALSE; + + num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); + cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); + if (((num_this_disk | cdir_disk_index) != 0) && + ((num_this_disk != 1) || (cdir_disk_index != 1))) + return MZ_FALSE; + + if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < + pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + + cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return MZ_FALSE; + + pZip->m_central_directory_file_ofs = cdir_ofs; + + if (pZip->m_total_files) { + mz_uint i, n; + + // Read the entire central directory into a heap block, and allocate another + // heap block to hold the unsorted central dir file record offsets, and + // another to hold the sorted indices. + if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, + MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, + pZip->m_total_files, MZ_FALSE))) + return MZ_FALSE; + + if (sort_central_dir) { + if (!mz_zip_array_resize(pZip, + &pZip->m_pState->m_sorted_central_dir_offsets, + pZip->m_total_files, MZ_FALSE)) + return MZ_FALSE; + } + + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, + pZip->m_pState->m_central_dir.m_p, + cdir_size) != cdir_size) + return MZ_FALSE; + + // Now create an index into the central directory file records, do some + // basic sanity checking on each record, and check for zip64 entries (which + // are not yet supported). + p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; + for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) { + mz_uint total_header_size, comp_size, decomp_size, disk_index; + if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || + (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) + return MZ_FALSE; + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, + i) = + (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + if (sort_central_dir) + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, + mz_uint32, i) = i; + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && + (decomp_size != comp_size)) || + (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || + (comp_size == 0xFFFFFFFF)) + return MZ_FALSE; + disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); + if ((disk_index != num_this_disk) && (disk_index != 1)) return MZ_FALSE; + if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) + return MZ_FALSE; + if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > + n) + return MZ_FALSE; + n -= total_header_size; + p += total_header_size; + } + } + + if (sort_central_dir) + mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, + mz_uint32 flags) { + if ((!pZip) || (!pZip->m_pRead)) return MZ_FALSE; + if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; + pZip->m_archive_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} + +static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, + void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + size_t s = (file_ofs >= pZip->m_archive_size) + ? 0 + : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); + memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); + return s; +} + +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, + size_t size, mz_uint32 flags) { + if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; + pZip->m_archive_size = size; + pZip->m_pRead = mz_zip_mem_read_func; + pZip->m_pIO_opaque = pZip; +#ifdef __cplusplus + pZip->m_pState->m_pMem = const_cast(pMem); +#else + pZip->m_pState->m_pMem = (void *)pMem; +#endif + pZip->m_pState->m_mem_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, + void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || + (((cur_ofs != (mz_int64)file_ofs)) && + (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint32 flags) { + mz_uint64 file_size; + MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb"); + if (!pFile) return MZ_FALSE; + if (MZ_FSEEK64(pFile, 0, SEEK_END)) { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + file_size = MZ_FTELL64(pFile); + if (!mz_zip_reader_init_internal(pZip, flags)) { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + pZip->m_pRead = mz_zip_file_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = file_size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) { + return pZip ? pZip->m_total_files : 0; +} + +static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh( + mz_zip_archive *pZip, mz_uint file_index) { + if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || + (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return NULL; + return &MZ_ZIP_ARRAY_ELEMENT( + &pZip->m_pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, + file_index)); +} + +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, + mz_uint file_index) { + mz_uint m_bit_flag; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) return MZ_FALSE; + m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + return (m_bit_flag & 1); +} + +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, + mz_uint file_index) { + mz_uint filename_len, external_attr; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) return MZ_FALSE; + + // First see if the filename ends with a '/' character. + filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_len) { + if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') + return MZ_TRUE; + } + + // Bugfix: This code was also checking if the internal attribute was non-zero, + // which wasn't correct. + // Most/all zip writers (hopefully) set DOS file/directory attributes in the + // low 16-bits, so check for the DOS directory flag and ignore the source OS + // ID in the created by field. + // FIXME: Remove this check? Is it necessary - we already check the filename. + external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + if ((external_attr & 0x10) != 0) return MZ_TRUE; + + return MZ_FALSE; +} + +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, + mz_zip_archive_file_stat *pStat) { + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if ((!p) || (!pStat)) return MZ_FALSE; + + // Unpack the central directory record. + pStat->m_file_index = file_index; + pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT( + &pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); + pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); + pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); + pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +#ifndef MINIZ_NO_TIME + pStat->m_time = + mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), + MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +#endif + pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); + pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + + // Copy as much of the filename and comment as possible. + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); + memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pStat->m_filename[n] = '\0'; + + n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); + pStat->m_comment_size = n; + memcpy(pStat->m_comment, + p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), + n); + pStat->m_comment[n] = '\0'; + + return MZ_TRUE; +} + +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, + char *pFilename, mz_uint filename_buf_size) { + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) { + if (filename_buf_size) pFilename[0] = '\0'; + return 0; + } + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_buf_size) { + n = MZ_MIN(n, filename_buf_size - 1); + memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pFilename[n] = '\0'; + } + return n + 1; +} + +static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, + const char *pB, + mz_uint len, + mz_uint flags) { + mz_uint i; + if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len); + for (i = 0; i < len; ++i) + if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) return MZ_FALSE; + return MZ_TRUE; +} + +static MZ_FORCEINLINE int mz_zip_reader_filename_compare( + const mz_zip_array *pCentral_dir_array, + const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, + mz_uint r_len) { + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT( + pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, + l_index)), + *pE; + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; + pL++; + pR++; + } + return (pL == pE) ? (int)(l_len - r_len) : (l - r); +} + +static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, + const char *pFilename) { + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT( + &pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + const mz_uint filename_len = (mz_uint)strlen(pFilename); + int l = 0, h = size - 1; + while (l <= h) { + int m = (l + h) >> 1, file_index = pIndices[m], + comp = + mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, + file_index, pFilename, filename_len); + if (!comp) + return file_index; + else if (comp < 0) + l = m + 1; + else + h = m - 1; + } + return -1; +} + +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, + const char *pComment, mz_uint flags) { + mz_uint file_index; + size_t name_len, comment_len; + if ((!pZip) || (!pZip->m_pState) || (!pName) || + (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return -1; + if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && + (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) + return mz_zip_reader_locate_file_binary_search(pZip, pName); + name_len = strlen(pName); + if (name_len > 0xFFFF) return -1; + comment_len = pComment ? strlen(pComment) : 0; + if (comment_len > 0xFFFF) return -1; + for (file_index = 0; file_index < pZip->m_total_files; file_index++) { + const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT( + &pZip->m_pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, + file_index)); + mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); + const char *pFilename = + (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + if (filename_len < name_len) continue; + if (comment_len) { + mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), + file_comment_len = + MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); + const char *pFile_comment = pFilename + filename_len + file_extra_len; + if ((file_comment_len != comment_len) || + (!mz_zip_reader_string_equal(pComment, pFile_comment, + file_comment_len, flags))) + continue; + } + if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) { + int ofs = filename_len - 1; + do { + if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || + (pFilename[ofs] == ':')) + break; + } while (--ofs >= 0); + ofs++; + pFilename += ofs; + filename_len -= ofs; + } + if ((filename_len == name_len) && + (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) + return file_index; + } + return -1; +} + +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, + mz_uint file_index, void *pBuf, + size_t buf_size, mz_uint flags, + void *pUser_read_buf, + size_t user_read_buf_size) { + int status = TINFL_STATUS_DONE; + mz_uint64 needed_size, cur_file_ofs, comp_remaining, + out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + mz_uint32 + local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / + sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + tinfl_decompressor inflator; + + if ((buf_size) && (!pBuf)) return MZ_FALSE; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; + + // Empty file, or a directory (but not always a directory - I've seen odd zips + // with directories that have compressed data which inflates to 0 bytes) + if (!file_stat.m_comp_size) return MZ_TRUE; + + // Entry is a subdirectory (I've seen old zips with dir entries which have + // compressed deflate data which inflates to 0 bytes, but these entries claim + // to uncompress to 512 bytes in the headers). + // I'm torn how to handle this case - should it fail instead? + if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; + + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE; + + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && + (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; + + // Ensure supplied output buffer is large enough. + needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size + : file_stat.m_uncomp_size; + if (buf_size < needed_size) return MZ_FALSE; + + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, + (size_t)needed_size) != needed_size) + return MZ_FALSE; + return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || + (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, + (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); + } + + // Decompress the file either directly from memory or from a file input + // buffer. + tinfl_init(&inflator); + + if (pZip->m_pState->m_pMem) { + // Read directly from the archive in memory. + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } else if (pUser_read_buf) { + // Use a user provided read buffer. + if (!user_read_buf_size) return MZ_FALSE; + pRead_buf = (mz_uint8 *)pUser_read_buf; + read_buf_size = user_read_buf_size; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } else { + // Temporarily allocate a read buffer. + read_buf_size = + MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE); +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && + (read_buf_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +#endif + return MZ_FALSE; + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + do { + size_t in_buf_size, + out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress( + &inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, + (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | + (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + out_buf_ofs += out_buf_size; + } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + + if (status == TINFL_STATUS_DONE) { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || + (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, + (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } + + if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc( + mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, + mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) return MZ_FALSE; + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, + flags, pUser_read_buf, + user_read_buf_size); +} + +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, + void *pBuf, size_t buf_size, + mz_uint flags) { + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, + flags, NULL, 0); +} + +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, + const char *pFilename, void *pBuf, + size_t buf_size, mz_uint flags) { + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, + buf_size, flags, NULL, 0); +} + +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, + size_t *pSize, mz_uint flags) { + mz_uint64 comp_size, uncomp_size, alloc_size; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + void *pBuf; + + if (pSize) *pSize = 0; + if (!p) return NULL; + + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + + alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#endif + return NULL; + if (NULL == + (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) + return NULL; + + if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, + flags)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return NULL; + } + + if (pSize) *pSize = (size_t)alloc_size; + return pBuf; +} + +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, + const char *pFilename, size_t *pSize, + mz_uint flags) { + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) { + if (pSize) *pSize = 0; + return MZ_FALSE; + } + return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +} + +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, + mz_uint file_index, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags) { + int status = TINFL_STATUS_DONE; + mz_uint file_crc32 = MZ_CRC32_INIT; + mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, + out_buf_ofs = 0, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf = NULL; + void *pWrite_buf = NULL; + mz_uint32 + local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / + sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; + + // Empty file, or a directory (but not always a directory - I've seen odd zips + // with directories that have compressed data which inflates to 0 bytes) + if (!file_stat.m_comp_size) return MZ_TRUE; + + // Entry is a subdirectory (I've seen old zips with dir entries which have + // compressed deflate data which inflates to 0 bytes, but these entries claim + // to uncompress to 512 bytes in the headers). + // I'm torn how to handle this case - should it fail instead? + if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; + + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE; + + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && + (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; + + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; + + // Decompress the file either directly from memory or from a file input + // buffer. + if (pZip->m_pState->m_pMem) { + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } else { + read_buf_size = + MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pState->m_pMem) { +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && + (file_stat.m_comp_size > 0xFFFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && + (file_stat.m_comp_size > 0xFFFFFFFF)) +#endif + return MZ_FALSE; + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, + (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) + status = TINFL_STATUS_FAILED; + else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = + (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, + (size_t)file_stat.m_comp_size); + cur_file_ofs += file_stat.m_comp_size; + out_buf_ofs += file_stat.m_comp_size; + comp_remaining = 0; + } else { + while (comp_remaining) { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + + if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = (mz_uint32)mz_crc32( + file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + out_buf_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + } + } + } else { + tinfl_decompressor inflator; + tinfl_init(&inflator); + + if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + TINFL_LZ_DICT_SIZE))) + status = TINFL_STATUS_FAILED; + else { + do { + mz_uint8 *pWrite_buf_cur = + (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + size_t in_buf_size, + out_buf_size = + TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress( + &inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, + (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, + comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + + if (out_buf_size) { + if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != + out_buf_size) { + status = TINFL_STATUS_FAILED; + break; + } + file_crc32 = + (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); + if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) { + status = TINFL_STATUS_FAILED; + break; + } + } + } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || + (status == TINFL_STATUS_HAS_MORE_OUTPUT)); + } + } + + if ((status == TINFL_STATUS_DONE) && + (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || + (file_crc32 != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } + + if (!pZip->m_pState->m_pMem) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + if (pWrite_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, + const char *pFilename, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags) { + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) return MZ_FALSE; + return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, + flags); +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, + const void *pBuf, size_t n) { + (void)ofs; + return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); +} + +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, + const char *pDst_filename, + mz_uint flags) { + mz_bool status; + mz_zip_archive_file_stat file_stat; + MZ_FILE *pFile; + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; + pFile = MZ_FOPEN(pDst_filename, "wb"); + if (!pFile) return MZ_FALSE; + status = mz_zip_reader_extract_to_callback( + pZip, file_index, mz_zip_file_write_callback, pFile, flags); + if (MZ_FCLOSE(pFile) == EOF) return MZ_FALSE; +#ifndef MINIZ_NO_TIME + if (status) + mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +#endif + return status; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_reader_end(mz_zip_archive *pZip) { + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || + (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return MZ_FALSE; + + if (pZip->m_pState) { + mz_zip_internal_state *pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + } + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, + const char *pArchive_filename, + const char *pDst_filename, + mz_uint flags) { + int file_index = + mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); + if (file_index < 0) return MZ_FALSE; + return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +} +#endif + +// ------------------- .ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); +} +static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); + p[2] = (mz_uint8)(v >> 16); + p[3] = (mz_uint8)(v >> 24); +} +#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) + +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) { + if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || + (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; + + if (pZip->m_file_offset_alignment) { + // Ensure user specified file offset alignment is a power of 2. + if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) + return MZ_FALSE; + } + + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_archive_size = existing_size; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, + sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, + sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, + sizeof(mz_uint32)); + return MZ_TRUE; +} + +static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, + const void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); +#ifdef _MSC_VER + if ((!n) || + ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#else + if ((!n) || + ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#endif + return 0; + if (new_size > pState->m_mem_capacity) { + void *pNew_block; + size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + while (new_capacity < new_size) new_capacity *= 2; + if (NULL == (pNew_block = pZip->m_pRealloc( + pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) + return 0; + pState->m_pMem = pNew_block; + pState->m_mem_capacity = new_capacity; + } + memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); + pState->m_mem_size = (size_t)new_size; + return n; +} + +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, + size_t size_to_reserve_at_beginning, + size_t initial_allocation_size) { + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; + if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, + size_to_reserve_at_beginning))) { + if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, initial_allocation_size))) { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_mem_capacity = initial_allocation_size; + } + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, + const void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || + (((cur_ofs != (mz_int64)file_ofs)) && + (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint64 size_to_reserve_at_beginning) { + MZ_FILE *pFile; + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; + if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_pFile = pFile; + if (size_to_reserve_at_beginning) { + mz_uint64 cur_ofs = 0; + char buf[4096]; + MZ_CLEAR_OBJ(buf); + do { + size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + cur_ofs += n; + size_to_reserve_at_beginning -= n; + } while (size_to_reserve_at_beginning); + } + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, + const char *pFilename) { + mz_zip_internal_state *pState; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return MZ_FALSE; + // No sense in trying to write to an archive that's already at the support max + // size + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + pState = pZip->m_pState; + + if (pState->m_pFile) { +#ifdef MINIZ_NO_STDIO + pFilename; + return MZ_FALSE; +#else + // Archive is being read from stdio - try to reopen as writable. + if (pZip->m_pIO_opaque != pZip) return MZ_FALSE; + if (!pFilename) return MZ_FALSE; + pZip->m_pWrite = mz_zip_file_write_func; + if (NULL == + (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) { + // The mz_zip_archive is now in a bogus state because pState->m_pFile is + // NULL, so just close it. + mz_zip_reader_end(pZip); + return MZ_FALSE; + } +#endif // #ifdef MINIZ_NO_STDIO + } else if (pState->m_pMem) { + // Archive lives in a memory block. Assume it's from the heap that we can + // resize using the realloc callback. + if (pZip->m_pIO_opaque != pZip) return MZ_FALSE; + pState->m_mem_capacity = pState->m_mem_size; + pZip->m_pWrite = mz_zip_heap_write_func; + } + // Archive is being read via a user provided read function - make sure the + // user has specified a write function too. + else if (!pZip->m_pWrite) + return MZ_FALSE; + + // Start writing new files at the archive's current central directory + // location. + pZip->m_archive_size = pZip->m_central_directory_file_ofs; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_central_directory_file_ofs = 0; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, + const void *pBuf, size_t buf_size, + mz_uint level_and_flags) { + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, + level_and_flags, 0, 0); +} + +typedef struct { + mz_zip_archive *m_pZip; + mz_uint64 m_cur_archive_file_ofs; + mz_uint64 m_comp_size; +} mz_zip_writer_add_state; + +static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, + void *pUser) { + mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; + if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, + pState->m_cur_archive_file_ofs, pBuf, + len) != len) + return MZ_FALSE; + pState->m_cur_archive_file_ofs += len; + pState->m_comp_size += len; + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_local_dir_header( + mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, + mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, + mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, + mz_uint16 dos_time, mz_uint16 dos_date) { + (void)pZip; + memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_central_dir_header( + mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, + mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, + mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, + mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, + mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { + (void)pZip; + memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_add_to_central_dir( + mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, + const void *pExtra, mz_uint16 extra_size, const void *pComment, + mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, + mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, + mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, + mz_uint32 ext_attributes) { + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; + size_t orig_central_dir_size = pState->m_central_dir.m_size; + mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + + // No zip64 support yet + if ((local_header_ofs > 0xFFFFFFFF) || + (((mz_uint64)pState->m_central_dir.m_size + + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + + comment_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_central_dir_header( + pZip, central_dir_header, filename_size, extra_size, comment_size, + uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, + dos_date, local_header_ofs, ext_attributes)) + return MZ_FALSE; + + if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, + filename_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, + extra_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, + comment_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, + ¢ral_dir_ofs, 1))) { + // Try to push the central directory array back into its original state. + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, + MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) { + // Basic ZIP archive filename validity checks: Valid filenames cannot start + // with a forward slash, cannot contain a drive letter, and cannot use + // DOS-style backward slashes. + if (*pArchive_name == '/') return MZ_FALSE; + while (*pArchive_name) { + if ((*pArchive_name == '\\') || (*pArchive_name == ':')) return MZ_FALSE; + pArchive_name++; + } + return MZ_TRUE; +} + +static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment( + mz_zip_archive *pZip) { + mz_uint32 n; + if (!pZip->m_file_offset_alignment) return 0; + n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); + return (pZip->m_file_offset_alignment - n) & + (pZip->m_file_offset_alignment - 1); +} + +static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, + mz_uint64 cur_file_ofs, mz_uint32 n) { + char buf[4096]; + memset(buf, 0, MZ_MIN(sizeof(buf), n)); + while (n) { + mz_uint32 s = MZ_MIN(sizeof(buf), n); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) + return MZ_FALSE; + cur_file_ofs += s; + n -= s; + } + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, + const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, + mz_uint16 comment_size, + mz_uint level_and_flags, mz_uint64 uncomp_size, + mz_uint32 uncomp_crc32) { + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, + cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + tdefl_compressor *pComp = NULL; + mz_bool store_data_uncompressed; + mz_zip_internal_state *pState; + + if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + store_data_uncompressed = + ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + + if ((!pZip) || (!pZip->m_pState) || + (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || + (!pArchive_name) || ((comment_size) && (!pComment)) || + (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + + pState = pZip->m_pState; + + if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) + return MZ_FALSE; + // No zip64 support yet + if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; + +#ifndef MINIZ_NO_TIME + { + time_t cur_time; + time(&cur_time); + mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); + } +#endif // #ifndef MINIZ_NO_TIME + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) return MZ_FALSE; + + num_alignment_padding_bytes = + mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + comment_size + archive_name_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) { + // Set DOS Subdirectory attribute bit. + ext_attributes |= 0x10; + // Subdirectories cannot contain data. + if ((buf_size) || (uncomp_size)) return MZ_FALSE; + } + + // Try to do any allocations before writing to the archive, so if an + // allocation fails the file remains unmodified. (A good idea if we're doing + // an in-place modification.) + if ((!mz_zip_array_ensure_room( + pZip, &pState->m_central_dir, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || + (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) + return MZ_FALSE; + + if ((!store_data_uncompressed) && (buf_size)) { + if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) + return MZ_FALSE; + } + + if (!mz_zip_writer_write_zeros( + pZip, cur_archive_file_ofs, + num_alignment_padding_bytes + sizeof(local_dir_header))) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == + 0); + } + cur_archive_file_ofs += + num_alignment_padding_bytes + sizeof(local_dir_header); + + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, + archive_name_size) != archive_name_size) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + + if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { + uncomp_crc32 = + (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); + uncomp_size = buf_size; + if (uncomp_size <= 3) { + level = 0; + store_data_uncompressed = MZ_TRUE; + } + } + + if (store_data_uncompressed) { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, + buf_size) != buf_size) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + cur_archive_file_ofs += buf_size; + comp_size = buf_size; + + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) method = MZ_DEFLATED; + } else if (buf_size) { + mz_zip_writer_add_state state; + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, + tdefl_create_comp_flags_from_zip_params( + level, -15, MZ_DEFAULT_STRATEGY)) != + TDEFL_STATUS_OKAY) || + (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != + TDEFL_STATUS_DONE)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + + method = MZ_DEFLATED; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pComp = NULL; + + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_local_dir_header( + pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, + comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, + sizeof(local_dir_header)) != sizeof(local_dir_header)) + return MZ_FALSE; + + if (!mz_zip_writer_add_to_central_dir( + pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, + dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, + const char *pSrc_filename, const void *pComment, + mz_uint16 comment_size, + mz_uint level_and_flags) { + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, + cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, + comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + MZ_FILE *pSrc_file = NULL; + + if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + + if ((!pZip) || (!pZip->m_pState) || + (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || + ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) return MZ_FALSE; + + num_alignment_padding_bytes = + mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + comment_size + archive_name_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) + return MZ_FALSE; + + pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); + if (!pSrc_file) return MZ_FALSE; + MZ_FSEEK64(pSrc_file, 0, SEEK_END); + uncomp_size = MZ_FTELL64(pSrc_file); + MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + + if (uncomp_size > 0xFFFFFFFF) { + // No zip64 support yet + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + if (uncomp_size <= 3) level = 0; + + if (!mz_zip_writer_write_zeros( + pZip, cur_archive_file_ofs, + num_alignment_padding_bytes + sizeof(local_dir_header))) { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == + 0); + } + cur_archive_file_ofs += + num_alignment_padding_bytes + sizeof(local_dir_header); + + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, + archive_name_size) != archive_name_size) { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + + if (uncomp_size) { + mz_uint64 uncomp_remaining = uncomp_size; + void *pRead_buf = + pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); + if (!pRead_buf) { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + if (!level) { + while (uncomp_remaining) { + mz_uint n = + (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); + if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || + (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, + n) != n)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + uncomp_crc32 = + (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + uncomp_remaining -= n; + cur_archive_file_ofs += n; + } + comp_size = uncomp_size; + } else { + mz_bool result = MZ_FALSE; + mz_zip_writer_add_state state; + tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, + tdefl_create_comp_flags_from_zip_params( + level, -15, MZ_DEFAULT_STRATEGY)) != + TDEFL_STATUS_OKAY) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + for (;;) { + size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, + (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE); + tdefl_status status; + + if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) + break; + + uncomp_crc32 = (mz_uint32)mz_crc32( + uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); + uncomp_remaining -= in_buf_size; + + status = tdefl_compress_buffer( + pComp, pRead_buf, in_buf_size, + uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); + if (status == TDEFL_STATUS_DONE) { + result = MZ_TRUE; + break; + } else if (status != TDEFL_STATUS_OKAY) + break; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + + if (!result) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + + method = MZ_DEFLATED; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } + + MZ_FCLOSE(pSrc_file); + pSrc_file = NULL; + + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_local_dir_header( + pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, + comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, + sizeof(local_dir_header)) != sizeof(local_dir_header)) + return MZ_FALSE; + + if (!mz_zip_writer_add_to_central_dir( + pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, + dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, + mz_zip_archive *pSource_zip, + mz_uint file_index) { + mz_uint n, bit_flags, num_alignment_padding_bytes; + mz_uint64 comp_bytes_remaining, local_dir_header_ofs; + mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; + mz_uint32 + local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / + sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + size_t orig_central_dir_size; + mz_zip_internal_state *pState; + void *pBuf; + const mz_uint8 *pSrc_central_header; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; + if (NULL == + (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) + return MZ_FALSE; + pState = pZip->m_pState; + + num_alignment_padding_bytes = + mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > + 0xFFFFFFFF)) + return MZ_FALSE; + + cur_src_file_ofs = + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + cur_dst_file_ofs = pZip->m_archive_size; + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, + pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, + num_alignment_padding_bytes)) + return MZ_FALSE; + cur_dst_file_ofs += num_alignment_padding_bytes; + local_dir_header_ofs = cur_dst_file_ofs; + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == + 0); + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + comp_bytes_remaining = + n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + + if (NULL == (pBuf = pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, + (size_t)MZ_MAX(sizeof(mz_uint32) * 4, + MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, + comp_bytes_remaining))))) + return MZ_FALSE; + + while (comp_bytes_remaining) { + n = (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, + n) != n) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_src_file_ofs += n; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_dst_file_ofs += n; + + comp_bytes_remaining -= n; + } + + bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + if (bit_flags & 8) { + // Copy data descriptor + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, + sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + + n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + + cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + + // no zip64 support yet + if (cur_dst_file_ofs > 0xFFFFFFFF) return MZ_FALSE; + + orig_central_dir_size = pState->m_central_dir.m_size; + + memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, + local_dir_header_ofs); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + return MZ_FALSE; + + n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); + if (!mz_zip_array_push_back( + pZip, &pState->m_central_dir, + pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, + MZ_FALSE); + return MZ_FALSE; + } + + if (pState->m_central_dir.m_size > 0xFFFFFFFF) return MZ_FALSE; + n = (mz_uint32)orig_central_dir_size; + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, + MZ_FALSE); + return MZ_FALSE; + } + + pZip->m_total_files++; + pZip->m_archive_size = cur_dst_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { + mz_zip_internal_state *pState; + mz_uint64 central_dir_ofs, central_dir_size; + mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; + + pState = pZip->m_pState; + + // no zip64 support yet + if ((pZip->m_total_files > 0xFFFF) || + ((pZip->m_archive_size + pState->m_central_dir.m_size + + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + central_dir_ofs = 0; + central_dir_size = 0; + if (pZip->m_total_files) { + // Write central directory + central_dir_ofs = pZip->m_archive_size; + central_dir_size = pState->m_central_dir.m_size; + pZip->m_central_directory_file_ofs = central_dir_ofs; + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, + pState->m_central_dir.m_p, + (size_t)central_dir_size) != central_dir_size) + return MZ_FALSE; + pZip->m_archive_size += central_dir_size; + } + + // Write end of central directory record + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, + pZip->m_total_files); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, + sizeof(hdr)) != sizeof(hdr)) + return MZ_FALSE; +#ifndef MINIZ_NO_STDIO + if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) return MZ_FALSE; +#endif // #ifndef MINIZ_NO_STDIO + + pZip->m_archive_size += sizeof(hdr); + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, + size_t *pSize) { + if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) return MZ_FALSE; + if (pZip->m_pWrite != mz_zip_heap_write_func) return MZ_FALSE; + if (!mz_zip_writer_finalize_archive(pZip)) return MZ_FALSE; + + *pBuf = pZip->m_pState->m_pMem; + *pSize = pZip->m_pState->m_mem_size; + pZip->m_pState->m_pMem = NULL; + pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_end(mz_zip_archive *pZip) { + mz_zip_internal_state *pState; + mz_bool status = MZ_TRUE; + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || + ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && + (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) + return MZ_FALSE; + + pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + + if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); + pState->m_pMem = NULL; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + return status; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_add_mem_to_archive_file_in_place( + const char *pZip_filename, const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, mz_uint16 comment_size, + mz_uint level_and_flags) { + mz_bool status, created_new_archive = MZ_FALSE; + mz_zip_archive zip_archive; + struct MZ_FILE_STAT_STRUCT file_stat; + MZ_CLEAR_OBJ(zip_archive); + if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; + if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || + ((comment_size) && (!pComment)) || + ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; + if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) { + // Create a new archive. + if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) + return MZ_FALSE; + created_new_archive = MZ_TRUE; + } else { + // Append to an existing archive. + if (!mz_zip_reader_init_file( + &zip_archive, pZip_filename, + level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return MZ_FALSE; + if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) { + mz_zip_reader_end(&zip_archive); + return MZ_FALSE; + } + } + status = + mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, + pComment, comment_size, level_and_flags, 0, 0); + // Always finalize, even if adding failed for some reason, so we have a valid + // central directory. (This may not always succeed, but we can try.) + if (!mz_zip_writer_finalize_archive(&zip_archive)) status = MZ_FALSE; + if (!mz_zip_writer_end(&zip_archive)) status = MZ_FALSE; + if ((!status) && (created_new_archive)) { + // It's a new archive and something went wrong, so just delete it. + int ignoredStatus = MZ_DELETE_FILE(pZip_filename); + (void)ignoredStatus; + } + return status; +} + +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, + const char *pArchive_name, + size_t *pSize, mz_uint flags) { + int file_index; + mz_zip_archive zip_archive; + void *p = NULL; + + if (pSize) *pSize = 0; + + if ((!pZip_filename) || (!pArchive_name)) return NULL; + + MZ_CLEAR_OBJ(zip_archive); + if (!mz_zip_reader_init_file( + &zip_archive, pZip_filename, + flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return NULL; + + if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, + flags)) >= 0) + p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); + + mz_zip_reader_end(&zip_archive); + return p; +} + +#endif // #ifndef MINIZ_NO_STDIO + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +} +#endif + +#endif // MINIZ_HEADER_FILE_ONLY + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ + +// ---------------------- end of miniz ---------------------------------------- + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif +} // namespace miniz +#else + +// Reuse MINIZ_LITTE_ENDIAN macro + +#if defined(__sparcv9) +// Big endian +#else +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#endif +#endif + +#endif // TINYEXR_USE_MINIZ + +// static bool IsBigEndian(void) { +// union { +// unsigned int i; +// char c[4]; +// } bint = {0x01020304}; +// +// return bint.c[0] == 1; +//} + +static void SetErrorMessage(const std::string &msg, const char **err) { + if (err) { +#ifdef _WIN32 + (*err) = _strdup(msg.c_str()); +#else + (*err) = strdup(msg.c_str()); +#endif + } +} + +static const int kEXRVersionSize = 8; + +static void cpy2(unsigned short *dst_val, const unsigned short *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; +} + +static void swap2(unsigned short *val) { +#ifdef MINIZ_LITTLE_ENDIAN + (void)val; +#else + unsigned short tmp = *val; + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[1]; + dst[1] = src[0]; +#endif +} + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif +static void cpy4(int *dst_val, const int *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} + +static void cpy4(unsigned int *dst_val, const unsigned int *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} + +static void cpy4(float *dst_val, const float *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +static void swap4(unsigned int *val) { +#ifdef MINIZ_LITTLE_ENDIAN + (void)val; +#else + unsigned int tmp = *val; + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; +#endif +} + +#if 0 +static void cpy8(tinyexr::tinyexr_uint64 *dst_val, const tinyexr::tinyexr_uint64 *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +} +#endif + +static void swap8(tinyexr::tinyexr_uint64 *val) { +#ifdef MINIZ_LITTLE_ENDIAN + (void)val; +#else + tinyexr::tinyexr_uint64 tmp = (*val); + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[7]; + dst[1] = src[6]; + dst[2] = src[5]; + dst[3] = src[4]; + dst[4] = src[3]; + dst[5] = src[2]; + dst[6] = src[1]; + dst[7] = src[0]; +#endif +} + +// https://gist.github.com/rygorous/2156668 +// Reuse MINIZ_LITTLE_ENDIAN flag from miniz. +union FP32 { + unsigned int u; + float f; + struct { +#if MINIZ_LITTLE_ENDIAN + unsigned int Mantissa : 23; + unsigned int Exponent : 8; + unsigned int Sign : 1; +#else + unsigned int Sign : 1; + unsigned int Exponent : 8; + unsigned int Mantissa : 23; +#endif + } s; +}; + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +union FP16 { + unsigned short u; + struct { +#if MINIZ_LITTLE_ENDIAN + unsigned int Mantissa : 10; + unsigned int Exponent : 5; + unsigned int Sign : 1; +#else + unsigned int Sign : 1; + unsigned int Exponent : 5; + unsigned int Mantissa : 10; +#endif + } s; +}; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +static FP32 half_to_float(FP16 h) { + static const FP32 magic = {113 << 23}; + static const unsigned int shifted_exp = 0x7c00 + << 13; // exponent mask after shift + FP32 o; + + o.u = (h.u & 0x7fffU) << 13U; // exponent/mantissa bits + unsigned int exp_ = shifted_exp & o.u; // just the exponent + o.u += (127 - 15) << 23; // exponent adjust + + // handle exponent special cases + if (exp_ == shifted_exp) // Inf/NaN? + o.u += (128 - 16) << 23; // extra exp adjust + else if (exp_ == 0) // Zero/Denormal? + { + o.u += 1 << 23; // extra exp adjust + o.f -= magic.f; // renormalize + } + + o.u |= (h.u & 0x8000U) << 16U; // sign bit + return o; +} + +static FP16 float_to_half_full(FP32 f) { + FP16 o = {0}; + + // Based on ISPC reference code (with minor modifications) + if (f.s.Exponent == 0) // Signed zero/denormal (which will underflow) + o.s.Exponent = 0; + else if (f.s.Exponent == 255) // Inf or NaN (all exponent bits set) + { + o.s.Exponent = 31; + o.s.Mantissa = f.s.Mantissa ? 0x200 : 0; // NaN->qNaN and Inf->Inf + } else // Normalized number + { + // Exponent unbias the single, then bias the halfp + int newexp = f.s.Exponent - 127 + 15; + if (newexp >= 31) // Overflow, return signed infinity + o.s.Exponent = 31; + else if (newexp <= 0) // Underflow + { + if ((14 - newexp) <= 24) // Mantissa might be non-zero + { + unsigned int mant = f.s.Mantissa | 0x800000; // Hidden 1 bit + o.s.Mantissa = mant >> (14 - newexp); + if ((mant >> (13 - newexp)) & 1) // Check for rounding + o.u++; // Round, might overflow into exp bit, but this is OK + } + } else { + o.s.Exponent = static_cast(newexp); + o.s.Mantissa = f.s.Mantissa >> 13; + if (f.s.Mantissa & 0x1000) // Check for rounding + o.u++; // Round, might overflow to inf, this is OK + } + } + + o.s.Sign = f.s.Sign; + return o; +} + +// NOTE: From OpenEXR code +// #define IMF_INCREASING_Y 0 +// #define IMF_DECREASING_Y 1 +// #define IMF_RAMDOM_Y 2 +// +// #define IMF_NO_COMPRESSION 0 +// #define IMF_RLE_COMPRESSION 1 +// #define IMF_ZIPS_COMPRESSION 2 +// #define IMF_ZIP_COMPRESSION 3 +// #define IMF_PIZ_COMPRESSION 4 +// #define IMF_PXR24_COMPRESSION 5 +// #define IMF_B44_COMPRESSION 6 +// #define IMF_B44A_COMPRESSION 7 + +#ifdef __clang__ +#pragma clang diagnostic push + +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#endif + +static const char *ReadString(std::string *s, const char *ptr, size_t len) { + // Read untile NULL(\0). + const char *p = ptr; + const char *q = ptr; + while ((size_t(q - ptr) < len) && (*q) != 0) { + q++; + } + + if (size_t(q - ptr) >= len) { + (*s) = std::string(); + return NULL; + } + + (*s) = std::string(p, q); + + return q + 1; // skip '\0' +} + +static bool ReadAttribute(std::string *name, std::string *type, + std::vector *data, size_t *marker_size, + const char *marker, size_t size) { + size_t name_len = strnlen(marker, size); + if (name_len == size) { + // String does not have a terminating character. + return false; + } + *name = std::string(marker, name_len); + + marker += name_len + 1; + size -= name_len + 1; + + size_t type_len = strnlen(marker, size); + if (type_len == size) { + return false; + } + *type = std::string(marker, type_len); + + marker += type_len + 1; + size -= type_len + 1; + + if (size < sizeof(uint32_t)) { + return false; + } + + uint32_t data_len; + memcpy(&data_len, marker, sizeof(uint32_t)); + tinyexr::swap4(reinterpret_cast(&data_len)); + + if (data_len == 0) { + if ((*type).compare("string") == 0) { + // Accept empty string attribute. + + marker += sizeof(uint32_t); + size -= sizeof(uint32_t); + + *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t); + + data->resize(1); + (*data)[0] = '\0'; + + return true; + } else { + return false; + } + } + + marker += sizeof(uint32_t); + size -= sizeof(uint32_t); + + if (size < data_len) { + return false; + } + + data->resize(static_cast(data_len)); + memcpy(&data->at(0), marker, static_cast(data_len)); + + *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t) + data_len; + return true; +} + +static void WriteAttributeToMemory(std::vector *out, + const char *name, const char *type, + const unsigned char *data, int len) { + out->insert(out->end(), name, name + strlen(name) + 1); + out->insert(out->end(), type, type + strlen(type) + 1); + + int outLen = len; + tinyexr::swap4(reinterpret_cast(&outLen)); + out->insert(out->end(), reinterpret_cast(&outLen), + reinterpret_cast(&outLen) + sizeof(int)); + out->insert(out->end(), data, data + len); +} + +typedef struct { + std::string name; // less than 255 bytes long + int pixel_type; + int x_sampling; + int y_sampling; + unsigned char p_linear; + unsigned char pad[3]; +} ChannelInfo; + +typedef struct HeaderInfo { + std::vector channels; + std::vector attributes; + + int data_window[4]; + int line_order; + int display_window[4]; + float screen_window_center[2]; + float screen_window_width; + float pixel_aspect_ratio; + + int chunk_count; + + // Tiled format + int tile_size_x; + int tile_size_y; + int tile_level_mode; + int tile_rounding_mode; + + unsigned int header_len; + + int compression_type; + + void clear() { + channels.clear(); + attributes.clear(); + + data_window[0] = 0; + data_window[1] = 0; + data_window[2] = 0; + data_window[3] = 0; + line_order = 0; + display_window[0] = 0; + display_window[1] = 0; + display_window[2] = 0; + display_window[3] = 0; + screen_window_center[0] = 0.0f; + screen_window_center[1] = 0.0f; + screen_window_width = 0.0f; + pixel_aspect_ratio = 0.0f; + + chunk_count = 0; + + // Tiled format + tile_size_x = 0; + tile_size_y = 0; + tile_level_mode = 0; + tile_rounding_mode = 0; + + header_len = 0; + compression_type = 0; + } +} HeaderInfo; + +static bool ReadChannelInfo(std::vector &channels, + const std::vector &data) { + const char *p = reinterpret_cast(&data.at(0)); + + for (;;) { + if ((*p) == 0) { + break; + } + ChannelInfo info; + + tinyexr_int64 data_len = static_cast(data.size()) - + (p - reinterpret_cast(data.data())); + if (data_len < 0) { + return false; + } + + p = ReadString(&info.name, p, size_t(data_len)); + if ((p == NULL) && (info.name.empty())) { + // Buffer overrun. Issue #51. + return false; + } + + const unsigned char *data_end = + reinterpret_cast(p) + 16; + if (data_end >= (data.data() + data.size())) { + return false; + } + + memcpy(&info.pixel_type, p, sizeof(int)); + p += 4; + info.p_linear = static_cast(p[0]); // uchar + p += 1 + 3; // reserved: uchar[3] + memcpy(&info.x_sampling, p, sizeof(int)); // int + p += 4; + memcpy(&info.y_sampling, p, sizeof(int)); // int + p += 4; + + tinyexr::swap4(reinterpret_cast(&info.pixel_type)); + tinyexr::swap4(reinterpret_cast(&info.x_sampling)); + tinyexr::swap4(reinterpret_cast(&info.y_sampling)); + + channels.push_back(info); + } + + return true; +} + +static void WriteChannelInfo(std::vector &data, + const std::vector &channels) { + size_t sz = 0; + + // Calculate total size. + for (size_t c = 0; c < channels.size(); c++) { + sz += strlen(channels[c].name.c_str()) + 1; // +1 for \0 + sz += 16; // 4 * int + } + data.resize(sz + 1); + + unsigned char *p = &data.at(0); + + for (size_t c = 0; c < channels.size(); c++) { + memcpy(p, channels[c].name.c_str(), strlen(channels[c].name.c_str())); + p += strlen(channels[c].name.c_str()); + (*p) = '\0'; + p++; + + int pixel_type = channels[c].pixel_type; + int x_sampling = channels[c].x_sampling; + int y_sampling = channels[c].y_sampling; + tinyexr::swap4(reinterpret_cast(&pixel_type)); + tinyexr::swap4(reinterpret_cast(&x_sampling)); + tinyexr::swap4(reinterpret_cast(&y_sampling)); + + memcpy(p, &pixel_type, sizeof(int)); + p += sizeof(int); + + (*p) = channels[c].p_linear; + p += 4; + + memcpy(p, &x_sampling, sizeof(int)); + p += sizeof(int); + + memcpy(p, &y_sampling, sizeof(int)); + p += sizeof(int); + } + + (*p) = '\0'; +} + +static void CompressZip(unsigned char *dst, + tinyexr::tinyexr_uint64 &compressedSize, + const unsigned char *src, unsigned long src_size) { + std::vector tmpBuf(src_size); + + // + // Apply EXR-specific? postprocess. Grabbed from OpenEXR's + // ImfZipCompressor.cpp + // + + // + // Reorder the pixel data. + // + + const char *srcPtr = reinterpret_cast(src); + + { + char *t1 = reinterpret_cast(&tmpBuf.at(0)); + char *t2 = reinterpret_cast(&tmpBuf.at(0)) + (src_size + 1) / 2; + const char *stop = srcPtr + src_size; + + for (;;) { + if (srcPtr < stop) + *(t1++) = *(srcPtr++); + else + break; + + if (srcPtr < stop) + *(t2++) = *(srcPtr++); + else + break; + } + } + + // + // Predictor. + // + + { + unsigned char *t = &tmpBuf.at(0) + 1; + unsigned char *stop = &tmpBuf.at(0) + src_size; + int p = t[-1]; + + while (t < stop) { + int d = int(t[0]) - p + (128 + 256); + p = t[0]; + t[0] = static_cast(d); + ++t; + } + } + +#if TINYEXR_USE_MINIZ + // + // Compress the data using miniz + // + + miniz::mz_ulong outSize = miniz::mz_compressBound(src_size); + int ret = miniz::mz_compress( + dst, &outSize, static_cast(&tmpBuf.at(0)), + src_size); + assert(ret == miniz::MZ_OK); + (void)ret; + + compressedSize = outSize; +#else + uLong outSize = compressBound(static_cast(src_size)); + int ret = compress(dst, &outSize, static_cast(&tmpBuf.at(0)), + src_size); + assert(ret == Z_OK); + + compressedSize = outSize; +#endif + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if (compressedSize >= src_size) { + compressedSize = src_size; + memcpy(dst, src, src_size); + } +} + +static bool DecompressZip(unsigned char *dst, + unsigned long *uncompressed_size /* inout */, + const unsigned char *src, unsigned long src_size) { + if ((*uncompressed_size) == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + return true; + } + std::vector tmpBuf(*uncompressed_size); + +#if TINYEXR_USE_MINIZ + int ret = + miniz::mz_uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size); + if (miniz::MZ_OK != ret) { + return false; + } +#else + int ret = uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size); + if (Z_OK != ret) { + return false; + } +#endif + + // + // Apply EXR-specific? postprocess. Grabbed from OpenEXR's + // ImfZipCompressor.cpp + // + + // Predictor. + { + unsigned char *t = &tmpBuf.at(0) + 1; + unsigned char *stop = &tmpBuf.at(0) + (*uncompressed_size); + + while (t < stop) { + int d = int(t[-1]) + int(t[0]) - 128; + t[0] = static_cast(d); + ++t; + } + } + + // Reorder the pixel data. + { + const char *t1 = reinterpret_cast(&tmpBuf.at(0)); + const char *t2 = reinterpret_cast(&tmpBuf.at(0)) + + (*uncompressed_size + 1) / 2; + char *s = reinterpret_cast(dst); + char *stop = s + (*uncompressed_size); + + for (;;) { + if (s < stop) + *(s++) = *(t1++); + else + break; + + if (s < stop) + *(s++) = *(t2++); + else + break; + } + } + + return true; +} + +// RLE code from OpenEXR -------------------------------------- + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsign-conversion" +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) // nonstandard extension used : non-constant + // aggregate initializer (also supported by GNU + // C and C99, so no big deal) +#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is + // deprecated. Instead, use the ISO C and C++ + // conformant name: _strdup. +#endif + +const int MIN_RUN_LENGTH = 3; +const int MAX_RUN_LENGTH = 127; + +// +// Compress an array of bytes, using run-length encoding, +// and return the length of the compressed data. +// + +static int rleCompress(int inLength, const char in[], signed char out[]) { + const char *inEnd = in + inLength; + const char *runStart = in; + const char *runEnd = in + 1; + signed char *outWrite = out; + + while (runStart < inEnd) { + while (runEnd < inEnd && *runStart == *runEnd && + runEnd - runStart - 1 < MAX_RUN_LENGTH) { + ++runEnd; + } + + if (runEnd - runStart >= MIN_RUN_LENGTH) { + // + // Compressable run + // + + *outWrite++ = static_cast(runEnd - runStart) - 1; + *outWrite++ = *(reinterpret_cast(runStart)); + runStart = runEnd; + } else { + // + // Uncompressable run + // + + while (runEnd < inEnd && + ((runEnd + 1 >= inEnd || *runEnd != *(runEnd + 1)) || + (runEnd + 2 >= inEnd || *(runEnd + 1) != *(runEnd + 2))) && + runEnd - runStart < MAX_RUN_LENGTH) { + ++runEnd; + } + + *outWrite++ = static_cast(runStart - runEnd); + + while (runStart < runEnd) { + *outWrite++ = *(reinterpret_cast(runStart++)); + } + } + + ++runEnd; + } + + return static_cast(outWrite - out); +} + +// +// Uncompress an array of bytes compressed with rleCompress(). +// Returns the length of the oncompressed data, or 0 if the +// length of the uncompressed data would be more than maxLength. +// + +static int rleUncompress(int inLength, int maxLength, const signed char in[], + char out[]) { + char *outStart = out; + + while (inLength > 0) { + if (*in < 0) { + int count = -(static_cast(*in++)); + inLength -= count + 1; + + // Fixes #116: Add bounds check to in buffer. + if ((0 > (maxLength -= count)) || (inLength < 0)) return 0; + + memcpy(out, in, count); + out += count; + in += count; + } else { + int count = *in++; + inLength -= 2; + + if (0 > (maxLength -= count + 1)) return 0; + + memset(out, *reinterpret_cast(in), count + 1); + out += count + 1; + + in++; + } + } + + return static_cast(out - outStart); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// End of RLE code from OpenEXR ----------------------------------- + +static void CompressRle(unsigned char *dst, + tinyexr::tinyexr_uint64 &compressedSize, + const unsigned char *src, unsigned long src_size) { + std::vector tmpBuf(src_size); + + // + // Apply EXR-specific? postprocess. Grabbed from OpenEXR's + // ImfRleCompressor.cpp + // + + // + // Reorder the pixel data. + // + + const char *srcPtr = reinterpret_cast(src); + + { + char *t1 = reinterpret_cast(&tmpBuf.at(0)); + char *t2 = reinterpret_cast(&tmpBuf.at(0)) + (src_size + 1) / 2; + const char *stop = srcPtr + src_size; + + for (;;) { + if (srcPtr < stop) + *(t1++) = *(srcPtr++); + else + break; + + if (srcPtr < stop) + *(t2++) = *(srcPtr++); + else + break; + } + } + + // + // Predictor. + // + + { + unsigned char *t = &tmpBuf.at(0) + 1; + unsigned char *stop = &tmpBuf.at(0) + src_size; + int p = t[-1]; + + while (t < stop) { + int d = int(t[0]) - p + (128 + 256); + p = t[0]; + t[0] = static_cast(d); + ++t; + } + } + + // outSize will be (srcSiz * 3) / 2 at max. + int outSize = rleCompress(static_cast(src_size), + reinterpret_cast(&tmpBuf.at(0)), + reinterpret_cast(dst)); + assert(outSize > 0); + + compressedSize = static_cast(outSize); + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if (compressedSize >= src_size) { + compressedSize = src_size; + memcpy(dst, src, src_size); + } +} + +static bool DecompressRle(unsigned char *dst, + const unsigned long uncompressed_size, + const unsigned char *src, unsigned long src_size) { + if (uncompressed_size == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + return true; + } + + // Workaround for issue #112. + // TODO(syoyo): Add more robust out-of-bounds check in `rleUncompress`. + if (src_size <= 2) { + return false; + } + + std::vector tmpBuf(uncompressed_size); + + int ret = rleUncompress(static_cast(src_size), + static_cast(uncompressed_size), + reinterpret_cast(src), + reinterpret_cast(&tmpBuf.at(0))); + if (ret != static_cast(uncompressed_size)) { + return false; + } + + // + // Apply EXR-specific? postprocess. Grabbed from OpenEXR's + // ImfRleCompressor.cpp + // + + // Predictor. + { + unsigned char *t = &tmpBuf.at(0) + 1; + unsigned char *stop = &tmpBuf.at(0) + uncompressed_size; + + while (t < stop) { + int d = int(t[-1]) + int(t[0]) - 128; + t[0] = static_cast(d); + ++t; + } + } + + // Reorder the pixel data. + { + const char *t1 = reinterpret_cast(&tmpBuf.at(0)); + const char *t2 = reinterpret_cast(&tmpBuf.at(0)) + + (uncompressed_size + 1) / 2; + char *s = reinterpret_cast(dst); + char *stop = s + uncompressed_size; + + for (;;) { + if (s < stop) + *(s++) = *(t1++); + else + break; + + if (s < stop) + *(s++) = *(t2++); + else + break; + } + } + + return true; +} + +#if TINYEXR_USE_PIZ + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wc++11-extensions" +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" + +#if __has_warning("-Wcast-qual") +#pragma clang diagnostic ignored "-Wcast-qual" +#endif + +#endif + +// +// PIZ compress/uncompress, based on OpenEXR's ImfPizCompressor.cpp +// +// ----------------------------------------------------------------- +// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas +// Digital Ltd. LLC) +// (3 clause BSD license) +// + +struct PIZChannelData { + unsigned short *start; + unsigned short *end; + int nx; + int ny; + int ys; + int size; +}; + +//----------------------------------------------------------------------------- +// +// 16-bit Haar Wavelet encoding and decoding +// +// The source code in this file is derived from the encoding +// and decoding routines written by Christian Rouet for his +// PIZ image file format. +// +//----------------------------------------------------------------------------- + +// +// Wavelet basis functions without modulo arithmetic; they produce +// the best compression ratios when the wavelet-transformed data are +// Huffman-encoded, but the wavelet transform works only for 14-bit +// data (untransformed data values must be less than (1 << 14)). +// + +inline void wenc14(unsigned short a, unsigned short b, unsigned short &l, + unsigned short &h) { + short as = static_cast(a); + short bs = static_cast(b); + + short ms = (as + bs) >> 1; + short ds = as - bs; + + l = static_cast(ms); + h = static_cast(ds); +} + +inline void wdec14(unsigned short l, unsigned short h, unsigned short &a, + unsigned short &b) { + short ls = static_cast(l); + short hs = static_cast(h); + + int hi = hs; + int ai = ls + (hi & 1) + (hi >> 1); + + short as = static_cast(ai); + short bs = static_cast(ai - hi); + + a = static_cast(as); + b = static_cast(bs); +} + +// +// Wavelet basis functions with modulo arithmetic; they work with full +// 16-bit data, but Huffman-encoding the wavelet-transformed data doesn't +// compress the data quite as well. +// + +const int NBITS = 16; +const int A_OFFSET = 1 << (NBITS - 1); +const int M_OFFSET = 1 << (NBITS - 1); +const int MOD_MASK = (1 << NBITS) - 1; + +inline void wenc16(unsigned short a, unsigned short b, unsigned short &l, + unsigned short &h) { + int ao = (a + A_OFFSET) & MOD_MASK; + int m = ((ao + b) >> 1); + int d = ao - b; + + if (d < 0) m = (m + M_OFFSET) & MOD_MASK; + + d &= MOD_MASK; + + l = static_cast(m); + h = static_cast(d); +} + +inline void wdec16(unsigned short l, unsigned short h, unsigned short &a, + unsigned short &b) { + int m = l; + int d = h; + int bb = (m - (d >> 1)) & MOD_MASK; + int aa = (d + bb - A_OFFSET) & MOD_MASK; + b = static_cast(bb); + a = static_cast(aa); +} + +// +// 2D Wavelet encoding: +// + +static void wav2Encode( + unsigned short *in, // io: values are transformed in place + int nx, // i : x size + int ox, // i : x offset + int ny, // i : y size + int oy, // i : y offset + unsigned short mx) // i : maximum in[x][y] value +{ + bool w14 = (mx < (1 << 14)); + int n = (nx > ny) ? ny : nx; + int p = 1; // == 1 << level + int p2 = 2; // == 1 << (level+1) + + // + // Hierachical loop on smaller dimension n + // + + while (p2 <= n) { + unsigned short *py = in; + unsigned short *ey = in + oy * (ny - p2); + int oy1 = oy * p; + int oy2 = oy * p2; + int ox1 = ox * p; + int ox2 = ox * p2; + unsigned short i00, i01, i10, i11; + + // + // Y loop + // + + for (; py <= ey; py += oy2) { + unsigned short *px = py; + unsigned short *ex = py + ox * (nx - p2); + + // + // X loop + // + + for (; px <= ex; px += ox2) { + unsigned short *p01 = px + ox1; + unsigned short *p10 = px + oy1; + unsigned short *p11 = p10 + ox1; + + // + // 2D wavelet encoding + // + + if (w14) { + wenc14(*px, *p01, i00, i01); + wenc14(*p10, *p11, i10, i11); + wenc14(i00, i10, *px, *p10); + wenc14(i01, i11, *p01, *p11); + } else { + wenc16(*px, *p01, i00, i01); + wenc16(*p10, *p11, i10, i11); + wenc16(i00, i10, *px, *p10); + wenc16(i01, i11, *p01, *p11); + } + } + + // + // Encode (1D) odd column (still in Y loop) + // + + if (nx & p) { + unsigned short *p10 = px + oy1; + + if (w14) + wenc14(*px, *p10, i00, *p10); + else + wenc16(*px, *p10, i00, *p10); + + *px = i00; + } + } + + // + // Encode (1D) odd line (must loop in X) + // + + if (ny & p) { + unsigned short *px = py; + unsigned short *ex = py + ox * (nx - p2); + + for (; px <= ex; px += ox2) { + unsigned short *p01 = px + ox1; + + if (w14) + wenc14(*px, *p01, i00, *p01); + else + wenc16(*px, *p01, i00, *p01); + + *px = i00; + } + } + + // + // Next level + // + + p = p2; + p2 <<= 1; + } +} + +// +// 2D Wavelet decoding: +// + +static void wav2Decode( + unsigned short *in, // io: values are transformed in place + int nx, // i : x size + int ox, // i : x offset + int ny, // i : y size + int oy, // i : y offset + unsigned short mx) // i : maximum in[x][y] value +{ + bool w14 = (mx < (1 << 14)); + int n = (nx > ny) ? ny : nx; + int p = 1; + int p2; + + // + // Search max level + // + + while (p <= n) p <<= 1; + + p >>= 1; + p2 = p; + p >>= 1; + + // + // Hierarchical loop on smaller dimension n + // + + while (p >= 1) { + unsigned short *py = in; + unsigned short *ey = in + oy * (ny - p2); + int oy1 = oy * p; + int oy2 = oy * p2; + int ox1 = ox * p; + int ox2 = ox * p2; + unsigned short i00, i01, i10, i11; + + // + // Y loop + // + + for (; py <= ey; py += oy2) { + unsigned short *px = py; + unsigned short *ex = py + ox * (nx - p2); + + // + // X loop + // + + for (; px <= ex; px += ox2) { + unsigned short *p01 = px + ox1; + unsigned short *p10 = px + oy1; + unsigned short *p11 = p10 + ox1; + + // + // 2D wavelet decoding + // + + if (w14) { + wdec14(*px, *p10, i00, i10); + wdec14(*p01, *p11, i01, i11); + wdec14(i00, i01, *px, *p01); + wdec14(i10, i11, *p10, *p11); + } else { + wdec16(*px, *p10, i00, i10); + wdec16(*p01, *p11, i01, i11); + wdec16(i00, i01, *px, *p01); + wdec16(i10, i11, *p10, *p11); + } + } + + // + // Decode (1D) odd column (still in Y loop) + // + + if (nx & p) { + unsigned short *p10 = px + oy1; + + if (w14) + wdec14(*px, *p10, i00, *p10); + else + wdec16(*px, *p10, i00, *p10); + + *px = i00; + } + } + + // + // Decode (1D) odd line (must loop in X) + // + + if (ny & p) { + unsigned short *px = py; + unsigned short *ex = py + ox * (nx - p2); + + for (; px <= ex; px += ox2) { + unsigned short *p01 = px + ox1; + + if (w14) + wdec14(*px, *p01, i00, *p01); + else + wdec16(*px, *p01, i00, *p01); + + *px = i00; + } + } + + // + // Next level + // + + p2 = p; + p >>= 1; + } +} + +//----------------------------------------------------------------------------- +// +// 16-bit Huffman compression and decompression. +// +// The source code in this file is derived from the 8-bit +// Huffman compression and decompression routines written +// by Christian Rouet for his PIZ image file format. +// +//----------------------------------------------------------------------------- + +// Adds some modification for tinyexr. + +const int HUF_ENCBITS = 16; // literal (value) bit length +const int HUF_DECBITS = 14; // decoding bit size (>= 8) + +const int HUF_ENCSIZE = (1 << HUF_ENCBITS) + 1; // encoding table size +const int HUF_DECSIZE = 1 << HUF_DECBITS; // decoding table size +const int HUF_DECMASK = HUF_DECSIZE - 1; + +struct HufDec { // short code long code + //------------------------------- + int len : 8; // code length 0 + int lit : 24; // lit p size + int *p; // 0 lits +}; + +inline long long hufLength(long long code) { return code & 63; } + +inline long long hufCode(long long code) { return code >> 6; } + +inline void outputBits(int nBits, long long bits, long long &c, int &lc, + char *&out) { + c <<= nBits; + lc += nBits; + + c |= bits; + + while (lc >= 8) *out++ = static_cast((c >> (lc -= 8))); +} + +inline long long getBits(int nBits, long long &c, int &lc, const char *&in) { + while (lc < nBits) { + c = (c << 8) | *(reinterpret_cast(in++)); + lc += 8; + } + + lc -= nBits; + return (c >> lc) & ((1 << nBits) - 1); +} + +// +// ENCODING TABLE BUILDING & (UN)PACKING +// + +// +// Build a "canonical" Huffman code table: +// - for each (uncompressed) symbol, hcode contains the length +// of the corresponding code (in the compressed data) +// - canonical codes are computed and stored in hcode +// - the rules for constructing canonical codes are as follows: +// * shorter codes (if filled with zeroes to the right) +// have a numerically higher value than longer codes +// * for codes with the same length, numerical values +// increase with numerical symbol values +// - because the canonical code table can be constructed from +// symbol lengths alone, the code table can be transmitted +// without sending the actual code values +// - see http://www.compressconsult.com/huffman/ +// + +static void hufCanonicalCodeTable(long long hcode[HUF_ENCSIZE]) { + long long n[59]; + + // + // For each i from 0 through 58, count the + // number of different codes of length i, and + // store the count in n[i]. + // + + for (int i = 0; i <= 58; ++i) n[i] = 0; + + for (int i = 0; i < HUF_ENCSIZE; ++i) n[hcode[i]] += 1; + + // + // For each i from 58 through 1, compute the + // numerically lowest code with length i, and + // store that code in n[i]. + // + + long long c = 0; + + for (int i = 58; i > 0; --i) { + long long nc = ((c + n[i]) >> 1); + n[i] = c; + c = nc; + } + + // + // hcode[i] contains the length, l, of the + // code for symbol i. Assign the next available + // code of length l to the symbol and store both + // l and the code in hcode[i]. + // + + for (int i = 0; i < HUF_ENCSIZE; ++i) { + int l = static_cast(hcode[i]); + + if (l > 0) hcode[i] = l | (n[l]++ << 6); + } +} + +// +// Compute Huffman codes (based on frq input) and store them in frq: +// - code structure is : [63:lsb - 6:msb] | [5-0: bit length]; +// - max code length is 58 bits; +// - codes outside the range [im-iM] have a null length (unused values); +// - original frequencies are destroyed; +// - encoding tables are used by hufEncode() and hufBuildDecTable(); +// + +struct FHeapCompare { + bool operator()(long long *a, long long *b) { return *a > *b; } +}; + +static void hufBuildEncTable( + long long *frq, // io: input frequencies [HUF_ENCSIZE], output table + int *im, // o: min frq index + int *iM) // o: max frq index +{ + // + // This function assumes that when it is called, array frq + // indicates the frequency of all possible symbols in the data + // that are to be Huffman-encoded. (frq[i] contains the number + // of occurrences of symbol i in the data.) + // + // The loop below does three things: + // + // 1) Finds the minimum and maximum indices that point + // to non-zero entries in frq: + // + // frq[im] != 0, and frq[i] == 0 for all i < im + // frq[iM] != 0, and frq[i] == 0 for all i > iM + // + // 2) Fills array fHeap with pointers to all non-zero + // entries in frq. + // + // 3) Initializes array hlink such that hlink[i] == i + // for all array entries. + // + + std::vector hlink(HUF_ENCSIZE); + std::vector fHeap(HUF_ENCSIZE); + + *im = 0; + + while (!frq[*im]) (*im)++; + + int nf = 0; + + for (int i = *im; i < HUF_ENCSIZE; i++) { + hlink[i] = i; + + if (frq[i]) { + fHeap[nf] = &frq[i]; + nf++; + *iM = i; + } + } + + // + // Add a pseudo-symbol, with a frequency count of 1, to frq; + // adjust the fHeap and hlink array accordingly. Function + // hufEncode() uses the pseudo-symbol for run-length encoding. + // + + (*iM)++; + frq[*iM] = 1; + fHeap[nf] = &frq[*iM]; + nf++; + + // + // Build an array, scode, such that scode[i] contains the number + // of bits assigned to symbol i. Conceptually this is done by + // constructing a tree whose leaves are the symbols with non-zero + // frequency: + // + // Make a heap that contains all symbols with a non-zero frequency, + // with the least frequent symbol on top. + // + // Repeat until only one symbol is left on the heap: + // + // Take the two least frequent symbols off the top of the heap. + // Create a new node that has first two nodes as children, and + // whose frequency is the sum of the frequencies of the first + // two nodes. Put the new node back into the heap. + // + // The last node left on the heap is the root of the tree. For each + // leaf node, the distance between the root and the leaf is the length + // of the code for the corresponding symbol. + // + // The loop below doesn't actually build the tree; instead we compute + // the distances of the leaves from the root on the fly. When a new + // node is added to the heap, then that node's descendants are linked + // into a single linear list that starts at the new node, and the code + // lengths of the descendants (that is, their distance from the root + // of the tree) are incremented by one. + // + + std::make_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); + + std::vector scode(HUF_ENCSIZE); + memset(scode.data(), 0, sizeof(long long) * HUF_ENCSIZE); + + while (nf > 1) { + // + // Find the indices, mm and m, of the two smallest non-zero frq + // values in fHeap, add the smallest frq to the second-smallest + // frq, and remove the smallest frq value from fHeap. + // + + int mm = fHeap[0] - frq; + std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); + --nf; + + int m = fHeap[0] - frq; + std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); + + frq[m] += frq[mm]; + std::push_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); + + // + // The entries in scode are linked into lists with the + // entries in hlink serving as "next" pointers and with + // the end of a list marked by hlink[j] == j. + // + // Traverse the lists that start at scode[m] and scode[mm]. + // For each element visited, increment the length of the + // corresponding code by one bit. (If we visit scode[j] + // during the traversal, then the code for symbol j becomes + // one bit longer.) + // + // Merge the lists that start at scode[m] and scode[mm] + // into a single list that starts at scode[m]. + // + + // + // Add a bit to all codes in the first list. + // + + for (int j = m;; j = hlink[j]) { + scode[j]++; + + assert(scode[j] <= 58); + + if (hlink[j] == j) { + // + // Merge the two lists. + // + + hlink[j] = mm; + break; + } + } + + // + // Add a bit to all codes in the second list + // + + for (int j = mm;; j = hlink[j]) { + scode[j]++; + + assert(scode[j] <= 58); + + if (hlink[j] == j) break; + } + } + + // + // Build a canonical Huffman code table, replacing the code + // lengths in scode with (code, code length) pairs. Copy the + // code table from scode into frq. + // + + hufCanonicalCodeTable(scode.data()); + memcpy(frq, scode.data(), sizeof(long long) * HUF_ENCSIZE); +} + +// +// Pack an encoding table: +// - only code lengths, not actual codes, are stored +// - runs of zeroes are compressed as follows: +// +// unpacked packed +// -------------------------------- +// 1 zero 0 (6 bits) +// 2 zeroes 59 +// 3 zeroes 60 +// 4 zeroes 61 +// 5 zeroes 62 +// n zeroes (6 or more) 63 n-6 (6 + 8 bits) +// + +const int SHORT_ZEROCODE_RUN = 59; +const int LONG_ZEROCODE_RUN = 63; +const int SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN; +const int LONGEST_LONG_RUN = 255 + SHORTEST_LONG_RUN; + +static void hufPackEncTable( + const long long *hcode, // i : encoding table [HUF_ENCSIZE] + int im, // i : min hcode index + int iM, // i : max hcode index + char **pcode) // o: ptr to packed table (updated) +{ + char *p = *pcode; + long long c = 0; + int lc = 0; + + for (; im <= iM; im++) { + int l = hufLength(hcode[im]); + + if (l == 0) { + int zerun = 1; + + while ((im < iM) && (zerun < LONGEST_LONG_RUN)) { + if (hufLength(hcode[im + 1]) > 0) break; + im++; + zerun++; + } + + if (zerun >= 2) { + if (zerun >= SHORTEST_LONG_RUN) { + outputBits(6, LONG_ZEROCODE_RUN, c, lc, p); + outputBits(8, zerun - SHORTEST_LONG_RUN, c, lc, p); + } else { + outputBits(6, SHORT_ZEROCODE_RUN + zerun - 2, c, lc, p); + } + continue; + } + } + + outputBits(6, l, c, lc, p); + } + + if (lc > 0) *p++ = (unsigned char)(c << (8 - lc)); + + *pcode = p; +} + +// +// Unpack an encoding table packed by hufPackEncTable(): +// + +static bool hufUnpackEncTable( + const char **pcode, // io: ptr to packed table (updated) + int ni, // i : input size (in bytes) + int im, // i : min hcode index + int iM, // i : max hcode index + long long *hcode) // o: encoding table [HUF_ENCSIZE] +{ + memset(hcode, 0, sizeof(long long) * HUF_ENCSIZE); + + const char *p = *pcode; + long long c = 0; + int lc = 0; + + for (; im <= iM; im++) { + if (p - *pcode >= ni) { + return false; + } + + long long l = hcode[im] = getBits(6, c, lc, p); // code length + + if (l == (long long)LONG_ZEROCODE_RUN) { + if (p - *pcode > ni) { + return false; + } + + int zerun = getBits(8, c, lc, p) + SHORTEST_LONG_RUN; + + if (im + zerun > iM + 1) { + return false; + } + + while (zerun--) hcode[im++] = 0; + + im--; + } else if (l >= (long long)SHORT_ZEROCODE_RUN) { + int zerun = l - SHORT_ZEROCODE_RUN + 2; + + if (im + zerun > iM + 1) { + return false; + } + + while (zerun--) hcode[im++] = 0; + + im--; + } + } + + *pcode = const_cast(p); + + hufCanonicalCodeTable(hcode); + + return true; +} + +// +// DECODING TABLE BUILDING +// + +// +// Clear a newly allocated decoding table so that it contains only zeroes. +// + +static void hufClearDecTable(HufDec *hdecod) // io: (allocated by caller) +// decoding table [HUF_DECSIZE] +{ + for (int i = 0; i < HUF_DECSIZE; i++) { + hdecod[i].len = 0; + hdecod[i].lit = 0; + hdecod[i].p = NULL; + } + // memset(hdecod, 0, sizeof(HufDec) * HUF_DECSIZE); +} + +// +// Build a decoding hash table based on the encoding table hcode: +// - short codes (<= HUF_DECBITS) are resolved with a single table access; +// - long code entry allocations are not optimized, because long codes are +// unfrequent; +// - decoding tables are used by hufDecode(); +// + +static bool hufBuildDecTable(const long long *hcode, // i : encoding table + int im, // i : min index in hcode + int iM, // i : max index in hcode + HufDec *hdecod) // o: (allocated by caller) +// decoding table [HUF_DECSIZE] +{ + // + // Init hashtable & loop on all codes. + // Assumes that hufClearDecTable(hdecod) has already been called. + // + + for (; im <= iM; im++) { + long long c = hufCode(hcode[im]); + int l = hufLength(hcode[im]); + + if (c >> l) { + // + // Error: c is supposed to be an l-bit code, + // but c contains a value that is greater + // than the largest l-bit number. + // + + // invalidTableEntry(); + return false; + } + + if (l > HUF_DECBITS) { + // + // Long code: add a secondary entry + // + + HufDec *pl = hdecod + (c >> (l - HUF_DECBITS)); + + if (pl->len) { + // + // Error: a short code has already + // been stored in table entry *pl. + // + + // invalidTableEntry(); + return false; + } + + pl->lit++; + + if (pl->p) { + int *p = pl->p; + pl->p = new int[pl->lit]; + + for (int i = 0; i < pl->lit - 1; ++i) pl->p[i] = p[i]; + + delete[] p; + } else { + pl->p = new int[1]; + } + + pl->p[pl->lit - 1] = im; + } else if (l) { + // + // Short code: init all primary entries + // + + HufDec *pl = hdecod + (c << (HUF_DECBITS - l)); + + for (long long i = 1ULL << (HUF_DECBITS - l); i > 0; i--, pl++) { + if (pl->len || pl->p) { + // + // Error: a short code or a long code has + // already been stored in table entry *pl. + // + + // invalidTableEntry(); + return false; + } + + pl->len = l; + pl->lit = im; + } + } + } + + return true; +} + +// +// Free the long code entries of a decoding table built by hufBuildDecTable() +// + +static void hufFreeDecTable(HufDec *hdecod) // io: Decoding table +{ + for (int i = 0; i < HUF_DECSIZE; i++) { + if (hdecod[i].p) { + delete[] hdecod[i].p; + hdecod[i].p = 0; + } + } +} + +// +// ENCODING +// + +inline void outputCode(long long code, long long &c, int &lc, char *&out) { + outputBits(hufLength(code), hufCode(code), c, lc, out); +} + +inline void sendCode(long long sCode, int runCount, long long runCode, + long long &c, int &lc, char *&out) { + // + // Output a run of runCount instances of the symbol sCount. + // Output the symbols explicitly, or if that is shorter, output + // the sCode symbol once followed by a runCode symbol and runCount + // expressed as an 8-bit number. + // + + if (hufLength(sCode) + hufLength(runCode) + 8 < hufLength(sCode) * runCount) { + outputCode(sCode, c, lc, out); + outputCode(runCode, c, lc, out); + outputBits(8, runCount, c, lc, out); + } else { + while (runCount-- >= 0) outputCode(sCode, c, lc, out); + } +} + +// +// Encode (compress) ni values based on the Huffman encoding table hcode: +// + +static int hufEncode // return: output size (in bits) + (const long long *hcode, // i : encoding table + const unsigned short *in, // i : uncompressed input buffer + const int ni, // i : input buffer size (in bytes) + int rlc, // i : rl code + char *out) // o: compressed output buffer +{ + char *outStart = out; + long long c = 0; // bits not yet written to out + int lc = 0; // number of valid bits in c (LSB) + int s = in[0]; + int cs = 0; + + // + // Loop on input values + // + + for (int i = 1; i < ni; i++) { + // + // Count same values or send code + // + + if (s == in[i] && cs < 255) { + cs++; + } else { + sendCode(hcode[s], cs, hcode[rlc], c, lc, out); + cs = 0; + } + + s = in[i]; + } + + // + // Send remaining code + // + + sendCode(hcode[s], cs, hcode[rlc], c, lc, out); + + if (lc) *out = (c << (8 - lc)) & 0xff; + + return (out - outStart) * 8 + lc; +} + +// +// DECODING +// + +// +// In order to force the compiler to inline them, +// getChar() and getCode() are implemented as macros +// instead of "inline" functions. +// + +#define getChar(c, lc, in) \ + { \ + c = (c << 8) | *(unsigned char *)(in++); \ + lc += 8; \ + } + +#if 0 +#define getCode(po, rlc, c, lc, in, out, ob, oe) \ + { \ + if (po == rlc) { \ + if (lc < 8) getChar(c, lc, in); \ + \ + lc -= 8; \ + \ + unsigned char cs = (c >> lc); \ + \ + if (out + cs > oe) return false; \ + \ + /* TinyEXR issue 78 */ \ + unsigned short s = out[-1]; \ + \ + while (cs-- > 0) *out++ = s; \ + } else if (out < oe) { \ + *out++ = po; \ + } else { \ + return false; \ + } \ + } +#else +static bool getCode(int po, int rlc, long long &c, int &lc, const char *&in, + const char *in_end, unsigned short *&out, + const unsigned short *ob, const unsigned short *oe) { + (void)ob; + if (po == rlc) { + if (lc < 8) { + /* TinyEXR issue 78 */ + if ((in + 1) >= in_end) { + return false; + } + + getChar(c, lc, in); + } + + lc -= 8; + + unsigned char cs = (c >> lc); + + if (out + cs > oe) return false; + + // Bounds check for safety + // Issue 100. + if ((out - 1) < ob) return false; + unsigned short s = out[-1]; + + while (cs-- > 0) *out++ = s; + } else if (out < oe) { + *out++ = po; + } else { + return false; + } + return true; +} +#endif + +// +// Decode (uncompress) ni bits based on encoding & decoding tables: +// + +static bool hufDecode(const long long *hcode, // i : encoding table + const HufDec *hdecod, // i : decoding table + const char *in, // i : compressed input buffer + int ni, // i : input size (in bits) + int rlc, // i : run-length code + int no, // i : expected output size (in bytes) + unsigned short *out) // o: uncompressed output buffer +{ + long long c = 0; + int lc = 0; + unsigned short *outb = out; // begin + unsigned short *oe = out + no; // end + const char *ie = in + (ni + 7) / 8; // input byte size + + // + // Loop on input bytes + // + + while (in < ie) { + getChar(c, lc, in); + + // + // Access decoding table + // + + while (lc >= HUF_DECBITS) { + const HufDec pl = hdecod[(c >> (lc - HUF_DECBITS)) & HUF_DECMASK]; + + if (pl.len) { + // + // Get short code + // + + lc -= pl.len; + // std::cout << "lit = " << pl.lit << std::endl; + // std::cout << "rlc = " << rlc << std::endl; + // std::cout << "c = " << c << std::endl; + // std::cout << "lc = " << lc << std::endl; + // std::cout << "in = " << in << std::endl; + // std::cout << "out = " << out << std::endl; + // std::cout << "oe = " << oe << std::endl; + if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) { + return false; + } + } else { + if (!pl.p) { + return false; + } + // invalidCode(); // wrong code + + // + // Search long code + // + + int j; + + for (j = 0; j < pl.lit; j++) { + int l = hufLength(hcode[pl.p[j]]); + + while (lc < l && in < ie) // get more bits + getChar(c, lc, in); + + if (lc >= l) { + if (hufCode(hcode[pl.p[j]]) == + ((c >> (lc - l)) & (((long long)(1) << l) - 1))) { + // + // Found : get long code + // + + lc -= l; + if (!getCode(pl.p[j], rlc, c, lc, in, ie, out, outb, oe)) { + return false; + } + break; + } + } + } + + if (j == pl.lit) { + return false; + // invalidCode(); // Not found + } + } + } + } + + // + // Get remaining (short) codes + // + + int i = (8 - ni) & 7; + c >>= i; + lc -= i; + + while (lc > 0) { + const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK]; + + if (pl.len) { + lc -= pl.len; + if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) { + return false; + } + } else { + return false; + // invalidCode(); // wrong (long) code + } + } + + if (out - outb != no) { + return false; + } + // notEnoughData (); + + return true; +} + +static void countFrequencies(std::vector &freq, + const unsigned short data[/*n*/], int n) { + for (int i = 0; i < HUF_ENCSIZE; ++i) freq[i] = 0; + + for (int i = 0; i < n; ++i) ++freq[data[i]]; +} + +static void writeUInt(char buf[4], unsigned int i) { + unsigned char *b = (unsigned char *)buf; + + b[0] = i; + b[1] = i >> 8; + b[2] = i >> 16; + b[3] = i >> 24; +} + +static unsigned int readUInt(const char buf[4]) { + const unsigned char *b = (const unsigned char *)buf; + + return (b[0] & 0x000000ff) | ((b[1] << 8) & 0x0000ff00) | + ((b[2] << 16) & 0x00ff0000) | ((b[3] << 24) & 0xff000000); +} + +// +// EXTERNAL INTERFACE +// + +static int hufCompress(const unsigned short raw[], int nRaw, + char compressed[]) { + if (nRaw == 0) return 0; + + std::vector freq(HUF_ENCSIZE); + + countFrequencies(freq, raw, nRaw); + + int im = 0; + int iM = 0; + hufBuildEncTable(freq.data(), &im, &iM); + + char *tableStart = compressed + 20; + char *tableEnd = tableStart; + hufPackEncTable(freq.data(), im, iM, &tableEnd); + int tableLength = tableEnd - tableStart; + + char *dataStart = tableEnd; + int nBits = hufEncode(freq.data(), raw, nRaw, iM, dataStart); + int data_length = (nBits + 7) / 8; + + writeUInt(compressed, im); + writeUInt(compressed + 4, iM); + writeUInt(compressed + 8, tableLength); + writeUInt(compressed + 12, nBits); + writeUInt(compressed + 16, 0); // room for future extensions + + return dataStart + data_length - compressed; +} + +static bool hufUncompress(const char compressed[], int nCompressed, + std::vector *raw) { + if (nCompressed == 0) { + if (raw->size() != 0) return false; + + return false; + } + + int im = readUInt(compressed); + int iM = readUInt(compressed + 4); + // int tableLength = readUInt (compressed + 8); + int nBits = readUInt(compressed + 12); + + if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE) return false; + + const char *ptr = compressed + 20; + + // + // Fast decoder needs at least 2x64-bits of compressed data, and + // needs to be run-able on this platform. Otherwise, fall back + // to the original decoder + // + + // if (FastHufDecoder::enabled() && nBits > 128) + //{ + // FastHufDecoder fhd (ptr, nCompressed - (ptr - compressed), im, iM, iM); + // fhd.decode ((unsigned char*)ptr, nBits, raw, nRaw); + //} + // else + { + std::vector freq(HUF_ENCSIZE); + std::vector hdec(HUF_DECSIZE); + + hufClearDecTable(&hdec.at(0)); + + hufUnpackEncTable(&ptr, nCompressed - (ptr - compressed), im, iM, + &freq.at(0)); + + { + if (nBits > 8 * (nCompressed - (ptr - compressed))) { + return false; + } + + hufBuildDecTable(&freq.at(0), im, iM, &hdec.at(0)); + hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, raw->size(), + raw->data()); + } + // catch (...) + //{ + // hufFreeDecTable (hdec); + // throw; + //} + + hufFreeDecTable(&hdec.at(0)); + } + + return true; +} + +// +// Functions to compress the range of values in the pixel data +// + +const int USHORT_RANGE = (1 << 16); +const int BITMAP_SIZE = (USHORT_RANGE >> 3); + +static void bitmapFromData(const unsigned short data[/*nData*/], int nData, + unsigned char bitmap[BITMAP_SIZE], + unsigned short &minNonZero, + unsigned short &maxNonZero) { + for (int i = 0; i < BITMAP_SIZE; ++i) bitmap[i] = 0; + + for (int i = 0; i < nData; ++i) bitmap[data[i] >> 3] |= (1 << (data[i] & 7)); + + bitmap[0] &= ~1; // zero is not explicitly stored in + // the bitmap; we assume that the + // data always contain zeroes + minNonZero = BITMAP_SIZE - 1; + maxNonZero = 0; + + for (int i = 0; i < BITMAP_SIZE; ++i) { + if (bitmap[i]) { + if (minNonZero > i) minNonZero = i; + if (maxNonZero < i) maxNonZero = i; + } + } +} + +static unsigned short forwardLutFromBitmap( + const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) { + int k = 0; + + for (int i = 0; i < USHORT_RANGE; ++i) { + if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) + lut[i] = k++; + else + lut[i] = 0; + } + + return k - 1; // maximum value stored in lut[], +} // i.e. number of ones in bitmap minus 1 + +static unsigned short reverseLutFromBitmap( + const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) { + int k = 0; + + for (int i = 0; i < USHORT_RANGE; ++i) { + if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) lut[k++] = i; + } + + int n = k - 1; + + while (k < USHORT_RANGE) lut[k++] = 0; + + return n; // maximum k where lut[k] is non-zero, +} // i.e. number of ones in bitmap minus 1 + +static void applyLut(const unsigned short lut[USHORT_RANGE], + unsigned short data[/*nData*/], int nData) { + for (int i = 0; i < nData; ++i) data[i] = lut[data[i]]; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize, + const unsigned char *inPtr, size_t inSize, + const std::vector &channelInfo, + int data_width, int num_lines) { + std::vector bitmap(BITMAP_SIZE); + unsigned short minNonZero; + unsigned short maxNonZero; + +#if !MINIZ_LITTLE_ENDIAN + // @todo { PIZ compression on BigEndian architecture. } + assert(0); + return false; +#endif + + // Assume `inSize` is multiple of 2 or 4. + std::vector tmpBuffer(inSize / sizeof(unsigned short)); + + std::vector channelData(channelInfo.size()); + unsigned short *tmpBufferEnd = &tmpBuffer.at(0); + + for (size_t c = 0; c < channelData.size(); c++) { + PIZChannelData &cd = channelData[c]; + + cd.start = tmpBufferEnd; + cd.end = cd.start; + + cd.nx = data_width; + cd.ny = num_lines; + // cd.ys = c.channel().ySampling; + + size_t pixelSize = sizeof(int); // UINT and FLOAT + if (channelInfo[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + pixelSize = sizeof(short); + } + + cd.size = static_cast(pixelSize / sizeof(short)); + + tmpBufferEnd += cd.nx * cd.ny * cd.size; + } + + const unsigned char *ptr = inPtr; + for (int y = 0; y < num_lines; ++y) { + for (size_t i = 0; i < channelData.size(); ++i) { + PIZChannelData &cd = channelData[i]; + + // if (modp (y, cd.ys) != 0) + // continue; + + size_t n = static_cast(cd.nx * cd.size); + memcpy(cd.end, ptr, n * sizeof(unsigned short)); + ptr += n * sizeof(unsigned short); + cd.end += n; + } + } + + bitmapFromData(&tmpBuffer.at(0), static_cast(tmpBuffer.size()), + bitmap.data(), minNonZero, maxNonZero); + + std::vector lut(USHORT_RANGE); + unsigned short maxValue = forwardLutFromBitmap(bitmap.data(), lut.data()); + applyLut(lut.data(), &tmpBuffer.at(0), static_cast(tmpBuffer.size())); + + // + // Store range compression info in _outBuffer + // + + char *buf = reinterpret_cast(outPtr); + + memcpy(buf, &minNonZero, sizeof(unsigned short)); + buf += sizeof(unsigned short); + memcpy(buf, &maxNonZero, sizeof(unsigned short)); + buf += sizeof(unsigned short); + + if (minNonZero <= maxNonZero) { + memcpy(buf, reinterpret_cast(&bitmap[0] + minNonZero), + maxNonZero - minNonZero + 1); + buf += maxNonZero - minNonZero + 1; + } + + // + // Apply wavelet encoding + // + + for (size_t i = 0; i < channelData.size(); ++i) { + PIZChannelData &cd = channelData[i]; + + for (int j = 0; j < cd.size; ++j) { + wav2Encode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size, + maxValue); + } + } + + // + // Apply Huffman encoding; append the result to _outBuffer + // + + // length header(4byte), then huff data. Initialize length header with zero, + // then later fill it by `length`. + char *lengthPtr = buf; + int zero = 0; + memcpy(buf, &zero, sizeof(int)); + buf += sizeof(int); + + int length = + hufCompress(&tmpBuffer.at(0), static_cast(tmpBuffer.size()), buf); + memcpy(lengthPtr, &length, sizeof(int)); + + (*outSize) = static_cast( + (reinterpret_cast(buf) - outPtr) + + static_cast(length)); + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if ((*outSize) >= inSize) { + (*outSize) = static_cast(inSize); + memcpy(outPtr, inPtr, inSize); + } + return true; +} + +static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr, + size_t tmpBufSize, size_t inLen, int num_channels, + const EXRChannelInfo *channels, int data_width, + int num_lines) { + if (inLen == tmpBufSize) { + // Data is not compressed(Issue 40). + memcpy(outPtr, inPtr, inLen); + return true; + } + + std::vector bitmap(BITMAP_SIZE); + unsigned short minNonZero; + unsigned short maxNonZero; + +#if !MINIZ_LITTLE_ENDIAN + // @todo { PIZ compression on BigEndian architecture. } + assert(0); + return false; +#endif + + memset(bitmap.data(), 0, BITMAP_SIZE); + + const unsigned char *ptr = inPtr; + // minNonZero = *(reinterpret_cast(ptr)); + tinyexr::cpy2(&minNonZero, reinterpret_cast(ptr)); + // maxNonZero = *(reinterpret_cast(ptr + 2)); + tinyexr::cpy2(&maxNonZero, reinterpret_cast(ptr + 2)); + ptr += 4; + + if (maxNonZero >= BITMAP_SIZE) { + return false; + } + + if (minNonZero <= maxNonZero) { + memcpy(reinterpret_cast(&bitmap[0] + minNonZero), ptr, + maxNonZero - minNonZero + 1); + ptr += maxNonZero - minNonZero + 1; + } + + std::vector lut(USHORT_RANGE); + memset(lut.data(), 0, sizeof(unsigned short) * USHORT_RANGE); + unsigned short maxValue = reverseLutFromBitmap(bitmap.data(), lut.data()); + + // + // Huffman decoding + // + + int length; + + // length = *(reinterpret_cast(ptr)); + tinyexr::cpy4(&length, reinterpret_cast(ptr)); + ptr += sizeof(int); + + if (size_t((ptr - inPtr) + length) > inLen) { + return false; + } + + std::vector tmpBuffer(tmpBufSize); + hufUncompress(reinterpret_cast(ptr), length, &tmpBuffer); + + // + // Wavelet decoding + // + + std::vector channelData(static_cast(num_channels)); + + unsigned short *tmpBufferEnd = &tmpBuffer.at(0); + + for (size_t i = 0; i < static_cast(num_channels); ++i) { + const EXRChannelInfo &chan = channels[i]; + + size_t pixelSize = sizeof(int); // UINT and FLOAT + if (chan.pixel_type == TINYEXR_PIXELTYPE_HALF) { + pixelSize = sizeof(short); + } + + channelData[i].start = tmpBufferEnd; + channelData[i].end = channelData[i].start; + channelData[i].nx = data_width; + channelData[i].ny = num_lines; + // channelData[i].ys = 1; + channelData[i].size = static_cast(pixelSize / sizeof(short)); + + tmpBufferEnd += channelData[i].nx * channelData[i].ny * channelData[i].size; + } + + for (size_t i = 0; i < channelData.size(); ++i) { + PIZChannelData &cd = channelData[i]; + + for (int j = 0; j < cd.size; ++j) { + wav2Decode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size, + maxValue); + } + } + + // + // Expand the pixel data to their original range + // + + applyLut(lut.data(), &tmpBuffer.at(0), static_cast(tmpBufSize)); + + for (int y = 0; y < num_lines; y++) { + for (size_t i = 0; i < channelData.size(); ++i) { + PIZChannelData &cd = channelData[i]; + + // if (modp (y, cd.ys) != 0) + // continue; + + size_t n = static_cast(cd.nx * cd.size); + memcpy(outPtr, cd.end, static_cast(n * sizeof(unsigned short))); + outPtr += n * sizeof(unsigned short); + cd.end += n; + } + } + + return true; +} +#endif // TINYEXR_USE_PIZ + +#if TINYEXR_USE_ZFP +struct ZFPCompressionParam { + double rate; + int precision; + double tolerance; + int type; // TINYEXR_ZFP_COMPRESSIONTYPE_* + + ZFPCompressionParam() { + type = TINYEXR_ZFP_COMPRESSIONTYPE_RATE; + rate = 2.0; + precision = 0; + tolerance = 0.0f; + } +}; + +bool FindZFPCompressionParam(ZFPCompressionParam *param, + const EXRAttribute *attributes, + int num_attributes) { + bool foundType = false; + + for (int i = 0; i < num_attributes; i++) { + if ((strcmp(attributes[i].name, "zfpCompressionType") == 0) && + (attributes[i].size == 1)) { + param->type = static_cast(attributes[i].value[0]); + + foundType = true; + } + } + + if (!foundType) { + return false; + } + + if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) { + for (int i = 0; i < num_attributes; i++) { + if ((strcmp(attributes[i].name, "zfpCompressionRate") == 0) && + (attributes[i].size == 8)) { + param->rate = *(reinterpret_cast(attributes[i].value)); + return true; + } + } + } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) { + for (int i = 0; i < num_attributes; i++) { + if ((strcmp(attributes[i].name, "zfpCompressionPrecision") == 0) && + (attributes[i].size == 4)) { + param->rate = *(reinterpret_cast(attributes[i].value)); + return true; + } + } + } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) { + for (int i = 0; i < num_attributes; i++) { + if ((strcmp(attributes[i].name, "zfpCompressionTolerance") == 0) && + (attributes[i].size == 8)) { + param->tolerance = *(reinterpret_cast(attributes[i].value)); + return true; + } + } + } else { + assert(0); + } + + return false; +} + +// Assume pixel format is FLOAT for all channels. +static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines, + int num_channels, const unsigned char *src, + unsigned long src_size, + const ZFPCompressionParam ¶m) { + size_t uncompressed_size = dst_width * dst_num_lines * num_channels; + + if (uncompressed_size == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + } + + zfp_stream *zfp = NULL; + zfp_field *field = NULL; + + assert((dst_width % 4) == 0); + assert((dst_num_lines % 4) == 0); + + if ((dst_width & 3U) || (dst_num_lines & 3U)) { + return false; + } + + field = + zfp_field_2d(reinterpret_cast(const_cast(src)), + zfp_type_float, dst_width, dst_num_lines * num_channels); + zfp = zfp_stream_open(NULL); + + if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) { + zfp_stream_set_rate(zfp, param.rate, zfp_type_float, /* dimention */ 2, + /* write random access */ 0); + } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) { + zfp_stream_set_precision(zfp, param.precision, zfp_type_float); + } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) { + zfp_stream_set_accuracy(zfp, param.tolerance, zfp_type_float); + } else { + assert(0); + } + + size_t buf_size = zfp_stream_maximum_size(zfp, field); + std::vector buf(buf_size); + memcpy(&buf.at(0), src, src_size); + + bitstream *stream = stream_open(&buf.at(0), buf_size); + zfp_stream_set_bit_stream(zfp, stream); + zfp_stream_rewind(zfp); + + size_t image_size = dst_width * dst_num_lines; + + for (int c = 0; c < num_channels; c++) { + // decompress 4x4 pixel block. + for (int y = 0; y < dst_num_lines; y += 4) { + for (int x = 0; x < dst_width; x += 4) { + float fblock[16]; + zfp_decode_block_float_2(zfp, fblock); + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + dst[c * image_size + ((y + j) * dst_width + (x + i))] = + fblock[j * 4 + i]; + } + } + } + } + } + + zfp_field_free(field); + zfp_stream_close(zfp); + stream_close(stream); + + return true; +} + +// Assume pixel format is FLOAT for all channels. +bool CompressZfp(std::vector *outBuf, unsigned int *outSize, + const float *inPtr, int width, int num_lines, int num_channels, + const ZFPCompressionParam ¶m) { + zfp_stream *zfp = NULL; + zfp_field *field = NULL; + + assert((width % 4) == 0); + assert((num_lines % 4) == 0); + + if ((width & 3U) || (num_lines & 3U)) { + return false; + } + + // create input array. + field = zfp_field_2d(reinterpret_cast(const_cast(inPtr)), + zfp_type_float, width, num_lines * num_channels); + + zfp = zfp_stream_open(NULL); + + if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) { + zfp_stream_set_rate(zfp, param.rate, zfp_type_float, 2, 0); + } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) { + zfp_stream_set_precision(zfp, param.precision, zfp_type_float); + } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) { + zfp_stream_set_accuracy(zfp, param.tolerance, zfp_type_float); + } else { + assert(0); + } + + size_t buf_size = zfp_stream_maximum_size(zfp, field); + + outBuf->resize(buf_size); + + bitstream *stream = stream_open(&outBuf->at(0), buf_size); + zfp_stream_set_bit_stream(zfp, stream); + zfp_field_free(field); + + size_t image_size = width * num_lines; + + for (int c = 0; c < num_channels; c++) { + // compress 4x4 pixel block. + for (int y = 0; y < num_lines; y += 4) { + for (int x = 0; x < width; x += 4) { + float fblock[16]; + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + fblock[j * 4 + i] = + inPtr[c * image_size + ((y + j) * width + (x + i))]; + } + } + zfp_encode_block_float_2(zfp, fblock); + } + } + } + + zfp_stream_flush(zfp); + (*outSize) = zfp_stream_compressed_size(zfp); + + zfp_stream_close(zfp); + + return true; +} + +#endif + +// +// ----------------------------------------------------------------- +// + +// TODO(syoyo): Refactor function arguments. +static bool DecodePixelData(/* out */ unsigned char **out_images, + const int *requested_pixel_types, + const unsigned char *data_ptr, size_t data_len, + int compression_type, int line_order, int width, + int height, int x_stride, int y, int line_no, + int num_lines, size_t pixel_data_size, + size_t num_attributes, + const EXRAttribute *attributes, size_t num_channels, + const EXRChannelInfo *channels, + const std::vector &channel_offset_list) { + if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { // PIZ +#if TINYEXR_USE_PIZ + if ((width == 0) || (num_lines == 0) || (pixel_data_size == 0)) { + // Invalid input #90 + return false; + } + + // Allocate original data size. + std::vector outBuf(static_cast( + static_cast(width * num_lines) * pixel_data_size)); + size_t tmpBufLen = outBuf.size(); + + bool ret = tinyexr::DecompressPiz( + reinterpret_cast(&outBuf.at(0)), data_ptr, tmpBufLen, + data_len, static_cast(num_channels), channels, width, num_lines); + + if (!ret) { + return false; + } + + // For PIZ_COMPRESSION: + // pixel sample data for channel 0 for scanline 0 + // pixel sample data for channel 1 for scanline 0 + // pixel sample data for channel ... for scanline 0 + // pixel sample data for channel n for scanline 0 + // pixel sample data for channel 0 for scanline 1 + // pixel sample data for channel 1 for scanline 1 + // pixel sample data for channel ... for scanline 1 + // pixel sample data for channel n for scanline 1 + // ... + for (size_t c = 0; c < static_cast(num_channels); c++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned short *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + FP16 hf; + + // hf.u = line_ptr[u]; + // use `cpy` to avoid unaligned memory access when compiler's + // optimization is on. + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + unsigned short *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += static_cast( + (height - 1 - (line_no + static_cast(v)))) * + static_cast(x_stride) + + u; + } + *image = hf.u; + } else { // HALF -> FLOAT + FP32 f32 = half_to_float(hf); + float *image = reinterpret_cast(out_images)[c]; + size_t offset = 0; + if (line_order == 0) { + offset = (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + offset = static_cast( + (height - 1 - (line_no + static_cast(v)))) * + static_cast(x_stride) + + u; + } + image += offset; + *image = f32.f; + } + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT); + + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned int *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + unsigned int val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(&val); + + unsigned int *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += static_cast( + (height - 1 - (line_no + static_cast(v)))) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); + for (size_t v = 0; v < static_cast(num_lines); v++) { + const float *line_ptr = reinterpret_cast(&outBuf.at( + v * pixel_data_size * static_cast(x_stride) + + channel_offset_list[c] * static_cast(x_stride))); + for (size_t u = 0; u < static_cast(width); u++) { + float val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += static_cast( + (height - 1 - (line_no + static_cast(v)))) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else { + assert(0); + } + } +#else + assert(0 && "PIZ is enabled in this build"); + return false; +#endif + + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS || + compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + // Allocate original data size. + std::vector outBuf(static_cast(width) * + static_cast(num_lines) * + pixel_data_size); + + unsigned long dstLen = static_cast(outBuf.size()); + assert(dstLen > 0); + if (!tinyexr::DecompressZip( + reinterpret_cast(&outBuf.at(0)), &dstLen, data_ptr, + static_cast(data_len))) { + return false; + } + + // For ZIP_COMPRESSION: + // pixel sample data for channel 0 for scanline 0 + // pixel sample data for channel 1 for scanline 0 + // pixel sample data for channel ... for scanline 0 + // pixel sample data for channel n for scanline 0 + // pixel sample data for channel 0 for scanline 1 + // pixel sample data for channel 1 for scanline 1 + // pixel sample data for channel ... for scanline 1 + // pixel sample data for channel n for scanline 1 + // ... + for (size_t c = 0; c < static_cast(num_channels); c++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned short *line_ptr = reinterpret_cast( + &outBuf.at(v * static_cast(pixel_data_size) * + static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + tinyexr::FP16 hf; + + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + unsigned short *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = hf.u; + } else { // HALF -> FLOAT + tinyexr::FP32 f32 = half_to_float(hf); + float *image = reinterpret_cast(out_images)[c]; + size_t offset = 0; + if (line_order == 0) { + offset = (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + offset = (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + image += offset; + + *image = f32.f; + } + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT); + + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned int *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + unsigned int val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(&val); + + unsigned int *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); + for (size_t v = 0; v < static_cast(num_lines); v++) { + const float *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + float val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else { + assert(0); + return false; + } + } + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) { + // Allocate original data size. + std::vector outBuf(static_cast(width) * + static_cast(num_lines) * + pixel_data_size); + + unsigned long dstLen = static_cast(outBuf.size()); + if (dstLen == 0) { + return false; + } + + if (!tinyexr::DecompressRle(reinterpret_cast(&outBuf.at(0)), + dstLen, data_ptr, + static_cast(data_len))) { + return false; + } + + // For RLE_COMPRESSION: + // pixel sample data for channel 0 for scanline 0 + // pixel sample data for channel 1 for scanline 0 + // pixel sample data for channel ... for scanline 0 + // pixel sample data for channel n for scanline 0 + // pixel sample data for channel 0 for scanline 1 + // pixel sample data for channel 1 for scanline 1 + // pixel sample data for channel ... for scanline 1 + // pixel sample data for channel n for scanline 1 + // ... + for (size_t c = 0; c < static_cast(num_channels); c++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned short *line_ptr = reinterpret_cast( + &outBuf.at(v * static_cast(pixel_data_size) * + static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + tinyexr::FP16 hf; + + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + unsigned short *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = hf.u; + } else { // HALF -> FLOAT + tinyexr::FP32 f32 = half_to_float(hf); + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = f32.f; + } + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT); + + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned int *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + unsigned int val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(&val); + + unsigned int *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); + for (size_t v = 0; v < static_cast(num_lines); v++) { + const float *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + float val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else { + assert(0); + return false; + } + } + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { +#if TINYEXR_USE_ZFP + tinyexr::ZFPCompressionParam zfp_compression_param; + if (!FindZFPCompressionParam(&zfp_compression_param, attributes, + num_attributes)) { + assert(0); + return false; + } + + // Allocate original data size. + std::vector outBuf(static_cast(width) * + static_cast(num_lines) * + pixel_data_size); + + unsigned long dstLen = outBuf.size(); + assert(dstLen > 0); + tinyexr::DecompressZfp(reinterpret_cast(&outBuf.at(0)), width, + num_lines, num_channels, data_ptr, + static_cast(data_len), + zfp_compression_param); + + // For ZFP_COMPRESSION: + // pixel sample data for channel 0 for scanline 0 + // pixel sample data for channel 1 for scanline 0 + // pixel sample data for channel ... for scanline 0 + // pixel sample data for channel n for scanline 0 + // pixel sample data for channel 0 for scanline 1 + // pixel sample data for channel 1 for scanline 1 + // pixel sample data for channel ... for scanline 1 + // pixel sample data for channel n for scanline 1 + // ... + for (size_t c = 0; c < static_cast(num_channels); c++) { + assert(channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT); + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); + for (size_t v = 0; v < static_cast(num_lines); v++) { + const float *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + float val; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else { + assert(0); + return false; + } + } +#else + (void)attributes; + (void)num_attributes; + (void)num_channels; + assert(0); + return false; +#endif + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) { + for (size_t c = 0; c < num_channels; c++) { + for (size_t v = 0; v < static_cast(num_lines); v++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + const unsigned short *line_ptr = + reinterpret_cast( + data_ptr + v * pixel_data_size * size_t(width) + + channel_offset_list[c] * static_cast(width)); + + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + unsigned short *outLine = + reinterpret_cast(out_images[c]); + if (line_order == 0) { + outLine += (size_t(y) + v) * size_t(x_stride); + } else { + outLine += + (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); + } + + for (int u = 0; u < width; u++) { + tinyexr::FP16 hf; + + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + outLine[u] = hf.u; + } + } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + float *outLine = reinterpret_cast(out_images[c]); + if (line_order == 0) { + outLine += (size_t(y) + v) * size_t(x_stride); + } else { + outLine += + (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); + } + + if (reinterpret_cast(line_ptr + width) > + (data_ptr + data_len)) { + // Insufficient data size + return false; + } + + for (int u = 0; u < width; u++) { + tinyexr::FP16 hf; + + // address may not be aliged. use byte-wise copy for safety.#76 + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + tinyexr::FP32 f32 = half_to_float(hf); + + outLine[u] = f32.f; + } + } else { + assert(0); + return false; + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + const float *line_ptr = reinterpret_cast( + data_ptr + v * pixel_data_size * size_t(width) + + channel_offset_list[c] * static_cast(width)); + + float *outLine = reinterpret_cast(out_images[c]); + if (line_order == 0) { + outLine += (size_t(y) + v) * size_t(x_stride); + } else { + outLine += + (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); + } + + if (reinterpret_cast(line_ptr + width) > + (data_ptr + data_len)) { + // Insufficient data size + return false; + } + + for (int u = 0; u < width; u++) { + float val; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + outLine[u] = val; + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + const unsigned int *line_ptr = reinterpret_cast( + data_ptr + v * pixel_data_size * size_t(width) + + channel_offset_list[c] * static_cast(width)); + + unsigned int *outLine = + reinterpret_cast(out_images[c]); + if (line_order == 0) { + outLine += (size_t(y) + v) * size_t(x_stride); + } else { + outLine += + (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); + } + + for (int u = 0; u < width; u++) { + if (reinterpret_cast(line_ptr + u) >= + (data_ptr + data_len)) { + // Corrupsed data? + return false; + } + + unsigned int val; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + outLine[u] = val; + } + } + } + } + } + + return true; +} + +static void DecodeTiledPixelData( + unsigned char **out_images, int *width, int *height, + const int *requested_pixel_types, const unsigned char *data_ptr, + size_t data_len, int compression_type, int line_order, int data_width, + int data_height, int tile_offset_x, int tile_offset_y, int tile_size_x, + int tile_size_y, size_t pixel_data_size, size_t num_attributes, + const EXRAttribute *attributes, size_t num_channels, + const EXRChannelInfo *channels, + const std::vector &channel_offset_list) { + assert(tile_offset_x * tile_size_x < data_width); + assert(tile_offset_y * tile_size_y < data_height); + + // Compute actual image size in a tile. + if ((tile_offset_x + 1) * tile_size_x >= data_width) { + (*width) = data_width - (tile_offset_x * tile_size_x); + } else { + (*width) = tile_size_x; + } + + if ((tile_offset_y + 1) * tile_size_y >= data_height) { + (*height) = data_height - (tile_offset_y * tile_size_y); + } else { + (*height) = tile_size_y; + } + + // Image size = tile size. + DecodePixelData(out_images, requested_pixel_types, data_ptr, data_len, + compression_type, line_order, (*width), tile_size_y, + /* stride */ tile_size_x, /* y */ 0, /* line_no */ 0, + (*height), pixel_data_size, num_attributes, attributes, + num_channels, channels, channel_offset_list); +} + +static bool ComputeChannelLayout(std::vector *channel_offset_list, + int *pixel_data_size, size_t *channel_offset, + int num_channels, + const EXRChannelInfo *channels) { + channel_offset_list->resize(static_cast(num_channels)); + + (*pixel_data_size) = 0; + (*channel_offset) = 0; + + for (size_t c = 0; c < static_cast(num_channels); c++) { + (*channel_offset_list)[c] = (*channel_offset); + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + (*pixel_data_size) += sizeof(unsigned short); + (*channel_offset) += sizeof(unsigned short); + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + (*pixel_data_size) += sizeof(float); + (*channel_offset) += sizeof(float); + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + (*pixel_data_size) += sizeof(unsigned int); + (*channel_offset) += sizeof(unsigned int); + } else { + // ??? + return false; + } + } + return true; +} + +static unsigned char **AllocateImage(int num_channels, + const EXRChannelInfo *channels, + const int *requested_pixel_types, + int data_width, int data_height) { + unsigned char **images = + reinterpret_cast(static_cast( + malloc(sizeof(float *) * static_cast(num_channels)))); + + for (size_t c = 0; c < static_cast(num_channels); c++) { + size_t data_len = + static_cast(data_width) * static_cast(data_height); + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + // pixel_data_size += sizeof(unsigned short); + // channel_offset += sizeof(unsigned short); + // Alloc internal image for half type. + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + images[c] = + reinterpret_cast(static_cast( + malloc(sizeof(unsigned short) * data_len))); + } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + images[c] = reinterpret_cast( + static_cast(malloc(sizeof(float) * data_len))); + } else { + assert(0); + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + // pixel_data_size += sizeof(float); + // channel_offset += sizeof(float); + images[c] = reinterpret_cast( + static_cast(malloc(sizeof(float) * data_len))); + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + // pixel_data_size += sizeof(unsigned int); + // channel_offset += sizeof(unsigned int); + images[c] = reinterpret_cast( + static_cast(malloc(sizeof(unsigned int) * data_len))); + } else { + assert(0); + } + } + + return images; +} + +static int ParseEXRHeader(HeaderInfo *info, bool *empty_header, + const EXRVersion *version, std::string *err, + const unsigned char *buf, size_t size) { + const char *marker = reinterpret_cast(&buf[0]); + + if (empty_header) { + (*empty_header) = false; + } + + if (version->multipart) { + if (size > 0 && marker[0] == '\0') { + // End of header list. + if (empty_header) { + (*empty_header) = true; + } + return TINYEXR_SUCCESS; + } + } + + // According to the spec, the header of every OpenEXR file must contain at + // least the following attributes: + // + // channels chlist + // compression compression + // dataWindow box2i + // displayWindow box2i + // lineOrder lineOrder + // pixelAspectRatio float + // screenWindowCenter v2f + // screenWindowWidth float + bool has_channels = false; + bool has_compression = false; + bool has_data_window = false; + bool has_display_window = false; + bool has_line_order = false; + bool has_pixel_aspect_ratio = false; + bool has_screen_window_center = false; + bool has_screen_window_width = false; + + info->data_window[0] = 0; + info->data_window[1] = 0; + info->data_window[2] = 0; + info->data_window[3] = 0; + info->line_order = 0; // @fixme + info->display_window[0] = 0; + info->display_window[1] = 0; + info->display_window[2] = 0; + info->display_window[3] = 0; + info->screen_window_center[0] = 0.0f; + info->screen_window_center[1] = 0.0f; + info->screen_window_width = -1.0f; + info->pixel_aspect_ratio = -1.0f; + + info->tile_size_x = -1; + info->tile_size_y = -1; + info->tile_level_mode = -1; + info->tile_rounding_mode = -1; + + info->attributes.clear(); + + // Read attributes + size_t orig_size = size; + for (size_t nattr = 0; nattr < TINYEXR_MAX_HEADER_ATTRIBUTES; nattr++) { + if (0 == size) { + if (err) { + (*err) += "Insufficient data size for attributes.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } else if (marker[0] == '\0') { + size--; + break; + } + + std::string attr_name; + std::string attr_type; + std::vector data; + size_t marker_size; + if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size, + marker, size)) { + if (err) { + (*err) += "Failed to read attribute.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + marker += marker_size; + size -= marker_size; + + if (version->tiled && attr_name.compare("tiles") == 0) { + unsigned int x_size, y_size; + unsigned char tile_mode; + assert(data.size() == 9); + memcpy(&x_size, &data.at(0), sizeof(int)); + memcpy(&y_size, &data.at(4), sizeof(int)); + tile_mode = data[8]; + tinyexr::swap4(&x_size); + tinyexr::swap4(&y_size); + + info->tile_size_x = static_cast(x_size); + info->tile_size_y = static_cast(y_size); + + // mode = levelMode + roundingMode * 16 + info->tile_level_mode = tile_mode & 0x3; + info->tile_rounding_mode = (tile_mode >> 4) & 0x1; + + } else if (attr_name.compare("compression") == 0) { + bool ok = false; + if (data[0] < TINYEXR_COMPRESSIONTYPE_PIZ) { + ok = true; + } + + if (data[0] == TINYEXR_COMPRESSIONTYPE_PIZ) { +#if TINYEXR_USE_PIZ + ok = true; +#else + if (err) { + (*err) = "PIZ compression is not supported."; + } + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; +#endif + } + + if (data[0] == TINYEXR_COMPRESSIONTYPE_ZFP) { +#if TINYEXR_USE_ZFP + ok = true; +#else + if (err) { + (*err) = "ZFP compression is not supported."; + } + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; +#endif + } + + if (!ok) { + if (err) { + (*err) = "Unknown compression type."; + } + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + info->compression_type = static_cast(data[0]); + has_compression = true; + + } else if (attr_name.compare("channels") == 0) { + // name: zero-terminated string, from 1 to 255 bytes long + // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2 + // pLinear: unsigned char, possible values are 0 and 1 + // reserved: three chars, should be zero + // xSampling: int + // ySampling: int + + if (!ReadChannelInfo(info->channels, data)) { + if (err) { + (*err) += "Failed to parse channel info.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + if (info->channels.size() < 1) { + if (err) { + (*err) += "# of channels is zero.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + has_channels = true; + + } else if (attr_name.compare("dataWindow") == 0) { + if (data.size() >= 16) { + memcpy(&info->data_window[0], &data.at(0), sizeof(int)); + memcpy(&info->data_window[1], &data.at(4), sizeof(int)); + memcpy(&info->data_window[2], &data.at(8), sizeof(int)); + memcpy(&info->data_window[3], &data.at(12), sizeof(int)); + tinyexr::swap4(reinterpret_cast(&info->data_window[0])); + tinyexr::swap4(reinterpret_cast(&info->data_window[1])); + tinyexr::swap4(reinterpret_cast(&info->data_window[2])); + tinyexr::swap4(reinterpret_cast(&info->data_window[3])); + has_data_window = true; + } + } else if (attr_name.compare("displayWindow") == 0) { + if (data.size() >= 16) { + memcpy(&info->display_window[0], &data.at(0), sizeof(int)); + memcpy(&info->display_window[1], &data.at(4), sizeof(int)); + memcpy(&info->display_window[2], &data.at(8), sizeof(int)); + memcpy(&info->display_window[3], &data.at(12), sizeof(int)); + tinyexr::swap4( + reinterpret_cast(&info->display_window[0])); + tinyexr::swap4( + reinterpret_cast(&info->display_window[1])); + tinyexr::swap4( + reinterpret_cast(&info->display_window[2])); + tinyexr::swap4( + reinterpret_cast(&info->display_window[3])); + + has_display_window = true; + } + } else if (attr_name.compare("lineOrder") == 0) { + if (data.size() >= 1) { + info->line_order = static_cast(data[0]); + has_line_order = true; + } + } else if (attr_name.compare("pixelAspectRatio") == 0) { + if (data.size() >= sizeof(float)) { + memcpy(&info->pixel_aspect_ratio, &data.at(0), sizeof(float)); + tinyexr::swap4( + reinterpret_cast(&info->pixel_aspect_ratio)); + has_pixel_aspect_ratio = true; + } + } else if (attr_name.compare("screenWindowCenter") == 0) { + if (data.size() >= 8) { + memcpy(&info->screen_window_center[0], &data.at(0), sizeof(float)); + memcpy(&info->screen_window_center[1], &data.at(4), sizeof(float)); + tinyexr::swap4( + reinterpret_cast(&info->screen_window_center[0])); + tinyexr::swap4( + reinterpret_cast(&info->screen_window_center[1])); + has_screen_window_center = true; + } + } else if (attr_name.compare("screenWindowWidth") == 0) { + if (data.size() >= sizeof(float)) { + memcpy(&info->screen_window_width, &data.at(0), sizeof(float)); + tinyexr::swap4( + reinterpret_cast(&info->screen_window_width)); + + has_screen_window_width = true; + } + } else if (attr_name.compare("chunkCount") == 0) { + if (data.size() >= sizeof(int)) { + memcpy(&info->chunk_count, &data.at(0), sizeof(int)); + tinyexr::swap4(reinterpret_cast(&info->chunk_count)); + } + } else { + // Custom attribute(up to TINYEXR_MAX_CUSTOM_ATTRIBUTES) + if (info->attributes.size() < TINYEXR_MAX_CUSTOM_ATTRIBUTES) { + EXRAttribute attrib; +#ifdef _MSC_VER + strncpy_s(attrib.name, attr_name.c_str(), 255); + strncpy_s(attrib.type, attr_type.c_str(), 255); +#else + strncpy(attrib.name, attr_name.c_str(), 255); + strncpy(attrib.type, attr_type.c_str(), 255); +#endif + attrib.name[255] = '\0'; + attrib.type[255] = '\0'; + attrib.size = static_cast(data.size()); + attrib.value = static_cast(malloc(data.size())); + memcpy(reinterpret_cast(attrib.value), &data.at(0), + data.size()); + info->attributes.push_back(attrib); + } + } + } + + // Check if required attributes exist + { + std::stringstream ss_err; + + if (!has_compression) { + ss_err << "\"compression\" attribute not found in the header." + << std::endl; + } + + if (!has_channels) { + ss_err << "\"channels\" attribute not found in the header." << std::endl; + } + + if (!has_line_order) { + ss_err << "\"lineOrder\" attribute not found in the header." << std::endl; + } + + if (!has_display_window) { + ss_err << "\"displayWindow\" attribute not found in the header." + << std::endl; + } + + if (!has_data_window) { + ss_err << "\"dataWindow\" attribute not found in the header or invalid." + << std::endl; + } + + if (!has_pixel_aspect_ratio) { + ss_err << "\"pixelAspectRatio\" attribute not found in the header." + << std::endl; + } + + if (!has_screen_window_width) { + ss_err << "\"screenWindowWidth\" attribute not found in the header." + << std::endl; + } + + if (!has_screen_window_center) { + ss_err << "\"screenWindowCenter\" attribute not found in the header." + << std::endl; + } + + if (!(ss_err.str().empty())) { + if (err) { + (*err) += ss_err.str(); + } + return TINYEXR_ERROR_INVALID_HEADER; + } + } + + info->header_len = static_cast(orig_size - size); + + return TINYEXR_SUCCESS; +} + +// C++ HeaderInfo to C EXRHeader conversion. +static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) { + exr_header->pixel_aspect_ratio = info.pixel_aspect_ratio; + exr_header->screen_window_center[0] = info.screen_window_center[0]; + exr_header->screen_window_center[1] = info.screen_window_center[1]; + exr_header->screen_window_width = info.screen_window_width; + exr_header->chunk_count = info.chunk_count; + exr_header->display_window[0] = info.display_window[0]; + exr_header->display_window[1] = info.display_window[1]; + exr_header->display_window[2] = info.display_window[2]; + exr_header->display_window[3] = info.display_window[3]; + exr_header->data_window[0] = info.data_window[0]; + exr_header->data_window[1] = info.data_window[1]; + exr_header->data_window[2] = info.data_window[2]; + exr_header->data_window[3] = info.data_window[3]; + exr_header->line_order = info.line_order; + exr_header->compression_type = info.compression_type; + + exr_header->tile_size_x = info.tile_size_x; + exr_header->tile_size_y = info.tile_size_y; + exr_header->tile_level_mode = info.tile_level_mode; + exr_header->tile_rounding_mode = info.tile_rounding_mode; + + exr_header->num_channels = static_cast(info.channels.size()); + + exr_header->channels = static_cast(malloc( + sizeof(EXRChannelInfo) * static_cast(exr_header->num_channels))); + for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { +#ifdef _MSC_VER + strncpy_s(exr_header->channels[c].name, info.channels[c].name.c_str(), 255); +#else + strncpy(exr_header->channels[c].name, info.channels[c].name.c_str(), 255); +#endif + // manually add '\0' for safety. + exr_header->channels[c].name[255] = '\0'; + + exr_header->channels[c].pixel_type = info.channels[c].pixel_type; + exr_header->channels[c].p_linear = info.channels[c].p_linear; + exr_header->channels[c].x_sampling = info.channels[c].x_sampling; + exr_header->channels[c].y_sampling = info.channels[c].y_sampling; + } + + exr_header->pixel_types = static_cast( + malloc(sizeof(int) * static_cast(exr_header->num_channels))); + for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { + exr_header->pixel_types[c] = info.channels[c].pixel_type; + } + + // Initially fill with values of `pixel_types` + exr_header->requested_pixel_types = static_cast( + malloc(sizeof(int) * static_cast(exr_header->num_channels))); + for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { + exr_header->requested_pixel_types[c] = info.channels[c].pixel_type; + } + + exr_header->num_custom_attributes = static_cast(info.attributes.size()); + + if (exr_header->num_custom_attributes > 0) { + // TODO(syoyo): Report warning when # of attributes exceeds + // `TINYEXR_MAX_CUSTOM_ATTRIBUTES` + if (exr_header->num_custom_attributes > TINYEXR_MAX_CUSTOM_ATTRIBUTES) { + exr_header->num_custom_attributes = TINYEXR_MAX_CUSTOM_ATTRIBUTES; + } + + exr_header->custom_attributes = static_cast(malloc( + sizeof(EXRAttribute) * size_t(exr_header->num_custom_attributes))); + + for (size_t i = 0; i < info.attributes.size(); i++) { + memcpy(exr_header->custom_attributes[i].name, info.attributes[i].name, + 256); + memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type, + 256); + exr_header->custom_attributes[i].size = info.attributes[i].size; + // Just copy poiner + exr_header->custom_attributes[i].value = info.attributes[i].value; + } + + } else { + exr_header->custom_attributes = NULL; + } + + exr_header->header_len = info.header_len; +} + +static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header, + const std::vector &offsets, + const unsigned char *head, const size_t size, + std::string *err) { + int num_channels = exr_header->num_channels; + + int num_scanline_blocks = 1; + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + num_scanline_blocks = 16; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + num_scanline_blocks = 32; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + num_scanline_blocks = 16; + } + + int data_width = exr_header->data_window[2] - exr_header->data_window[0] + 1; + int data_height = exr_header->data_window[3] - exr_header->data_window[1] + 1; + + if ((data_width < 0) || (data_height < 0)) { + if (err) { + std::stringstream ss; + ss << "Invalid data width or data height: " << data_width << ", " + << data_height << std::endl; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_DATA; + } + + // Do not allow too large data_width and data_height. header invalid? + { + const int threshold = 1024 * 8192; // heuristics + if ((data_width > threshold) || (data_height > threshold)) { + if (err) { + std::stringstream ss; + ss << "data_with or data_height too large. data_width: " << data_width + << ", " + << "data_height = " << data_height << std::endl; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_DATA; + } + } + + size_t num_blocks = offsets.size(); + + std::vector channel_offset_list; + int pixel_data_size = 0; + size_t channel_offset = 0; + if (!tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size, + &channel_offset, num_channels, + exr_header->channels)) { + if (err) { + (*err) += "Failed to compute channel layout.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + bool invalid_data = false; // TODO(LTE): Use atomic lock for MT safety. + + if (exr_header->tiled) { + // value check + if (exr_header->tile_size_x < 0) { + if (err) { + std::stringstream ss; + ss << "Invalid tile size x : " << exr_header->tile_size_x << "\n"; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_HEADER; + } + + if (exr_header->tile_size_y < 0) { + if (err) { + std::stringstream ss; + ss << "Invalid tile size y : " << exr_header->tile_size_y << "\n"; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_HEADER; + } + + size_t num_tiles = offsets.size(); // = # of blocks + + exr_image->tiles = static_cast( + calloc(sizeof(EXRTile), static_cast(num_tiles))); + + for (size_t tile_idx = 0; tile_idx < num_tiles; tile_idx++) { + // Allocate memory for each tile. + exr_image->tiles[tile_idx].images = tinyexr::AllocateImage( + num_channels, exr_header->channels, exr_header->requested_pixel_types, + exr_header->tile_size_x, exr_header->tile_size_y); + + // 16 byte: tile coordinates + // 4 byte : data size + // ~ : data(uncompressed or compressed) + if (offsets[tile_idx] + sizeof(int) * 5 > size) { + if (err) { + (*err) += "Insufficient data size.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + size_t data_size = size_t(size - (offsets[tile_idx] + sizeof(int) * 5)); + const unsigned char *data_ptr = + reinterpret_cast(head + offsets[tile_idx]); + + int tile_coordinates[4]; + memcpy(tile_coordinates, data_ptr, sizeof(int) * 4); + tinyexr::swap4(reinterpret_cast(&tile_coordinates[0])); + tinyexr::swap4(reinterpret_cast(&tile_coordinates[1])); + tinyexr::swap4(reinterpret_cast(&tile_coordinates[2])); + tinyexr::swap4(reinterpret_cast(&tile_coordinates[3])); + + // @todo{ LoD } + if (tile_coordinates[2] != 0) { + return TINYEXR_ERROR_UNSUPPORTED_FEATURE; + } + if (tile_coordinates[3] != 0) { + return TINYEXR_ERROR_UNSUPPORTED_FEATURE; + } + + int data_len; + memcpy(&data_len, data_ptr + 16, + sizeof(int)); // 16 = sizeof(tile_coordinates) + tinyexr::swap4(reinterpret_cast(&data_len)); + + if (data_len < 4 || size_t(data_len) > data_size) { + if (err) { + (*err) += "Insufficient data length.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + // Move to data addr: 20 = 16 + 4; + data_ptr += 20; + + tinyexr::DecodeTiledPixelData( + exr_image->tiles[tile_idx].images, + &(exr_image->tiles[tile_idx].width), + &(exr_image->tiles[tile_idx].height), + exr_header->requested_pixel_types, data_ptr, + static_cast(data_len), exr_header->compression_type, + exr_header->line_order, data_width, data_height, tile_coordinates[0], + tile_coordinates[1], exr_header->tile_size_x, exr_header->tile_size_y, + static_cast(pixel_data_size), + static_cast(exr_header->num_custom_attributes), + exr_header->custom_attributes, + static_cast(exr_header->num_channels), exr_header->channels, + channel_offset_list); + + exr_image->tiles[tile_idx].offset_x = tile_coordinates[0]; + exr_image->tiles[tile_idx].offset_y = tile_coordinates[1]; + exr_image->tiles[tile_idx].level_x = tile_coordinates[2]; + exr_image->tiles[tile_idx].level_y = tile_coordinates[3]; + + exr_image->num_tiles = static_cast(num_tiles); + } + } else { // scanline format + + // Don't allow too large image(256GB * pixel_data_size or more). Workaround + // for #104. + size_t total_data_len = + size_t(data_width) * size_t(data_height) * size_t(num_channels); + const bool total_data_len_overflown = sizeof(void*) == 8 ? (total_data_len >= 0x4000000000) : false; + if ((total_data_len == 0) || total_data_len_overflown ) { + if (err) { + std::stringstream ss; + ss << "Image data size is zero or too large: width = " << data_width + << ", height = " << data_height << ", channels = " << num_channels + << std::endl; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_DATA; + } + + exr_image->images = tinyexr::AllocateImage( + num_channels, exr_header->channels, exr_header->requested_pixel_types, + data_width, data_height); + +#ifdef _OPENMP +#pragma omp parallel for +#endif + for (int y = 0; y < static_cast(num_blocks); y++) { + size_t y_idx = static_cast(y); + + if (offsets[y_idx] + sizeof(int) * 2 > size) { + invalid_data = true; + } else { + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(uncompressed or compressed) + size_t data_size = size_t(size - (offsets[y_idx] + sizeof(int) * 2)); + const unsigned char *data_ptr = + reinterpret_cast(head + offsets[y_idx]); + + int line_no; + memcpy(&line_no, data_ptr, sizeof(int)); + int data_len; + memcpy(&data_len, data_ptr + 4, sizeof(int)); + tinyexr::swap4(reinterpret_cast(&line_no)); + tinyexr::swap4(reinterpret_cast(&data_len)); + + if (size_t(data_len) > data_size) { + invalid_data = true; + + } else if ((line_no > (2 << 20)) || (line_no < -(2 << 20))) { + // Too large value. Assume this is invalid + // 2**20 = 1048576 = heuristic value. + invalid_data = true; + } else if (data_len == 0) { + // TODO(syoyo): May be ok to raise the threshold for example `data_len + // < 4` + invalid_data = true; + } else { + // line_no may be negative. + int end_line_no = (std::min)(line_no + num_scanline_blocks, + (exr_header->data_window[3] + 1)); + + int num_lines = end_line_no - line_no; + + if (num_lines <= 0) { + invalid_data = true; + } else { + // Move to data addr: 8 = 4 + 4; + data_ptr += 8; + + // Adjust line_no with data_window.bmin.y + + // overflow check + tinyexr_int64 lno = static_cast(line_no) - static_cast(exr_header->data_window[1]); + if (lno > std::numeric_limits::max()) { + line_no = -1; // invalid + } else if (lno < -std::numeric_limits::max()) { + line_no = -1; // invalid + } else { + line_no -= exr_header->data_window[1]; + } + + if (line_no < 0) { + invalid_data = true; + } else { + if (!tinyexr::DecodePixelData( + exr_image->images, exr_header->requested_pixel_types, + data_ptr, static_cast(data_len), + exr_header->compression_type, exr_header->line_order, + data_width, data_height, data_width, y, line_no, + num_lines, static_cast(pixel_data_size), + static_cast(exr_header->num_custom_attributes), + exr_header->custom_attributes, + static_cast(exr_header->num_channels), + exr_header->channels, channel_offset_list)) { + invalid_data = true; + } + } + } + } + } + } // omp parallel + } + + if (invalid_data) { + if (err) { + std::stringstream ss; + (*err) += "Invalid data found when decoding pixels.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + // Overwrite `pixel_type` with `requested_pixel_type`. + { + for (int c = 0; c < exr_header->num_channels; c++) { + exr_header->pixel_types[c] = exr_header->requested_pixel_types[c]; + } + } + + { + exr_image->num_channels = num_channels; + + exr_image->width = data_width; + exr_image->height = data_height; + } + + return TINYEXR_SUCCESS; +} + +static bool ReconstructLineOffsets( + std::vector *offsets, size_t n, + const unsigned char *head, const unsigned char *marker, const size_t size) { + assert(head < marker); + assert(offsets->size() == n); + + for (size_t i = 0; i < n; i++) { + size_t offset = static_cast(marker - head); + // Offset should not exceed whole EXR file/data size. + if ((offset + sizeof(tinyexr::tinyexr_uint64)) >= size) { + return false; + } + + int y; + unsigned int data_len; + + memcpy(&y, marker, sizeof(int)); + memcpy(&data_len, marker + 4, sizeof(unsigned int)); + + if (data_len >= size) { + return false; + } + + tinyexr::swap4(reinterpret_cast(&y)); + tinyexr::swap4(reinterpret_cast(&data_len)); + + (*offsets)[i] = offset; + + marker += data_len + 8; // 8 = 4 bytes(y) + 4 bytes(data_len) + } + + return true; +} + +static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header, + const unsigned char *head, + const unsigned char *marker, const size_t size, + const char **err) { + if (exr_image == NULL || exr_header == NULL || head == NULL || + marker == NULL || (size <= tinyexr::kEXRVersionSize)) { + tinyexr::SetErrorMessage("Invalid argument for DecodeEXRImage().", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + int num_scanline_blocks = 1; + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + num_scanline_blocks = 16; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + num_scanline_blocks = 32; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + num_scanline_blocks = 16; + } + + int data_width = exr_header->data_window[2] - exr_header->data_window[0]; + if (data_width >= std::numeric_limits::max()) { + // Issue 63 + tinyexr::SetErrorMessage("Invalid data width value", err); + return TINYEXR_ERROR_INVALID_DATA; + } + data_width++; + + int data_height = exr_header->data_window[3] - exr_header->data_window[1]; + if (data_height >= std::numeric_limits::max()) { + tinyexr::SetErrorMessage("Invalid data height value", err); + return TINYEXR_ERROR_INVALID_DATA; + } + data_height++; + + if ((data_width < 0) || (data_height < 0)) { + tinyexr::SetErrorMessage("data width or data height is negative.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + // Do not allow too large data_width and data_height. header invalid? + { + const int threshold = 1024 * 8192; // heuristics + if (data_width > threshold) { + tinyexr::SetErrorMessage("data width too large.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + if (data_height > threshold) { + tinyexr::SetErrorMessage("data height too large.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + + // Read offset tables. + size_t num_blocks = 0; + + if (exr_header->chunk_count > 0) { + // Use `chunkCount` attribute. + num_blocks = static_cast(exr_header->chunk_count); + } else if (exr_header->tiled) { + // @todo { LoD } + size_t num_x_tiles = static_cast(data_width) / + static_cast(exr_header->tile_size_x); + if (num_x_tiles * static_cast(exr_header->tile_size_x) < + static_cast(data_width)) { + num_x_tiles++; + } + size_t num_y_tiles = static_cast(data_height) / + static_cast(exr_header->tile_size_y); + if (num_y_tiles * static_cast(exr_header->tile_size_y) < + static_cast(data_height)) { + num_y_tiles++; + } + + num_blocks = num_x_tiles * num_y_tiles; + } else { + num_blocks = static_cast(data_height) / + static_cast(num_scanline_blocks); + if (num_blocks * static_cast(num_scanline_blocks) < + static_cast(data_height)) { + num_blocks++; + } + } + + std::vector offsets(num_blocks); + + for (size_t y = 0; y < num_blocks; y++) { + tinyexr::tinyexr_uint64 offset; + // Issue #81 + if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) { + tinyexr::SetErrorMessage("Insufficient data size in offset table.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64)); + tinyexr::swap8(&offset); + if (offset >= size) { + tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + marker += sizeof(tinyexr::tinyexr_uint64); // = 8 + offsets[y] = offset; + } + + // If line offsets are invalid, we try to reconstruct it. + // See OpenEXR/IlmImf/ImfScanLineInputFile.cpp::readLineOffsets() for details. + for (size_t y = 0; y < num_blocks; y++) { + if (offsets[y] <= 0) { + // TODO(syoyo) Report as warning? + // if (err) { + // stringstream ss; + // ss << "Incomplete lineOffsets." << std::endl; + // (*err) += ss.str(); + //} + bool ret = + ReconstructLineOffsets(&offsets, num_blocks, head, marker, size); + if (ret) { + // OK + break; + } else { + tinyexr::SetErrorMessage( + "Cannot reconstruct lineOffset table in DecodeEXRImage.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + } + + { + std::string e; + int ret = DecodeChunk(exr_image, exr_header, offsets, head, size, &e); + + if (ret != TINYEXR_SUCCESS) { + if (!e.empty()) { + tinyexr::SetErrorMessage(e, err); + } + + // release memory(if exists) + if ((exr_header->num_channels > 0) && exr_image && exr_image->images) { + for (size_t c = 0; c < size_t(exr_header->num_channels); c++) { + if (exr_image->images[c]) { + free(exr_image->images[c]); + exr_image->images[c] = NULL; + } + } + free(exr_image->images); + exr_image->images = NULL; + } + } + + return ret; + } +} + +} // namespace tinyexr + +int LoadEXR(float **out_rgba, int *width, int *height, const char *filename, + const char **err) { + if (out_rgba == NULL) { + tinyexr::SetErrorMessage("Invalid argument for LoadEXR()", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + EXRVersion exr_version; + EXRImage exr_image; + EXRHeader exr_header; + InitEXRHeader(&exr_header); + InitEXRImage(&exr_image); + + { + int ret = ParseEXRVersionFromFile(&exr_version, filename); + if (ret != TINYEXR_SUCCESS) { + tinyexr::SetErrorMessage("Invalid EXR header.", err); + return ret; + } + + if (exr_version.multipart || exr_version.non_image) { + tinyexr::SetErrorMessage( + "Loading multipart or DeepImage is not supported in LoadEXR() API", + err); + return TINYEXR_ERROR_INVALID_DATA; // @fixme. + } + } + + { + int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err); + if (ret != TINYEXR_SUCCESS) { + FreeEXRHeader(&exr_header); + return ret; + } + } + + // Read HALF channel as FLOAT. + for (int i = 0; i < exr_header.num_channels; i++) { + if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) { + exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; + } + } + + { + int ret = LoadEXRImageFromFile(&exr_image, &exr_header, filename, err); + if (ret != TINYEXR_SUCCESS) { + FreeEXRHeader(&exr_header); + return ret; + } + } + + // RGBA + int idxR = -1; + int idxG = -1; + int idxB = -1; + int idxA = -1; + for (int c = 0; c < exr_header.num_channels; c++) { + if (strcmp(exr_header.channels[c].name, "R") == 0) { + idxR = c; + } else if (strcmp(exr_header.channels[c].name, "G") == 0) { + idxG = c; + } else if (strcmp(exr_header.channels[c].name, "B") == 0) { + idxB = c; + } else if (strcmp(exr_header.channels[c].name, "A") == 0) { + idxA = c; + } + } + + if (exr_header.num_channels == 1) { + // Grayscale channel only. + + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + + if (exr_header.tiled) { + for (int it = 0; it < exr_image.num_tiles; it++) { + for (int j = 0; j < exr_header.tile_size_y; j++) { + for (int i = 0; i < exr_header.tile_size_x; i++) { + const int ii = + exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; + const int jj = + exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; + const int idx = ii + jj * exr_image.width; + + // out of region check. + if (ii >= exr_image.width) { + continue; + } + if (jj >= exr_image.height) { + continue; + } + const int srcIdx = i + j * exr_header.tile_size_x; + unsigned char **src = exr_image.tiles[it].images; + (*out_rgba)[4 * idx + 0] = + reinterpret_cast(src)[0][srcIdx]; + (*out_rgba)[4 * idx + 1] = + reinterpret_cast(src)[0][srcIdx]; + (*out_rgba)[4 * idx + 2] = + reinterpret_cast(src)[0][srcIdx]; + (*out_rgba)[4 * idx + 3] = + reinterpret_cast(src)[0][srcIdx]; + } + } + } + } else { + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + const float val = reinterpret_cast(exr_image.images)[0][i]; + (*out_rgba)[4 * i + 0] = val; + (*out_rgba)[4 * i + 1] = val; + (*out_rgba)[4 * i + 2] = val; + (*out_rgba)[4 * i + 3] = val; + } + } + } else { + // Assume RGB(A) + + if (idxR == -1) { + tinyexr::SetErrorMessage("R channel not found", err); + + // @todo { free exr_image } + FreeEXRHeader(&exr_header); + return TINYEXR_ERROR_INVALID_DATA; + } + + if (idxG == -1) { + tinyexr::SetErrorMessage("G channel not found", err); + // @todo { free exr_image } + FreeEXRHeader(&exr_header); + return TINYEXR_ERROR_INVALID_DATA; + } + + if (idxB == -1) { + tinyexr::SetErrorMessage("B channel not found", err); + // @todo { free exr_image } + FreeEXRHeader(&exr_header); + return TINYEXR_ERROR_INVALID_DATA; + } + + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + if (exr_header.tiled) { + for (int it = 0; it < exr_image.num_tiles; it++) { + for (int j = 0; j < exr_header.tile_size_y; j++) { + for (int i = 0; i < exr_header.tile_size_x; i++) { + const int ii = + exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; + const int jj = + exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; + const int idx = ii + jj * exr_image.width; + + // out of region check. + if (ii >= exr_image.width) { + continue; + } + if (jj >= exr_image.height) { + continue; + } + const int srcIdx = i + j * exr_header.tile_size_x; + unsigned char **src = exr_image.tiles[it].images; + (*out_rgba)[4 * idx + 0] = + reinterpret_cast(src)[idxR][srcIdx]; + (*out_rgba)[4 * idx + 1] = + reinterpret_cast(src)[idxG][srcIdx]; + (*out_rgba)[4 * idx + 2] = + reinterpret_cast(src)[idxB][srcIdx]; + if (idxA != -1) { + (*out_rgba)[4 * idx + 3] = + reinterpret_cast(src)[idxA][srcIdx]; + } else { + (*out_rgba)[4 * idx + 3] = 1.0; + } + } + } + } + } else { + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + (*out_rgba)[4 * i + 0] = + reinterpret_cast(exr_image.images)[idxR][i]; + (*out_rgba)[4 * i + 1] = + reinterpret_cast(exr_image.images)[idxG][i]; + (*out_rgba)[4 * i + 2] = + reinterpret_cast(exr_image.images)[idxB][i]; + if (idxA != -1) { + (*out_rgba)[4 * i + 3] = + reinterpret_cast(exr_image.images)[idxA][i]; + } else { + (*out_rgba)[4 * i + 3] = 1.0; + } + } + } + } + + (*width) = exr_image.width; + (*height) = exr_image.height; + + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + + return TINYEXR_SUCCESS; +} + +int IsEXR(const char *filename) { + EXRVersion exr_version; + + int ret = ParseEXRVersionFromFile(&exr_version, filename); + if (ret != TINYEXR_SUCCESS) { + return TINYEXR_ERROR_INVALID_HEADER; + } + + return TINYEXR_SUCCESS; +} + +int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version, + const unsigned char *memory, size_t size, + const char **err) { + if (memory == NULL || exr_header == NULL) { + tinyexr::SetErrorMessage( + "Invalid argument. `memory` or `exr_header` argument is null in " + "ParseEXRHeaderFromMemory()", + err); + + // Invalid argument + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (size < tinyexr::kEXRVersionSize) { + tinyexr::SetErrorMessage("Insufficient header/data size.\n", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + const unsigned char *marker = memory + tinyexr::kEXRVersionSize; + size_t marker_size = size - tinyexr::kEXRVersionSize; + + tinyexr::HeaderInfo info; + info.clear(); + + std::string err_str; + int ret = ParseEXRHeader(&info, NULL, version, &err_str, marker, marker_size); + + if (ret != TINYEXR_SUCCESS) { + if (err && !err_str.empty()) { + tinyexr::SetErrorMessage(err_str, err); + } + } + + ConvertHeader(exr_header, info); + + // transfoer `tiled` from version. + exr_header->tiled = version->tiled; + + return ret; +} + +int LoadEXRFromMemory(float **out_rgba, int *width, int *height, + const unsigned char *memory, size_t size, + const char **err) { + if (out_rgba == NULL || memory == NULL) { + tinyexr::SetErrorMessage("Invalid argument for LoadEXRFromMemory", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + EXRVersion exr_version; + EXRImage exr_image; + EXRHeader exr_header; + + InitEXRHeader(&exr_header); + + int ret = ParseEXRVersionFromMemory(&exr_version, memory, size); + if (ret != TINYEXR_SUCCESS) { + tinyexr::SetErrorMessage("Failed to parse EXR version", err); + return ret; + } + + ret = ParseEXRHeaderFromMemory(&exr_header, &exr_version, memory, size, err); + if (ret != TINYEXR_SUCCESS) { + return ret; + } + + // Read HALF channel as FLOAT. + for (int i = 0; i < exr_header.num_channels; i++) { + if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) { + exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; + } + } + + InitEXRImage(&exr_image); + ret = LoadEXRImageFromMemory(&exr_image, &exr_header, memory, size, err); + if (ret != TINYEXR_SUCCESS) { + return ret; + } + + // RGBA + int idxR = -1; + int idxG = -1; + int idxB = -1; + int idxA = -1; + for (int c = 0; c < exr_header.num_channels; c++) { + if (strcmp(exr_header.channels[c].name, "R") == 0) { + idxR = c; + } else if (strcmp(exr_header.channels[c].name, "G") == 0) { + idxG = c; + } else if (strcmp(exr_header.channels[c].name, "B") == 0) { + idxB = c; + } else if (strcmp(exr_header.channels[c].name, "A") == 0) { + idxA = c; + } + } + + // TODO(syoyo): Refactor removing same code as used in LoadEXR(). + if (exr_header.num_channels == 1) { + // Grayscale channel only. + + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + + if (exr_header.tiled) { + for (int it = 0; it < exr_image.num_tiles; it++) { + for (int j = 0; j < exr_header.tile_size_y; j++) { + for (int i = 0; i < exr_header.tile_size_x; i++) { + const int ii = + exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; + const int jj = + exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; + const int idx = ii + jj * exr_image.width; + + // out of region check. + if (ii >= exr_image.width) { + continue; + } + if (jj >= exr_image.height) { + continue; + } + const int srcIdx = i + j * exr_header.tile_size_x; + unsigned char **src = exr_image.tiles[it].images; + (*out_rgba)[4 * idx + 0] = + reinterpret_cast(src)[0][srcIdx]; + (*out_rgba)[4 * idx + 1] = + reinterpret_cast(src)[0][srcIdx]; + (*out_rgba)[4 * idx + 2] = + reinterpret_cast(src)[0][srcIdx]; + (*out_rgba)[4 * idx + 3] = + reinterpret_cast(src)[0][srcIdx]; + } + } + } + } else { + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + const float val = reinterpret_cast(exr_image.images)[0][i]; + (*out_rgba)[4 * i + 0] = val; + (*out_rgba)[4 * i + 1] = val; + (*out_rgba)[4 * i + 2] = val; + (*out_rgba)[4 * i + 3] = val; + } + } + + } else { + // TODO(syoyo): Support non RGBA image. + + if (idxR == -1) { + tinyexr::SetErrorMessage("R channel not found", err); + + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; + } + + if (idxG == -1) { + tinyexr::SetErrorMessage("G channel not found", err); + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; + } + + if (idxB == -1) { + tinyexr::SetErrorMessage("B channel not found", err); + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; + } + + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + + if (exr_header.tiled) { + for (int it = 0; it < exr_image.num_tiles; it++) { + for (int j = 0; j < exr_header.tile_size_y; j++) + for (int i = 0; i < exr_header.tile_size_x; i++) { + const int ii = + exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; + const int jj = + exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; + const int idx = ii + jj * exr_image.width; + + // out of region check. + if (ii >= exr_image.width) { + continue; + } + if (jj >= exr_image.height) { + continue; + } + const int srcIdx = i + j * exr_header.tile_size_x; + unsigned char **src = exr_image.tiles[it].images; + (*out_rgba)[4 * idx + 0] = + reinterpret_cast(src)[idxR][srcIdx]; + (*out_rgba)[4 * idx + 1] = + reinterpret_cast(src)[idxG][srcIdx]; + (*out_rgba)[4 * idx + 2] = + reinterpret_cast(src)[idxB][srcIdx]; + if (idxA != -1) { + (*out_rgba)[4 * idx + 3] = + reinterpret_cast(src)[idxA][srcIdx]; + } else { + (*out_rgba)[4 * idx + 3] = 1.0; + } + } + } + } else { + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + (*out_rgba)[4 * i + 0] = + reinterpret_cast(exr_image.images)[idxR][i]; + (*out_rgba)[4 * i + 1] = + reinterpret_cast(exr_image.images)[idxG][i]; + (*out_rgba)[4 * i + 2] = + reinterpret_cast(exr_image.images)[idxB][i]; + if (idxA != -1) { + (*out_rgba)[4 * i + 3] = + reinterpret_cast(exr_image.images)[idxA][i]; + } else { + (*out_rgba)[4 * i + 3] = 1.0; + } + } + } + } + + (*width) = exr_image.width; + (*height) = exr_image.height; + + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + + return TINYEXR_SUCCESS; +} + +int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header, + const char *filename, const char **err) { + if (exr_image == NULL) { + tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromFile", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + +#ifdef _WIN32 + FILE *fp = NULL; + fopen_s(&fp, filename, "rb"); +#else + FILE *fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + if (filesize < 16) { + tinyexr::SetErrorMessage("File size too short " + std::string(filename), + err); + return TINYEXR_ERROR_INVALID_FILE; + } + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + fclose(fp); + (void)ret; + } + + return LoadEXRImageFromMemory(exr_image, exr_header, &buf.at(0), filesize, + err); +} + +int LoadEXRImageFromMemory(EXRImage *exr_image, const EXRHeader *exr_header, + const unsigned char *memory, const size_t size, + const char **err) { + if (exr_image == NULL || memory == NULL || + (size < tinyexr::kEXRVersionSize)) { + tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromMemory", + err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (exr_header->header_len == 0) { + tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + const unsigned char *head = memory; + const unsigned char *marker = reinterpret_cast( + memory + exr_header->header_len + + 8); // +8 for magic number + version header. + return tinyexr::DecodeEXRImage(exr_image, exr_header, head, marker, size, + err); +} + +size_t SaveEXRImageToMemory(const EXRImage *exr_image, + const EXRHeader *exr_header, + unsigned char **memory_out, const char **err) { + if (exr_image == NULL || memory_out == NULL || + exr_header->compression_type < 0) { + tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToMemory", err); + return 0; + } + +#if !TINYEXR_USE_PIZ + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + tinyexr::SetErrorMessage("PIZ compression is not supported in this build", + err); + return 0; + } +#endif + +#if !TINYEXR_USE_ZFP + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + tinyexr::SetErrorMessage("ZFP compression is not supported in this build", + err); + return 0; + } +#endif + +#if TINYEXR_USE_ZFP + for (size_t i = 0; i < static_cast(exr_header->num_channels); i++) { + if (exr_header->requested_pixel_types[i] != TINYEXR_PIXELTYPE_FLOAT) { + tinyexr::SetErrorMessage("Pixel type must be FLOAT for ZFP compression", + err); + return 0; + } + } +#endif + + std::vector memory; + + // Header + { + const char header[] = {0x76, 0x2f, 0x31, 0x01}; + memory.insert(memory.end(), header, header + 4); + } + + // Version, scanline. + { + char marker[] = {2, 0, 0, 0}; + /* @todo + if (exr_header->tiled) { + marker[1] |= 0x2; + } + if (exr_header->long_name) { + marker[1] |= 0x4; + } + if (exr_header->non_image) { + marker[1] |= 0x8; + } + if (exr_header->multipart) { + marker[1] |= 0x10; + } + */ + memory.insert(memory.end(), marker, marker + 4); + } + + int num_scanlines = 1; + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + num_scanlines = 16; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + num_scanlines = 32; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + num_scanlines = 16; + } + + // Write attributes. + std::vector channels; + { + std::vector data; + + for (int c = 0; c < exr_header->num_channels; c++) { + tinyexr::ChannelInfo info; + info.p_linear = 0; + info.pixel_type = exr_header->requested_pixel_types[c]; + info.x_sampling = 1; + info.y_sampling = 1; + info.name = std::string(exr_header->channels[c].name); + channels.push_back(info); + } + + tinyexr::WriteChannelInfo(data, channels); + + tinyexr::WriteAttributeToMemory(&memory, "channels", "chlist", &data.at(0), + static_cast(data.size())); + } + + { + int comp = exr_header->compression_type; + tinyexr::swap4(reinterpret_cast(&comp)); + tinyexr::WriteAttributeToMemory( + &memory, "compression", "compression", + reinterpret_cast(&comp), 1); + } + + { + int data[4] = {0, 0, exr_image->width - 1, exr_image->height - 1}; + tinyexr::swap4(reinterpret_cast(&data[0])); + tinyexr::swap4(reinterpret_cast(&data[1])); + tinyexr::swap4(reinterpret_cast(&data[2])); + tinyexr::swap4(reinterpret_cast(&data[3])); + tinyexr::WriteAttributeToMemory( + &memory, "dataWindow", "box2i", + reinterpret_cast(data), sizeof(int) * 4); + tinyexr::WriteAttributeToMemory( + &memory, "displayWindow", "box2i", + reinterpret_cast(data), sizeof(int) * 4); + } + + { + unsigned char line_order = 0; // @fixme { read line_order from EXRHeader } + tinyexr::WriteAttributeToMemory(&memory, "lineOrder", "lineOrder", + &line_order, 1); + } + + { + float aspectRatio = 1.0f; + tinyexr::swap4(reinterpret_cast(&aspectRatio)); + tinyexr::WriteAttributeToMemory( + &memory, "pixelAspectRatio", "float", + reinterpret_cast(&aspectRatio), sizeof(float)); + } + + { + float center[2] = {0.0f, 0.0f}; + tinyexr::swap4(reinterpret_cast(¢er[0])); + tinyexr::swap4(reinterpret_cast(¢er[1])); + tinyexr::WriteAttributeToMemory( + &memory, "screenWindowCenter", "v2f", + reinterpret_cast(center), 2 * sizeof(float)); + } + + { + float w = static_cast(exr_image->width); + tinyexr::swap4(reinterpret_cast(&w)); + tinyexr::WriteAttributeToMemory(&memory, "screenWindowWidth", "float", + reinterpret_cast(&w), + sizeof(float)); + } + + // Custom attributes + if (exr_header->num_custom_attributes > 0) { + for (int i = 0; i < exr_header->num_custom_attributes; i++) { + tinyexr::WriteAttributeToMemory( + &memory, exr_header->custom_attributes[i].name, + exr_header->custom_attributes[i].type, + reinterpret_cast( + exr_header->custom_attributes[i].value), + exr_header->custom_attributes[i].size); + } + } + + { // end of header + unsigned char e = 0; + memory.push_back(e); + } + + int num_blocks = exr_image->height / num_scanlines; + if (num_blocks * num_scanlines < exr_image->height) { + num_blocks++; + } + + std::vector offsets(static_cast(num_blocks)); + + size_t headerSize = memory.size(); + tinyexr::tinyexr_uint64 offset = + headerSize + + static_cast(num_blocks) * + sizeof( + tinyexr::tinyexr_int64); // sizeof(header) + sizeof(offsetTable) + + std::vector > data_list( + static_cast(num_blocks)); + std::vector channel_offset_list( + static_cast(exr_header->num_channels)); + + int pixel_data_size = 0; + size_t channel_offset = 0; + for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { + channel_offset_list[c] = channel_offset; + if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + pixel_data_size += sizeof(unsigned short); + channel_offset += sizeof(unsigned short); + } else if (exr_header->requested_pixel_types[c] == + TINYEXR_PIXELTYPE_FLOAT) { + pixel_data_size += sizeof(float); + channel_offset += sizeof(float); + } else if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT) { + pixel_data_size += sizeof(unsigned int); + channel_offset += sizeof(unsigned int); + } else { + assert(0); + } + } + +#if TINYEXR_USE_ZFP + tinyexr::ZFPCompressionParam zfp_compression_param; + + // Use ZFP compression parameter from custom attributes(if such a parameter + // exists) + { + bool ret = tinyexr::FindZFPCompressionParam( + &zfp_compression_param, exr_header->custom_attributes, + exr_header->num_custom_attributes); + + if (!ret) { + // Use predefined compression parameter. + zfp_compression_param.type = 0; + zfp_compression_param.rate = 2; + } + } +#endif + +// Use signed int since some OpenMP compiler doesn't allow unsigned type for +// `parallel for` +#ifdef _OPENMP +#pragma omp parallel for +#endif + for (int i = 0; i < num_blocks; i++) { + size_t ii = static_cast(i); + int start_y = num_scanlines * i; + int endY = (std::min)(num_scanlines * (i + 1), exr_image->height); + int h = endY - start_y; + + std::vector buf( + static_cast(exr_image->width * h * pixel_data_size)); + + for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { + if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + for (int y = 0; y < h; y++) { + // Assume increasing Y + float *line_ptr = reinterpret_cast(&buf.at( + static_cast(pixel_data_size * y * exr_image->width) + + channel_offset_list[c] * + static_cast(exr_image->width))); + for (int x = 0; x < exr_image->width; x++) { + tinyexr::FP16 h16; + h16.u = reinterpret_cast( + exr_image->images)[c][(y + start_y) * exr_image->width + x]; + + tinyexr::FP32 f32 = half_to_float(h16); + + tinyexr::swap4(reinterpret_cast(&f32.f)); + + // line_ptr[x] = f32.f; + tinyexr::cpy4(line_ptr + x, &(f32.f)); + } + } + } else if (exr_header->requested_pixel_types[c] == + TINYEXR_PIXELTYPE_HALF) { + for (int y = 0; y < h; y++) { + // Assume increasing Y + unsigned short *line_ptr = reinterpret_cast( + &buf.at(static_cast(pixel_data_size * y * + exr_image->width) + + channel_offset_list[c] * + static_cast(exr_image->width))); + for (int x = 0; x < exr_image->width; x++) { + unsigned short val = reinterpret_cast( + exr_image->images)[c][(y + start_y) * exr_image->width + x]; + + tinyexr::swap2(&val); + + // line_ptr[x] = val; + tinyexr::cpy2(line_ptr + x, &val); + } + } + } else { + assert(0); + } + + } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + for (int y = 0; y < h; y++) { + // Assume increasing Y + unsigned short *line_ptr = reinterpret_cast( + &buf.at(static_cast(pixel_data_size * y * + exr_image->width) + + channel_offset_list[c] * + static_cast(exr_image->width))); + for (int x = 0; x < exr_image->width; x++) { + tinyexr::FP32 f32; + f32.f = reinterpret_cast( + exr_image->images)[c][(y + start_y) * exr_image->width + x]; + + tinyexr::FP16 h16; + h16 = float_to_half_full(f32); + + tinyexr::swap2(reinterpret_cast(&h16.u)); + + // line_ptr[x] = h16.u; + tinyexr::cpy2(line_ptr + x, &(h16.u)); + } + } + } else if (exr_header->requested_pixel_types[c] == + TINYEXR_PIXELTYPE_FLOAT) { + for (int y = 0; y < h; y++) { + // Assume increasing Y + float *line_ptr = reinterpret_cast(&buf.at( + static_cast(pixel_data_size * y * exr_image->width) + + channel_offset_list[c] * + static_cast(exr_image->width))); + for (int x = 0; x < exr_image->width; x++) { + float val = reinterpret_cast( + exr_image->images)[c][(y + start_y) * exr_image->width + x]; + + tinyexr::swap4(reinterpret_cast(&val)); + + // line_ptr[x] = val; + tinyexr::cpy4(line_ptr + x, &val); + } + } + } else { + assert(0); + } + } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_UINT) { + for (int y = 0; y < h; y++) { + // Assume increasing Y + unsigned int *line_ptr = reinterpret_cast(&buf.at( + static_cast(pixel_data_size * y * exr_image->width) + + channel_offset_list[c] * static_cast(exr_image->width))); + for (int x = 0; x < exr_image->width; x++) { + unsigned int val = reinterpret_cast( + exr_image->images)[c][(y + start_y) * exr_image->width + x]; + + tinyexr::swap4(&val); + + // line_ptr[x] = val; + tinyexr::cpy4(line_ptr + x, &val); + } + } + } + } + + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_NONE) { + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(uncompressed) + std::vector header(8); + unsigned int data_len = static_cast(buf.size()); + memcpy(&header.at(0), &start_y, sizeof(int)); + memcpy(&header.at(4), &data_len, sizeof(unsigned int)); + + tinyexr::swap4(reinterpret_cast(&header.at(0))); + tinyexr::swap4(reinterpret_cast(&header.at(4))); + + data_list[ii].insert(data_list[ii].end(), header.begin(), header.end()); + data_list[ii].insert(data_list[ii].end(), buf.begin(), + buf.begin() + data_len); + + } else if ((exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) || + (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) { +#if TINYEXR_USE_MINIZ + std::vector block(tinyexr::miniz::mz_compressBound( + static_cast(buf.size()))); +#else + std::vector block( + compressBound(static_cast(buf.size()))); +#endif + tinyexr::tinyexr_uint64 outSize = block.size(); + + tinyexr::CompressZip(&block.at(0), outSize, + reinterpret_cast(&buf.at(0)), + static_cast(buf.size())); + + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(compressed) + std::vector header(8); + unsigned int data_len = static_cast(outSize); // truncate + memcpy(&header.at(0), &start_y, sizeof(int)); + memcpy(&header.at(4), &data_len, sizeof(unsigned int)); + + tinyexr::swap4(reinterpret_cast(&header.at(0))); + tinyexr::swap4(reinterpret_cast(&header.at(4))); + + data_list[ii].insert(data_list[ii].end(), header.begin(), header.end()); + data_list[ii].insert(data_list[ii].end(), block.begin(), + block.begin() + data_len); + + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_RLE) { + // (buf.size() * 3) / 2 would be enough. + std::vector block((buf.size() * 3) / 2); + + tinyexr::tinyexr_uint64 outSize = block.size(); + + tinyexr::CompressRle(&block.at(0), outSize, + reinterpret_cast(&buf.at(0)), + static_cast(buf.size())); + + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(compressed) + std::vector header(8); + unsigned int data_len = static_cast(outSize); // truncate + memcpy(&header.at(0), &start_y, sizeof(int)); + memcpy(&header.at(4), &data_len, sizeof(unsigned int)); + + tinyexr::swap4(reinterpret_cast(&header.at(0))); + tinyexr::swap4(reinterpret_cast(&header.at(4))); + + data_list[ii].insert(data_list[ii].end(), header.begin(), header.end()); + data_list[ii].insert(data_list[ii].end(), block.begin(), + block.begin() + data_len); + + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { +#if TINYEXR_USE_PIZ + unsigned int bufLen = + 8192 + static_cast( + 2 * static_cast( + buf.size())); // @fixme { compute good bound. } + std::vector block(bufLen); + unsigned int outSize = static_cast(block.size()); + + CompressPiz(&block.at(0), &outSize, + reinterpret_cast(&buf.at(0)), + buf.size(), channels, exr_image->width, h); + + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(compressed) + std::vector header(8); + unsigned int data_len = outSize; + memcpy(&header.at(0), &start_y, sizeof(int)); + memcpy(&header.at(4), &data_len, sizeof(unsigned int)); + + tinyexr::swap4(reinterpret_cast(&header.at(0))); + tinyexr::swap4(reinterpret_cast(&header.at(4))); + + data_list[ii].insert(data_list[ii].end(), header.begin(), header.end()); + data_list[ii].insert(data_list[ii].end(), block.begin(), + block.begin() + data_len); + +#else + assert(0); +#endif + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { +#if TINYEXR_USE_ZFP + std::vector block; + unsigned int outSize; + + tinyexr::CompressZfp( + &block, &outSize, reinterpret_cast(&buf.at(0)), + exr_image->width, h, exr_header->num_channels, zfp_compression_param); + + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(compressed) + std::vector header(8); + unsigned int data_len = outSize; + memcpy(&header.at(0), &start_y, sizeof(int)); + memcpy(&header.at(4), &data_len, sizeof(unsigned int)); + + tinyexr::swap4(reinterpret_cast(&header.at(0))); + tinyexr::swap4(reinterpret_cast(&header.at(4))); + + data_list[ii].insert(data_list[ii].end(), header.begin(), header.end()); + data_list[ii].insert(data_list[ii].end(), block.begin(), + block.begin() + data_len); + +#else + assert(0); +#endif + } else { + assert(0); + } + } // omp parallel + + for (size_t i = 0; i < static_cast(num_blocks); i++) { + offsets[i] = offset; + tinyexr::swap8(reinterpret_cast(&offsets[i])); + offset += data_list[i].size(); + } + + size_t totalSize = static_cast(offset); + { + memory.insert( + memory.end(), reinterpret_cast(&offsets.at(0)), + reinterpret_cast(&offsets.at(0)) + + sizeof(tinyexr::tinyexr_uint64) * static_cast(num_blocks)); + } + + if (memory.size() == 0) { + tinyexr::SetErrorMessage("Output memory size is zero", err); + return 0; + } + + (*memory_out) = static_cast(malloc(totalSize)); + memcpy((*memory_out), &memory.at(0), memory.size()); + unsigned char *memory_ptr = *memory_out + memory.size(); + + for (size_t i = 0; i < static_cast(num_blocks); i++) { + memcpy(memory_ptr, &data_list[i].at(0), data_list[i].size()); + memory_ptr += data_list[i].size(); + } + + return totalSize; // OK +} + +int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header, + const char *filename, const char **err) { + if (exr_image == NULL || filename == NULL || + exr_header->compression_type < 0) { + tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToFile", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + +#if !TINYEXR_USE_PIZ + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + tinyexr::SetErrorMessage("PIZ compression is not supported in this build", + err); + return TINYEXR_ERROR_UNSUPPORTED_FEATURE; + } +#endif + +#if !TINYEXR_USE_ZFP + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + tinyexr::SetErrorMessage("ZFP compression is not supported in this build", + err); + return TINYEXR_ERROR_UNSUPPORTED_FEATURE; + } +#endif + +#ifdef _WIN32 + FILE *fp = NULL; + fopen_s(&fp, filename, "wb"); +#else + FILE *fp = fopen(filename, "wb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot write a file", err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } + + unsigned char *mem = NULL; + size_t mem_size = SaveEXRImageToMemory(exr_image, exr_header, &mem, err); + if (mem_size == 0) { + return TINYEXR_ERROR_SERIALZATION_FAILED; + } + + size_t written_size = 0; + if ((mem_size > 0) && mem) { + written_size = fwrite(mem, 1, mem_size, fp); + } + free(mem); + + fclose(fp); + + if (written_size != mem_size) { + tinyexr::SetErrorMessage("Cannot write a file", err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } + + return TINYEXR_SUCCESS; +} + +int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { + if (deep_image == NULL) { + tinyexr::SetErrorMessage("Invalid argument for LoadDeepEXR", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + +#ifdef _MSC_VER + FILE *fp = NULL; + errno_t errcode = fopen_s(&fp, filename, "rb"); + if ((0 != errcode) || (!fp)) { + tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#else + FILE *fp = fopen(filename, "rb"); + if (!fp) { + tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#endif + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + if (filesize == 0) { + fclose(fp); + tinyexr::SetErrorMessage("File size is zero : " + std::string(filename), + err); + return TINYEXR_ERROR_INVALID_FILE; + } + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + (void)ret; + } + fclose(fp); + + const char *head = &buf[0]; + const char *marker = &buf[0]; + + // Header check. + { + const char header[] = {0x76, 0x2f, 0x31, 0x01}; + + if (memcmp(marker, header, 4) != 0) { + tinyexr::SetErrorMessage("Invalid magic number", err); + return TINYEXR_ERROR_INVALID_MAGIC_NUMBER; + } + marker += 4; + } + + // Version, scanline. + { + // ver 2.0, scanline, deep bit on(0x800) + // must be [2, 0, 0, 0] + if (marker[0] != 2 || marker[1] != 8 || marker[2] != 0 || marker[3] != 0) { + tinyexr::SetErrorMessage("Unsupported version or scanline", err); + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + marker += 4; + } + + int dx = -1; + int dy = -1; + int dw = -1; + int dh = -1; + int num_scanline_blocks = 1; // 16 for ZIP compression. + int compression_type = -1; + int num_channels = -1; + std::vector channels; + + // Read attributes + size_t size = filesize - tinyexr::kEXRVersionSize; + for (;;) { + if (0 == size) { + return TINYEXR_ERROR_INVALID_DATA; + } else if (marker[0] == '\0') { + marker++; + size--; + break; + } + + std::string attr_name; + std::string attr_type; + std::vector data; + size_t marker_size; + if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size, + marker, size)) { + std::stringstream ss; + ss << "Failed to parse attribute\n"; + tinyexr::SetErrorMessage(ss.str(), err); + return TINYEXR_ERROR_INVALID_DATA; + } + marker += marker_size; + size -= marker_size; + + if (attr_name.compare("compression") == 0) { + compression_type = data[0]; + if (compression_type > TINYEXR_COMPRESSIONTYPE_PIZ) { + std::stringstream ss; + ss << "Unsupported compression type : " << compression_type; + tinyexr::SetErrorMessage(ss.str(), err); + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + num_scanline_blocks = 16; + } + + } else if (attr_name.compare("channels") == 0) { + // name: zero-terminated string, from 1 to 255 bytes long + // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2 + // pLinear: unsigned char, possible values are 0 and 1 + // reserved: three chars, should be zero + // xSampling: int + // ySampling: int + + if (!tinyexr::ReadChannelInfo(channels, data)) { + tinyexr::SetErrorMessage("Failed to parse channel info", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + num_channels = static_cast(channels.size()); + + if (num_channels < 1) { + tinyexr::SetErrorMessage("Invalid channels format", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + } else if (attr_name.compare("dataWindow") == 0) { + memcpy(&dx, &data.at(0), sizeof(int)); + memcpy(&dy, &data.at(4), sizeof(int)); + memcpy(&dw, &data.at(8), sizeof(int)); + memcpy(&dh, &data.at(12), sizeof(int)); + tinyexr::swap4(reinterpret_cast(&dx)); + tinyexr::swap4(reinterpret_cast(&dy)); + tinyexr::swap4(reinterpret_cast(&dw)); + tinyexr::swap4(reinterpret_cast(&dh)); + + } else if (attr_name.compare("displayWindow") == 0) { + int x; + int y; + int w; + int h; + memcpy(&x, &data.at(0), sizeof(int)); + memcpy(&y, &data.at(4), sizeof(int)); + memcpy(&w, &data.at(8), sizeof(int)); + memcpy(&h, &data.at(12), sizeof(int)); + tinyexr::swap4(reinterpret_cast(&x)); + tinyexr::swap4(reinterpret_cast(&y)); + tinyexr::swap4(reinterpret_cast(&w)); + tinyexr::swap4(reinterpret_cast(&h)); + } + } + + assert(dx >= 0); + assert(dy >= 0); + assert(dw >= 0); + assert(dh >= 0); + assert(num_channels >= 1); + + int data_width = dw - dx + 1; + int data_height = dh - dy + 1; + + std::vector image( + static_cast(data_width * data_height * 4)); // 4 = RGBA + + // Read offset tables. + int num_blocks = data_height / num_scanline_blocks; + if (num_blocks * num_scanline_blocks < data_height) { + num_blocks++; + } + + std::vector offsets(static_cast(num_blocks)); + + for (size_t y = 0; y < static_cast(num_blocks); y++) { + tinyexr::tinyexr_int64 offset; + memcpy(&offset, marker, sizeof(tinyexr::tinyexr_int64)); + tinyexr::swap8(reinterpret_cast(&offset)); + marker += sizeof(tinyexr::tinyexr_int64); // = 8 + offsets[y] = offset; + } + +#if TINYEXR_USE_PIZ + if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) || + (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) || + (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ)) { +#else + if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) || + (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) { +#endif + // OK + } else { + tinyexr::SetErrorMessage("Unsupported compression format", err); + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + deep_image->image = static_cast( + malloc(sizeof(float **) * static_cast(num_channels))); + for (int c = 0; c < num_channels; c++) { + deep_image->image[c] = static_cast( + malloc(sizeof(float *) * static_cast(data_height))); + for (int y = 0; y < data_height; y++) { + } + } + + deep_image->offset_table = static_cast( + malloc(sizeof(int *) * static_cast(data_height))); + for (int y = 0; y < data_height; y++) { + deep_image->offset_table[y] = static_cast( + malloc(sizeof(int) * static_cast(data_width))); + } + + for (size_t y = 0; y < static_cast(num_blocks); y++) { + const unsigned char *data_ptr = + reinterpret_cast(head + offsets[y]); + + // int: y coordinate + // int64: packed size of pixel offset table + // int64: packed size of sample data + // int64: unpacked size of sample data + // compressed pixel offset table + // compressed sample data + int line_no; + tinyexr::tinyexr_int64 packedOffsetTableSize; + tinyexr::tinyexr_int64 packedSampleDataSize; + tinyexr::tinyexr_int64 unpackedSampleDataSize; + memcpy(&line_no, data_ptr, sizeof(int)); + memcpy(&packedOffsetTableSize, data_ptr + 4, + sizeof(tinyexr::tinyexr_int64)); + memcpy(&packedSampleDataSize, data_ptr + 12, + sizeof(tinyexr::tinyexr_int64)); + memcpy(&unpackedSampleDataSize, data_ptr + 20, + sizeof(tinyexr::tinyexr_int64)); + + tinyexr::swap4(reinterpret_cast(&line_no)); + tinyexr::swap8( + reinterpret_cast(&packedOffsetTableSize)); + tinyexr::swap8( + reinterpret_cast(&packedSampleDataSize)); + tinyexr::swap8( + reinterpret_cast(&unpackedSampleDataSize)); + + std::vector pixelOffsetTable(static_cast(data_width)); + + // decode pixel offset table. + { + unsigned long dstLen = + static_cast(pixelOffsetTable.size() * sizeof(int)); + if (!tinyexr::DecompressZip( + reinterpret_cast(&pixelOffsetTable.at(0)), + &dstLen, data_ptr + 28, + static_cast(packedOffsetTableSize))) { + return false; + } + + assert(dstLen == pixelOffsetTable.size() * sizeof(int)); + for (size_t i = 0; i < static_cast(data_width); i++) { + deep_image->offset_table[y][i] = pixelOffsetTable[i]; + } + } + + std::vector sample_data( + static_cast(unpackedSampleDataSize)); + + // decode sample data. + { + unsigned long dstLen = static_cast(unpackedSampleDataSize); + if (dstLen) { + if (!tinyexr::DecompressZip( + reinterpret_cast(&sample_data.at(0)), &dstLen, + data_ptr + 28 + packedOffsetTableSize, + static_cast(packedSampleDataSize))) { + return false; + } + assert(dstLen == static_cast(unpackedSampleDataSize)); + } + } + + // decode sample + int sampleSize = -1; + std::vector channel_offset_list(static_cast(num_channels)); + { + int channel_offset = 0; + for (size_t i = 0; i < static_cast(num_channels); i++) { + channel_offset_list[i] = channel_offset; + if (channels[i].pixel_type == TINYEXR_PIXELTYPE_UINT) { // UINT + channel_offset += 4; + } else if (channels[i].pixel_type == TINYEXR_PIXELTYPE_HALF) { // half + channel_offset += 2; + } else if (channels[i].pixel_type == + TINYEXR_PIXELTYPE_FLOAT) { // float + channel_offset += 4; + } else { + assert(0); + } + } + sampleSize = channel_offset; + } + assert(sampleSize >= 2); + + assert(static_cast( + pixelOffsetTable[static_cast(data_width - 1)] * + sampleSize) == sample_data.size()); + int samples_per_line = static_cast(sample_data.size()) / sampleSize; + + // + // Alloc memory + // + + // + // pixel data is stored as image[channels][pixel_samples] + // + { + tinyexr::tinyexr_uint64 data_offset = 0; + for (size_t c = 0; c < static_cast(num_channels); c++) { + deep_image->image[c][y] = static_cast( + malloc(sizeof(float) * static_cast(samples_per_line))); + + if (channels[c].pixel_type == 0) { // UINT + for (size_t x = 0; x < static_cast(samples_per_line); x++) { + unsigned int ui; + unsigned int *src_ptr = reinterpret_cast( + &sample_data.at(size_t(data_offset) + x * sizeof(int))); + tinyexr::cpy4(&ui, src_ptr); + deep_image->image[c][y][x] = static_cast(ui); // @fixme + } + data_offset += + sizeof(unsigned int) * static_cast(samples_per_line); + } else if (channels[c].pixel_type == 1) { // half + for (size_t x = 0; x < static_cast(samples_per_line); x++) { + tinyexr::FP16 f16; + const unsigned short *src_ptr = reinterpret_cast( + &sample_data.at(size_t(data_offset) + x * sizeof(short))); + tinyexr::cpy2(&(f16.u), src_ptr); + tinyexr::FP32 f32 = half_to_float(f16); + deep_image->image[c][y][x] = f32.f; + } + data_offset += sizeof(short) * static_cast(samples_per_line); + } else { // float + for (size_t x = 0; x < static_cast(samples_per_line); x++) { + float f; + const float *src_ptr = reinterpret_cast( + &sample_data.at(size_t(data_offset) + x * sizeof(float))); + tinyexr::cpy4(&f, src_ptr); + deep_image->image[c][y][x] = f; + } + data_offset += sizeof(float) * static_cast(samples_per_line); + } + } + } + } // y + + deep_image->width = data_width; + deep_image->height = data_height; + + deep_image->channel_names = static_cast( + malloc(sizeof(const char *) * static_cast(num_channels))); + for (size_t c = 0; c < static_cast(num_channels); c++) { +#ifdef _WIN32 + deep_image->channel_names[c] = _strdup(channels[c].name.c_str()); +#else + deep_image->channel_names[c] = strdup(channels[c].name.c_str()); +#endif + } + deep_image->num_channels = num_channels; + + return TINYEXR_SUCCESS; +} + +void InitEXRImage(EXRImage *exr_image) { + if (exr_image == NULL) { + return; + } + + exr_image->width = 0; + exr_image->height = 0; + exr_image->num_channels = 0; + + exr_image->images = NULL; + exr_image->tiles = NULL; + + exr_image->num_tiles = 0; +} + +void FreeEXRErrorMessage(const char *msg) { + if (msg) { + free(reinterpret_cast(const_cast(msg))); + } + return; +} + +void InitEXRHeader(EXRHeader *exr_header) { + if (exr_header == NULL) { + return; + } + + memset(exr_header, 0, sizeof(EXRHeader)); +} + +int FreeEXRHeader(EXRHeader *exr_header) { + if (exr_header == NULL) { + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (exr_header->channels) { + free(exr_header->channels); + } + + if (exr_header->pixel_types) { + free(exr_header->pixel_types); + } + + if (exr_header->requested_pixel_types) { + free(exr_header->requested_pixel_types); + } + + for (int i = 0; i < exr_header->num_custom_attributes; i++) { + if (exr_header->custom_attributes[i].value) { + free(exr_header->custom_attributes[i].value); + } + } + + if (exr_header->custom_attributes) { + free(exr_header->custom_attributes); + } + + return TINYEXR_SUCCESS; +} + +int FreeEXRImage(EXRImage *exr_image) { + if (exr_image == NULL) { + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + for (int i = 0; i < exr_image->num_channels; i++) { + if (exr_image->images && exr_image->images[i]) { + free(exr_image->images[i]); + } + } + + if (exr_image->images) { + free(exr_image->images); + } + + if (exr_image->tiles) { + for (int tid = 0; tid < exr_image->num_tiles; tid++) { + for (int i = 0; i < exr_image->num_channels; i++) { + if (exr_image->tiles[tid].images && exr_image->tiles[tid].images[i]) { + free(exr_image->tiles[tid].images[i]); + } + } + if (exr_image->tiles[tid].images) { + free(exr_image->tiles[tid].images); + } + } + free(exr_image->tiles); + } + + return TINYEXR_SUCCESS; +} + +int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version, + const char *filename, const char **err) { + if (exr_header == NULL || exr_version == NULL || filename == NULL) { + tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile", + err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + +#ifdef _WIN32 + FILE *fp = NULL; + fopen_s(&fp, filename, "rb"); +#else + FILE *fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + fclose(fp); + + if (ret != filesize) { + tinyexr::SetErrorMessage("fread() error on " + std::string(filename), + err); + return TINYEXR_ERROR_INVALID_FILE; + } + } + + return ParseEXRHeaderFromMemory(exr_header, exr_version, &buf.at(0), filesize, + err); +} + +int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers, + int *num_headers, + const EXRVersion *exr_version, + const unsigned char *memory, size_t size, + const char **err) { + if (memory == NULL || exr_headers == NULL || num_headers == NULL || + exr_version == NULL) { + // Invalid argument + tinyexr::SetErrorMessage( + "Invalid argument for ParseEXRMultipartHeaderFromMemory", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (size < tinyexr::kEXRVersionSize) { + tinyexr::SetErrorMessage("Data size too short", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + const unsigned char *marker = memory + tinyexr::kEXRVersionSize; + size_t marker_size = size - tinyexr::kEXRVersionSize; + + std::vector infos; + + for (;;) { + tinyexr::HeaderInfo info; + info.clear(); + + std::string err_str; + bool empty_header = false; + int ret = ParseEXRHeader(&info, &empty_header, exr_version, &err_str, + marker, marker_size); + + if (ret != TINYEXR_SUCCESS) { + tinyexr::SetErrorMessage(err_str, err); + return ret; + } + + if (empty_header) { + marker += 1; // skip '\0' + break; + } + + // `chunkCount` must exist in the header. + if (info.chunk_count == 0) { + tinyexr::SetErrorMessage( + "`chunkCount' attribute is not found in the header.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + infos.push_back(info); + + // move to next header. + marker += info.header_len; + size -= info.header_len; + } + + // allocate memory for EXRHeader and create array of EXRHeader pointers. + (*exr_headers) = + static_cast(malloc(sizeof(EXRHeader *) * infos.size())); + for (size_t i = 0; i < infos.size(); i++) { + EXRHeader *exr_header = static_cast(malloc(sizeof(EXRHeader))); + + ConvertHeader(exr_header, infos[i]); + + // transfoer `tiled` from version. + exr_header->tiled = exr_version->tiled; + + (*exr_headers)[i] = exr_header; + } + + (*num_headers) = static_cast(infos.size()); + + return TINYEXR_SUCCESS; +} + +int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers, + const EXRVersion *exr_version, + const char *filename, const char **err) { + if (exr_headers == NULL || num_headers == NULL || exr_version == NULL || + filename == NULL) { + tinyexr::SetErrorMessage( + "Invalid argument for ParseEXRMultipartHeaderFromFile()", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + +#ifdef _WIN32 + FILE *fp = NULL; + fopen_s(&fp, filename, "rb"); +#else + FILE *fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + fclose(fp); + + if (ret != filesize) { + tinyexr::SetErrorMessage("`fread' error. file may be corrupted.", err); + return TINYEXR_ERROR_INVALID_FILE; + } + } + + return ParseEXRMultipartHeaderFromMemory( + exr_headers, num_headers, exr_version, &buf.at(0), filesize, err); +} + +int ParseEXRVersionFromMemory(EXRVersion *version, const unsigned char *memory, + size_t size) { + if (version == NULL || memory == NULL) { + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (size < tinyexr::kEXRVersionSize) { + return TINYEXR_ERROR_INVALID_DATA; + } + + const unsigned char *marker = memory; + + // Header check. + { + const char header[] = {0x76, 0x2f, 0x31, 0x01}; + + if (memcmp(marker, header, 4) != 0) { + return TINYEXR_ERROR_INVALID_MAGIC_NUMBER; + } + marker += 4; + } + + version->tiled = false; + version->long_name = false; + version->non_image = false; + version->multipart = false; + + // Parse version header. + { + // must be 2 + if (marker[0] != 2) { + return TINYEXR_ERROR_INVALID_EXR_VERSION; + } + + if (version == NULL) { + return TINYEXR_SUCCESS; // May OK + } + + version->version = 2; + + if (marker[1] & 0x2) { // 9th bit + version->tiled = true; + } + if (marker[1] & 0x4) { // 10th bit + version->long_name = true; + } + if (marker[1] & 0x8) { // 11th bit + version->non_image = true; // (deep image) + } + if (marker[1] & 0x10) { // 12th bit + version->multipart = true; + } + } + + return TINYEXR_SUCCESS; +} + +int ParseEXRVersionFromFile(EXRVersion *version, const char *filename) { + if (filename == NULL) { + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + +#ifdef _WIN32 + FILE *fp = NULL; + fopen_s(&fp, filename, "rb"); +#else + FILE *fp = fopen(filename, "rb"); +#endif + if (!fp) { + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t file_size; + // Compute size + fseek(fp, 0, SEEK_END); + file_size = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + if (file_size < tinyexr::kEXRVersionSize) { + return TINYEXR_ERROR_INVALID_FILE; + } + + unsigned char buf[tinyexr::kEXRVersionSize]; + size_t ret = fread(&buf[0], 1, tinyexr::kEXRVersionSize, fp); + fclose(fp); + + if (ret != tinyexr::kEXRVersionSize) { + return TINYEXR_ERROR_INVALID_FILE; + } + + return ParseEXRVersionFromMemory(version, buf, tinyexr::kEXRVersionSize); +} + +int LoadEXRMultipartImageFromMemory(EXRImage *exr_images, + const EXRHeader **exr_headers, + unsigned int num_parts, + const unsigned char *memory, + const size_t size, const char **err) { + if (exr_images == NULL || exr_headers == NULL || num_parts == 0 || + memory == NULL || (size <= tinyexr::kEXRVersionSize)) { + tinyexr::SetErrorMessage( + "Invalid argument for LoadEXRMultipartImageFromMemory()", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + // compute total header size. + size_t total_header_size = 0; + for (unsigned int i = 0; i < num_parts; i++) { + if (exr_headers[i]->header_len == 0) { + tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + total_header_size += exr_headers[i]->header_len; + } + + const char *marker = reinterpret_cast( + memory + total_header_size + 4 + + 4); // +8 for magic number and version header. + + marker += 1; // Skip empty header. + + // NOTE 1: + // In multipart image, There is 'part number' before chunk data. + // 4 byte : part number + // 4+ : chunk + // + // NOTE 2: + // EXR spec says 'part number' is 'unsigned long' but actually this is + // 'unsigned int(4 bytes)' in OpenEXR implementation... + // http://www.openexr.com/openexrfilelayout.pdf + + // Load chunk offset table. + std::vector > chunk_offset_table_list; + for (size_t i = 0; i < static_cast(num_parts); i++) { + std::vector offset_table( + static_cast(exr_headers[i]->chunk_count)); + + for (size_t c = 0; c < offset_table.size(); c++) { + tinyexr::tinyexr_uint64 offset; + memcpy(&offset, marker, 8); + tinyexr::swap8(&offset); + + if (offset >= size) { + tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.", + err); + return TINYEXR_ERROR_INVALID_DATA; + } + + offset_table[c] = offset + 4; // +4 to skip 'part number' + marker += 8; + } + + chunk_offset_table_list.push_back(offset_table); + } + + // Decode image. + for (size_t i = 0; i < static_cast(num_parts); i++) { + std::vector &offset_table = + chunk_offset_table_list[i]; + + // First check 'part number' is identitical to 'i' + for (size_t c = 0; c < offset_table.size(); c++) { + const unsigned char *part_number_addr = + memory + offset_table[c] - 4; // -4 to move to 'part number' field. + unsigned int part_no; + memcpy(&part_no, part_number_addr, sizeof(unsigned int)); // 4 + tinyexr::swap4(&part_no); + + if (part_no != i) { + tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.", + err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + + std::string e; + int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_table, + memory, size, &e); + if (ret != TINYEXR_SUCCESS) { + if (!e.empty()) { + tinyexr::SetErrorMessage(e, err); + } + return ret; + } + } + + return TINYEXR_SUCCESS; +} + +int LoadEXRMultipartImageFromFile(EXRImage *exr_images, + const EXRHeader **exr_headers, + unsigned int num_parts, const char *filename, + const char **err) { + if (exr_images == NULL || exr_headers == NULL || num_parts == 0) { + tinyexr::SetErrorMessage( + "Invalid argument for LoadEXRMultipartImageFromFile", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + +#ifdef _WIN32 + FILE *fp = NULL; + fopen_s(&fp, filename, "rb"); +#else + FILE *fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + fclose(fp); + (void)ret; + } + + return LoadEXRMultipartImageFromMemory(exr_images, exr_headers, num_parts, + &buf.at(0), filesize, err); +} + +int SaveEXR(const float *data, int width, int height, int components, + const int save_as_fp16, const char *outfilename, const char **err) { + if ((components == 1) || components == 3 || components == 4) { + // OK + } else { + std::stringstream ss; + ss << "Unsupported component value : " << components << std::endl; + + tinyexr::SetErrorMessage(ss.str(), err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + EXRHeader header; + InitEXRHeader(&header); + + if ((width < 16) && (height < 16)) { + // No compression for small image. + header.compression_type = TINYEXR_COMPRESSIONTYPE_NONE; + } else { + header.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP; + } + + EXRImage image; + InitEXRImage(&image); + + image.num_channels = components; + + std::vector images[4]; + + if (components == 1) { + images[0].resize(static_cast(width * height)); + memcpy(images[0].data(), data, sizeof(float) * size_t(width * height)); + } else { + images[0].resize(static_cast(width * height)); + images[1].resize(static_cast(width * height)); + images[2].resize(static_cast(width * height)); + images[3].resize(static_cast(width * height)); + + // Split RGB(A)RGB(A)RGB(A)... into R, G and B(and A) layers + for (size_t i = 0; i < static_cast(width * height); i++) { + images[0][i] = data[static_cast(components) * i + 0]; + images[1][i] = data[static_cast(components) * i + 1]; + images[2][i] = data[static_cast(components) * i + 2]; + if (components == 4) { + images[3][i] = data[static_cast(components) * i + 3]; + } + } + } + + float *image_ptr[4] = {0, 0, 0, 0}; + if (components == 4) { + image_ptr[0] = &(images[3].at(0)); // A + image_ptr[1] = &(images[2].at(0)); // B + image_ptr[2] = &(images[1].at(0)); // G + image_ptr[3] = &(images[0].at(0)); // R + } else if (components == 3) { + image_ptr[0] = &(images[2].at(0)); // B + image_ptr[1] = &(images[1].at(0)); // G + image_ptr[2] = &(images[0].at(0)); // R + } else if (components == 1) { + image_ptr[0] = &(images[0].at(0)); // A + } + + image.images = reinterpret_cast(image_ptr); + image.width = width; + image.height = height; + + header.num_channels = components; + header.channels = static_cast(malloc( + sizeof(EXRChannelInfo) * static_cast(header.num_channels))); + // Must be (A)BGR order, since most of EXR viewers expect this channel order. + if (components == 4) { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "A", 255); + strncpy_s(header.channels[1].name, "B", 255); + strncpy_s(header.channels[2].name, "G", 255); + strncpy_s(header.channels[3].name, "R", 255); +#else + strncpy(header.channels[0].name, "A", 255); + strncpy(header.channels[1].name, "B", 255); + strncpy(header.channels[2].name, "G", 255); + strncpy(header.channels[3].name, "R", 255); +#endif + header.channels[0].name[strlen("A")] = '\0'; + header.channels[1].name[strlen("B")] = '\0'; + header.channels[2].name[strlen("G")] = '\0'; + header.channels[3].name[strlen("R")] = '\0'; + } else if (components == 3) { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "B", 255); + strncpy_s(header.channels[1].name, "G", 255); + strncpy_s(header.channels[2].name, "R", 255); +#else + strncpy(header.channels[0].name, "B", 255); + strncpy(header.channels[1].name, "G", 255); + strncpy(header.channels[2].name, "R", 255); +#endif + header.channels[0].name[strlen("B")] = '\0'; + header.channels[1].name[strlen("G")] = '\0'; + header.channels[2].name[strlen("R")] = '\0'; + } else { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "A", 255); +#else + strncpy(header.channels[0].name, "A", 255); +#endif + header.channels[0].name[strlen("A")] = '\0'; + } + + header.pixel_types = static_cast( + malloc(sizeof(int) * static_cast(header.num_channels))); + header.requested_pixel_types = static_cast( + malloc(sizeof(int) * static_cast(header.num_channels))); + for (int i = 0; i < header.num_channels; i++) { + header.pixel_types[i] = + TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image + + if (save_as_fp16 > 0) { + header.requested_pixel_types[i] = + TINYEXR_PIXELTYPE_HALF; // save with half(fp16) pixel format + } else { + header.requested_pixel_types[i] = + TINYEXR_PIXELTYPE_FLOAT; // save with float(fp32) pixel format(i.e. + // no precision reduction) + } + } + + int ret = SaveEXRImageToFile(&image, &header, outfilename, err); + if (ret != TINYEXR_SUCCESS) { + return ret; + } + + free(header.channels); + free(header.pixel_types); + free(header.requested_pixel_types); + + return ret; +} + +#ifdef __clang__ +// zero-as-null-ppinter-constant +#pragma clang diagnostic pop +#endif + +#endif // TINYEXR_IMPLEMENTATION_DEIFNED +#endif // TINYEXR_IMPLEMENTATION diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/tinygltf/LICENSE b/Extern/3rdParty/OptiX/Linux/SDK/support/tinygltf/LICENSE new file mode 100644 index 00000000..34398adf --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/tinygltf/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Syoyo Fujita, Aurélien Chatelain and many contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Extern/3rdParty/OptiX/Linux/SDK/support/tinygltf/json.hpp b/Extern/3rdParty/OptiX/Linux/SDK/support/tinygltf/json.hpp new file mode 100644 index 00000000..c9af0bed --- /dev/null +++ b/Extern/3rdParty/OptiX/Linux/SDK/support/tinygltf/json.hpp @@ -0,0 +1,20406 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.5.0 +|_____|_____|_____|_|___| /~https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2018 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 5 +#define NLOHMANN_JSON_VERSION_PATCH 0 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // random_access_iterator_tag +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap + +// #include +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see /~https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} // namespace nlohmann + +#endif + +// #include + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see /~https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see /~https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// #include + + +#include // not +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // not +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + +// #include + + +#include // random_access_iterator_tag + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See /~https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; +} +} + +// #include + +// #include + + +#include + +// #include + + +// http://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + void operator=(nonesuch const&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template