Updated almost all stuff

This commit is contained in:
2025-06-14 16:20:47 +03:00
parent 756fb3bdd0
commit a1f1e09af6
152 changed files with 53441 additions and 26 deletions

744
.clang-format Normal file
View File

@@ -0,0 +1,744 @@
# SPDX-License-Identifier: GPL-2.0
#
# clang-format configuration file. Intended for clang-format >= 11.
#
# For more information, see:
#
# Documentation/process/clang-format.rst
# https://clang.llvm.org/docs/ClangFormat.html
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
---
AccessModifierOffset: -8
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
# Taken from:
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ tools/ \
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
# | LC_ALL=C sort -u
ForEachMacros:
- '__ata_qc_for_each'
- '__bio_for_each_bvec'
- '__bio_for_each_segment'
- '__evlist__for_each_entry'
- '__evlist__for_each_entry_continue'
- '__evlist__for_each_entry_from'
- '__evlist__for_each_entry_reverse'
- '__evlist__for_each_entry_safe'
- '__for_each_mem_range'
- '__for_each_mem_range_rev'
- '__for_each_thread'
- '__hlist_for_each_rcu'
- '__map__for_each_symbol_by_name'
- '__pci_bus_for_each_res0'
- '__pci_bus_for_each_res1'
- '__pci_dev_for_each_res0'
- '__pci_dev_for_each_res1'
- '__perf_evlist__for_each_entry'
- '__perf_evlist__for_each_entry_reverse'
- '__perf_evlist__for_each_entry_safe'
- '__rq_for_each_bio'
- '__shost_for_each_device'
- '__sym_for_each'
- 'apei_estatus_for_each_section'
- 'ata_for_each_dev'
- 'ata_for_each_link'
- 'ata_qc_for_each'
- 'ata_qc_for_each_raw'
- 'ata_qc_for_each_with_internal'
- 'ax25_for_each'
- 'ax25_uid_for_each'
- 'bio_for_each_bvec'
- 'bio_for_each_bvec_all'
- 'bio_for_each_folio_all'
- 'bio_for_each_integrity_vec'
- 'bio_for_each_segment'
- 'bio_for_each_segment_all'
- 'bio_list_for_each'
- 'bip_for_each_vec'
- 'bond_for_each_slave'
- 'bond_for_each_slave_rcu'
- 'bpf_for_each'
- 'bpf_for_each_reg_in_vstate'
- 'bpf_for_each_reg_in_vstate_mask'
- 'bpf_for_each_spilled_reg'
- 'bpf_object__for_each_map'
- 'bpf_object__for_each_program'
- 'btree_for_each_safe128'
- 'btree_for_each_safe32'
- 'btree_for_each_safe64'
- 'btree_for_each_safel'
- 'card_for_each_dev'
- 'cgroup_taskset_for_each'
- 'cgroup_taskset_for_each_leader'
- 'cpu_aggr_map__for_each_idx'
- 'cpufreq_for_each_efficient_entry_idx'
- 'cpufreq_for_each_entry'
- 'cpufreq_for_each_entry_idx'
- 'cpufreq_for_each_valid_entry'
- 'cpufreq_for_each_valid_entry_idx'
- 'css_for_each_child'
- 'css_for_each_descendant_post'
- 'css_for_each_descendant_pre'
- 'damon_for_each_region'
- 'damon_for_each_region_from'
- 'damon_for_each_region_safe'
- 'damon_for_each_scheme'
- 'damon_for_each_scheme_safe'
- 'damon_for_each_target'
- 'damon_for_each_target_safe'
- 'damos_for_each_filter'
- 'damos_for_each_filter_safe'
- 'data__for_each_file'
- 'data__for_each_file_new'
- 'data__for_each_file_start'
- 'device_for_each_child_node'
- 'displayid_iter_for_each'
- 'dma_fence_array_for_each'
- 'dma_fence_chain_for_each'
- 'dma_fence_unwrap_for_each'
- 'dma_resv_for_each_fence'
- 'dma_resv_for_each_fence_unlocked'
- 'do_for_each_ftrace_op'
- 'drm_atomic_crtc_for_each_plane'
- 'drm_atomic_crtc_state_for_each_plane'
- 'drm_atomic_crtc_state_for_each_plane_state'
- 'drm_atomic_for_each_plane_damage'
- 'drm_client_for_each_connector_iter'
- 'drm_client_for_each_modeset'
- 'drm_connector_for_each_possible_encoder'
- 'drm_exec_for_each_locked_object'
- 'drm_exec_for_each_locked_object_reverse'
- 'drm_for_each_bridge_in_chain'
- 'drm_for_each_connector_iter'
- 'drm_for_each_crtc'
- 'drm_for_each_crtc_reverse'
- 'drm_for_each_encoder'
- 'drm_for_each_encoder_mask'
- 'drm_for_each_fb'
- 'drm_for_each_legacy_plane'
- 'drm_for_each_plane'
- 'drm_for_each_plane_mask'
- 'drm_for_each_privobj'
- 'drm_gem_for_each_gpuva'
- 'drm_gem_for_each_gpuva_safe'
- 'drm_gpuva_for_each_op'
- 'drm_gpuva_for_each_op_from_reverse'
- 'drm_gpuva_for_each_op_safe'
- 'drm_gpuvm_for_each_va'
- 'drm_gpuvm_for_each_va_range'
- 'drm_gpuvm_for_each_va_range_safe'
- 'drm_gpuvm_for_each_va_safe'
- 'drm_mm_for_each_hole'
- 'drm_mm_for_each_node'
- 'drm_mm_for_each_node_in_range'
- 'drm_mm_for_each_node_safe'
- 'dsa_switch_for_each_available_port'
- 'dsa_switch_for_each_cpu_port'
- 'dsa_switch_for_each_cpu_port_continue_reverse'
- 'dsa_switch_for_each_port'
- 'dsa_switch_for_each_port_continue_reverse'
- 'dsa_switch_for_each_port_safe'
- 'dsa_switch_for_each_user_port'
- 'dsa_tree_for_each_cpu_port'
- 'dsa_tree_for_each_user_port'
- 'dsa_tree_for_each_user_port_continue_reverse'
- 'dso__for_each_symbol'
- 'dsos__for_each_with_build_id'
- 'elf_hash_for_each_possible'
- 'elf_symtab__for_each_symbol'
- 'evlist__for_each_cpu'
- 'evlist__for_each_entry'
- 'evlist__for_each_entry_continue'
- 'evlist__for_each_entry_from'
- 'evlist__for_each_entry_reverse'
- 'evlist__for_each_entry_safe'
- 'flow_action_for_each'
- 'for_each_acpi_consumer_dev'
- 'for_each_acpi_dev_match'
- 'for_each_active_dev_scope'
- 'for_each_active_drhd_unit'
- 'for_each_active_iommu'
- 'for_each_active_route'
- 'for_each_aggr_pgid'
- 'for_each_and_bit'
- 'for_each_andnot_bit'
- 'for_each_available_child_of_node'
- 'for_each_bench'
- 'for_each_bio'
- 'for_each_board_func_rsrc'
- 'for_each_btf_ext_rec'
- 'for_each_btf_ext_sec'
- 'for_each_bvec'
- 'for_each_card_auxs'
- 'for_each_card_auxs_safe'
- 'for_each_card_components'
- 'for_each_card_dapms'
- 'for_each_card_pre_auxs'
- 'for_each_card_prelinks'
- 'for_each_card_rtds'
- 'for_each_card_rtds_safe'
- 'for_each_card_widgets'
- 'for_each_card_widgets_safe'
- 'for_each_cgroup_storage_type'
- 'for_each_child_of_node'
- 'for_each_clear_bit'
- 'for_each_clear_bit_from'
- 'for_each_clear_bitrange'
- 'for_each_clear_bitrange_from'
- 'for_each_cmd'
- 'for_each_cmsghdr'
- 'for_each_collection'
- 'for_each_comp_order'
- 'for_each_compatible_node'
- 'for_each_component_dais'
- 'for_each_component_dais_safe'
- 'for_each_conduit'
- 'for_each_console'
- 'for_each_console_srcu'
- 'for_each_cpu'
- 'for_each_cpu_and'
- 'for_each_cpu_andnot'
- 'for_each_cpu_or'
- 'for_each_cpu_wrap'
- 'for_each_dapm_widgets'
- 'for_each_dedup_cand'
- 'for_each_dev_addr'
- 'for_each_dev_scope'
- 'for_each_dma_cap_mask'
- 'for_each_dpcm_be'
- 'for_each_dpcm_be_rollback'
- 'for_each_dpcm_be_safe'
- 'for_each_dpcm_fe'
- 'for_each_drhd_unit'
- 'for_each_dss_dev'
- 'for_each_efi_memory_desc'
- 'for_each_efi_memory_desc_in_map'
- 'for_each_element'
- 'for_each_element_extid'
- 'for_each_element_id'
- 'for_each_endpoint_of_node'
- 'for_each_event'
- 'for_each_event_tps'
- 'for_each_evictable_lru'
- 'for_each_fib6_node_rt_rcu'
- 'for_each_fib6_walker_rt'
- 'for_each_free_mem_pfn_range_in_zone'
- 'for_each_free_mem_pfn_range_in_zone_from'
- 'for_each_free_mem_range'
- 'for_each_free_mem_range_reverse'
- 'for_each_func_rsrc'
- 'for_each_gpiochip_node'
- 'for_each_group_evsel'
- 'for_each_group_evsel_head'
- 'for_each_group_member'
- 'for_each_group_member_head'
- 'for_each_hstate'
- 'for_each_if'
- 'for_each_inject_fn'
- 'for_each_insn'
- 'for_each_insn_prefix'
- 'for_each_intid'
- 'for_each_iommu'
- 'for_each_ip_tunnel_rcu'
- 'for_each_irq_nr'
- 'for_each_lang'
- 'for_each_link_codecs'
- 'for_each_link_cpus'
- 'for_each_link_platforms'
- 'for_each_lru'
- 'for_each_matching_node'
- 'for_each_matching_node_and_match'
- 'for_each_media_entity_data_link'
- 'for_each_mem_pfn_range'
- 'for_each_mem_range'
- 'for_each_mem_range_rev'
- 'for_each_mem_region'
- 'for_each_member'
- 'for_each_memory'
- 'for_each_migratetype_order'
- 'for_each_missing_reg'
- 'for_each_mle_subelement'
- 'for_each_mod_mem_type'
- 'for_each_net'
- 'for_each_net_continue_reverse'
- 'for_each_net_rcu'
- 'for_each_netdev'
- 'for_each_netdev_continue'
- 'for_each_netdev_continue_rcu'
- 'for_each_netdev_continue_reverse'
- 'for_each_netdev_dump'
- 'for_each_netdev_feature'
- 'for_each_netdev_in_bond_rcu'
- 'for_each_netdev_rcu'
- 'for_each_netdev_reverse'
- 'for_each_netdev_safe'
- 'for_each_new_connector_in_state'
- 'for_each_new_crtc_in_state'
- 'for_each_new_mst_mgr_in_state'
- 'for_each_new_plane_in_state'
- 'for_each_new_plane_in_state_reverse'
- 'for_each_new_private_obj_in_state'
- 'for_each_new_reg'
- 'for_each_node'
- 'for_each_node_by_name'
- 'for_each_node_by_type'
- 'for_each_node_mask'
- 'for_each_node_state'
- 'for_each_node_with_cpus'
- 'for_each_node_with_property'
- 'for_each_nonreserved_multicast_dest_pgid'
- 'for_each_numa_hop_mask'
- 'for_each_of_allnodes'
- 'for_each_of_allnodes_from'
- 'for_each_of_cpu_node'
- 'for_each_of_pci_range'
- 'for_each_old_connector_in_state'
- 'for_each_old_crtc_in_state'
- 'for_each_old_mst_mgr_in_state'
- 'for_each_old_plane_in_state'
- 'for_each_old_private_obj_in_state'
- 'for_each_oldnew_connector_in_state'
- 'for_each_oldnew_crtc_in_state'
- 'for_each_oldnew_mst_mgr_in_state'
- 'for_each_oldnew_plane_in_state'
- 'for_each_oldnew_plane_in_state_reverse'
- 'for_each_oldnew_private_obj_in_state'
- 'for_each_online_cpu'
- 'for_each_online_node'
- 'for_each_online_pgdat'
- 'for_each_or_bit'
- 'for_each_path'
- 'for_each_pci_bridge'
- 'for_each_pci_dev'
- 'for_each_pcm_streams'
- 'for_each_physmem_range'
- 'for_each_populated_zone'
- 'for_each_possible_cpu'
- 'for_each_present_blessed_reg'
- 'for_each_present_cpu'
- 'for_each_prime_number'
- 'for_each_prime_number_from'
- 'for_each_probe_cache_entry'
- 'for_each_process'
- 'for_each_process_thread'
- 'for_each_prop_codec_conf'
- 'for_each_prop_dai_codec'
- 'for_each_prop_dai_cpu'
- 'for_each_prop_dlc_codecs'
- 'for_each_prop_dlc_cpus'
- 'for_each_prop_dlc_platforms'
- 'for_each_property_of_node'
- 'for_each_reg'
- 'for_each_reg_filtered'
- 'for_each_reloc'
- 'for_each_reloc_from'
- 'for_each_requested_gpio'
- 'for_each_requested_gpio_in_range'
- 'for_each_reserved_mem_range'
- 'for_each_reserved_mem_region'
- 'for_each_rtd_codec_dais'
- 'for_each_rtd_components'
- 'for_each_rtd_cpu_dais'
- 'for_each_rtd_dais'
- 'for_each_sband_iftype_data'
- 'for_each_script'
- 'for_each_sec'
- 'for_each_set_bit'
- 'for_each_set_bit_from'
- 'for_each_set_bit_wrap'
- 'for_each_set_bitrange'
- 'for_each_set_bitrange_from'
- 'for_each_set_clump8'
- 'for_each_sg'
- 'for_each_sg_dma_page'
- 'for_each_sg_page'
- 'for_each_sgtable_dma_page'
- 'for_each_sgtable_dma_sg'
- 'for_each_sgtable_page'
- 'for_each_sgtable_sg'
- 'for_each_sibling_event'
- 'for_each_sta_active_link'
- 'for_each_subelement'
- 'for_each_subelement_extid'
- 'for_each_subelement_id'
- 'for_each_sublist'
- 'for_each_subsystem'
- 'for_each_supported_activate_fn'
- 'for_each_supported_inject_fn'
- 'for_each_sym'
- 'for_each_test'
- 'for_each_thread'
- 'for_each_token'
- 'for_each_unicast_dest_pgid'
- 'for_each_valid_link'
- 'for_each_vif_active_link'
- 'for_each_vma'
- 'for_each_vma_range'
- 'for_each_vsi'
- 'for_each_wakeup_source'
- 'for_each_zone'
- 'for_each_zone_zonelist'
- 'for_each_zone_zonelist_nodemask'
- 'func_for_each_insn'
- 'fwnode_for_each_available_child_node'
- 'fwnode_for_each_child_node'
- 'fwnode_for_each_parent_node'
- 'fwnode_graph_for_each_endpoint'
- 'gadget_for_each_ep'
- 'genradix_for_each'
- 'genradix_for_each_from'
- 'genradix_for_each_reverse'
- 'hash_for_each'
- 'hash_for_each_possible'
- 'hash_for_each_possible_rcu'
- 'hash_for_each_possible_rcu_notrace'
- 'hash_for_each_possible_safe'
- 'hash_for_each_rcu'
- 'hash_for_each_safe'
- 'hashmap__for_each_entry'
- 'hashmap__for_each_entry_safe'
- 'hashmap__for_each_key_entry'
- 'hashmap__for_each_key_entry_safe'
- 'hctx_for_each_ctx'
- 'hists__for_each_format'
- 'hists__for_each_sort_list'
- 'hlist_bl_for_each_entry'
- 'hlist_bl_for_each_entry_rcu'
- 'hlist_bl_for_each_entry_safe'
- 'hlist_for_each'
- 'hlist_for_each_entry'
- 'hlist_for_each_entry_continue'
- 'hlist_for_each_entry_continue_rcu'
- 'hlist_for_each_entry_continue_rcu_bh'
- 'hlist_for_each_entry_from'
- 'hlist_for_each_entry_from_rcu'
- 'hlist_for_each_entry_rcu'
- 'hlist_for_each_entry_rcu_bh'
- 'hlist_for_each_entry_rcu_notrace'
- 'hlist_for_each_entry_safe'
- 'hlist_for_each_entry_srcu'
- 'hlist_for_each_safe'
- 'hlist_nulls_for_each_entry'
- 'hlist_nulls_for_each_entry_from'
- 'hlist_nulls_for_each_entry_rcu'
- 'hlist_nulls_for_each_entry_safe'
- 'i3c_bus_for_each_i2cdev'
- 'i3c_bus_for_each_i3cdev'
- 'idr_for_each_entry'
- 'idr_for_each_entry_continue'
- 'idr_for_each_entry_continue_ul'
- 'idr_for_each_entry_ul'
- 'in_dev_for_each_ifa_rcu'
- 'in_dev_for_each_ifa_rtnl'
- 'inet_bind_bucket_for_each'
- 'interval_tree_for_each_span'
- 'intlist__for_each_entry'
- 'intlist__for_each_entry_safe'
- 'kcore_copy__for_each_phdr'
- 'key_for_each'
- 'key_for_each_safe'
- 'klp_for_each_func'
- 'klp_for_each_func_safe'
- 'klp_for_each_func_static'
- 'klp_for_each_object'
- 'klp_for_each_object_safe'
- 'klp_for_each_object_static'
- 'kunit_suite_for_each_test_case'
- 'kvm_for_each_memslot'
- 'kvm_for_each_memslot_in_gfn_range'
- 'kvm_for_each_vcpu'
- 'libbpf_nla_for_each_attr'
- 'list_for_each'
- 'list_for_each_codec'
- 'list_for_each_codec_safe'
- 'list_for_each_continue'
- 'list_for_each_entry'
- 'list_for_each_entry_continue'
- 'list_for_each_entry_continue_rcu'
- 'list_for_each_entry_continue_reverse'
- 'list_for_each_entry_from'
- 'list_for_each_entry_from_rcu'
- 'list_for_each_entry_from_reverse'
- 'list_for_each_entry_lockless'
- 'list_for_each_entry_rcu'
- 'list_for_each_entry_reverse'
- 'list_for_each_entry_safe'
- 'list_for_each_entry_safe_continue'
- 'list_for_each_entry_safe_from'
- 'list_for_each_entry_safe_reverse'
- 'list_for_each_entry_srcu'
- 'list_for_each_from'
- 'list_for_each_prev'
- 'list_for_each_prev_safe'
- 'list_for_each_rcu'
- 'list_for_each_reverse'
- 'list_for_each_safe'
- 'llist_for_each'
- 'llist_for_each_entry'
- 'llist_for_each_entry_safe'
- 'llist_for_each_safe'
- 'lwq_for_each_safe'
- 'map__for_each_symbol'
- 'map__for_each_symbol_by_name'
- 'maps__for_each_entry'
- 'maps__for_each_entry_safe'
- 'mas_for_each'
- 'mci_for_each_dimm'
- 'media_device_for_each_entity'
- 'media_device_for_each_intf'
- 'media_device_for_each_link'
- 'media_device_for_each_pad'
- 'media_entity_for_each_pad'
- 'media_pipeline_for_each_entity'
- 'media_pipeline_for_each_pad'
- 'mlx5_lag_for_each_peer_mdev'
- 'msi_domain_for_each_desc'
- 'msi_for_each_desc'
- 'mt_for_each'
- 'nanddev_io_for_each_page'
- 'netdev_for_each_lower_dev'
- 'netdev_for_each_lower_private'
- 'netdev_for_each_lower_private_rcu'
- 'netdev_for_each_mc_addr'
- 'netdev_for_each_synced_mc_addr'
- 'netdev_for_each_synced_uc_addr'
- 'netdev_for_each_uc_addr'
- 'netdev_for_each_upper_dev_rcu'
- 'netdev_hw_addr_list_for_each'
- 'nft_rule_for_each_expr'
- 'nla_for_each_attr'
- 'nla_for_each_nested'
- 'nlmsg_for_each_attr'
- 'nlmsg_for_each_msg'
- 'nr_neigh_for_each'
- 'nr_neigh_for_each_safe'
- 'nr_node_for_each'
- 'nr_node_for_each_safe'
- 'of_for_each_phandle'
- 'of_property_for_each_string'
- 'of_property_for_each_u32'
- 'pci_bus_for_each_resource'
- 'pci_dev_for_each_resource'
- 'pcl_for_each_chunk'
- 'pcl_for_each_segment'
- 'pcm_for_each_format'
- 'perf_config_items__for_each_entry'
- 'perf_config_sections__for_each_entry'
- 'perf_config_set__for_each_entry'
- 'perf_cpu_map__for_each_cpu'
- 'perf_cpu_map__for_each_idx'
- 'perf_evlist__for_each_entry'
- 'perf_evlist__for_each_entry_reverse'
- 'perf_evlist__for_each_entry_safe'
- 'perf_evlist__for_each_evsel'
- 'perf_evlist__for_each_mmap'
- 'perf_hpp_list__for_each_format'
- 'perf_hpp_list__for_each_format_safe'
- 'perf_hpp_list__for_each_sort_list'
- 'perf_hpp_list__for_each_sort_list_safe'
- 'perf_tool_event__for_each_event'
- 'plist_for_each'
- 'plist_for_each_continue'
- 'plist_for_each_entry'
- 'plist_for_each_entry_continue'
- 'plist_for_each_entry_safe'
- 'plist_for_each_safe'
- 'pnp_for_each_card'
- 'pnp_for_each_dev'
- 'protocol_for_each_card'
- 'protocol_for_each_dev'
- 'queue_for_each_hw_ctx'
- 'radix_tree_for_each_slot'
- 'radix_tree_for_each_tagged'
- 'rb_for_each'
- 'rbtree_postorder_for_each_entry_safe'
- 'rdma_for_each_block'
- 'rdma_for_each_port'
- 'rdma_umem_for_each_dma_block'
- 'resort_rb__for_each_entry'
- 'resource_list_for_each_entry'
- 'resource_list_for_each_entry_safe'
- 'rhl_for_each_entry_rcu'
- 'rhl_for_each_rcu'
- 'rht_for_each'
- 'rht_for_each_entry'
- 'rht_for_each_entry_from'
- 'rht_for_each_entry_rcu'
- 'rht_for_each_entry_rcu_from'
- 'rht_for_each_entry_safe'
- 'rht_for_each_from'
- 'rht_for_each_rcu'
- 'rht_for_each_rcu_from'
- 'rq_for_each_bvec'
- 'rq_for_each_segment'
- 'rq_list_for_each'
- 'rq_list_for_each_safe'
- 'sample_read_group__for_each'
- 'scsi_for_each_prot_sg'
- 'scsi_for_each_sg'
- 'sctp_for_each_hentry'
- 'sctp_skb_for_each'
- 'sec_for_each_insn'
- 'sec_for_each_insn_continue'
- 'sec_for_each_insn_from'
- 'sec_for_each_sym'
- 'shdma_for_each_chan'
- 'shost_for_each_device'
- 'sk_for_each'
- 'sk_for_each_bound'
- 'sk_for_each_bound_bhash2'
- 'sk_for_each_entry_offset_rcu'
- 'sk_for_each_from'
- 'sk_for_each_rcu'
- 'sk_for_each_safe'
- 'sk_nulls_for_each'
- 'sk_nulls_for_each_from'
- 'sk_nulls_for_each_rcu'
- 'snd_array_for_each'
- 'snd_pcm_group_for_each_entry'
- 'snd_soc_dapm_widget_for_each_path'
- 'snd_soc_dapm_widget_for_each_path_safe'
- 'snd_soc_dapm_widget_for_each_sink_path'
- 'snd_soc_dapm_widget_for_each_source_path'
- 'strlist__for_each_entry'
- 'strlist__for_each_entry_safe'
- 'sym_for_each_insn'
- 'sym_for_each_insn_continue_reverse'
- 'symbols__for_each_entry'
- 'tb_property_for_each'
- 'tcf_act_for_each_action'
- 'tcf_exts_for_each_action'
- 'ttm_resource_manager_for_each_res'
- 'twsk_for_each_bound_bhash2'
- 'udp_portaddr_for_each_entry'
- 'udp_portaddr_for_each_entry_rcu'
- 'usb_hub_for_each_child'
- 'v4l2_device_for_each_subdev'
- 'v4l2_m2m_for_each_dst_buf'
- 'v4l2_m2m_for_each_dst_buf_safe'
- 'v4l2_m2m_for_each_src_buf'
- 'v4l2_m2m_for_each_src_buf_safe'
- 'virtio_device_for_each_vq'
- 'while_for_each_ftrace_op'
- 'xa_for_each'
- 'xa_for_each_marked'
- 'xa_for_each_range'
- 'xa_for_each_start'
- 'xas_for_each'
- 'xas_for_each_conflict'
- 'xas_for_each_marked'
- 'xbc_array_for_each_value'
- 'xbc_for_each_key_value'
- 'xbc_node_for_each_array_value'
- 'xbc_node_for_each_child'
- 'xbc_node_for_each_key_value'
- 'xbc_node_for_each_subkey'
- 'zorro_for_each_dev'
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentGotoLabels: false
IndentPPDirectives: None
IndentWidth: 8
IndentAccessModifiers: false
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 8
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
# Taken from git's rules
PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatementsExceptForEachMacros
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 8
UseTab: Always
...

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
build/*
build-vscode/*
characters/*
resources/buildings/*

7
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
"cmake.generator": "Unix Makefiles",
"cmake.configureSettings": {
"CMAKE_PREFIX_PATH": "/media/slapin/library/ogre/ogre-sdk"
},
"cmake.buildDirectory": "${workspaceFolder}/build-vscode"
}

62
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,62 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "cmake",
"label": "CMake: configure",
"command": "configure",
"problemMatcher": [],
"detail": "CMake config"
},
{
"type": "cmake",
"label": "CMake: clean rebuild",
"command": "build",
"targets": [
"GuiTest",
"0_Bootstrap",
"TerrainTest",
"Procedural"
],
"group": "build",
"problemMatcher": [],
"detail": "CMake clean rebuild task"
},
{
"type": "cmake",
"label": "CMake: clean rebuild",
"command": "cleanRebuild",
"targets": [
"GuiTest",
"0_Bootstrap",
"TerrainTest",
"Procedural"
],
"group": "build",
"problemMatcher": [],
"detail": "CMake clean rebuild task"
},
{
"type": "cmake",
"label": "CMake: complete build",
"command": "build",
"targets": [
"all"
],
"group": "build",
"problemMatcher": [],
"detail": "CMake build"
},
{
"type": "cmake",
"label": "CMake: complete rebuild",
"command": "cleanRebuild",
"targets": [
"all"
],
"group": "build",
"problemMatcher": [],
"detail": "CMake clean rebuild task"
}
]
}

View File

@@ -2,19 +2,778 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at https://www.ogre3d.org/licensing.
// SPDX-License-Identifier: MIT
//
#include <iostream>
#include "Ogre.h"
#include "OgreApplicationContext.h"
#include "Bullet/OgreBullet.h"
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
#include "btKinematicCharacterController.h"
#include "LinearMath/btTransform.h"
#include "OgrePageManager.h"
class CharacterController {
#define CAM_HEIGHT 1.6f // height of camera above character's center of mass
#define RUN_SPEED 17 // character running speed in units per second
#define TURN_SPEED 500.0f // character turning in degrees per second
#define ANIM_FADE_SPEED 7.5f // animation crossfade speed in % of full weight per second
using Real = Ogre::Real;
using Math = Ogre::Math;
class WorldData {
std::unique_ptr<Ogre::Bullet::DynamicsWorld> mDynWorld;
std::unique_ptr<Ogre::Bullet::DebugDrawer> mDbgDraw;
std::unique_ptr<Ogre::Root> mRoot;
std::unique_ptr<Ogre::SceneManager> mScnMgr;
std::unique_ptr<btDynamicsWorld> mbtWorld;
std::unique_ptr<Ogre::PageManager> mPageManager;
Ogre::PagedWorld *mPagedWorld;
private:
static WorldData *singleton;
class DummyPageProvider : public Ogre::PageProvider
{
public:
bool prepareProceduralPage(Ogre::Page* page, Ogre::PagedWorldSection* section) override { return true; }
bool loadProceduralPage(Ogre::Page* page, Ogre::PagedWorldSection* section) override { return true; }
bool unloadProceduralPage(Ogre::Page* page, Ogre::PagedWorldSection* section) override { return true; }
bool unprepareProceduralPage(Ogre::Page* page, Ogre::PagedWorldSection* section) override { return true; }
};
DummyPageProvider mDummyPageProvider;
WorldData(Ogre::Root *root, Ogre::SceneManager *scnMgr)
: mDynWorld(new Ogre::Bullet::DynamicsWorld(Ogre::Vector3(0, -9.8, 0)))
, mDbgDraw(new Ogre::Bullet::DebugDrawer(scnMgr->getRootSceneNode(), mDynWorld->getBtWorld()))
, mRoot(root)
, mScnMgr(scnMgr)
, mbtWorld(mDynWorld->getBtWorld())
, mPageManager(nullptr)
, mPagedWorld(nullptr)
{
}
public:
static void init(Ogre::Root *root, Ogre::SceneManager *scnMgr)
{
singleton = new WorldData(root, scnMgr);
}
static WorldData *get_singleton()
{
return singleton;
}
static void cleanup()
{
if (singleton)
delete singleton;
singleton = nullptr;
}
Ogre::SceneManager *getSceneManager()
{
return mScnMgr.get();
}
Ogre::Root *getRoot()
{
return mRoot.get();
}
void createTrimesh(Ogre::Entity *entity)
{
}
btPairCachingGhostObject *addGhostObject(Ogre::Entity *ent, btCollisionShape *shape, int group = 1, int mask = 0xFFFF)
{
btDynamicsWorld *world = mDynWorld->getBtWorld();
Ogre::SceneNode *node = ent->getParentSceneNode();
btPairCachingGhostObject *ghost = new btPairCachingGhostObject();
ghost->setCollisionShape(shape);
ghost->setCollisionFlags(ghost->getCollisionFlags()
| btCollisionObject::CF_NO_CONTACT_RESPONSE
| btCollisionObject::CF_CHARACTER_OBJECT
);
getWorld()->attachCollisionObject(ghost, ent, group, mask);
#if 0
getBtWorld()
->getBroadphase()->getOverlappingPairCache()
->setInternalGhostPairCallback(new btGhostPairCallback());
ghost->setUserPointer(new EntityCollisionListener{ent, nullptr});
#endif
return ghost;
}
btRigidBody *addRigidBody(float mass, Ogre::Entity *ent, Ogre::Bullet::ColliderType ct, int group = 1, int mask = 0xFFFF)
{
btDynamicsWorld *world = mDynWorld->getBtWorld();
Ogre::SceneNode *node = ent->getParentSceneNode();
Ogre::Bullet::RigidBodyState *state = new Ogre::Bullet::RigidBodyState(node);
btCollisionShape *cs;
btCollisionShape *shape;
btVector3 inertia(0, 0, 0);
switch(ct) {
case Ogre::Bullet::CT_TRIMESH: {
cs = Ogre::Bullet::createTrimeshCollider(ent);
if (mass != 0)
cs->calculateLocalInertia(mass, inertia);
} break;
case Ogre::Bullet::CT_CAPSULE: {
cs = new btCompoundShape();
btScalar height = 1.0f;
btScalar radius = 0.3f;
shape = new btCapsuleShape(radius, 2 * height - 2 * radius);
btTransform transform;
transform.setIdentity();
transform.setOrigin(btVector3(0, 1, 0));
static_cast<btCompoundShape *>(cs)->addChildShape(transform, shape);
btScalar masses[1] = {mass};
btTransform principal;
static_cast<btCompoundShape *>(cs)->calculatePrincipalAxisTransform(masses, principal, inertia);
} break;
default:
assert(false);
break;
}
btRigidBody *body = new btRigidBody(mass, state, cs, inertia);
getWorld()->attachRigidBody(body, ent, nullptr, group, mask);
#if 0
body->setUserPointer(new EntityCollisionListener{ent, nullptr});
// btRigidBody *body = mDynWorld->addRigidBody(0, ent, Ogre::Bullet::CT_TRIMESH);
#endif
return body;
}
btRigidBody *addKinematicRigidBody(float mass, Ogre::Entity *ent, Ogre::Bullet::ColliderType ct, int group = 1, int mask = 0xFFFF)
{
return mDynWorld->addKinematicRigidBody(ent, ct, group, mask);
}
btDynamicsWorld *getBtWorld()
{
return mDynWorld->getBtWorld();
}
Ogre::Bullet::DynamicsWorld *getWorld()
{
return mDynWorld.get();
}
void update(float delta)
{
WorldData::get_singleton()
->getBtWorld()->stepSimulation(delta, 10);
mDbgDraw->update();
}
void initPagedWorld(Ogre::Camera *camera)
{
mPageManager = std::make_unique<Ogre::PageManager>();
mPageManager->setPageProvider(&mDummyPageProvider);
mPageManager->addCamera(camera);
mPageManager->setDebugDisplayLevel(0);
mPagedWorld = mPageManager->createWorld();
}
};
WorldData *WorldData::singleton = nullptr;
class MainWorld : public Ogre::FrameListener
{
btRigidBody *mFloorBody;
public:
void setup()
{
// mScnMgr = scnMgr;
// mDynWorld.reset(new Ogre::Bullet::DynamicsWorld(Ogre::Vector3(0, -9.8, 0)));
// mDbgDraw.reset(new Ogre::Bullet::DebugDrawer(mScnMgr->getRootSceneNode(), mDynWorld->getBtWorld()));
Ogre::MeshManager::getSingleton().createPlane("floor", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::Plane(Ogre::Vector3::UNIT_Y, 0), 100, 100, 10, 10, true, 1, 10, 10, Ogre::Vector3::UNIT_Z);
// create a floor entity, give it a material, and place it at the origin
Ogre::SceneManager *scnMgr = WorldData::get_singleton()->getSceneManager();
Ogre::Entity *floor = scnMgr->createEntity("Floor", "floor");
scnMgr->getRootSceneNode()->attachObject(floor);
mFloorBody = WorldData::get_singleton()->addRigidBody(0, floor, Ogre::Bullet::CT_TRIMESH);
}
btRigidBody *addCharacter(Ogre::Entity *ent, float mass)
{
return WorldData::get_singleton()->addKinematicRigidBody(mass, ent, Ogre::Bullet::CT_COMPOUND);
}
bool frameStarted(const Ogre::FrameEvent& evt) override;
};
class CharacterController : public OgreBites::InputListener, Ogre::FrameListener {
enum AnimID
{
ANIM_IDLE = 0,
ANIM_WALK,
ANIM_RUN,
NUM_ANIMS,
ANIM_NONE = NUM_ANIMS
};
Ogre::Node *mRootBone;
Ogre::SceneNode *mCameraNode;
Ogre::Camera *mCamera;
Ogre::SceneManager *mScnMgr;
Ogre::SceneNode *mCameraPivot;
Ogre::SceneNode *mCameraGoal, *mBodyNode;
Ogre::Entity *mBodyEnt;
Real mPivotPitch;
Real mVerticalVelocity;
Ogre::Vector3 mKeyDirection; // player's local intended direction based on WASD keys
Ogre::Vector3 mGoalDirection; // actual intended direction in world-space
Ogre::AnimationState *mAnims[NUM_ANIMS]; // master animation list
Ogre::Animation *mSkelAnimations[NUM_ANIMS];
Ogre::NodeAnimationTrack *mHipsTracks[NUM_ANIMS];
Ogre::NodeAnimationTrack *mRootTracks[NUM_ANIMS];
AnimID mAnimID;
bool mFadingIn[NUM_ANIMS]; // which animations are fading in
bool mFadingOut[NUM_ANIMS]; // which animations are fading out
Real mTimer; // general timer to see how long animations have been playing
Ogre::Skeleton *mSkeleton;
bool mRunning;
MainWorld *world;
Ogre::Vector3 rootMotion;
Ogre::Quaternion rootRotation;
// btRigidBody *mRigidBody;
btCompoundShape *mCollisionShape;
btPairCachingGhostObject *mGhostObject;
btKinematicCharacterController *mController;
public:
CharacterController(Ogre::SceneNode *camNode, Ogre::Camera *cam, Ogre::SceneManager *scnMgr, MainWorld *world);
~CharacterController();
private:
void setupBody();
void setupCamera();
void setupAnimations();
public:
bool keyPressed(const OgreBites::KeyboardEvent& evt) override;
bool keyReleased(const OgreBites::KeyboardEvent& evt) override;
bool mouseMoved(const OgreBites::MouseMotionEvent& evt) override;
bool mouseWheelRolled(const OgreBites::MouseWheelEvent& evt) override;
bool mousePressed(const OgreBites::MouseButtonEvent& evt) override;
bool frameStarted(const Ogre::FrameEvent& evt) override;
void frameRendered(const Ogre::FrameEvent& evt) override;
private:
void updateBody(Ogre::Real deltaTime);
void updateAnimations(Real deltaTime);
void updateRootMotion(Real deltaTime);
void fadeAnimations(Real deltaTime);
void updateCamera(Real deltaTime);
void updateCameraGoal(Real deltaYaw, Real deltaPitch, Real deltaZoom);
void setAnimation(AnimID id, bool reset = false);
#if 0
struct testMotionResult {
};
struct recoverResult {
};
bool bodyTestMotion(btRigidBody *body,
const btTransform &from,
const btVector3 &motion, bool infinite_inertia,
textMotionResult *result,
bool excludeRaycastShapes,
const std::set<btCollisionObject *> &exclude);
bool recoverFromPenetration(btRigidBody *body,
const btTransform &body_position,
btScalar recover_movement_scale,
bool infinite_inertia,
btVector3 &delta_recover_movement,
recoverResult *recover_result,
const std::set<btCollisionObject *> &exclude);
#endif
inline btQuaternion convert(const Ogre::Quaternion& q)
{
return btQuaternion(q.x, q.y, q.z, q.w);
}
inline btVector3 convert(const Ogre::Vector3& v)
{
return btVector3(v.x, v.y, v.z);
}
inline btTransform convert(const Ogre::Quaternion& q, const Ogre::Vector3& v)
{
btQuaternion mq = convert(q);
btVector3 mv = convert(v);
return btTransform(mq, mv);
}
inline Ogre::Quaternion convert(const btQuaternion& q)
{
return Ogre::Quaternion(q.w(), q.x(), q.y(), q.z());
}
inline Ogre::Vector3 convert(const btVector3& v)
{
return Ogre::Vector3(v.x(), v.y(), v.z());
}
inline void convert(const btTransform &from, Ogre::Quaternion &q, Ogre::Vector3 &v)
{
q = convert(from.getRotation());
v = convert(from.getOrigin());
}
};
CharacterController::CharacterController(
Ogre::SceneNode *camNode,
Ogre::Camera *cam,
Ogre::SceneManager *scnMgr,
MainWorld *world)
: mCameraNode(camNode)
, mCamera(cam)
, mScnMgr(scnMgr)
, mPivotPitch(0)
, mVerticalVelocity(0)
, mAnimID(ANIM_NONE)
, mRunning(false)
, world(world)
, mCollisionShape(nullptr)
, mGhostObject(nullptr)
, mController(nullptr)
{
setupBody();
setupCamera();
setupAnimations();
}
CharacterController::~CharacterController()
{
}
void CharacterController::setupBody()
{
mBodyEnt = mScnMgr->createEntity("normal-male.glb");
mBodyNode = mScnMgr->getRootSceneNode()->createChildSceneNode();
mBodyNode->attachObject(mBodyEnt);
mSkeleton = mBodyEnt->getSkeleton();
// mRigidBody = world->addCharacter(mBodyEnt, 0);
// mCollisionShape = static_cast<btCompoundShape *>(mRigidBody->getCollisionShape());
mGhostObject = new btPairCachingGhostObject();
mCollisionShape = new btCompoundShape;
mGhostObject->setCollisionShape(mCollisionShape);
{
btVector3 inertia(0, 0, 0);
// mCollisionShape = new btCompoundShape();
btScalar height = 1.0f;
btScalar radius = 0.3f;
btCapsuleShape *shape = new btCapsuleShape(radius, 2 * height - 2 * radius);
btTransform transform;
transform.setIdentity();
transform.setOrigin(btVector3(0, 1, 0));
static_cast<btCompoundShape *>(mCollisionShape)->addChildShape(transform, shape);
btScalar masses[1] = {0};
btTransform principal;
static_cast<btCompoundShape *>(mCollisionShape)->calculatePrincipalAxisTransform(masses, principal, inertia);
}
mGhostObject->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_NO_CONTACT_RESPONSE);
mGhostObject->setActivationState(DISABLE_DEACTIVATION);
Ogre::Bullet::KinematicMotionSimple *controller = new Ogre::Bullet::KinematicMotionSimple(mGhostObject, mBodyNode);
WorldData::get_singleton()->getWorld()->attachCollisionObject(mGhostObject, mBodyEnt, btBroadphaseProxy::AllFilter, btBroadphaseProxy::AllFilter);
WorldData::get_singleton()->getBtWorld()->addAction(controller);
assert(mCollisionShape);
#if 0
if (mRigidBody->getMass() == 0) {
#if 0
mRigidBody->setCollisionFlags(mRigidBody->getCollisionFlags()
| btCollisionObject::CF_KINEMATIC_OBJECT
| btCollisionObject::CF_NO_CONTACT_RESPONSE
);
#endif
#if 0
mGhostObject->setWorldTransform(mRigidBody->getWorldTransform());
WorldData::get_singleton()->getBtWorld()
->getBroadphase()->getOverlappingPairCache()
->setInternalGhostPairCallback(new btGhostPairCallback());
#endif
}
#endif
#if 0
mRigidBody->setActivationState(DISABLE_DEACTIVATION);
#endif
#if 0
{
Ogre::Entity *e2 = mScnMgr->createEntity("normal-male.glb");
Ogre::SceneNode *e2node = mScnMgr->getRootSceneNode()->createChildSceneNode();
e2node->attachObject(e2);
mGhostObject = WorldData::get_singleton()->addGhostObject(e2, mCollisionShape);
mController = new btKinematicCharacterController(mGhostObject, mCollisionShape, 0.5f);
WorldData::get_singleton()->getBtWorld()->addAction(mController);
}
#endif
assert(mSkeleton->hasBone("Root"));
mRootBone = mSkeleton->getBone("Root");
assert(mRootBone);
}
void CharacterController::setupCamera()
{
// create a pivot at roughly the character's shoulder
mCameraPivot = mScnMgr->getRootSceneNode()->createChildSceneNode();
mCameraGoal = mCameraPivot->createChildSceneNode(Ogre::Vector3(0, 2, 3));
mCameraNode->setPosition(mCameraPivot->getPosition() + mCameraGoal->getPosition());
mCameraPivot->setFixedYawAxis(true);
mCameraGoal->setFixedYawAxis(true);
mCameraNode->setFixedYawAxis(true);
// our model is quite small, so reduce the clipping planes
mCamera->setNearClipDistance(0.1f);
mCamera->setFarClipDistance(700);
mPivotPitch = 0;
mKeyDirection = Ogre::Vector3::ZERO;
mVerticalVelocity = 0;
}
void CharacterController::setupAnimations()
{
int i, j;
mSkeleton->setBlendMode(Ogre::ANIMBLEND_CUMULATIVE);
Ogre::String animNames[NUM_ANIMS] = {"idle", "walking", "running"};
for (i = 0; i < NUM_ANIMS; i++) {
mAnims[i] = mBodyEnt->getAnimationState(animNames[i]);
mAnims[i]->setLoop(true);
mAnims[i]->setEnabled(true);
mAnims[i]->setWeight(0);
mFadingIn[i] = false;
mFadingOut[i] = false;
mSkelAnimations[i] = mSkeleton->getAnimation(animNames[i]);
for (const auto& it : mSkelAnimations[i]->_getNodeTrackList()) {
Ogre::NodeAnimationTrack* track = it.second;
Ogre::String trackName = track->getAssociatedNode()->getName();
if (trackName == "mixamorig:Hips") {
mHipsTracks[i] = track;
} else if (trackName == "Root") {
mRootTracks[i] = track;
// mRootTracks[i]->removeAllKeyFrames();
}
}
Ogre::Vector3 delta = Ogre::Vector3::ZERO;
Ogre::Vector3 motion = Ogre::Vector3::ZERO;
for(j = 0; j < mRootTracks[i]->getNumKeyFrames(); j++) {
Ogre::Vector3 trans = mRootTracks[i]->getNodeKeyFrame(j)->getTranslate();
if (j == 0)
delta = trans;
else
delta = trans - motion;
mRootTracks[i]->getNodeKeyFrame(j)->setTranslate(delta);
motion = trans;
}
}
#if 0
for(i = 0; i < NUM_ANIMS - 1; i++) {
// need to cache
int j;
Ogre::String animName = mAnims[i]->getAnimationName();
Ogre::Animation *anim = mSkeleton->getAnimation(animName);
Ogre::NodeAnimationTrack *hips_track = nullptr, *root_track = nullptr;
Ogre::Node *root_node = nullptr;
for (const auto& it : anim->_getNodeTrackList()) {
Ogre::NodeAnimationTrack* track = it.second;
Ogre::String trackName = track->getAssociatedNode()->getName();
std::cout << animName << " track: " << trackName << "\n";
if (trackName == "mixamorig:Hips")
hips_track = track;
else if (trackName == "Root") {
root_track = track;
root_node = track->getAssociatedNode();
}
}
assert(false);
root_track->removeAllKeyFrames();
std::cout << hips_track << " " << root_track << "\n";
std::cout << hips_track->getNumKeyFrames() << " " << root_track->getNumKeyFrames() << "\n";
assert(hips_track && root_track);
Ogre::Vector3 delta = Ogre::Vector3::ZERO;
for(j = 0; j < hips_track->getNumKeyFrames(); j++) {
float timePos = hips_track->getNodeKeyFrame(j)->getTime();
Ogre::Vector3 trans = hips_track->getNodeKeyFrame(j)->getTranslate();
Ogre::Vector3 hips_trans(0, 0, 0);
Ogre::Vector3 root_trans(0, 0, 0);
hips_track->getNodeKeyFrame(j)->setTranslate(hips_trans);
Ogre::TransformKeyFrame *nk = root_track->createNodeKeyFrame(timePos);
nk->setTranslate(root_trans - delta);
nk->setScale(Ogre::Vector3(1, 1, 1));
nk->setRotation(Ogre::Quaternion());
std::cout << animName << " delta: " << j << " " << timePos << " " << root_trans - delta << "\n";
delta = root_trans;
}
for(j = 0; j < root_track->getNumKeyFrames(); j++) {
float timePos = hips_track->getNodeKeyFrame(j)->getTime();
Ogre::Vector3 root_trans = hips_track->getNodeKeyFrame(j)->getTranslate();
std::cout << animName << " delta: root: " << j << " " << timePos << " " << root_trans << "\n";
}
}
// assert(false);
#endif
setAnimation(ANIM_IDLE);
}
bool CharacterController::keyPressed(const OgreBites::KeyboardEvent& evt)
{
OgreBites::Keycode key = evt.keysym.sym;
if (key == 'q' && (mAnimID == ANIM_IDLE)) {
/* ... */
mTimer = 0;
} else if (key == 'e') {
} else if (key == 'w')
mKeyDirection.z = -1;
else if (key == 'a')
mKeyDirection.x = -1;
else if (key == 's')
mKeyDirection.z = 1;
else if (key == 'd')
mKeyDirection.x = 1;
if (key == OgreBites::SDLK_LSHIFT)
mRunning = true;
if (!mKeyDirection.isZeroLength() && mAnimID == ANIM_IDLE) {
if (mRunning)
setAnimation(ANIM_RUN, true);
else
setAnimation(ANIM_WALK, true);
// std::cout << "Walking\n";
} else if (!mKeyDirection.isZeroLength() && mAnimID == ANIM_WALK && mRunning)
setAnimation(ANIM_RUN);
return true;
}
bool CharacterController::keyReleased(const OgreBites::KeyboardEvent& evt)
{
OgreBites::Keycode key = evt.keysym.sym;
if (key == 'w' && mKeyDirection.z == -1) mKeyDirection.z = 0;
else if (key == 'a' && mKeyDirection.x == -1) mKeyDirection.x = 0;
else if (key == 's' && mKeyDirection.z == 1) mKeyDirection.z = 0;
else if (key == 'd' && mKeyDirection.x == 1) mKeyDirection.x = 0;
if (key == OgreBites::SDLK_LSHIFT)
mRunning = false;
if (mKeyDirection.isZeroLength() && (mAnimID == ANIM_WALK || mAnimID == ANIM_RUN))
setAnimation(ANIM_IDLE);
else if (!mKeyDirection.isZeroLength() && mAnimID == ANIM_RUN && !mRunning)
setAnimation(ANIM_WALK);
return true;
}
bool CharacterController::mouseMoved(const OgreBites::MouseMotionEvent& evt)
{
// update camera goal based on mouse movement
updateCameraGoal(-0.18f * evt.xrel, -0.12f * evt.yrel, 0);
return true;
}
bool CharacterController::mouseWheelRolled(const OgreBites::MouseWheelEvent& evt)
{
// update camera goal based on mouse movement
updateCameraGoal(0, 0, -0.15f * evt.y);
return true;
}
bool CharacterController::mousePressed(const OgreBites::MouseButtonEvent& evt)
{
std::cout << "Mouse press\n";
return false;
}
void CharacterController::frameRendered(const Ogre::FrameEvent& evt)
{
updateBody(evt.timeSinceLastFrame);
updateAnimations(evt.timeSinceLastFrame);
updateCamera(evt.timeSinceLastFrame);
if (evt.timeSinceLastFrame > 0)
updateRootMotion(evt.timeSinceLastFrame);
}
bool CharacterController::frameStarted(const Ogre::FrameEvent& evt)
{
return true;
}
void CharacterController::updateCameraGoal(Real deltaYaw, Real deltaPitch, Real deltaZoom)
{
mCameraPivot->yaw(Ogre::Degree(deltaYaw), Ogre::Node::TS_PARENT);
if (!(mPivotPitch + deltaPitch > 25 && deltaPitch > 0) &&
!(mPivotPitch + deltaPitch < -60 && deltaPitch < 0)) {
mCameraPivot->pitch(Ogre::Degree(deltaPitch), Ogre::Node::TS_LOCAL);
mPivotPitch += deltaPitch;
}
Real dist = mCameraGoal->_getDerivedPosition().distance(mCameraPivot->_getDerivedPosition());
Real distChange = deltaZoom * dist;
// bound the zoom
if (!(dist + distChange < 8 && distChange < 0) &&
!(dist + distChange > 25 && distChange > 0))
mCameraGoal->translate(0, 0, distChange, Ogre::Node::TS_LOCAL);
}
void CharacterController::updateBody(Real delta)
{
mGoalDirection = Ogre::Vector3::ZERO;
if (mKeyDirection != Ogre::Vector3::ZERO) {
// calculate actually goal direction in world based on player's key directions
mGoalDirection += mKeyDirection.z * mCameraNode->getOrientation().zAxis();
mGoalDirection += mKeyDirection.x * mCameraNode->getOrientation().xAxis();
mGoalDirection.y = 0;
mGoalDirection.normalise();
Ogre::Quaternion toGoal = mBodyNode->getOrientation().zAxis().getRotationTo(mGoalDirection);
// calculate how much the character has to turn to face goal direction
Real yawToGoal = toGoal.getYaw().valueDegrees();
// this is how much the character CAN turn this frame
Real yawAtSpeed = yawToGoal / Math::Abs(yawToGoal) * delta * TURN_SPEED;
// reduce "turnability" if we're in midair
// if (mBaseAnimID == ANIM_JUMP_LOOP) yawAtSpeed *= 0.2f;
if (yawToGoal < 0)
yawToGoal = std::min<Real>(0, std::max<Real>(yawToGoal, yawAtSpeed)); //yawToGoal = Math::Clamp<Real>(yawToGoal, yawAtSpeed, 0);
else if (yawToGoal > 0)
yawToGoal = std::max<Real>(0, std::min<Real>(yawToGoal, yawAtSpeed)); //yawToGoal = Math::Clamp<Real>(yawToGoal, 0, yawAtSpeed);
mBodyNode->yaw(Ogre::Degree(yawToGoal));
// move in current body direction (not the goal direction)
// mBodyNode->translate(0, 0, delta * RUN_SPEED * mAnims[mAnimID]->getWeight(),
// Ogre::Node::TS_LOCAL);
#if 0
if (mBaseAnimID == ANIM_JUMP_LOOP)
{
// if we're jumping, add a vertical offset too, and apply gravity
mBodyNode->translate(0, mVerticalVelocity * deltaTime, 0, Node::TS_LOCAL);
mVerticalVelocity -= GRAVITY * deltaTime;
Vector3 pos = mBodyNode->getPosition();
if (pos.y <= CHAR_HEIGHT)
{
// if we've hit the ground, change to landing state
pos.y = CHAR_HEIGHT;
mBodyNode->setPosition(pos);
setBaseAnimation(ANIM_JUMP_END, true);
mTimer = 0;
}
}
#endif
}
}
void CharacterController::updateAnimations(Real delta)
{
int i, j, k;
Real animSpeed = 1;
mTimer += delta;
if (mAnimID != ANIM_NONE) {
if (mAnimID == ANIM_WALK)
mAnims[mAnimID]->addTime(delta * 1.0f);
else
mAnims[mAnimID]->addTime(delta * animSpeed);
}
fadeAnimations(delta);
}
void CharacterController::updateRootMotion(Real delta)
{
Ogre::Vector3 boneMotion = mRootBone->getPosition();
OgreAssert(delta > 0.0f, "Zero delta");
#if 0
Ogre::Vector3 motion = boneMotion - rootMotion;
if (motion.squaredLength() > 0.1f * 0.1f)
motion = Ogre::Vector3();
rootMotion = boneMotion;
#endif
#if 0
float mass = mRigidBody->getMass();
std::cout << "Root bone position: " << boneMotion << "\n";
std::cout << "body mass: " << mass << "\n";
#endif
/* Kinematic motion */
Ogre::Quaternion rot = mBodyNode->getOrientation();
Ogre::Vector3 gravity(0, -9.8, 0);
Ogre::Vector3 velocity = rot * boneMotion / delta;
velocity += gravity * delta;
Ogre::Vector3 rotMotion = velocity * delta;
btTransform from(convert(mBodyNode->getOrientation()), convert(mBodyNode->getPosition()));
mBodyNode->setPosition(mBodyNode->getPosition() + rotMotion);
// WorldData::get_singleton()->getWorld()->testBodyMotion(mRigidBody, from, Ogre::Bullet::convert(rotMotion), true,
// nullptr, false, std::set<btCollisionObject *>());
}
void CharacterController::fadeAnimations(Real delta)
{
int i;
for (i = 0; i < NUM_ANIMS; i++) {
if (mFadingIn[i])
{
// slowly fade this animation in until it has full weight
Real newWeight = mAnims[i]->getWeight() + delta * ANIM_FADE_SPEED;
mAnims[i]->setWeight(Math::Clamp<Real>(newWeight, 0, 1));
if (newWeight >= 1)
mFadingIn[i] = false;
}
else if (mFadingOut[i])
{
// slowly fade this animation out until it has no weight, and then disable it
Real newWeight = mAnims[i]->getWeight() - delta * ANIM_FADE_SPEED;
mAnims[i]->setWeight(Math::Clamp<Real>(newWeight, 0, 1));
if (newWeight <= 0)
{
mAnims[i]->setEnabled(false);
mFadingOut[i] = false;
}
}
}
}
void CharacterController::updateCamera(Real delta)
{
// place the camera pivot roughly at the character's shoulder
mCameraPivot->setPosition(mBodyNode->getPosition() + Ogre::Vector3::UNIT_Y * CAM_HEIGHT);
// move the camera smoothly to the goal
Ogre::Vector3 goalOffset = mCameraGoal->_getDerivedPosition() - mCameraNode->getPosition();
mCameraNode->translate(goalOffset * delta * 9.0f);
// always look at the pivot
mCameraNode->lookAt(mCameraPivot->_getDerivedPosition(), Ogre::Node::TS_PARENT);
}
void CharacterController::setAnimation(AnimID id, bool reset)
{
assert(id >= 0 && id < NUM_ANIMS);
if (mAnimID != ANIM_NONE) {
mFadingIn[mAnimID] = false;
mFadingOut[mAnimID] = true;
}
mAnimID = id;
if (id != ANIM_NONE) {
mAnims[id]->setEnabled(true);
mAnims[id]->setWeight(0);
mFadingOut[id] = false;
mFadingIn[id] = true;
if (reset)
mAnims[id]->setTimePosition(0);
}
}
#if 0
bool CharacterController::recoverFromPenetration(btRigidBody *body,
const btTransform &body_position,
btScalar recover_movement_scale,
bool infinite_inertia,
btVector3 &delta_recover_movement,
recoverResult *recover_result,
const std::set<btCollisionObject *> &exclude)
{
return false;
}
bool CharacterController::bodyTestMotion(btRigidBody *body,
const btTransform &from,
const btVector3 &motion, bool infinite_inertia,
textMotionResult *result,
bool excludeRaycastShapes,
std::set<btCollisionObject *> exclude)
{
int t;
btTransform body_transform;
btVector3 initial_recover_motion(0, 0, 0);
// phase one - depenetration
for (t = 0; t < RECOVERING_MOVEMENT_CYCLES; t++)
if (!recoverFromPenetration(body,
body_transform,
RECOVERING_MOVEMENT_SCALE,
infinite_inertia,
initial_recover_motion,
nullptr, exclude))
break;
return false;
}
#endif
class KeyHandler : public OgreBites::InputListener
{
bool keyPressed(const OgreBites::KeyboardEvent& evt) override
{
if (evt.keysym.sym == OgreBites::SDLK_ESCAPE)
{
Ogre::Root::getSingleton().queueEndRendering();
}
return true;
}
};
bool MainWorld::frameStarted(const Ogre::FrameEvent& evt)
{
WorldData::get_singleton()->update(evt.timeSinceLastFrame);
return true;
}
class App
: public OgreBites::ApplicationContext
{
Ogre::SceneNode *mCameraNode;
Ogre::SceneManager *mScnMgr;
std::unique_ptr<CharacterController> mCharacter;
KeyHandler mKeyHandler;
MainWorld mWorld;
public:
App();
virtual ~App();
@@ -28,6 +787,7 @@ public:
}
void createContent();
void createCharacter();
void setupWorld();
};
App::App()
@@ -64,34 +824,33 @@ void App::initCamera()
// and tell it to render into the main window
getRenderWindow()->addViewport(cam);
}
void App::setupWorld()
{
addInputListener(&mKeyHandler);
mWorld.setup();
getRoot()->addFrameListener(&mWorld);
}
void App::createCharacter()
{
Ogre::Entity* ent = mScnMgr->createEntity("normal-male.glb");
Ogre::SceneNode* node = mScnMgr->getRootSceneNode()->createChildSceneNode();
node->attachObject(ent);
Ogre::Camera *cam = static_cast<Ogre::Camera *>(mCameraNode->getAttachedObject("tps_camera"));
mCharacter = std::make_unique<CharacterController>(mCameraNode, cam, mScnMgr, &mWorld);
// mInputListenerChain = TouchAgnosticInputListenerChain(getRenderWindow(), {&mKeyHandler, mCharacter.get()});
addInputListener(mCharacter.get());
WorldData::get_singleton()->initPagedWorld(cam);
}
void App::createContent()
{
// without light we would just get a black screen
Ogre::Light* light = mScnMgr->createLight("MainLight");
Ogre::SceneNode* lightNode = mScnMgr->getRootSceneNode()->createChildSceneNode();
lightNode->setPosition(0, 10, 15);
// lightNode->setPosition(0, 10, 15);
lightNode->setDirection(Ogre::Vector3(0.55, -0.3, 0.75).normalisedCopy());
lightNode->attachObject(light);
light->setType(Ogre::Light::LT_DIRECTIONAL);
light->setDiffuseColour(Ogre::ColourValue::White);
light->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4));
mScnMgr->setSkyBox(true, "Skybox", 490);
}
class KeyHandler : public OgreBites::InputListener
{
bool keyPressed(const OgreBites::KeyboardEvent& evt) override
{
if (evt.keysym.sym == OgreBites::SDLK_ESCAPE)
{
Ogre::Root::getSingleton().queueEndRendering();
}
return true;
}
};
int main(int argc, char *argv[])
{
App ctx;
@@ -103,16 +862,20 @@ int main(int argc, char *argv[])
// register our scene with the RTSS
Ogre::RTShader::ShaderGenerator* shadergen = Ogre::RTShader::ShaderGenerator::getSingletonPtr();
shadergen->addSceneManager(scnMgr);
WorldData::init(root, scnMgr);
ctx.setWindowGrab(true);
ctx.createContent();
ctx.initCamera();
ctx.setupWorld();
ctx.createCharacter();
// register for input events
KeyHandler keyHandler;
ctx.addInputListener(&keyHandler);
// KeyHandler keyHandler;
// ctx.addInputListener(&keyHandler);
ctx.getRoot()->startRendering();
ctx.setWindowGrab(false);
ctx.closeApp();
WorldData::cleanup();
return 0;
}

View File

@@ -15,25 +15,86 @@ set(CREATE_SCENES
${CMAKE_SOURCE_DIR}/characters/male/vroid-normal-male.scene
)
# workaround horribly broken assimp cmake, fixed with assimp 5.1
add_library(fix::assimp INTERFACE IMPORTED)
set_target_properties(fix::assimp PROPERTIES
INTERFACE_LINK_LIBRARIES "${ASSIMP_LIBRARIES};pugixml"
INTERFACE_LINK_DIRECTORIES "${ASSIMP_LIBRARY_DIRS}"
)
file(GLOB TERRAIN_SRC src/terrain/*.cpp)
# The COMPONENTS part checks that OGRE was built the way we need it
# The CONFIG flag makes sure we get OGRE instead of OGRE-next
find_package(OGRE REQUIRED COMPONENTS Bites CONFIG)
find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging CONFIG)
find_package(ZLIB)
find_package(SDL2)
find_package(assimp)
find_package(Bullet)
find_package(OgreProcedural REQUIRED CONFIG)
add_library(fix::OgreProcedural INTERFACE IMPORTED)
set_target_properties(fix::OgreProcedural PROPERTIES
INTERFACE_LINK_LIBRARIES "OgreProcedural"
INTERFACE_LINK_DIRECTORIES "${CMAKE_PREFIX_PATH}/lib"
)
add_subdirectory(src/lua)
# add the source files as usual
add_executable(0_Bootstrap Bootstrap.cpp)
# this also sets the includes and pulls third party dependencies
target_link_libraries(0_Bootstrap OgreBites)
target_link_libraries(0_Bootstrap OgreBites OgreBullet OgrePaging ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY})
target_include_directories(0_Bootstrap PUBLIC OgreBites OgrePaging OgreBullet)
add_dependencies(0_Bootstrap stage_files)
add_executable(GuiTest GuiTest.cpp ${TERRAIN_SRC})
target_link_libraries(GuiTest OgreBites OgreBullet OgrePaging OgreTerrain ${OgreProcedural_LIBRARIES} ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY})
target_include_directories(GuiTest PUBLIC OgreBites OgrePaging OgreBullet OgreTerrain ${OgreProcedural_INCLUDE_DIRS})
add_dependencies(GuiTest stage_files import_buildings)
add_executable(Procedural Procedural.cpp ${TERRAIN_SRC})
target_link_libraries(Procedural OgreBites OgreBullet OgrePaging OgreTerrain OgreProcedural::OgreProcedural ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY})
target_include_directories(Procedural PUBLIC OgreBites OgrePaging OgreBullet OgreTerrain OgreProcedural::OgreProcedural ${CMAKE_PREFIX_PATH}/include/OgreProcedural)
add_dependencies(Procedural stage_files import_buildings)
file(GLOB BUILDINGS_SRC ${CMAKE_SOURCE_DIR}/assets/blender/buildings/*.blend)
set(BUILDING_OUTPUT_FILES)
foreach(BUILDING_FILE ${BUILDINGS_SRC})
get_filename_component(FILE_NAME ${BUILDING_FILE} NAME_WE)
set(BUILDING_OUTPUT_FILE ${CMAKE_BINARY_DIR}/resources/buildings/${FILE_NAME}.gltf)
add_custom_command(
OUTPUT ${BUILDING_OUTPUT_FILE}
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/resources/buildings
COMMAND ${BLENDER} ${BUILDING_FILE}
-b -Y -P
${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_buildings.py
-- ${BUILDING_OUTPUT_FILE}
COMMAND touch ${BUILDING_OUTPUT_FILE}
DEPENDS ${BUILDING_FILE})
list(APPEND BUILDING_OUTPUT_FILES ${BUILDING_OUTPUT_FILE})
endforeach()
add_custom_target(import_buildings ALL DEPENDS ${BUILDING_OUTPUT_FILES})
add_executable(TerrainTest terrain.cpp ${TERRAIN_SRC})
target_link_libraries(TerrainTest OgreBites OgreBullet OgrePaging OgreTerrain lua ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY})
target_include_directories(TerrainTest PUBLIC OgreBites OgrePaging OgreTerrain OgreBullet PRIVATE . src/terrain src/lua src/lua/lua-5.4.8/src)
file(GLOB LUA_SCRIPTS_SRC ${CMAKE_SOURCE_DIR}/lua-scripts/*.lua)
set(LUA_SCRIPTS_OUTPUT)
foreach(LUA_SCRIPT_FILE ${LUA_SCRIPTS_SRC})
get_filename_component(FILE_NAME ${LUA_SCRIPT_FILE} NAME_WE)
set(LUA_SCRIPT_OUTPUT_FILE ${CMAKE_BINARY_DIR}/lua-scripts/${FILE_NAME}.lua)
add_custom_command(OUTPUT ${LUA_SCRIPT_OUTPUT_FILE}
COMMAND ${CMAKE_COMMAND} -E copy ${LUA_SCRIPT_FILE} ${LUA_SCRIPT_OUTPUT_FILE}
DEPENDS ${LUA_SCRIPT_FILE})
list(APPEND LUA_SCRIPTS_OUTPUT ${LUA_SCRIPT_OUTPUT_FILE})
endforeach()
add_custom_target(stage_lua_scripts ALL DEPENDS ${LUA_SCRIPTS_OUTPUT})
add_dependencies(TerrainTest stage_lua_scripts stage_files)
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/resources.cfg
@@ -46,8 +107,48 @@ add_custom_command(
${CMAKE_BINARY_DIR}/resources/terrain
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/characters
${CMAKE_BINARY_DIR}/characters
# COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/lua-scripts
# ${CMAKE_BINARY_DIR}/lua-scripts
# COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/skybox
# ${CMAKE_BINARY_DIR}/skybox
# COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/resources/debug
# ${CMAKE_BINARY_DIR}/resources/debug
DEPENDS ${CMAKE_SOURCE_DIR}/resources.cfg)
set(SKYBOX_SRC
early_morning_bk.jpg
early_morning_dn.jpg
early_morning_fr.jpg
early_morning_lf.jpg
early_morning_rt.jpg
early_morning_up.jpg
skybox.material
)
set(DEBUG_MATERIAL_SRC
debug.frag
debug.material
debug.program
debug.vert
)
set(MATERIALS_OUTPUT)
foreach(SKYBOX_FILE ${SKYBOX_SRC})
set(OUTPUT_FILE ${CMAKE_BINARY_DIR}/skybox/${SKYBOX_FILE})
set(INPUT_FILE ${CMAKE_SOURCE_DIR}/skybox/${SKYBOX_FILE})
add_custom_command(OUTPUT ${OUTPUT_FILE}
COMMAND ${CMAKE_COMMAND} -E copy ${INPUT_FILE} ${OUTPUT_FILE}
DEPENDS ${INPUT_FILE})
list(APPEND MATERIALS_OUTPUT ${OUTPUT_FILE})
endforeach()
foreach(DEBUG_MATERIAL_FILE ${DEBUG_MATERIAL_SRC})
set(OUTPUT_FILE ${CMAKE_BINARY_DIR}/resources/debug/${DEBUG_MATERIAL_FILE})
set(INPUT_FILE ${CMAKE_SOURCE_DIR}/resources/debug/${DEBUG_MATERIAL_FILE})
add_custom_command(OUTPUT ${OUTPUT_FILE}
COMMAND ${CMAKE_COMMAND} -E copy ${INPUT_FILE} ${OUTPUT_FILE}
DEPENDS ${INPUT_FILE})
list(APPEND MATERIALS_OUTPUT ${OUTPUT_FILE})
endforeach()
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/characters/female/vroid-normal-female.scene
${CMAKE_SOURCE_DIR}/characters/male/vroid-normal-male.scene
@@ -65,7 +166,7 @@ add_custom_command(
${CMAKE_SOURCE_DIR}/assets/vroid/jane2-dress.vrm
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
add_custom_target(stage_files ALL DEPENDS ${CMAKE_BINARY_DIR}/resources.cfg)
add_custom_target(stage_files ALL DEPENDS ${CMAKE_BINARY_DIR}/resources.cfg ${MATERIALS_OUTPUT})
add_custom_target(remove_scenes COMMAND rm -f ${CREATE_SCENES})

874
GuiTest.cpp Normal file
View File

@@ -0,0 +1,874 @@
#include <iostream>
#include <Ogre.h>
#include <OgreApplicationContext.h>
#include <OgreOverlaySystem.h>
#include <OgreOverlayManager.h>
#include <OgreImGuiOverlay.h>
#include <OgreImGuiInputListener.h>
#include <OgreTrays.h>
#include <OgreTimer.h>
#include "src/terrain/terrain.h"
class App;
class SkyRenderer : public Ogre::SceneManager::Listener {
protected:
Ogre::SceneManager *mSceneManager;
virtual void _updateRenderQueue(Ogre::RenderQueue *queue) = 0;
public:
enum BoxPlane {
BP_FRONT = 0,
BP_BACK = 1,
BP_LEFT = 2,
BP_RIGHT = 3,
BP_UP = 4,
BP_DOWN = 5
};
SkyRenderer(Ogre::SceneManager *owner)
: mSceneManager(owner)
, mSceneNode(0)
, mEnabled(false)
{
}
virtual ~SkyRenderer()
{
setEnabled(false);
if (mSceneNode)
mSceneManager->destroySceneNode(mSceneNode);
}
Ogre::SceneNode *mSceneNode;
bool mEnabled;
void setEnabled(bool enable)
{
if (enable == mEnabled)
return;
mEnabled = enable;
enable ? mSceneManager->addListener(this) :
mSceneManager->removeListener(this);
}
void
postFindVisibleObjects(Ogre::SceneManager *source,
Ogre::SceneManager::IlluminationRenderStage irs,
Ogre::Viewport *vp) override
{
// Queue skies, if viewport seems it
if (!vp->getSkiesEnabled() ||
irs == Ogre::SceneManager::IRS_RENDER_TO_TEXTURE)
return;
if (!mEnabled || !mSceneNode)
return;
// Update nodes
// Translate the box by the camera position (constant distance)
mSceneNode->setPosition(vp->getCamera()->getDerivedPosition());
_updateRenderQueue(source->getRenderQueue());
}
};
class SkyBoxRenderer : public SkyRenderer {
std::unique_ptr<Ogre::ManualObject> mSkyBoxObj;
Ogre::Quaternion mSkyBoxOrientation;
void _updateRenderQueue(Ogre::RenderQueue *queue) override
{
if (mSkyBoxObj->isVisible()) {
mSkyBoxObj->_updateRenderQueue(queue);
}
}
public:
SkyBoxRenderer(Ogre::SceneManager *owner)
: SkyRenderer(owner)
{
}
Ogre::SceneManager::SkyBoxGenParameters mSkyBoxGenParameters;
void create(const Ogre::String &materialName, Ogre::Real distance,
uint8_t renderQueue, const Ogre::Quaternion &orientation,
const Ogre::String &groupName)
{
Ogre::MaterialPtr m =
Ogre::MaterialManager::getSingleton().getByName(
materialName, groupName);
OgreAssert(m, "Sky box material '" + materialName +
"' not found.");
// Ensure loaded
m->load();
bool valid = m->getBestTechnique() &&
m->getBestTechnique()->getNumPasses();
#if 0
if (valid) {
Pass *pass = m->getBestTechnique()->getPass(0);
valid = valid && pass->getNumTextureUnitStates() &&
pass->getTextureUnitState(0)->getTextureType() ==
TEX_TYPE_CUBE_MAP;
}
if (!valid) {
LogManager::getSingleton().logWarning(
"skybox material " + materialName +
" is not supported, defaulting");
m = MaterialManager::getSingleton().getDefaultSettings();
}
#endif
OgreAssert(valid, "Bad material" + materialName);
// Create node
mSceneNode = mSceneManager->createSceneNode();
// Create object
mSkyBoxObj = std::make_unique<Ogre::ManualObject>("SkyBox");
mSkyBoxObj->setCastShadows(false);
mSceneNode->attachObject(mSkyBoxObj.get());
mSkyBoxObj->setRenderQueueGroup(renderQueue);
mSkyBoxObj->begin(materialName,
Ogre::RenderOperation::OT_TRIANGLE_STRIP,
groupName);
// rendering cube, only using 14 vertices
const Ogre::Vector3 cube_strip[14] = {
{ -1.f, 1.f, 1.f }, // Front-top-left
{ 1.f, 1.f, 1.f }, // Front-top-right
{ -1.f, -1.f, 1.f }, // Front-bottom-left
{ 1.f, -1.f, 1.f }, // Front-bottom-right
{ 1.f, -1.f, -1.f }, // Back-bottom-right
{ 1.f, 1.f, 1.f }, // Front-top-right
{ 1.f, 1.f, -1.f }, // Back-top-right
{ -1.f, 1.f, 1.f }, // Front-top-left
{ -1.f, 1.f, -1.f }, // Back-top-left
{ -1.f, -1.f, 1.f }, // Front-bottom-left
{ -1.f, -1.f, -1.f }, // Back-bottom-left
{ 1.f, -1.f, -1.f }, // Back-bottom-right
{ -1.f, 1.f, -1.f }, // Back-top-left
{ 1.f, 1.f, -1.f } // Back-top-right
};
for (const auto &vtx : cube_strip) {
mSkyBoxObj->position(orientation * (vtx * distance));
// Note UVs mirrored front/back
mSkyBoxObj->textureCoord(vtx.normalisedCopy() *
Ogre::Vector3(1, 1, -1));
}
mSkyBoxObj->end();
mSkyBoxGenParameters.skyBoxDistance = distance;
}
};
class EditUI : public Ogre::RenderTargetListener {
App *m_app;
Ogre::SceneManager *mScnMgr;
Ogre::ImGuiOverlay *mGuiOverlay;
OgreBites::ImGuiInputListener *mGuiListener;
void
preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override
{
preview(evt);
}
public:
EditUI(App *app)
: Ogre::RenderTargetListener()
, m_app(app)
{
}
void position_editor(Ogre::SceneNode *node)
{
Ogre::Vector3 position = node->getPosition();
float v[3] = { position.x, position.y, position.z };
ImGui::InputFloat3("position", v);
position.x = v[0];
position.y = v[1];
position.z = v[2];
node->setPosition(position);
}
void orientation_editor(Ogre::SceneNode *node)
{
Ogre::Quaternion q = node->getOrientation();
float yaw = Ogre::Radian(q.getYaw()).valueDegrees();
float pitch = Ogre::Radian(q.getPitch()).valueDegrees();
float roll = Ogre::Radian(q.getRoll()).valueDegrees();
bool m1 = ImGui::InputFloat("yaw", &yaw);
bool m2 = ImGui::InputFloat("pitch", &pitch);
bool m3 = ImGui::InputFloat("roll", &roll);
if (m1 || m2 || m3) {
Ogre::Quaternion q1(Ogre::Radian(Ogre::Degree(yaw)),
Ogre::Vector3::UNIT_Y);
Ogre::Quaternion q2(Ogre::Degree(pitch),
Ogre::Vector3::UNIT_X);
Ogre::Quaternion q3(Ogre::Degree(roll),
Ogre::Vector3::UNIT_Z);
node->setOrientation(q1 * q2 * q3);
}
}
void attachments_editor(Ogre::SceneNode *node)
{
const Ogre::SceneNode::ObjectMap &pmap =
node->getAttachedObjects();
int i;
for (i = 0; i < pmap.size(); i++) {
const Ogre::MovableObject *mobj = pmap[i];
const Ogre::String &pname = mobj->getName();
ImGui::Text("Name: %s", pname.c_str());
}
}
std::vector<Ogre::String> glb_names;
void init_glb_list()
{
int i;
const std::vector<Ogre::String> &groups =
Ogre::ResourceGroupManager::getSingleton()
.getResourceGroups();
for (i = 0; i < groups.size(); i++) {
std::vector<Ogre::String> names =
*Ogre::ResourceGroupManager::getSingleton()
.findResourceNames(groups[i], "*.glb");
glb_names.insert(glb_names.end(), names.begin(),
names.end());
}
}
void buildings_editor();
void buttons_panel();
void preview(const Ogre::RenderTargetViewportEvent &evt);
float panel_width;
void initGui();
};
class App : public OgreBites::ApplicationContext {
std::unique_ptr<Ogre::Bullet::DynamicsWorld> mDynWorld;
std::unique_ptr<Ogre::Bullet::DebugDrawer> mDbgDraw;
Ogre::SceneNode *mCameraNode;
Ogre::SceneNode *mCameraPivot;
Ogre::SceneNode *mCameraGoal;
Ogre::Camera *mCamera;
Ogre::Real mPivotPitch;
Ogre::SceneManager *mScnMgr;
OgreBites::InputListenerChain mInput;
Ogre::Viewport *mViewport;
EditUI m_edit_ui;
TerrainSetup m_terrain;
Ogre::Light *mSun;
SkyBoxRenderer *sky;
// OgreBites::TrayManager *mTrayMgr;
class KeyboardListener : public OgreBites::InputListener,
public Ogre::FrameListener {
App *mApp;
public:
Ogre::Vector3 motion;
bool gui_active;
Ogre::Timer fps_timer;
bool fast;
KeyboardListener(App *app)
: OgreBites::InputListener()
, Ogre::FrameListener()
, mApp(app)
, gui_active(false)
, fast(false)
{
}
bool keyPressed(const OgreBites::KeyboardEvent &evt) override
{
if (gui_active)
return false;
if (evt.keysym.sym == OgreBites::SDLK_ESCAPE) {
gui_active = true;
// std::cout << "Escape!\n";
// Ogre::Root::getSingleton().queueEndRendering();
mApp->setWindowGrab(false);
}
if (evt.keysym.sym == 'w')
motion.z = -1.0f;
if (evt.keysym.sym == 's')
motion.z = 1.0f;
if (evt.keysym.sym == 'a')
motion.x = -1.0f;
if (evt.keysym.sym == 'd')
motion.x = 1.0f;
if (evt.keysym.sym == OgreBites::SDLK_LSHIFT)
fast = true;
// std::cout << "motion: " << motion << "\n";
return true;
}
bool keyReleased(const OgreBites::KeyboardEvent &evt) override
{
if (gui_active)
return false;
if (evt.keysym.sym == 'w' && motion.z < 0.0f)
motion.z = 0.0f;
if (evt.keysym.sym == 's' && motion.z > 0.0f)
motion.z = 0.0f;
if (evt.keysym.sym == 'a' && motion.x < 0.0f)
motion.x = 0.0f;
if (evt.keysym.sym == 'd' && motion.x > 0.0f)
motion.x = 0.0f;
if (evt.keysym.sym == OgreBites::SDLK_LSHIFT)
fast = false;
return true;
}
bool mouseMoved(const OgreBites::MouseMotionEvent &evt)
{
if (gui_active)
return false;
// update camera goal based on mouse movement
mApp->updateCameraGoal(-0.18f * evt.xrel,
-0.12f * evt.yrel, 0);
return true;
}
bool mouseWheelRolled(const OgreBites::MouseWheelEvent &evt)
{
if (gui_active)
return false;
// update camera goal based on mouse movement
mApp->updateCameraGoal(0, 0, -0.15f * evt.y);
return true;
}
void update(float delta)
{
return;
// float fade = (1.0f - delta) * 0.98f;
// motion *= fade;
}
void frameRendered(const Ogre::FrameEvent &evt) override
{
if (fps_timer.getMilliseconds() > 1000.0f) {
std::cout << "FPS: "
<< mApp->getRenderWindow()
->getStatistics()
.lastFPS
<< " ";
std::cout << "Draw calls: "
<< mApp->getRenderWindow()
->getStatistics()
.batchCount
<< " ";
fps_timer.reset();
std::cout << "Drops: "
<< mApp->getRenderWindow()
->getStatistics()
.vBlankMissCount
<< "\n";
fps_timer.reset();
}
update(evt.timeSinceLastFrame);
if (!gui_active) {
mApp->updateMotion(evt.timeSinceLastFrame);
mApp->updateCamera(evt.timeSinceLastFrame);
mApp->updateSun(evt.timeSinceLastFrame);
mApp->updateTerrain(evt.timeSinceLastFrame);
}
}
};
KeyboardListener mKbd;
public:
App()
: OgreBites::ApplicationContext("GuiTest")
, mKbd(this)
, m_edit_ui(this)
, mDynWorld(new Ogre::Bullet::DynamicsWorld(
Ogre::Vector3(0, -9.8, 0)))
, m_terrain(mDynWorld->getBtWorld())
{
}
virtual ~App()
{
}
void setup()
{
OgreBites::ApplicationContext::setup();
Ogre::Root *root = getRoot();
Ogre::SceneManager *scnMgr = root->createSceneManager();
mScnMgr = scnMgr;
Ogre::OverlaySystem *pOverlaySystem = getOverlaySystem();
mScnMgr->addRenderQueueListener(pOverlaySystem);
// mTrayMgr = new OgreBites::TrayManager("AppTrays",
// getRenderWindow());
mDbgDraw.reset(new Ogre::Bullet::DebugDrawer(
mScnMgr->getRootSceneNode(), mDynWorld->getBtWorld()));
}
void locateResources()
{
OgreBites::ApplicationContext::locateResources();
}
void initCamera()
{
mCameraNode = mScnMgr->getRootSceneNode()->createChildSceneNode(
"CameraNode");
mCameraNode->setPosition(0, 2, 3);
mCameraNode->lookAt(Ogre::Vector3(0, 1, -1),
Ogre::Node::TS_PARENT);
// create the camera
mCamera = mScnMgr->createCamera("fps_camera");
mCamera->setNearClipDistance(0.1f); // specific to this sample
mCamera->setAutoAspectRatio(true);
mCameraNode->attachObject(mCamera);
// and tell it to render into the main window
mViewport = getRenderWindow()->addViewport(mCamera);
mCameraPivot =
mScnMgr->getRootSceneNode()->createChildSceneNode(
"FPSCameraPivot");
mCameraGoal = mCameraPivot->createChildSceneNode(
"FPSCameraGoal", Ogre::Vector3(0, 2, 3));
mCameraNode->setPosition(mCameraPivot->getPosition() +
mCameraGoal->getPosition());
mCameraPivot->setFixedYawAxis(true);
mCameraGoal->setFixedYawAxis(true);
mCameraNode->setFixedYawAxis(true);
// our model is quite small, so reduce the clipping planes
mCamera->setNearClipDistance(0.1f);
mCamera->setFarClipDistance(700);
mPivotPitch = 0;
// mKeyDirection = Ogre::Vector3::ZERO;
// mVerticalVelocity = 0;
Ogre::ManualObject *mobj =
mScnMgr->createManualObject("cursorGen");
#if 0
Ogre::MaterialPtr mat =
Ogre::static_pointer_cast<Ogre::Material>(
Ogre::MaterialManager::getSingleton()
.createOrRetrieve("Debug/Red2",
"General")
.first);
mat->removeAllTechniques();
Ogre::Technique *tech = mat->createTechnique();
tech->setDiffuse(Ogre::ColourValue(1, 0, 0, 1));
tech->setName("Debug/S");
tech->setDepthCheckEnabled(false);
tech->setLightingEnabled(false);
mobj->begin(mat, Ogre::RenderOperation::OT_LINE_LIST);
#endif
mobj->begin("Debug/Red", Ogre::RenderOperation::OT_LINE_LIST);
mobj->position(0, 0, 0);
mobj->colour(Ogre::ColourValue(1, 0, 0));
mobj->position(0, 2, 0);
mobj->colour(Ogre::ColourValue(1, 0, 0));
mobj->position(-1, 1, 0);
mobj->colour(Ogre::ColourValue(1, 0, 0));
mobj->position(1, 1, 0);
mobj->colour(Ogre::ColourValue(1, 0, 0));
mobj->index(0);
mobj->index(1);
mobj->index(2);
mobj->index(3);
mobj->end();
mCameraPivot->attachObject(mobj);
}
Ogre::SceneManager *getSceneManager()
{
return mScnMgr;
}
void updateMotion(float delta)
{
if (delta == 0.0f)
return;
Ogre::Vector3 move(mCameraNode->getOrientation().zAxis() *
mKbd.motion.z);
move += Ogre::Vector3(mCameraNode->getOrientation().xAxis() *
mKbd.motion.x);
move.y = 0.0f;
float speed = 15.0f;
if (mKbd.fast)
speed = 40.0f;
Ogre::Vector3 opos = mCameraPivot->getPosition();
Ogre::Vector3 pos =
mCameraPivot->getPosition() + move * speed * delta;
float y = m_terrain.get_height(pos);
pos.y = y;
mCameraPivot->translate(pos - opos);
// mKbd.motion = Ogre::Vector3(0, 0, 0);
// if (move.squaredLength() > 0)
// std::cout << move << "\n";
}
void updateCamera(Ogre::Real delta)
{
if (delta == 0.0f)
return;
// place the camera pivot roughly at the character's shoulder
// mCameraPivot->setPosition(mBodyNode->getPosition() +
// Ogre::Vector3::UNIT_Y * CAM_HEIGHT);
// move the camera smoothly to the goal
Ogre::Vector3 goalOffset = mCameraGoal->_getDerivedPosition() -
mCameraNode->getPosition();
float l = goalOffset.squaredLength();
Ogre::Vector3 v = goalOffset * 10.0 * delta;
if (v.squaredLength() > l * 0.5f - delta)
v = goalOffset * delta;
mCameraNode->translate(v);
// mCameraNode->translate(goalOffset);
// always look at the pivot
mCameraNode->lookAt(mCameraPivot->_getDerivedPosition(),
Ogre::Node::TS_PARENT);
}
void updateCameraGoal(Ogre::Real deltaYaw, Ogre::Real deltaPitch,
Ogre::Real deltaZoom)
{
mCameraPivot->yaw(Ogre::Degree(deltaYaw),
Ogre::Node::TS_PARENT);
if (!(mPivotPitch + deltaPitch > 25 && deltaPitch > 0) &&
!(mPivotPitch + deltaPitch < -60 && deltaPitch < 0)) {
mCameraPivot->pitch(Ogre::Degree(deltaPitch),
Ogre::Node::TS_LOCAL);
mPivotPitch += deltaPitch;
}
Ogre::Real dist = mCameraGoal->_getDerivedPosition().distance(
mCameraPivot->_getDerivedPosition());
Ogre::Real distChange = deltaZoom * dist * 0.5f;
if (distChange > 0 && dist + distChange > 30)
distChange *= 0.3f;
if (distChange < 0 && dist + distChange < 5)
distChange *= 0.2f;
// bound the zoom
if (!(dist + distChange < 3 && distChange < 0) &&
!(dist + distChange > 40 && distChange > 0))
mCameraGoal->translate(0, 0, distChange,
Ogre::Node::TS_LOCAL);
Ogre::Vector3 mh = mCameraGoal->_getDerivedPosition();
float h = m_terrain.get_height(mh);
if (h + 3 > mh.y)
mCameraGoal->translate(0, 10.0f * deltaZoom, distChange,
Ogre::Node::TS_LOCAL);
}
Ogre::SceneNode *mSunGoal;
Ogre::SceneNode *mSunNode;
Ogre::SceneNode *mSunTarget;
Ogre::Timer mSunUpdate;
void createSun()
{
Ogre::Light *light = mScnMgr->createLight("Sun");
mSunNode = mScnMgr->getRootSceneNode()->createChildSceneNode(
"SunPivot");
mSunGoal = mScnMgr->getRootSceneNode()->createChildSceneNode(
"SunGoal");
mSunTarget = mSunGoal->createChildSceneNode(
"SunGoalTarget",
Ogre::Vector3(100.0f, -400.0f, -400.0f),
Ogre::Quaternion::IDENTITY);
// mSunNode->setAutoTracking(true, sun_target);
// lightNode->setPosition(0, 10, 15);
mSunNode->attachObject(light);
light->setType(Ogre::Light::LT_DIRECTIONAL);
light->setDiffuseColour(Ogre::ColourValue::White);
light->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4));
mSunNode->setDirection(Ogre::Vector3(100.0f, -400.0f, -400.f));
mSun = light;
}
void updateSun(float delta)
{
static const float sun_speed = 1.0f;
float uangle = M_PI * 2.0f / 24.0f / 60.0f;
mSunNode->pitch(Ogre::Radian(uangle) * sun_speed * delta);
if (mSunUpdate.getMilliseconds() > 1000) {
Ogre::TerrainGlobalOptions::getSingleton()
.setCompositeMapAmbient(
mScnMgr->getAmbientLight());
Ogre::TerrainGlobalOptions::getSingleton()
.setCompositeMapDiffuse(
mSun->getDiffuseColour());
Ogre::TerrainGlobalOptions::getSingleton()
.setLightMapDirection(
mSun->getDerivedDirection());
std::cout << "sun pitch: "
<< mSunNode->getOrientation().getPitch()
<< "\n";
mSunUpdate.reset();
}
if (mSunNode->getOrientation().getPitch().valueRadians() > 0)
mScnMgr->setAmbientLight(
Ogre::ColourValue(0.0f, 0.0f, 0.2f, 1.0f));
else
mScnMgr->setAmbientLight(
Ogre::ColourValue(0.2f, 0.2f, 0.2f, 1.0f));
}
Ogre::Timer mTerrainUpd;
void updateTerrain(float delta)
{
mDbgDraw->update();
#if 0
if (mTerrainUpd.getMilliseconds() > 1000) {
m_terrain.create_colliders();
mTerrainUpd.reset();
}
#endif
}
void createContent()
{
m_edit_ui.init_glb_list();
m_edit_ui.initGui();
createSun();
mInput = OgreBites::InputListenerChain(
{ getImGuiInputListener(), &mKbd });
addInputListener(&mInput);
getRoot()->addFrameListener(&mKbd);
// mTrayMgr->showCursor();
// OgreBites::TrayManager *mTrayMgr = new OgreBites::TrayManager(
// "InterfaceName", getRenderWindow());
// mScnMgr->setSkyBox(true, "Skybox/Dynamic", 490);
// /* mCamera->getCameraToViewportRay(left, top); */
sky = new SkyBoxRenderer(getSceneManager());
bool drawFirst = true;
uint8_t renderQueue = drawFirst ?
Ogre::RENDER_QUEUE_SKIES_EARLY :
Ogre::RENDER_QUEUE_SKIES_LATE;
sky->create("Skybox/Dynamic", 490, renderQueue,
Ogre::Quaternion::IDENTITY,
Ogre::ResourceGroupManager::
AUTODETECT_RESOURCE_GROUP_NAME);
sky->setEnabled(true);
Ogre::MaterialPtr m =
Ogre::MaterialManager::getSingleton().getByName(
"Skybox/Dynamic", "General");
OgreAssert(m, "Sky box material not found.");
m->load();
Ogre::MeshManager::getSingleton().createPlane(
"water",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::Plane(Ogre::Vector3::UNIT_Y, 0), 100, 100, 100,
100, true, 1, 100, 100, Ogre::Vector3::UNIT_Z);
// create a floor entity, give it a material, and place it at the origin
Ogre::Entity *water = mScnMgr->createEntity("Water", "water");
water->setMaterialName("Water");
mScnMgr->getRootSceneNode()
->createChildSceneNode("Water")
->attachObject(water);
}
void create_entity_node(const Ogre::String &name, int key)
{
Ogre::Entity *ent = mScnMgr->createEntity(name);
Ogre::SceneNode *pnode =
mScnMgr->getRootSceneNode()->createChildSceneNode(
"ent:" + name +
Ogre::StringConverter::toString(key),
mCameraPivot->getPosition(),
mCameraPivot->getOrientation());
pnode->attachObject(ent);
Ogre::Quaternion q = pnode->getOrientation();
Ogre::Radian yaw = q.getYaw();
Ogre::Quaternion nq(yaw, Ogre::Vector3(0, 1, 0));
pnode->setOrientation(nq);
mKbd.gui_active = false;
setWindowGrab(true);
}
bool get_gui_active()
{
return mKbd.gui_active;
}
void set_gui_active(bool active)
{
mKbd.gui_active = active;
}
Ogre::Camera *getCamera()
{
return mCamera;
}
void setupTerrain()
{
m_terrain.setupTerrain(mCamera, mSun, mDynWorld.get(),
mDbgDraw.get());
}
};
void EditUI::buildings_editor()
{
int i;
ImVec2 size = ImGui::GetMainViewport()->Size;
float window_width = size.x * 0.2f;
if (window_width > panel_width)
window_width = panel_width;
float window_height = size.y * 0.5 - 20;
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(window_width, window_height),
ImGuiCond_Always);
ImGui::Begin("Droppings...");
for (i = 0; i < glb_names.size(); i++) {
Ogre::String id_button = "Create entity: " + glb_names[i] +
"##ent:" + glb_names[i];
if (ImGui::Button(id_button.c_str())) {
m_app->create_entity_node(glb_names[i], i);
}
}
ImGui::End();
}
void EditUI::buttons_panel()
{
ImVec2 size = ImGui::GetMainViewport()->Size;
float window_width = size.x * 0.2f;
if (window_width > panel_width)
window_width = panel_width;
float window_height = size.y * 0.5f - 20;
ImGui::SetNextWindowPos(ImVec2(0, size.y * 0.5f + 20),
ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(window_width, window_height),
ImGuiCond_Always);
ImGui::Begin("Dumb and Stupid");
if (!m_app->get_gui_active())
m_app->setWindowGrab(true);
if (ImGui::Button("Shitty Quit button"))
Ogre::Root::getSingleton().queueEndRendering();
if (ImGui::Button("Chick-chick")) {
m_app->set_gui_active(false);
m_app->setWindowGrab(true);
}
ImGui::Text("We do stoopid...");
ImGui::End();
}
void EditUI::preview(const Ogre::RenderTargetViewportEvent &evt)
{
int i;
Ogre::ImGuiOverlay::NewFrame();
if (m_app->get_gui_active()) {
buttons_panel();
buildings_editor();
ImVec2 size = ImGui::GetMainViewport()->Size;
float window_width = size.x * 0.2f;
if (window_width > panel_width)
window_width = panel_width;
float window_height = size.y * 0.5f - 20;
ImGui::SetNextWindowPos(ImVec2(size.x - window_width,
size.y * 0.5f + 20),
ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(window_width, window_height),
ImGuiCond_Always);
// ImGui::Begin("Dumb and Stupid", &mKbd.gui_active);
ImGui::Begin("Panel...");
std::deque<Ogre::SceneNode *> tree_input_queue,
tree_output_queue;
std::vector<Ogre::SceneNode *> tree_list;
tree_input_queue.push_back(mScnMgr->getRootSceneNode());
tree_input_queue.push_back(nullptr);
std::set<Ogre::SceneNode *> visited;
while (true) {
int new_nodes_count = 0;
while (!tree_input_queue.empty()) {
int child;
Ogre::SceneNode *item =
tree_input_queue.front();
tree_input_queue.pop_front();
if (item && visited.find(item) ==
visited.end()) { // new node
new_nodes_count++;
tree_output_queue.push_back(item);
visited.insert(item);
const Ogre::Node::ChildNodeMap
&children = item->getChildren();
for (child = 0; child < children.size();
child++) {
tree_output_queue.push_back(
static_cast<Ogre::SceneNode
*>(
children[child]));
tree_output_queue.push_back(
nullptr);
}
} else
tree_output_queue.push_back(item);
}
if (new_nodes_count == 0)
break;
tree_input_queue = tree_output_queue;
tree_output_queue.clear();
}
tree_list.insert(tree_list.begin(), tree_output_queue.begin(),
tree_output_queue.end());
int count = 0;
int depth = 0;
std::vector<int> check_depth;
int max_depth = 0;
check_depth.push_back(0);
for (count = 0; count < tree_list.size(); count++) {
int t;
Ogre::SceneNode *node = tree_list[count];
if (node && max_depth >= depth) {
Ogre::String name = node->getName();
if (name.length() == 0) {
name = "Node #" +
Ogre::StringConverter::toString(
count);
}
if (ImGui::TreeNode(name.c_str())) {
check_depth.push_back(max_depth);
max_depth++;
ImGui::Text(
"%s",
(name + "##caption").c_str());
position_editor(node);
ImGui::Separator();
orientation_editor(node);
ImGui::Separator();
ImGui::Text("Attachments");
attachments_editor(node);
}
} else if (!node && max_depth >= depth) {
max_depth = check_depth.back();
check_depth.pop_back();
ImGui::TreePop();
}
if (tree_list[count])
depth++;
else
depth--;
}
ImGui::Spacing();
ImGui::End();
}
}
void EditUI::initGui()
{
mScnMgr = m_app->getSceneManager();
float vpScale = m_app->getDisplayDPI() / 96 *
(float)m_app->getRenderWindow()->getWidth() / 1280;
panel_width =
380.0f * (float)m_app->getRenderWindow()->getWidth() / 1280;
Ogre::OverlayManager::getSingleton().setPixelRatio(vpScale);
mGuiOverlay = m_app->initialiseImGui();
// float vpScale =
// Ogre::OverlayManager::getSingleton().getPixelRatio();
ImGui::GetIO().FontGlobalScale = std::round(vpScale);
mGuiOverlay->setZOrder(300);
mGuiOverlay->show();
m_app->getRenderWindow()->addListener(this);
}
int main()
{
App ctx;
ctx.initApp();
// ctx.runRenderingSettingsDialog();
// get a pointer to the already created root
Ogre::Root *root = ctx.getRoot();
Ogre::SceneManager *scnMgr = ctx.getSceneManager();
// register our scene with the RTSS
Ogre::RTShader::ShaderGenerator *shadergen =
Ogre::RTShader::ShaderGenerator::getSingletonPtr();
shadergen->addSceneManager(scnMgr);
ctx.setWindowGrab(true);
ctx.initCamera();
ctx.createContent();
ctx.setupTerrain();
// register for input events
// KeyHandler keyHandler;
// ctx.addInputListener(&keyHandler);
ctx.getRoot()->startRendering();
ctx.setWindowGrab(false);
ctx.closeApp();
return 0;
}

984
Procedural.cpp Normal file
View File

@@ -0,0 +1,984 @@
// This file is part of the OGRE project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at https://www.ogre3d.org/licensing.
// SPDX-License-Identifier: MIT
//
#include <iostream>
#include "Ogre.h"
#include "OgreApplicationContext.h"
#include "Bullet/OgreBullet.h"
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
#include "btKinematicCharacterController.h"
#include "LinearMath/btTransform.h"
#include "OgrePageManager.h"
#include "Procedural.h"
#define CAM_HEIGHT 1.6f // height of camera above character's center of mass
#define RUN_SPEED 17 // character running speed in units per second
#define TURN_SPEED 500.0f // character turning in degrees per second
#define ANIM_FADE_SPEED \
7.5f // animation crossfade speed in % of full weight per second
using Real = Ogre::Real;
using Math = Ogre::Math;
class WorldData {
std::unique_ptr<Ogre::Bullet::DynamicsWorld> mDynWorld;
std::unique_ptr<Ogre::Bullet::DebugDrawer> mDbgDraw;
std::unique_ptr<Ogre::Root> mRoot;
std::unique_ptr<Ogre::SceneManager> mScnMgr;
std::unique_ptr<btDynamicsWorld> mbtWorld;
std::unique_ptr<Ogre::PageManager> mPageManager;
Ogre::PagedWorld *mPagedWorld;
private:
static WorldData *singleton;
class DummyPageProvider : public Ogre::PageProvider {
public:
bool
prepareProceduralPage(Ogre::Page *page,
Ogre::PagedWorldSection *section) override
{
return true;
}
bool
loadProceduralPage(Ogre::Page *page,
Ogre::PagedWorldSection *section) override
{
return true;
}
bool
unloadProceduralPage(Ogre::Page *page,
Ogre::PagedWorldSection *section) override
{
return true;
}
bool unprepareProceduralPage(
Ogre::Page *page,
Ogre::PagedWorldSection *section) override
{
return true;
}
};
DummyPageProvider mDummyPageProvider;
WorldData(Ogre::Root *root, Ogre::SceneManager *scnMgr)
: mDynWorld(new Ogre::Bullet::DynamicsWorld(
Ogre::Vector3(0, -9.8, 0)))
, mDbgDraw(new Ogre::Bullet::DebugDrawer(
scnMgr->getRootSceneNode(), mDynWorld->getBtWorld()))
, mRoot(root)
, mScnMgr(scnMgr)
, mbtWorld(mDynWorld->getBtWorld())
, mPageManager(nullptr)
, mPagedWorld(nullptr)
{
}
public:
static void init(Ogre::Root *root, Ogre::SceneManager *scnMgr)
{
singleton = new WorldData(root, scnMgr);
}
static WorldData *get_singleton()
{
return singleton;
}
static void cleanup()
{
if (singleton)
delete singleton;
singleton = nullptr;
}
Ogre::SceneManager *getSceneManager()
{
return mScnMgr.get();
}
Ogre::Root *getRoot()
{
return mRoot.get();
}
void createTrimesh(Ogre::Entity *entity)
{
}
btPairCachingGhostObject *addGhostObject(Ogre::Entity *ent,
btCollisionShape *shape,
int group = 1,
int mask = 0xFFFF)
{
btDynamicsWorld *world = mDynWorld->getBtWorld();
Ogre::SceneNode *node = ent->getParentSceneNode();
btPairCachingGhostObject *ghost =
new btPairCachingGhostObject();
ghost->setCollisionShape(shape);
ghost->setCollisionFlags(
ghost->getCollisionFlags() |
btCollisionObject::CF_NO_CONTACT_RESPONSE |
btCollisionObject::CF_CHARACTER_OBJECT);
getWorld()->attachCollisionObject(ghost, ent, group, mask);
#if 0
getBtWorld()
->getBroadphase()->getOverlappingPairCache()
->setInternalGhostPairCallback(new btGhostPairCallback());
ghost->setUserPointer(new EntityCollisionListener{ent, nullptr});
#endif
return ghost;
}
btRigidBody *addRigidBody(float mass, Ogre::Entity *ent,
Ogre::Bullet::ColliderType ct, int group = 1,
int mask = 0xFFFF)
{
btDynamicsWorld *world = mDynWorld->getBtWorld();
Ogre::SceneNode *node = ent->getParentSceneNode();
Ogre::Bullet::RigidBodyState *state =
new Ogre::Bullet::RigidBodyState(node);
btCollisionShape *cs;
btCollisionShape *shape;
btVector3 inertia(0, 0, 0);
switch (ct) {
case Ogre::Bullet::CT_TRIMESH: {
cs = Ogre::Bullet::createTrimeshCollider(ent);
if (mass != 0)
cs->calculateLocalInertia(mass, inertia);
} break;
case Ogre::Bullet::CT_CAPSULE: {
cs = new btCompoundShape();
btScalar height = 1.0f;
btScalar radius = 0.3f;
shape = new btCapsuleShape(radius,
2 * height - 2 * radius);
btTransform transform;
transform.setIdentity();
transform.setOrigin(btVector3(0, 1, 0));
static_cast<btCompoundShape *>(cs)->addChildShape(
transform, shape);
btScalar masses[1] = { mass };
btTransform principal;
static_cast<btCompoundShape *>(cs)
->calculatePrincipalAxisTransform(
masses, principal, inertia);
} break;
default:
assert(false);
break;
}
btRigidBody *body = new btRigidBody(mass, state, cs, inertia);
getWorld()->attachRigidBody(body, ent, nullptr, group, mask);
#if 0
body->setUserPointer(new EntityCollisionListener{ent, nullptr});
// btRigidBody *body = mDynWorld->addRigidBody(0, ent, Ogre::Bullet::CT_TRIMESH);
#endif
return body;
}
btRigidBody *addKinematicRigidBody(float mass, Ogre::Entity *ent,
Ogre::Bullet::ColliderType ct,
int group = 1, int mask = 0xFFFF)
{
return mDynWorld->addKinematicRigidBody(ent, ct, group, mask);
}
btDynamicsWorld *getBtWorld()
{
return mDynWorld->getBtWorld();
}
Ogre::Bullet::DynamicsWorld *getWorld()
{
return mDynWorld.get();
}
void update(float delta)
{
WorldData::get_singleton()->getBtWorld()->stepSimulation(delta,
10);
mDbgDraw->update();
}
void initPagedWorld(Ogre::Camera *camera)
{
mPageManager = std::make_unique<Ogre::PageManager>();
mPageManager->setPageProvider(&mDummyPageProvider);
mPageManager->addCamera(camera);
mPageManager->setDebugDisplayLevel(0);
mPagedWorld = mPageManager->createWorld();
}
};
WorldData *WorldData::singleton = nullptr;
class MainWorld : public Ogre::FrameListener {
btRigidBody *mFloorBody;
public:
void setup()
{
// mScnMgr = scnMgr;
// mDynWorld.reset(new Ogre::Bullet::DynamicsWorld(Ogre::Vector3(0, -9.8, 0)));
// mDbgDraw.reset(new Ogre::Bullet::DebugDrawer(mScnMgr->getRootSceneNode(), mDynWorld->getBtWorld()));
Ogre::MeshManager::getSingleton().createPlane(
"floor",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::Plane(Ogre::Vector3::UNIT_Y, 0), 100, 100, 10, 10,
true, 1, 10, 10, Ogre::Vector3::UNIT_Z);
// create a floor entity, give it a material, and place it at the origin
Ogre::SceneManager *scnMgr =
WorldData::get_singleton()->getSceneManager();
Ogre::Entity *floor = scnMgr->createEntity("Floor", "floor");
scnMgr->getRootSceneNode()->attachObject(floor);
mFloorBody = WorldData::get_singleton()->addRigidBody(
0, floor, Ogre::Bullet::CT_TRIMESH);
}
btRigidBody *addCharacter(Ogre::Entity *ent, float mass)
{
return WorldData::get_singleton()->addKinematicRigidBody(
mass, ent, Ogre::Bullet::CT_COMPOUND);
}
bool frameStarted(const Ogre::FrameEvent &evt) override;
};
class CharacterController : public OgreBites::InputListener,
Ogre::FrameListener {
enum AnimID {
ANIM_IDLE = 0,
ANIM_WALK,
ANIM_RUN,
NUM_ANIMS,
ANIM_NONE = NUM_ANIMS
};
Ogre::Node *mRootBone;
Ogre::SceneNode *mCameraNode;
Ogre::Camera *mCamera;
Ogre::SceneManager *mScnMgr;
Ogre::SceneNode *mCameraPivot;
Ogre::SceneNode *mCameraGoal, *mBodyNode;
Ogre::Entity *mBodyEnt;
Real mPivotPitch;
Real mVerticalVelocity;
Ogre::Vector3
mKeyDirection; // player's local intended direction based on WASD keys
Ogre::Vector3 mGoalDirection; // actual intended direction in world-space
Ogre::AnimationState *mAnims[NUM_ANIMS]; // master animation list
Ogre::Animation *mSkelAnimations[NUM_ANIMS];
Ogre::NodeAnimationTrack *mHipsTracks[NUM_ANIMS];
Ogre::NodeAnimationTrack *mRootTracks[NUM_ANIMS];
AnimID mAnimID;
bool mFadingIn[NUM_ANIMS]; // which animations are fading in
bool mFadingOut[NUM_ANIMS]; // which animations are fading out
Real mTimer; // general timer to see how long animations have been playing
Ogre::Skeleton *mSkeleton;
bool mRunning;
MainWorld *world;
Ogre::Vector3 rootMotion;
Ogre::Quaternion rootRotation;
// btRigidBody *mRigidBody;
btCompoundShape *mCollisionShape;
btPairCachingGhostObject *mGhostObject;
btKinematicCharacterController *mController;
public:
CharacterController(Ogre::SceneNode *camNode, Ogre::Camera *cam,
Ogre::SceneManager *scnMgr, MainWorld *world);
~CharacterController();
private:
void setupBody();
void setupCamera();
void setupAnimations();
public:
bool keyPressed(const OgreBites::KeyboardEvent &evt) override;
bool keyReleased(const OgreBites::KeyboardEvent &evt) override;
bool mouseMoved(const OgreBites::MouseMotionEvent &evt) override;
bool mouseWheelRolled(const OgreBites::MouseWheelEvent &evt) override;
bool mousePressed(const OgreBites::MouseButtonEvent &evt) override;
bool frameStarted(const Ogre::FrameEvent &evt) override;
void frameRendered(const Ogre::FrameEvent &evt) override;
private:
void updateBody(Ogre::Real deltaTime);
void updateAnimations(Real deltaTime);
void updateRootMotion(Real deltaTime);
void fadeAnimations(Real deltaTime);
void updateCamera(Real deltaTime);
void updateCameraGoal(Real deltaYaw, Real deltaPitch, Real deltaZoom);
void setAnimation(AnimID id, bool reset = false);
#if 0
struct testMotionResult {
};
struct recoverResult {
};
bool bodyTestMotion(btRigidBody *body,
const btTransform &from,
const btVector3 &motion, bool infinite_inertia,
textMotionResult *result,
bool excludeRaycastShapes,
const std::set<btCollisionObject *> &exclude);
bool recoverFromPenetration(btRigidBody *body,
const btTransform &body_position,
btScalar recover_movement_scale,
bool infinite_inertia,
btVector3 &delta_recover_movement,
recoverResult *recover_result,
const std::set<btCollisionObject *> &exclude);
#endif
inline btQuaternion convert(const Ogre::Quaternion &q)
{
return btQuaternion(q.x, q.y, q.z, q.w);
}
inline btVector3 convert(const Ogre::Vector3 &v)
{
return btVector3(v.x, v.y, v.z);
}
inline btTransform convert(const Ogre::Quaternion &q,
const Ogre::Vector3 &v)
{
btQuaternion mq = convert(q);
btVector3 mv = convert(v);
return btTransform(mq, mv);
}
inline Ogre::Quaternion convert(const btQuaternion &q)
{
return Ogre::Quaternion(q.w(), q.x(), q.y(), q.z());
}
inline Ogre::Vector3 convert(const btVector3 &v)
{
return Ogre::Vector3(v.x(), v.y(), v.z());
}
inline void convert(const btTransform &from, Ogre::Quaternion &q,
Ogre::Vector3 &v)
{
q = convert(from.getRotation());
v = convert(from.getOrigin());
}
};
CharacterController::CharacterController(Ogre::SceneNode *camNode,
Ogre::Camera *cam,
Ogre::SceneManager *scnMgr,
MainWorld *world)
: mCameraNode(camNode)
, mCamera(cam)
, mScnMgr(scnMgr)
, mPivotPitch(0)
, mVerticalVelocity(0)
, mAnimID(ANIM_NONE)
, mRunning(false)
, world(world)
, mCollisionShape(nullptr)
, mGhostObject(nullptr)
, mController(nullptr)
{
setupBody();
setupCamera();
setupAnimations();
}
CharacterController::~CharacterController()
{
}
void CharacterController::setupBody()
{
mBodyEnt = mScnMgr->createEntity("normal-male.glb");
mBodyNode = mScnMgr->getRootSceneNode()->createChildSceneNode();
mBodyNode->attachObject(mBodyEnt);
mSkeleton = mBodyEnt->getSkeleton();
// mRigidBody = world->addCharacter(mBodyEnt, 0);
// mCollisionShape = static_cast<btCompoundShape *>(mRigidBody->getCollisionShape());
mGhostObject = new btPairCachingGhostObject();
mCollisionShape = new btCompoundShape;
mGhostObject->setCollisionShape(mCollisionShape);
{
btVector3 inertia(0, 0, 0);
// mCollisionShape = new btCompoundShape();
btScalar height = 1.0f;
btScalar radius = 0.3f;
btCapsuleShape *shape =
new btCapsuleShape(radius, 2 * height - 2 * radius);
btTransform transform;
transform.setIdentity();
transform.setOrigin(btVector3(0, 1, 0));
static_cast<btCompoundShape *>(mCollisionShape)
->addChildShape(transform, shape);
btScalar masses[1] = { 0 };
btTransform principal;
static_cast<btCompoundShape *>(mCollisionShape)
->calculatePrincipalAxisTransform(masses, principal,
inertia);
}
mGhostObject->setCollisionFlags(
btCollisionObject::CF_KINEMATIC_OBJECT |
btCollisionObject::CF_NO_CONTACT_RESPONSE);
mGhostObject->setActivationState(DISABLE_DEACTIVATION);
Ogre::Bullet::KinematicMotionSimple *controller =
new Ogre::Bullet::KinematicMotionSimple(mGhostObject,
mBodyNode);
WorldData::get_singleton()->getWorld()->attachCollisionObject(
mGhostObject, mBodyEnt, btBroadphaseProxy::AllFilter,
btBroadphaseProxy::AllFilter);
WorldData::get_singleton()->getBtWorld()->addAction(controller);
assert(mCollisionShape);
#if 0
if (mRigidBody->getMass() == 0) {
#if 0
mRigidBody->setCollisionFlags(mRigidBody->getCollisionFlags()
| btCollisionObject::CF_KINEMATIC_OBJECT
| btCollisionObject::CF_NO_CONTACT_RESPONSE
);
#endif
#if 0
mGhostObject->setWorldTransform(mRigidBody->getWorldTransform());
WorldData::get_singleton()->getBtWorld()
->getBroadphase()->getOverlappingPairCache()
->setInternalGhostPairCallback(new btGhostPairCallback());
#endif
}
#endif
#if 0
mRigidBody->setActivationState(DISABLE_DEACTIVATION);
#endif
#if 0
{
Ogre::Entity *e2 = mScnMgr->createEntity("normal-male.glb");
Ogre::SceneNode *e2node = mScnMgr->getRootSceneNode()->createChildSceneNode();
e2node->attachObject(e2);
mGhostObject = WorldData::get_singleton()->addGhostObject(e2, mCollisionShape);
mController = new btKinematicCharacterController(mGhostObject, mCollisionShape, 0.5f);
WorldData::get_singleton()->getBtWorld()->addAction(mController);
}
#endif
assert(mSkeleton->hasBone("Root"));
mRootBone = mSkeleton->getBone("Root");
assert(mRootBone);
}
void CharacterController::setupCamera()
{
// create a pivot at roughly the character's shoulder
mCameraPivot = mScnMgr->getRootSceneNode()->createChildSceneNode();
mCameraGoal =
mCameraPivot->createChildSceneNode(Ogre::Vector3(0, 2, 3));
mCameraNode->setPosition(mCameraPivot->getPosition() +
mCameraGoal->getPosition());
mCameraPivot->setFixedYawAxis(true);
mCameraGoal->setFixedYawAxis(true);
mCameraNode->setFixedYawAxis(true);
// our model is quite small, so reduce the clipping planes
mCamera->setNearClipDistance(0.1f);
mCamera->setFarClipDistance(700);
mPivotPitch = 0;
mKeyDirection = Ogre::Vector3::ZERO;
mVerticalVelocity = 0;
}
void CharacterController::setupAnimations()
{
int i, j;
mSkeleton->setBlendMode(Ogre::ANIMBLEND_CUMULATIVE);
Ogre::String animNames[NUM_ANIMS] = { "idle", "walking", "running" };
for (i = 0; i < NUM_ANIMS; i++) {
mAnims[i] = mBodyEnt->getAnimationState(animNames[i]);
mAnims[i]->setLoop(true);
mAnims[i]->setEnabled(true);
mAnims[i]->setWeight(0);
mFadingIn[i] = false;
mFadingOut[i] = false;
mSkelAnimations[i] = mSkeleton->getAnimation(animNames[i]);
for (const auto &it : mSkelAnimations[i]->_getNodeTrackList()) {
Ogre::NodeAnimationTrack *track = it.second;
Ogre::String trackName =
track->getAssociatedNode()->getName();
if (trackName == "mixamorig:Hips") {
mHipsTracks[i] = track;
} else if (trackName == "Root") {
mRootTracks[i] = track;
// mRootTracks[i]->removeAllKeyFrames();
}
}
Ogre::Vector3 delta = Ogre::Vector3::ZERO;
Ogre::Vector3 motion = Ogre::Vector3::ZERO;
for (j = 0; j < mRootTracks[i]->getNumKeyFrames(); j++) {
Ogre::Vector3 trans = mRootTracks[i]
->getNodeKeyFrame(j)
->getTranslate();
if (j == 0)
delta = trans;
else
delta = trans - motion;
mRootTracks[i]->getNodeKeyFrame(j)->setTranslate(delta);
motion = trans;
}
}
#if 0
for(i = 0; i < NUM_ANIMS - 1; i++) {
// need to cache
int j;
Ogre::String animName = mAnims[i]->getAnimationName();
Ogre::Animation *anim = mSkeleton->getAnimation(animName);
Ogre::NodeAnimationTrack *hips_track = nullptr, *root_track = nullptr;
Ogre::Node *root_node = nullptr;
for (const auto& it : anim->_getNodeTrackList()) {
Ogre::NodeAnimationTrack* track = it.second;
Ogre::String trackName = track->getAssociatedNode()->getName();
std::cout << animName << " track: " << trackName << "\n";
if (trackName == "mixamorig:Hips")
hips_track = track;
else if (trackName == "Root") {
root_track = track;
root_node = track->getAssociatedNode();
}
}
assert(false);
root_track->removeAllKeyFrames();
std::cout << hips_track << " " << root_track << "\n";
std::cout << hips_track->getNumKeyFrames() << " " << root_track->getNumKeyFrames() << "\n";
assert(hips_track && root_track);
Ogre::Vector3 delta = Ogre::Vector3::ZERO;
for(j = 0; j < hips_track->getNumKeyFrames(); j++) {
float timePos = hips_track->getNodeKeyFrame(j)->getTime();
Ogre::Vector3 trans = hips_track->getNodeKeyFrame(j)->getTranslate();
Ogre::Vector3 hips_trans(0, 0, 0);
Ogre::Vector3 root_trans(0, 0, 0);
hips_track->getNodeKeyFrame(j)->setTranslate(hips_trans);
Ogre::TransformKeyFrame *nk = root_track->createNodeKeyFrame(timePos);
nk->setTranslate(root_trans - delta);
nk->setScale(Ogre::Vector3(1, 1, 1));
nk->setRotation(Ogre::Quaternion());
std::cout << animName << " delta: " << j << " " << timePos << " " << root_trans - delta << "\n";
delta = root_trans;
}
for(j = 0; j < root_track->getNumKeyFrames(); j++) {
float timePos = hips_track->getNodeKeyFrame(j)->getTime();
Ogre::Vector3 root_trans = hips_track->getNodeKeyFrame(j)->getTranslate();
std::cout << animName << " delta: root: " << j << " " << timePos << " " << root_trans << "\n";
}
}
// assert(false);
#endif
setAnimation(ANIM_IDLE);
}
bool CharacterController::keyPressed(const OgreBites::KeyboardEvent &evt)
{
OgreBites::Keycode key = evt.keysym.sym;
if (key == 'q' && (mAnimID == ANIM_IDLE)) {
/* ... */
mTimer = 0;
} else if (key == 'e') {
} else if (key == 'w')
mKeyDirection.z = -1;
else if (key == 'a')
mKeyDirection.x = -1;
else if (key == 's')
mKeyDirection.z = 1;
else if (key == 'd')
mKeyDirection.x = 1;
if (key == OgreBites::SDLK_LSHIFT)
mRunning = true;
if (!mKeyDirection.isZeroLength() && mAnimID == ANIM_IDLE) {
if (mRunning)
setAnimation(ANIM_RUN, true);
else
setAnimation(ANIM_WALK, true);
// std::cout << "Walking\n";
} else if (!mKeyDirection.isZeroLength() && mAnimID == ANIM_WALK &&
mRunning)
setAnimation(ANIM_RUN);
return true;
}
bool CharacterController::keyReleased(const OgreBites::KeyboardEvent &evt)
{
OgreBites::Keycode key = evt.keysym.sym;
if (key == 'w' && mKeyDirection.z == -1)
mKeyDirection.z = 0;
else if (key == 'a' && mKeyDirection.x == -1)
mKeyDirection.x = 0;
else if (key == 's' && mKeyDirection.z == 1)
mKeyDirection.z = 0;
else if (key == 'd' && mKeyDirection.x == 1)
mKeyDirection.x = 0;
if (key == OgreBites::SDLK_LSHIFT)
mRunning = false;
if (mKeyDirection.isZeroLength() &&
(mAnimID == ANIM_WALK || mAnimID == ANIM_RUN))
setAnimation(ANIM_IDLE);
else if (!mKeyDirection.isZeroLength() && mAnimID == ANIM_RUN &&
!mRunning)
setAnimation(ANIM_WALK);
return true;
}
bool CharacterController::mouseMoved(const OgreBites::MouseMotionEvent &evt)
{
// update camera goal based on mouse movement
updateCameraGoal(-0.18f * evt.xrel, -0.12f * evt.yrel, 0);
return true;
}
bool CharacterController::mouseWheelRolled(const OgreBites::MouseWheelEvent &evt)
{
// update camera goal based on mouse movement
updateCameraGoal(0, 0, -0.15f * evt.y);
return true;
}
bool CharacterController::mousePressed(const OgreBites::MouseButtonEvent &evt)
{
std::cout << "Mouse press\n";
return false;
}
void CharacterController::frameRendered(const Ogre::FrameEvent &evt)
{
updateBody(evt.timeSinceLastFrame);
updateAnimations(evt.timeSinceLastFrame);
updateCamera(evt.timeSinceLastFrame);
if (evt.timeSinceLastFrame > 0)
updateRootMotion(evt.timeSinceLastFrame);
}
bool CharacterController::frameStarted(const Ogre::FrameEvent &evt)
{
return true;
}
void CharacterController::updateCameraGoal(Real deltaYaw, Real deltaPitch,
Real deltaZoom)
{
mCameraPivot->yaw(Ogre::Degree(deltaYaw), Ogre::Node::TS_PARENT);
if (!(mPivotPitch + deltaPitch > 25 && deltaPitch > 0) &&
!(mPivotPitch + deltaPitch < -60 && deltaPitch < 0)) {
mCameraPivot->pitch(Ogre::Degree(deltaPitch),
Ogre::Node::TS_LOCAL);
mPivotPitch += deltaPitch;
}
Real dist = mCameraGoal->_getDerivedPosition().distance(
mCameraPivot->_getDerivedPosition());
Real distChange = deltaZoom * dist;
// bound the zoom
if (!(dist + distChange < 8 && distChange < 0) &&
!(dist + distChange > 25 && distChange > 0))
mCameraGoal->translate(0, 0, distChange, Ogre::Node::TS_LOCAL);
}
void CharacterController::updateBody(Real delta)
{
mGoalDirection = Ogre::Vector3::ZERO;
if (mKeyDirection != Ogre::Vector3::ZERO) {
// calculate actually goal direction in world based on player's key directions
mGoalDirection +=
mKeyDirection.z * mCameraNode->getOrientation().zAxis();
mGoalDirection +=
mKeyDirection.x * mCameraNode->getOrientation().xAxis();
mGoalDirection.y = 0;
mGoalDirection.normalise();
Ogre::Quaternion toGoal =
mBodyNode->getOrientation().zAxis().getRotationTo(
mGoalDirection);
// calculate how much the character has to turn to face goal direction
Real yawToGoal = toGoal.getYaw().valueDegrees();
// this is how much the character CAN turn this frame
Real yawAtSpeed =
yawToGoal / Math::Abs(yawToGoal) * delta * TURN_SPEED;
// reduce "turnability" if we're in midair
// if (mBaseAnimID == ANIM_JUMP_LOOP) yawAtSpeed *= 0.2f;
if (yawToGoal < 0)
yawToGoal = std::min<Real>(
0,
std::max<Real>(
yawToGoal,
yawAtSpeed)); //yawToGoal = Math::Clamp<Real>(yawToGoal, yawAtSpeed, 0);
else if (yawToGoal > 0)
yawToGoal = std::max<Real>(
0,
std::min<Real>(
yawToGoal,
yawAtSpeed)); //yawToGoal = Math::Clamp<Real>(yawToGoal, 0, yawAtSpeed);
mBodyNode->yaw(Ogre::Degree(yawToGoal));
// move in current body direction (not the goal direction)
// mBodyNode->translate(0, 0, delta * RUN_SPEED * mAnims[mAnimID]->getWeight(),
// Ogre::Node::TS_LOCAL);
#if 0
if (mBaseAnimID == ANIM_JUMP_LOOP)
{
// if we're jumping, add a vertical offset too, and apply gravity
mBodyNode->translate(0, mVerticalVelocity * deltaTime, 0, Node::TS_LOCAL);
mVerticalVelocity -= GRAVITY * deltaTime;
Vector3 pos = mBodyNode->getPosition();
if (pos.y <= CHAR_HEIGHT)
{
// if we've hit the ground, change to landing state
pos.y = CHAR_HEIGHT;
mBodyNode->setPosition(pos);
setBaseAnimation(ANIM_JUMP_END, true);
mTimer = 0;
}
}
#endif
}
}
void CharacterController::updateAnimations(Real delta)
{
int i, j, k;
Real animSpeed = 1;
mTimer += delta;
if (mAnimID != ANIM_NONE) {
if (mAnimID == ANIM_WALK)
mAnims[mAnimID]->addTime(delta * 1.0f);
else
mAnims[mAnimID]->addTime(delta * animSpeed);
}
fadeAnimations(delta);
}
void CharacterController::updateRootMotion(Real delta)
{
Ogre::Vector3 boneMotion = mRootBone->getPosition();
OgreAssert(delta > 0.0f, "Zero delta");
#if 0
Ogre::Vector3 motion = boneMotion - rootMotion;
if (motion.squaredLength() > 0.1f * 0.1f)
motion = Ogre::Vector3();
rootMotion = boneMotion;
#endif
#if 0
float mass = mRigidBody->getMass();
std::cout << "Root bone position: " << boneMotion << "\n";
std::cout << "body mass: " << mass << "\n";
#endif
/* Kinematic motion */
Ogre::Quaternion rot = mBodyNode->getOrientation();
Ogre::Vector3 gravity(0, -9.8, 0);
Ogre::Vector3 velocity = rot * boneMotion / delta;
velocity += gravity * delta;
Ogre::Vector3 rotMotion = velocity * delta;
btTransform from(convert(mBodyNode->getOrientation()),
convert(mBodyNode->getPosition()));
mBodyNode->setPosition(mBodyNode->getPosition() + rotMotion);
// WorldData::get_singleton()->getWorld()->testBodyMotion(mRigidBody, from, Ogre::Bullet::convert(rotMotion), true,
// nullptr, false, std::set<btCollisionObject *>());
}
void CharacterController::fadeAnimations(Real delta)
{
int i;
for (i = 0; i < NUM_ANIMS; i++) {
if (mFadingIn[i]) {
// slowly fade this animation in until it has full weight
Real newWeight = mAnims[i]->getWeight() +
delta * ANIM_FADE_SPEED;
mAnims[i]->setWeight(
Math::Clamp<Real>(newWeight, 0, 1));
if (newWeight >= 1)
mFadingIn[i] = false;
} else if (mFadingOut[i]) {
// slowly fade this animation out until it has no weight, and then disable it
Real newWeight = mAnims[i]->getWeight() -
delta * ANIM_FADE_SPEED;
mAnims[i]->setWeight(
Math::Clamp<Real>(newWeight, 0, 1));
if (newWeight <= 0) {
mAnims[i]->setEnabled(false);
mFadingOut[i] = false;
}
}
}
}
void CharacterController::updateCamera(Real delta)
{
// place the camera pivot roughly at the character's shoulder
mCameraPivot->setPosition(mBodyNode->getPosition() +
Ogre::Vector3::UNIT_Y * CAM_HEIGHT);
// move the camera smoothly to the goal
Ogre::Vector3 goalOffset =
mCameraGoal->_getDerivedPosition() - mCameraNode->getPosition();
mCameraNode->translate(goalOffset * delta * 9.0f);
// always look at the pivot
mCameraNode->lookAt(mCameraPivot->_getDerivedPosition(),
Ogre::Node::TS_PARENT);
}
void CharacterController::setAnimation(AnimID id, bool reset)
{
assert(id >= 0 && id < NUM_ANIMS);
if (mAnimID != ANIM_NONE) {
mFadingIn[mAnimID] = false;
mFadingOut[mAnimID] = true;
}
mAnimID = id;
if (id != ANIM_NONE) {
mAnims[id]->setEnabled(true);
mAnims[id]->setWeight(0);
mFadingOut[id] = false;
mFadingIn[id] = true;
if (reset)
mAnims[id]->setTimePosition(0);
}
}
#if 0
bool CharacterController::recoverFromPenetration(btRigidBody *body,
const btTransform &body_position,
btScalar recover_movement_scale,
bool infinite_inertia,
btVector3 &delta_recover_movement,
recoverResult *recover_result,
const std::set<btCollisionObject *> &exclude)
{
return false;
}
bool CharacterController::bodyTestMotion(btRigidBody *body,
const btTransform &from,
const btVector3 &motion, bool infinite_inertia,
textMotionResult *result,
bool excludeRaycastShapes,
std::set<btCollisionObject *> exclude)
{
int t;
btTransform body_transform;
btVector3 initial_recover_motion(0, 0, 0);
// phase one - depenetration
for (t = 0; t < RECOVERING_MOVEMENT_CYCLES; t++)
if (!recoverFromPenetration(body,
body_transform,
RECOVERING_MOVEMENT_SCALE,
infinite_inertia,
initial_recover_motion,
nullptr, exclude))
break;
return false;
}
#endif
class KeyHandler : public OgreBites::InputListener {
bool keyPressed(const OgreBites::KeyboardEvent &evt) override
{
if (evt.keysym.sym == OgreBites::SDLK_ESCAPE) {
Ogre::Root::getSingleton().queueEndRendering();
}
return true;
}
};
bool MainWorld::frameStarted(const Ogre::FrameEvent &evt)
{
WorldData::get_singleton()->update(evt.timeSinceLastFrame);
return true;
}
class App : public OgreBites::ApplicationContext {
Ogre::SceneNode *mCameraNode;
Ogre::SceneManager *mScnMgr;
std::unique_ptr<CharacterController> mCharacter;
KeyHandler mKeyHandler;
MainWorld mWorld;
public:
App();
virtual ~App();
void setup();
void locateResources();
void initCamera();
Ogre::SceneManager *getSceneManager()
{
return mScnMgr;
}
void createContent();
void createCharacter();
void setupWorld();
};
App::App()
: OgreBites::ApplicationContext("App")
{
}
void App::setup()
{
OgreBites::ApplicationContext::setup();
Ogre::Root *root = getRoot();
Ogre::SceneManager *scnMgr = root->createSceneManager();
mScnMgr = scnMgr;
}
void App::locateResources()
{
OgreBites::ApplicationContext::locateResources();
}
App::~App()
{
}
void App::initCamera()
{
// also need to tell where we are
mCameraNode = mScnMgr->getRootSceneNode()->createChildSceneNode();
mCameraNode->setPosition(0, 2, 3);
mCameraNode->lookAt(Ogre::Vector3(0, 1, -1), Ogre::Node::TS_PARENT);
// create the camera
Ogre::Camera *cam = mScnMgr->createCamera("tps_camera");
cam->setNearClipDistance(0.1f); // specific to this sample
cam->setAutoAspectRatio(true);
mCameraNode->attachObject(cam);
// and tell it to render into the main window
getRenderWindow()->addViewport(cam);
}
void App::setupWorld()
{
addInputListener(&mKeyHandler);
mWorld.setup();
getRoot()->addFrameListener(&mWorld);
}
void App::createCharacter()
{
Ogre::Camera *cam = static_cast<Ogre::Camera *>(
mCameraNode->getAttachedObject("tps_camera"));
mCharacter = std::make_unique<CharacterController>(mCameraNode, cam,
mScnMgr, &mWorld);
// mInputListenerChain = TouchAgnosticInputListenerChain(getRenderWindow(), {&mKeyHandler, mCharacter.get()});
addInputListener(mCharacter.get());
WorldData::get_singleton()->initPagedWorld(cam);
}
void App::createContent()
{
// without light we would just get a black screen
Ogre::Light *light = mScnMgr->createLight("MainLight");
Ogre::SceneNode *lightNode =
mScnMgr->getRootSceneNode()->createChildSceneNode();
// lightNode->setPosition(0, 10, 15);
lightNode->setDirection(
Ogre::Vector3(0.55, -0.3, 0.75).normalisedCopy());
lightNode->attachObject(light);
light->setType(Ogre::Light::LT_DIRECTIONAL);
light->setDiffuseColour(Ogre::ColourValue::White);
light->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4));
mScnMgr->setSkyBox(true, "Skybox", 490);
// Two boxes in one batch
Procedural::TriangleBuffer tb;
Procedural::BoxGenerator b;
b.setPosition(2, 0, 0).addToTriangleBuffer(tb);
b.setPosition(-2, 0, 0).addToTriangleBuffer(tb);
tb.transformToMesh("twoBoxes");
Ogre::Entity *ent = mScnMgr->createEntity("twoBoxes");
Ogre::SceneNode *boxes =
mScnMgr->getRootSceneNode()->createChildSceneNode(
"boxes", Ogre::Vector3(5, 0, -5));
boxes->attachObject(ent);
}
int main(int argc, char *argv[])
{
App ctx;
ctx.initApp();
// get a pointer to the already created root
Ogre::Root *root = ctx.getRoot();
Ogre::SceneManager *scnMgr = ctx.getSceneManager();
// register our scene with the RTSS
Ogre::RTShader::ShaderGenerator *shadergen =
Ogre::RTShader::ShaderGenerator::getSingletonPtr();
shadergen->addSceneManager(scnMgr);
WorldData::init(root, scnMgr);
ctx.setWindowGrab(true);
ctx.createContent();
ctx.initCamera();
ctx.setupWorld();
ctx.createCharacter();
// register for input events
// KeyHandler keyHandler;
// ctx.addInputListener(&keyHandler);
ctx.getRoot()->startRendering();
ctx.setWindowGrab(false);
ctx.closeApp();
WorldData::cleanup();
return 0;
}

39
lua-scripts/data.lua Normal file
View File

@@ -0,0 +1,39 @@
function foo()
tree()
.node("p1", Quaternion(), Vector3(0, 0, -200))
.entity("b1", "residental-house1.glb")
.endnode()
.node("p2", Quaternion(), Vector3(0, 0, -150))
.entity("residental-house1.glb")
.endnode()
.node("p3", Quaternion(), Vector3(0, 0, -100))
.entity("residental-house1.glb")
.endnode()
.node("p4", Quaternion(), Vector3(0, 0, -50))
.entity("residental-house1.glb")
.endnode()
.node("p5", Quaternion(), Vector3(0, 0, 50))
.entity("residental-house1.glb")
.endnode()
.node("p6", Quaternion(), Vector3(0, 0, 100))
.entity("residental-house1.glb")
.endnode()
.node("p7", Quaternion(), Vector3(0, 0, 150))
.entity("residental-house2.glb")
.endnode()
.node("p8", Quaternion(), Vector3(0, 0, 200))
.entity("residental-house3.glb")
.endnode()
for x = -1000, 1000, 50 do
for z = -1000, 1000, 50 do
if not ((x >-100 and x < 100) and (z > -100 and z < 100)) then
tree()
.node("p00" .. tostring(x * 1000 + z), Quaternion(), Vector3(x, 0, z))
.entity("residental-house2.glb")
.endnode()
end
end
end
v = Vector3(0, 1, 2)
end
foo()

View File

@@ -18,6 +18,9 @@ FileSystem=resources/terrain
# Rarely used resources should be separately loaded by the
# samples which require them.
[General]
FileSystem=skybox
FileSystem=resources/buildings
FileSystem=resources/debug
# PBR media must come before the scripts that reference it
#FileSystem=./Media/PBR
#FileSystem=./Media/PBR/filament
@@ -63,6 +66,8 @@ FileSystem=resources/terrain
# Materials for visual tests
#[Tests]
#FileSystem=/media/slapin/library/ogre/ogre-sdk/Tests/Media
[LuaScripts]
FileSystem=lua-scripts
[Characters]
FileSystem=./characters/male

View File

@@ -0,0 +1,11 @@
OGRE_NATIVE_GLSL_VERSION_DIRECTIVE
#include <OgreUnifiedShader.h>
OGRE_UNIFORMS(uniform vec4 ambient;)
OGRE_UNIFORMS(uniform vec4 diffuse;)
MAIN_PARAMETERS
MAIN_DECLARATION
{
gl_FragColor = ambient * diffuse;
}

View File

@@ -0,0 +1,71 @@
material Skybox/Debug1
{
technique
{
pass
{
lighting off
depth_write off
ambient 1.0 0.0 0.0 1.0
diffuse 1.0 0.0 0.0 1.0
vertex_program_ref debug_vp
{
}
fragment_program_ref debug_fp
{
}
}
}
}
material Debug/Red
{
technique
{
pass
{
lighting off
depth_check on
depth_write on
depth_func always_pass
ambient 1.0 0.0 0.0 1.0
diffuse vertexcolour
specular 0.0 0.0 0.0 1.0
cull_software none
cull_hardware none
/*
rtshader_system
{
lighting_stage metal_roughness
}
*/
}
}
}
material Debug/Red2
{
technique
{
pass
{
lighting off
depth_check on
depth_write on
depth_func always_pass
ambient 1.0 0.0 0.0 1.0
diffuse vertexcolour
specular 0.0 0.0 0.0 1.0
cull_software none
cull_hardware none
rtshader_system
{
lighting_stage metal_roughness
}
}
}
}

View File

@@ -0,0 +1,19 @@
fragment_program debug_fp glsl glsles glslang hlsl
{
source debug.frag
default_params
{
param_named_auto ambient surface_ambient_colour
param_named_auto diffuse surface_diffuse_colour
}
}
vertex_program debug_vp glsl glsles glslang hlsl
{
source debug.vert
default_params
{
param_named worldViewProj worldviewproj_matrix
}
}

View File

@@ -0,0 +1,25 @@
OGRE_NATIVE_GLSL_VERSION_DIRECTIVE
#include <OgreUnifiedShader.h>
OGRE_UNIFORMS(
uniform mat4 worldViewProj;
)
MAIN_PARAMETERS
IN(vec4 vertex, POSITION)
IN(vec3 normal, NORMAL)
IN(vec3 tangent, TANGENT)
IN(vec3 uv0, TEXCOORD0)
// uniform mat4 worldViewProj;
// attribute vec4 vertex;
// attribute vec3 normal;
// attribute vec4 tangent;
// attribute vec2 uv0;
MAIN_DECLARATION
// void main()
{
// gl_Position = mul(worldViewProj, position);
gl_Position = worldViewProj * vertex;
}

View File

@@ -0,0 +1,38 @@
#include "OgreUnifiedShader.h"
struct RasterizerData
{
vec4 pos [[position]];
vec2 uv;
};
struct Vertex
{
IN(vec3 pos, POSITION);
IN(vec2 uv, TEXCOORD0);
};
struct Uniform
{
mat4 mvpMtx;
mat4 texMtx;
};
// first 15 slots are reserved for the vertex attributes
#define UNIFORM_INDEX_START 16
vertex RasterizerData default_vp(Vertex in [[stage_in]],
constant Uniform& u [[buffer(UNIFORM_INDEX_START)]])
{
RasterizerData out;
out.pos = u.mvpMtx * vec4(in.pos, 1);
out.uv = (u.texMtx * vec4(in.uv,1,1)).xy;
return out;
}
fragment half4 default_fp(RasterizerData in [[stage_in]],
metal::texture2d<half> tex [[texture(0)]],
metal::sampler s [[sampler(0)]])
{
return tex.sample(s, in.uv);
}

View File

@@ -0,0 +1,97 @@
// This file is part of the OGRE project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at https://www.ogre3d.org/licensing.
// @public-api
#if defined(OGRE_FRAGMENT_SHADER) && defined(OGRE_GLSLES)
// define default precisions for ES fragement shaders
precision mediump float;
#if __VERSION__ > 100
precision lowp sampler2DArray;
precision lowp sampler2DShadow;
precision lowp sampler3D;
#endif
#endif
#if __VERSION__ == 100
mat2 transpose(mat2 m)
{
return mat2(m[0][0], m[1][0],
m[0][1], m[1][1]);
}
mat3 transpose(mat3 m)
{
return mat3(m[0][0], m[1][0], m[2][0],
m[0][1], m[1][1], m[2][1],
m[0][2], m[1][2], m[2][2]);
}
mat4 transpose(mat4 m)
{
return mat4(m[0][0], m[1][0], m[2][0], m[3][0],
m[0][1], m[1][1], m[2][1], m[3][1],
m[0][2], m[1][2], m[2][2], m[3][2],
m[0][3], m[1][3], m[2][3], m[3][3]);
}
#endif
#if __VERSION__ > 120 || defined(OGRE_GLSLANG)
#define texture1D texture
#define texture2D texture
#define texture3D texture
#define texture2DArray texture
#define textureCube texture
#define shadow2D texture
#define shadow2DProj textureProj
#define texture2DProj textureProj
#define texture2DLod textureLod
#define textureCubeLod textureLod
#if defined(OGRE_GLSLANG) || (__VERSION__ > 150 && defined(OGRE_VERTEX_SHADER)) || __VERSION__ >= 410
#define IN(decl, loc) layout(location = loc) in decl;
#else
#define IN(decl, loc) in decl;
#endif
#if defined(OGRE_GLSLANG) || (__VERSION__ > 150 && defined(OGRE_FRAGMENT_SHADER)) || __VERSION__ >= 410
#define OUT(decl, loc) layout(location = loc) out decl;
#else
#define OUT(decl, loc) out decl;
#endif
#else
#ifdef OGRE_VERTEX_SHADER
#define IN(decl, loc) attribute decl;
#define OUT(decl, loc) varying decl;
#else
#define IN(decl, loc) varying decl;
#define OUT(decl, loc) out decl;
#endif
#endif
#if defined(OGRE_FRAGMENT_SHADER) && (defined(OGRE_GLSLANG) || (__VERSION__ > 130))
#define gl_FragColor FragColor
OUT(vec4 FragColor, 0)
#endif
#ifdef VULKAN
#ifdef OGRE_VERTEX_SHADER
#define OGRE_UNIFORMS_BEGIN layout(binding = 0, row_major) uniform OgreUniforms {
#else
#define OGRE_UNIFORMS_BEGIN layout(binding = 1, row_major) uniform OgreUniforms {
#endif
#define OGRE_UNIFORMS_END };
#else
#define OGRE_UNIFORMS_BEGIN
#define OGRE_UNIFORMS_END
#endif

View File

@@ -0,0 +1,98 @@
// This file is part of the OGRE project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at https://www.ogre3d.org/licensing.
// @public-api
#if OGRE_HLSL >= 4
// SM4 separates sampler into Texture and SamplerState
#define sampler1D Sampler1D
#define sampler2D Sampler2D
#define sampler3D Sampler3D
#define samplerCUBE SamplerCube
struct Sampler1D
{
Texture1D t;
SamplerState s;
};
struct Sampler2D
{
Texture2D t;
SamplerState s;
};
struct Sampler3D
{
Texture3D t;
SamplerState s;
};
struct SamplerCube
{
TextureCube t;
SamplerState s;
};
float4 tex1D(Sampler1D s, float v) { return s.t.Sample(s.s, v); }
float4 tex2D(Sampler2D s, float2 v) { return s.t.Sample(s.s, v); }
float4 tex3D(Sampler3D s, float3 v) { return s.t.Sample(s.s, v); }
float4 texCUBE(SamplerCube s, float3 v) { return s.t.Sample(s.s, v); }
float4 texCUBElod(SamplerCube s, float4 v) { return s.t.SampleLevel(s.s, v.xyz, v.w); }
float4 tex2D(Sampler2D s, float2 v, float2 ddx, float2 ddy) { return s.t.SampleGrad(s.s, v, ddx, ddy); }
float4 tex2Dproj(Sampler2D s, float4 v) { return s.t.Sample(s.s, v.xy/v.w); }
float4 tex2Dlod(Sampler2D s, float4 v) { return s.t.SampleLevel(s.s, v.xy, v.w); }
#define SAMPLER1D(name, reg) \
Texture1D name ## Tex : register(t ## reg);\
SamplerState name ## State : register(s ## reg);\
static Sampler1D name = {name ## Tex, name ## State}
#define SAMPLER2D(name, reg) \
Texture2D name ## Tex : register(t ## reg);\
SamplerState name ## State : register(s ## reg);\
static Sampler2D name = {name ## Tex, name ## State}
#define SAMPLER3D(name, reg) \
Texture3D name ## Tex : register(t ## reg);\
SamplerState name ## State : register(s ## reg);\
static Sampler3D name = {name ## Tex, name ## State}
#define SAMPLERCUBE(name, reg) \
TextureCube name ## Tex : register(t ## reg);\
SamplerState name ## State : register(s ## reg);\
static SamplerCube name = {name ## Tex, name ## State}
// the following are not available in D3D9, but provided for convenience
struct Sampler2DShadow
{
Texture2D t;
SamplerComparisonState s;
};
struct Sampler2DArray
{
Texture2DArray t;
SamplerState s;
};
#define SAMPLER2DSHADOW(name, reg) \
Texture2D name ## Tex : register(t ## reg);\
SamplerComparisonState name ## State : register(s ## reg);\
static Sampler2DShadow name = {name ## Tex, name ## State}
#define SAMPLER2DARRAY(name, reg) \
Texture2DArray name ## Tex : register(t ## reg);\
SamplerState name ## State : register(s ## reg);\
static Sampler2DArray name = {name ## Tex, name ## State}
float tex2Dcmp(Sampler2DShadow s, float3 v) { return s.t.SampleCmpLevelZero(s.s, v.xy, v.z); }
float4 tex2DARRAY(Sampler2DArray s, float3 v) { return s.t.Sample(s.s, v); }
#else
#define SAMPLER1D(name, reg) sampler1D name : register(s ## reg)
#define SAMPLER2D(name, reg) sampler2D name : register(s ## reg)
#define SAMPLER3D(name, reg) sampler3D name : register(s ## reg)
#define SAMPLERCUBE(name, reg) samplerCUBE name : register(s ## reg)
#endif

View File

@@ -0,0 +1,185 @@
// This file is part of the OGRE project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at https://www.ogre3d.org/licensing.
// greatly inspired by
// - shiny: https://ogrecave.github.io/shiny/defining-materials-shaders.html
// - bgfx: https://github.com/bkaradzic/bgfx/blob/master/src/bgfx_shader.sh
/// general usage:
// MAIN_PARAMETERS
// IN(vec4 vertex, POSITION)
// MAIN_DECLARATION
// {
// GLSL code here
// }
/// configuration
// use macros that will be default with Ogre 15
// #define USE_OGRE_FROM_FUTURE
// @public-api
#if defined(OGRE_HLSL) || defined(OGRE_CG)
// HLSL
#include "HLSL_SM4Support.hlsl"
#define vec2 float2
#define vec3 float3
#define vec4 float4
#define mat3 float3x3
#define mat4 float4x4
#define ivec2 int2
#define ivec3 int3
#define ivec4 int4
#define texture1D tex1D
#define texture2D tex2D
#define texture3D tex3D
#define texture2DArray tex2DARRAY
#define textureCube texCUBE
#define shadow2D tex2Dcmp
#define texture2DProj tex2Dproj
vec4 texture2DLod(sampler2D s, vec2 v, float lod) { return tex2Dlod(s, vec4(v.x, v.y, 0, lod)); }
#define samplerCube samplerCUBE
vec4 textureCubeLod(samplerCube s, vec3 v, float lod) { return texCUBElod(s, vec4(v.x, v.y, v.z, lod)); }
#define sampler2DShadow Sampler2DShadow
#define mix lerp
#define fract frac
#define inversesqrt rsqrt
#define dFdx ddx
#define dFdy ddy
float mod(float _a, float _b) { return _a - _b * floor(_a / _b); }
vec2 mod(vec2 _a, vec2 _b) { return _a - _b * floor(_a / _b); }
vec3 mod(vec3 _a, vec3 _b) { return _a - _b * floor(_a / _b); }
vec4 mod(vec4 _a, vec4 _b) { return _a - _b * floor(_a / _b); }
vec2 vec2_splat(float x) { return vec2(x, x); }
vec3 vec3_splat(float x) { return vec3(x, x, x); }
vec4 vec4_splat(float x) { return vec4(x, x, x, x); }
mat4 mtxFromRows(vec4 a, vec4 b, vec4 c, vec4 d)
{
return mat4(a, b, c, d);
}
mat3 mtxFromRows(vec3 a, vec3 b, vec3 c)
{
return mat3(a, b, c);
}
mat3 mtxFromCols(vec3 a, vec3 b, vec3 c)
{
return transpose(mat3(a, b, c));
}
#define STATIC static
#define OGRE_UNIFORMS_BEGIN
#define OGRE_UNIFORMS_END
#define MAIN_PARAMETERS void main(
#ifdef OGRE_VERTEX_SHADER
#define MAIN_DECLARATION out float4 gl_Position : POSITION)
#else
#define MAIN_DECLARATION in float4 gl_FragCoord : POSITION, out float4 gl_FragColor : COLOR)
#endif
#define IN(decl, sem) in decl : sem,
#define OUT(decl, sem) out decl : sem,
#elif defined(OGRE_METAL)
#define vec2 float2
#define vec3 float3
#define vec4 float4
#define mat3 metal::float3x3
#define mat4 metal::float4x4
#define IN(decl, sem) decl [[ attribute(sem) ]];
#else
// GLSL
#include "GLSL_GL3Support.glsl"
#ifdef VULKAN
#define _UNIFORM_BINDING(b) layout(binding = b + 2) uniform
#elif __VERSION__ >= 420
#define _UNIFORM_BINDING(b) layout(binding = b) uniform
#else
#define _UNIFORM_BINDING(b) uniform
#endif
#define SAMPLER1D(name, reg) _UNIFORM_BINDING(reg) sampler1D name
#define SAMPLER2D(name, reg) _UNIFORM_BINDING(reg) sampler2D name
#define SAMPLER3D(name, reg) _UNIFORM_BINDING(reg) sampler3D name
#define SAMPLER2DARRAY(name, reg) _UNIFORM_BINDING(reg) sampler2DArray name
#define SAMPLERCUBE(name, reg) _UNIFORM_BINDING(reg) samplerCube name
#define SAMPLER2DSHADOW(name, reg) _UNIFORM_BINDING(reg) sampler2DShadow name
#define saturate(x) clamp(x, 0.0, 1.0)
#define mul(a, b) ((a) * (b))
#define vec2_splat vec2
#define vec3_splat vec3
#define vec4_splat vec4
mat4 mtxFromRows(vec4 a, vec4 b, vec4 c, vec4 d)
{
return transpose(mat4(a, b, c, d));
}
mat3 mtxFromRows(vec3 a, vec3 b, vec3 c)
{
return transpose(mat3(a, b, c));
}
mat3 mtxFromCols(vec3 a, vec3 b, vec3 c)
{
return mat3(a, b, c);
}
#define STATIC
#define MAIN_PARAMETERS
#define MAIN_DECLARATION void main()
#endif
#if !defined(OGRE_HLSL) && !defined(OGRE_CG)
// semantics as aliases for attribute locations
#define POSITION 0
#define BLENDWEIGHT 1
#define NORMAL 2
#define COLOR0 3
#define COLOR1 4
#define COLOR COLOR0
#define FOG 5
#define BLENDINDICES 7
#define TEXCOORD0 8
#define TEXCOORD1 9
#define TEXCOORD2 10
#define TEXCOORD3 11
#define TEXCOORD4 12
#define TEXCOORD5 13
#define TEXCOORD6 14
#define TEXCOORD7 15
#define TANGENT 14
#endif
#define OGRE_UNIFORMS(params) OGRE_UNIFORMS_BEGIN params OGRE_UNIFORMS_END
// GL_EXT_shader_explicit_arithmetic_types polyfill
#ifdef OGRE_GLSLES
#define float32_t highp float
#define f32vec2 highp vec2
#define f32vec3 highp vec3
#define f32vec4 highp vec4
#else
#define float32_t float
#define f32vec2 vec2
#define f32vec3 vec3
#define f32vec4 vec4
#endif

View File

@@ -0,0 +1,85 @@
// This file is part of the OGRE project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at https://www.ogre3d.org/licensing.
material Ogre/TextureShadowCaster
{
receive_shadows false
technique
{
pass
{
// Lighting has to be on, because we need shadow coloured objects
// Note that because we can't predict vertex programs, we'll have to
// bind light values to those, and so we bind White to ambient
// reflectance, and we'll set the ambient colour to the shadow colour
ambient 1 1 1
diffuse 0 0 0
specular 0 0 0 1
emissive 0 0 0
fog_override true none
// set depth bias in case this is used with PF_DEPTH
depth_bias -1 -1
}
}
}
material Ogre/StencilShadowModulationPass
{
technique
{
pass
{
lighting off
scene_blend modulate
depth_write off
depth_check off
cull_hardware none
vertex_program_ref Ogre/ShadowBlendVP {}
fragment_program_ref Ogre/ShadowBlendFP {}
texture_unit {}
}
}
}
material Ogre/StencilShadowVolumes
{
technique
{
pass
{
// program will be set dynamically to match light type
vertex_program_ref Ogre/ShadowExtrudeDirLightFinite
{
// however, the parameters here are shared between all programs
param_named_auto worldviewproj_matrix worldviewproj_matrix
param_named_auto light_position_object_space light_position_object_space 0
param_named_auto shadow_extrusion_distance shadow_extrusion_distance 0
}
fragment_program_ref Ogre/ShadowBlendFP {}
}
}
}
material Ogre/Debug/ShadowVolumes
{
technique
{
pass
{
depth_write off
scene_blend add
cull_hardware none
// program will be set dynamically to match light type
vertex_program_ref Ogre/ShadowExtrudeDirLight
{
// however, the parameters here are shared between all programs
param_named_auto worldviewproj_matrix worldviewproj_matrix
param_named_auto light_position_object_space light_position_object_space 0
}
fragment_program_ref Ogre/ShadowBlendFP {}
}
}
}

View File

@@ -0,0 +1,11 @@
#include <OgreUnifiedShader.h>
OGRE_UNIFORMS(
uniform vec4 shadowColor;
)
MAIN_PARAMETERS
MAIN_DECLARATION
{
gl_FragColor = shadowColor;
}

View File

@@ -0,0 +1,12 @@
#include <OgreUnifiedShader.h>
OGRE_UNIFORMS(
uniform mat4 worldViewProj;
)
MAIN_PARAMETERS
IN(vec4 vertex, POSITION)
MAIN_DECLARATION
{
gl_Position = mul(worldViewProj, vertex);
}

View File

@@ -0,0 +1,18 @@
#include <OgreUnifiedShader.h>
// Directional light extrude
uniform mat4 worldviewproj_matrix;
uniform vec4 light_position_object_space; // homogenous, object space
MAIN_PARAMETERS
IN(vec4 uv0, TEXCOORD0)
IN(vec4 position, POSITION)
MAIN_DECLARATION
{
// Extrusion in object space
// Vertex unmodified if w==1, extruded if w==0
vec4 newpos =
(uv0.xxxx * (position + light_position_object_space)) - light_position_object_space;
gl_Position = mul(worldviewproj_matrix, newpos);
}

View File

@@ -0,0 +1,22 @@
#include <OgreUnifiedShader.h>
// Directional light extrude - FINITE
uniform mat4 worldviewproj_matrix;
uniform vec4 light_position_object_space; // homogenous, object space
uniform float shadow_extrusion_distance; // how far to extrude
MAIN_PARAMETERS
IN(vec4 uv0, TEXCOORD0)
IN(vec4 position, POSITION)
MAIN_DECLARATION
{
// Extrusion in object space
// Vertex unmodified if w==1, extruded if w==0
vec3 extrusionDir = - light_position_object_space.xyz;
extrusionDir = normalize(extrusionDir);
vec4 newpos = vec4(position.xyz +
((1.0 - uv0.x) * shadow_extrusion_distance * extrusionDir), 1.0);
gl_Position = mul(worldviewproj_matrix, newpos);
}

View File

@@ -0,0 +1,19 @@
#include <OgreUnifiedShader.h>
// Point light shadow volume extrude
uniform mat4 worldviewproj_matrix;
uniform vec4 light_position_object_space; // homogenous, object space
MAIN_PARAMETERS
IN(vec4 uv0, TEXCOORD0)
IN(vec4 position, POSITION)
MAIN_DECLARATION
{
// Extrusion in object space
// Vertex unmodified if w==1, extruded if w==0
vec4 newpos =
(uv0.xxxx * light_position_object_space) +
vec4(position.xyz - light_position_object_space.xyz, 0.0);
gl_Position = mul(worldviewproj_matrix, newpos);
}

View File

@@ -0,0 +1,22 @@
#include <OgreUnifiedShader.h>
// Point light shadow volume extrude - FINITE
uniform mat4 worldviewproj_matrix;
uniform vec4 light_position_object_space; // homogenous, object space
uniform float shadow_extrusion_distance; // how far to extrude
MAIN_PARAMETERS
IN(vec4 uv0, TEXCOORD0)
IN(vec4 position, POSITION)
MAIN_DECLARATION
{
// Extrusion in object space
// Vertex unmodified if w==1, extruded if w==0
vec3 extrusionDir = position.xyz - light_position_object_space.xyz;
extrusionDir = normalize(extrusionDir);
vec4 newpos = vec4(position.xyz +
((1.0 - uv0.x) * shadow_extrusion_distance * extrusionDir), 1.0);
gl_Position = mul(worldviewproj_matrix, newpos);
}

View File

@@ -0,0 +1,41 @@
// This file is part of the OGRE project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at https://www.ogre3d.org/licensing.
vertex_program Ogre/ShadowBlendVP glsl glsles hlsl glslang
{
source ShadowBlend.vert
default_params
{
param_named_auto worldViewProj worldviewproj_matrix
}
}
fragment_program Ogre/ShadowBlendFP glsl glsles hlsl glslang
{
source ShadowBlend.frag
default_params
{
param_named_auto shadowColor shadow_colour
}
}
vertex_program Ogre/ShadowExtrudePointLight glsl glsles hlsl
{
source ShadowExtrudePointLight.vert
}
vertex_program Ogre/ShadowExtrudeDirLight glsl glsles hlsl
{
source ShadowExtrudeDirLight.vert
}
vertex_program Ogre/ShadowExtrudePointLightFinite glsl glsles hlsl
{
source ShadowExtrudePointLightFinite.vert
}
vertex_program Ogre/ShadowExtrudeDirLightFinite glsl glsles hlsl
{
source ShadowExtrudeDirLightFinite.vert
}

Binary file not shown.

View File

@@ -0,0 +1,45 @@
//-----------------------------------------------------------------------------
// Program Name: FFPLib_AlphaTest
// Program Desc: Alpha test function.
// Program Type: Vertex/Pixel shader
// Language: GLSL
//-----------------------------------------------------------------------------
#define CMPF_ALWAYS_FAIL 0
#define CMPF_ALWAYS_PASS 1
#define CMPF_LESS 2
#define CMPF_LESS_EQUAL 3
#define CMPF_EQUAL 4
#define CMPF_NOT_EQUAL 5
#define CMPF_GREATER_EQUAL 6
#define CMPF_GREATER 7
bool Alpha_Func(in int func, in float alphaRef, in float alphaValue)
{
// ES2 does not have switch
if(func == CMPF_ALWAYS_PASS)
return true;
else if(func == CMPF_LESS)
return alphaValue < alphaRef;
else if(func == CMPF_LESS_EQUAL)
return alphaValue <= alphaRef;
else if(func == CMPF_EQUAL)
return alphaValue == alphaRef;
else if(func == CMPF_NOT_EQUAL)
return alphaValue != alphaRef;
else if(func == CMPF_GREATER_EQUAL)
return alphaValue >= alphaRef;
else if(func == CMPF_GREATER)
return alphaValue > alphaRef;
// CMPF_ALWAYS_FAIL and default
return false;
}
void FFP_Alpha_Test(in float func, in float alphaRef, in vec4 texel)
{
bool pass_ = Alpha_Func(int(func), alphaRef, texel.a);
if (!pass_)
discard;
}

View File

@@ -0,0 +1,92 @@
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org
Copyright (c) 2000-2014 Torus Knot Software Ltd
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.
-----------------------------------------------------------------------------
*/
//-----------------------------------------------------------------------------
// Program Name: FFPLib_Fog
// Program Desc: Fog functions of the FFP.
// Program Type: Vertex/Pixel shader
// Language: GLSL
// Notes: Implements core functions needed by FFPFog class.
// Based on fog engine.
// See http://msdn.microsoft.com/en-us/library/bb173398.aspx
// Vertex based fog: the w component of the out position is used
// as the distance parameter to fog formulas. This is basically the z coordinate
// in world space. See pixel fog under D3D docs. The fog factor is computed according
// to each formula, then clamped and output to the pixel shader.
// Pixel based fog: the w component of the out position is passed to pixel shader
// that computes the fog factor based on it.
// Both techniques use the fog factor in the end of the pixel shader to blend
// the output color with the fog color.
//-----------------------------------------------------------------------------
#define FOG_EXP 1
#define FOG_EXP2 2
#define FOG_LINEAR 3
//-----------------------------------------------------------------------------
void FFP_FogFactor(in float depth,
in vec4 fogParams,
out float oFogFactor)
{
float distance = abs(depth);
#if FOG_TYPE == FOG_LINEAR
float fogFactor = (fogParams.z - distance) * fogParams.w;
#elif FOG_TYPE == FOG_EXP
float x = distance*fogParams.x;
float fogFactor = 1.0 / exp(x);
#elif FOG_TYPE == FOG_EXP2
float x = (distance*fogParams.x*distance*fogParams.x);
float fogFactor = 1.0 / exp(x);
#endif
oFogFactor = saturate(fogFactor);
}
//-----------------------------------------------------------------------------
void FFP_PixelFog_PositionDepth(in mat4 mWorld,
in vec3 cameraPos,
in vec4 pos,
out vec3 oPosView,
out float oDepth)
{
vec4 vOutPos = mul(mWorld, pos);
oPosView = vOutPos.xyz - cameraPos;
oDepth = length(oPosView);
}
//-----------------------------------------------------------------------------
void FFP_PixelFog(in float depth,
in vec4 fogParams,
in vec4 fogColor,
in vec4 baseColor,
out vec4 oColor)
{
float fogFactor = 0.0;
FFP_FogFactor(depth, fogParams, fogFactor);
oColor = mix(fogColor, baseColor, fogFactor);
}

View File

@@ -0,0 +1,144 @@
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org
Copyright (c) 2000-2014 Torus Knot Software Ltd
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.
-----------------------------------------------------------------------------
*/
//-----------------------------------------------------------------------------
// Program Name: FFPLib_Texturing
// Program Desc: Texture functions of the FFP.
// Program Type: Vertex/Pixel shader
// Language: GLSL
// Notes: Implements core functions for FFPTexturing class.
// based on texturing operations needed by render system.
// Implements texture coordinate processing:
// see http://msdn.microsoft.com/en-us/library/bb206247.aspx
// Implements texture blending operation:
// see http://msdn.microsoft.com/en-us/library/bb206241.aspx
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void FFP_TransformTexCoord(in mat4 m, in vec2 v, out vec2 vOut)
{
vOut = mul(m, vec4(v, 0.0, 1.0)).xy;
}
//-----------------------------------------------------------------------------
void FFP_TransformTexCoord(in mat4 m, in vec4 v, out vec2 vOut)
{
vOut = mul(m, v).xy;
}
//-----------------------------------------------------------------------------
void FFP_TransformTexCoord(in mat4 m, in vec3 v, out vec3 vOut)
{
vOut = mul(m, vec4(v, 1.0)).xyz;
}
//-----------------------------------------------------------------------------
void FFP_GenerateTexCoord_EnvMap_Normal(in mat3 mWorldIT,
in vec3 vNormal,
out vec3 vOut)
{
vOut = normalize(mul(mWorldIT, vNormal));
}
//-----------------------------------------------------------------------------
void FFP_GenerateTexCoord_EnvMap_Sphere(in mat4 mWorldView,
in mat3 mWorldIT,
in vec4 vPos,
in vec3 vNormal,
out vec2 vOut)
{
vec3 normal = normalize( mul(mWorldIT, vNormal));
vec3 eyedir = normalize(mul(mWorldView, vPos)).xyz;
vec3 r = reflect(eyedir, normal);
r.z += 1.0;
float two_p = 2.0 * length(r);
vOut = vec2(0.5 + r.x / two_p, 0.5 - r.y / two_p);
}
//-----------------------------------------------------------------------------
void FFP_GenerateTexCoord_EnvMap_Reflect(in mat4 mWorld,
in mat4 mWorldIT,
in vec3 vCamPos,
in vec3 vNormal,
in vec4 vPos,
out vec3 vOut)
{
vec3 vWorldNormal = normalize(mul(mWorldIT, vec4(vNormal, 0.0)).xyz);
vec3 vWorldPos = mul(mWorld, vPos).xyz;
vec3 vEyeDir = normalize(vWorldPos - vCamPos);
vec3 vReflect = reflect(vEyeDir, vWorldNormal);
vReflect.z *= -1.0;
vOut = vReflect;
}
//-----------------------------------------------------------------------------
void FFP_AddSmooth(in float vIn0, in float vIn1, out float vOut)
{
vOut = vIn0 + vIn1 - (vIn0 * vIn1);
}
//-----------------------------------------------------------------------------
void FFP_AddSmooth(in vec2 vIn0, in vec2 vIn1, out vec2 vOut)
{
vOut = vIn0 + vIn1 - (vIn0 * vIn1);
}
//-----------------------------------------------------------------------------
void FFP_AddSmooth(in vec3 vIn0, in vec3 vIn1, out vec3 vOut)
{
vOut = vIn0 + vIn1 - (vIn0 * vIn1);
}
//-----------------------------------------------------------------------------
void FFP_AddSmooth(in vec4 vIn0, in vec4 vIn1, out vec4 vOut)
{
vOut = vIn0 + vIn1 - (vIn0 * vIn1);
}
//-----------------------------------------------------------------------------
void FFP_DotProduct(in float vIn0, in float vIn1, out float vOut)
{
vOut = dot(vIn0, vIn1);
}
//-----------------------------------------------------------------------------
void FFP_DotProduct(in vec2 vIn0, in vec2 vIn1, out vec2 vOut)
{
vOut = vec2_splat(dot(vIn0, vIn1));
}
//-----------------------------------------------------------------------------
void FFP_DotProduct(in vec3 vIn0, in vec3 vIn1, out vec3 vOut)
{
vOut = vec3_splat(dot(vIn0, vIn1));
}
//-----------------------------------------------------------------------------
void FFP_DotProduct(in vec4 vIn0, in vec4 vIn1, out vec4 vOut)
{
vOut = vec4_splat(dot(vIn0, vIn1));
}

View File

@@ -0,0 +1,100 @@
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org
Copyright (c) 2000-2014 Torus Knot Software Ltd
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.
-----------------------------------------------------------------------------
*/
//-----------------------------------------------------------------------------
// Program Name: FFPLib_Transform
// Program Desc: Transform functions of the FFP.
// Program Type: Vertex shader
// Language: GLSL
// Notes: Implements core functions for FFPTransform class.
// based on transform engine.
// See http://msdn.microsoft.com/en-us/library/bb206269.aspx
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void FFP_Transform(in mat4 m,
in vec4 v,
out vec3 vOut)
{
vOut = mul(m, v).xyz;
}
#ifdef OGRE_HLSL
void FFP_Transform(in float3x4 m,
in float4 v,
out float3 vOut)
{
vOut = mul(m, v);
}
//-----------------------------------------------------------------------------
void FFP_Transform(in float3x4 m,
in float3 v,
out float3 vOut)
{
vOut = mul((float3x3)m, v);
}
#elif !defined(OGRE_GLSLES) || OGRE_GLSLES > 100
//-----------------------------------------------------------------------------
void FFP_Transform(in mat3x4 m,
in vec4 v,
out vec3 vOut)
{
/* transpose non-square uniform matrix for correct row-major > column-major mapping
* to keep the indexing inside the shader so mat[0] returns the same data in both GLSL and HLSL
* although it will be the first row in HLSL and the first column in GLSL
*/
vOut = v * m;
}
void FFP_Transform(in mat3x4 m,
in vec3 v,
out vec3 vOut)
{
vOut = v * mat3(m);
}
#endif
//-----------------------------------------------------------------------------
void FFP_Transform(in mat4 m,
in vec3 v,
out vec3 vOut)
{
#ifdef OGRE_HLSL
vOut = mul((float3x3)m, v);
#else
vOut = mat3(m) * v;
#endif
}
//-----------------------------------------------------------------------------
void FFP_DerivePointSize(in vec4 params,
in float d,
out float sz)
{
sz = params.x/sqrt(params.y + params.z*d + params.w*d*d);
}

View File

@@ -0,0 +1,88 @@
// This file is part of the OGRE project.
// code adapted from Google Filament
// SPDX-License-Identifier: Apache-2.0
vec3 specularDFG(const PixelParams pixel) {
return mix(pixel.dfg.xxx, pixel.dfg.yyy, pixel.f0);
}
vec3 decodeDataForIBL(const vec4 data) {
return data.rgb;
}
vec3 Irradiance_RoughnessOne(samplerCube light_iblSpecular, const vec3 n, float iblRoughnessOneLevel) {
// note: lod used is always integer, hopefully the hardware skips tri-linear filtering
return decodeDataForIBL(textureCubeLod(light_iblSpecular, n, iblRoughnessOneLevel));
}
vec3 PrefilteredDFG_LUT(sampler2D light_iblDFG, float lod, float NoV) {
// coord = sqrt(linear_roughness), which is the mapping used by cmgen.
// OGRE Specific: y is flipped compared to Filament code
return texture2DLod(light_iblDFG, vec2(NoV, 1.0 - lod), 0.0).rgb;
}
float perceptualRoughnessToLod(float iblRoughnessOneLevel, float perceptualRoughness) {
// The mapping below is a quadratic fit for log2(perceptualRoughness)+iblRoughnessOneLevel when
// iblRoughnessOneLevel is 4. We found empirically that this mapping works very well for
// a 256 cubemap with 5 levels used. But also scales well for other iblRoughnessOneLevel values.
return iblRoughnessOneLevel * perceptualRoughness * (2.0 - perceptualRoughness);
}
vec3 prefilteredRadiance(samplerCube light_iblSpecular, const vec3 r, float perceptualRoughness, float iblRoughnessOneLevel) {
float lod = perceptualRoughnessToLod(iblRoughnessOneLevel, perceptualRoughness);
return decodeDataForIBL(textureCubeLod(light_iblSpecular, r, lod));
}
vec3 getSpecularDominantDirection(const vec3 n, const vec3 r, float roughness) {
return mix(r, n, roughness * roughness);
}
void evaluateIBL(inout PixelParams pixel,
in vec3 vNormal,
in vec3 viewPos,
in mat4 invViewMat,
in sampler2D dfgTex,
in samplerCube iblEnvTex,
in float iblRoughnessOneLevel,
in float iblLuminance,
inout vec3 color)
{
vec3 shading_normal = normalize(vNormal);
vec3 shading_view = -normalize(viewPos);
float shading_NoV = clampNoV(abs(dot(shading_normal, shading_view)));
// the above is currently duplicated with CookTorrance
vec3 shading_reflected = reflect(-shading_view, shading_normal);
// Pre-filtered DFG term used for image-based lighting
pixel.dfg = PrefilteredDFG_LUT(dfgTex, pixel.perceptualRoughness, shading_NoV);
vec3 E = specularDFG(pixel);
vec3 r = getSpecularDominantDirection(shading_normal, shading_reflected, pixel.roughness);
// OGRE specific: convert r and n back to world space for texture sampling
r = normalize(mul(invViewMat, vec4(r, 0.0)).xyz);
r.z *= -1.0;
shading_normal = normalize(mul(invViewMat, vec4(shading_normal, 0.0)).xyz);
// specular layer
vec3 Fr = E * prefilteredRadiance(iblEnvTex, r, pixel.perceptualRoughness, iblRoughnessOneLevel);
vec3 diffuseIrradiance = Irradiance_RoughnessOne(iblEnvTex, shading_normal, iblRoughnessOneLevel);
vec3 Fd = pixel.diffuseColor * diffuseIrradiance * (1.0 - E);
Fr *= iblLuminance;
Fd *= iblLuminance;
// Combine all terms
// Note: iblLuminance is already premultiplied by the exposure
color = pow(color, vec3_splat(2.2)); // gamma to linear
color += Fr + Fd;
// linear to gamma
color = pow(color, vec3_splat(1.0/2.2));
color = saturate(color);
}

View File

@@ -0,0 +1,114 @@
// Real-Time Polygonal-Light Shading with Linearly Transformed Cosines
// by Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt
// code: https://github.com/selfshadow/ltc_code/
// also: https://github.com/mrdoob/three.js/blob/master/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js
// adapted for Ogre by Pavel Rojtberg
#define LUT_SIZE 64.0
#define LUT_SCALE ((LUT_SIZE - 1.0)/LUT_SIZE)
#define LUT_BIAS (0.5/LUT_SIZE)
vec3 IntegrateEdgeVec(vec3 v1, vec3 v2)
{
float x = dot(v1, v2);
float y = abs(x);
float a = 0.8543985 + (0.4965155 + 0.0145206*y)*y;
float b = 3.4175940 + (4.1616724 + y)*y;
float v = a / b;
float theta_sintheta = (x > 0.0) ? v : 0.5*inversesqrt(max(1.0 - x*x, 1e-7)) - v;
return cross(v1, v2)*theta_sintheta;
}
float LTC_Evaluate(vec3 N, vec3 V, vec3 P, mat3 Minv, vec3 points[4], sampler2D ltc_2)
{
vec3 dir = points[0] - P;
vec3 lightDir = cross(points[1] - points[0], points[3] - points[0]);
if(dot(dir, lightDir) < 0.0)
return 0.0;
// construct orthonormal basis around N
vec3 T1, T2;
T1 = normalize(V - N*dot(V, N));
T2 = cross(N, T1);
// rotate area light in (T1, T2, N) basis
Minv = mul(Minv, mtxFromRows(T1, T2, N));
// polygon
vec3 L[4];
L[0] = mul(Minv, points[0] - P);
L[1] = mul(Minv, points[1] - P);
L[2] = mul(Minv, points[2] - P);
L[3] = mul(Minv, points[3] - P);
// project rect onto sphere
L[0] = normalize(L[0]);
L[1] = normalize(L[1]);
L[2] = normalize(L[2]);
L[3] = normalize(L[3]);
vec3 vsum = vec3_splat(0.0);
vsum += IntegrateEdgeVec(L[0], L[1]);
vsum += IntegrateEdgeVec(L[1], L[2]);
vsum += IntegrateEdgeVec(L[2], L[3]);
vsum += IntegrateEdgeVec(L[3], L[0]);
float len = length(vsum);
float z = vsum.z/len;
// clipless approximation: tabulated horizon-clipped sphere
// visually better than alternatives, but produces artifacts at low roughness values
vec2 uv = vec2(z*0.5 + 0.5, len);
uv = uv*LUT_SCALE + LUT_BIAS;
float scale = texture2D(ltc_2, uv).w;
return len*scale;
}
void InitRectPoints(vec3 center, vec3 ex, vec3 ey, out vec3 points[4])
{
points[0] = center - ex - ey;
points[1] = center + ex - ey;
points[2] = center + ex + ey;
points[3] = center - ex + ey;
}
void evaluateRectLight(sampler2D ltc_1, sampler2D ltc_2, float roughness, vec3 N, vec3 pos, vec3 lpos, vec3 halfwidth, vec3 halfheight,
inout vec3 scol, inout vec3 dcol)
{
vec3 points[4];
InitRectPoints(lpos, halfwidth, halfheight, points);
vec3 V = -normalize(pos);
float ndotv = saturate(dot(N, V));
vec2 uv = vec2(roughness, sqrt(1.0 - ndotv));
uv = uv*LUT_SCALE + LUT_BIAS;
vec4 t1 = texture2D(ltc_1, uv);
mat3 Minv = mtxFromCols(
vec3(t1.x, 0.0, t1.y),
vec3( 0.0, 1.0, 0.0),
vec3(t1.z, 0.0, t1.w)
);
float spec = LTC_Evaluate(N, V, pos, Minv, points, ltc_2);
// LTC Fresnel Approximation by Stephen Hill
// http://blog.selfshadow.com/publications/s2016-advances/s2016_ltc_fresnel.pdf
vec4 t2 = texture2D(ltc_2, uv);
scol = (scol*t2.x + (1.0 - scol)*t2.y)*spec;
mat3 Meye = mat3(
vec3(1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, 0.0, 1.0)
);
dcol *= LTC_Evaluate(N, V, pos, Meye, points, ltc_2);
}

View File

@@ -0,0 +1,18 @@
// This file is part of the OGRE project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at https://www.ogre3d.org/licensing.
// SPDX-License-Identifier: MIT
#define M_PI 3.14159265359
float getDistanceAttenuation(const vec3 params, float distance)
{
return 1.0 / (params.x + params.y * distance + params.z * distance * distance);
}
float getAngleAttenuation(const vec3 params, const vec3 lightDir, const vec3 toLight)
{
float rho = dot(-lightDir, toLight);
float fSpotE = saturate((rho - params.y) / (params.x - params.y));
return pow(fSpotE, params.z);
}

View File

@@ -0,0 +1,17 @@
sampler Ogre/ShadowSampler
{
tex_address_mode border
tex_border_colour 1 1 1 1
}
sampler Ogre/DepthShadowSampler : Ogre/ShadowSampler
{
compare_test on
comp_func less_equal
}
sampler Ogre/LtcLUTSampler
{
filtering point linear point
tex_address_mode clamp
}

View File

@@ -0,0 +1,246 @@
// This file is part of the OGRE project.
// code adapted from Google Filament
// SPDX-License-Identifier: Apache-2.0
#include "RTSLib_Lighting.glsl"
#ifdef HAVE_AREA_LIGHTS
#include "RTSLib_LTC.glsl"
#endif
#ifdef OGRE_GLSLES
// min roughness such that (MIN_PERCEPTUAL_ROUGHNESS^4) > 0 in fp16 (i.e. 2^(-14/4), rounded up)
#define MIN_PERCEPTUAL_ROUGHNESS 0.089
#else
#define MIN_PERCEPTUAL_ROUGHNESS 0.045
#endif
#define MEDIUMP_FLT_MAX 65504.0
#define saturateMediump(x) min(x, MEDIUMP_FLT_MAX)
#define MIN_N_DOT_V 1e-4
struct PixelParams
{
vec3 baseColor;
vec3 diffuseColor;
float perceptualRoughness;
float roughness;
vec3 f0;
vec3 dfg;
vec3 energyCompensation;
};
float clampNoV(float NoV) {
// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
return max(NoV, MIN_N_DOT_V);
}
// Computes x^5 using only multiply operations.
float pow5(float x) {
float x2 = x * x;
return x2 * x2 * x;
}
// https://google.github.io/filament/Filament.md.html#materialsystem/diffusebrdf
float Fd_Lambert() {
return 1.0 / M_PI;
}
// https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf/fresnel(specularf)
vec3 F_Schlick(const vec3 f0, float f90, float VoH) {
// Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"
return f0 + (f90 - f0) * pow5(1.0 - VoH);
}
vec3 computeDiffuseColor(const vec3 baseColor, float metallic) {
return baseColor.rgb * (1.0 - metallic);
}
vec3 computeF0(const vec3 baseColor, float metallic, float reflectance) {
return baseColor.rgb * metallic + (reflectance * (1.0 - metallic));
}
float perceptualRoughnessToRoughness(float perceptualRoughness) {
return perceptualRoughness * perceptualRoughness;
}
// https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf/geometricshadowing(specularg)
float V_SmithGGXCorrelated(float roughness, float NoV, float NoL) {
// Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs"
float a2 = roughness * roughness;
// TODO: lambdaV can be pre-computed for all the lights, it should be moved out of this function
float lambdaV = NoL * sqrt((NoV - a2 * NoV) * NoV + a2);
float lambdaL = NoV * sqrt((NoL - a2 * NoL) * NoL + a2);
float v = 0.5 / (lambdaV + lambdaL);
// a2=0 => v = 1 / 4*NoL*NoV => min=1/4, max=+inf
// a2=1 => v = 1 / 2*(NoL+NoV) => min=1/4, max=+inf
// clamp to the maximum value representable in mediump
return saturateMediump(v);
}
// https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf/normaldistributionfunction(speculard)
float D_GGX(float roughness, float NoH, const vec3 h, const vec3 n) {
// Walter et al. 2007, "Microfacet Models for Refraction through Rough Surfaces"
// In mediump, there are two problems computing 1.0 - NoH^2
// 1) 1.0 - NoH^2 suffers floating point cancellation when NoH^2 is close to 1 (highlights)
// 2) NoH doesn't have enough precision around 1.0
// Both problem can be fixed by computing 1-NoH^2 in highp and providing NoH in highp as well
// However, we can do better using Lagrange's identity:
// ||a x b||^2 = ||a||^2 ||b||^2 - (a . b)^2
// since N and H are unit vectors: ||N x H||^2 = 1.0 - NoH^2
// This computes 1.0 - NoH^2 directly (which is close to zero in the highlights and has
// enough precision).
// Overall this yields better performance, keeping all computations in mediump
#ifdef OGRE_GLSLES
vec3 NxH = cross(n, h);
float oneMinusNoHSquared = dot(NxH, NxH);
#else
float oneMinusNoHSquared = 1.0 - NoH * NoH;
#endif
float a = NoH * roughness;
float k = roughness / (oneMinusNoHSquared + a * a);
float d = k * k * (1.0 / M_PI);
return saturateMediump(d);
}
vec3 evaluateLight(
in vec3 vNormal,
in vec3 viewPos,
in vec4 lightPos,
in vec3 lightColor,
in vec4 pointParams,
in vec4 vLightDirView,
in vec4 spotParams,
in PixelParams pixel)
{
vec3 vLightView = lightPos.xyz;
float fLightD = 0.0;
if (lightPos.w != 0.0)
{
vLightView -= viewPos; // to light
fLightD = length(vLightView);
if(fLightD > pointParams.x)
return vec3_splat(0.0);
}
vLightView = normalize(vLightView);
vec3 vNormalView = normalize(vNormal);
float NoL = saturate(dot(vNormalView, vLightView));
if(NoL <= 0.0)
return vec3_splat(0.0); // not lit by this light
// https://google.github.io/filament/Filament.md.html#toc5.6.2
float f90 = saturate(dot(pixel.f0, vec3_splat(50.0 * 0.33)));
vec3 vView = -normalize(viewPos);
// https://google.github.io/filament/Filament.md.html#materialsystem/standardmodelsummary
vec3 h = normalize(vView + vLightView);
float NoH = saturate(dot(vNormalView, h));
float NoV = clampNoV(abs(dot(vNormalView, vView)));
float V = V_SmithGGXCorrelated(pixel.roughness, NoV, NoL);
vec3 F = F_Schlick(pixel.f0, f90, NoH);
float D = D_GGX(pixel.roughness, NoH, h, vNormalView);
vec3 Fr = (D * V) * F;
vec3 Fd = pixel.diffuseColor * Fd_Lambert();
// https://google.github.io/filament/Filament.md.html#materialsystem/improvingthebrdfs/energylossinspecularreflectance
vec3 color = NoL * lightColor * (Fr * pixel.energyCompensation + Fd);
color *= getDistanceAttenuation(pointParams.yzw, fLightD);
if(spotParams.w != 0.0)
{
color *= getAngleAttenuation(spotParams.xyz, vLightDirView.xyz, vLightView);
}
return color;
}
void PBR_MakeParams(in vec3 baseColor, in vec2 mrParam, inout PixelParams pixel)
{
baseColor = pow(baseColor, vec3_splat(2.2));
pixel.baseColor = baseColor;
float perceptualRoughness = mrParam.x;
// Clamp the roughness to a minimum value to avoid divisions by 0 during lighting
pixel.perceptualRoughness = clamp(perceptualRoughness, MIN_PERCEPTUAL_ROUGHNESS, 1.0);
// Remaps the roughness to a perceptually linear roughness (roughness^2)
pixel.roughness = perceptualRoughnessToRoughness(pixel.perceptualRoughness);
float metallic = saturate(mrParam.y);
pixel.f0 = computeF0(baseColor, metallic, 0.04);
pixel.diffuseColor = computeDiffuseColor(baseColor, metallic);
pixel.dfg = vec3_splat(0.5); // use full f0 for energy compensation
pixel.energyCompensation = vec3_splat(0.0); // will be set later
}
#if LIGHT_COUNT > 0
void PBR_Lights(
#ifdef SHADOWLIGHT_COUNT
in float shadowFactor[SHADOWLIGHT_COUNT],
#endif
#ifdef HAVE_AREA_LIGHTS
in sampler2D ltcLUT1,
in sampler2D ltcLUT2,
#endif
in vec3 vNormal,
in vec3 viewPos,
in vec4 ambient,
in vec4 lightPos[LIGHT_COUNT],
in vec4 lightColor[LIGHT_COUNT],
in vec4 pointParams[LIGHT_COUNT],
in vec4 vLightDirView[LIGHT_COUNT],
in vec4 spotParams[LIGHT_COUNT],
in PixelParams pixel,
inout vec3 vOutColour)
{
vOutColour = pow(vOutColour, vec3_splat(2.2)); // gamma to linear
// Energy compensation for multiple scattering in a microfacet model
// See "Multiple-Scattering Microfacet BSDFs with the Smith Model"
pixel.energyCompensation = 1.0 + pixel.f0 * (1.0 / pixel.dfg.y - 1.0);
for(int i = 0; i < LIGHT_COUNT; i++)
{
#ifdef HAVE_AREA_LIGHTS
if(spotParams[i].w == 2.0)
{
// rect area light
vec3 dcol = pixel.diffuseColor;
vec3 scol = pixel.f0;
evaluateRectLight(ltcLUT1, ltcLUT2, pixel.roughness, normalize(vNormal), viewPos,
lightPos[i].xyz, spotParams[i].xyz, pointParams[i].xyz, scol, dcol);
vOutColour += lightColor[i].xyz * (scol + dcol) * 4.0;
continue;
}
#endif
vec3 lightVal = evaluateLight(vNormal, viewPos, lightPos[i], lightColor[i].xyz, pointParams[i], vLightDirView[i], spotParams[i],
pixel);
#ifdef SHADOWLIGHT_COUNT
if(i < SHADOWLIGHT_COUNT)
lightVal *= shadowFactor[i];
#endif
vOutColour += lightVal;
}
vOutColour += pixel.baseColor * pow(ambient.rgb, vec3_splat(2.2));
// linear to gamma
vOutColour = pow(vOutColour, vec3_splat(1.0/2.2));
vOutColour = saturate(vOutColour);
}
#endif

View File

@@ -0,0 +1,172 @@
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org
Copyright (c) 2000-2014 Torus Knot Software Ltd
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.
-----------------------------------------------------------------------------
*/
//These functions are based on dqs.cg from http://isg.cs.tcd.ie/kavanl/dq/
/* dqs.cg
Dual quaternion skinning vertex shaders (no shading computations)
Version 1.0.3, November 1st, 2007
Copyright (C) 2006-2007 University of Dublin, Trinity College, All Rights
Reserved
This software is provided 'as-is', without any express or implied
warranty. In no event will the author(s) 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.
Author: Ladislav Kavan, kavanl@cs.tcd.ie
*/
//-----------------------------------------------------------------------------
// Program Name: SGXLib_DualQuaternion
// Program Desc: Dual quaternion skinning functions.
// Program Type: Vertex shader
// Language: GLSL
//-----------------------------------------------------------------------------
#if defined(OGRE_HLSL) || defined(OGRE_CG)
// this is technically wrong, thats why we dont put it into OgreUnifiedShader.h
#define mat2x4 float2x4
#define mat3x4 float3x4
#endif
//-----------------------------------------------------------------------------
void SGX_BlendWeight(in float blendWgt, in mat2x4 dualQuaternion, out mat2x4 vOut)
{
vOut = blendWgt*dualQuaternion;
}
//-----------------------------------------------------------------------------
void SGX_BlendWeight(in float blendWgt, in mat3x4 scaleShearMatrix, out mat3x4 vOut)
{
vOut = blendWgt*scaleShearMatrix;
}
//-----------------------------------------------------------------------------
// Adjusts the sign of a dual quaternion depending on its orientation to the root dual quaternion
void SGX_AntipodalityAdjustment(in mat2x4 dq0, in mat2x4 dq1,out mat2x4 dq2)
{
//Accurate antipodality handling. For speed increase, remove the following line,
//though, the results will only be valid for rotations less than 180 degrees.
dq2 = (dot(dq0[0], dq1[0]) < 0.0) ? dq1 * -1.0 : dq1;
}
//-----------------------------------------------------------------------------
void SGX_CalculateBlendPosition(in vec3 position, in mat2x4 blendDQ, out vec4 vOut)
{
vec3 blendPosition = position + 2.0*cross(blendDQ[0].yzw, cross(blendDQ[0].yzw, position) + blendDQ[0].x*position);
vec3 trans = 2.0*(blendDQ[0].x*blendDQ[1].yzw - blendDQ[1].x*blendDQ[0].yzw + cross(blendDQ[0].yzw, blendDQ[1].yzw));
blendPosition += trans;
vOut = vec4(blendPosition, 1.0);
}
//-----------------------------------------------------------------------------
void SGX_CalculateBlendNormal(in vec3 normal, in mat2x4 blendDQ, out vec3 vOut)
{
vOut = normal + 2.0*cross(blendDQ[0].yzw, cross(blendDQ[0].yzw, normal) + blendDQ[0].x*normal);
}
//-----------------------------------------------------------------------------
void SGX_AdjointTransposeMatrix(in mat3x4 M, out mat3 vOut)
{
mat3 atM;
atM[0][0] = M[2][2] * M[1][1] - M[1][2] * M[2][1];
atM[0][1] = M[1][2] * M[2][0] - M[1][0] * M[2][2];
atM[0][2] = M[1][0] * M[2][1] - M[2][0] * M[1][1];
atM[1][0] = M[0][2] * M[2][1] - M[2][2] * M[0][1];
atM[1][1] = M[2][2] * M[0][0] - M[0][2] * M[2][0];
atM[1][2] = M[2][0] * M[0][1] - M[0][0] * M[2][1];
atM[2][0] = M[1][2] * M[0][1] - M[0][2] * M[1][1];
atM[2][1] = M[1][0] * M[0][2] - M[1][2] * M[0][0];
atM[2][2] = M[0][0] * M[1][1] - M[1][0] * M[0][1];
vOut = atM;
}
//-----------------------------------------------------------------------------
void blendBonesDQ(mat2x4 bones_dq[BONE_COUNT], vec4 indices, vec4 weights, out mat2x4 blendDQ)
{
blendDQ = bones_dq[int(indices.x)] * weights.x;
mat2x4 dqi;
#ifdef CORRECT_ANTIPODALITY
mat2x4 dq0 = blendDQ;
#endif
#if WEIGHT_COUNT > 1
dqi = bones_dq[int(indices.y)] * weights.y;
# ifdef CORRECT_ANTIPODALITY
SGX_AntipodalityAdjustment(dq0, dqi, dqi);
# endif
blendDQ += dqi;
#endif
#if WEIGHT_COUNT > 2
dqi = bones_dq[int(indices.z)] * weights.z;
# ifdef CORRECT_ANTIPODALITY
SGX_AntipodalityAdjustment(dq0, dqi, dqi);
# endif
blendDQ += dqi;
#endif
#if WEIGHT_COUNT > 3
dqi = bones_dq[int(indices.w)] * weights.w;
# ifdef CORRECT_ANTIPODALITY
SGX_AntipodalityAdjustment(dq0, dqi, dqi);
# endif
blendDQ += dqi;
#endif
blendDQ /= length(blendDQ[0]); // normalise dual quaternion
}
void blendBonesMat3x4(mat3x4 bones_mat[BONE_COUNT], vec4 indices, vec4 weights, out mat3x4 blendMat)
{
blendMat = bones_mat[int(indices.x)] * weights.x;
#if WEIGHT_COUNT > 1
blendMat += bones_mat[int(indices.y)] * weights.y;
#endif
#if WEIGHT_COUNT > 2
blendMat += bones_mat[int(indices.z)] * weights.z;
#endif
#if WEIGHT_COUNT > 3
blendMat += bones_mat[int(indices.w)] * weights.w;
#endif
}

View File

@@ -0,0 +1,183 @@
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org
Copyright (c) 2000-2014 Torus Knot Software Ltd
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.
-----------------------------------------------------------------------------
*/
//-----------------------------------------------------------------------------
// Program Name: SGXLib_IntegratedPSSM
// Program Desc: Integrated PSSM functions.
// Program Type: Vertex/Pixel shader
// Language: GLSL
//-----------------------------------------------------------------------------
#ifdef PSSM_SAMPLE_CMP
#define SAMPLER_TYPE sampler2DShadow
#else
#define SAMPLER_TYPE sampler2D
#endif
// default to 2x2 PCF
#ifndef PCF_XSAMPLES
#define PCF_XSAMPLES 2.0
#endif
//-----------------------------------------------------------------------------
#ifdef SHADOWLIGHT_COUNT
void SGX_ApplyShadowFactor_Modulative(in vec4 ambient,
in float fShadowFactor[SHADOWLIGHT_COUNT],
inout vec4 diffCol
#ifdef USE_SPECULAR
, inout vec4 specCol
#endif
)
{
float shadowFactor = fShadowFactor[0];
for(int i = 1; i < SHADOWLIGHT_COUNT; ++i)
shadowFactor *= fShadowFactor[i];
diffCol.rgb = mix(ambient.rgb, diffCol.rgb, shadowFactor);
#ifdef USE_SPECULAR
specCol.rgb *= shadowFactor;
#endif
}
#endif
float sampleDepth(in SAMPLER_TYPE shadowMap, vec2 uv, float depth)
{
#ifdef PSSM_SAMPLE_CMP
# if defined(OGRE_GLSL) && OGRE_GLSL < 130
return shadow2D(shadowMap, vec3(uv, depth)).r;
# else
return shadow2D(shadowMap, vec3(uv, depth));
# endif
#else
return (depth <= texture2D(shadowMap, uv).r) ? 1.0 : 0.0;
#endif
}
//-----------------------------------------------------------------------------
#ifdef PSSM_SAMPLE_COLOUR
void SGX_ShadowPCF4(in sampler2D shadowMap, in vec4 shadowMapPos, in vec2 invTexSize, out float c)
{
c = texture2DProj(shadowMap, shadowMapPos).x;
}
#else
void SGX_ShadowPCF4(in SAMPLER_TYPE shadowMap, in vec4 shadowMapPos, in vec2 invTexSize, out float c)
{
shadowMapPos = shadowMapPos / shadowMapPos.w;
#if !defined(OGRE_REVERSED_Z) && !defined(OGRE_HLSL) && !defined(VULKAN)
shadowMapPos.z = shadowMapPos.z * 0.5 + 0.5; // convert -1..1 to 0..1
#endif
vec2 uv = shadowMapPos.xy;
// depth must be clamped to support floating-point depth formats. This is to avoid comparing a
// value from the depth texture (which is never greater than 1.0) with a greater-than-one
// comparison value (which is possible with floating-point formats).
float depth = clamp(shadowMapPos.z, 0.0, 1.0);
c = 0.0;
float scale = 1.0;
float offset = (PCF_XSAMPLES / 2.0 - 0.5) * scale;
for (float y = -offset; y <= offset; y += scale)
for (float x = -offset; x <= offset; x += scale)
c += sampleDepth(shadowMap, uv + invTexSize * vec2(x, y), depth);
c /= PCF_XSAMPLES * PCF_XSAMPLES;
}
#endif
//-----------------------------------------------------------------------------
void SGX_ComputeShadowFactor_PSSM3(in float fDepth,
in vec4 vSplitPoints,
in vec4 lightPosition0,
in SAMPLER_TYPE shadowMap0,
in vec2 invShadowMapSize0,
#if PSSM_NUM_SPLITS > 2
in vec4 lightPosition1,
in SAMPLER_TYPE shadowMap1,
in vec2 invShadowMapSize1,
#endif
#if PSSM_NUM_SPLITS > 3
in vec4 lightPosition2,
in SAMPLER_TYPE shadowMap2,
in vec2 invShadowMapSize2,
#endif
in vec4 lightPosition3,
in SAMPLER_TYPE shadowMap3,
in vec2 invShadowMapSize3,
out float oShadowFactor
#ifdef DEBUG_PSSM
, out vec4 oDiffuse
#endif
)
{
#if !defined(OGRE_REVERSED_Z) && !defined(OGRE_HLSL) && !defined(VULKAN)
vSplitPoints = vSplitPoints * 0.5 + 0.5; // convert -1..1 to 0..1
#endif
#ifdef OGRE_REVERSED_Z
vSplitPoints = vec4_splat(1.0) - vSplitPoints;
fDepth = 1.0 - fDepth;
#endif
if (fDepth <= vSplitPoints.x)
{
SGX_ShadowPCF4(shadowMap0, lightPosition0, invShadowMapSize0, oShadowFactor);
#ifdef DEBUG_PSSM
oDiffuse.r += 1.0;
#endif
}
#if PSSM_NUM_SPLITS > 2
else if (fDepth <= vSplitPoints.y)
{
SGX_ShadowPCF4(shadowMap1, lightPosition1, invShadowMapSize1, oShadowFactor);
#ifdef DEBUG_PSSM
oDiffuse.g += 1.0;
#endif
}
#endif
#if PSSM_NUM_SPLITS > 3
else if (fDepth <= vSplitPoints.z)
{
SGX_ShadowPCF4(shadowMap2, lightPosition2, invShadowMapSize2, oShadowFactor);
#ifdef DEBUG_PSSM
oDiffuse.r += 1.0;
oDiffuse.g += 1.0;
#endif
}
#endif
else if (fDepth <= vSplitPoints.w)
{
SGX_ShadowPCF4(shadowMap3, lightPosition3, invShadowMapSize3, oShadowFactor);
#ifdef DEBUG_PSSM
oDiffuse.b += 1.0;
#endif
}
else
{
// behind far distance
oShadowFactor = 1.0;
}
}

View File

@@ -0,0 +1,825 @@
/*
** layered blending & misc math
** Blending modes, RGB/HSL/Contrast/Desaturate, levels control
**
** The shaders below are base on the shaders created by:
** Romain Dura | Romz
** Blog: http://blog.mouaif.org
** Post: http://blog.mouaif.org/?p=94
*/
/*
** Desaturation
*/
vec4 Desaturate(in vec3 color, in float Desaturation)
{
vec3 grayXfer = vec3(0.3, 0.59, 0.11);
float grayf = dot(grayXfer, color);
vec3 gray = vec3(grayf, grayf, grayf);
return vec4(mix(color, gray, Desaturation), 1.0);
}
/*
** Hue, saturation, luminance
*/
vec3 RGBToHSL(in vec3 color)
{
vec3 hsl; // init to 0 to avoid warnings ? (and reverse if + remove first part)
float fmin = min(min(color.r, color.g), color.b); //Min. value of RGB
float fmax = max(max(color.r, color.g), color.b); //Max. value of RGB
float delta = fmax - fmin; //Delta RGB value
hsl.z = (fmax + fmin) / 2.0; // Luminance
if (delta == 0.0) //This is a gray, no chroma...
{
hsl.x = 0.0; // Hue
hsl.y = 0.0; // Saturation
}
else //Chromatic data...
{
if (hsl.z < 0.5)
hsl.y = delta / (fmax + fmin); // Saturation
else
hsl.y = delta / (2.0 - fmax - fmin); // Saturation
float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;
float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;
float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;
if (color.r == fmax )
hsl.x = deltaB - deltaG; // Hue
else if (color.g == fmax)
hsl.x = (1.0 / 3.0) + deltaR - deltaB; // Hue
else if (color.b == fmax)
hsl.x = (2.0 / 3.0) + deltaG - deltaR; // Hue
if (hsl.x < 0.0)
hsl.x += 1.0; // Hue
else if (hsl.x > 1.0)
hsl.x -= 1.0; // Hue
}
return hsl;
}
float HueToRGB(in float f1, in float f2, in float hue)
{
if (hue < 0.0)
hue += 1.0;
else if (hue > 1.0)
hue -= 1.0;
float res;
if ((6.0 * hue) < 1.0)
res = f1 + (f2 - f1) * 6.0 * hue;
else if ((2.0 * hue) < 1.0)
res = f2;
else if ((3.0 * hue) < 2.0)
res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;
else
res = f1;
return res;
}
vec3 HSLToRGB(in vec3 hsl)
{
vec3 rgb;
if (hsl.y == 0.0)
rgb = hsl.zzz; // Luminance
else
{
float f2;
if (hsl.z < 0.5)
f2 = hsl.z * (1.0 + hsl.y);
else
f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);
float f1 = 2.0 * hsl.z - f2;
rgb.r = HueToRGB(f1, f2, hsl.x + (1.0/3.0));
rgb.g = HueToRGB(f1, f2, hsl.x);
rgb.b = HueToRGB(f1, f2, hsl.x - (1.0/3.0));
}
return rgb;
}
/*
** Contrast, saturation, brightness
** Code of this function is from TGM's shader pack
** http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=21057
*/
// For all settings: 1.0 = 100% 0.5=50% 1.5 = 150%
vec3 ContrastSaturationBrightness(in vec3 color, in float brt, in float sat, in float con)
{
// Increase or decrease these values to adjust r, g and b color channels separately
const float AvgLumR = 0.5;
const float AvgLumG = 0.5;
const float AvgLumB = 0.5;
const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);
vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);
vec3 brtColor = color * brt;
float intensityf = dot(brtColor, LumCoeff);
vec3 intensity = vec3(intensityf, intensityf, intensityf);
vec3 satColor = mix(intensity, brtColor, sat);
vec3 conColor = mix(AvgLumin, satColor, con);
return conColor;
}
/*
** Float blending modes
** Adapted from here: http://www.nathanm.com/photoshop-blending-math/
** But I modified the HardMix (wrong condition), Overlay, SoftLight, ColorDodge, ColorBurn, VividLight, PinLight (inverted layers) ones to have correct results
*/
#define BlendLinearDodgef BlendAddf
#define BlendLinearBurnf BlendSubtractf
#define BlendAddf(base, blend) min(base + blend, 1.0)
#define BlendSubtractf(base, blend) max(base + blend - 1.0, 0.0)
#define BlendLightenf(base, blend) max(blend, base)
#define BlendDarkenf(base, blend) min(blend, base)
#define BlendScreenf(base, blend) (1.0 - ((1.0 - base) * (1.0 - blend)))
#define BlendOverlayf(base, blend) (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)))
#define BlendSoftLightf(base, blend) ((blend < 0.5) ? (2.0 * base * blend + base * base * (1.0 - 2.0 * blend)) : (sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend)))
#define BlendColorDodgef(base, blend) ((blend == 1.0) ? blend : min(base / (1.0 - blend), 1.0))
#define BlendColorBurnf(base, blend) ((blend == 0.0) ? blend : max((1.0 - ((1.0 - base) / blend)), 0.0))
#define BlendHardMixf(base, blend) ((BlendVividLightf(base, blend) < 0.5) ? 0.0 : 1.0)
/*
** Vector3 blending modes
*/
// Component wise blending
#define Blend1(base, blend, funcf) funcf(base, blend)
#define Blend3(base, blend, funcf) vec3(funcf(base.r, blend.r), funcf(base.g, blend.g), funcf(base.b, blend.b))
#define Blend4(base, blend, funcf) vec4(funcf(base.r, blend.r), funcf(base.g, blend.g), funcf(base.b, blend.b), funcf(base.a, blend.a))
#define BlendNormal(base, blend) (base)
#define BlendMultiply(base, blend) (base * blend)
#define BlendAverage(base, blend) ((base + blend) / 2.0)
#define BlendAdd(base, blend) min(base + blend, 1.0)
#define BlendSubtract(base, blend) max(base + blend - 1.0, 0.0)
#define BlendDifference(base, blend) abs(base - blend)
#define BlendNegation(base, blend) (1.0 - abs(1.0 - base - blend))
#define BlendExclusion(base, blend) (base + blend - 2.0 * base * blend)
#define BlendPhoenix(base, blend) (min(base, blend) - max(base, blend) + 1.0)
#define BlendOpacity(base, blend, F, O) (F(base, blend) * O + blend * (1.0 - O))
// Hue Blend mode creates the result color by combining the luminance and saturation of the base color with the hue of the blend color.
float BlendHue1(in float base, in float blend)
{
return base;
}
vec3 BlendHue3(in vec3 base, in vec3 blend)
{
vec3 baseHSL = RGBToHSL(base);
return HSLToRGB(vec3(RGBToHSL(blend).r, baseHSL.g, baseHSL.b));
}
vec4 BlendHue4(in vec4 base, in vec4 blend)
{
vec3 hue = BlendHue3(base.xyz, blend.xyz);
return vec4(hue.x, hue.y, hue.z, BlendHue1(base.w, blend.w));
}
// Saturation Blend mode creates the result color by combining the luminance and hue of the base color with the saturation of the blend color.
float BlendSaturation1(in float base, in float blend)
{
return base;
}
vec3 BlendSaturation3(in vec3 base, in vec3 blend)
{
vec3 baseHSL = RGBToHSL(base);
return HSLToRGB(vec3(baseHSL.r, RGBToHSL(blend).g, baseHSL.b));
}
vec4 BlendSaturation4(in vec4 base, in vec4 blend)
{
vec3 hue = BlendSaturation3(base.xyz, blend.xyz);
return vec4(hue.x, hue.y, hue.z, BlendSaturation1(base.w, blend.w));
}
// Color Mode keeps the brightness of the base color and applies both the hue and saturation of the blend color.
float BlendColor1(in float base, in float blend)
{
return base;
}
vec3 BlendColor3(in vec3 base, in vec3 blend)
{
vec3 blendHSL = RGBToHSL(blend);
return HSLToRGB(vec3(blendHSL.r, blendHSL.g, RGBToHSL(base).b));
}
vec4 BlendColor4(in vec4 base, in vec4 blend)
{
vec3 hue = BlendColor3(base.xyz, blend.xyz);
return vec4(hue.x, hue.y, hue.z, BlendColor1(base.w, blend.w));
}
// Luminosity Blend mode creates the result color by combining the hue and saturation of the base color with the luminance of the blend color.
float BlendLuminosity1(in float base, in float blend)
{
return base;
}
vec3 BlendLuminosity3(in vec3 base, in vec3 blend)
{
vec3 baseHSL = RGBToHSL(base);
return HSLToRGB(vec3(baseHSL.r, baseHSL.g, RGBToHSL(blend).b));
}
vec4 BlendLuminosity4(in vec4 base, in vec4 blend)
{
vec3 hue = BlendLuminosity3(base.xyz, blend.xyz);
return vec4(hue.x, hue.y, hue.z, BlendLuminosity1(base.w, blend.w));
}
float BlendLinearLightf(in float s1, in float s2)
{
float oColor;
if (s2 < 0.5)
{
float s2x = (2.0 * s2);
oColor = BlendSubtractf(s1, s2x);
}
else
{
float s2x = (2.0 * (s2 - 0.5));
oColor = BlendAddf(s1, s2x);
}
return oColor;
}
float BlendVividLightf(in float s1, in float s2)
{
float oColor;
if (s2 < 0.5)
{
float s2x = (2.0 * s2);
oColor = BlendColorBurnf(s1, s2x);
}
else
{
float s2x = (2.0 * (s2 - 0.5));
oColor = BlendColorDodgef(s1, s2x);
}
return oColor;
}
float BlendPinLightf(in float s1, in float s2)
{
float oColor;
if (s2 < 0.5)
{
float s2x = (2.0 * s2);
oColor = BlendDarkenf(s1, s2x);
}
else
{
float s2x = (2.0 * (s2 - 0.5));
oColor = BlendLightenf(s1, s2x);
}
return oColor;
}
float BlendReflectf(in float s1, in float s2)
{
float oColor;
if (s2 == 1.0)
{
oColor = s2;
}
else
{
float s1x = (s1 * s1) / (1.0 - s2);
oColor = min(s1x, 1.0);
}
return oColor;
}
//------------------------------------
// Interface for RTShader
//------------------------------------
void SGX_blend_normal(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendNormal(basePixel, blendPixel);
}
void SGX_blend_normal(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendNormal(basePixel, blendPixel);
}
void SGX_blend_normal(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendNormal(basePixel, blendPixel);
}
void SGX_blend_lighten(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendLightenf(basePixel, blendPixel);
}
void SGX_blend_lighten(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendLightenf(basePixel, blendPixel);
}
void SGX_blend_lighten(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendLightenf(basePixel, blendPixel);
}
void SGX_blend_darken(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendDarkenf(basePixel, blendPixel);
}
void SGX_blend_darken(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendDarkenf(basePixel, blendPixel);
}
void SGX_blend_darken(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendDarkenf(basePixel, blendPixel);
}
void SGX_blend_multiply(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendMultiply(basePixel, blendPixel);
}
void SGX_blend_multiply(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendMultiply(basePixel, blendPixel);
}
void SGX_blend_multiply(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendMultiply(basePixel, blendPixel);
}
void SGX_blend_average(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendAverage(basePixel, blendPixel);
}
void SGX_blend_average(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendAverage(basePixel, blendPixel);
}
void SGX_blend_average(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendAverage(basePixel, blendPixel);
}
void SGX_blend_add(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendAdd(basePixel, blendPixel);
}
void SGX_blend_add(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendAdd(basePixel, blendPixel);
}
void SGX_blend_add(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendAdd(basePixel, blendPixel);
}
void SGX_blend_subtract(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendSubtract(basePixel, blendPixel);
}
void SGX_blend_subtract(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendSubtract(basePixel, blendPixel);
}
void SGX_blend_subtract(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendSubtract(basePixel, blendPixel);
}
void SGX_blend_difference(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendDifference(basePixel, blendPixel);
}
void SGX_blend_difference(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendDifference(basePixel, blendPixel);
}
void SGX_blend_difference(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendDifference(basePixel, blendPixel);
}
void SGX_blend_negation(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendNegation(basePixel, blendPixel);
}
void SGX_blend_negation(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendNegation(basePixel, blendPixel);
}
void SGX_blend_negation(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendNegation(basePixel, blendPixel);
}
void SGX_blend_exclusion(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendExclusion(basePixel, blendPixel);
}
void SGX_blend_exclusion(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendExclusion(basePixel, blendPixel);
}
void SGX_blend_exclusion(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendExclusion(basePixel, blendPixel);
}
void SGX_blend_screen(in vec4 s1, in vec4 s2, out vec4 oColor)
{
oColor = vec4(BlendScreenf(s1.r, s2.r),
BlendScreenf(s1.g, s2.g),
BlendScreenf(s1.b, s2.b),
BlendScreenf(s1.a, s2.a));
}
void SGX_blend_screen(in vec3 s1, in vec3 s2, out vec3 oColor)
{
oColor = vec3(BlendScreenf(s1.r, s2.r),
BlendScreenf(s1.g, s2.g),
BlendScreenf(s1.b, s2.b));
}
void SGX_blend_screen(in float s1, in float s2, out float oColor)
{
oColor = BlendScreenf(s1, s2);
}
void SGX_blend_overlay(in vec4 s1, in vec4 s2, out vec4 oColor)
{
oColor = vec4(BlendOverlayf(s1.r, s2.r),
BlendOverlayf(s1.g, s2.g),
BlendOverlayf(s1.b, s2.b),
BlendOverlayf(s1.a, s2.a));
}
void SGX_blend_overlay(in vec3 s1, in vec3 s2, out vec3 oColor)
{
oColor = vec3(BlendOverlayf(s1.r, s2.r),
BlendOverlayf(s1.g, s2.g),
BlendOverlayf(s1.b, s2.b));
}
void SGX_blend_overlay(in float s1, in float s2, out float oColor)
{
oColor = BlendOverlayf(s1, s2);
}
void SGX_blend_softLight(in vec4 s1, in vec4 s2, out vec4 oColor)
{
oColor = vec4(BlendSoftLightf(s1.r, s2.r),
BlendSoftLightf(s1.g, s2.g),
BlendSoftLightf(s1.b, s2.b),
BlendSoftLightf(s1.a, s2.a));
}
void SGX_blend_softLight(in vec3 s1, in vec3 s2, out vec3 oColor)
{
oColor = vec3(BlendSoftLightf(s1.r, s2.r),
BlendSoftLightf(s1.g, s2.g),
BlendSoftLightf(s1.b, s2.b));
}
void SGX_blend_softLight(in float s1, in float s2, out float oColor)
{
oColor = BlendSoftLightf(s1, s2);
}
void SGX_blend_hardLight(in vec4 s1, in vec4 s2, out vec4 oColor)
{
oColor = vec4(BlendOverlayf(s1.r, s2.r),
BlendOverlayf(s1.g, s2.g),
BlendOverlayf(s1.b, s2.b),
BlendOverlayf(s1.a, s2.a));
}
void SGX_blend_hardLight(in vec3 s1, in vec3 s2, out vec3 oColor)
{
oColor = vec3(BlendOverlayf(s1.r, s2.r),
BlendOverlayf(s1.g, s2.g),
BlendOverlayf(s1.b, s2.b));
}
void SGX_blend_hardLight(in float s1, in float s2, out float oColor)
{
oColor = BlendOverlayf(s1, s2);
}
void SGX_blend_colorDodge(in vec4 s1, in vec4 s2, out vec4 oColor)
{
oColor = vec4(BlendColorDodgef(s1.r, s2.r),
BlendColorDodgef(s1.g, s2.g),
BlendColorDodgef(s1.b, s2.b),
BlendColorDodgef(s1.a, s2.a));
}
void SGX_blend_colorDodge(in vec3 s1, in vec3 s2, out vec3 oColor)
{
oColor = vec3(BlendColorDodgef(s1.r, s2.r),
BlendColorDodgef(s1.g, s2.g),
BlendColorDodgef(s1.b, s2.b));
}
void SGX_blend_colorDodge(in float s1, in float s2, out float oColor)
{
oColor = BlendColorDodgef(s1, s2);
}
void SGX_blend_colorBurn(in vec4 s1, in vec4 s2, out vec4 oColor)
{
oColor = vec4(BlendColorBurnf(s1.r, s2.r),
BlendColorBurnf(s1.g, s2.g),
BlendColorBurnf(s1.b, s2.b),
BlendColorBurnf(s1.a, s2.a));
}
void SGX_blend_colorBurn(in vec3 s1, in vec3 s2, out vec3 oColor)
{
oColor = vec3(BlendColorBurnf(s1.r, s2.r),
BlendColorBurnf(s1.g, s2.g),
BlendColorBurnf(s1.b, s2.b));
}
void SGX_blend_colorBurn(in float s1, in float s2, out float oColor)
{
oColor = BlendColorBurnf(s1, s2);
}
void SGX_blend_linearDodge(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendAddf(basePixel, blendPixel);
}
void SGX_blend_linearDodge(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendAddf(basePixel, blendPixel);
}
void SGX_blend_linearDodge(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendAddf(basePixel, blendPixel);
}
void SGX_blend_linearBurn(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendSubtractf(basePixel, blendPixel);
}
void SGX_blend_linearBurn(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendSubtractf(basePixel, blendPixel);
}
void SGX_blend_linearBurn(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendSubtractf(basePixel, blendPixel);
}
void SGX_blend_linearLight(in vec4 s1, in vec4 s2, out vec4 oColor)
{
oColor = vec4(BlendLinearLightf(s1.r, s2.r),
BlendLinearLightf(s1.g, s2.g),
BlendLinearLightf(s1.b, s2.b),
BlendLinearLightf(s1.a, s2.a));
}
void SGX_blend_linearLight(in vec3 s1, in vec3 s2, out vec3 oColor)
{
oColor = vec3(BlendLinearLightf(s1.r, s2.r),
BlendLinearLightf(s1.g, s2.g),
BlendLinearLightf(s1.b, s2.b));
}
void SGX_blend_linearLight(in float s1, in float s2, out float oColor)
{
oColor = BlendLinearLightf(s1, s2);
}
void SGX_blend_vividLight(in vec4 s1, in vec4 s2, out vec4 oColor)
{
oColor = vec4(BlendVividLightf(s1.r, s2.r),
BlendVividLightf(s1.g, s2.g),
BlendVividLightf(s1.b, s2.b),
BlendVividLightf(s1.a, s2.a));
}
void SGX_blend_vividLight(in vec3 s1, in vec3 s2, out vec3 oColor)
{
oColor = vec3(BlendVividLightf(s1.r, s2.r),
BlendVividLightf(s1.g, s2.g),
BlendVividLightf(s1.b, s2.b));
}
void SGX_blend_vividLight(in float s1, in float s2, out float oColor)
{
oColor = BlendVividLightf(s1, s2);
}
void SGX_blend_pinLight(in vec4 s1, in vec4 s2, out vec4 oColor)
{
oColor = vec4(BlendPinLightf(s1.r, s2.r),
BlendPinLightf(s1.g, s2.g),
BlendPinLightf(s1.b, s2.b),
BlendPinLightf(s1.a, s2.a));
}
void SGX_blend_pinLight(in vec3 s1, in vec3 s2, out vec3 oColor)
{
oColor = vec3(BlendPinLightf(s1.r, s2.r),
BlendPinLightf(s1.g, s2.g),
BlendPinLightf(s1.b, s2.b));
}
void SGX_blend_pinLight(in float s1, in float s2, out float oColor)
{
oColor = BlendPinLightf(s1, s2);
}
void SGX_blend_hardMix(in vec4 s1, in vec4 s2, out vec4 oColor)
{
oColor = vec4(BlendHardMixf(s1.r, s2.r),
BlendHardMixf(s1.g, s2.g),
BlendHardMixf(s1.b, s2.b),
BlendHardMixf(s1.a, s2.a));
}
void SGX_blend_hardMix(in vec3 s1, in vec3 s2, out vec3 oColor)
{
oColor = vec3(BlendHardMixf(s1.r, s2.r),
BlendHardMixf(s1.g, s2.g),
BlendHardMixf(s1.b, s2.b));
}
void SGX_blend_hardMix(in float s1, in float s2, out float oColor)
{
oColor = BlendHardMixf(s1, s2);
}
void SGX_blend_reflect(in vec4 s1, in vec4 s2, out vec4 oColor)
{
oColor = vec4(BlendReflectf(s1.r, s2.r),
BlendReflectf(s1.g, s2.g),
BlendReflectf(s1.b, s2.b),
BlendReflectf(s1.a, s2.a));
}
void SGX_blend_reflect(in vec3 s1, in vec3 s2, out vec3 oColor)
{
oColor = vec3(BlendReflectf(s1.r, s2.r),
BlendReflectf(s1.g, s2.g),
BlendReflectf(s1.b, s2.b));
}
void SGX_blend_reflect(in float s1, in float s2, out float oColor)
{
oColor = BlendReflectf(s1, s2);
}
void SGX_blend_glow(in vec4 s1, in vec4 s2, out vec4 oColor)
{
oColor = vec4(BlendReflectf(s1.r, s2.r),
BlendReflectf(s1.g, s2.g),
BlendReflectf(s1.b, s2.b),
BlendReflectf(s1.a, s2.a));
}
void SGX_blend_glow(in vec3 s1, in vec3 s2, out vec3 oColor)
{
oColor = vec3(BlendReflectf(s1.r, s2.r),
BlendReflectf(s1.g, s2.g),
BlendReflectf(s1.b, s2.b));
}
void SGX_blend_glow(in float s1, in float s2, out float oColor)
{
oColor = BlendReflectf(s1, s2);
}
void SGX_blend_phoenix(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendPhoenix(basePixel, blendPixel);
}
void SGX_blend_phoenix(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendPhoenix(basePixel, blendPixel);
}
void SGX_blend_phoenix(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendPhoenix(basePixel, blendPixel);
}
void SGX_blend_saturation(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendSaturation4(basePixel, blendPixel);
}
void SGX_blend_saturation(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendSaturation3(basePixel, blendPixel);
}
void SGX_blend_saturation(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendSaturation1(basePixel, blendPixel);
}
void SGX_blend_color(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendColor4(basePixel, blendPixel);
}
void SGX_blend_color(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendColor3(basePixel, blendPixel);
}
void SGX_blend_color(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendColor1(basePixel, blendPixel);
}
void SGX_blend_luminosity(in vec4 basePixel, in vec4 blendPixel, out vec4 oColor)
{
oColor = BlendLuminosity4(basePixel, blendPixel);
}
void SGX_blend_luminosity(in vec3 basePixel, in vec3 blendPixel, out vec3 oColor)
{
oColor = BlendLuminosity3(basePixel, blendPixel);
}
void SGX_blend_luminosity(in float basePixel, in float blendPixel, out float oColor)
{
oColor = BlendLuminosity1(basePixel, blendPixel);
}
////////////////////////////////////////////////////////////////////////////////////
/// Source modification functions
////////////////////////////////////////////////////////////////////////////////////
void SGX_src_mod_modulate(in vec4 iColor, in vec4 controlVal, out vec4 oColor)
{
oColor = iColor * controlVal;
}
void SGX_src_mod_modulate(in vec3 iColor, in vec3 controlVal, out vec3 oColor)
{
oColor = iColor * controlVal;
}
void SGX_src_mod_modulate(in float iColor, in float controlVal, out float oColor)
{
oColor = iColor * controlVal;
}
void SGX_src_mod_inv_modulate(in vec4 iColor, in vec4 controlVal, out vec4 oColor)
{
oColor = mix(iColor, vec4(1.0,1.0,1.0,1.0), controlVal);
}
void SGX_src_mod_inv_modulate(in vec3 iColor, in vec3 controlVal, out vec3 oColor)
{
oColor = mix(iColor, vec3(1.0,1.0,1.0), controlVal);
}
void SGX_src_mod_inv_modulate(in float iColor, in float controlVal, out float oColor)
{
oColor = mix(iColor, 1.0, controlVal);
}

View File

@@ -0,0 +1,125 @@
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org
Copyright (c) 2000-2014 Torus Knot Software Ltd
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.
-----------------------------------------------------------------------------
*/
//-----------------------------------------------------------------------------
// Program Name: SGXLib_NormalMapLighting
// Program Desc: Normal map lighting functions.
// Program Type: Vertex/Pixel shader
// Language: GLSL
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void SGX_FetchNormal(in sampler2D s,
in vec2 uv,
out vec3 vOut)
{
vOut = 2.0 * texture2D(s, uv).xyz - 1.0;
}
//-----------------------------------------------------------------------------
void SGX_CalculateTBN(in vec3 vNormal,
in vec4 vTangent,
out mat3 TBN)
{
vec3 vBinormal = cross(vNormal, vTangent.xyz) * vTangent.w;
// direction: from tangent space to world
TBN = mtxFromCols(vTangent.xyz, vBinormal, vNormal);
}
//-----------------------------------------------------------------------------
void SGX_Generate_Parallax_Texcoord(in sampler2D normalHeightMap,
in vec2 texCoord,
in vec3 viewPos,
in float heightScale,
in mat3 TBN,
out vec2 newTexCoord)
{
//Calculate eye direction
vec3 eyeVec = mul(-viewPos, TBN);
eyeVec = normalize(eyeVec);
#ifndef TERRAIN_PARALLAX_MAPPING
eyeVec.y = -eyeVec.y; //Inverse y
#endif
newTexCoord = texCoord;
#ifndef POM_LAYER_COUNT
//Simple parallax mapping
float height = 1.0f - texture2D(normalHeightMap, newTexCoord).a;
#ifndef TERRAIN_PARALLAX_MAPPING
vec2 p = eyeVec.xy / eyeVec.z * (height * heightScale);
#else
vec2 p = eyeVec.xy * (height * heightScale);
#endif
newTexCoord = newTexCoord - p;
#else
// parallax occlusion mapping
#ifdef POM_MAX_DISTANCE
if (abs(viewPos.z) > POM_MAX_DISTANCE)
return;
#endif
//Configure steep mapping layering.
float layerDepth = 1.0 / float(POM_LAYER_COUNT);
float currentLayerDepth = 0.0;
vec2 parallaxShift = (eyeVec.xy) * heightScale;
vec2 deltaTexCoords = parallaxShift / float(POM_LAYER_COUNT);
float currentDepthMapValue = 1.0f - texture2D(normalHeightMap, newTexCoord).a;
//Loop through layers and break early if match found.
for (int currentLayerId = 0; currentLayerId < POM_LAYER_COUNT; currentLayerId++)
{
// shift texture coordinates along direction of P
newTexCoord -= deltaTexCoords;
// get depthmap value at current texture coordinates
currentDepthMapValue = 1.0f - texture2D(normalHeightMap, newTexCoord).a;
//Break if layer height matched
if (currentLayerDepth > currentDepthMapValue)
break;
// get depth of next layer
currentLayerDepth += layerDepth;
}
// get texture coordinates before collision (reverse operations)
vec2 prevTexCoords = newTexCoord + deltaTexCoords;
// get depth after and before collision for linear interpolation
float afterDepth = currentDepthMapValue - currentLayerDepth;
float beforeDepth = (1.0f - texture2D(normalHeightMap, prevTexCoords).a) - currentLayerDepth + layerDepth;
// interpolation of texture coordinates
float weight = afterDepth / (afterDepth - beforeDepth);
newTexCoord = mix(newTexCoord, prevTexCoords, weight);
#endif
}

View File

@@ -0,0 +1,172 @@
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org
Copyright (c) 2000-2014 Torus Knot Software Ltd
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.
-----------------------------------------------------------------------------
*/
//-----------------------------------------------------------------------------
// Program Name: SGXLib_Lighting
// Program Desc: Per pixel lighting functions.
// Program Type: Vertex/Pixel shader
// Language: GLSL
// Notes: Implements core functions for FFPLighting class.
// based on lighting engine.
// See http://msdn.microsoft.com/en-us/library/bb147178.aspx
//-----------------------------------------------------------------------------
#include "RTSLib_Lighting.glsl"
#ifdef HAVE_AREA_LIGHTS
#include "RTSLib_LTC.glsl"
#endif
#ifdef OGRE_HLSL
void SGX_Flip_Backface_Normal(in float triArea, in float targetFlipped, inout vec3 normal)
{
#if OGRE_HLSL == 3
triArea *= -1.0;
triArea *= targetFlipped;
#endif
if(triArea < 0.0)
normal *= -1.0;
}
#else
void SGX_Flip_Backface_Normal(in bool frontFacing, in float targetFlipped, inout vec3 normal)
{
if(!frontFacing)
normal *= -1.0;
}
#endif
void evaluateLight(
in vec3 vNormal,
in vec3 vViewPos,
in vec4 vLightPos,
in vec4 vAttParams,
in vec4 vLightDirView,
in vec4 spotParams,
in vec4 vDiffuseColour,
inout vec3 vOutDiffuse
#if defined(TVC_DIFFUSE) || defined(TVC_SPECULAR)
, in vec4 vInVertexColour
#endif
#ifdef USE_SPECULAR
, in vec4 vSpecularColour,
in float fSpecularPower,
inout vec3 vOutSpecular
#endif
#ifdef SHADOWLIGHT_COUNT
, in float shadowFactor
#endif
#ifdef HAVE_AREA_LIGHTS
, in sampler2D ltcLUT1,
in sampler2D ltcLUT2
#endif
)
{
vec3 vLightView = vLightPos.xyz;
float fLightD = 0.0;
#ifdef TVC_DIFFUSE
vDiffuseColour *= vInVertexColour;
#endif
#ifdef HAVE_AREA_LIGHTS
if(spotParams.w == 2.0)
{
// rect area light
vec3 dcol = vDiffuseColour.rgb;
#ifdef USE_SPECULAR
#ifdef TVC_SPECULAR
vSpecularColour *= vInVertexColour;
#endif
vec3 scol = vSpecularColour.rgb;
#else
vec3 scol = vec3_splat(0.0);
float fSpecularPower = 0.0;
#endif
float roughness = saturate(1.0 - fSpecularPower/128.0); // convert specular to roughness
roughness *= roughness; // perceptual to physical roughness
evaluateRectLight(ltcLUT1, ltcLUT2, roughness, normalize(vNormal), vViewPos, vLightPos.xyz, spotParams.xyz, vAttParams.xyz, scol, dcol);
#ifdef SHADOWLIGHT_COUNT
dcol *= shadowFactor;
scol *= shadowFactor;
#endif
// linear to gamma
dcol = pow(dcol, vec3_splat(1.0/2.2));
vOutDiffuse.rgb = saturate(vOutDiffuse.rgb + dcol);
#ifdef USE_SPECULAR
scol = pow(scol, vec3_splat(1.0/2.2));
vOutSpecular.rgb = saturate(vOutSpecular.rgb + scol);
#endif
return;
}
#endif
if (vLightPos.w != 0.0)
{
vLightView -= vViewPos; // to light
fLightD = length(vLightView);
if(fLightD > vAttParams.x)
return;
}
vLightView = normalize(vLightView);
vec3 vNormalView = normalize(vNormal);
float nDotL = saturate(dot(vNormalView, vLightView));
if (nDotL <= 0.0)
return;
float fAtten = getDistanceAttenuation(vAttParams.yzw, fLightD);
#ifdef SHADOWLIGHT_COUNT
fAtten *= shadowFactor;
#endif
if(spotParams.w != 0.0)
{
fAtten *= getAngleAttenuation(spotParams.xyz, vLightDirView.xyz, vLightView);
}
vOutDiffuse += vDiffuseColour.rgb * nDotL * fAtten;
vOutDiffuse = saturate(vOutDiffuse);
#ifdef USE_SPECULAR
vec3 vView = -normalize(vViewPos);
vec3 vHalfWay = normalize(vView + vLightView);
float nDotH = saturate(dot(vNormalView, vHalfWay));
#ifdef TVC_SPECULAR
vSpecularColour *= vInVertexColour;
#endif
#ifdef NORMALISED
vSpecularColour *= (fSpecularPower + 8.0)/(8.0 * M_PI);
#endif
vOutSpecular += vSpecularColour.rgb * pow(nDotH, fSpecularPower) * fAtten;
vOutSpecular = saturate(vOutSpecular);
#endif
}

View File

@@ -0,0 +1,47 @@
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org
Copyright (c) 2000-2014 Torus Knot Software Ltd
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.
-----------------------------------------------------------------------------
*/
void SGX_TriplanarTexturing(in vec4 diffuse, in vec3 normal, in vec4 position, in sampler2D texFromX, in sampler2D texFromY, in sampler2D texFromZ, in vec3 parameters, out vec4 cOut)
{
vec3 blendWeights = abs(normalize(normal));
blendWeights = blendWeights - parameters.y;
blendWeights = pow(max(blendWeights, vec3(0.0, 0.0, 0.0)), parameters.zzz);
float tot = (blendWeights.x + blendWeights.y + blendWeights.z);
blendWeights /= vec3(tot, tot, tot);
// Move the planar mapping a bit according to the normal length to avoid bad looking skirts.
float nLength = length(normal - 1.0);
vec2 coord1 = (position.yz + nLength) * parameters.x;
vec2 coord2 = (position.zx + nLength) * parameters.x;
vec2 coord3 = (position.xy + nLength) * parameters.x;
vec4 col1 = texture2D(texFromX, coord1);
vec4 col2 = texture2D(texFromY, coord2);
vec4 col3 = texture2D(texFromZ, coord3);
cOut = diffuse * vec4(col1.xyz * blendWeights.x +
col2.xyz * blendWeights.y +
col3.xyz * blendWeights.z, 1);
}

View File

@@ -0,0 +1,19 @@
// This file is part of the OGRE project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at https://www.ogre3d.org/licensing.
// SPDX-License-Identifier: MIT
float weight(float z, float a)
{
// from https://casual-effects.blogspot.com/2015/03/implemented-weighted-blended-order.html
return clamp(pow(min(1.0, a * 10.0) + 0.01, 3.0) * 1e8 * pow(1.0 - z * 0.9, 3.0), 1e-2, 3e3);
}
void SGX_WBOIT(float depth, inout vec4 accum, out vec4 revealage)
{
vec4 colour = accum;
// Weighted Blended Order-Independent Transparency, Listing 4
float w = weight(depth, colour.a);
accum = vec4(colour.rgb * w * colour.a, colour.a);
revealage = vec4_splat(colour.a * w);
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
Textures are CC0 from https://cc0textures.com/ adapted for Ogre

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,83 @@
void transformToTS(in vec3 TSnormal, in mat3 normalMatrix, inout vec3 normal)
{
// derive the tangent space basis
// we do this in the pixel shader because we don't have per-vertex normals
// because of the LOD, we use a normal map
// tangent is always +x or -z in object space depending on alignment
#ifdef TERRAIN_ALIGN_Y_Z
vec3 tangent = vec3(0, 0, -1);
#else
vec3 tangent = vec3(1, 0, 0);
#endif
normal = normalize(normal);
tangent = normalize(mul(normalMatrix, tangent));
vec3 binormal = cross(tangent, normal);
// note, now we need to re-cross to derive tangent again because it wasn't orthonormal
tangent = cross(normal, binormal);
// derive final matrix
mat3 TBN = mtxFromCols(tangent, binormal, normal);
normal = mul(TBN, TSnormal);
}
void getShadowFactor(in sampler2D lightmap, in vec2 uv, inout float shadowFactor)
{
float lmShadow = texture2D(lightmap, uv).x;
shadowFactor = min(shadowFactor, lmShadow);
}
#define MIN_BLEND_WEIGHT 0.0039 // 1/255
void blendTerrainLayer(in float blendWeight, in f32vec2 uv0, in float uvMul,
#ifdef TERRAIN_PARALLAX_MAPPING
in vec3 viewPos, in float scaleBias, in mat3 TBN,
#endif
#ifdef TERRAIN_NORMAL_MAPPING
in sampler2D normtex, inout vec3 normal,
#endif
in sampler2D difftex, inout vec4 diffuseSpec)
{
if(blendWeight < MIN_BLEND_WEIGHT)
return;
// generate UV
vec2 uv = mod(uv0 * uvMul, 1.0);
#ifdef TERRAIN_PARALLAX_MAPPING
SGX_Generate_Parallax_Texcoord(normtex, uv, viewPos, scaleBias, TBN, uv);
#endif
// sample diffuse texture
vec4 diffuseSpecTex = texture2D(difftex, uv);
// apply to common
diffuseSpec = mix(diffuseSpec, diffuseSpecTex, blendWeight);
#ifdef TERRAIN_NORMAL_MAPPING
vec3 TSnormal;
// access TS normal map
SGX_FetchNormal(normtex, uv, TSnormal);
// Partial Derivative Blending https://blog.selfshadow.com/publications/blending-in-detail/
normal = normalize(vec3(mix(normal.xy*TSnormal.z, TSnormal.xy*normal.z, blendWeight), TSnormal.z*normal.z));
#endif
}
//-----------------------------------------------------------------------------
void SGX_CalculateTerrainTBN(in vec3 normal, in mat3 normalMatrix, out mat3 TBN)
{
// derive the tangent space basis
// we do this in the pixel shader because we don't have per-vertex normals
// because of the LOD, we use a normal map
// tangent is always +x or -z in object space depending on alignment
#ifdef TERRAIN_ALIGN_Y_Z
vec3 tangent = vec3(0, 0, -1);
#else
vec3 tangent = vec3(1, 0, 0);
#endif
normal = normalize(normal);
tangent = normalize(mul(normalMatrix, tangent));
vec3 binormal = cross(tangent, normal);
// note, now we need to re-cross to derive tangent again because it wasn't orthonormal
tangent = cross(normal, binormal);
// derive final matrix
TBN = mtxFromCols(tangent, binormal, normal);
}

View File

@@ -0,0 +1,36 @@
/**
* @param delta: lodDelta, lodThreshold (vertex attribute)
* @param lodMorph: morph amount, morph targetLOD (uniform)
*/
void applyLODMorph(vec2 delta, vec2 lodMorph, inout float height
#ifdef TERRAIN_DEBUG
, out vec2 lodInfo
#endif
)
{
// determine whether to apply the LOD morph to this vertex
// we store the deltas against all vertices so we only want to apply
// the morph to the ones which would disappear.
// If we subtract
// the lodThreshold from the targetLOD, and arrange to only morph if the
// result is negative (it will only be -1 in fact, since after that
// the vertex will never be indexed), we will achieve our aim.
// sign(lodThreshold - targetLOD) == -1 is to morph
// this will either be 1 (morph) or 0 (don't morph)
float toMorph = -min(0.0, sign(delta.y - lodMorph.y));
height += delta.x * toMorph * lodMorph.x;
#ifdef TERRAIN_DEBUG
// LOD level (-1 since value is target level, we want to display actual)
lodInfo.x = (lodMorph.y - 1) / NUM_LODS;
// LOD morph
lodInfo.y = toMorph * lodMorph.x;
#endif
}
void expandVertex(mat4 idxToObjectSpace, float baseUVScale, vec2 idx, float height, out vec4 position, out vec2 uv)
{
position = mul(idxToObjectSpace, vec4(idx, height, 1));
uv = vec2(idx.x * baseUVScale, 1.0 - idx.y * baseUVScale);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
skybox/early_morning_bk.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
skybox/early_morning_dn.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
skybox/early_morning_fr.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
skybox/early_morning_lf.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
skybox/early_morning_rt.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
skybox/early_morning_up.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

37
skybox/skybox.material Normal file
View File

@@ -0,0 +1,37 @@
material Skybox
{
technique
{
pass
{
lighting off
depth_write off
texture_unit
{
texture early_morning.jpg cubic
tex_address_mode clamp
}
}
}
}
material Skybox/Dynamic
{
technique
{
pass
{
lighting off
depth_write off
ambient 1.0 1.0 1.0 1.0
diffuse 0.0 0.0 1.0 1.0
specular 0.0 0.0 0.0 1.0
vertex_program_ref debug_vp
{
}
fragment_program_ref debug_fp
{
}
}
}
}

30
src/lua/CMakeLists.txt Normal file
View File

@@ -0,0 +1,30 @@
#file(GLOB LUA_SRC lua-5.4.8/src/*.c)
set(LUA_OBJ
# core
lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o
lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o
lparser.o lstate.o lstring.o ltable.o ltm.o
lundump.o lvm.o lzio.o
lauxlib.o lbaselib.o lcorolib.o ldblib.o liolib.o
lmathlib.o loadlib.o loslib.o lstrlib.o ltablib.o
lutf8lib.o linit.o
#lib
lauxlib.o lbaselib.o lcorolib.o ldblib.o liolib.o
lmathlib.o loadlib.o loslib.o lstrlib.o ltablib.o
lutf8lib.o linit.o)
set(LUA_SRC)
foreach(LUA_FILE ${LUA_OBJ})
string(REPLACE ".o" ".c" LUA_SRC_ITEM ${LUA_FILE})
list(APPEND LUA_SRC lua-5.4.8/src/${LUA_SRC_ITEM})
endforeach()
add_library(lua ${LUA_SRC})
target_include_directories(lua PRIVATE lua-5.4.8/src)
add_executable(luavm lua-5.4.8/src/lua.c)
target_link_libraries(luavm lua m)
target_include_directories(luavm PRIVATE lua-5.4.8/src)
add_executable(luac lua-5.4.8/src/luac.c)
target_link_libraries(luac lua m)
target_include_directories(luac PRIVATE lua-5.4.8/src)

106
src/lua/lua-5.4.8/Makefile Normal file
View File

@@ -0,0 +1,106 @@
# Makefile for installing Lua
# See doc/readme.html for installation and customization instructions.
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
# Your platform. See PLATS for possible values.
PLAT= guess
# Where to install. The installation starts in the src and doc directories,
# so take care if INSTALL_TOP is not an absolute path. See the local target.
# You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with
# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h.
INSTALL_TOP= /usr/local
INSTALL_BIN= $(INSTALL_TOP)/bin
INSTALL_INC= $(INSTALL_TOP)/include
INSTALL_LIB= $(INSTALL_TOP)/lib
INSTALL_MAN= $(INSTALL_TOP)/man/man1
INSTALL_LMOD= $(INSTALL_TOP)/share/lua/$V
INSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V
# How to install. If your install program does not support "-p", then
# you may have to run ranlib on the installed liblua.a.
INSTALL= install -p
INSTALL_EXEC= $(INSTALL) -m 0755
INSTALL_DATA= $(INSTALL) -m 0644
#
# If you don't have "install" you can use "cp" instead.
# INSTALL= cp -p
# INSTALL_EXEC= $(INSTALL)
# INSTALL_DATA= $(INSTALL)
# Other utilities.
MKDIR= mkdir -p
RM= rm -f
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
# Convenience platforms targets.
PLATS= guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
# What to install.
TO_BIN= lua luac
TO_INC= lua.h luaconf.h lualib.h lauxlib.h lua.hpp
TO_LIB= liblua.a
TO_MAN= lua.1 luac.1
# Lua version and release.
V= 5.4
R= $V.8
# Targets start here.
all: $(PLAT)
$(PLATS) help test clean:
@cd src && $(MAKE) $@
install: dummy
cd src && $(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD)
cd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN)
cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC)
cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB)
cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN)
uninstall:
cd src && cd $(INSTALL_BIN) && $(RM) $(TO_BIN)
cd src && cd $(INSTALL_INC) && $(RM) $(TO_INC)
cd src && cd $(INSTALL_LIB) && $(RM) $(TO_LIB)
cd doc && cd $(INSTALL_MAN) && $(RM) $(TO_MAN)
local:
$(MAKE) install INSTALL_TOP=../install
# make may get confused with install/ if it does not support .PHONY.
dummy:
# Echo config parameters.
echo:
@cd src && $(MAKE) -s echo
@echo "PLAT= $(PLAT)"
@echo "V= $V"
@echo "R= $R"
@echo "TO_BIN= $(TO_BIN)"
@echo "TO_INC= $(TO_INC)"
@echo "TO_LIB= $(TO_LIB)"
@echo "TO_MAN= $(TO_MAN)"
@echo "INSTALL_TOP= $(INSTALL_TOP)"
@echo "INSTALL_BIN= $(INSTALL_BIN)"
@echo "INSTALL_INC= $(INSTALL_INC)"
@echo "INSTALL_LIB= $(INSTALL_LIB)"
@echo "INSTALL_MAN= $(INSTALL_MAN)"
@echo "INSTALL_LMOD= $(INSTALL_LMOD)"
@echo "INSTALL_CMOD= $(INSTALL_CMOD)"
@echo "INSTALL_EXEC= $(INSTALL_EXEC)"
@echo "INSTALL_DATA= $(INSTALL_DATA)"
# Echo pkg-config data.
pc:
@echo "version=$R"
@echo "prefix=$(INSTALL_TOP)"
@echo "libdir=$(INSTALL_LIB)"
@echo "includedir=$(INSTALL_INC)"
# Targets that do not create files (not all makes understand .PHONY).
.PHONY: all $(PLATS) help test clean install uninstall local dummy echo pc
# (end of Makefile)

6
src/lua/lua-5.4.8/README Normal file
View File

@@ -0,0 +1,6 @@
This is Lua 5.4.8, released on 21 May 2025.
For installation instructions, license details, and
further information about Lua, see doc/readme.html.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,678 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Lua 5.4 Reference Manual - contents</TITLE>
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
<LINK REL="stylesheet" TYPE="text/css" HREF="index.css">
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
</HEAD>
<BODY>
<H1>
<A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
Lua 5.4 Reference Manual
</H1>
<P>
The reference manual is the official definition of the Lua language.
<BR>
For a complete introduction to Lua programming, see the book
<A HREF="https://www.lua.org/pil/">Programming in Lua</A>.
<DIV CLASS="menubar">
<A HREF="manual.html">start</A>
&middot;
<A HREF="#contents">contents</A>
&middot;
<A HREF="#index">index</A>
&middot;
<A HREF="https://www.lua.org/manual/">other versions</A>
</DIV>
<P>
<SMALL>
Copyright &copy; 2020&ndash;2025 Lua.org, PUC-Rio.
Freely available under the terms of the
<A HREF="https://www.lua.org/license.html">Lua license</A>.
</SMALL>
<H2><A NAME="contents">Contents</A></H2>
<UL CLASS="contents menubar">
<LI><A HREF="manual.html">1 &ndash; Introduction</A>
<P>
<LI><A HREF="manual.html#2">2 &ndash; Basic Concepts</A>
<UL>
<LI><A HREF="manual.html#2.1">2.1 &ndash; Values and Types</A>
<LI><A HREF="manual.html#2.2">2.2 &ndash; Environments and the Global Environment</A>
<LI><A HREF="manual.html#2.3">2.3 &ndash; Error Handling</A>
<LI><A HREF="manual.html#2.4">2.4 &ndash; Metatables and Metamethods</A>
<LI><A HREF="manual.html#2.5">2.5 &ndash; Garbage Collection</A>
<UL>
<LI><A HREF="manual.html#2.5.1">2.5.1 &ndash; Incremental Garbage Collection</A>
<LI><A HREF="manual.html#2.5.2">2.5.2 &ndash; Generational Garbage Collection</A>
<LI><A HREF="manual.html#2.5.3">2.5.3 &ndash; Garbage-Collection Metamethods</A>
<LI><A HREF="manual.html#2.5.4">2.5.4 &ndash; Weak Tables</A>
</UL>
<LI><A HREF="manual.html#2.6">2.6 &ndash; Coroutines</A>
</UL>
<P>
<LI><A HREF="manual.html#3">3 &ndash; The Language</A>
<UL>
<LI><A HREF="manual.html#3.1">3.1 &ndash; Lexical Conventions</A>
<LI><A HREF="manual.html#3.2">3.2 &ndash; Variables</A>
<LI><A HREF="manual.html#3.3">3.3 &ndash; Statements</A>
<UL>
<LI><A HREF="manual.html#3.3.1">3.3.1 &ndash; Blocks</A>
<LI><A HREF="manual.html#3.3.2">3.3.2 &ndash; Chunks</A>
<LI><A HREF="manual.html#3.3.3">3.3.3 &ndash; Assignment</A>
<LI><A HREF="manual.html#3.3.4">3.3.4 &ndash; Control Structures</A>
<LI><A HREF="manual.html#3.3.5">3.3.5 &ndash; For Statement</A>
<LI><A HREF="manual.html#3.3.6">3.3.6 &ndash; Function Calls as Statements</A>
<LI><A HREF="manual.html#3.3.7">3.3.7 &ndash; Local Declarations</A>
<LI><A HREF="manual.html#3.3.8">3.3.8 &ndash; To-be-closed Variables</A>
</UL>
<LI><A HREF="manual.html#3.4">3.4 &ndash; Expressions</A>
<UL>
<LI><A HREF="manual.html#3.4.1">3.4.1 &ndash; Arithmetic Operators</A>
<LI><A HREF="manual.html#3.4.2">3.4.2 &ndash; Bitwise Operators</A>
<LI><A HREF="manual.html#3.4.3">3.4.3 &ndash; Coercions and Conversions</A>
<LI><A HREF="manual.html#3.4.4">3.4.4 &ndash; Relational Operators</A>
<LI><A HREF="manual.html#3.4.5">3.4.5 &ndash; Logical Operators</A>
<LI><A HREF="manual.html#3.4.6">3.4.6 &ndash; Concatenation</A>
<LI><A HREF="manual.html#3.4.7">3.4.7 &ndash; The Length Operator</A>
<LI><A HREF="manual.html#3.4.8">3.4.8 &ndash; Precedence</A>
<LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Table Constructors</A>
<LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Calls</A>
<LI><A HREF="manual.html#3.4.11">3.4.11 &ndash; Function Definitions</A>
<LI><A HREF="manual.html#3.4.12">3.4.12 &ndash; Lists of expressions, multiple results, and adjustment<A>
</UL>
<LI><A HREF="manual.html#3.5">3.5 &ndash; Visibility Rules</A>
</UL>
<P>
<LI><A HREF="manual.html#4">4 &ndash; The Application Program Interface</A>
<UL>
<LI><A HREF="manual.html#4.1">4.1 &ndash; The Stack</A>
<UL>
<LI><A HREF="manual.html#4.1.1">4.1.1 &ndash; Stack Size</A>
<LI><A HREF="manual.html#4.1.2">4.1.2 &ndash; Valid and Acceptable Indices</A>
<LI><A HREF="manual.html#4.1.3">4.1.3 &ndash; Pointers to strings</A>
</UL>
<LI><A HREF="manual.html#4.2">4.2 &ndash; C Closures</A>
<LI><A HREF="manual.html#4.3">4.3 &ndash; Registry</A>
<LI><A HREF="manual.html#4.4">4.4 &ndash; Error Handling in C</A>
<UL>
<LI><A HREF="manual.html#4.4.1">4.4.1 &ndash; Status Codes</A>
</UL>
<LI><A HREF="manual.html#4.5">4.5 &ndash; Handling Yields in C</A>
<LI><A HREF="manual.html#4.6">4.6 &ndash; Functions and Types</A>
<LI><A HREF="manual.html#4.7">4.7 &ndash; The Debug Interface</A>
</UL>
<P>
<LI><A HREF="manual.html#5">5 &ndash; The Auxiliary Library</A>
<UL>
<LI><A HREF="manual.html#5.1">5.1 &ndash; Functions and Types</A>
</UL>
<P>
<LI><A HREF="manual.html#6">6 &ndash; The Standard Libraries</A>
<UL>
<LI><A HREF="manual.html#6.1">6.1 &ndash; Basic Functions</A>
<LI><A HREF="manual.html#6.2">6.2 &ndash; Coroutine Manipulation</A>
<LI><A HREF="manual.html#6.3">6.3 &ndash; Modules</A>
<LI><A HREF="manual.html#6.4">6.4 &ndash; String Manipulation</A>
<UL>
<LI><A HREF="manual.html#6.4.1">6.4.1 &ndash; Patterns</A>
<LI><A HREF="manual.html#6.4.2">6.4.2 &ndash; Format Strings for Pack and Unpack</A>
</UL>
<LI><A HREF="manual.html#6.5">6.5 &ndash; UTF-8 Support</A>
<LI><A HREF="manual.html#6.6">6.6 &ndash; Table Manipulation</A>
<LI><A HREF="manual.html#6.7">6.7 &ndash; Mathematical Functions</A>
<LI><A HREF="manual.html#6.8">6.8 &ndash; Input and Output Facilities</A>
<LI><A HREF="manual.html#6.9">6.9 &ndash; Operating System Facilities</A>
<LI><A HREF="manual.html#6.10">6.10 &ndash; The Debug Library</A>
</UL>
<P>
<LI><A HREF="manual.html#7">7 &ndash; Lua Standalone</A>
<P>
<LI><A HREF="manual.html#8">8 &ndash; Incompatibilities with the Previous Version</A>
<UL>
<LI><A HREF="manual.html#8.1">8.1 &ndash; Incompatibilities in the Language</A>
<LI><A HREF="manual.html#8.2">8.2 &ndash; Incompatibilities in the Libraries</A>
<LI><A HREF="manual.html#8.3">8.3 &ndash; Incompatibilities in the API</A>
</UL>
<P>
<LI><A HREF="manual.html#9">9 &ndash; The Complete Syntax of Lua</A>
</UL>
<H2><A NAME="index">Index</A></H2>
<TABLE CLASS="menubar" WIDTH="100%">
<TR>
<TD>
<H3><A NAME="functions">Lua functions</A></H3>
<P>
<A HREF="manual.html#6.1">basic</A><BR>
<A HREF="manual.html#pdf-_G">_G</A><BR>
<A HREF="manual.html#pdf-_VERSION">_VERSION</A><BR>
<A HREF="manual.html#pdf-assert">assert</A><BR>
<A HREF="manual.html#pdf-collectgarbage">collectgarbage</A><BR>
<A HREF="manual.html#pdf-dofile">dofile</A><BR>
<A HREF="manual.html#pdf-error">error</A><BR>
<A HREF="manual.html#pdf-getmetatable">getmetatable</A><BR>
<A HREF="manual.html#pdf-ipairs">ipairs</A><BR>
<A HREF="manual.html#pdf-load">load</A><BR>
<A HREF="manual.html#pdf-loadfile">loadfile</A><BR>
<A HREF="manual.html#pdf-next">next</A><BR>
<A HREF="manual.html#pdf-pairs">pairs</A><BR>
<A HREF="manual.html#pdf-pcall">pcall</A><BR>
<A HREF="manual.html#pdf-print">print</A><BR>
<A HREF="manual.html#pdf-rawequal">rawequal</A><BR>
<A HREF="manual.html#pdf-rawget">rawget</A><BR>
<A HREF="manual.html#pdf-rawlen">rawlen</A><BR>
<A HREF="manual.html#pdf-rawset">rawset</A><BR>
<A HREF="manual.html#pdf-require">require</A><BR>
<A HREF="manual.html#pdf-select">select</A><BR>
<A HREF="manual.html#pdf-setmetatable">setmetatable</A><BR>
<A HREF="manual.html#pdf-tonumber">tonumber</A><BR>
<A HREF="manual.html#pdf-tostring">tostring</A><BR>
<A HREF="manual.html#pdf-type">type</A><BR>
<A HREF="manual.html#pdf-warn">warn</A><BR>
<A HREF="manual.html#pdf-xpcall">xpcall</A><BR>
<P>
<A HREF="manual.html#6.2">coroutine</A><BR>
<A HREF="manual.html#pdf-coroutine.close">coroutine.close</A><BR>
<A HREF="manual.html#pdf-coroutine.create">coroutine.create</A><BR>
<A HREF="manual.html#pdf-coroutine.isyieldable">coroutine.isyieldable</A><BR>
<A HREF="manual.html#pdf-coroutine.resume">coroutine.resume</A><BR>
<A HREF="manual.html#pdf-coroutine.running">coroutine.running</A><BR>
<A HREF="manual.html#pdf-coroutine.status">coroutine.status</A><BR>
<A HREF="manual.html#pdf-coroutine.wrap">coroutine.wrap</A><BR>
<A HREF="manual.html#pdf-coroutine.yield">coroutine.yield</A><BR>
<P>
<A HREF="manual.html#6.10">debug</A><BR>
<A HREF="manual.html#pdf-debug.debug">debug.debug</A><BR>
<A HREF="manual.html#pdf-debug.gethook">debug.gethook</A><BR>
<A HREF="manual.html#pdf-debug.getinfo">debug.getinfo</A><BR>
<A HREF="manual.html#pdf-debug.getlocal">debug.getlocal</A><BR>
<A HREF="manual.html#pdf-debug.getmetatable">debug.getmetatable</A><BR>
<A HREF="manual.html#pdf-debug.getregistry">debug.getregistry</A><BR>
<A HREF="manual.html#pdf-debug.getupvalue">debug.getupvalue</A><BR>
<A HREF="manual.html#pdf-debug.getuservalue">debug.getuservalue</A><BR>
<A HREF="manual.html#pdf-debug.sethook">debug.sethook</A><BR>
<A HREF="manual.html#pdf-debug.setlocal">debug.setlocal</A><BR>
<A HREF="manual.html#pdf-debug.setmetatable">debug.setmetatable</A><BR>
<A HREF="manual.html#pdf-debug.setupvalue">debug.setupvalue</A><BR>
<A HREF="manual.html#pdf-debug.setuservalue">debug.setuservalue</A><BR>
<A HREF="manual.html#pdf-debug.traceback">debug.traceback</A><BR>
<A HREF="manual.html#pdf-debug.upvalueid">debug.upvalueid</A><BR>
<A HREF="manual.html#pdf-debug.upvaluejoin">debug.upvaluejoin</A><BR>
<P>
<A HREF="manual.html#6.8">io</A><BR>
<A HREF="manual.html#pdf-io.close">io.close</A><BR>
<A HREF="manual.html#pdf-io.flush">io.flush</A><BR>
<A HREF="manual.html#pdf-io.input">io.input</A><BR>
<A HREF="manual.html#pdf-io.lines">io.lines</A><BR>
<A HREF="manual.html#pdf-io.open">io.open</A><BR>
<A HREF="manual.html#pdf-io.output">io.output</A><BR>
<A HREF="manual.html#pdf-io.popen">io.popen</A><BR>
<A HREF="manual.html#pdf-io.read">io.read</A><BR>
<A HREF="manual.html#pdf-io.stderr">io.stderr</A><BR>
<A HREF="manual.html#pdf-io.stdin">io.stdin</A><BR>
<A HREF="manual.html#pdf-io.stdout">io.stdout</A><BR>
<A HREF="manual.html#pdf-io.tmpfile">io.tmpfile</A><BR>
<A HREF="manual.html#pdf-io.type">io.type</A><BR>
<A HREF="manual.html#pdf-io.write">io.write</A><BR>
<A HREF="manual.html#pdf-file:close">file:close</A><BR>
<A HREF="manual.html#pdf-file:flush">file:flush</A><BR>
<A HREF="manual.html#pdf-file:lines">file:lines</A><BR>
<A HREF="manual.html#pdf-file:read">file:read</A><BR>
<A HREF="manual.html#pdf-file:seek">file:seek</A><BR>
<A HREF="manual.html#pdf-file:setvbuf">file:setvbuf</A><BR>
<A HREF="manual.html#pdf-file:write">file:write</A><BR>
</TD>
<TD>
<H3>&nbsp;</H3>
<P>
<A HREF="manual.html#6.7">math</A><BR>
<A HREF="manual.html#pdf-math.abs">math.abs</A><BR>
<A HREF="manual.html#pdf-math.acos">math.acos</A><BR>
<A HREF="manual.html#pdf-math.asin">math.asin</A><BR>
<A HREF="manual.html#pdf-math.atan">math.atan</A><BR>
<A HREF="manual.html#pdf-math.ceil">math.ceil</A><BR>
<A HREF="manual.html#pdf-math.cos">math.cos</A><BR>
<A HREF="manual.html#pdf-math.deg">math.deg</A><BR>
<A HREF="manual.html#pdf-math.exp">math.exp</A><BR>
<A HREF="manual.html#pdf-math.floor">math.floor</A><BR>
<A HREF="manual.html#pdf-math.fmod">math.fmod</A><BR>
<A HREF="manual.html#pdf-math.huge">math.huge</A><BR>
<A HREF="manual.html#pdf-math.log">math.log</A><BR>
<A HREF="manual.html#pdf-math.max">math.max</A><BR>
<A HREF="manual.html#pdf-math.maxinteger">math.maxinteger</A><BR>
<A HREF="manual.html#pdf-math.min">math.min</A><BR>
<A HREF="manual.html#pdf-math.mininteger">math.mininteger</A><BR>
<A HREF="manual.html#pdf-math.modf">math.modf</A><BR>
<A HREF="manual.html#pdf-math.pi">math.pi</A><BR>
<A HREF="manual.html#pdf-math.rad">math.rad</A><BR>
<A HREF="manual.html#pdf-math.random">math.random</A><BR>
<A HREF="manual.html#pdf-math.randomseed">math.randomseed</A><BR>
<A HREF="manual.html#pdf-math.sin">math.sin</A><BR>
<A HREF="manual.html#pdf-math.sqrt">math.sqrt</A><BR>
<A HREF="manual.html#pdf-math.tan">math.tan</A><BR>
<A HREF="manual.html#pdf-math.tointeger">math.tointeger</A><BR>
<A HREF="manual.html#pdf-math.type">math.type</A><BR>
<A HREF="manual.html#pdf-math.ult">math.ult</A><BR>
<P>
<A HREF="manual.html#6.9">os</A><BR>
<A HREF="manual.html#pdf-os.clock">os.clock</A><BR>
<A HREF="manual.html#pdf-os.date">os.date</A><BR>
<A HREF="manual.html#pdf-os.difftime">os.difftime</A><BR>
<A HREF="manual.html#pdf-os.execute">os.execute</A><BR>
<A HREF="manual.html#pdf-os.exit">os.exit</A><BR>
<A HREF="manual.html#pdf-os.getenv">os.getenv</A><BR>
<A HREF="manual.html#pdf-os.remove">os.remove</A><BR>
<A HREF="manual.html#pdf-os.rename">os.rename</A><BR>
<A HREF="manual.html#pdf-os.setlocale">os.setlocale</A><BR>
<A HREF="manual.html#pdf-os.time">os.time</A><BR>
<A HREF="manual.html#pdf-os.tmpname">os.tmpname</A><BR>
<P>
<A HREF="manual.html#6.3">package</A><BR>
<A HREF="manual.html#pdf-package.config">package.config</A><BR>
<A HREF="manual.html#pdf-package.cpath">package.cpath</A><BR>
<A HREF="manual.html#pdf-package.loaded">package.loaded</A><BR>
<A HREF="manual.html#pdf-package.loadlib">package.loadlib</A><BR>
<A HREF="manual.html#pdf-package.path">package.path</A><BR>
<A HREF="manual.html#pdf-package.preload">package.preload</A><BR>
<A HREF="manual.html#pdf-package.searchers">package.searchers</A><BR>
<A HREF="manual.html#pdf-package.searchpath">package.searchpath</A><BR>
<P>
<A HREF="manual.html#6.4">string</A><BR>
<A HREF="manual.html#pdf-string.byte">string.byte</A><BR>
<A HREF="manual.html#pdf-string.char">string.char</A><BR>
<A HREF="manual.html#pdf-string.dump">string.dump</A><BR>
<A HREF="manual.html#pdf-string.find">string.find</A><BR>
<A HREF="manual.html#pdf-string.format">string.format</A><BR>
<A HREF="manual.html#pdf-string.gmatch">string.gmatch</A><BR>
<A HREF="manual.html#pdf-string.gsub">string.gsub</A><BR>
<A HREF="manual.html#pdf-string.len">string.len</A><BR>
<A HREF="manual.html#pdf-string.lower">string.lower</A><BR>
<A HREF="manual.html#pdf-string.match">string.match</A><BR>
<A HREF="manual.html#pdf-string.pack">string.pack</A><BR>
<A HREF="manual.html#pdf-string.packsize">string.packsize</A><BR>
<A HREF="manual.html#pdf-string.rep">string.rep</A><BR>
<A HREF="manual.html#pdf-string.reverse">string.reverse</A><BR>
<A HREF="manual.html#pdf-string.sub">string.sub</A><BR>
<A HREF="manual.html#pdf-string.unpack">string.unpack</A><BR>
<A HREF="manual.html#pdf-string.upper">string.upper</A><BR>
<P>
<A HREF="manual.html#6.6">table</A><BR>
<A HREF="manual.html#pdf-table.concat">table.concat</A><BR>
<A HREF="manual.html#pdf-table.insert">table.insert</A><BR>
<A HREF="manual.html#pdf-table.move">table.move</A><BR>
<A HREF="manual.html#pdf-table.pack">table.pack</A><BR>
<A HREF="manual.html#pdf-table.remove">table.remove</A><BR>
<A HREF="manual.html#pdf-table.sort">table.sort</A><BR>
<A HREF="manual.html#pdf-table.unpack">table.unpack</A><BR>
<P>
<A HREF="manual.html#6.5">utf8</A><BR>
<A HREF="manual.html#pdf-utf8.char">utf8.char</A><BR>
<A HREF="manual.html#pdf-utf8.charpattern">utf8.charpattern</A><BR>
<A HREF="manual.html#pdf-utf8.codepoint">utf8.codepoint</A><BR>
<A HREF="manual.html#pdf-utf8.codes">utf8.codes</A><BR>
<A HREF="manual.html#pdf-utf8.len">utf8.len</A><BR>
<A HREF="manual.html#pdf-utf8.offset">utf8.offset</A><BR>
<H3><A NAME="metamethods">metamethods</A></H3>
<P>
<A HREF="manual.html#2.4">__add</A><BR>
<A HREF="manual.html#2.4">__band</A><BR>
<A HREF="manual.html#2.4">__bnot</A><BR>
<A HREF="manual.html#2.4">__bor</A><BR>
<A HREF="manual.html#2.4">__bxor</A><BR>
<A HREF="manual.html#2.4">__call</A><BR>
<A HREF="manual.html#3.3.8">__close</A><BR>
<A HREF="manual.html#2.4">__concat</A><BR>
<A HREF="manual.html#2.4">__div</A><BR>
<A HREF="manual.html#2.4">__eq</A><BR>
<A HREF="manual.html#2.5.3">__gc</A><BR>
<A HREF="manual.html#2.4">__idiv</A><BR>
<A HREF="manual.html#2.4">__index</A><BR>
<A HREF="manual.html#2.4">__le</A><BR>
<A HREF="manual.html#2.4">__len</A><BR>
<A HREF="manual.html#2.4">__lt</A><BR>
<A HREF="manual.html#pdf-getmetatable">__metatable</A><BR>
<A HREF="manual.html#2.4">__mod</A><BR>
<A HREF="manual.html#2.5.4">__mode</A><BR>
<A HREF="manual.html#2.4">__mul</A><BR>
<A HREF="manual.html#luaL_newmetatable">__name</A><BR>
<A HREF="manual.html#2.4">__newindex</A><BR>
<A HREF="manual.html#pdf-pairs">__pairs</A><BR>
<A HREF="manual.html#2.4">__pow</A><BR>
<A HREF="manual.html#2.4">__shl</A><BR>
<A HREF="manual.html#2.4">__shr</A><BR>
<A HREF="manual.html#2.4">__sub</A><BR>
<A HREF="manual.html#pdf-tostring">__tostring</A><BR>
<A HREF="manual.html#2.4">__unm</A><BR>
<H3><A NAME="env">environment<BR>variables</A></H3>
<P>
<A HREF="manual.html#pdf-LUA_CPATH">LUA_CPATH</A><BR>
<A HREF="manual.html#pdf-LUA_CPATH_5_4">LUA_CPATH_5_4</A><BR>
<A HREF="manual.html#pdf-LUA_INIT">LUA_INIT</A><BR>
<A HREF="manual.html#pdf-LUA_INIT_5_4">LUA_INIT_5_4</A><BR>
<A HREF="manual.html#pdf-LUA_PATH">LUA_PATH</A><BR>
<A HREF="manual.html#pdf-LUA_PATH_5_4">LUA_PATH_5_4</A><BR>
</TD>
<TD>
<H3><A NAME="api">C API</A></H3>
<P>
<A HREF="manual.html#lua_Alloc">lua_Alloc</A><BR>
<A HREF="manual.html#lua_CFunction">lua_CFunction</A><BR>
<A HREF="manual.html#lua_Debug">lua_Debug</A><BR>
<A HREF="manual.html#lua_Hook">lua_Hook</A><BR>
<A HREF="manual.html#lua_Integer">lua_Integer</A><BR>
<A HREF="manual.html#lua_KContext">lua_KContext</A><BR>
<A HREF="manual.html#lua_KFunction">lua_KFunction</A><BR>
<A HREF="manual.html#lua_Number">lua_Number</A><BR>
<A HREF="manual.html#lua_Reader">lua_Reader</A><BR>
<A HREF="manual.html#lua_State">lua_State</A><BR>
<A HREF="manual.html#lua_Unsigned">lua_Unsigned</A><BR>
<A HREF="manual.html#lua_WarnFunction">lua_WarnFunction</A><BR>
<A HREF="manual.html#lua_Writer">lua_Writer</A><BR>
<P>
<A HREF="manual.html#lua_absindex">lua_absindex</A><BR>
<A HREF="manual.html#lua_arith">lua_arith</A><BR>
<A HREF="manual.html#lua_atpanic">lua_atpanic</A><BR>
<A HREF="manual.html#lua_call">lua_call</A><BR>
<A HREF="manual.html#lua_callk">lua_callk</A><BR>
<A HREF="manual.html#lua_checkstack">lua_checkstack</A><BR>
<A HREF="manual.html#lua_close">lua_close</A><BR>
<A HREF="manual.html#lua_closeslot">lua_closeslot</A><BR>
<A HREF="manual.html#lua_compare">lua_compare</A><BR>
<A HREF="manual.html#lua_concat">lua_concat</A><BR>
<A HREF="manual.html#lua_copy">lua_copy</A><BR>
<A HREF="manual.html#lua_createtable">lua_createtable</A><BR>
<A HREF="manual.html#lua_dump">lua_dump</A><BR>
<A HREF="manual.html#lua_error">lua_error</A><BR>
<A HREF="manual.html#lua_gc">lua_gc</A><BR>
<A HREF="manual.html#lua_getallocf">lua_getallocf</A><BR>
<A HREF="manual.html#lua_getextraspace">lua_getextraspace</A><BR>
<A HREF="manual.html#lua_getfield">lua_getfield</A><BR>
<A HREF="manual.html#lua_getglobal">lua_getglobal</A><BR>
<A HREF="manual.html#lua_gethook">lua_gethook</A><BR>
<A HREF="manual.html#lua_gethookcount">lua_gethookcount</A><BR>
<A HREF="manual.html#lua_gethookmask">lua_gethookmask</A><BR>
<A HREF="manual.html#lua_geti">lua_geti</A><BR>
<A HREF="manual.html#lua_getinfo">lua_getinfo</A><BR>
<A HREF="manual.html#lua_getiuservalue">lua_getiuservalue</A><BR>
<A HREF="manual.html#lua_getlocal">lua_getlocal</A><BR>
<A HREF="manual.html#lua_getmetatable">lua_getmetatable</A><BR>
<A HREF="manual.html#lua_getstack">lua_getstack</A><BR>
<A HREF="manual.html#lua_gettable">lua_gettable</A><BR>
<A HREF="manual.html#lua_gettop">lua_gettop</A><BR>
<A HREF="manual.html#lua_getupvalue">lua_getupvalue</A><BR>
<A HREF="manual.html#lua_insert">lua_insert</A><BR>
<A HREF="manual.html#lua_isboolean">lua_isboolean</A><BR>
<A HREF="manual.html#lua_iscfunction">lua_iscfunction</A><BR>
<A HREF="manual.html#lua_isfunction">lua_isfunction</A><BR>
<A HREF="manual.html#lua_isinteger">lua_isinteger</A><BR>
<A HREF="manual.html#lua_islightuserdata">lua_islightuserdata</A><BR>
<A HREF="manual.html#lua_isnil">lua_isnil</A><BR>
<A HREF="manual.html#lua_isnone">lua_isnone</A><BR>
<A HREF="manual.html#lua_isnoneornil">lua_isnoneornil</A><BR>
<A HREF="manual.html#lua_isnumber">lua_isnumber</A><BR>
<A HREF="manual.html#lua_isstring">lua_isstring</A><BR>
<A HREF="manual.html#lua_istable">lua_istable</A><BR>
<A HREF="manual.html#lua_isthread">lua_isthread</A><BR>
<A HREF="manual.html#lua_isuserdata">lua_isuserdata</A><BR>
<A HREF="manual.html#lua_isyieldable">lua_isyieldable</A><BR>
<A HREF="manual.html#lua_len">lua_len</A><BR>
<A HREF="manual.html#lua_load">lua_load</A><BR>
<A HREF="manual.html#lua_newstate">lua_newstate</A><BR>
<A HREF="manual.html#lua_newtable">lua_newtable</A><BR>
<A HREF="manual.html#lua_newthread">lua_newthread</A><BR>
<A HREF="manual.html#lua_newuserdatauv">lua_newuserdatauv</A><BR>
<A HREF="manual.html#lua_next">lua_next</A><BR>
<A HREF="manual.html#lua_numbertointeger">lua_numbertointeger</A><BR>
<A HREF="manual.html#lua_pcall">lua_pcall</A><BR>
<A HREF="manual.html#lua_pcallk">lua_pcallk</A><BR>
<A HREF="manual.html#lua_pop">lua_pop</A><BR>
<A HREF="manual.html#lua_pushboolean">lua_pushboolean</A><BR>
<A HREF="manual.html#lua_pushcclosure">lua_pushcclosure</A><BR>
<A HREF="manual.html#lua_pushcfunction">lua_pushcfunction</A><BR>
<A HREF="manual.html#lua_pushfstring">lua_pushfstring</A><BR>
<A HREF="manual.html#lua_pushglobaltable">lua_pushglobaltable</A><BR>
<A HREF="manual.html#lua_pushinteger">lua_pushinteger</A><BR>
<A HREF="manual.html#lua_pushlightuserdata">lua_pushlightuserdata</A><BR>
<A HREF="manual.html#lua_pushliteral">lua_pushliteral</A><BR>
<A HREF="manual.html#lua_pushlstring">lua_pushlstring</A><BR>
<A HREF="manual.html#lua_pushnil">lua_pushnil</A><BR>
<A HREF="manual.html#lua_pushnumber">lua_pushnumber</A><BR>
<A HREF="manual.html#lua_pushstring">lua_pushstring</A><BR>
<A HREF="manual.html#lua_pushthread">lua_pushthread</A><BR>
<A HREF="manual.html#lua_pushvalue">lua_pushvalue</A><BR>
<A HREF="manual.html#lua_pushvfstring">lua_pushvfstring</A><BR>
<A HREF="manual.html#lua_rawequal">lua_rawequal</A><BR>
<A HREF="manual.html#lua_rawget">lua_rawget</A><BR>
<A HREF="manual.html#lua_rawgeti">lua_rawgeti</A><BR>
<A HREF="manual.html#lua_rawgetp">lua_rawgetp</A><BR>
<A HREF="manual.html#lua_rawlen">lua_rawlen</A><BR>
<A HREF="manual.html#lua_rawset">lua_rawset</A><BR>
<A HREF="manual.html#lua_rawseti">lua_rawseti</A><BR>
<A HREF="manual.html#lua_rawsetp">lua_rawsetp</A><BR>
<A HREF="manual.html#lua_register">lua_register</A><BR>
<A HREF="manual.html#lua_remove">lua_remove</A><BR>
<A HREF="manual.html#lua_replace">lua_replace</A><BR>
<A HREF="manual.html#lua_resetthread">lua_resetthread</A><BR>
<A HREF="manual.html#lua_resume">lua_resume</A><BR>
<A HREF="manual.html#lua_rotate">lua_rotate</A><BR>
<A HREF="manual.html#lua_setallocf">lua_setallocf</A><BR>
<A HREF="manual.html#lua_setfield">lua_setfield</A><BR>
<A HREF="manual.html#lua_setglobal">lua_setglobal</A><BR>
<A HREF="manual.html#lua_sethook">lua_sethook</A><BR>
<A HREF="manual.html#lua_seti">lua_seti</A><BR>
<A HREF="manual.html#lua_setiuservalue">lua_setiuservalue</A><BR>
<A HREF="manual.html#lua_setlocal">lua_setlocal</A><BR>
<A HREF="manual.html#lua_setmetatable">lua_setmetatable</A><BR>
<A HREF="manual.html#lua_settable">lua_settable</A><BR>
<A HREF="manual.html#lua_settop">lua_settop</A><BR>
<A HREF="manual.html#lua_setupvalue">lua_setupvalue</A><BR>
<A HREF="manual.html#lua_setwarnf">lua_setwarnf</A><BR>
<A HREF="manual.html#lua_status">lua_status</A><BR>
<A HREF="manual.html#lua_stringtonumber">lua_stringtonumber</A><BR>
<A HREF="manual.html#lua_toboolean">lua_toboolean</A><BR>
<A HREF="manual.html#lua_tocfunction">lua_tocfunction</A><BR>
<A HREF="manual.html#lua_toclose">lua_toclose</A><BR>
<A HREF="manual.html#lua_tointeger">lua_tointeger</A><BR>
<A HREF="manual.html#lua_tointegerx">lua_tointegerx</A><BR>
<A HREF="manual.html#lua_tolstring">lua_tolstring</A><BR>
<A HREF="manual.html#lua_tonumber">lua_tonumber</A><BR>
<A HREF="manual.html#lua_tonumberx">lua_tonumberx</A><BR>
<A HREF="manual.html#lua_topointer">lua_topointer</A><BR>
<A HREF="manual.html#lua_tostring">lua_tostring</A><BR>
<A HREF="manual.html#lua_tothread">lua_tothread</A><BR>
<A HREF="manual.html#lua_touserdata">lua_touserdata</A><BR>
<A HREF="manual.html#lua_type">lua_type</A><BR>
<A HREF="manual.html#lua_typename">lua_typename</A><BR>
<A HREF="manual.html#lua_upvalueid">lua_upvalueid</A><BR>
<A HREF="manual.html#lua_upvalueindex">lua_upvalueindex</A><BR>
<A HREF="manual.html#lua_upvaluejoin">lua_upvaluejoin</A><BR>
<A HREF="manual.html#lua_version">lua_version</A><BR>
<A HREF="manual.html#lua_warning">lua_warning</A><BR>
<A HREF="manual.html#lua_xmove">lua_xmove</A><BR>
<A HREF="manual.html#lua_yield">lua_yield</A><BR>
<A HREF="manual.html#lua_yieldk">lua_yieldk</A><BR>
</TD>
<TD>
<H3><A NAME="auxlib">auxiliary library</A></H3>
<P>
<A HREF="manual.html#luaL_Buffer">luaL_Buffer</A><BR>
<A HREF="manual.html#luaL_Reg">luaL_Reg</A><BR>
<A HREF="manual.html#luaL_Stream">luaL_Stream</A><BR>
<P>
<A HREF="manual.html#luaL_addchar">luaL_addchar</A><BR>
<A HREF="manual.html#luaL_addgsub">luaL_addgsub</A><BR>
<A HREF="manual.html#luaL_addlstring">luaL_addlstring</A><BR>
<A HREF="manual.html#luaL_addsize">luaL_addsize</A><BR>
<A HREF="manual.html#luaL_addstring">luaL_addstring</A><BR>
<A HREF="manual.html#luaL_addvalue">luaL_addvalue</A><BR>
<A HREF="manual.html#luaL_argcheck">luaL_argcheck</A><BR>
<A HREF="manual.html#luaL_argerror">luaL_argerror</A><BR>
<A HREF="manual.html#luaL_argexpected">luaL_argexpected</A><BR>
<A HREF="manual.html#luaL_buffaddr">luaL_buffaddr</A><BR>
<A HREF="manual.html#luaL_buffinit">luaL_buffinit</A><BR>
<A HREF="manual.html#luaL_buffinitsize">luaL_buffinitsize</A><BR>
<A HREF="manual.html#luaL_bufflen">luaL_bufflen</A><BR>
<A HREF="manual.html#luaL_buffsub">luaL_buffsub</A><BR>
<A HREF="manual.html#luaL_callmeta">luaL_callmeta</A><BR>
<A HREF="manual.html#luaL_checkany">luaL_checkany</A><BR>
<A HREF="manual.html#luaL_checkinteger">luaL_checkinteger</A><BR>
<A HREF="manual.html#luaL_checklstring">luaL_checklstring</A><BR>
<A HREF="manual.html#luaL_checknumber">luaL_checknumber</A><BR>
<A HREF="manual.html#luaL_checkoption">luaL_checkoption</A><BR>
<A HREF="manual.html#luaL_checkstack">luaL_checkstack</A><BR>
<A HREF="manual.html#luaL_checkstring">luaL_checkstring</A><BR>
<A HREF="manual.html#luaL_checktype">luaL_checktype</A><BR>
<A HREF="manual.html#luaL_checkudata">luaL_checkudata</A><BR>
<A HREF="manual.html#luaL_checkversion">luaL_checkversion</A><BR>
<A HREF="manual.html#luaL_dofile">luaL_dofile</A><BR>
<A HREF="manual.html#luaL_dostring">luaL_dostring</A><BR>
<A HREF="manual.html#luaL_error">luaL_error</A><BR>
<A HREF="manual.html#luaL_execresult">luaL_execresult</A><BR>
<A HREF="manual.html#luaL_fileresult">luaL_fileresult</A><BR>
<A HREF="manual.html#luaL_getmetafield">luaL_getmetafield</A><BR>
<A HREF="manual.html#luaL_getmetatable">luaL_getmetatable</A><BR>
<A HREF="manual.html#luaL_getsubtable">luaL_getsubtable</A><BR>
<A HREF="manual.html#luaL_gsub">luaL_gsub</A><BR>
<A HREF="manual.html#luaL_len">luaL_len</A><BR>
<A HREF="manual.html#luaL_loadbuffer">luaL_loadbuffer</A><BR>
<A HREF="manual.html#luaL_loadbufferx">luaL_loadbufferx</A><BR>
<A HREF="manual.html#luaL_loadfile">luaL_loadfile</A><BR>
<A HREF="manual.html#luaL_loadfilex">luaL_loadfilex</A><BR>
<A HREF="manual.html#luaL_loadstring">luaL_loadstring</A><BR>
<A HREF="manual.html#luaL_newlib">luaL_newlib</A><BR>
<A HREF="manual.html#luaL_newlibtable">luaL_newlibtable</A><BR>
<A HREF="manual.html#luaL_newmetatable">luaL_newmetatable</A><BR>
<A HREF="manual.html#luaL_newstate">luaL_newstate</A><BR>
<A HREF="manual.html#luaL_openlibs">luaL_openlibs</A><BR>
<A HREF="manual.html#luaL_opt">luaL_opt</A><BR>
<A HREF="manual.html#luaL_optinteger">luaL_optinteger</A><BR>
<A HREF="manual.html#luaL_optlstring">luaL_optlstring</A><BR>
<A HREF="manual.html#luaL_optnumber">luaL_optnumber</A><BR>
<A HREF="manual.html#luaL_optstring">luaL_optstring</A><BR>
<A HREF="manual.html#luaL_prepbuffer">luaL_prepbuffer</A><BR>
<A HREF="manual.html#luaL_prepbuffsize">luaL_prepbuffsize</A><BR>
<A HREF="manual.html#luaL_pushfail">luaL_pushfail</A><BR>
<A HREF="manual.html#luaL_pushresult">luaL_pushresult</A><BR>
<A HREF="manual.html#luaL_pushresultsize">luaL_pushresultsize</A><BR>
<A HREF="manual.html#luaL_ref">luaL_ref</A><BR>
<A HREF="manual.html#luaL_requiref">luaL_requiref</A><BR>
<A HREF="manual.html#luaL_setfuncs">luaL_setfuncs</A><BR>
<A HREF="manual.html#luaL_setmetatable">luaL_setmetatable</A><BR>
<A HREF="manual.html#luaL_testudata">luaL_testudata</A><BR>
<A HREF="manual.html#luaL_tolstring">luaL_tolstring</A><BR>
<A HREF="manual.html#luaL_traceback">luaL_traceback</A><BR>
<A HREF="manual.html#luaL_typeerror">luaL_typeerror</A><BR>
<A HREF="manual.html#luaL_typename">luaL_typename</A><BR>
<A HREF="manual.html#luaL_unref">luaL_unref</A><BR>
<A HREF="manual.html#luaL_where">luaL_where</A><BR>
<H3><A NAME="library">standard library</A></H3>
<P>
<A HREF="manual.html#pdf-luaopen_base">luaopen_base</A><BR>
<A HREF="manual.html#pdf-luaopen_coroutine">luaopen_coroutine</A><BR>
<A HREF="manual.html#pdf-luaopen_debug">luaopen_debug</A><BR>
<A HREF="manual.html#pdf-luaopen_io">luaopen_io</A><BR>
<A HREF="manual.html#pdf-luaopen_math">luaopen_math</A><BR>
<A HREF="manual.html#pdf-luaopen_os">luaopen_os</A><BR>
<A HREF="manual.html#pdf-luaopen_package">luaopen_package</A><BR>
<A HREF="manual.html#pdf-luaopen_string">luaopen_string</A><BR>
<A HREF="manual.html#pdf-luaopen_table">luaopen_table</A><BR>
<A HREF="manual.html#pdf-luaopen_utf8">luaopen_utf8</A><BR>
<H3><A NAME="constants">constants</A></H3>
<P>
<A HREF="manual.html#pdf-LUA_ERRERR">LUA_ERRERR</A><BR>
<A HREF="manual.html#pdf-LUA_ERRFILE">LUA_ERRFILE</A><BR>
<A HREF="manual.html#pdf-LUA_ERRMEM">LUA_ERRMEM</A><BR>
<A HREF="manual.html#pdf-LUA_ERRRUN">LUA_ERRRUN</A><BR>
<A HREF="manual.html#pdf-LUA_ERRSYNTAX">LUA_ERRSYNTAX</A><BR>
<A HREF="manual.html#pdf-LUA_HOOKCALL">LUA_HOOKCALL</A><BR>
<A HREF="manual.html#pdf-LUA_HOOKCOUNT">LUA_HOOKCOUNT</A><BR>
<A HREF="manual.html#pdf-LUA_HOOKLINE">LUA_HOOKLINE</A><BR>
<A HREF="manual.html#pdf-LUA_HOOKRET">LUA_HOOKRET</A><BR>
<A HREF="manual.html#pdf-LUA_HOOKTAILCALL">LUA_HOOKTAILCALL</A><BR>
<A HREF="manual.html#pdf-LUA_LOADED_TABLE">LUA_LOADED_TABLE</A><BR>
<A HREF="manual.html#pdf-LUA_MASKCALL">LUA_MASKCALL</A><BR>
<A HREF="manual.html#pdf-LUA_MASKCOUNT">LUA_MASKCOUNT</A><BR>
<A HREF="manual.html#pdf-LUA_MASKLINE">LUA_MASKLINE</A><BR>
<A HREF="manual.html#pdf-LUA_MASKRET">LUA_MASKRET</A><BR>
<A HREF="manual.html#pdf-LUA_MAXINTEGER">LUA_MAXINTEGER</A><BR>
<A HREF="manual.html#pdf-LUA_MININTEGER">LUA_MININTEGER</A><BR>
<A HREF="manual.html#pdf-LUA_MINSTACK">LUA_MINSTACK</A><BR>
<A HREF="manual.html#pdf-LUA_MULTRET">LUA_MULTRET</A><BR>
<A HREF="manual.html#pdf-LUA_NOREF">LUA_NOREF</A><BR>
<A HREF="manual.html#pdf-LUA_OK">LUA_OK</A><BR>
<A HREF="manual.html#pdf-LUA_OPADD">LUA_OPADD</A><BR>
<A HREF="manual.html#pdf-LUA_OPBAND">LUA_OPBAND</A><BR>
<A HREF="manual.html#pdf-LUA_OPBNOT">LUA_OPBNOT</A><BR>
<A HREF="manual.html#pdf-LUA_OPBOR">LUA_OPBOR</A><BR>
<A HREF="manual.html#pdf-LUA_OPBXOR">LUA_OPBXOR</A><BR>
<A HREF="manual.html#pdf-LUA_OPDIV">LUA_OPDIV</A><BR>
<A HREF="manual.html#pdf-LUA_OPEQ">LUA_OPEQ</A><BR>
<A HREF="manual.html#pdf-LUA_OPIDIV">LUA_OPIDIV</A><BR>
<A HREF="manual.html#pdf-LUA_OPLE">LUA_OPLE</A><BR>
<A HREF="manual.html#pdf-LUA_OPLT">LUA_OPLT</A><BR>
<A HREF="manual.html#pdf-LUA_OPMOD">LUA_OPMOD</A><BR>
<A HREF="manual.html#pdf-LUA_OPMUL">LUA_OPMUL</A><BR>
<A HREF="manual.html#pdf-LUA_OPPOW">LUA_OPPOW</A><BR>
<A HREF="manual.html#pdf-LUA_OPSHL">LUA_OPSHL</A><BR>
<A HREF="manual.html#pdf-LUA_OPSHR">LUA_OPSHR</A><BR>
<A HREF="manual.html#pdf-LUA_OPSUB">LUA_OPSUB</A><BR>
<A HREF="manual.html#pdf-LUA_OPUNM">LUA_OPUNM</A><BR>
<A HREF="manual.html#pdf-LUA_PRELOAD_TABLE">LUA_PRELOAD_TABLE</A><BR>
<A HREF="manual.html#pdf-LUA_REFNIL">LUA_REFNIL</A><BR>
<A HREF="manual.html#pdf-LUA_REGISTRYINDEX">LUA_REGISTRYINDEX</A><BR>
<A HREF="manual.html#pdf-LUA_RIDX_GLOBALS">LUA_RIDX_GLOBALS</A><BR>
<A HREF="manual.html#pdf-LUA_RIDX_MAINTHREAD">LUA_RIDX_MAINTHREAD</A><BR>
<A HREF="manual.html#pdf-LUA_TBOOLEAN">LUA_TBOOLEAN</A><BR>
<A HREF="manual.html#pdf-LUA_TFUNCTION">LUA_TFUNCTION</A><BR>
<A HREF="manual.html#pdf-LUA_TLIGHTUSERDATA">LUA_TLIGHTUSERDATA</A><BR>
<A HREF="manual.html#pdf-LUA_TNIL">LUA_TNIL</A><BR>
<A HREF="manual.html#pdf-LUA_TNONE">LUA_TNONE</A><BR>
<A HREF="manual.html#pdf-LUA_TNUMBER">LUA_TNUMBER</A><BR>
<A HREF="manual.html#pdf-LUA_TSTRING">LUA_TSTRING</A><BR>
<A HREF="manual.html#pdf-LUA_TTABLE">LUA_TTABLE</A><BR>
<A HREF="manual.html#pdf-LUA_TTHREAD">LUA_TTHREAD</A><BR>
<A HREF="manual.html#pdf-LUA_TUSERDATA">LUA_TUSERDATA</A><BR>
<A HREF="manual.html#pdf-LUA_USE_APICHECK">LUA_USE_APICHECK</A><BR>
<A HREF="manual.html#pdf-LUA_YIELD">LUA_YIELD</A><BR>
<A HREF="manual.html#pdf-LUAL_BUFFERSIZE">LUAL_BUFFERSIZE</A><BR>
</TD>
</TR>
</TABLE>
<P CLASS="footer">
Last update:
Wed May 21 21:11:33 UTC 2025
</P>
<!--
Last change: revised for Lua 5.4.8
-->
</BODY>
</HTML>

View File

@@ -0,0 +1,21 @@
ul {
list-style-type: none ;
}
ul.contents {
padding: 0 ;
}
table {
border: none ;
border-spacing: 0 ;
border-collapse: collapse ;
}
td {
vertical-align: top ;
padding: 0 ;
text-align: left ;
line-height: 1.25 ;
width: 15% ;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

155
src/lua/lua-5.4.8/doc/lua.1 Normal file
View File

@@ -0,0 +1,155 @@
.\" $Id: lua.man,v 1.14 2024/05/08 18:48:27 lhf Exp $
.TH LUA 1 "$Date: 2024/05/08 18:48:27 $"
.SH NAME
lua \- Lua interpreter
.SH SYNOPSIS
.B lua
[
.I options
]
[
.I script
[
.I args
]
]
.SH DESCRIPTION
.B lua
is the standalone Lua interpreter.
It loads and executes Lua programs,
either in textual source form or
in precompiled binary form.
(Precompiled binaries are output by
.BR luac ,
the Lua compiler.)
.B lua
can be used as a batch interpreter and also interactively.
.LP
After handling the
.IR options ,
the Lua program in file
.I script
is loaded and executed.
The
.I args
are available to
.I script
as strings in a global table named
.B arg
and also as arguments to its main function.
When called without arguments,
.B lua
behaves as
.B "lua \-v \-i"
if the standard input is a terminal,
and as
.B "lua \-"
otherwise.
.LP
In interactive mode,
.B lua
prompts the user,
reads lines from the standard input,
and executes them as they are read.
If the line contains an expression,
then the line is evaluated and the result is printed.
If a line does not contain a complete statement,
then a secondary prompt is displayed and
lines are read until a complete statement is formed or
a syntax error is found.
.LP
Before handling command line options and scripts,
.B lua
checks the contents of the environment variables
.B LUA_INIT_5_4
and
.BR LUA_INIT ,
in that order.
If the contents are of the form
.RI '@ filename ',
then
.I filename
is executed.
Otherwise, the contents are assumed to be a Lua statement and is executed.
When
.B LUA_INIT_5_4
is defined,
.B LUA_INIT
is ignored.
.SH OPTIONS
.TP
.BI \-e " stat"
execute statement
.IR stat .
.TP
.B \-i
enter interactive mode after executing
.IR script .
.TP
.BI \-l " mod"
require library
.I mod
into global
.IR mod .
.TP
.BI \-l " g=mod"
require library
.I mod
into global
.IR g .
.TP
.B \-v
show version information.
.TP
.B \-E
ignore environment variables.
.TP
.B \-W
turn warnings on.
.TP
.B \-\-
stop handling options.
.TP
.B \-
stop handling options and execute the standard input as a file.
.SH ENVIRONMENT VARIABLES
The following environment variables affect the execution of
.BR lua .
When defined,
the version-specific variants take priority
and the version-neutral variants are ignored.
.TP
.B LUA_INIT, LUA_INIT_5_4
Code to be executed before command line options and scripts.
.TP
.B LUA_PATH, LUA_PATH_5_4
Initial value of package.path,
the path used by require to search for Lua loaders.
.TP
.B LUA_CPATH, LUA_CPATH_5_4
Initial value of package.cpath,
the path used by require to search for C loaders.
.SH EXIT STATUS
If a script calls os.exit,
then
.B lua
exits with the given exit status.
Otherwise,
.B lua
exits
with EXIT_SUCCESS (0 on POSIX systems) if there were no errors
and
with EXIT_FAILURE (1 on POSIX systems) if there were errors.
Errors raised in interactive mode do not cause exits.
.SH DIAGNOSTICS
Error messages should be self explanatory.
.SH "SEE ALSO"
.BR luac (1)
.br
The documentation at lua.org,
especially section 7 of the reference manual.
.SH AUTHORS
R. Ierusalimschy,
L. H. de Figueiredo,
W. Celes
.\" EOF

View File

@@ -0,0 +1,162 @@
html {
background-color: #F8F8F8 ;
}
body {
background-color: #FFFFFF ;
color: #000000 ;
font-family: Helvetica, Arial, sans-serif ;
text-align: justify ;
line-height: 1.25 ;
margin: 16px auto ;
padding: 32px ;
border: solid #ccc 1px ;
border-radius: 20px ;
max-width: 70em ;
width: 90% ;
}
h1, h2, h3, h4 {
color: #000080 ;
font-family: Verdana, Geneva, sans-serif ;
font-weight: normal ;
font-style: normal ;
text-align: left ;
}
h1 {
font-size: 28pt ;
}
h1 img {
vertical-align: text-bottom ;
}
h2:before {
content: "\2756" ;
padding-right: 0.5em ;
}
a {
text-decoration: none ;
}
a:link {
color: #000080 ;
}
a:link:hover, a:visited:hover {
background-color: #D0D0FF ;
color: #000080 ;
border-radius: 4px ;
}
a:link:active, a:visited:active {
color: #FF0000 ;
}
div.menubar {
padding-bottom: 0.5em ;
}
p.menubar {
margin-left: 2.5em ;
}
.menubar a:hover {
margin: -3px -3px -3px -3px ;
padding: 3px 3px 3px 3px ;
border-radius: 4px ;
}
:target {
background-color: #F0F0F0 ;
margin: -8px ;
padding: 8px ;
border-radius: 8px ;
outline: none ;
}
hr {
display: none ;
}
table hr {
background-color: #a0a0a0 ;
color: #a0a0a0 ;
border: 0 ;
height: 1px ;
display: block ;
}
.footer {
color: gray ;
font-size: x-small ;
text-transform: lowercase ;
}
input[type=text] {
border: solid #a0a0a0 2px ;
border-radius: 2em ;
background-image: url('images/search.png') ;
background-repeat: no-repeat ;
background-position: 4px center ;
padding-left: 20px ;
height: 2em ;
}
pre.session {
background-color: #F8F8F8 ;
padding: 1em ;
border-radius: 8px ;
}
table {
border: none ;
border-spacing: 0 ;
border-collapse: collapse ;
}
td {
padding: 0 ;
margin: 0 ;
}
td.gutter {
width: 4% ;
}
table.columns td {
vertical-align: top ;
padding-bottom: 1em ;
text-align: justify ;
line-height: 1.25 ;
}
table.book td {
vertical-align: top ;
}
table.book td.cover {
padding-right: 1em ;
}
table.book img {
border: solid #000080 1px ;
border-radius: 2px ;
}
table.book span {
font-size: small ;
text-align: left ;
display: block ;
margin-top: 0.25em ;
}
p.logos a:link:hover, p.logos a:visited:hover {
background-color: inherit ;
}
img {
background-color: white ;
}

View File

@@ -0,0 +1,118 @@
.\" $Id: luac.man,v 1.29 2011/11/16 13:53:40 lhf Exp $
.TH LUAC 1 "$Date: 2011/11/16 13:53:40 $"
.SH NAME
luac \- Lua compiler
.SH SYNOPSIS
.B luac
[
.I options
] [
.I filenames
]
.SH DESCRIPTION
.B luac
is the Lua compiler.
It translates programs written in the Lua programming language
into binary files containing precompiled chunks
that can be later loaded and executed.
.LP
The main advantages of precompiling chunks are:
faster loading,
protecting source code from accidental user changes,
and
off-line syntax checking.
Precompiling does not imply faster execution
because in Lua chunks are always compiled into bytecodes before being executed.
.B luac
simply allows those bytecodes to be saved in a file for later execution.
Precompiled chunks are not necessarily smaller than the corresponding source.
The main goal in precompiling is faster loading.
.LP
In the command line,
you can mix
text files containing Lua source and
binary files containing precompiled chunks.
.B luac
produces a single output file containing the combined bytecodes
for all files given.
Executing the combined file is equivalent to executing the given files.
By default,
the output file is named
.BR luac.out ,
but you can change this with the
.B \-o
option.
.LP
Precompiled chunks are
.I not
portable across different architectures.
Moreover,
the internal format of precompiled chunks
is likely to change when a new version of Lua is released.
Make sure you save the source files of all Lua programs that you precompile.
.LP
.SH OPTIONS
.TP
.B \-l
produce a listing of the compiled bytecode for Lua's virtual machine.
Listing bytecodes is useful to learn about Lua's virtual machine.
If no files are given, then
.B luac
loads
.B luac.out
and lists its contents.
Use
.B \-l \-l
for a full listing.
.TP
.BI \-o " file"
output to
.IR file ,
instead of the default
.BR luac.out .
(You can use
.B "'\-'"
for standard output,
but not on platforms that open standard output in text mode.)
The output file may be one of the given files because
all files are loaded before the output file is written.
Be careful not to overwrite precious files.
.TP
.B \-p
load files but do not generate any output file.
Used mainly for syntax checking and for testing precompiled chunks:
corrupted files will probably generate errors when loaded.
If no files are given, then
.B luac
loads
.B luac.out
and tests its contents.
No messages are displayed if the file loads without errors.
.TP
.B \-s
strip debug information before writing the output file.
This saves some space in very large chunks,
but if errors occur when running a stripped chunk,
then the error messages may not contain the full information they usually do.
In particular,
line numbers and names of local variables are lost.
.TP
.B \-v
show version information.
.TP
.B \-\-
stop handling options.
.TP
.B \-
stop handling options and process standard input.
.SH "SEE ALSO"
.BR lua (1)
.br
The documentation at lua.org.
.SH DIAGNOSTICS
Error messages should be self explanatory.
.SH AUTHORS
R. Ierusalimschy,
L. H. de Figueiredo,
W. Celes
.\" EOF

View File

@@ -0,0 +1,21 @@
h3 code {
font-family: inherit ;
font-size: inherit ;
}
pre, code {
font-size: 12pt ;
}
span.apii {
color: gray ;
float: right ;
font-family: inherit ;
font-style: normal ;
font-size: small ;
}
h2:before {
content: "" ;
padding-right: 0em ;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,339 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Lua 5.4 readme</TITLE>
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
<STYLE TYPE="text/css">
blockquote, .display {
border: solid #a0a0a0 2px ;
border-radius: 8px ;
padding: 1em ;
margin: 0px ;
}
.display {
word-spacing: 0.25em ;
}
dl.display dd {
padding-bottom: 0.2em ;
}
tt, kbd, code {
font-size: 12pt ;
}
</STYLE>
</HEAD>
<BODY>
<H1>
<A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
Welcome to Lua 5.4
</H1>
<DIV CLASS="menubar">
<A HREF="#about">about</A>
&middot;
<A HREF="#install">installation</A>
&middot;
<A HREF="#changes">changes</A>
&middot;
<A HREF="#license">license</A>
&middot;
<A HREF="contents.html">reference manual</A>
</DIV>
<H2><A NAME="about">About Lua</A></H2>
<P>
Lua is a powerful, efficient, lightweight, embeddable scripting language
developed by a
<A HREF="https://www.lua.org/authors.html">team</A>
at
<A HREF="https://www.puc-rio.br/">PUC-Rio</A>,
the Pontifical Catholic University of Rio de Janeiro in Brazil.
Lua is
<A HREF="#license">free software</A>
used in
<A HREF="https://www.lua.org/uses.html">many products and projects</A>
around the world.
<P>
Lua's
<A HREF="https://www.lua.org/">official website</A>
provides complete information
about Lua,
including
an
<A HREF="https://www.lua.org/about.html">executive summary</A>,
tips on
<A HREF="https://www.lua.org/start.html">getting started</A>,
and
updated
<A HREF="https://www.lua.org/docs.html">documentation</A>,
especially the
<A HREF="https://www.lua.org/manual/5.4/">reference manual</A>,
which may differ slightly from the
<A HREF="contents.html">local copy</A>
distributed in this package.
<H2><A NAME="install">Installing Lua</A></H2>
<P>
Lua is distributed in
<A HREF="https://www.lua.org/ftp/">source</A>
form.
You need to build it before using it.
Building Lua should be straightforward
because
Lua is implemented in pure ANSI C and compiles unmodified in all known
platforms that have an ANSI C compiler.
Lua also compiles unmodified as C++.
The instructions given below for building Lua are for Unix-like platforms,
such as Linux and macOS.
See also
<A HREF="#other">instructions for other systems</A>
and
<A HREF="#customization">customization options</A>.
<P>
If you don't have the time or the inclination to compile Lua yourself,
get a binary from
<A HREF="https://luabinaries.sourceforge.net">LuaBinaries</A>.
<H3>Building Lua</H3>
<P>
In most common Unix-like platforms, simply do "<KBD>make</KBD>".
Here are the details.
<OL>
<LI>
Open a terminal window and move to
the top-level directory, which is named <TT>lua-5.4.8</TT>.
The <TT>Makefile</TT> there controls both the build process and the installation process.
<P>
<LI>
Do "<KBD>make</KBD>". The <TT>Makefile</TT> will guess your platform and build Lua for it.
<P>
<LI>
If the guess failed, do "<KBD>make help</KBD>" and see if your platform is listed.
The platforms currently supported are:
<P>
<P CLASS="display">
guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
</P>
<P>
If your platform is listed, just do "<KBD>make xxx</KBD>", where xxx
is your platform name.
<P>
If your platform is not listed, try the closest one or posix, generic,
c89, in this order.
<P>
<LI>
The compilation takes only a few moments
and produces three files in the <TT>src</TT> directory:
lua (the interpreter),
luac (the compiler),
and liblua.a (the library).
<P>
<LI>
To check that Lua has been built correctly, do "<KBD>make test</KBD>"
after building Lua. This will run the interpreter and print its version.
</OL>
<P>
If you're running Linux, try "<KBD>make linux-readline</KBD>" to build the interactive Lua interpreter with handy line-editing and history capabilities.
If you get compilation errors,
make sure you have installed the <TT>readline</TT> development package
(which is probably named <TT>libreadline-dev</TT> or <TT>readline-devel</TT>).
If you get link errors after that,
then try "<KBD>make linux-readline MYLIBS=-ltermcap</KBD>".
<H3>Installing Lua</H3>
<P>
Once you have built Lua, you may want to install it in an official
place in your system. In this case, do "<KBD>make install</KBD>". The official
place and the way to install files are defined in the <TT>Makefile</TT>. You'll
probably need the right permissions to install files, and so may need to do "<KBD>sudo make install</KBD>".
<P>
To build and install Lua in one step, do "<KBD>make all install</KBD>",
or "<KBD>make xxx install</KBD>",
where xxx is your platform name.
<P>
To install Lua locally after building it, do "<KBD>make local</KBD>".
This will create a directory <TT>install</TT> with subdirectories
<TT>bin</TT>, <TT>include</TT>, <TT>lib</TT>, <TT>man</TT>, <TT>share</TT>,
and install Lua as listed below.
To install Lua locally, but in some other directory, do
"<KBD>make install INSTALL_TOP=xxx</KBD>", where xxx is your chosen directory.
The installation starts in the <TT>src</TT> and <TT>doc</TT> directories,
so take care if <TT>INSTALL_TOP</TT> is not an absolute path.
<DL CLASS="display">
<DT>
bin:
<DD>
lua luac
<DT>
include:
<DD>
lua.h luaconf.h lualib.h lauxlib.h lua.hpp
<DT>
lib:
<DD>
liblua.a
<DT>
man/man1:
<DD>
lua.1 luac.1
</DL>
<P>
These are the only directories you need for development.
If you only want to run Lua programs,
you only need the files in <TT>bin</TT> and <TT>man</TT>.
The files in <TT>include</TT> and <TT>lib</TT> are needed for
embedding Lua in C or C++ programs.
<H3><A NAME="customization">Customization</A></H3>
<P>
Three kinds of things can be customized by editing a file:
<UL>
<LI> Where and how to install Lua &mdash; edit <TT>Makefile</TT>.
<LI> How to build Lua &mdash; edit <TT>src/Makefile</TT>.
<LI> Lua features &mdash; edit <TT>src/luaconf.h</TT>.
</UL>
<P>
You don't actually need to edit the Makefiles because you may set the
relevant variables in the command line when invoking make.
Nevertheless, it's probably best to edit and save the Makefiles to
record the changes you've made.
<P>
On the other hand, if you need to customize some Lua features,
edit <TT>src/luaconf.h</TT> before building and installing Lua.
The edited file will be the one installed, and
it will be used by any Lua clients that you build, to ensure consistency.
Further customization is available to experts by editing the Lua sources.
<H3><A NAME="other">Building Lua on other systems</A></H3>
<P>
If you're not using the usual Unix tools, then the instructions for
building Lua depend on the compiler you use. You'll need to create
projects (or whatever your compiler uses) for building the library,
the interpreter, and the compiler, as follows:
<DL CLASS="display">
<DT>
library:
<DD>
lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c
lauxlib.c lbaselib.c lcorolib.c ldblib.c liolib.c lmathlib.c loadlib.c loslib.c lstrlib.c ltablib.c lutf8lib.c linit.c
<DT>
interpreter:
<DD>
library, lua.c
<DT>
compiler:
<DD>
library, luac.c
</DL>
<P>
To use Lua as a library in your own programs, you need to know how to
create and use libraries with your compiler. Moreover, to dynamically load
C libraries for Lua, you'll need to know how to create dynamic libraries
and you'll need to make sure that the Lua API functions are accessible to
those dynamic libraries &mdash; but <EM>don't</EM> link the Lua library
into each dynamic library. For Unix, we recommend that the Lua library
be linked statically into the host program and its symbols exported for
dynamic linking; <TT>src/Makefile</TT> does this for the Lua interpreter.
For Windows, we recommend that the Lua library be a DLL.
In all cases, the compiler luac should be linked statically.
<P>
As mentioned above, you may edit <TT>src/luaconf.h</TT> to customize
some features before building Lua.
<H2><A NAME="changes">Changes since Lua 5.3</A></H2>
<P>
Here are the main changes introduced in Lua 5.4.
The
<A HREF="contents.html">reference manual</A>
lists the
<A HREF="manual.html#8">incompatibilities</A> that had to be introduced.
<H3>Main changes</H3>
<UL>
<LI> new generational mode for garbage collection
<LI> to-be-closed variables
<LI> const variables
<LI> userdata can have multiple user values
<LI> new implementation for math.random
<LI> warning system
<LI> debug information about function arguments and returns
<LI> new semantics for the integer 'for' loop
<LI> optional 'init' argument to 'string.gmatch'
<LI> new functions 'lua_resetthread' and 'coroutine.close'
<LI> string-to-number coercions moved to the string library
<LI> allocation function allowed to fail when shrinking a memory block
<LI> new format '%p' in 'string.format'
<LI> utf8 library accepts codepoints up to 2^31
</UL>
<H2><A NAME="license">License</A></H2>
<P>
<A HREF="https://opensource.org/osd">
<IMG SRC="OSIApproved_100X125.png" ALIGN="right" ALT="[Open Source Initiative Approved License]" STYLE="padding-left: 1em" WIDTH=50>
</A>
Lua is free software distributed under the terms of the
<A HREF="https://opensource.org/license/mit">MIT license</A>
reproduced below;
it may be used for any purpose, including commercial purposes,
at absolutely no cost without having to ask us.
The only requirement is that if you do use Lua,
then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation.
For details, see the
<A HREF="https://www.lua.org/license.html">license page</A>.
<BLOCKQUOTE STYLE="padding-bottom: 0em">
Copyright &copy; 1994&ndash;2025 Lua.org, PUC-Rio.
<P>
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:
<P>
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
<P>
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.
</BLOCKQUOTE>
<P>
<P CLASS="footer">
Last update:
Wed May 21 21:12:01 UTC 2025
</P>
<!--
Last change: revised for Lua 5.4.8
-->
</BODY>
</HTML>

View File

@@ -0,0 +1,225 @@
# Makefile for building Lua
# See ../doc/readme.html for installation and customization instructions.
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
# Your platform. See PLATS for possible values.
PLAT= guess
CC= gcc -std=gnu99
CFLAGS= -O2 -Wall -Wextra -DLUA_COMPAT_5_3 $(SYSCFLAGS) $(MYCFLAGS)
LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)
LIBS= -lm $(SYSLIBS) $(MYLIBS)
AR= ar rcu
RANLIB= ranlib
RM= rm -f
UNAME= uname
SYSCFLAGS=
SYSLDFLAGS=
SYSLIBS=
MYCFLAGS=
MYLDFLAGS=
MYLIBS=
MYOBJS=
# Special flags for compiler modules; -Os reduces code size.
CMCFLAGS=
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
PLATS= guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
LUA_A= liblua.a
CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o
LIB_O= lauxlib.o lbaselib.o lcorolib.o ldblib.o liolib.o lmathlib.o loadlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o linit.o
BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS)
LUA_T= lua
LUA_O= lua.o
LUAC_T= luac
LUAC_O= luac.o
ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O)
ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
ALL_A= $(LUA_A)
# Targets start here.
default: $(PLAT)
all: $(ALL_T)
o: $(ALL_O)
a: $(ALL_A)
$(LUA_A): $(BASE_O)
$(AR) $@ $(BASE_O)
$(RANLIB) $@
$(LUA_T): $(LUA_O) $(LUA_A)
$(CC) -o $@ $(LDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)
$(LUAC_T): $(LUAC_O) $(LUA_A)
$(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
test:
./$(LUA_T) -v
clean:
$(RM) $(ALL_T) $(ALL_O)
depend:
@$(CC) $(CFLAGS) -MM l*.c
echo:
@echo "PLAT= $(PLAT)"
@echo "CC= $(CC)"
@echo "CFLAGS= $(CFLAGS)"
@echo "LDFLAGS= $(LDFLAGS)"
@echo "LIBS= $(LIBS)"
@echo "AR= $(AR)"
@echo "RANLIB= $(RANLIB)"
@echo "RM= $(RM)"
@echo "UNAME= $(UNAME)"
# Convenience targets for popular platforms.
ALL= all
help:
@echo "Do 'make PLATFORM' where PLATFORM is one of these:"
@echo " $(PLATS)"
@echo "See doc/readme.html for complete instructions."
guess:
@echo Guessing `$(UNAME)`
@$(MAKE) `$(UNAME)`
AIX aix:
$(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall"
bsd:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-Wl,-E"
c89:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_C89" CC="gcc -std=c89"
@echo ''
@echo '*** C89 does not guarantee 64-bit integers for Lua.'
@echo '*** Make sure to compile all external Lua libraries'
@echo '*** with LUA_USE_C89 to ensure consistency'
@echo ''
FreeBSD NetBSD OpenBSD freebsd:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX -DLUA_USE_READLINE -I/usr/include/edit" SYSLIBS="-Wl,-E -ledit" CC="cc"
generic: $(ALL)
ios:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_IOS"
Linux linux: linux-noreadline
linux-noreadline:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl"
linux-readline:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX -DLUA_USE_READLINE" SYSLIBS="-Wl,-E -ldl -lreadline"
Darwin macos macosx:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX -DLUA_USE_READLINE" SYSLIBS="-lreadline"
mingw:
$(MAKE) "LUA_A=lua54.dll" "LUA_T=lua.exe" \
"AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \
"SYSCFLAGS=-DLUA_BUILD_AS_DLL" "SYSLIBS=" "SYSLDFLAGS=-s" lua.exe
$(MAKE) "LUAC_T=luac.exe" luac.exe
posix:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX"
SunOS solaris:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN -D_REENTRANT" SYSLIBS="-ldl"
# Targets that do not create files (not all makes understand .PHONY).
.PHONY: all $(PLATS) help test clean default o a depend echo
# Compiler modules may use special flags.
llex.o:
$(CC) $(CFLAGS) $(CMCFLAGS) -c llex.c
lparser.o:
$(CC) $(CFLAGS) $(CMCFLAGS) -c lparser.c
lcode.o:
$(CC) $(CFLAGS) $(CMCFLAGS) -c lcode.c
# DO NOT DELETE
lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \
ltable.h lundump.h lvm.h
lauxlib.o: lauxlib.c lprefix.h lua.h luaconf.h lauxlib.h
lbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lcode.o: lcode.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
ldo.h lgc.h lstring.h ltable.h lvm.h
lcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h
ldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ldebug.o: ldebug.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \
ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h
ldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \
lparser.h lstring.h ltable.h lundump.h lvm.h
ldump.o: ldump.c lprefix.h lua.h luaconf.h lobject.h llimits.h lstate.h \
ltm.h lzio.h lmem.h lundump.h
lfunc.o: lfunc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h
lgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h
liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \
lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lgc.h llex.h lparser.h \
lstring.h ltable.h
lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h
loadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lobject.o: lobject.c lprefix.h lua.h luaconf.h lctype.h llimits.h \
ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \
lvm.h
lopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h
loslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lparser.o: lparser.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
ldo.h lfunc.h lstring.h lgc.h ltable.h
lstate.o: lstate.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \
lstring.h ltable.h
lstring.o: lstring.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h
lstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ltable.o: ltable.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
ltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
lua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
luac.o: luac.c lprefix.h lua.h luaconf.h lauxlib.h ldebug.h lstate.h \
lobject.h llimits.h ltm.h lzio.h lmem.h lopcodes.h lopnames.h lundump.h
lundump.o: lundump.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \
lundump.h
lutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \
ltable.h lvm.h ljumptab.h
lzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \
lobject.h ltm.h lzio.h
# (end of Makefile)

1463
src/lua/lua-5.4.8/src/lapi.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
/*
** $Id: lapi.h $
** Auxiliary functions from Lua API
** See Copyright Notice in lua.h
*/
#ifndef lapi_h
#define lapi_h
#include "llimits.h"
#include "lstate.h"
/* Increments 'L->top.p', checking for stack overflows */
#define api_incr_top(L) {L->top.p++; \
api_check(L, L->top.p <= L->ci->top.p, \
"stack overflow");}
/*
** If a call returns too many multiple returns, the callee may not have
** stack space to accommodate all results. In this case, this macro
** increases its stack space ('L->ci->top.p').
*/
#define adjustresults(L,nres) \
{ if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
L->ci->top.p = L->top.p; }
/* Ensure the stack has at least 'n' elements */
#define api_checknelems(L,n) \
api_check(L, (n) < (L->top.p - L->ci->func.p), \
"not enough elements in the stack")
/*
** To reduce the overhead of returning from C functions, the presence of
** to-be-closed variables in these functions is coded in the CallInfo's
** field 'nresults', in a way that functions with no to-be-closed variables
** with zero, one, or "all" wanted results have no overhead. Functions
** with other number of wanted results, as well as functions with
** variables to be closed, have an extra check.
*/
#define hastocloseCfunc(n) ((n) < LUA_MULTRET)
/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */
#define codeNresults(n) (-(n) - 3)
#define decodeNresults(n) (-(n) - 3)
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,301 @@
/*
** $Id: lauxlib.h $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#ifndef lauxlib_h
#define lauxlib_h
#include <stddef.h>
#include <stdio.h>
#include "luaconf.h"
#include "lua.h"
/* global table */
#define LUA_GNAME "_G"
typedef struct luaL_Buffer luaL_Buffer;
/* extra error code for 'luaL_loadfilex' */
#define LUA_ERRFILE (LUA_ERRERR+1)
/* key, in the registry, for table of loaded modules */
#define LUA_LOADED_TABLE "_LOADED"
/* key, in the registry, for table of preloaded loaders */
#define LUA_PRELOAD_TABLE "_PRELOAD"
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number))
LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz);
#define luaL_checkversion(L) \
luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES)
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
LUALIB_API int (luaL_typeerror) (lua_State *L, int arg, const char *tname);
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,
size_t *l);
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,
const char *def, size_t *l);
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg);
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def);
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg);
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg,
lua_Integer def);
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);
LUALIB_API void (luaL_checkany) (lua_State *L, int arg);
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
const char *const lst[]);
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
/* predefined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
LUALIB_API int (luaL_ref) (lua_State *L, int t);
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode);
#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
const char *name, const char *mode);
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
LUALIB_API lua_State *(luaL_newstate) (void);
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s,
const char *p, const char *r);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s,
const char *p, const char *r);
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
const char *msg, int level);
LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
lua_CFunction openf, int glb);
/*
** ===============================================================
** some useful macros
** ===============================================================
*/
#define luaL_newlibtable(L,l) \
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
#define luaL_newlib(L,l) \
(luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
#define luaL_argcheck(L, cond,arg,extramsg) \
((void)(luai_likely(cond) || luaL_argerror(L, (arg), (extramsg))))
#define luaL_argexpected(L,cond,arg,tname) \
((void)(luai_likely(cond) || luaL_typeerror(L, (arg), (tname))))
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
#define luaL_dofile(L, fn) \
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_dostring(L, s) \
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
/*
** Perform arithmetic operations on lua_Integer values with wrap-around
** semantics, as the Lua core does.
*/
#define luaL_intop(op,v1,v2) \
((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2)))
/* push the value used to represent failure/error */
#define luaL_pushfail(L) lua_pushnil(L)
/*
** Internal assertions for in-house debugging
*/
#if !defined(lua_assert)
#if defined LUAI_ASSERT
#include <assert.h>
#define lua_assert(c) assert(c)
#else
#define lua_assert(c) ((void)0)
#endif
#endif
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
struct luaL_Buffer {
char *b; /* buffer address */
size_t size; /* buffer size */
size_t n; /* number of characters in buffer */
lua_State *L;
union {
LUAI_MAXALIGN; /* ensure maximum alignment for buffer */
char b[LUAL_BUFFERSIZE]; /* initial buffer */
} init;
};
#define luaL_bufflen(bf) ((bf)->n)
#define luaL_buffaddr(bf) ((bf)->b)
#define luaL_addchar(B,c) \
((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
((B)->b[(B)->n++] = (c)))
#define luaL_addsize(B,s) ((B)->n += (s))
#define luaL_buffsub(B,s) ((B)->n -= (s))
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
/* }====================================================== */
/*
** {======================================================
** File handles for IO library
** =======================================================
*/
/*
** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
** initial structure 'luaL_Stream' (it may contain other fields
** after that initial structure).
*/
#define LUA_FILEHANDLE "FILE*"
typedef struct luaL_Stream {
FILE *f; /* stream (NULL for incompletely created streams) */
lua_CFunction closef; /* to close stream (NULL for closed streams) */
} luaL_Stream;
/* }====================================================== */
/*
** {==================================================================
** "Abstraction Layer" for basic report of messages and errors
** ===================================================================
*/
/* print a string */
#if !defined(lua_writestring)
#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
#endif
/* print a newline and flush the output */
#if !defined(lua_writeline)
#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
#endif
/* print an error message */
#if !defined(lua_writestringerror)
#define lua_writestringerror(s,p) \
(fprintf(stderr, (s), (p)), fflush(stderr))
#endif
/* }================================================================== */
/*
** {============================================================
** Compatibility with deprecated conversions
** =============================================================
*/
#if defined(LUA_COMPAT_APIINTCASTS)
#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a))
#define luaL_optunsigned(L,a,d) \
((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d)))
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
#endif
/* }============================================================ */
#endif

View File

@@ -0,0 +1,549 @@
/*
** $Id: lbaselib.c $
** Basic library
** See Copyright Notice in lua.h
*/
#define lbaselib_c
#define LUA_LIB
#include "lprefix.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
static int luaB_print (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
int i;
for (i = 1; i <= n; i++) { /* for each argument */
size_t l;
const char *s = luaL_tolstring(L, i, &l); /* convert it to string */
if (i > 1) /* not the first element? */
lua_writestring("\t", 1); /* add a tab before it */
lua_writestring(s, l); /* print it */
lua_pop(L, 1); /* pop result */
}
lua_writeline();
return 0;
}
/*
** Creates a warning with all given arguments.
** Check first for errors; otherwise an error may interrupt
** the composition of a warning, leaving it unfinished.
*/
static int luaB_warn (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
int i;
luaL_checkstring(L, 1); /* at least one argument */
for (i = 2; i <= n; i++)
luaL_checkstring(L, i); /* make sure all arguments are strings */
for (i = 1; i < n; i++) /* compose warning */
lua_warning(L, lua_tostring(L, i), 1);
lua_warning(L, lua_tostring(L, n), 0); /* close warning */
return 0;
}
#define SPACECHARS " \f\n\r\t\v"
static const char *b_str2int (const char *s, int base, lua_Integer *pn) {
lua_Unsigned n = 0;
int neg = 0;
s += strspn(s, SPACECHARS); /* skip initial spaces */
if (*s == '-') { s++; neg = 1; } /* handle sign */
else if (*s == '+') s++;
if (!isalnum((unsigned char)*s)) /* no digit? */
return NULL;
do {
int digit = (isdigit((unsigned char)*s)) ? *s - '0'
: (toupper((unsigned char)*s) - 'A') + 10;
if (digit >= base) return NULL; /* invalid numeral */
n = n * base + digit;
s++;
} while (isalnum((unsigned char)*s));
s += strspn(s, SPACECHARS); /* skip trailing spaces */
*pn = (lua_Integer)((neg) ? (0u - n) : n);
return s;
}
static int luaB_tonumber (lua_State *L) {
if (lua_isnoneornil(L, 2)) { /* standard conversion? */
if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */
lua_settop(L, 1); /* yes; return it */
return 1;
}
else {
size_t l;
const char *s = lua_tolstring(L, 1, &l);
if (s != NULL && lua_stringtonumber(L, s) == l + 1)
return 1; /* successful conversion to number */
/* else not a number */
luaL_checkany(L, 1); /* (but there must be some parameter) */
}
}
else {
size_t l;
const char *s;
lua_Integer n = 0; /* to avoid warnings */
lua_Integer base = luaL_checkinteger(L, 2);
luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
s = lua_tolstring(L, 1, &l);
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
if (b_str2int(s, (int)base, &n) == s + l) {
lua_pushinteger(L, n);
return 1;
} /* else not a number */
} /* else not a number */
luaL_pushfail(L); /* not a number */
return 1;
}
static int luaB_error (lua_State *L) {
int level = (int)luaL_optinteger(L, 2, 1);
lua_settop(L, 1);
if (lua_type(L, 1) == LUA_TSTRING && level > 0) {
luaL_where(L, level); /* add extra information */
lua_pushvalue(L, 1);
lua_concat(L, 2);
}
return lua_error(L);
}
static int luaB_getmetatable (lua_State *L) {
luaL_checkany(L, 1);
if (!lua_getmetatable(L, 1)) {
lua_pushnil(L);
return 1; /* no metatable */
}
luaL_getmetafield(L, 1, "__metatable");
return 1; /* returns either __metatable field (if present) or metatable */
}
static int luaB_setmetatable (lua_State *L) {
int t = lua_type(L, 2);
luaL_checktype(L, 1, LUA_TTABLE);
luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table");
if (l_unlikely(luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL))
return luaL_error(L, "cannot change a protected metatable");
lua_settop(L, 2);
lua_setmetatable(L, 1);
return 1;
}
static int luaB_rawequal (lua_State *L) {
luaL_checkany(L, 1);
luaL_checkany(L, 2);
lua_pushboolean(L, lua_rawequal(L, 1, 2));
return 1;
}
static int luaB_rawlen (lua_State *L) {
int t = lua_type(L, 1);
luaL_argexpected(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
"table or string");
lua_pushinteger(L, lua_rawlen(L, 1));
return 1;
}
static int luaB_rawget (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
luaL_checkany(L, 2);
lua_settop(L, 2);
lua_rawget(L, 1);
return 1;
}
static int luaB_rawset (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
luaL_checkany(L, 2);
luaL_checkany(L, 3);
lua_settop(L, 3);
lua_rawset(L, 1);
return 1;
}
static int pushmode (lua_State *L, int oldmode) {
if (oldmode == -1)
luaL_pushfail(L); /* invalid call to 'lua_gc' */
else
lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
: "generational");
return 1;
}
/*
** check whether call to 'lua_gc' was valid (not inside a finalizer)
*/
#define checkvalres(res) { if (res == -1) break; }
static int luaB_collectgarbage (lua_State *L) {
static const char *const opts[] = {"stop", "restart", "collect",
"count", "step", "setpause", "setstepmul",
"isrunning", "generational", "incremental", NULL};
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
switch (o) {
case LUA_GCCOUNT: {
int k = lua_gc(L, o);
int b = lua_gc(L, LUA_GCCOUNTB);
checkvalres(k);
lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
return 1;
}
case LUA_GCSTEP: {
int step = (int)luaL_optinteger(L, 2, 0);
int res = lua_gc(L, o, step);
checkvalres(res);
lua_pushboolean(L, res);
return 1;
}
case LUA_GCSETPAUSE:
case LUA_GCSETSTEPMUL: {
int p = (int)luaL_optinteger(L, 2, 0);
int previous = lua_gc(L, o, p);
checkvalres(previous);
lua_pushinteger(L, previous);
return 1;
}
case LUA_GCISRUNNING: {
int res = lua_gc(L, o);
checkvalres(res);
lua_pushboolean(L, res);
return 1;
}
case LUA_GCGEN: {
int minormul = (int)luaL_optinteger(L, 2, 0);
int majormul = (int)luaL_optinteger(L, 3, 0);
return pushmode(L, lua_gc(L, o, minormul, majormul));
}
case LUA_GCINC: {
int pause = (int)luaL_optinteger(L, 2, 0);
int stepmul = (int)luaL_optinteger(L, 3, 0);
int stepsize = (int)luaL_optinteger(L, 4, 0);
return pushmode(L, lua_gc(L, o, pause, stepmul, stepsize));
}
default: {
int res = lua_gc(L, o);
checkvalres(res);
lua_pushinteger(L, res);
return 1;
}
}
luaL_pushfail(L); /* invalid call (inside a finalizer) */
return 1;
}
static int luaB_type (lua_State *L) {
int t = lua_type(L, 1);
luaL_argcheck(L, t != LUA_TNONE, 1, "value expected");
lua_pushstring(L, lua_typename(L, t));
return 1;
}
static int luaB_next (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 2); /* create a 2nd argument if there isn't one */
if (lua_next(L, 1))
return 2;
else {
lua_pushnil(L);
return 1;
}
}
static int pairscont (lua_State *L, int status, lua_KContext k) {
(void)L; (void)status; (void)k; /* unused */
return 3;
}
static int luaB_pairs (lua_State *L) {
luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
lua_pushcfunction(L, luaB_next); /* will return generator, */
lua_pushvalue(L, 1); /* state, */
lua_pushnil(L); /* and initial value */
}
else {
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */
}
return 3;
}
/*
** Traversal function for 'ipairs'
*/
static int ipairsaux (lua_State *L) {
lua_Integer i = luaL_checkinteger(L, 2);
i = luaL_intop(+, i, 1);
lua_pushinteger(L, i);
return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
}
/*
** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
** (The given "table" may not be a table.)
*/
static int luaB_ipairs (lua_State *L) {
luaL_checkany(L, 1);
lua_pushcfunction(L, ipairsaux); /* iteration function */
lua_pushvalue(L, 1); /* state */
lua_pushinteger(L, 0); /* initial value */
return 3;
}
static int load_aux (lua_State *L, int status, int envidx) {
if (l_likely(status == LUA_OK)) {
if (envidx != 0) { /* 'env' parameter? */
lua_pushvalue(L, envidx); /* environment for loaded function */
if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */
lua_pop(L, 1); /* remove 'env' if not used by previous call */
}
return 1;
}
else { /* error (message is on top of the stack) */
luaL_pushfail(L);
lua_insert(L, -2); /* put before error message */
return 2; /* return fail plus error message */
}
}
static int luaB_loadfile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL);
const char *mode = luaL_optstring(L, 2, NULL);
int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */
int status = luaL_loadfilex(L, fname, mode);
return load_aux(L, status, env);
}
/*
** {======================================================
** Generic Read function
** =======================================================
*/
/*
** reserved slot, above all arguments, to hold a copy of the returned
** string to avoid it being collected while parsed. 'load' has four
** optional arguments (chunk, source name, mode, and environment).
*/
#define RESERVEDSLOT 5
/*
** Reader for generic 'load' function: 'lua_load' uses the
** stack for internal stuff, so the reader cannot change the
** stack top. Instead, it keeps its resulting string in a
** reserved slot inside the stack.
*/
static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
(void)(ud); /* not used */
luaL_checkstack(L, 2, "too many nested functions");
lua_pushvalue(L, 1); /* get function */
lua_call(L, 0, 1); /* call it */
if (lua_isnil(L, -1)) {
lua_pop(L, 1); /* pop result */
*size = 0;
return NULL;
}
else if (l_unlikely(!lua_isstring(L, -1)))
luaL_error(L, "reader function must return a string");
lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
return lua_tolstring(L, RESERVEDSLOT, size);
}
static int luaB_load (lua_State *L) {
int status;
size_t l;
const char *s = lua_tolstring(L, 1, &l);
const char *mode = luaL_optstring(L, 3, "bt");
int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */
if (s != NULL) { /* loading a string? */
const char *chunkname = luaL_optstring(L, 2, s);
status = luaL_loadbufferx(L, s, l, chunkname, mode);
}
else { /* loading from a reader function */
const char *chunkname = luaL_optstring(L, 2, "=(load)");
luaL_checktype(L, 1, LUA_TFUNCTION);
lua_settop(L, RESERVEDSLOT); /* create reserved slot */
status = lua_load(L, generic_reader, NULL, chunkname, mode);
}
return load_aux(L, status, env);
}
/* }====================================================== */
static int dofilecont (lua_State *L, int d1, lua_KContext d2) {
(void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */
return lua_gettop(L) - 1;
}
static int luaB_dofile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL);
lua_settop(L, 1);
if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK))
return lua_error(L);
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
return dofilecont(L, 0, 0);
}
static int luaB_assert (lua_State *L) {
if (l_likely(lua_toboolean(L, 1))) /* condition is true? */
return lua_gettop(L); /* return all arguments */
else { /* error */
luaL_checkany(L, 1); /* there must be a condition */
lua_remove(L, 1); /* remove it */
lua_pushliteral(L, "assertion failed!"); /* default message */
lua_settop(L, 1); /* leave only message (default if no other one) */
return luaB_error(L); /* call 'error' */
}
}
static int luaB_select (lua_State *L) {
int n = lua_gettop(L);
if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
lua_pushinteger(L, n-1);
return 1;
}
else {
lua_Integer i = luaL_checkinteger(L, 1);
if (i < 0) i = n + i;
else if (i > n) i = n;
luaL_argcheck(L, 1 <= i, 1, "index out of range");
return n - (int)i;
}
}
/*
** Continuation function for 'pcall' and 'xpcall'. Both functions
** already pushed a 'true' before doing the call, so in case of success
** 'finishpcall' only has to return everything in the stack minus
** 'extra' values (where 'extra' is exactly the number of items to be
** ignored).
*/
static int finishpcall (lua_State *L, int status, lua_KContext extra) {
if (l_unlikely(status != LUA_OK && status != LUA_YIELD)) { /* error? */
lua_pushboolean(L, 0); /* first result (false) */
lua_pushvalue(L, -2); /* error message */
return 2; /* return false, msg */
}
else
return lua_gettop(L) - (int)extra; /* return all results */
}
static int luaB_pcall (lua_State *L) {
int status;
luaL_checkany(L, 1);
lua_pushboolean(L, 1); /* first result if no errors */
lua_insert(L, 1); /* put it in place */
status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall);
return finishpcall(L, status, 0);
}
/*
** Do a protected call with error handling. After 'lua_rotate', the
** stack will have <f, err, true, f, [args...]>; so, the function passes
** 2 to 'finishpcall' to skip the 2 first values when returning results.
*/
static int luaB_xpcall (lua_State *L) {
int status;
int n = lua_gettop(L);
luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */
lua_pushboolean(L, 1); /* first result */
lua_pushvalue(L, 1); /* function */
lua_rotate(L, 3, 2); /* move them below function's arguments */
status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall);
return finishpcall(L, status, 2);
}
static int luaB_tostring (lua_State *L) {
luaL_checkany(L, 1);
luaL_tolstring(L, 1, NULL);
return 1;
}
static const luaL_Reg base_funcs[] = {
{"assert", luaB_assert},
{"collectgarbage", luaB_collectgarbage},
{"dofile", luaB_dofile},
{"error", luaB_error},
{"getmetatable", luaB_getmetatable},
{"ipairs", luaB_ipairs},
{"loadfile", luaB_loadfile},
{"load", luaB_load},
{"next", luaB_next},
{"pairs", luaB_pairs},
{"pcall", luaB_pcall},
{"print", luaB_print},
{"warn", luaB_warn},
{"rawequal", luaB_rawequal},
{"rawlen", luaB_rawlen},
{"rawget", luaB_rawget},
{"rawset", luaB_rawset},
{"select", luaB_select},
{"setmetatable", luaB_setmetatable},
{"tonumber", luaB_tonumber},
{"tostring", luaB_tostring},
{"type", luaB_type},
{"xpcall", luaB_xpcall},
/* placeholders */
{LUA_GNAME, NULL},
{"_VERSION", NULL},
{NULL, NULL}
};
LUAMOD_API int luaopen_base (lua_State *L) {
/* open lib into global table */
lua_pushglobaltable(L);
luaL_setfuncs(L, base_funcs, 0);
/* set global _G */
lua_pushvalue(L, -1);
lua_setfield(L, -2, LUA_GNAME);
/* set global _VERSION */
lua_pushliteral(L, LUA_VERSION);
lua_setfield(L, -2, "_VERSION");
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,101 @@
/*
** $Id: lcode.h $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
#ifndef lcode_h
#define lcode_h
#include "llex.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
/*
** Marks the end of a patch list. It is an invalid value both as an absolute
** address, and as a list link (would link an element to itself).
*/
#define NO_JUMP (-1)
/*
** grep "ORDER OPR" if you change these enums (ORDER OP)
*/
typedef enum BinOpr {
/* arithmetic operators */
OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW,
OPR_DIV, OPR_IDIV,
/* bitwise operators */
OPR_BAND, OPR_BOR, OPR_BXOR,
OPR_SHL, OPR_SHR,
/* string operator */
OPR_CONCAT,
/* comparison operators */
OPR_EQ, OPR_LT, OPR_LE,
OPR_NE, OPR_GT, OPR_GE,
/* logical operators */
OPR_AND, OPR_OR,
OPR_NOBINOPR
} BinOpr;
/* true if operation is foldable (that is, it is arithmetic or bitwise) */
#define foldbinop(op) ((op) <= OPR_SHR)
#define luaK_codeABC(fs,o,a,b,c) luaK_codeABCk(fs,o,a,b,c,0)
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
/* get (pointer to) instruction of given 'expdesc' */
#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info])
#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET)
#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
LUAI_FUNC int luaK_code (FuncState *fs, Instruction i);
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
int B, int C, int k);
LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n);
LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
LUAI_FUNC int luaK_jump (FuncState *fs);
LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
LUAI_FUNC int luaK_getlabel (FuncState *fs);
LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line);
LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,
expdesc *v2, int line);
LUAI_FUNC void luaK_settablesize (FuncState *fs, int pc,
int ra, int asize, int hsize);
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
LUAI_FUNC void luaK_finish (FuncState *fs);
LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *msg);
#endif

View File

@@ -0,0 +1,210 @@
/*
** $Id: lcorolib.c $
** Coroutine Library
** See Copyright Notice in lua.h
*/
#define lcorolib_c
#define LUA_LIB
#include "lprefix.h"
#include <stdlib.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
static lua_State *getco (lua_State *L) {
lua_State *co = lua_tothread(L, 1);
luaL_argexpected(L, co, 1, "thread");
return co;
}
/*
** Resumes a coroutine. Returns the number of results for non-error
** cases or -1 for errors.
*/
static int auxresume (lua_State *L, lua_State *co, int narg) {
int status, nres;
if (l_unlikely(!lua_checkstack(co, narg))) {
lua_pushliteral(L, "too many arguments to resume");
return -1; /* error flag */
}
lua_xmove(L, co, narg);
status = lua_resume(co, L, narg, &nres);
if (l_likely(status == LUA_OK || status == LUA_YIELD)) {
if (l_unlikely(!lua_checkstack(L, nres + 1))) {
lua_pop(co, nres); /* remove results anyway */
lua_pushliteral(L, "too many results to resume");
return -1; /* error flag */
}
lua_xmove(co, L, nres); /* move yielded values */
return nres;
}
else {
lua_xmove(co, L, 1); /* move error message */
return -1; /* error flag */
}
}
static int luaB_coresume (lua_State *L) {
lua_State *co = getco(L);
int r;
r = auxresume(L, co, lua_gettop(L) - 1);
if (l_unlikely(r < 0)) {
lua_pushboolean(L, 0);
lua_insert(L, -2);
return 2; /* return false + error message */
}
else {
lua_pushboolean(L, 1);
lua_insert(L, -(r + 1));
return r + 1; /* return true + 'resume' returns */
}
}
static int luaB_auxwrap (lua_State *L) {
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
int r = auxresume(L, co, lua_gettop(L));
if (l_unlikely(r < 0)) { /* error? */
int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
stat = lua_closethread(co, L); /* close its tbc variables */
lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* move error message to the caller */
}
if (stat != LUA_ERRMEM && /* not a memory error and ... */
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
luaL_where(L, 1); /* add extra info, if available */
lua_insert(L, -2);
lua_concat(L, 2);
}
return lua_error(L); /* propagate error */
}
return r;
}
static int luaB_cocreate (lua_State *L) {
lua_State *NL;
luaL_checktype(L, 1, LUA_TFUNCTION);
NL = lua_newthread(L);
lua_pushvalue(L, 1); /* move function to top */
lua_xmove(L, NL, 1); /* move function from L to NL */
return 1;
}
static int luaB_cowrap (lua_State *L) {
luaB_cocreate(L);
lua_pushcclosure(L, luaB_auxwrap, 1);
return 1;
}
static int luaB_yield (lua_State *L) {
return lua_yield(L, lua_gettop(L));
}
#define COS_RUN 0
#define COS_DEAD 1
#define COS_YIELD 2
#define COS_NORM 3
static const char *const statname[] =
{"running", "dead", "suspended", "normal"};
static int auxstatus (lua_State *L, lua_State *co) {
if (L == co) return COS_RUN;
else {
switch (lua_status(co)) {
case LUA_YIELD:
return COS_YIELD;
case LUA_OK: {
lua_Debug ar;
if (lua_getstack(co, 0, &ar)) /* does it have frames? */
return COS_NORM; /* it is running */
else if (lua_gettop(co) == 0)
return COS_DEAD;
else
return COS_YIELD; /* initial state */
}
default: /* some error occurred */
return COS_DEAD;
}
}
}
static int luaB_costatus (lua_State *L) {
lua_State *co = getco(L);
lua_pushstring(L, statname[auxstatus(L, co)]);
return 1;
}
static int luaB_yieldable (lua_State *L) {
lua_State *co = lua_isnone(L, 1) ? L : getco(L);
lua_pushboolean(L, lua_isyieldable(co));
return 1;
}
static int luaB_corunning (lua_State *L) {
int ismain = lua_pushthread(L);
lua_pushboolean(L, ismain);
return 2;
}
static int luaB_close (lua_State *L) {
lua_State *co = getco(L);
int status = auxstatus(L, co);
switch (status) {
case COS_DEAD: case COS_YIELD: {
status = lua_closethread(co, L);
if (status == LUA_OK) {
lua_pushboolean(L, 1);
return 1;
}
else {
lua_pushboolean(L, 0);
lua_xmove(co, L, 1); /* move error message */
return 2;
}
}
default: /* normal or running coroutine */
return luaL_error(L, "cannot close a %s coroutine", statname[status]);
}
}
static const luaL_Reg co_funcs[] = {
{"create", luaB_cocreate},
{"resume", luaB_coresume},
{"running", luaB_corunning},
{"status", luaB_costatus},
{"wrap", luaB_cowrap},
{"yield", luaB_yield},
{"isyieldable", luaB_yieldable},
{"close", luaB_close},
{NULL, NULL}
};
LUAMOD_API int luaopen_coroutine (lua_State *L) {
luaL_newlib(L, co_funcs);
return 1;
}

View File

@@ -0,0 +1,64 @@
/*
** $Id: lctype.c $
** 'ctype' functions for Lua
** See Copyright Notice in lua.h
*/
#define lctype_c
#define LUA_CORE
#include "lprefix.h"
#include "lctype.h"
#if !LUA_USE_CTYPE /* { */
#include <limits.h>
#if defined (LUA_UCID) /* accept UniCode IDentifiers? */
/* consider all non-ascii codepoints to be alphabetic */
#define NONA 0x01
#else
#define NONA 0x00 /* default */
#endif
LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {
0x00, /* EOZ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */
0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */
0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05,
0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */
0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00,
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 8. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 9. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* a. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* b. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
0x00, 0x00, NONA, NONA, NONA, NONA, NONA, NONA, /* c. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* d. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* e. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
NONA, NONA, NONA, NONA, NONA, 0x00, 0x00, 0x00, /* f. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#endif /* } */

View File

@@ -0,0 +1,101 @@
/*
** $Id: lctype.h $
** 'ctype' functions for Lua
** See Copyright Notice in lua.h
*/
#ifndef lctype_h
#define lctype_h
#include "lua.h"
/*
** WARNING: the functions defined here do not necessarily correspond
** to the similar functions in the standard C ctype.h. They are
** optimized for the specific needs of Lua.
*/
#if !defined(LUA_USE_CTYPE)
#if 'A' == 65 && '0' == 48
/* ASCII case: can use its own tables; faster and fixed */
#define LUA_USE_CTYPE 0
#else
/* must use standard C ctype */
#define LUA_USE_CTYPE 1
#endif
#endif
#if !LUA_USE_CTYPE /* { */
#include <limits.h>
#include "llimits.h"
#define ALPHABIT 0
#define DIGITBIT 1
#define PRINTBIT 2
#define SPACEBIT 3
#define XDIGITBIT 4
#define MASK(B) (1 << (B))
/*
** add 1 to char to allow index -1 (EOZ)
*/
#define testprop(c,p) (luai_ctype_[(c)+1] & (p))
/*
** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_'
*/
#define lislalpha(c) testprop(c, MASK(ALPHABIT))
#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT)))
#define lisdigit(c) testprop(c, MASK(DIGITBIT))
#define lisspace(c) testprop(c, MASK(SPACEBIT))
#define lisprint(c) testprop(c, MASK(PRINTBIT))
#define lisxdigit(c) testprop(c, MASK(XDIGITBIT))
/*
** In ASCII, this 'ltolower' is correct for alphabetic characters and
** for '.'. That is enough for Lua needs. ('check_exp' ensures that
** the character either is an upper-case letter or is unchanged by
** the transformation, which holds for lower-case letters and '.'.)
*/
#define ltolower(c) \
check_exp(('A' <= (c) && (c) <= 'Z') || (c) == ((c) | ('A' ^ 'a')), \
(c) | ('A' ^ 'a'))
/* one entry for each character and for -1 (EOZ) */
LUAI_DDEC(const lu_byte luai_ctype_[UCHAR_MAX + 2];)
#else /* }{ */
/*
** use standard C ctypes
*/
#include <ctype.h>
#define lislalpha(c) (isalpha(c) || (c) == '_')
#define lislalnum(c) (isalnum(c) || (c) == '_')
#define lisdigit(c) (isdigit(c))
#define lisspace(c) (isspace(c))
#define lisprint(c) (isprint(c))
#define lisxdigit(c) (isxdigit(c))
#define ltolower(c) (tolower(c))
#endif /* } */
#endif

View File

@@ -0,0 +1,483 @@
/*
** $Id: ldblib.c $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
#define ldblib_c
#define LUA_LIB
#include "lprefix.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
/*
** The hook table at registry[HOOKKEY] maps threads to their current
** hook function.
*/
static const char *const HOOKKEY = "_HOOKKEY";
/*
** If L1 != L, L1 can be in any state, and therefore there are no
** guarantees about its stack space; any push in L1 must be
** checked.
*/
static void checkstack (lua_State *L, lua_State *L1, int n) {
if (l_unlikely(L != L1 && !lua_checkstack(L1, n)))
luaL_error(L, "stack overflow");
}
static int db_getregistry (lua_State *L) {
lua_pushvalue(L, LUA_REGISTRYINDEX);
return 1;
}
static int db_getmetatable (lua_State *L) {
luaL_checkany(L, 1);
if (!lua_getmetatable(L, 1)) {
lua_pushnil(L); /* no metatable */
}
return 1;
}
static int db_setmetatable (lua_State *L) {
int t = lua_type(L, 2);
luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table");
lua_settop(L, 2);
lua_setmetatable(L, 1);
return 1; /* return 1st argument */
}
static int db_getuservalue (lua_State *L) {
int n = (int)luaL_optinteger(L, 2, 1);
if (lua_type(L, 1) != LUA_TUSERDATA)
luaL_pushfail(L);
else if (lua_getiuservalue(L, 1, n) != LUA_TNONE) {
lua_pushboolean(L, 1);
return 2;
}
return 1;
}
static int db_setuservalue (lua_State *L) {
int n = (int)luaL_optinteger(L, 3, 1);
luaL_checktype(L, 1, LUA_TUSERDATA);
luaL_checkany(L, 2);
lua_settop(L, 2);
if (!lua_setiuservalue(L, 1, n))
luaL_pushfail(L);
return 1;
}
/*
** Auxiliary function used by several library functions: check for
** an optional thread as function's first argument and set 'arg' with
** 1 if this argument is present (so that functions can skip it to
** access their other arguments)
*/
static lua_State *getthread (lua_State *L, int *arg) {
if (lua_isthread(L, 1)) {
*arg = 1;
return lua_tothread(L, 1);
}
else {
*arg = 0;
return L; /* function will operate over current thread */
}
}
/*
** Variations of 'lua_settable', used by 'db_getinfo' to put results
** from 'lua_getinfo' into result table. Key is always a string;
** value can be a string, an int, or a boolean.
*/
static void settabss (lua_State *L, const char *k, const char *v) {
lua_pushstring(L, v);
lua_setfield(L, -2, k);
}
static void settabsi (lua_State *L, const char *k, int v) {
lua_pushinteger(L, v);
lua_setfield(L, -2, k);
}
static void settabsb (lua_State *L, const char *k, int v) {
lua_pushboolean(L, v);
lua_setfield(L, -2, k);
}
/*
** In function 'db_getinfo', the call to 'lua_getinfo' may push
** results on the stack; later it creates the result table to put
** these objects. Function 'treatstackoption' puts the result from
** 'lua_getinfo' on top of the result table so that it can call
** 'lua_setfield'.
*/
static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
if (L == L1)
lua_rotate(L, -2, 1); /* exchange object and table */
else
lua_xmove(L1, L, 1); /* move object to the "main" stack */
lua_setfield(L, -2, fname); /* put object into table */
}
/*
** Calls 'lua_getinfo' and collects all results in a new table.
** L1 needs stack space for an optional input (function) plus
** two optional outputs (function and line table) from function
** 'lua_getinfo'.
*/
static int db_getinfo (lua_State *L) {
lua_Debug ar;
int arg;
lua_State *L1 = getthread(L, &arg);
const char *options = luaL_optstring(L, arg+2, "flnSrtu");
checkstack(L, L1, 3);
luaL_argcheck(L, options[0] != '>', arg + 2, "invalid option '>'");
if (lua_isfunction(L, arg + 1)) { /* info about a function? */
options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */
lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */
lua_xmove(L, L1, 1);
}
else { /* stack level */
if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) {
luaL_pushfail(L); /* level out of range */
return 1;
}
}
if (!lua_getinfo(L1, options, &ar))
return luaL_argerror(L, arg+2, "invalid option");
lua_newtable(L); /* table to collect results */
if (strchr(options, 'S')) {
lua_pushlstring(L, ar.source, ar.srclen);
lua_setfield(L, -2, "source");
settabss(L, "short_src", ar.short_src);
settabsi(L, "linedefined", ar.linedefined);
settabsi(L, "lastlinedefined", ar.lastlinedefined);
settabss(L, "what", ar.what);
}
if (strchr(options, 'l'))
settabsi(L, "currentline", ar.currentline);
if (strchr(options, 'u')) {
settabsi(L, "nups", ar.nups);
settabsi(L, "nparams", ar.nparams);
settabsb(L, "isvararg", ar.isvararg);
}
if (strchr(options, 'n')) {
settabss(L, "name", ar.name);
settabss(L, "namewhat", ar.namewhat);
}
if (strchr(options, 'r')) {
settabsi(L, "ftransfer", ar.ftransfer);
settabsi(L, "ntransfer", ar.ntransfer);
}
if (strchr(options, 't'))
settabsb(L, "istailcall", ar.istailcall);
if (strchr(options, 'L'))
treatstackoption(L, L1, "activelines");
if (strchr(options, 'f'))
treatstackoption(L, L1, "func");
return 1; /* return table */
}
static int db_getlocal (lua_State *L) {
int arg;
lua_State *L1 = getthread(L, &arg);
int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */
if (lua_isfunction(L, arg + 1)) { /* function argument? */
lua_pushvalue(L, arg + 1); /* push function */
lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */
return 1; /* return only name (there is no value) */
}
else { /* stack-level argument */
lua_Debug ar;
const char *name;
int level = (int)luaL_checkinteger(L, arg + 1);
if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range");
checkstack(L, L1, 1);
name = lua_getlocal(L1, &ar, nvar);
if (name) {
lua_xmove(L1, L, 1); /* move local value */
lua_pushstring(L, name); /* push name */
lua_rotate(L, -2, 1); /* re-order */
return 2;
}
else {
luaL_pushfail(L); /* no name (nor value) */
return 1;
}
}
}
static int db_setlocal (lua_State *L) {
int arg;
const char *name;
lua_State *L1 = getthread(L, &arg);
lua_Debug ar;
int level = (int)luaL_checkinteger(L, arg + 1);
int nvar = (int)luaL_checkinteger(L, arg + 2);
if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range");
luaL_checkany(L, arg+3);
lua_settop(L, arg+3);
checkstack(L, L1, 1);
lua_xmove(L, L1, 1);
name = lua_setlocal(L1, &ar, nvar);
if (name == NULL)
lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */
lua_pushstring(L, name);
return 1;
}
/*
** get (if 'get' is true) or set an upvalue from a closure
*/
static int auxupvalue (lua_State *L, int get) {
const char *name;
int n = (int)luaL_checkinteger(L, 2); /* upvalue index */
luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */
name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
if (name == NULL) return 0;
lua_pushstring(L, name);
lua_insert(L, -(get+1)); /* no-op if get is false */
return get + 1;
}
static int db_getupvalue (lua_State *L) {
return auxupvalue(L, 1);
}
static int db_setupvalue (lua_State *L) {
luaL_checkany(L, 3);
return auxupvalue(L, 0);
}
/*
** Check whether a given upvalue from a given closure exists and
** returns its index
*/
static void *checkupval (lua_State *L, int argf, int argnup, int *pnup) {
void *id;
int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */
luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */
id = lua_upvalueid(L, argf, nup);
if (pnup) {
luaL_argcheck(L, id != NULL, argnup, "invalid upvalue index");
*pnup = nup;
}
return id;
}
static int db_upvalueid (lua_State *L) {
void *id = checkupval(L, 1, 2, NULL);
if (id != NULL)
lua_pushlightuserdata(L, id);
else
luaL_pushfail(L);
return 1;
}
static int db_upvaluejoin (lua_State *L) {
int n1, n2;
checkupval(L, 1, 2, &n1);
checkupval(L, 3, 4, &n2);
luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
lua_upvaluejoin(L, 1, n1, 3, n2);
return 0;
}
/*
** Call hook function registered at hook table for the current
** thread (if there is one)
*/
static void hookf (lua_State *L, lua_Debug *ar) {
static const char *const hooknames[] =
{"call", "return", "line", "count", "tail call"};
lua_getfield(L, LUA_REGISTRYINDEX, HOOKKEY);
lua_pushthread(L);
if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */
lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */
if (ar->currentline >= 0)
lua_pushinteger(L, ar->currentline); /* push current line */
else lua_pushnil(L);
lua_assert(lua_getinfo(L, "lS", ar));
lua_call(L, 2, 0); /* call hook function */
}
}
/*
** Convert a string mask (for 'sethook') into a bit mask
*/
static int makemask (const char *smask, int count) {
int mask = 0;
if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
if (strchr(smask, 'r')) mask |= LUA_MASKRET;
if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
if (count > 0) mask |= LUA_MASKCOUNT;
return mask;
}
/*
** Convert a bit mask (for 'gethook') into a string mask
*/
static char *unmakemask (int mask, char *smask) {
int i = 0;
if (mask & LUA_MASKCALL) smask[i++] = 'c';
if (mask & LUA_MASKRET) smask[i++] = 'r';
if (mask & LUA_MASKLINE) smask[i++] = 'l';
smask[i] = '\0';
return smask;
}
static int db_sethook (lua_State *L) {
int arg, mask, count;
lua_Hook func;
lua_State *L1 = getthread(L, &arg);
if (lua_isnoneornil(L, arg+1)) { /* no hook? */
lua_settop(L, arg+1);
func = NULL; mask = 0; count = 0; /* turn off hooks */
}
else {
const char *smask = luaL_checkstring(L, arg+2);
luaL_checktype(L, arg+1, LUA_TFUNCTION);
count = (int)luaL_optinteger(L, arg + 3, 0);
func = hookf; mask = makemask(smask, count);
}
if (!luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)) {
/* table just created; initialize it */
lua_pushliteral(L, "k");
lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */
lua_pushvalue(L, -1);
lua_setmetatable(L, -2); /* metatable(hooktable) = hooktable */
}
checkstack(L, L1, 1);
lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */
lua_pushvalue(L, arg + 1); /* value (hook function) */
lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */
lua_sethook(L1, func, mask, count);
return 0;
}
static int db_gethook (lua_State *L) {
int arg;
lua_State *L1 = getthread(L, &arg);
char buff[5];
int mask = lua_gethookmask(L1);
lua_Hook hook = lua_gethook(L1);
if (hook == NULL) { /* no hook? */
luaL_pushfail(L);
return 1;
}
else if (hook != hookf) /* external hook? */
lua_pushliteral(L, "external hook");
else { /* hook table must exist */
lua_getfield(L, LUA_REGISTRYINDEX, HOOKKEY);
checkstack(L, L1, 1);
lua_pushthread(L1); lua_xmove(L1, L, 1);
lua_rawget(L, -2); /* 1st result = hooktable[L1] */
lua_remove(L, -2); /* remove hook table */
}
lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */
lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */
return 3;
}
static int db_debug (lua_State *L) {
for (;;) {
char buffer[250];
lua_writestringerror("%s", "lua_debug> ");
if (fgets(buffer, sizeof(buffer), stdin) == NULL ||
strcmp(buffer, "cont\n") == 0)
return 0;
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
lua_pcall(L, 0, 0, 0))
lua_writestringerror("%s\n", luaL_tolstring(L, -1, NULL));
lua_settop(L, 0); /* remove eventual returns */
}
}
static int db_traceback (lua_State *L) {
int arg;
lua_State *L1 = getthread(L, &arg);
const char *msg = lua_tostring(L, arg + 1);
if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */
lua_pushvalue(L, arg + 1); /* return it untouched */
else {
int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0);
luaL_traceback(L, L1, msg, level);
}
return 1;
}
static int db_setcstacklimit (lua_State *L) {
int limit = (int)luaL_checkinteger(L, 1);
int res = lua_setcstacklimit(L, limit);
lua_pushinteger(L, res);
return 1;
}
static const luaL_Reg dblib[] = {
{"debug", db_debug},
{"getuservalue", db_getuservalue},
{"gethook", db_gethook},
{"getinfo", db_getinfo},
{"getlocal", db_getlocal},
{"getregistry", db_getregistry},
{"getmetatable", db_getmetatable},
{"getupvalue", db_getupvalue},
{"upvaluejoin", db_upvaluejoin},
{"upvalueid", db_upvalueid},
{"setuservalue", db_setuservalue},
{"sethook", db_sethook},
{"setlocal", db_setlocal},
{"setmetatable", db_setmetatable},
{"setupvalue", db_setupvalue},
{"traceback", db_traceback},
{"setcstacklimit", db_setcstacklimit},
{NULL, NULL}
};
LUAMOD_API int luaopen_debug (lua_State *L) {
luaL_newlib(L, dblib);
return 1;
}

View File

@@ -0,0 +1,971 @@
/*
** $Id: ldebug.c $
** Debug Interface
** See Copyright Notice in lua.h
*/
#define ldebug_c
#define LUA_CORE
#include "lprefix.h"
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#include "lua.h"
#include "lapi.h"
#include "lcode.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
#include "lvm.h"
#define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL)
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
const char **name);
static const char strlocal[] = "local";
static const char strupval[] = "upvalue";
static int currentpc (CallInfo *ci) {
lua_assert(isLua(ci));
return pcRel(ci->u.l.savedpc, ci_func(ci)->p);
}
/*
** Get a "base line" to find the line corresponding to an instruction.
** Base lines are regularly placed at MAXIWTHABS intervals, so usually
** an integer division gets the right place. When the source file has
** large sequences of empty/comment lines, it may need extra entries,
** so the original estimate needs a correction.
** If the original estimate is -1, the initial 'if' ensures that the
** 'while' will run at least once.
** The assertion that the estimate is a lower bound for the correct base
** is valid as long as the debug info has been generated with the same
** value for MAXIWTHABS or smaller. (Previous releases use a little
** smaller value.)
*/
static int getbaseline (const Proto *f, int pc, int *basepc) {
if (f->sizeabslineinfo == 0 || pc < f->abslineinfo[0].pc) {
*basepc = -1; /* start from the beginning */
return f->linedefined;
}
else {
int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */
/* estimate must be a lower bound of the correct base */
lua_assert(i < 0 ||
(i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
i++; /* low estimate; adjust it */
*basepc = f->abslineinfo[i].pc;
return f->abslineinfo[i].line;
}
}
/*
** Get the line corresponding to instruction 'pc' in function 'f';
** first gets a base line and from there does the increments until
** the desired instruction.
*/
int luaG_getfuncline (const Proto *f, int pc) {
if (f->lineinfo == NULL) /* no debug information? */
return -1;
else {
int basepc;
int baseline = getbaseline(f, pc, &basepc);
while (basepc++ < pc) { /* walk until given instruction */
lua_assert(f->lineinfo[basepc] != ABSLINEINFO);
baseline += f->lineinfo[basepc]; /* correct line */
}
return baseline;
}
}
static int getcurrentline (CallInfo *ci) {
return luaG_getfuncline(ci_func(ci)->p, currentpc(ci));
}
/*
** Set 'trap' for all active Lua frames.
** This function can be called during a signal, under "reasonable"
** assumptions. A new 'ci' is completely linked in the list before it
** becomes part of the "active" list, and we assume that pointers are
** atomic; see comment in next function.
** (A compiler doing interprocedural optimizations could, theoretically,
** reorder memory writes in such a way that the list could be
** temporarily broken while inserting a new element. We simply assume it
** has no good reasons to do that.)
*/
static void settraps (CallInfo *ci) {
for (; ci != NULL; ci = ci->previous)
if (isLua(ci))
ci->u.l.trap = 1;
}
/*
** This function can be called during a signal, under "reasonable"
** assumptions.
** Fields 'basehookcount' and 'hookcount' (set by 'resethookcount')
** are for debug only, and it is no problem if they get arbitrary
** values (causes at most one wrong hook call). 'hookmask' is an atomic
** value. We assume that pointers are atomic too (e.g., gcc ensures that
** for all platforms where it runs). Moreover, 'hook' is always checked
** before being called (see 'luaD_hook').
*/
LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
if (func == NULL || mask == 0) { /* turn off hooks? */
mask = 0;
func = NULL;
}
L->hook = func;
L->basehookcount = count;
resethookcount(L);
L->hookmask = cast_byte(mask);
if (mask)
settraps(L->ci); /* to trace inside 'luaV_execute' */
}
LUA_API lua_Hook lua_gethook (lua_State *L) {
return L->hook;
}
LUA_API int lua_gethookmask (lua_State *L) {
return L->hookmask;
}
LUA_API int lua_gethookcount (lua_State *L) {
return L->basehookcount;
}
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
int status;
CallInfo *ci;
if (level < 0) return 0; /* invalid (negative) level */
lua_lock(L);
for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous)
level--;
if (level == 0 && ci != &L->base_ci) { /* level found? */
status = 1;
ar->i_ci = ci;
}
else status = 0; /* no such level */
lua_unlock(L);
return status;
}
static const char *upvalname (const Proto *p, int uv) {
TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name);
if (s == NULL) return "?";
else return getstr(s);
}
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
if (clLvalue(s2v(ci->func.p))->p->is_vararg) {
int nextra = ci->u.l.nextraargs;
if (n >= -nextra) { /* 'n' is negative */
*pos = ci->func.p - nextra - (n + 1);
return "(vararg)"; /* generic name for any vararg */
}
}
return NULL; /* no such vararg */
}
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
StkId base = ci->func.p + 1;
const char *name = NULL;
if (isLua(ci)) {
if (n < 0) /* access to vararg values? */
return findvararg(ci, n, pos);
else
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
}
if (name == NULL) { /* no 'standard' name? */
StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
/* generic name for any valid slot */
name = isLua(ci) ? "(temporary)" : "(C temporary)";
}
else
return NULL; /* no name */
}
if (pos)
*pos = base + (n - 1);
return name;
}
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name;
lua_lock(L);
if (ar == NULL) { /* information about non-active function? */
if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
name = NULL;
else /* consider live variables at function start (parameters) */
name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
}
else { /* active function; get information through 'ar' */
StkId pos = NULL; /* to avoid warnings */
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobjs2s(L, L->top.p, pos);
api_incr_top(L);
}
}
lua_unlock(L);
return name;
}
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
StkId pos = NULL; /* to avoid warnings */
const char *name;
lua_lock(L);
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobjs2s(L, pos, L->top.p - 1);
L->top.p--; /* pop value */
}
lua_unlock(L);
return name;
}
static void funcinfo (lua_Debug *ar, Closure *cl) {
if (!LuaClosure(cl)) {
ar->source = "=[C]";
ar->srclen = LL("=[C]");
ar->linedefined = -1;
ar->lastlinedefined = -1;
ar->what = "C";
}
else {
const Proto *p = cl->l.p;
if (p->source) {
ar->source = getstr(p->source);
ar->srclen = tsslen(p->source);
}
else {
ar->source = "=?";
ar->srclen = LL("=?");
}
ar->linedefined = p->linedefined;
ar->lastlinedefined = p->lastlinedefined;
ar->what = (ar->linedefined == 0) ? "main" : "Lua";
}
luaO_chunkid(ar->short_src, ar->source, ar->srclen);
}
static int nextline (const Proto *p, int currentline, int pc) {
if (p->lineinfo[pc] != ABSLINEINFO)
return currentline + p->lineinfo[pc];
else
return luaG_getfuncline(p, pc);
}
static void collectvalidlines (lua_State *L, Closure *f) {
if (!LuaClosure(f)) {
setnilvalue(s2v(L->top.p));
api_incr_top(L);
}
else {
const Proto *p = f->l.p;
int currentline = p->linedefined;
Table *t = luaH_new(L); /* new table to store active lines */
sethvalue2s(L, L->top.p, t); /* push it on stack */
api_incr_top(L);
if (p->lineinfo != NULL) { /* proto with debug information? */
int i;
TValue v;
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
if (!p->is_vararg) /* regular function? */
i = 0; /* consider all instructions */
else { /* vararg function */
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
currentline = nextline(p, currentline, 0);
i = 1; /* skip first instruction (OP_VARARGPREP) */
}
for (; i < p->sizelineinfo; i++) { /* for each instruction */
currentline = nextline(p, currentline, i); /* get its line */
luaH_setint(L, t, currentline, &v); /* table[line] = true */
}
}
}
}
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
/* calling function is a known function? */
if (ci != NULL && !(ci->callstatus & CIST_TAIL))
return funcnamefromcall(L, ci->previous, name);
else return NULL; /* no way to find a name */
}
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
Closure *f, CallInfo *ci) {
int status = 1;
for (; *what; what++) {
switch (*what) {
case 'S': {
funcinfo(ar, f);
break;
}
case 'l': {
ar->currentline = (ci && isLua(ci)) ? getcurrentline(ci) : -1;
break;
}
case 'u': {
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
if (!LuaClosure(f)) {
ar->isvararg = 1;
ar->nparams = 0;
}
else {
ar->isvararg = f->l.p->is_vararg;
ar->nparams = f->l.p->numparams;
}
break;
}
case 't': {
ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;
break;
}
case 'n': {
ar->namewhat = getfuncname(L, ci, &ar->name);
if (ar->namewhat == NULL) {
ar->namewhat = ""; /* not found */
ar->name = NULL;
}
break;
}
case 'r': {
if (ci == NULL || !(ci->callstatus & CIST_TRAN))
ar->ftransfer = ar->ntransfer = 0;
else {
ar->ftransfer = ci->u2.transferinfo.ftransfer;
ar->ntransfer = ci->u2.transferinfo.ntransfer;
}
break;
}
case 'L':
case 'f': /* handled by lua_getinfo */
break;
default: status = 0; /* invalid option */
}
}
return status;
}
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
int status;
Closure *cl;
CallInfo *ci;
TValue *func;
lua_lock(L);
if (*what == '>') {
ci = NULL;
func = s2v(L->top.p - 1);
api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */
L->top.p--; /* pop function */
}
else {
ci = ar->i_ci;
func = s2v(ci->func.p);
lua_assert(ttisfunction(func));
}
cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) {
setobj2s(L, L->top.p, func);
api_incr_top(L);
}
if (strchr(what, 'L'))
collectvalidlines(L, cl);
lua_unlock(L);
return status;
}
/*
** {======================================================
** Symbolic Execution
** =======================================================
*/
static int filterpc (int pc, int jmptarget) {
if (pc < jmptarget) /* is code conditional (inside a jump)? */
return -1; /* cannot know who sets that register */
else return pc; /* current position sets that register */
}
/*
** Try to find last instruction before 'lastpc' that modified register 'reg'.
*/
static int findsetreg (const Proto *p, int lastpc, int reg) {
int pc;
int setreg = -1; /* keep last instruction that changed 'reg' */
int jmptarget = 0; /* any code before this address is conditional */
if (testMMMode(GET_OPCODE(p->code[lastpc])))
lastpc--; /* previous instruction was not actually executed */
for (pc = 0; pc < lastpc; pc++) {
Instruction i = p->code[pc];
OpCode op = GET_OPCODE(i);
int a = GETARG_A(i);
int change; /* true if current instruction changed 'reg' */
switch (op) {
case OP_LOADNIL: { /* set registers from 'a' to 'a+b' */
int b = GETARG_B(i);
change = (a <= reg && reg <= a + b);
break;
}
case OP_TFORCALL: { /* affect all regs above its base */
change = (reg >= a + 2);
break;
}
case OP_CALL:
case OP_TAILCALL: { /* affect all registers above base */
change = (reg >= a);
break;
}
case OP_JMP: { /* doesn't change registers, but changes 'jmptarget' */
int b = GETARG_sJ(i);
int dest = pc + 1 + b;
/* jump does not skip 'lastpc' and is larger than current one? */
if (dest <= lastpc && dest > jmptarget)
jmptarget = dest; /* update 'jmptarget' */
change = 0;
break;
}
default: /* any instruction that sets A */
change = (testAMode(op) && reg == a);
break;
}
if (change)
setreg = filterpc(pc, jmptarget);
}
return setreg;
}
/*
** Find a "name" for the constant 'c'.
*/
static const char *kname (const Proto *p, int index, const char **name) {
TValue *kvalue = &p->k[index];
if (ttisstring(kvalue)) {
*name = getstr(tsvalue(kvalue));
return "constant";
}
else {
*name = "?";
return NULL;
}
}
static const char *basicgetobjname (const Proto *p, int *ppc, int reg,
const char **name) {
int pc = *ppc;
*name = luaF_getlocalname(p, reg + 1, pc);
if (*name) /* is a local? */
return strlocal;
/* else try symbolic execution */
*ppc = pc = findsetreg(p, pc, reg);
if (pc != -1) { /* could find instruction? */
Instruction i = p->code[pc];
OpCode op = GET_OPCODE(i);
switch (op) {
case OP_MOVE: {
int b = GETARG_B(i); /* move from 'b' to 'a' */
if (b < GETARG_A(i))
return basicgetobjname(p, ppc, b, name); /* get name for 'b' */
break;
}
case OP_GETUPVAL: {
*name = upvalname(p, GETARG_B(i));
return strupval;
}
case OP_LOADK: return kname(p, GETARG_Bx(i), name);
case OP_LOADKX: return kname(p, GETARG_Ax(p->code[pc + 1]), name);
default: break;
}
}
return NULL; /* could not find reasonable name */
}
/*
** Find a "name" for the register 'c'.
*/
static void rname (const Proto *p, int pc, int c, const char **name) {
const char *what = basicgetobjname(p, &pc, c, name); /* search for 'c' */
if (!(what && *what == 'c')) /* did not find a constant name? */
*name = "?";
}
/*
** Find a "name" for a 'C' value in an RK instruction.
*/
static void rkname (const Proto *p, int pc, Instruction i, const char **name) {
int c = GETARG_C(i); /* key index */
if (GETARG_k(i)) /* is 'c' a constant? */
kname(p, c, name);
else /* 'c' is a register */
rname(p, pc, c, name);
}
/*
** Check whether table being indexed by instruction 'i' is the
** environment '_ENV'. If the table is an upvalue, get its name;
** otherwise, find some "name" for the table and check whether
** that name is the name of a local variable (and not, for instance,
** a string). Then check that, if there is a name, it is '_ENV'.
*/
static const char *isEnv (const Proto *p, int pc, Instruction i, int isup) {
int t = GETARG_B(i); /* table index */
const char *name; /* name of indexed variable */
if (isup) /* is 't' an upvalue? */
name = upvalname(p, t);
else { /* 't' is a register */
const char *what = basicgetobjname(p, &pc, t, &name);
if (what != strlocal && what != strupval)
name = NULL; /* cannot be the variable _ENV */
}
return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field";
}
/*
** Extend 'basicgetobjname' to handle table accesses
*/
static const char *getobjname (const Proto *p, int lastpc, int reg,
const char **name) {
const char *kind = basicgetobjname(p, &lastpc, reg, name);
if (kind != NULL)
return kind;
else if (lastpc != -1) { /* could find instruction? */
Instruction i = p->code[lastpc];
OpCode op = GET_OPCODE(i);
switch (op) {
case OP_GETTABUP: {
int k = GETARG_C(i); /* key index */
kname(p, k, name);
return isEnv(p, lastpc, i, 1);
}
case OP_GETTABLE: {
int k = GETARG_C(i); /* key index */
rname(p, lastpc, k, name);
return isEnv(p, lastpc, i, 0);
}
case OP_GETI: {
*name = "integer index";
return "field";
}
case OP_GETFIELD: {
int k = GETARG_C(i); /* key index */
kname(p, k, name);
return isEnv(p, lastpc, i, 0);
}
case OP_SELF: {
rkname(p, lastpc, i, name);
return "method";
}
default: break; /* go through to return NULL */
}
}
return NULL; /* could not find reasonable name */
}
/*
** Try to find a name for a function based on the code that called it.
** (Only works when function was called by a Lua function.)
** Returns what the name is (e.g., "for iterator", "method",
** "metamethod") and sets '*name' to point to the name.
*/
static const char *funcnamefromcode (lua_State *L, const Proto *p,
int pc, const char **name) {
TMS tm = (TMS)0; /* (initial value avoids warnings) */
Instruction i = p->code[pc]; /* calling instruction */
switch (GET_OPCODE(i)) {
case OP_CALL:
case OP_TAILCALL:
return getobjname(p, pc, GETARG_A(i), name); /* get function name */
case OP_TFORCALL: { /* for iterator */
*name = "for iterator";
return "for iterator";
}
/* other instructions can do calls through metamethods */
case OP_SELF: case OP_GETTABUP: case OP_GETTABLE:
case OP_GETI: case OP_GETFIELD:
tm = TM_INDEX;
break;
case OP_SETTABUP: case OP_SETTABLE: case OP_SETI: case OP_SETFIELD:
tm = TM_NEWINDEX;
break;
case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
tm = cast(TMS, GETARG_C(i));
break;
}
case OP_UNM: tm = TM_UNM; break;
case OP_BNOT: tm = TM_BNOT; break;
case OP_LEN: tm = TM_LEN; break;
case OP_CONCAT: tm = TM_CONCAT; break;
case OP_EQ: tm = TM_EQ; break;
/* no cases for OP_EQI and OP_EQK, as they don't call metamethods */
case OP_LT: case OP_LTI: case OP_GTI: tm = TM_LT; break;
case OP_LE: case OP_LEI: case OP_GEI: tm = TM_LE; break;
case OP_CLOSE: case OP_RETURN: tm = TM_CLOSE; break;
default:
return NULL; /* cannot find a reasonable name */
}
*name = getshrstr(G(L)->tmname[tm]) + 2;
return "metamethod";
}
/*
** Try to find a name for a function based on how it was called.
*/
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
const char **name) {
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
*name = "?";
return "hook";
}
else if (ci->callstatus & CIST_FIN) { /* was it called as a finalizer? */
*name = "__gc";
return "metamethod"; /* report it as such */
}
else if (isLua(ci))
return funcnamefromcode(L, ci_func(ci)->p, currentpc(ci), name);
else
return NULL;
}
/* }====================================================== */
/*
** Check whether pointer 'o' points to some value in the stack frame of
** the current function and, if so, returns its index. Because 'o' may
** not point to a value in this stack, we cannot compare it with the
** region boundaries (undefined behavior in ISO C).
*/
static int instack (CallInfo *ci, const TValue *o) {
int pos;
StkId base = ci->func.p + 1;
for (pos = 0; base + pos < ci->top.p; pos++) {
if (o == s2v(base + pos))
return pos;
}
return -1; /* not found */
}
/*
** Checks whether value 'o' came from an upvalue. (That can only happen
** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on
** upvalues.)
*/
static const char *getupvalname (CallInfo *ci, const TValue *o,
const char **name) {
LClosure *c = ci_func(ci);
int i;
for (i = 0; i < c->nupvalues; i++) {
if (c->upvals[i]->v.p == o) {
*name = upvalname(c->p, i);
return strupval;
}
}
return NULL;
}
static const char *formatvarinfo (lua_State *L, const char *kind,
const char *name) {
if (kind == NULL)
return ""; /* no information */
else
return luaO_pushfstring(L, " (%s '%s')", kind, name);
}
/*
** Build a string with a "description" for the value 'o', such as
** "variable 'x'" or "upvalue 'y'".
*/
static const char *varinfo (lua_State *L, const TValue *o) {
CallInfo *ci = L->ci;
const char *name = NULL; /* to avoid warnings */
const char *kind = NULL;
if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
if (!kind) { /* not an upvalue? */
int reg = instack(ci, o); /* try a register */
if (reg >= 0) /* is 'o' a register? */
kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
}
}
return formatvarinfo(L, kind, name);
}
/*
** Raise a type error
*/
static l_noret typeerror (lua_State *L, const TValue *o, const char *op,
const char *extra) {
const char *t = luaT_objtypename(L, o);
luaG_runerror(L, "attempt to %s a %s value%s", op, t, extra);
}
/*
** Raise a type error with "standard" information about the faulty
** object 'o' (using 'varinfo').
*/
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
typeerror(L, o, op, varinfo(L, o));
}
/*
** Raise an error for calling a non-callable object. Try to find a name
** for the object based on how it was called ('funcnamefromcall'); if it
** cannot get a name there, try 'varinfo'.
*/
l_noret luaG_callerror (lua_State *L, const TValue *o) {
CallInfo *ci = L->ci;
const char *name = NULL; /* to avoid warnings */
const char *kind = funcnamefromcall(L, ci, &name);
const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o);
typeerror(L, o, "call", extra);
}
l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what) {
luaG_runerror(L, "bad 'for' %s (number expected, got %s)",
what, luaT_objtypename(L, o));
}
l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) {
if (ttisstring(p1) || cvt2str(p1)) p1 = p2;
luaG_typeerror(L, p1, "concatenate");
}
l_noret luaG_opinterror (lua_State *L, const TValue *p1,
const TValue *p2, const char *msg) {
if (!ttisnumber(p1)) /* first operand is wrong? */
p2 = p1; /* now second is wrong */
luaG_typeerror(L, p2, msg);
}
/*
** Error when both values are convertible to numbers, but not to integers
*/
l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
lua_Integer temp;
if (!luaV_tointegerns(p1, &temp, LUA_FLOORN2I))
p2 = p1;
luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2));
}
l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
const char *t1 = luaT_objtypename(L, p1);
const char *t2 = luaT_objtypename(L, p2);
if (strcmp(t1, t2) == 0)
luaG_runerror(L, "attempt to compare two %s values", t1);
else
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
}
/* add src:line information to 'msg' */
const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
int line) {
char buff[LUA_IDSIZE];
if (src)
luaO_chunkid(buff, getstr(src), tsslen(src));
else { /* no source available; use "?" instead */
buff[0] = '?'; buff[1] = '\0';
}
return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
}
l_noret luaG_errormsg (lua_State *L) {
if (L->errfunc != 0) { /* is there an error handling function? */
StkId errfunc = restorestack(L, L->errfunc);
lua_assert(ttisfunction(s2v(errfunc)));
setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
setobjs2s(L, L->top.p - 1, errfunc); /* push function */
L->top.p++; /* assume EXTRA_STACK */
luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
}
luaD_throw(L, LUA_ERRRUN);
}
l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
CallInfo *ci = L->ci;
const char *msg;
va_list argp;
luaC_checkGC(L); /* error message uses memory */
va_start(argp, fmt);
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp);
if (isLua(ci)) { /* if Lua function, add source:line information */
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
L->top.p--;
}
luaG_errormsg(L);
}
/*
** Check whether new instruction 'newpc' is in a different line from
** previous instruction 'oldpc'. More often than not, 'newpc' is only
** one or a few instructions after 'oldpc' (it must be after, see
** caller), so try to avoid calling 'luaG_getfuncline'. If they are
** too far apart, there is a good chance of a ABSLINEINFO in the way,
** so it goes directly to 'luaG_getfuncline'.
*/
static int changedline (const Proto *p, int oldpc, int newpc) {
if (p->lineinfo == NULL) /* no debug information? */
return 0;
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
int delta = 0; /* line difference */
int pc = oldpc;
for (;;) {
int lineinfo = p->lineinfo[++pc];
if (lineinfo == ABSLINEINFO)
break; /* cannot compute delta; fall through */
delta += lineinfo;
if (pc == newpc)
return (delta != 0); /* delta computed successfully */
}
}
/* either instructions are too far apart or there is an absolute line
info in the way; compute line difference explicitly */
return (luaG_getfuncline(p, oldpc) != luaG_getfuncline(p, newpc));
}
/*
** Traces Lua calls. If code is running the first instruction of a function,
** and function is not vararg, and it is not coming from an yield,
** calls 'luaD_hookcall'. (Vararg functions will call 'luaD_hookcall'
** after adjusting its variable arguments; otherwise, they could call
** a line/count hook before the call hook. Functions coming from
** an yield already called 'luaD_hookcall' before yielding.)
*/
int luaG_tracecall (lua_State *L) {
CallInfo *ci = L->ci;
Proto *p = ci_func(ci)->p;
ci->u.l.trap = 1; /* ensure hooks will be checked */
if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */
if (p->is_vararg)
return 0; /* hooks will start at VARARGPREP instruction */
else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yieded? */
luaD_hookcall(L, ci); /* check 'call' hook */
}
return 1; /* keep 'trap' on */
}
/*
** Traces the execution of a Lua function. Called before the execution
** of each opcode, when debug is on. 'L->oldpc' stores the last
** instruction traced, to detect line changes. When entering a new
** function, 'npci' will be zero and will test as a new line whatever
** the value of 'oldpc'. Some exceptional conditions may return to
** a function without setting 'oldpc'. In that case, 'oldpc' may be
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
** at most causes an extra call to a line hook.)
** This function is not "Protected" when called, so it should correct
** 'L->top.p' before calling anything that can run the GC.
*/
int luaG_traceexec (lua_State *L, const Instruction *pc) {
CallInfo *ci = L->ci;
lu_byte mask = L->hookmask;
const Proto *p = ci_func(ci)->p;
int counthook;
if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */
ci->u.l.trap = 0; /* don't need to stop again */
return 0; /* turn off 'trap' */
}
pc++; /* reference is always next instruction */
ci->u.l.savedpc = pc; /* save 'pc' */
counthook = (mask & LUA_MASKCOUNT) && (--L->hookcount == 0);
if (counthook)
resethookcount(L); /* reset count */
else if (!(mask & LUA_MASKLINE))
return 1; /* no line hook and count != 0; nothing to be done now */
if (ci->callstatus & CIST_HOOKYIELD) { /* hook yielded last time? */
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
return 1; /* do not call hook again (VM yielded, so it did not move) */
}
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
L->top.p = ci->top.p; /* correct top */
if (counthook)
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
if (mask & LUA_MASKLINE) {
/* 'L->oldpc' may be invalid; use zero in this case */
int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0;
int npci = pcRel(pc, p);
if (npci <= oldpc || /* call hook when jump back (loop), */
changedline(p, oldpc, npci)) { /* or when enter new line */
int newline = luaG_getfuncline(p, npci);
luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */
}
L->oldpc = npci; /* 'pc' of last call to line hook */
}
if (L->status == LUA_YIELD) { /* did hook yield? */
if (counthook)
L->hookcount = 1; /* undo decrement to zero */
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
luaD_throw(L, LUA_YIELD);
}
return 1; /* keep 'trap' on */
}

View File

@@ -0,0 +1,64 @@
/*
** $Id: ldebug.h $
** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h
*/
#ifndef ldebug_h
#define ldebug_h
#include "lstate.h"
#define pcRel(pc, p) (cast_int((pc) - (p)->code) - 1)
/* Active Lua function (given call info) */
#define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
#define resethookcount(L) (L->hookcount = L->basehookcount)
/*
** mark for entries in 'lineinfo' array that has absolute information in
** 'abslineinfo' array
*/
#define ABSLINEINFO (-0x80)
/*
** MAXimum number of successive Instructions WiTHout ABSolute line
** information. (A power of two allows fast divisions.)
*/
#if !defined(MAXIWTHABS)
#define MAXIWTHABS 128
#endif
LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc);
LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n,
StkId *pos);
LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
const char *opname);
LUAI_FUNC l_noret luaG_callerror (lua_State *L, const TValue *o);
LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o,
const char *what);
LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1,
const TValue *p2);
LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1,
const TValue *p2,
const char *msg);
LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,
const TValue *p2);
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
const TValue *p2);
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
TString *src, int line);
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
LUAI_FUNC int luaG_tracecall (lua_State *L);
#endif

1035
src/lua/lua-5.4.8/src/ldo.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,88 @@
/*
** $Id: ldo.h $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
#ifndef ldo_h
#define ldo_h
#include "llimits.h"
#include "lobject.h"
#include "lstate.h"
#include "lzio.h"
/*
** Macro to check stack size and grow stack if needed. Parameters
** 'pre'/'pos' allow the macro to preserve a pointer into the
** stack across reallocations, doing the work only when needed.
** It also allows the running of one GC step when the stack is
** reallocated.
** 'condmovestack' is used in heavy tests to force a stack reallocation
** at every check.
*/
#define luaD_checkstackaux(L,n,pre,pos) \
if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
{ pre; luaD_growstack(L, n, 1); pos; } \
else { condmovestack(L,pre,pos); }
/* In general, 'pre'/'pos' are empty (nothing to save) */
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)
#define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
/* macro to check stack size, preserving 'p' */
#define checkstackp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
/* macro to check stack size and GC, preserving 'p' */
#define checkstackGCp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
luaC_checkGC(L), /* stack grow uses memory */ \
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
/* macro to check stack size and GC */
#define checkstackGC(L,fsize) \
luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0)
/* type of protected functions, to be ran by 'runprotected' */
typedef void (*Pfunc) (lua_State *L, void *ud);
LUAI_FUNC l_noret luaD_errerr (lua_State *L);
LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop);
LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
const char *mode);
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
int fTransfer, int nTransfer);
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int narg1, int delta);
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef);
LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres);
LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror);
LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror);
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
LUAI_FUNC void luaD_inctop (lua_State *L);
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
#endif

Some files were not shown because too many files have changed in this diff Show More