mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Merge remote-tracking branch 'upstream/master' into Visuals-Vol-2
This commit is contained in:
commit
e7c7441429
285 changed files with 8894 additions and 4654 deletions
1
.gitattributes
vendored
1
.gitattributes
vendored
|
@ -5,3 +5,4 @@
|
|||
*.h diff=cpp
|
||||
|
||||
*.gltf binary
|
||||
*.x binary
|
||||
|
|
2
.github/workflows/linux.yml
vendored
2
.github/workflows/linux.yml
vendored
|
@ -49,6 +49,8 @@ jobs:
|
|||
env:
|
||||
CC: gcc-7
|
||||
CXX: g++-7
|
||||
# Test fallback SHA implementations
|
||||
CMAKE_FLAGS: '-DENABLE_OPENSSL=0'
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
|
|
2
CNAME
2
CNAME
|
@ -1 +1 @@
|
|||
api.minetest.net
|
||||
api.luanti.org
|
||||
|
|
|
@ -63,6 +63,8 @@ Zughy:
|
|||
textures/base/pack/settings_btn.png
|
||||
textures/base/pack/settings_info.png
|
||||
textures/base/pack/settings_reset.png
|
||||
textures/base/pack/server_url.png
|
||||
textures/base/pack/server_view_clients.png
|
||||
|
||||
appgurueu:
|
||||
textures/base/pack/server_incompatible.png
|
||||
|
|
|
@ -26,7 +26,7 @@ Table of Contents
|
|||
Further documentation
|
||||
----------------------
|
||||
- Website: https://www.luanti.org/
|
||||
- Wiki: https://wiki.minetest.net/
|
||||
- Wiki: https://wiki.luanti.org/
|
||||
- Forum: https://forum.luanti.org/
|
||||
- GitHub: https://github.com/minetest/minetest/
|
||||
- [Developer documentation](doc/developing/)
|
||||
|
|
|
@ -44,6 +44,7 @@ core.features = {
|
|||
bulk_lbms = true,
|
||||
abm_without_neighbors = true,
|
||||
biome_weights = true,
|
||||
particle_blend_clip = true,
|
||||
}
|
||||
|
||||
function core.has_feature(arg)
|
||||
|
|
|
@ -36,11 +36,7 @@ end
|
|||
|
||||
|
||||
function core.setting_get_pos(name)
|
||||
local value = core.settings:get(name)
|
||||
if not value then
|
||||
return nil
|
||||
end
|
||||
return core.string_to_pos(value)
|
||||
return core.settings:get_pos(name)
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
local static_spawnpoint_string = core.settings:get("static_spawnpoint")
|
||||
if static_spawnpoint_string and
|
||||
static_spawnpoint_string ~= "" and
|
||||
not core.setting_get_pos("static_spawnpoint") then
|
||||
not core.settings:get_pos("static_spawnpoint") then
|
||||
error('The static_spawnpoint setting is invalid: "' ..
|
||||
static_spawnpoint_string .. '"')
|
||||
end
|
||||
|
|
49
builtin/mainmenu/dlg_clients_list.lua
Normal file
49
builtin/mainmenu/dlg_clients_list.lua
Normal file
|
@ -0,0 +1,49 @@
|
|||
-- Luanti
|
||||
-- Copyright (C) 2024 siliconsniffer
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
local function clients_list_formspec(dialogdata)
|
||||
local TOUCH_GUI = core.settings:get_bool("touch_gui")
|
||||
local clients_list = dialogdata.server.clients_list
|
||||
local servername = dialogdata.server.name
|
||||
|
||||
local function fmt_formspec_list(clients_list)
|
||||
local escaped = {}
|
||||
for i, str in ipairs(clients_list) do
|
||||
escaped[i] = core.formspec_escape(str)
|
||||
end
|
||||
return table.concat(escaped, ",")
|
||||
end
|
||||
|
||||
local formspec = {
|
||||
"formspec_version[8]",
|
||||
"size[6,9.5]",
|
||||
TOUCH_GUI and "padding[0.01,0.01]" or "",
|
||||
"hypertext[0,0;6,1.5;;<global margin=5 halign=center valign=middle>",
|
||||
fgettext("This is the list of clients connected to\n$1",
|
||||
"<b>" .. core.hypertext_escape(servername) .. "</b>") .. "]",
|
||||
"textlist[0.5,1.5;5,6.8;;" .. fmt_formspec_list(clients_list) .. "]",
|
||||
"button[1.5,8.5;3,0.8;quit;OK]"
|
||||
}
|
||||
return table.concat(formspec, "")
|
||||
end
|
||||
|
||||
|
||||
local function clients_list_buttonhandler(this, fields)
|
||||
if fields.quit then
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function create_clientslist_dialog(server)
|
||||
local retval = dialog_create("dlg_clients_list",
|
||||
clients_list_formspec,
|
||||
clients_list_buttonhandler,
|
||||
nil)
|
||||
retval.data.server = server
|
||||
return retval
|
||||
end
|
|
@ -55,6 +55,7 @@ dofile(menupath .. DIR_DELIM .. "dlg_register.lua")
|
|||
dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_version_info.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_reinstall_mtg.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_clients_list.lua")
|
||||
|
||||
local tabs = {
|
||||
content = dofile(menupath .. DIR_DELIM .. "tab_content.lua"),
|
||||
|
|
|
@ -123,6 +123,22 @@ local function load()
|
|||
end,
|
||||
}
|
||||
|
||||
local touchscreen_layout = {
|
||||
query_text = "Touchscreen layout",
|
||||
requires = {
|
||||
touchscreen = true,
|
||||
},
|
||||
get_formspec = function(self, avail_w)
|
||||
local btn_w = math.min(avail_w, 6)
|
||||
return ("button[0,0;%f,0.8;btn_touch_layout;%s]"):format(btn_w, fgettext("Touchscreen layout")), 0.8
|
||||
end,
|
||||
on_submit = function(self, fields)
|
||||
if fields.btn_touch_layout then
|
||||
core.show_touchscreen_layout()
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
add_page({
|
||||
id = "accessibility",
|
||||
title = fgettext_ne("Accessibility"),
|
||||
|
@ -151,6 +167,8 @@ local function load()
|
|||
load_settingtypes()
|
||||
|
||||
table.insert(page_by_id.controls_keyboard_and_mouse.content, 1, change_keys)
|
||||
-- insert after "touch_controls"
|
||||
table.insert(page_by_id.controls_touchscreen.content, 2, touchscreen_layout)
|
||||
do
|
||||
local content = page_by_id.graphics_and_audio_effects.content
|
||||
local idx = table.indexof(content, "enable_dynamic_shadows")
|
||||
|
|
|
@ -16,7 +16,7 @@ local minetest_example_header = [[
|
|||
# to the program, eg. "luanti.exe --config ../minetest.conf.example".
|
||||
|
||||
# Further documentation:
|
||||
# https://wiki.minetest.net/
|
||||
# https://wiki.luanti.org/
|
||||
|
||||
]]
|
||||
|
||||
|
|
|
@ -55,6 +55,51 @@ local function get_sorted_servers()
|
|||
return servers
|
||||
end
|
||||
|
||||
local function is_selected_fav(server)
|
||||
local address = core.settings:get("address")
|
||||
local port = tonumber(core.settings:get("remote_port"))
|
||||
|
||||
for _, fav in ipairs(serverlistmgr.get_favorites()) do
|
||||
if address == fav.address and port == fav.port then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Persists the selected server in the "address" and "remote_port" settings
|
||||
|
||||
local function set_selected_server(server)
|
||||
if server == nil then -- reset selection
|
||||
core.settings:remove("address")
|
||||
core.settings:remove("remote_port")
|
||||
return
|
||||
end
|
||||
local address = server.address
|
||||
local port = server.port
|
||||
gamedata.serverdescription = server.description
|
||||
|
||||
if address and port then
|
||||
core.settings:set("address", address)
|
||||
core.settings:set("remote_port", port)
|
||||
end
|
||||
end
|
||||
|
||||
local function find_selected_server()
|
||||
local address = core.settings:get("address")
|
||||
local port = tonumber(core.settings:get("remote_port"))
|
||||
for _, server in ipairs(serverlistmgr.servers) do
|
||||
if server.address == address and server.port == port then
|
||||
return server
|
||||
end
|
||||
end
|
||||
for _, server in ipairs(serverlistmgr.get_favorites()) do
|
||||
if server.address == address and server.port == port then
|
||||
return server
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function get_formspec(tabview, name, tabdata)
|
||||
-- Update the cached supported proto info,
|
||||
-- it may have changed after a change by the settings menu.
|
||||
|
@ -107,17 +152,51 @@ local function get_formspec(tabview, name, tabdata)
|
|||
retval = retval .. "button[0.25,6;2.5,0.75;btn_mp_register;" .. fgettext("Register") .. "]"
|
||||
end
|
||||
|
||||
if tabdata.selected then
|
||||
if gamedata.fav then
|
||||
retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]"
|
||||
retval = retval .. "style[btn_delete_favorite;padding=6]"
|
||||
retval = retval .. "image_button[5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir ..
|
||||
"server_favorite_delete.png") .. ";btn_delete_favorite;]"
|
||||
end
|
||||
local selected_server = find_selected_server()
|
||||
|
||||
if selected_server then
|
||||
if gamedata.serverdescription then
|
||||
retval = retval .. "textarea[0.25,1.85;5.25,2.7;;;" ..
|
||||
core.formspec_escape(gamedata.serverdescription) .. "]"
|
||||
end
|
||||
|
||||
local clients_list = selected_server.clients_list
|
||||
local can_view_clients_list = clients_list and #clients_list > 0
|
||||
if can_view_clients_list then
|
||||
table.sort(clients_list, function(a, b)
|
||||
return a:lower() < b:lower()
|
||||
end)
|
||||
local max_clients = 5
|
||||
if #clients_list > max_clients then
|
||||
retval = retval .. "tooltip[btn_view_clients;" ..
|
||||
fgettext("Clients:\n$1", table.concat(clients_list, "\n", 1, max_clients)) .. "\n..." .. "]"
|
||||
else
|
||||
retval = retval .. "tooltip[btn_view_clients;" ..
|
||||
fgettext("Clients:\n$1", table.concat(clients_list, "\n")) .. "]"
|
||||
end
|
||||
retval = retval .. "style[btn_view_clients;padding=6]"
|
||||
retval = retval .. "image_button[4.5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir ..
|
||||
"server_view_clients.png") .. ";btn_view_clients;]"
|
||||
end
|
||||
|
||||
if selected_server.url then
|
||||
retval = retval .. "tooltip[btn_server_url;" .. fgettext("Open server website") .. "]"
|
||||
retval = retval .. "style[btn_server_url;padding=6]"
|
||||
retval = retval .. "image_button[" .. (can_view_clients_list and "4" or "4.5") .. ",1.3;0.5,0.5;" ..
|
||||
core.formspec_escape(defaulttexturedir .. "server_url.png") .. ";btn_server_url;]"
|
||||
end
|
||||
|
||||
if is_selected_fav() then
|
||||
retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]"
|
||||
retval = retval .. "style[btn_delete_favorite;padding=6]"
|
||||
retval = retval .. "image_button[5,1.3;0.5,0.5;" ..
|
||||
core.formspec_escape(defaulttexturedir .. "server_favorite_delete.png") .. ";btn_delete_favorite;]"
|
||||
else
|
||||
retval = retval .. "tooltip[btn_add_favorite;" .. fgettext("Add favorite") .. "]"
|
||||
retval = retval .. "style[btn_add_favorite;padding=6]"
|
||||
retval = retval .. "image_button[5,1.3;0.5,0.5;" ..
|
||||
core.formspec_escape(defaulttexturedir .. "server_favorite.png") .. ";btn_add_favorite;]"
|
||||
end
|
||||
end
|
||||
|
||||
retval = retval .. "container_end[]"
|
||||
|
@ -175,11 +254,17 @@ local function get_formspec(tabview, name, tabdata)
|
|||
|
||||
retval = retval .. table.concat(rows, ",")
|
||||
|
||||
if tabdata.selected then
|
||||
retval = retval .. ";" .. tabdata.selected .. "]"
|
||||
else
|
||||
retval = retval .. ";0]"
|
||||
local selected_row_idx = 0
|
||||
if selected_server then
|
||||
for i, server in pairs(tabdata.lookup) do
|
||||
if selected_server.address == server.address and
|
||||
selected_server.port == server.port then
|
||||
selected_row_idx = i
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
retval = retval .. ";" .. selected_row_idx .. "]"
|
||||
|
||||
return retval
|
||||
end
|
||||
|
@ -231,35 +316,6 @@ local function search_server_list(input)
|
|||
menudata.search_result = search_result
|
||||
end
|
||||
|
||||
local function set_selected_server(tabdata, idx, server)
|
||||
-- reset selection
|
||||
if idx == nil or server == nil then
|
||||
tabdata.selected = nil
|
||||
|
||||
core.settings:set("address", "")
|
||||
core.settings:set("remote_port", "30000")
|
||||
return
|
||||
end
|
||||
|
||||
local address = server.address
|
||||
local port = server.port
|
||||
gamedata.serverdescription = server.description
|
||||
|
||||
gamedata.fav = false
|
||||
for _, fav in ipairs(serverlistmgr.get_favorites()) do
|
||||
if address == fav.address and port == fav.port then
|
||||
gamedata.fav = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if address and port then
|
||||
core.settings:set("address", address)
|
||||
core.settings:set("remote_port", port)
|
||||
end
|
||||
tabdata.selected = idx
|
||||
end
|
||||
|
||||
local function main_button_handler(tabview, fields, name, tabdata)
|
||||
if fields.te_name then
|
||||
gamedata.playername = fields.te_name
|
||||
|
@ -290,19 +346,23 @@ local function main_button_handler(tabview, fields, name, tabdata)
|
|||
gamedata.serverdescription = server.description
|
||||
|
||||
if gamedata.address and gamedata.port then
|
||||
core.settings:set("address", gamedata.address)
|
||||
core.settings:set("remote_port", gamedata.port)
|
||||
set_selected_server(server)
|
||||
core.start()
|
||||
end
|
||||
return true
|
||||
end
|
||||
if event.type == "CHG" then
|
||||
set_selected_server(tabdata, event.row, server)
|
||||
set_selected_server(server)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if fields.btn_add_favorite then
|
||||
serverlistmgr.add_favorite(find_selected_server())
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_delete_favorite then
|
||||
local idx = core.get_table_index("servers")
|
||||
if not idx then return end
|
||||
|
@ -310,8 +370,20 @@ local function main_button_handler(tabview, fields, name, tabdata)
|
|||
if not server then return end
|
||||
|
||||
serverlistmgr.delete_favorite(server)
|
||||
-- the server at [idx+1] will be at idx once list is refreshed
|
||||
set_selected_server(tabdata, idx, tabdata.lookup[idx+1])
|
||||
set_selected_server(server)
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_server_url then
|
||||
core.open_url_dialog(find_selected_server().url)
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_view_clients then
|
||||
local dlg = create_clientslist_dialog(find_selected_server())
|
||||
dlg:set_parent(tabview)
|
||||
tabview:hide()
|
||||
dlg:show()
|
||||
return true
|
||||
end
|
||||
|
||||
|
@ -325,8 +397,8 @@ local function main_button_handler(tabview, fields, name, tabdata)
|
|||
tabdata.search_for = fields.te_search
|
||||
search_server_list(fields.te_search:lower())
|
||||
if menudata.search_result then
|
||||
-- first server in row 2 due to header
|
||||
set_selected_server(tabdata, 2, menudata.search_result[1])
|
||||
-- Note: This clears the selection if there are no results
|
||||
set_selected_server(menudata.search_result[1])
|
||||
end
|
||||
|
||||
return true
|
||||
|
@ -353,8 +425,6 @@ local function main_button_handler(tabview, fields, name, tabdata)
|
|||
local idx = core.get_table_index("servers")
|
||||
local server = idx and tabdata.lookup[idx]
|
||||
|
||||
set_selected_server(tabdata)
|
||||
|
||||
if server and server.address == gamedata.address and
|
||||
server.port == gamedata.port then
|
||||
|
||||
|
|
|
@ -77,8 +77,11 @@
|
|||
# Sections are marked by a single line in the format: [Section Name]
|
||||
# Sub-section are marked by adding * in front of the section name: [*Sub-section]
|
||||
# Sub-sub-sections have two * etc.
|
||||
# There shouldn't be too much settings per category; settings that shouldn't be
|
||||
# modified by the "average user" should be in (sub-)categories called "Advanced".
|
||||
# There shouldn't be too many settings per category.
|
||||
#
|
||||
# The top-level categories "Advanced", "Client and Server" and "Mapgen" are
|
||||
# handled specially and its contents only shown when a checkbox is checked.
|
||||
# They contain settings not intended for the "average user".
|
||||
|
||||
|
||||
[Controls]
|
||||
|
@ -410,10 +413,12 @@ anisotropic_filter (Anisotropic filtering) bool false
|
|||
# * None - No antialiasing (default)
|
||||
#
|
||||
# * FSAA - Hardware-provided full-screen antialiasing
|
||||
# (incompatible with Post Processing and Undersampling)
|
||||
# A.K.A multi-sample antialiasing (MSAA)
|
||||
# Smoothens out block edges but does not affect the insides of textures.
|
||||
# A restart is required to change this option.
|
||||
#
|
||||
# If Post Processing is disabled, changing FSAA requires a restart.
|
||||
# Also, if Post Processing is disabled, FSAA will not work together with
|
||||
# undersampling or a non-default "3d_mode" setting.
|
||||
#
|
||||
# * FXAA - Fast approximate antialiasing
|
||||
# Applies a post-processing filter to detect and smoothen high-contrast edges.
|
||||
|
@ -469,6 +474,7 @@ performance_tradeoffs (Tradeoffs for performance) bool false
|
|||
# Adds particles when digging a node.
|
||||
enable_particles (Digging particles) bool true
|
||||
|
||||
|
||||
[**Waving Nodes]
|
||||
|
||||
# Set to true to enable waving leaves.
|
||||
|
@ -535,12 +541,6 @@ shadow_map_texture_size (Shadow map texture size) int 2048 128 8192
|
|||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_map_texture_32bit (Shadow map texture in 32 bits) bool true
|
||||
|
||||
# Enable Poisson disk filtering.
|
||||
# On true uses Poisson disk to make "soft shadows". Otherwise uses PCF filtering.
|
||||
#
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_poisson_filter (Poisson filtering) bool true
|
||||
|
||||
# Define shadow filtering quality.
|
||||
# This simulates the soft shadows effect by applying a PCF or Poisson disk
|
||||
# but also uses more resources.
|
||||
|
@ -554,14 +554,6 @@ shadow_filters (Shadow filter quality) enum 1 0,1,2
|
|||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_map_color (Colored shadows) bool false
|
||||
|
||||
# Spread a complete update of shadow map over given number of frames.
|
||||
# Higher values might make shadows laggy, lower values
|
||||
# will consume more resources.
|
||||
# Minimum value: 1; maximum value: 16
|
||||
#
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_update_frames (Map shadows update frames) int 8 1 16
|
||||
|
||||
# Set the soft shadow radius size.
|
||||
# Lower values mean sharper shadows, bigger values mean softer shadows.
|
||||
# Minimum value: 1.0; maximum value: 15.0
|
||||
|
@ -805,7 +797,7 @@ contentdb_max_concurrent_downloads (ContentDB Max Concurrent Downloads) int 3 1
|
|||
enable_local_map_saving (Saving map received from server) bool false
|
||||
|
||||
# URL to the server list displayed in the Multiplayer Tab.
|
||||
serverlist_url (Serverlist URL) string servers.luanti.org
|
||||
serverlist_url (Serverlist URL) string https://servers.luanti.org
|
||||
|
||||
# If enabled, account registration is separate from login in the UI.
|
||||
# If disabled, new accounts will be registered automatically when logging in.
|
||||
|
@ -843,7 +835,7 @@ server_announce (Announce server) bool false
|
|||
server_announce_send_players (Send player names to the server list) bool true
|
||||
|
||||
# Announce to this serverlist.
|
||||
serverlist_url (Serverlist URL) string servers.luanti.org
|
||||
serverlist_url (Serverlist URL) string https://servers.luanti.org
|
||||
|
||||
# Message of the day displayed to players connecting.
|
||||
motd (Message of the day) string
|
||||
|
@ -1853,6 +1845,9 @@ ignore_world_load_errors (Ignore world errors) bool false
|
|||
|
||||
[**Graphics]
|
||||
|
||||
# Enables debug and error-checking in the OpenGL driver.
|
||||
opengl_debug (OpenGL debug) bool false
|
||||
|
||||
# Path to shader directory. If no path is defined, default location will be used.
|
||||
shader_path (Shader path) path
|
||||
|
||||
|
@ -1866,6 +1861,11 @@ video_driver (Video driver) enum ,opengl,opengl3,ogles2
|
|||
# Set to 0 to disable it entirely.
|
||||
transparency_sorting_distance (Transparency Sorting Distance) int 16 0 128
|
||||
|
||||
# Draw transparency sorted triangles grouped by their mesh buffers.
|
||||
# This breaks transparency sorting between mesh buffers, but avoids situations
|
||||
# where transparency sorting would be very slow otherwise.
|
||||
transparency_sorting_group_by_buffers (Transparency Sorting Group by Buffers) bool true
|
||||
|
||||
# Radius of cloud area stated in number of 64 node cloud squares.
|
||||
# Values larger than 26 will start to produce sharp cutoffs at cloud area corners.
|
||||
cloud_radius (Cloud radius) int 12 1 62
|
||||
|
@ -1919,8 +1919,26 @@ texture_min_size (Base texture size) int 64 1 32768
|
|||
# Systems with a low-end GPU (or no GPU) would benefit from smaller values.
|
||||
client_mesh_chunk (Client Mesh Chunksize) int 1 1 16
|
||||
|
||||
# Enables debug and error-checking in the OpenGL driver.
|
||||
opengl_debug (OpenGL debug) bool false
|
||||
# Decide the color depth of the texture used for the post-processing pipeline.
|
||||
# Reducing this can improve performance, but might cause some effects (e.g. bloom)
|
||||
# to not work.
|
||||
#
|
||||
# Requires: enable_post_processing
|
||||
post_processing_texture_bits (Color depth for post-processing texture) enum 16 8,10,16
|
||||
|
||||
# Enable Poisson disk filtering.
|
||||
# On true uses Poisson disk to make "soft shadows". Otherwise uses PCF filtering.
|
||||
#
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_poisson_filter (Poisson filtering) bool true
|
||||
|
||||
# Spread a complete update of shadow map over given number of frames.
|
||||
# Higher values might make shadows laggy, lower values
|
||||
# will consume more resources.
|
||||
# Minimum value: 1; maximum value: 16
|
||||
#
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_update_frames (Map shadows update frames) int 8 1 16
|
||||
|
||||
# Set to true to render debugging breakdown of the bloom effect.
|
||||
# In debug mode, the screen is split into 4 quadrants:
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
varying lowp vec4 varColor;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_FragData[0] = varColor;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
varying lowp vec4 varColor;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = mWorldViewProj * inVertexPosition;
|
||||
varColor = inVertexColor;
|
||||
}
|
|
@ -23,7 +23,7 @@ void main(void)
|
|||
vec2 uv = varTexCoord.st;
|
||||
vec3 color = texture2D(rendered, uv).rgb;
|
||||
// translate to linear colorspace (approximate)
|
||||
color = pow(color, vec3(2.2));
|
||||
color = pow(clamp(color, 0.0, 1.0), vec3(2.2));
|
||||
|
||||
color *= exposureParams.compensationFactor * bloomStrength;
|
||||
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_OPAQUE || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_BASIC || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT)
|
||||
#define MATERIAL_WAVING_LIQUID 1
|
||||
#define MATERIAL_LIQUID 1
|
||||
#elif (MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE)
|
||||
#define MATERIAL_LIQUID 1
|
||||
#endif
|
||||
|
||||
uniform sampler2D baseTexture;
|
||||
uniform vec2 texelSize0;
|
||||
|
||||
|
@ -60,7 +53,7 @@ varying highp vec3 eyeVec;
|
|||
varying float nightRatio;
|
||||
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
#if (defined(MATERIAL_WAVING_LIQUID) && defined(ENABLE_WATER_REFLECTIONS))
|
||||
#if (MATERIAL_WAVING_LIQUID && defined(ENABLE_WATER_REFLECTIONS))
|
||||
vec4 perm(vec4 x)
|
||||
{
|
||||
return mod(((x * 34.0) + 1.0) * x, 289.0);
|
||||
|
@ -511,8 +504,7 @@ void main(void)
|
|||
vec3 reflect_ray = -normalize(v_LightDirection - fNormal * dot(v_LightDirection, fNormal) * 2.0);
|
||||
|
||||
// Water reflections
|
||||
#if (defined(MATERIAL_WAVING_LIQUID) && defined(ENABLE_WATER_REFLECTIONS))
|
||||
|
||||
#if (MATERIAL_WAVING_LIQUID && defined(ENABLE_WATER_REFLECTIONS))
|
||||
vec3 wavePos = worldPosition * vec3(2.0, 0.0, 2.0);
|
||||
float off = animationTimer * WATER_WAVE_SPEED * 10.0;
|
||||
wavePos.x /= WATER_WAVE_LENGTH * 3.0;
|
||||
|
@ -542,7 +534,7 @@ void main(void)
|
|||
col.rgb += water_reflect_color * brightness_factor;
|
||||
#endif
|
||||
|
||||
#if (defined(ENABLE_NODE_SPECULAR) && !defined(MATERIAL_WAVING_LIQUID))
|
||||
#if (defined(ENABLE_NODE_SPECULAR) && !MATERIAL_WAVING_LIQUID)
|
||||
// Apply specular to blocks.
|
||||
if (dot(v_LightDirection, vNormal) < 0.0) {
|
||||
// This intensity is a placeholder and should be replaced by proper specular maps.
|
||||
|
|
|
@ -113,8 +113,7 @@ float smoothTriangleWave(float x)
|
|||
return smoothCurve(triangleWave(x)) * 2.0 - 1.0;
|
||||
}
|
||||
|
||||
// OpenGL < 4.3 does not support continued preprocessor lines
|
||||
#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_OPAQUE || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_BASIC) && ENABLE_WAVING_WATER
|
||||
#if MATERIAL_WAVING_LIQUID && ENABLE_WAVING_WATER
|
||||
|
||||
//
|
||||
// Simple, fast noise function.
|
||||
|
@ -180,8 +179,7 @@ void main(void)
|
|||
#endif
|
||||
|
||||
vec4 pos = inVertexPosition;
|
||||
// OpenGL < 4.3 does not support continued preprocessor lines
|
||||
#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_OPAQUE || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_BASIC) && ENABLE_WAVING_WATER
|
||||
#if MATERIAL_WAVING_LIQUID && ENABLE_WAVING_WATER
|
||||
// Generate waves with Perlin-type noise.
|
||||
// The constants are calibrated such that they roughly
|
||||
// correspond to the old sine waves.
|
||||
|
|
|
@ -42,7 +42,7 @@ configuration file can usually be found at:
|
|||
* After 5.4.2:
|
||||
* `/sdcard/Android/data/net.minetest.minetest/` or `/storage/emulated/0/Android/data/net.minetest.minetest/` if stored on the device
|
||||
* `/storage/emulated/(varying folder name)/Android/data/net.minetest.minetest/` if stored on the SD card
|
||||
* [Learn more about Android directory](https://wiki.minetest.net/Accessing_Android_Data_Directory)
|
||||
* [Learn more about Android directory](https://wiki.luanti.org/Accessing_Android_Data_Directory)
|
||||
|
||||
## Useful settings
|
||||
|
||||
|
|
|
@ -21,3 +21,4 @@ This list is largely advisory and items may be reevaluated once the time comes.
|
|||
* merge `sound` and `sounds` table in itemdef
|
||||
* remove `DIR_DELIM` from Lua
|
||||
* stop reading initial properties from bare entity def
|
||||
* change particle default blend mode to `clip`
|
||||
|
|
|
@ -30,6 +30,7 @@ General options and their default values:
|
|||
ENABLE_POSTGRESQL=ON - Build with libpq; Enables use of PostgreSQL map backend (PostgreSQL 9.5 or greater recommended)
|
||||
ENABLE_REDIS=ON - Build with libhiredis; Enables use of Redis map backend
|
||||
ENABLE_SPATIAL=ON - Build with LibSpatial; Speeds up AreaStores
|
||||
ENABLE_OPENSSL=ON - Build with OpenSSL; Speeds up SHA1 and SHA2 hashing
|
||||
ENABLE_SOUND=ON - Build with OpenAL, libogg & libvorbis; in-game sounds
|
||||
ENABLE_LTO=<varies> - Build with IPO/LTO optimizations (smaller and more efficient than regular build)
|
||||
ENABLE_LUAJIT=ON - Build with LuaJIT (much faster than non-JIT Lua)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
| JsonCPP | 1.0.0+ | Bundled JsonCPP is used if not present |
|
||||
| Curl | 7.56.0+ | Optional |
|
||||
| gettext | - | Optional |
|
||||
| OpenSSL | 3.0+ | Optional (only libcrypto used) |
|
||||
|
||||
For Debian/Ubuntu users:
|
||||
|
||||
|
@ -33,7 +34,7 @@ For openSUSE users:
|
|||
|
||||
For Arch users:
|
||||
|
||||
sudo pacman -S --needed base-devel libcurl-gnutls cmake libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext sdl2
|
||||
sudo pacman -S --needed base-devel libcurl-gnutls cmake libpng libjpeg-turbo sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext sdl2
|
||||
|
||||
For Alpine users:
|
||||
|
||||
|
|
|
@ -23,4 +23,4 @@ Notable pages:
|
|||
|
||||
Oftentimes knowledge hasn't been written down (yet) and your best bet is to ask someone experienced and/or the core developers.
|
||||
|
||||
Feel free to join the [#minetest-dev IRC](https://wiki.minetest.net/IRC) and ask questions related to **engine development**.
|
||||
Feel free to join the [#minetest-dev IRC](https://wiki.luanti.org/IRC) and ask questions related to **engine development**.
|
||||
|
|
|
@ -309,17 +309,24 @@ it unlocks no special rendering features.
|
|||
Binary glTF (`.glb`) files are supported and recommended over `.gltf` files
|
||||
due to their space savings.
|
||||
|
||||
This means that many glTF features are not supported *yet*, including:
|
||||
Bone weights should be normalized, e.g. using ["normalize all" in Blender](https://docs.blender.org/manual/en/4.2/grease_pencil/modes/weight_paint/weights_menu.html#normalize-all).
|
||||
|
||||
You can use the [Khronos glTF validator](https://github.com/KhronosGroup/glTF-Validator)
|
||||
to check whether a model is a valid glTF file.
|
||||
|
||||
Many glTF features are not supported *yet*, including:
|
||||
|
||||
* Animations
|
||||
* Only a single animation is supported, use frame ranges within this animation.
|
||||
* Only linear interpolation is supported.
|
||||
* Cameras
|
||||
* Materials
|
||||
* Only base color textures are supported
|
||||
* Backface culling is overridden
|
||||
* Double-sided materials don't work
|
||||
* Alternative means of supplying data
|
||||
* Embedded images
|
||||
* Embedded images. You can use `gltfutil.py` from the
|
||||
[modding tools](https://github.com/minetest/modtools) to strip or extract embedded images.
|
||||
* References to files via URIs
|
||||
|
||||
Textures are supplied solely via the same means as for the other model file formats:
|
||||
|
@ -4183,14 +4190,14 @@ Two functions are provided to translate strings: `core.translate` and
|
|||
|
||||
* `core.get_translator(textdomain)` is a simple wrapper around
|
||||
`core.translate` and `core.translate_n`.
|
||||
After `local S, NS = core.get_translator(textdomain)`, we have
|
||||
After `local S, PS = core.get_translator(textdomain)`, we have
|
||||
`S(str, ...)` equivalent to `core.translate(textdomain, str, ...)`, and
|
||||
`NS(str, str_plural, n, ...)` to `core.translate_n(textdomain, str, str_plural, n, ...)`.
|
||||
`PS(str, str_plural, n, ...)` to `core.translate_n(textdomain, str, str_plural, n, ...)`.
|
||||
It is intended to be used in the following way, so that it avoids verbose
|
||||
repetitions of `core.translate`:
|
||||
|
||||
```lua
|
||||
local S, NS = core.get_translator(textdomain)
|
||||
local S, PS = core.get_translator(textdomain)
|
||||
S(str, ...)
|
||||
```
|
||||
|
||||
|
@ -4224,7 +4231,7 @@ command that shows the amount of time since the player joined. We can do the
|
|||
following:
|
||||
|
||||
```lua
|
||||
local S, NS = core.get_translator("hello")
|
||||
local S, PS = core.get_translator("hello")
|
||||
core.register_on_joinplayer(function(player)
|
||||
local name = player:get_player_name()
|
||||
core.chat_send_player(name, S("Hello @1, how are you today?", name))
|
||||
|
@ -4233,7 +4240,7 @@ core.register_chatcommand("playtime", {
|
|||
func = function(name)
|
||||
local last_login = core.get_auth_handler().get_auth(name).last_login
|
||||
local playtime = math.floor((last_login-os.time())/60)
|
||||
return true, NS(
|
||||
return true, PS(
|
||||
"You have been playing for @1 minute.",
|
||||
"You have been playing for @1 minutes.",
|
||||
minutes, tostring(minutes))
|
||||
|
@ -4280,7 +4287,7 @@ After creating the `locale` directory, a translation template for the above
|
|||
example using the following command:
|
||||
|
||||
```sh
|
||||
xgettext -L lua -kS -kNS:1,2 -kcore.translate:1c,2 -kcore.translate_n:1c,2,3 \
|
||||
xgettext -L lua -kS -kPS:1,2 -kcore.translate:1c,2 -kcore.translate_n:1c,2,3 \
|
||||
-d hello -o locale/hello.pot *.lua
|
||||
```
|
||||
|
||||
|
@ -5657,6 +5664,8 @@ Utilities
|
|||
abm_without_neighbors = true,
|
||||
-- biomes have a weight parameter (5.11.0)
|
||||
biome_weights = true,
|
||||
-- Particles can specify a "clip" blend mode (5.11.0)
|
||||
particle_blend_clip = true,
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -6178,7 +6187,7 @@ Setting-related
|
|||
* `core.settings`: Settings object containing all of the settings from the
|
||||
main config file (`minetest.conf`). See [`Settings`].
|
||||
* `core.setting_get_pos(name)`: Loads a setting from the main settings and
|
||||
parses it as a position (in the format `(1,2,3)`). Returns a position or nil.
|
||||
parses it as a position (in the format `(1,2,3)`). Returns a position or nil. **Deprecated: use `core.settings:get_pos()` instead**
|
||||
|
||||
Authentication
|
||||
--------------
|
||||
|
@ -6577,8 +6586,11 @@ Environment access
|
|||
Difference between `"A*"` and `"A*_noprefetch"` is that
|
||||
`"A*"` will pre-calculate the cost-data, the other will calculate it
|
||||
on-the-fly
|
||||
* `core.spawn_tree (pos, {treedef})`
|
||||
* `core.spawn_tree(pos, treedef)`
|
||||
* spawns L-system tree at given `pos` with definition in `treedef` table
|
||||
* `core.spawn_tree_on_vmanip(vmanip, pos, treedef)`
|
||||
* analogous to `core.spawn_tree`, but spawns a L-system tree onto the specified
|
||||
VoxelManip object `vmanip` instead of the map.
|
||||
* `core.transforming_liquid_add(pos)`
|
||||
* add node to liquid flow update queue
|
||||
* `core.get_node_max_level(pos)`
|
||||
|
@ -6697,6 +6709,9 @@ Formspec
|
|||
* `core.hypertext_escape(string)`: returns a string
|
||||
* escapes the characters "\", "<", and ">" to show text in a hypertext element.
|
||||
* not safe for use with tag attributes.
|
||||
* this function does not do formspec escaping, you will likely need to do
|
||||
`core.formspec_escape(core.hypertext_escape(string))` if the hypertext is
|
||||
not already being formspec escaped.
|
||||
* `core.explode_table_event(string)`: returns a table
|
||||
* returns e.g. `{type="CHG", row=1, column=2}`
|
||||
* `type` is one of:
|
||||
|
@ -8909,7 +8924,7 @@ For `core.get_perlin_map()`, the actual seed used is the noiseparams seed
|
|||
plus the world seed, to create world-specific noise.
|
||||
|
||||
Format of `size` is `{x=dimx, y=dimy, z=dimz}`. The `z` component is omitted
|
||||
for 2D noise, and it must be must be larger than 1 for 3D noise (otherwise
|
||||
for 2D noise, and it must be larger than 1 for 3D noise (otherwise
|
||||
`nil` is returned).
|
||||
|
||||
For each of the functions with an optional `buffer` parameter: If `buffer` is
|
||||
|
@ -9065,6 +9080,9 @@ means that no defaults will be returned for mod settings.
|
|||
* Is currently limited to mapgen flags `mg_flags` and mapgen-specific
|
||||
flags like `mgv5_spflags`.
|
||||
* Returns `nil` if `key` is not found.
|
||||
* `get_pos(key)`:
|
||||
* Returns a `vector`
|
||||
* Returns `nil` if no value is found or parsing failed.
|
||||
* `set(key, value)`
|
||||
* Setting names can't contain whitespace or any of `="{}#`.
|
||||
* Setting values can't contain the sequence `\n"""`.
|
||||
|
@ -9075,6 +9093,9 @@ means that no defaults will be returned for mod settings.
|
|||
* `set_np_group(key, value)`
|
||||
* `value` is a NoiseParams table.
|
||||
* Also, see documentation for `set()` above.
|
||||
* `set_pos(key, value)`
|
||||
* `value` is a `vector`.
|
||||
* Also, see documentation for `set()` above.
|
||||
* `remove(key)`: returns a boolean (`true` for success)
|
||||
* `get_names()`: returns `{key1,...}`
|
||||
* `has(key)`:
|
||||
|
@ -11502,6 +11523,14 @@ texture = {
|
|||
-- (default) blends transparent pixels with those they are drawn atop
|
||||
-- according to the alpha channel of the source texture. useful for
|
||||
-- e.g. material objects like rocks, dirt, smoke, or node chunks
|
||||
-- note: there will be rendering bugs when particles interact with
|
||||
-- translucent nodes. particles are also not transparency-sorted
|
||||
-- relative to each other.
|
||||
blend = "clip",
|
||||
-- pixels are either fully opaque or fully transparent,
|
||||
-- depending on whether alpha is greater than or less than 50%
|
||||
-- (just like `use_texture_alpha = "clip"` for nodes).
|
||||
-- you should prefer this if you don't need semi-transparency, as it's faster.
|
||||
blend = "add",
|
||||
-- adds the value of pixels to those underneath them, modulo the sources
|
||||
-- alpha channel. useful for e.g. bright light effects like sparks or fire
|
||||
|
|
|
@ -223,6 +223,7 @@ GUI
|
|||
* `core.set_clouds(<true/false>)`
|
||||
* `core.set_topleft_text(text)`
|
||||
* `core.show_keys_menu()`
|
||||
* `core.show_touchscreen_layout()`
|
||||
* `core.show_path_select_dialog(formname, caption, is_file_select)`
|
||||
* shows a path select dialog
|
||||
* `formname` is base name of dialog response returned in fields
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
"Minetest Sam":
|
||||
|
||||
Original model by MirceaKitsune (CC BY-SA 3.0).
|
||||
Various alterations and fixes by kilbith, sofar, xunto, Rogier-5, TeTpaAka, Desour,
|
||||
stujones11, An0n3m0us (CC BY-SA 3.0):
|
||||
|
@ -5,3 +7,9 @@ stujones11, An0n3m0us (CC BY-SA 3.0):
|
|||
|
||||
Jordach (CC BY-SA 3.0):
|
||||
testentities_sam.png
|
||||
|
||||
"Lava Flan":
|
||||
|
||||
Zeg9 (CC BY-SA 3.0):
|
||||
testentities_lava_flan.x
|
||||
testentities_lava_flan.png
|
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
3506
games/devtest/mods/testentities/models/testentities_lava_flan.x
Normal file
3506
games/devtest/mods/testentities/models/testentities_lava_flan.x
Normal file
File diff suppressed because it is too large
Load diff
|
@ -79,6 +79,20 @@ core.register_entity("testentities:sam", {
|
|||
end,
|
||||
})
|
||||
|
||||
core.register_entity("testentities:lava_flan", {
|
||||
initial_properties = {
|
||||
infotext = "Lava Flan (smoke test .x)",
|
||||
visual = "mesh",
|
||||
mesh = "testentities_lava_flan.x",
|
||||
textures = {
|
||||
"testentities_lava_flan.png"
|
||||
},
|
||||
},
|
||||
on_activate = function(self)
|
||||
self.object:set_animation({x = 0, y = 28}, 15, 0, true)
|
||||
end,
|
||||
})
|
||||
|
||||
-- Advanced visual tests
|
||||
|
||||
-- An entity for testing animated and yaw-modulated sprites
|
||||
|
|
|
@ -105,3 +105,68 @@ core.register_craftitem("testitems:telescope_stick", {
|
|||
return itemstack
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
-- Tree spawners
|
||||
|
||||
local tree_def={
|
||||
axiom="Af",
|
||||
rules_a="TT[&GB][&+GB][&++GB][&+++GB]A",
|
||||
rules_b="[+GB]fB",
|
||||
trunk="basenodes:tree",
|
||||
leaves="basenodes:leaves",
|
||||
angle=90,
|
||||
iterations=4,
|
||||
trunk_type="single",
|
||||
thin_branches=true,
|
||||
}
|
||||
|
||||
core.register_craftitem("testitems:tree_spawner", {
|
||||
description = S("Tree Spawner"),
|
||||
inventory_image = "testitems_tree_spawner.png",
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
if (not pointed_thing or pointed_thing.type ~= "node") then
|
||||
return
|
||||
end
|
||||
core.spawn_tree(pointed_thing.above, tree_def)
|
||||
end,
|
||||
})
|
||||
|
||||
local vmanip_for_trees = {} -- per player
|
||||
core.register_craftitem("testitems:tree_spawner_vmanip", {
|
||||
description = S("Tree Spawner using VoxelManip"),
|
||||
inventory_image = "testitems_tree_spawner_vmanip.png",
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
if (not pointed_thing or pointed_thing.type ~= "node" or
|
||||
not core.is_player(placer)) then
|
||||
return
|
||||
end
|
||||
local name = placer:get_player_name()
|
||||
local vm = vmanip_for_trees[name]
|
||||
if not vm then
|
||||
vm = VoxelManip(vector.add(pointed_thing.above, 20),
|
||||
vector.subtract(pointed_thing.above, 20))
|
||||
vmanip_for_trees[name] = vm
|
||||
core.chat_send_player(name,
|
||||
"Tree in new VoxelManip spawned, left click to apply to map, "..
|
||||
"or right click to add more trees.")
|
||||
end
|
||||
core.spawn_tree_on_vmanip(vm, pointed_thing.above, tree_def)
|
||||
end,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if not core.is_player(user) then
|
||||
return
|
||||
end
|
||||
local name = user:get_player_name()
|
||||
local vm = vmanip_for_trees[name]
|
||||
if vm then
|
||||
vm:write_to_map()
|
||||
vmanip_for_trees[name] = nil
|
||||
core.chat_send_player(name, "VoxelManip written to map.")
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_on_leaveplayer(function(player, timed_out)
|
||||
vmanip_for_trees[player:get_player_name()] = nil
|
||||
end)
|
||||
|
|
BIN
games/devtest/mods/testitems/textures/testitems_tree_spawner.png
Normal file
BIN
games/devtest/mods/testitems/textures/testitems_tree_spawner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 120 B |
Binary file not shown.
After Width: | Height: | Size: 150 B |
|
@ -1,14 +1,27 @@
|
|||
local function spawn_clip_test_particle(pos)
|
||||
core.add_particle({
|
||||
pos = pos,
|
||||
size = 5,
|
||||
expirationtime = 10,
|
||||
texture = {
|
||||
name = "testtools_particle_clip.png",
|
||||
blend = "clip",
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
core.register_tool("testtools:particle_spawner", {
|
||||
description = "Particle Spawner".."\n"..
|
||||
description = table.concat({
|
||||
"Particle Spawner",
|
||||
"Punch: Spawn random test particle",
|
||||
"Place: Spawn clip test particle",
|
||||
}, "\n"),
|
||||
inventory_image = "testtools_particle_spawner.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
local pos = core.get_pointed_thing_position(pointed_thing, true)
|
||||
if pos == nil then
|
||||
if user then
|
||||
pos = user:get_pos()
|
||||
end
|
||||
pos = assert(user):get_pos()
|
||||
end
|
||||
pos = vector.add(pos, {x=0, y=0.5, z=0})
|
||||
local tex, anim
|
||||
|
@ -32,5 +45,12 @@ core.register_tool("testtools:particle_spawner", {
|
|||
glow = math.random(0, 5),
|
||||
})
|
||||
end,
|
||||
on_place = function(itemstack, user, pointed_thing)
|
||||
local pos = assert(core.get_pointed_thing_position(pointed_thing, true))
|
||||
spawn_clip_test_particle(pos)
|
||||
end,
|
||||
on_secondary_use = function(_, user)
|
||||
spawn_clip_test_particle(assert(user):get_pos())
|
||||
end,
|
||||
})
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 179 B |
|
@ -24,12 +24,7 @@ class CIndexBuffer final : public IIndexBuffer
|
|||
{
|
||||
public:
|
||||
//! Default constructor for empty buffer
|
||||
CIndexBuffer()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CIndexBuffer");
|
||||
#endif
|
||||
}
|
||||
CIndexBuffer() {}
|
||||
|
||||
video::E_INDEX_TYPE getType() const override
|
||||
{
|
||||
|
|
|
@ -22,9 +22,6 @@ public:
|
|||
CMeshBuffer() :
|
||||
PrimitiveType(EPT_TRIANGLES)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CMeshBuffer");
|
||||
#endif
|
||||
Vertices = new CVertexBuffer<T>();
|
||||
Indices = new SIndexBuffer();
|
||||
}
|
||||
|
|
|
@ -24,12 +24,7 @@ class CVertexBuffer final : public IVertexBuffer
|
|||
{
|
||||
public:
|
||||
//! Default constructor for empty buffer
|
||||
CVertexBuffer()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CVertexBuffer");
|
||||
#endif
|
||||
}
|
||||
CVertexBuffer() {}
|
||||
|
||||
const void *getData() const override
|
||||
{
|
||||
|
|
|
@ -129,6 +129,9 @@ enum E_VIDEO_DRIVER_FEATURE
|
|||
//! Support for clamping vertices beyond far-plane to depth instead of capping them.
|
||||
EVDF_DEPTH_CLAMP,
|
||||
|
||||
//! Support for multisample textures.
|
||||
EVDF_TEXTURE_MULTISAMPLE,
|
||||
|
||||
//! Only used for counting the elements of this enum
|
||||
EVDF_COUNT
|
||||
};
|
||||
|
|
|
@ -48,7 +48,7 @@ const c8 *const BoneAnimationModeNames[] = {
|
|||
};
|
||||
|
||||
//! Interface for bones used for skeletal animation.
|
||||
/** Used with ISkinnedMesh and IAnimatedMeshSceneNode. */
|
||||
/** Used with SkinnedMesh and IAnimatedMeshSceneNode. */
|
||||
class IBoneSceneNode : public ISceneNode
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -34,10 +34,6 @@ public:
|
|||
AlignLeft(EGUIA_UPPERLEFT), AlignRight(EGUIA_UPPERLEFT), AlignTop(EGUIA_UPPERLEFT), AlignBottom(EGUIA_UPPERLEFT),
|
||||
Environment(environment), Type(type)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("IGUIElement");
|
||||
#endif
|
||||
|
||||
// if we were given a parent to attach to
|
||||
if (parent) {
|
||||
parent->addChildToEnd(this);
|
||||
|
|
|
@ -342,6 +342,8 @@ public:
|
|||
return 16;
|
||||
case ECF_R16G16:
|
||||
return 32;
|
||||
case ECF_A2R10G10B10:
|
||||
return 32;
|
||||
case ECF_R16F:
|
||||
return 16;
|
||||
case ECF_G16R16F:
|
||||
|
|
|
@ -136,31 +136,6 @@ public:
|
|||
return ReferenceCounter;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
//! Returns the debug name of the object.
|
||||
/** The Debugname may only be set and changed by the object
|
||||
itself. This method should only be used in Debug mode.
|
||||
\return Returns a string, previously set by setDebugName(); */
|
||||
const c8 *getDebugName() const
|
||||
{
|
||||
return DebugName;
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Sets the debug name of the object.
|
||||
/** The Debugname may only be set and changed by the object
|
||||
itself. This method should only be used in Debug mode.
|
||||
\param newName: New debug name to set. */
|
||||
void setDebugName(const c8 *newName)
|
||||
{
|
||||
DebugName = newName;
|
||||
}
|
||||
|
||||
private:
|
||||
//! The debug name.
|
||||
const c8 *DebugName = nullptr;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
//! The reference counter. Mutable to do reference counting on const objects.
|
||||
|
|
|
@ -26,6 +26,7 @@ enum E_CUBE_SURFACE
|
|||
};
|
||||
|
||||
//! Interface of a Render Target.
|
||||
/** This is a framebuffer object (FBO) in OpenGL. */
|
||||
class IRenderTarget : public virtual IReferenceCounted
|
||||
{
|
||||
public:
|
||||
|
@ -108,11 +109,6 @@ protected:
|
|||
|
||||
//! Driver type of render target.
|
||||
E_DRIVER_TYPE DriverType;
|
||||
|
||||
private:
|
||||
// no copying (IReferenceCounted still allows that for reasons which take some time to work around)
|
||||
IRenderTarget(const IRenderTarget &);
|
||||
IRenderTarget &operator=(const IRenderTarget &);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "SColor.h"
|
||||
#include "ESceneNodeTypes.h"
|
||||
#include "SceneParameters.h" // IWYU pragma: export
|
||||
#include "ISkinnedMesh.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
@ -55,9 +54,6 @@ enum E_SCENE_NODE_RENDER_PASS
|
|||
//! Camera pass. The active view is set up here. The very first pass.
|
||||
ESNRP_CAMERA = 1,
|
||||
|
||||
//! In this pass, lights are transformed into camera space and added to the driver
|
||||
ESNRP_LIGHT = 2,
|
||||
|
||||
//! This is used for sky boxes.
|
||||
ESNRP_SKY_BOX = 4,
|
||||
|
||||
|
@ -85,9 +81,6 @@ enum E_SCENE_NODE_RENDER_PASS
|
|||
//! Transparent effect scene nodes, drawn after Transparent nodes. They are sorted from back to front and drawn in that order.
|
||||
ESNRP_TRANSPARENT_EFFECT = 32,
|
||||
|
||||
//! Drawn after the solid nodes, before the transparent nodes, the time for drawing shadow volumes
|
||||
ESNRP_SHADOW = 64,
|
||||
|
||||
//! Drawn after transparent effect nodes. For custom gui's. Unsorted (in order nodes registered themselves).
|
||||
ESNRP_GUI = 128
|
||||
|
||||
|
@ -99,6 +92,7 @@ class IBillboardSceneNode;
|
|||
class ICameraSceneNode;
|
||||
class IDummyTransformationSceneNode;
|
||||
class IMesh;
|
||||
class SkinnedMesh;
|
||||
class IMeshBuffer;
|
||||
class IMeshCache;
|
||||
class ISceneCollisionManager;
|
||||
|
@ -127,189 +121,6 @@ public:
|
|||
//! Get pointer to an animatable mesh. Loads the file if not loaded already.
|
||||
/**
|
||||
* If you want to remove a loaded mesh from the cache again, use removeMesh().
|
||||
* Currently there are the following mesh formats supported:
|
||||
* <TABLE border="1" cellpadding="2" cellspacing="0">
|
||||
* <TR>
|
||||
* <TD>Format</TD>
|
||||
* <TD>Description</TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>3D Studio (.3ds)</TD>
|
||||
* <TD>Loader for 3D-Studio files which lots of 3D packages
|
||||
* are able to export. Only static meshes are currently
|
||||
* supported by this importer.</TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>3D World Studio (.smf)</TD>
|
||||
* <TD>Loader for Leadwerks SMF mesh files, a simple mesh format
|
||||
* containing static geometry for games. The proprietary .STF texture format
|
||||
* is not supported yet. This loader was originally written by Joseph Ellis. </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Bliz Basic B3D (.b3d)</TD>
|
||||
* <TD>Loader for blitz basic files, developed by Mark
|
||||
* Sibly. This is the ideal animated mesh format for game
|
||||
* characters as it is both rigidly defined and widely
|
||||
* supported by modeling and animation software.
|
||||
* As this format supports skeletal animations, an
|
||||
* ISkinnedMesh will be returned by this importer.</TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Cartography shop 4 (.csm)</TD>
|
||||
* <TD>Cartography Shop is a modeling program for creating
|
||||
* architecture and calculating lighting. Irrlicht can
|
||||
* directly import .csm files thanks to the IrrCSM library
|
||||
* created by Saurav Mohapatra which is now integrated
|
||||
* directly in Irrlicht.
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Delgine DeleD (.dmf)</TD>
|
||||
* <TD>DeleD (delgine.com) is a 3D editor and level-editor
|
||||
* combined into one and is specifically designed for 3D
|
||||
* game-development. With this loader, it is possible to
|
||||
* directly load all geometry is as well as textures and
|
||||
* lightmaps from .dmf files. To set texture and
|
||||
* material paths, see scene::DMF_USE_MATERIALS_DIRS.
|
||||
* It is also possible to flip the alpha texture by setting
|
||||
* scene::DMF_FLIP_ALPHA_TEXTURES to true and to set the
|
||||
* material transparent reference value by setting
|
||||
* scene::DMF_ALPHA_CHANNEL_REF to a float between 0 and
|
||||
* 1. The loader is based on Salvatore Russo's .dmf
|
||||
* loader, I just changed some parts of it. Thanks to
|
||||
* Salvatore for his work and for allowing me to use his
|
||||
* code in Irrlicht and put it under Irrlicht's license.
|
||||
* For newer and more enhanced versions of the loader,
|
||||
* take a look at delgine.com.
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>DirectX (.x)</TD>
|
||||
* <TD>Platform independent importer (so not D3D-only) for
|
||||
* .x files. Most 3D packages can export these natively
|
||||
* and there are several tools for them available, e.g.
|
||||
* the Maya exporter included in the DX SDK.
|
||||
* .x files can include skeletal animations and Irrlicht
|
||||
* is able to play and display them, users can manipulate
|
||||
* the joints via the ISkinnedMesh interface. Currently,
|
||||
* Irrlicht only supports uncompressed .x files.</TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Half-Life model (.mdl)</TD>
|
||||
* <TD>This loader opens Half-life 1 models, it was contributed
|
||||
* by Fabio Concas and adapted by Thomas Alten.</TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>LightWave (.lwo)</TD>
|
||||
* <TD>Native to NewTek's LightWave 3D, the LWO format is well
|
||||
* known and supported by many exporters. This loader will
|
||||
* import LWO2 models including lightmaps, bumpmaps and
|
||||
* reflection textures.</TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Maya (.obj)</TD>
|
||||
* <TD>Most 3D software can create .obj files which contain
|
||||
* static geometry without material data. The material
|
||||
* files .mtl are also supported. This importer for
|
||||
* Irrlicht can load them directly. </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Milkshape (.ms3d)</TD>
|
||||
* <TD>.MS3D files contain models and sometimes skeletal
|
||||
* animations from the Milkshape 3D modeling and animation
|
||||
* software. Like the other skeletal mesh loaders, joints
|
||||
* are exposed via the ISkinnedMesh animated mesh type.</TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>My3D (.my3d)</TD>
|
||||
* <TD>.my3D is a flexible 3D file format. The My3DTools
|
||||
* contains plug-ins to export .my3D files from several
|
||||
* 3D packages. With this built-in importer, Irrlicht
|
||||
* can read and display those files directly. This
|
||||
* loader was written by Zhuck Dimitry who also created
|
||||
* the whole My3DTools package.
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>OCT (.oct)</TD>
|
||||
* <TD>The oct file format contains 3D geometry and
|
||||
* lightmaps and can be loaded directly by Irrlicht. OCT
|
||||
* files<br> can be created by FSRad, Paul Nette's
|
||||
* radiosity processor or exported from Blender using
|
||||
* OCTTools which can be found in the exporters/OCTTools
|
||||
* directory of the SDK. Thanks to Murphy McCauley for
|
||||
* creating all this.</TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>OGRE Meshes (.mesh)</TD>
|
||||
* <TD>Ogre .mesh files contain 3D data for the OGRE 3D
|
||||
* engine. Irrlicht can read and display them directly
|
||||
* with this importer. To define materials for the mesh,
|
||||
* copy a .material file named like the corresponding
|
||||
* .mesh file where the .mesh file is. (For example
|
||||
* ogrehead.material for ogrehead.mesh). Thanks to
|
||||
* Christian Stehno who wrote and contributed this
|
||||
* loader.</TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Pulsar LMTools (.lmts)</TD>
|
||||
* <TD>LMTools is a set of tools (Windows & Linux) for
|
||||
* creating lightmaps. Irrlicht can directly read .lmts
|
||||
* files thanks to<br> the importer created by Jonas
|
||||
* Petersen.
|
||||
* Notes for<br> this version of the loader:<br>
|
||||
* - It does not recognize/support user data in the
|
||||
* *.lmts files.<br>
|
||||
* - The TGAs generated by LMTools don't work in
|
||||
* Irrlicht for some reason (the textures are upside
|
||||
* down). Opening and resaving them in a graphics app
|
||||
* will solve the problem.</TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Quake 3 levels (.bsp)</TD>
|
||||
* <TD>Quake 3 is a popular game by IDSoftware, and .pk3
|
||||
* files contain .bsp files and textures/lightmaps
|
||||
* describing huge prelighted levels. Irrlicht can read
|
||||
* .pk3 and .bsp files directly and thus render Quake 3
|
||||
* levels directly. Written by Nikolaus Gebhardt
|
||||
* enhanced by Dean P. Macri with the curved surfaces
|
||||
* feature. </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Quake 2 models (.md2)</TD>
|
||||
* <TD>Quake 2 models are characters with morph target
|
||||
* animation. Irrlicht can read, display and animate
|
||||
* them directly with this importer. </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Quake 3 models (.md3)</TD>
|
||||
* <TD>Quake 3 models are characters with morph target
|
||||
* animation, they contain mount points for weapons and body
|
||||
* parts and are typically made of several sections which are
|
||||
* manually joined together.</TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Stanford Triangle (.ply)</TD>
|
||||
* <TD>Invented by Stanford University and known as the native
|
||||
* format of the infamous "Stanford Bunny" model, this is a
|
||||
* popular static mesh format used by 3D scanning hardware
|
||||
* and software. This loader supports extremely large models
|
||||
* in both ASCII and binary format, but only has rudimentary
|
||||
* material support in the form of vertex colors and texture
|
||||
* coordinates.</TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Stereolithography (.stl)</TD>
|
||||
* <TD>The STL format is used for rapid prototyping and
|
||||
* computer-aided manufacturing, thus has no support for
|
||||
* materials.</TD>
|
||||
* </TR>
|
||||
* </TABLE>
|
||||
*
|
||||
* To load and display a mesh quickly, just do this:
|
||||
* \code
|
||||
* SceneManager->addAnimatedMeshSceneNode(
|
||||
* SceneManager->getMesh("yourmesh.3ds"));
|
||||
* \endcode
|
||||
* If you would like to implement and add your own file format loader to Irrlicht,
|
||||
* see addExternalMeshLoader().
|
||||
* \param file File handle of the mesh to load.
|
||||
|
@ -600,13 +411,7 @@ public:
|
|||
//! Get a skinned mesh, which is not available as header-only code
|
||||
/** Note: You need to drop() the pointer after use again, see IReferenceCounted::drop()
|
||||
for details. */
|
||||
virtual ISkinnedMesh *createSkinnedMesh() = 0;
|
||||
|
||||
//! Sets ambient color of the scene
|
||||
virtual void setAmbientLight(const video::SColorf &ambientColor) = 0;
|
||||
|
||||
//! Get ambient color of the scene
|
||||
virtual const video::SColorf &getAmbientLight() const = 0;
|
||||
virtual SkinnedMesh *createSkinnedMesh() = 0;
|
||||
|
||||
//! Get current render pass.
|
||||
virtual E_SCENE_NODE_RENDER_PASS getCurrentRenderPass() const = 0;
|
||||
|
|
|
@ -1,226 +0,0 @@
|
|||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "irrArray.h"
|
||||
#include "IAnimatedMesh.h"
|
||||
#include "SSkinMeshBuffer.h"
|
||||
#include "quaternion.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene
|
||||
{
|
||||
|
||||
enum E_INTERPOLATION_MODE
|
||||
{
|
||||
// constant does use the current key-values without interpolation
|
||||
EIM_CONSTANT = 0,
|
||||
|
||||
// linear interpolation
|
||||
EIM_LINEAR,
|
||||
|
||||
//! count of all available interpolation modes
|
||||
EIM_COUNT
|
||||
};
|
||||
|
||||
//! Interface for using some special functions of Skinned meshes
|
||||
class ISkinnedMesh : public IAnimatedMesh
|
||||
{
|
||||
public:
|
||||
//! Gets joint count.
|
||||
/** \return Amount of joints in the skeletal animated mesh. */
|
||||
virtual u32 getJointCount() const = 0;
|
||||
|
||||
//! Gets the name of a joint.
|
||||
/** \param number: Zero based index of joint. The last joint
|
||||
has the number getJointCount()-1;
|
||||
\return Name of joint and null if an error happened. */
|
||||
virtual const std::optional<std::string> &getJointName(u32 number) const = 0;
|
||||
|
||||
//! Gets a joint number from its name
|
||||
/** \param name: Name of the joint.
|
||||
\return Number of the joint or std::nullopt if not found. */
|
||||
virtual std::optional<u32> getJointNumber(const std::string &name) const = 0;
|
||||
|
||||
//! Use animation from another mesh
|
||||
/** The animation is linked (not copied) based on joint names
|
||||
so make sure they are unique.
|
||||
\return True if all joints in this mesh were
|
||||
matched up (empty names will not be matched, and it's case
|
||||
sensitive). Unmatched joints will not be animated. */
|
||||
virtual bool useAnimationFrom(const ISkinnedMesh *mesh) = 0;
|
||||
|
||||
//! Update Normals when Animating
|
||||
/** \param on If false don't animate, which is faster.
|
||||
Else update normals, which allows for proper lighting of
|
||||
animated meshes. */
|
||||
virtual void updateNormalsWhenAnimating(bool on) = 0;
|
||||
|
||||
//! Sets Interpolation Mode
|
||||
virtual void setInterpolationMode(E_INTERPOLATION_MODE mode) = 0;
|
||||
|
||||
//! Animates this mesh's joints based on frame input
|
||||
virtual void animateMesh(f32 frame, f32 blend) = 0;
|
||||
|
||||
//! Preforms a software skin on this mesh based of joint positions
|
||||
virtual void skinMesh() = 0;
|
||||
|
||||
//! converts the vertex type of all meshbuffers to tangents.
|
||||
/** E.g. used for bump mapping. */
|
||||
virtual void convertMeshToTangents() = 0;
|
||||
|
||||
//! Allows to enable hardware skinning.
|
||||
/* This feature is not implemented in Irrlicht yet */
|
||||
virtual bool setHardwareSkinning(bool on) = 0;
|
||||
|
||||
//! Refreshes vertex data cached in joints such as positions and normals
|
||||
virtual void refreshJointCache() = 0;
|
||||
|
||||
//! Moves the mesh into static position.
|
||||
virtual void resetAnimation() = 0;
|
||||
|
||||
//! A vertex weight
|
||||
struct SWeight
|
||||
{
|
||||
//! Index of the mesh buffer
|
||||
u16 buffer_id; // I doubt 32bits is needed
|
||||
|
||||
//! Index of the vertex
|
||||
u32 vertex_id; // Store global ID here
|
||||
|
||||
//! Weight Strength/Percentage (0-1)
|
||||
f32 strength;
|
||||
|
||||
private:
|
||||
//! Internal members used by CSkinnedMesh
|
||||
friend class CSkinnedMesh;
|
||||
char *Moved;
|
||||
core::vector3df StaticPos;
|
||||
core::vector3df StaticNormal;
|
||||
};
|
||||
|
||||
//! Animation keyframe which describes a new position
|
||||
struct SPositionKey
|
||||
{
|
||||
f32 frame;
|
||||
core::vector3df position;
|
||||
};
|
||||
|
||||
//! Animation keyframe which describes a new scale
|
||||
struct SScaleKey
|
||||
{
|
||||
f32 frame;
|
||||
core::vector3df scale;
|
||||
};
|
||||
|
||||
//! Animation keyframe which describes a new rotation
|
||||
struct SRotationKey
|
||||
{
|
||||
f32 frame;
|
||||
core::quaternion rotation;
|
||||
};
|
||||
|
||||
//! Joints
|
||||
struct SJoint
|
||||
{
|
||||
SJoint() :
|
||||
UseAnimationFrom(0), GlobalSkinningSpace(false),
|
||||
positionHint(-1), scaleHint(-1), rotationHint(-1)
|
||||
{
|
||||
}
|
||||
|
||||
//! The name of this joint
|
||||
std::optional<std::string> Name;
|
||||
|
||||
//! Local matrix of this joint
|
||||
core::matrix4 LocalMatrix;
|
||||
|
||||
//! List of child joints
|
||||
core::array<SJoint *> Children;
|
||||
|
||||
//! List of attached meshes
|
||||
core::array<u32> AttachedMeshes;
|
||||
|
||||
//! Animation keys causing translation change
|
||||
core::array<SPositionKey> PositionKeys;
|
||||
|
||||
//! Animation keys causing scale change
|
||||
core::array<SScaleKey> ScaleKeys;
|
||||
|
||||
//! Animation keys causing rotation change
|
||||
core::array<SRotationKey> RotationKeys;
|
||||
|
||||
//! Skin weights
|
||||
core::array<SWeight> Weights;
|
||||
|
||||
//! Unnecessary for loaders, will be overwritten on finalize
|
||||
core::matrix4 GlobalMatrix; // loaders may still choose to set this (temporarily) to calculate absolute vertex data.
|
||||
core::matrix4 GlobalAnimatedMatrix;
|
||||
core::matrix4 LocalAnimatedMatrix;
|
||||
|
||||
//! These should be set by loaders.
|
||||
core::vector3df Animatedposition;
|
||||
core::vector3df Animatedscale;
|
||||
core::quaternion Animatedrotation;
|
||||
|
||||
// The .x and .gltf formats pre-calculate this
|
||||
std::optional<core::matrix4> GlobalInversedMatrix;
|
||||
private:
|
||||
//! Internal members used by CSkinnedMesh
|
||||
friend class CSkinnedMesh;
|
||||
|
||||
SJoint *UseAnimationFrom;
|
||||
bool GlobalSkinningSpace;
|
||||
|
||||
s32 positionHint;
|
||||
s32 scaleHint;
|
||||
s32 rotationHint;
|
||||
};
|
||||
|
||||
// Interface for the mesh loaders (finalize should lock these functions, and they should have some prefix like loader_
|
||||
|
||||
// these functions will use the needed arrays, set values, etc to help the loaders
|
||||
|
||||
//! exposed for loaders: to add mesh buffers
|
||||
virtual core::array<SSkinMeshBuffer *> &getMeshBuffers() = 0;
|
||||
|
||||
//! exposed for loaders: joints list
|
||||
virtual core::array<SJoint *> &getAllJoints() = 0;
|
||||
|
||||
//! exposed for loaders: joints list
|
||||
virtual const core::array<SJoint *> &getAllJoints() const = 0;
|
||||
|
||||
//! loaders should call this after populating the mesh
|
||||
virtual void finalize() = 0;
|
||||
|
||||
//! Adds a new meshbuffer to the mesh, access it as last one
|
||||
virtual SSkinMeshBuffer *addMeshBuffer() = 0;
|
||||
|
||||
//! Adds a new meshbuffer to the mesh, access it as last one
|
||||
virtual void addMeshBuffer(SSkinMeshBuffer *meshbuf) = 0;
|
||||
|
||||
//! Adds a new joint to the mesh, access it as last one
|
||||
virtual SJoint *addJoint(SJoint *parent = 0) = 0;
|
||||
|
||||
//! Adds a new weight to the mesh, access it as last one
|
||||
virtual SWeight *addWeight(SJoint *joint) = 0;
|
||||
|
||||
//! Adds a new position key to the mesh, access it as last one
|
||||
virtual SPositionKey *addPositionKey(SJoint *joint) = 0;
|
||||
//! Adds a new scale key to the mesh, access it as last one
|
||||
virtual SScaleKey *addScaleKey(SJoint *joint) = 0;
|
||||
//! Adds a new rotation key to the mesh, access it as last one
|
||||
virtual SRotationKey *addRotationKey(SJoint *joint) = 0;
|
||||
|
||||
//! Check if the mesh is non-animated
|
||||
virtual bool isStatic() = 0;
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
} // end namespace irr
|
|
@ -156,6 +156,9 @@ enum E_TEXTURE_TYPE
|
|||
//! 2D texture.
|
||||
ETT_2D,
|
||||
|
||||
//! 2D texture with multisampling.
|
||||
ETT_2D_MS,
|
||||
|
||||
//! Cubemap texture.
|
||||
ETT_CUBEMAP
|
||||
};
|
||||
|
|
|
@ -131,7 +131,6 @@ public:
|
|||
/** The following names can be queried for the given types:
|
||||
MaxTextures (int) The maximum number of simultaneous textures supported by the driver. This can be less than the supported number of textures of the driver. Use _IRR_MATERIAL_MAX_TEXTURES_ to adapt the number.
|
||||
MaxSupportedTextures (int) The maximum number of simultaneous textures supported by the fixed function pipeline of the (hw) driver. The actual supported number of textures supported by the engine can be lower.
|
||||
MaxLights (int) Number of hardware lights supported in the fixed function pipeline of the driver, typically 6-8. Use light manager or deferred shading for more.
|
||||
MaxAnisotropy (int) Number of anisotropy levels supported for filtering. At least 1, max is typically at 16 or 32.
|
||||
MaxAuxBuffers (int) Special render buffers, which are currently not really usable inside Irrlicht. Only supported by OpenGL
|
||||
MaxMultipleRenderTargets (int) Number of render targets which can be bound simultaneously. Rendering to MRTs is done via shaders.
|
||||
|
@ -273,6 +272,14 @@ public:
|
|||
virtual ITexture *addRenderTargetTexture(const core::dimension2d<u32> &size,
|
||||
const io::path &name = "rt", const ECOLOR_FORMAT format = ECF_UNKNOWN) = 0;
|
||||
|
||||
//! Adds a multisampled render target texture to the texture cache.
|
||||
/** \param msaa The number of samples to use, values that make sense are > 1.
|
||||
Only works if the driver supports the EVDF_TEXTURE_MULTISAMPLE feature,
|
||||
check via queryFeature.
|
||||
\see addRenderTargetTexture */
|
||||
virtual ITexture *addRenderTargetTextureMs(const core::dimension2d<u32> &size, u8 msaa,
|
||||
const io::path &name = "rt", const ECOLOR_FORMAT format = ECF_UNKNOWN) = 0;
|
||||
|
||||
//! Adds a new render target texture with 6 sides for a cubemap map to the texture cache.
|
||||
/** \param sideLen Length of one cubemap side.
|
||||
\param name A name for the texture. Later calls of getTexture() with this name will return this texture.
|
||||
|
@ -358,6 +365,10 @@ public:
|
|||
//! Remove all render targets.
|
||||
virtual void removeAllRenderTargets() = 0;
|
||||
|
||||
//! Blit contents of one render target to another one.
|
||||
/** This is glBlitFramebuffer in OpenGL. */
|
||||
virtual void blitRenderTarget(IRenderTarget *from, IRenderTarget *to) = 0;
|
||||
|
||||
//! Sets a boolean alpha channel on the texture based on a color key.
|
||||
/** This makes the texture fully transparent at the texels where
|
||||
this color key can be found when using for example draw2DImage
|
||||
|
@ -1098,15 +1109,6 @@ public:
|
|||
//! Get the graphics card vendor name.
|
||||
virtual core::stringc getVendorInfo() = 0;
|
||||
|
||||
//! Only used by the engine internally.
|
||||
/** The ambient color is set in the scene manager, see
|
||||
scene::ISceneManager::setAmbientLight().
|
||||
\param color New color of the ambient light. */
|
||||
virtual void setAmbientLight(const SColorf &color) = 0;
|
||||
|
||||
//! Get the global ambient light currently used by the driver
|
||||
virtual const SColorf &getAmbientLight() const = 0;
|
||||
|
||||
//! Only used by the engine internally.
|
||||
/** Passes the global material flag AllowZWriteOnTransparent.
|
||||
Use the SceneManager attribute to set this value from your app.
|
||||
|
@ -1116,19 +1118,6 @@ public:
|
|||
//! Get the maximum texture size supported.
|
||||
virtual core::dimension2du getMaxTextureSize() const = 0;
|
||||
|
||||
//! Color conversion convenience function
|
||||
/** Convert an image (as array of pixels) from source to destination
|
||||
array, thereby converting the color format. The pixel size is
|
||||
determined by the color formats.
|
||||
\param sP Pointer to source
|
||||
\param sF Color format of source
|
||||
\param sN Number of pixels to convert, both array must be large enough
|
||||
\param dP Pointer to destination
|
||||
\param dF Color format of destination
|
||||
*/
|
||||
virtual void convertColor(const void *sP, ECOLOR_FORMAT sF, s32 sN,
|
||||
void *dP, ECOLOR_FORMAT dF) const = 0;
|
||||
|
||||
//! Check if the driver supports creating textures with the given color format
|
||||
/** \return True if the format is available, false if not. */
|
||||
virtual bool queryTextureFormat(ECOLOR_FORMAT format) const = 0;
|
||||
|
|
|
@ -21,9 +21,6 @@ struct SAnimatedMesh final : public IAnimatedMesh
|
|||
SAnimatedMesh(scene::IMesh *mesh = 0, scene::E_ANIMATED_MESH_TYPE type = scene::EAMT_UNKNOWN) :
|
||||
IAnimatedMesh(), FramesPerSecond(25.f), Type(type)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("SAnimatedMesh");
|
||||
#endif
|
||||
addMesh(mesh);
|
||||
recalculateBoundingBox();
|
||||
}
|
||||
|
|
|
@ -72,6 +72,9 @@ enum ECOLOR_FORMAT
|
|||
//! 32 bit format using 16 bits for the red and green channels.
|
||||
ECF_R16G16,
|
||||
|
||||
//! 32 bit format using 10 bits for R, G, B and 2 for alpha.
|
||||
ECF_A2R10G10B10,
|
||||
|
||||
/** Depth and stencil formats. */
|
||||
|
||||
//! 16 bit format using 16 bits for depth.
|
||||
|
@ -91,7 +94,7 @@ enum ECOLOR_FORMAT
|
|||
};
|
||||
|
||||
//! Names for ECOLOR_FORMAT types
|
||||
const c8 *const ColorFormatNames[ECF_UNKNOWN + 2] = {
|
||||
const c8 *const ColorFormatNames[] = {
|
||||
"A1R5G5B5",
|
||||
"R5G6B5",
|
||||
"R8G8B8",
|
||||
|
@ -106,6 +109,7 @@ const c8 *const ColorFormatNames[ECF_UNKNOWN + 2] = {
|
|||
"R8G8",
|
||||
"R16",
|
||||
"R16G16",
|
||||
"A2R10G10B10",
|
||||
"D16",
|
||||
"D24",
|
||||
"D32",
|
||||
|
@ -114,6 +118,9 @@ const c8 *const ColorFormatNames[ECF_UNKNOWN + 2] = {
|
|||
0,
|
||||
};
|
||||
|
||||
static_assert(sizeof(ColorFormatNames) / sizeof(ColorFormatNames[0])
|
||||
== ECF_UNKNOWN + 2, "name table size mismatch");
|
||||
|
||||
//! Creates a 16 bit A1R5G5B5 color
|
||||
inline u16 RGBA16(u32 r, u32 g, u32 b, u32 a = 0xFF)
|
||||
{
|
||||
|
@ -224,12 +231,6 @@ inline u32 getBlue(u16 color)
|
|||
return (color & 0x1F);
|
||||
}
|
||||
|
||||
//! Returns the average from a 16 bit A1R5G5B5 color
|
||||
inline s32 getAverage(s16 color)
|
||||
{
|
||||
return ((getRed(color) << 3) + (getGreen(color) << 3) + (getBlue(color) << 3)) / 3;
|
||||
}
|
||||
|
||||
//! Class representing a 32 bit ARGB color.
|
||||
/** The color values for alpha, red, green, and blue are
|
||||
stored in a single u32. So all four values may be between 0 and 255.
|
||||
|
@ -275,24 +276,12 @@ public:
|
|||
0 means no blue, 255 means full blue. */
|
||||
u32 getBlue() const { return color & 0xff; }
|
||||
|
||||
//! Get lightness of the color in the range [0,255]
|
||||
f32 getLightness() const
|
||||
{
|
||||
return 0.5f * (core::max_(core::max_(getRed(), getGreen()), getBlue()) + core::min_(core::min_(getRed(), getGreen()), getBlue()));
|
||||
}
|
||||
|
||||
//! Get luminance of the color in the range [0,255].
|
||||
f32 getLuminance() const
|
||||
//! Get an approximate brightness value of the color in the range [0,255]
|
||||
f32 getBrightness() const
|
||||
{
|
||||
return 0.3f * getRed() + 0.59f * getGreen() + 0.11f * getBlue();
|
||||
}
|
||||
|
||||
//! Get average intensity of the color in the range [0,255].
|
||||
u32 getAverage() const
|
||||
{
|
||||
return (getRed() + getGreen() + getBlue()) / 3;
|
||||
}
|
||||
|
||||
//! Sets the alpha component of the Color.
|
||||
/** The alpha component defines how transparent a color should be.
|
||||
\param a The alpha value of the color. 0 is fully transparent, 255 is fully opaque. */
|
||||
|
@ -362,9 +351,9 @@ public:
|
|||
/** \return True if this color is smaller than the other one */
|
||||
bool operator<(const SColor &other) const { return (color < other.color); }
|
||||
|
||||
//! Adds two colors, result is clamped to 0..255 values
|
||||
//! Adds two colors in a gamma-incorrect way
|
||||
/** \param other Color to add to this color
|
||||
\return Addition of the two colors, clamped to 0..255 values */
|
||||
\return Sum of the two non-linear colors, clamped to 0..255 values */
|
||||
SColor operator+(const SColor &other) const
|
||||
{
|
||||
return SColor(core::min_(getAlpha() + other.getAlpha(), 255u),
|
||||
|
@ -374,7 +363,9 @@ public:
|
|||
}
|
||||
|
||||
//! Interpolates the color with a f32 value to another color
|
||||
/** \param other: Other color
|
||||
/** Note that the interpolation is neither physically nor perceptually
|
||||
linear since it happens directly in the sRGB color space.
|
||||
\param other: Other color
|
||||
\param d: value between 0.0f and 1.0f. d=0 returns other, d=1 returns this, values between interpolate.
|
||||
\return Interpolated color. */
|
||||
SColor getInterpolated(const SColor &other, f32 d) const
|
||||
|
@ -387,34 +378,6 @@ public:
|
|||
(u32)core::round32(other.getBlue() * inv + getBlue() * d));
|
||||
}
|
||||
|
||||
//! Returns interpolated color. ( quadratic )
|
||||
/** \param c1: first color to interpolate with
|
||||
\param c2: second color to interpolate with
|
||||
\param d: value between 0.0f and 1.0f. */
|
||||
SColor getInterpolated_quadratic(const SColor &c1, const SColor &c2, f32 d) const
|
||||
{
|
||||
// this*(1-d)*(1-d) + 2 * c1 * (1-d) + c2 * d * d;
|
||||
d = core::clamp(d, 0.f, 1.f);
|
||||
const f32 inv = 1.f - d;
|
||||
const f32 mul0 = inv * inv;
|
||||
const f32 mul1 = 2.f * d * inv;
|
||||
const f32 mul2 = d * d;
|
||||
|
||||
return SColor(
|
||||
core::clamp(core::floor32(
|
||||
getAlpha() * mul0 + c1.getAlpha() * mul1 + c2.getAlpha() * mul2),
|
||||
0, 255),
|
||||
core::clamp(core::floor32(
|
||||
getRed() * mul0 + c1.getRed() * mul1 + c2.getRed() * mul2),
|
||||
0, 255),
|
||||
core::clamp(core::floor32(
|
||||
getGreen() * mul0 + c1.getGreen() * mul1 + c2.getGreen() * mul2),
|
||||
0, 255),
|
||||
core::clamp(core::floor32(
|
||||
getBlue() * mul0 + c1.getBlue() * mul1 + c2.getBlue() * mul2),
|
||||
0, 255));
|
||||
}
|
||||
|
||||
//! set the color by expecting data in the given format
|
||||
/** \param data: must point to valid memory containing color information in the given format
|
||||
\param format: tells the format in which data is available
|
||||
|
@ -508,7 +471,7 @@ public:
|
|||
SColorf(f32 r, f32 g, f32 b, f32 a = 1.0f) :
|
||||
r(r), g(g), b(b), a(a) {}
|
||||
|
||||
//! Constructs a color from 32 bit Color.
|
||||
//! Constructs a color from 32 bit Color without gamma correction
|
||||
/** \param c: 32 bit color from which this SColorf class is
|
||||
constructed from. */
|
||||
SColorf(SColor c)
|
||||
|
@ -520,7 +483,7 @@ public:
|
|||
a = c.getAlpha() * inv;
|
||||
}
|
||||
|
||||
//! Converts this color to a SColor without floats.
|
||||
//! Converts this color to a SColor without gamma correction
|
||||
SColor toSColor() const
|
||||
{
|
||||
return SColor((u32)core::round32(a * 255.0f), (u32)core::round32(r * 255.0f), (u32)core::round32(g * 255.0f), (u32)core::round32(b * 255.0f));
|
||||
|
@ -558,7 +521,9 @@ public:
|
|||
}
|
||||
|
||||
//! Interpolates the color with a f32 value to another color
|
||||
/** \param other: Other color
|
||||
/** Note that the interpolation is neither physically nor perceptually
|
||||
linear if it happens directly in the sRGB color space.
|
||||
\param other: Other color
|
||||
\param d: value between 0.0f and 1.0f
|
||||
\return Interpolated color. */
|
||||
SColorf getInterpolated(const SColorf &other, f32 d) const
|
||||
|
@ -569,45 +534,6 @@ public:
|
|||
other.g * inv + g * d, other.b * inv + b * d, other.a * inv + a * d);
|
||||
}
|
||||
|
||||
//! Returns interpolated color. ( quadratic )
|
||||
/** \param c1: first color to interpolate with
|
||||
\param c2: second color to interpolate with
|
||||
\param d: value between 0.0f and 1.0f. */
|
||||
inline SColorf getInterpolated_quadratic(const SColorf &c1, const SColorf &c2,
|
||||
f32 d) const
|
||||
{
|
||||
d = core::clamp(d, 0.f, 1.f);
|
||||
// this*(1-d)*(1-d) + 2 * c1 * (1-d) + c2 * d * d;
|
||||
const f32 inv = 1.f - d;
|
||||
const f32 mul0 = inv * inv;
|
||||
const f32 mul1 = 2.f * d * inv;
|
||||
const f32 mul2 = d * d;
|
||||
|
||||
return SColorf(r * mul0 + c1.r * mul1 + c2.r * mul2,
|
||||
g * mul0 + c1.g * mul1 + c2.g * mul2,
|
||||
b * mul0 + c1.b * mul1 + c2.b * mul2,
|
||||
a * mul0 + c1.a * mul1 + c2.a * mul2);
|
||||
}
|
||||
|
||||
//! Sets a color component by index. R=0, G=1, B=2, A=3
|
||||
void setColorComponentValue(s32 index, f32 value)
|
||||
{
|
||||
switch (index) {
|
||||
case 0:
|
||||
r = value;
|
||||
break;
|
||||
case 1:
|
||||
g = value;
|
||||
break;
|
||||
case 2:
|
||||
b = value;
|
||||
break;
|
||||
case 3:
|
||||
a = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//! Returns the alpha component of the color in the range 0.0 (transparent) to 1.0 (opaque)
|
||||
f32 getAlpha() const { return a; }
|
||||
|
||||
|
|
|
@ -230,14 +230,14 @@ const c8 *const ZWriteNames[] = {
|
|||
/** SMaterial might ignore some textures in most function, like assignment and comparison,
|
||||
when SIrrlichtCreationParameters::MaxTextureUnits is set to a lower number.
|
||||
*/
|
||||
const u32 MATERIAL_MAX_TEXTURES = 4;
|
||||
constexpr static u32 MATERIAL_MAX_TEXTURES = 4;
|
||||
|
||||
//! Struct for holding parameters for a material renderer
|
||||
// Note for implementors: Serialization is in CNullDriver
|
||||
class SMaterial
|
||||
{
|
||||
public:
|
||||
//! Default constructor. Creates a solid, lit material with white colors
|
||||
//! Default constructor. Creates a solid material
|
||||
SMaterial() :
|
||||
MaterialType(EMT_SOLID), ColorParam(0, 0, 0, 0),
|
||||
MaterialTypeParam(0.0f), Thickness(1.0f), ZBuffer(ECFN_LESSEQUAL),
|
||||
|
@ -257,7 +257,7 @@ public:
|
|||
E_MATERIAL_TYPE MaterialType;
|
||||
|
||||
//! Custom color parameter, can be used by custom shader materials.
|
||||
// See MainShaderConstantSetter in Minetest.
|
||||
// See MainShaderConstantSetter in Luanti.
|
||||
SColor ColorParam;
|
||||
|
||||
//! Free parameter, dependent on the material type.
|
||||
|
@ -427,10 +427,13 @@ public:
|
|||
PolygonOffsetDepthBias != b.PolygonOffsetDepthBias ||
|
||||
PolygonOffsetSlopeScale != b.PolygonOffsetSlopeScale ||
|
||||
UseMipMaps != b.UseMipMaps;
|
||||
for (u32 i = 0; (i < MATERIAL_MAX_TEXTURES) && !different; ++i) {
|
||||
different |= (TextureLayers[i] != b.TextureLayers[i]);
|
||||
if (different)
|
||||
return true;
|
||||
for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; ++i) {
|
||||
if (TextureLayers[i] != b.TextureLayers[i])
|
||||
return true;
|
||||
}
|
||||
return different;
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Equality operator
|
||||
|
@ -477,5 +480,19 @@ public:
|
|||
|
||||
//! global const identity Material
|
||||
IRRLICHT_API extern SMaterial IdentityMaterial;
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
template<>
|
||||
struct std::hash<irr::video::SMaterial>
|
||||
{
|
||||
/// @brief std::hash specialization for video::SMaterial
|
||||
std::size_t operator()(const irr::video::SMaterial &m) const noexcept
|
||||
{
|
||||
// basic implementation that hashes the two things most likely to differ
|
||||
auto h1 = std::hash<irr::video::ITexture*>{}(m.getTexture(0));
|
||||
auto h2 = std::hash<int>{}(m.MaterialType);
|
||||
return (h1 << 1) ^ h2;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,12 +17,7 @@ namespace scene
|
|||
struct SMesh final : public IMesh
|
||||
{
|
||||
//! constructor
|
||||
SMesh()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("SMesh");
|
||||
#endif
|
||||
}
|
||||
SMesh() {}
|
||||
|
||||
//! destructor
|
||||
virtual ~SMesh()
|
||||
|
|
|
@ -22,9 +22,6 @@ struct SSkinMeshBuffer final : public IMeshBuffer
|
|||
VertexType(vt), PrimitiveType(EPT_TRIANGLES),
|
||||
BoundingBoxNeedsRecalculated(true)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("SSkinMeshBuffer");
|
||||
#endif
|
||||
Vertices_Tangents = new SVertexBufferTangents();
|
||||
Vertices_2TCoords = new SVertexBufferLightMap();
|
||||
Vertices_Standard = new SVertexBuffer();
|
||||
|
|
419
irr/include/SkinnedMesh.h
Normal file
419
irr/include/SkinnedMesh.h
Normal file
|
@ -0,0 +1,419 @@
|
|||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IAnimatedMesh.h"
|
||||
#include "ISceneManager.h"
|
||||
#include "SMeshBuffer.h"
|
||||
#include "SSkinMeshBuffer.h"
|
||||
#include "quaternion.h"
|
||||
#include "vector3d.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene
|
||||
{
|
||||
|
||||
class IAnimatedMeshSceneNode;
|
||||
class IBoneSceneNode;
|
||||
class ISceneManager;
|
||||
|
||||
class SkinnedMesh : public IAnimatedMesh
|
||||
{
|
||||
public:
|
||||
//! constructor
|
||||
SkinnedMesh() :
|
||||
EndFrame(0.f), FramesPerSecond(25.f),
|
||||
LastAnimatedFrame(-1), SkinnedLastFrame(false),
|
||||
HasAnimation(false), PreparedForSkinning(false),
|
||||
AnimateNormals(true), HardwareSkinning(false)
|
||||
{
|
||||
SkinningBuffers = &LocalBuffers;
|
||||
}
|
||||
|
||||
//! destructor
|
||||
virtual ~SkinnedMesh();
|
||||
|
||||
//! If the duration is 0, it is a static (=non animated) mesh.
|
||||
f32 getMaxFrameNumber() const override;
|
||||
|
||||
//! Gets the default animation speed of the animated mesh.
|
||||
/** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */
|
||||
f32 getAnimationSpeed() const override;
|
||||
|
||||
//! Gets the frame count of the animated mesh.
|
||||
/** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated.
|
||||
The actual speed is set in the scene node the mesh is instantiated in.*/
|
||||
void setAnimationSpeed(f32 fps) override;
|
||||
|
||||
//! returns the animated mesh for the given frame
|
||||
IMesh *getMesh(f32) override;
|
||||
|
||||
//! Animates joints based on frame input
|
||||
void animateMesh(f32 frame);
|
||||
|
||||
//! Performs a software skin on this mesh based of joint positions
|
||||
void skinMesh();
|
||||
|
||||
//! returns amount of mesh buffers.
|
||||
u32 getMeshBufferCount() const override;
|
||||
|
||||
//! returns pointer to a mesh buffer
|
||||
IMeshBuffer *getMeshBuffer(u32 nr) const override;
|
||||
|
||||
//! Returns pointer to a mesh buffer which fits a material
|
||||
/** \param material: material to search for
|
||||
\return Returns the pointer to the mesh buffer or
|
||||
NULL if there is no such mesh buffer. */
|
||||
IMeshBuffer *getMeshBuffer(const video::SMaterial &material) const override;
|
||||
|
||||
u32 getTextureSlot(u32 meshbufNr) const override;
|
||||
|
||||
void setTextureSlot(u32 meshbufNr, u32 textureSlot);
|
||||
|
||||
//! returns an axis aligned bounding box
|
||||
const core::aabbox3d<f32> &getBoundingBox() const override {
|
||||
return BoundingBox;
|
||||
}
|
||||
|
||||
//! set user axis aligned bounding box
|
||||
void setBoundingBox(const core::aabbox3df &box) override {
|
||||
BoundingBox = box;
|
||||
}
|
||||
|
||||
//! set the hardware mapping hint, for driver
|
||||
void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer = EBT_VERTEX_AND_INDEX) override;
|
||||
|
||||
//! flags the meshbuffer as changed, reloads hardware buffers
|
||||
void setDirty(E_BUFFER_TYPE buffer = EBT_VERTEX_AND_INDEX) override;
|
||||
|
||||
//! Returns the type of the animated mesh.
|
||||
E_ANIMATED_MESH_TYPE getMeshType() const override {
|
||||
return EAMT_SKINNED;
|
||||
}
|
||||
|
||||
//! Gets joint count.
|
||||
u32 getJointCount() const;
|
||||
|
||||
//! Gets the name of a joint.
|
||||
/** \param number: Zero based index of joint.
|
||||
\return Name of joint and null if an error happened. */
|
||||
const std::optional<std::string> &getJointName(u32 number) const;
|
||||
|
||||
//! Gets a joint number from its name
|
||||
/** \param name: Name of the joint.
|
||||
\return Number of the joint or std::nullopt if not found. */
|
||||
std::optional<u32> getJointNumber(const std::string &name) const;
|
||||
|
||||
//! Update Normals when Animating
|
||||
/** \param on If false don't animate, which is faster.
|
||||
Else update normals, which allows for proper lighting of
|
||||
animated meshes (default). */
|
||||
void updateNormalsWhenAnimating(bool on) {
|
||||
AnimateNormals = on;
|
||||
}
|
||||
|
||||
//! converts the vertex type of all meshbuffers to tangents.
|
||||
/** E.g. used for bump mapping. */
|
||||
void convertMeshToTangents();
|
||||
|
||||
//! Does the mesh have no animation
|
||||
bool isStatic() const {
|
||||
return !HasAnimation;
|
||||
}
|
||||
|
||||
//! Allows to enable hardware skinning.
|
||||
/* This feature is not implemented in Irrlicht yet */
|
||||
bool setHardwareSkinning(bool on);
|
||||
|
||||
//! Refreshes vertex data cached in joints such as positions and normals
|
||||
void refreshJointCache();
|
||||
|
||||
//! Moves the mesh into static position.
|
||||
void resetAnimation();
|
||||
|
||||
virtual void updateBoundingBox();
|
||||
|
||||
//! Recovers the joints from the mesh
|
||||
void recoverJointsFromMesh(std::vector<IBoneSceneNode *> &jointChildSceneNodes);
|
||||
|
||||
//! Transfers the joint data to the mesh
|
||||
void transferJointsToMesh(const std::vector<IBoneSceneNode *> &jointChildSceneNodes);
|
||||
|
||||
//! Creates an array of joints from this mesh as children of node
|
||||
void addJoints(std::vector<IBoneSceneNode *> &jointChildSceneNodes,
|
||||
IAnimatedMeshSceneNode *node,
|
||||
ISceneManager *smgr);
|
||||
|
||||
//! A vertex weight
|
||||
struct SWeight
|
||||
{
|
||||
//! Index of the mesh buffer
|
||||
u16 buffer_id; // I doubt 32bits is needed
|
||||
|
||||
//! Index of the vertex
|
||||
u32 vertex_id; // Store global ID here
|
||||
|
||||
//! Weight Strength/Percentage (0-1)
|
||||
f32 strength;
|
||||
|
||||
private:
|
||||
//! Internal members used by SkinnedMesh
|
||||
friend class SkinnedMesh;
|
||||
char *Moved;
|
||||
core::vector3df StaticPos;
|
||||
core::vector3df StaticNormal;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Channel {
|
||||
struct Frame {
|
||||
f32 time;
|
||||
T value;
|
||||
};
|
||||
std::vector<Frame> frames;
|
||||
bool interpolate = true;
|
||||
|
||||
bool empty() const {
|
||||
return frames.empty();
|
||||
}
|
||||
|
||||
f32 getEndFrame() const {
|
||||
return frames.empty() ? 0 : frames.back().time;
|
||||
}
|
||||
|
||||
void pushBack(f32 time, const T &value) {
|
||||
frames.push_back({time, value});
|
||||
}
|
||||
|
||||
void append(const Channel<T> &other) {
|
||||
frames.insert(frames.end(), other.frames.begin(), other.frames.end());
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
if (frames.empty())
|
||||
return;
|
||||
|
||||
std::vector<Frame> ordered;
|
||||
ordered.push_back(frames.front());
|
||||
// Drop out-of-order frames
|
||||
for (auto it = frames.begin() + 1; it != frames.end(); ++it) {
|
||||
if (it->time > ordered.back().time) {
|
||||
ordered.push_back(*it);
|
||||
}
|
||||
}
|
||||
frames.clear();
|
||||
// Drop redundant middle keys
|
||||
frames.push_back(ordered.front());
|
||||
for (u32 i = 1; i < ordered.size() - 1; ++i) {
|
||||
if (ordered[i - 1].value != ordered[i].value
|
||||
|| ordered[i + 1].value != ordered[i].value) {
|
||||
frames.push_back(ordered[i]);
|
||||
}
|
||||
}
|
||||
if (ordered.size() > 1)
|
||||
frames.push_back(ordered.back());
|
||||
frames.shrink_to_fit();
|
||||
}
|
||||
|
||||
static core::quaternion interpolateValue(core::quaternion from, core::quaternion to, f32 time) {
|
||||
core::quaternion result;
|
||||
result.slerp(from, to, time, 0.001f);
|
||||
return result;
|
||||
}
|
||||
|
||||
static core::vector3df interpolateValue(core::vector3df from, core::vector3df to, f32 time) {
|
||||
// Note: `from` and `to` are swapped here compared to quaternion slerp
|
||||
return to.getInterpolated(from, time);
|
||||
}
|
||||
|
||||
std::optional<T> get(f32 time) const {
|
||||
if (frames.empty())
|
||||
return std::nullopt;
|
||||
|
||||
const auto next = std::lower_bound(frames.begin(), frames.end(), time, [](const auto& frame, f32 time) {
|
||||
return frame.time < time;
|
||||
});
|
||||
if (next == frames.begin())
|
||||
return next->value;
|
||||
if (next == frames.end())
|
||||
return frames.back().value;
|
||||
|
||||
const auto prev = next - 1;
|
||||
if (!interpolate)
|
||||
return prev->value;
|
||||
|
||||
return interpolateValue(prev->value, next->value, (time - prev->time) / (next->time - prev->time));
|
||||
}
|
||||
};
|
||||
|
||||
struct Keys {
|
||||
Channel<core::vector3df> position;
|
||||
Channel<core::quaternion> rotation;
|
||||
Channel<core::vector3df> scale;
|
||||
|
||||
bool empty() const {
|
||||
return position.empty() && rotation.empty() && scale.empty();
|
||||
}
|
||||
|
||||
void append(const Keys &other) {
|
||||
position.append(other.position);
|
||||
rotation.append(other.rotation);
|
||||
scale.append(other.scale);
|
||||
}
|
||||
|
||||
f32 getEndFrame() const {
|
||||
return std::max({
|
||||
position.getEndFrame(),
|
||||
rotation.getEndFrame(),
|
||||
scale.getEndFrame()
|
||||
});
|
||||
}
|
||||
|
||||
void updateTransform(f32 frame,
|
||||
core::vector3df &t, core::quaternion &r, core::vector3df &s) const
|
||||
{
|
||||
if (auto pos = position.get(frame))
|
||||
t = *pos;
|
||||
if (auto rot = rotation.get(frame))
|
||||
r = *rot;
|
||||
if (auto scl = scale.get(frame))
|
||||
s = *scl;
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
position.cleanup();
|
||||
rotation.cleanup();
|
||||
scale.cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
//! Joints
|
||||
struct SJoint
|
||||
{
|
||||
SJoint() : GlobalSkinningSpace(false) {}
|
||||
|
||||
//! The name of this joint
|
||||
std::optional<std::string> Name;
|
||||
|
||||
//! Local matrix of this joint
|
||||
core::matrix4 LocalMatrix;
|
||||
|
||||
//! List of child joints
|
||||
std::vector<SJoint *> Children;
|
||||
|
||||
//! List of attached meshes
|
||||
std::vector<u32> AttachedMeshes;
|
||||
|
||||
// Animation keyframes for translation, rotation, scale
|
||||
Keys keys;
|
||||
|
||||
//! Skin weights
|
||||
std::vector<SWeight> Weights;
|
||||
|
||||
//! Unnecessary for loaders, will be overwritten on finalize
|
||||
core::matrix4 GlobalMatrix; // loaders may still choose to set this (temporarily) to calculate absolute vertex data.
|
||||
core::matrix4 GlobalAnimatedMatrix;
|
||||
core::matrix4 LocalAnimatedMatrix;
|
||||
|
||||
//! These should be set by loaders.
|
||||
core::vector3df Animatedposition;
|
||||
core::vector3df Animatedscale;
|
||||
core::quaternion Animatedrotation;
|
||||
|
||||
// The .x and .gltf formats pre-calculate this
|
||||
std::optional<core::matrix4> GlobalInversedMatrix;
|
||||
private:
|
||||
//! Internal members used by SkinnedMesh
|
||||
friend class SkinnedMesh;
|
||||
|
||||
bool GlobalSkinningSpace;
|
||||
};
|
||||
|
||||
const std::vector<SJoint *> &getAllJoints() const {
|
||||
return AllJoints;
|
||||
}
|
||||
|
||||
protected:
|
||||
void checkForAnimation();
|
||||
|
||||
void normalizeWeights();
|
||||
|
||||
void buildAllLocalAnimatedMatrices();
|
||||
|
||||
void buildAllGlobalAnimatedMatrices(SJoint *Joint = 0, SJoint *ParentJoint = 0);
|
||||
|
||||
void calculateGlobalMatrices(SJoint *Joint, SJoint *ParentJoint);
|
||||
|
||||
void skinJoint(SJoint *Joint, SJoint *ParentJoint);
|
||||
|
||||
void calculateTangents(core::vector3df &normal,
|
||||
core::vector3df &tangent, core::vector3df &binormal,
|
||||
const core::vector3df &vt1, const core::vector3df &vt2, const core::vector3df &vt3,
|
||||
const core::vector2df &tc1, const core::vector2df &tc2, const core::vector2df &tc3);
|
||||
|
||||
std::vector<SSkinMeshBuffer *> *SkinningBuffers; // Meshbuffer to skin, default is to skin localBuffers
|
||||
|
||||
std::vector<SSkinMeshBuffer *> LocalBuffers;
|
||||
//! Mapping from meshbuffer number to bindable texture slot
|
||||
std::vector<u32> TextureSlots;
|
||||
|
||||
std::vector<SJoint *> AllJoints;
|
||||
std::vector<SJoint *> RootJoints;
|
||||
|
||||
// bool can't be used here because std::vector<bool>
|
||||
// doesn't allow taking a reference to individual elements.
|
||||
std::vector<std::vector<char>> Vertices_Moved;
|
||||
|
||||
core::aabbox3d<f32> BoundingBox;
|
||||
|
||||
f32 EndFrame;
|
||||
f32 FramesPerSecond;
|
||||
|
||||
f32 LastAnimatedFrame;
|
||||
bool SkinnedLastFrame;
|
||||
|
||||
bool HasAnimation;
|
||||
bool PreparedForSkinning;
|
||||
bool AnimateNormals;
|
||||
bool HardwareSkinning;
|
||||
};
|
||||
|
||||
// Interface for mesh loaders
|
||||
class SkinnedMeshBuilder : public SkinnedMesh {
|
||||
public:
|
||||
SkinnedMeshBuilder() : SkinnedMesh() {}
|
||||
|
||||
//! loaders should call this after populating the mesh
|
||||
// returns *this, so do not try to drop the mesh builder instance
|
||||
SkinnedMesh *finalize();
|
||||
|
||||
//! alternative method for adding joints
|
||||
std::vector<SJoint *> &getAllJoints() {
|
||||
return AllJoints;
|
||||
}
|
||||
|
||||
//! Adds a new meshbuffer to the mesh, access it as last one
|
||||
SSkinMeshBuffer *addMeshBuffer();
|
||||
|
||||
//! Adds a new meshbuffer to the mesh, access it as last one
|
||||
void addMeshBuffer(SSkinMeshBuffer *meshbuf);
|
||||
|
||||
//! Adds a new joint to the mesh, access it as last one
|
||||
SJoint *addJoint(SJoint *parent = nullptr);
|
||||
|
||||
void addPositionKey(SJoint *joint, f32 frame, core::vector3df pos);
|
||||
void addRotationKey(SJoint *joint, f32 frame, core::quaternion rotation);
|
||||
void addScaleKey(SJoint *joint, f32 frame, core::vector3df scale);
|
||||
|
||||
//! Adds a new weight to the mesh, access it as last one
|
||||
SWeight *addWeight(SJoint *joint);
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
} // end namespace irr
|
|
@ -59,8 +59,12 @@ public:
|
|||
{
|
||||
size_t allocated = m_data.capacity();
|
||||
if (new_size < allocated) {
|
||||
if (canShrink)
|
||||
if (canShrink) {
|
||||
// since capacity != size don't accidentally make it bigger
|
||||
if (m_data.size() > new_size)
|
||||
m_data.resize(new_size);
|
||||
m_data.shrink_to_fit();
|
||||
}
|
||||
} else {
|
||||
m_data.reserve(new_size);
|
||||
}
|
||||
|
|
|
@ -13,11 +13,6 @@
|
|||
#include "rect.h"
|
||||
#include "IrrCompileConfig.h" // for IRRLICHT_API
|
||||
|
||||
// enable this to keep track of changes to the matrix
|
||||
// and make simpler identity check for seldom changing matrices
|
||||
// otherwise identity check will always compare the elements
|
||||
// #define USE_MATRIX_TEST
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace core
|
||||
|
@ -81,9 +76,6 @@ public:
|
|||
//! Simple operator for directly accessing every element of the matrix.
|
||||
T &operator()(const s32 row, const s32 col)
|
||||
{
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return M[row * 4 + col];
|
||||
}
|
||||
|
||||
|
@ -93,9 +85,6 @@ public:
|
|||
//! Simple operator for linearly accessing every element of the matrix.
|
||||
T &operator[](u32 index)
|
||||
{
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return M[index];
|
||||
}
|
||||
|
||||
|
@ -112,19 +101,12 @@ public:
|
|||
const T *pointer() const { return M; }
|
||||
T *pointer()
|
||||
{
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return M;
|
||||
}
|
||||
|
||||
//! Returns true if other matrix is equal to this matrix.
|
||||
constexpr bool operator==(const CMatrix4<T> &other) const
|
||||
{
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
|
||||
return true;
|
||||
#endif
|
||||
for (s32 i = 0; i < 16; ++i)
|
||||
if (M[i] != other.M[i])
|
||||
return false;
|
||||
|
@ -196,9 +178,13 @@ public:
|
|||
CMatrix4<T> &setInverseTranslation(const vector3d<T> &translation);
|
||||
|
||||
//! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
|
||||
//! NOTE: Rotation order is ZYX. This means that vectors are
|
||||
//! first rotated around the X, then the Y, and finally the Z axis.
|
||||
//! NOTE: The rotation is done as per the right-hand rule.
|
||||
//! See test_irr_matrix4.cpp if you're still unsure about the conventions used here.
|
||||
inline CMatrix4<T> &setRotationRadians(const vector3d<T> &rotation);
|
||||
|
||||
//! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
|
||||
//! Same as `setRotationRadians`, but uses degrees.
|
||||
CMatrix4<T> &setRotationDegrees(const vector3d<T> &rotation);
|
||||
|
||||
//! Get the rotation, as set by setRotation() when you already know the scale used to create the matrix
|
||||
|
@ -255,11 +241,20 @@ public:
|
|||
|
||||
//! Transforms the vector by this matrix
|
||||
/** This operation is performed as if the vector was 4d with the 4th component = 1 */
|
||||
void transformVect(vector3df &vect) const;
|
||||
[[nodiscard]] vector3d<T> transformVect(const vector3d<T> &v) const;
|
||||
|
||||
//! Transforms the vector by this matrix
|
||||
/** This operation is performed as if the vector was 4d with the 4th component = 1 */
|
||||
void transformVect(vector3d<T> &vect) const {
|
||||
const vector3d<T> &v = vect;
|
||||
vect = transformVect(v);
|
||||
}
|
||||
|
||||
//! Transforms input vector by this matrix and stores result in output vector
|
||||
/** This operation is performed as if the vector was 4d with the 4th component = 1 */
|
||||
void transformVect(vector3df &out, const vector3df &in) const;
|
||||
void transformVect(vector3d<T> &out, const vector3d<T> &in) const {
|
||||
out = transformVect(in);
|
||||
}
|
||||
|
||||
//! An alternate transform vector method, writing into an array of 4 floats
|
||||
/** This operation is performed as if the vector was 4d with the 4th component =1.
|
||||
|
@ -443,31 +438,17 @@ public:
|
|||
//! Sets all matrix data members at once
|
||||
CMatrix4<T> &setM(const T *data);
|
||||
|
||||
//! Sets if the matrix is definitely identity matrix
|
||||
void setDefinitelyIdentityMatrix(bool isDefinitelyIdentityMatrix);
|
||||
|
||||
//! Gets if the matrix is definitely identity matrix
|
||||
bool getDefinitelyIdentityMatrix() const;
|
||||
|
||||
//! Compare two matrices using the equal method
|
||||
bool equals(const core::CMatrix4<T> &other, const T tolerance = (T)ROUNDING_ERROR_f64) const;
|
||||
|
||||
private:
|
||||
//! Matrix data, stored in row-major order
|
||||
T M[16];
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
//! Flag is this matrix is identity matrix
|
||||
mutable u32 definitelyIdentityMatrix;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Default constructor
|
||||
template <class T>
|
||||
inline CMatrix4<T>::CMatrix4(eConstructor constructor)
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
:
|
||||
definitelyIdentityMatrix(BIT_UNTESTED)
|
||||
#endif
|
||||
{
|
||||
switch (constructor) {
|
||||
case EM4CONST_NOTHING:
|
||||
|
@ -484,10 +465,6 @@ inline CMatrix4<T>::CMatrix4(eConstructor constructor)
|
|||
// Copy constructor
|
||||
template <class T>
|
||||
inline CMatrix4<T>::CMatrix4(const CMatrix4<T> &other, eConstructor constructor)
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
:
|
||||
definitelyIdentityMatrix(BIT_UNTESTED)
|
||||
#endif
|
||||
{
|
||||
switch (constructor) {
|
||||
case EM4CONST_IDENTITY:
|
||||
|
@ -713,9 +690,6 @@ inline CMatrix4<T> &CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T> &other_a
|
|||
M[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15];
|
||||
M[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15];
|
||||
M[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15];
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -787,9 +761,6 @@ inline CMatrix4<T> &CMatrix4<T>::setTranslation(const vector3d<T> &translation)
|
|||
M[12] = translation.X;
|
||||
M[13] = translation.Y;
|
||||
M[14] = translation.Z;
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -799,9 +770,6 @@ inline CMatrix4<T> &CMatrix4<T>::setInverseTranslation(const vector3d<T> &transl
|
|||
M[12] = -translation.X;
|
||||
M[13] = -translation.Y;
|
||||
M[14] = -translation.Z;
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -811,9 +779,6 @@ inline CMatrix4<T> &CMatrix4<T>::setScale(const vector3d<T> &scale)
|
|||
M[0] = scale.X;
|
||||
M[5] = scale.Y;
|
||||
M[10] = scale.Z;
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -856,30 +821,27 @@ inline CMatrix4<T> &CMatrix4<T>::setInverseRotationDegrees(const vector3d<T> &ro
|
|||
template <class T>
|
||||
inline CMatrix4<T> &CMatrix4<T>::setRotationRadians(const vector3d<T> &rotation)
|
||||
{
|
||||
const f64 cr = cos(rotation.X);
|
||||
const f64 sr = sin(rotation.X);
|
||||
const f64 cp = cos(rotation.Y);
|
||||
const f64 sp = sin(rotation.Y);
|
||||
const f64 cy = cos(rotation.Z);
|
||||
const f64 sy = sin(rotation.Z);
|
||||
const f64 cPitch = cos(rotation.X);
|
||||
const f64 sPitch = sin(rotation.X);
|
||||
const f64 cYaw = cos(rotation.Y);
|
||||
const f64 sYaw = sin(rotation.Y);
|
||||
const f64 cRoll = cos(rotation.Z);
|
||||
const f64 sRoll = sin(rotation.Z);
|
||||
|
||||
M[0] = (T)(cp * cy);
|
||||
M[1] = (T)(cp * sy);
|
||||
M[2] = (T)(-sp);
|
||||
M[0] = (T)(cYaw * cRoll);
|
||||
M[1] = (T)(cYaw * sRoll);
|
||||
M[2] = (T)(-sYaw);
|
||||
|
||||
const f64 srsp = sr * sp;
|
||||
const f64 crsp = cr * sp;
|
||||
const f64 sPitch_sYaw = sPitch * sYaw;
|
||||
const f64 cPitch_sYaw = cPitch * sYaw;
|
||||
|
||||
M[4] = (T)(srsp * cy - cr * sy);
|
||||
M[5] = (T)(srsp * sy + cr * cy);
|
||||
M[6] = (T)(sr * cp);
|
||||
M[4] = (T)(sPitch_sYaw * cRoll - cPitch * sRoll);
|
||||
M[5] = (T)(sPitch_sYaw * sRoll + cPitch * cRoll);
|
||||
M[6] = (T)(sPitch * cYaw);
|
||||
|
||||
M[8] = (T)(crsp * cy + sr * sy);
|
||||
M[9] = (T)(crsp * sy - sr * cy);
|
||||
M[10] = (T)(cr * cp);
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
M[8] = (T)(cPitch_sYaw * cRoll + sPitch * sRoll);
|
||||
M[9] = (T)(cPitch_sYaw * sRoll - sPitch * cRoll);
|
||||
M[10] = (T)(cPitch * cYaw);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -960,30 +922,27 @@ inline core::vector3d<T> CMatrix4<T>::getRotationDegrees() const
|
|||
template <class T>
|
||||
inline CMatrix4<T> &CMatrix4<T>::setInverseRotationRadians(const vector3d<T> &rotation)
|
||||
{
|
||||
f64 cr = cos(rotation.X);
|
||||
f64 sr = sin(rotation.X);
|
||||
f64 cp = cos(rotation.Y);
|
||||
f64 sp = sin(rotation.Y);
|
||||
f64 cy = cos(rotation.Z);
|
||||
f64 sy = sin(rotation.Z);
|
||||
f64 cPitch = cos(rotation.X);
|
||||
f64 sPitch = sin(rotation.X);
|
||||
f64 cYaw = cos(rotation.Y);
|
||||
f64 sYaw = sin(rotation.Y);
|
||||
f64 cRoll = cos(rotation.Z);
|
||||
f64 sRoll = sin(rotation.Z);
|
||||
|
||||
M[0] = (T)(cp * cy);
|
||||
M[4] = (T)(cp * sy);
|
||||
M[8] = (T)(-sp);
|
||||
M[0] = (T)(cYaw * cRoll);
|
||||
M[4] = (T)(cYaw * sRoll);
|
||||
M[8] = (T)(-sYaw);
|
||||
|
||||
f64 srsp = sr * sp;
|
||||
f64 crsp = cr * sp;
|
||||
f64 sPitch_sYaw = sPitch * sYaw;
|
||||
f64 cPitch_sYaw = cPitch * sYaw;
|
||||
|
||||
M[1] = (T)(srsp * cy - cr * sy);
|
||||
M[5] = (T)(srsp * sy + cr * cy);
|
||||
M[9] = (T)(sr * cp);
|
||||
M[1] = (T)(sPitch_sYaw * cRoll - cPitch * sRoll);
|
||||
M[5] = (T)(sPitch_sYaw * sRoll + cPitch * cRoll);
|
||||
M[9] = (T)(sPitch * cYaw);
|
||||
|
||||
M[2] = (T)(crsp * cy + sr * sy);
|
||||
M[6] = (T)(crsp * sy - sr * cy);
|
||||
M[10] = (T)(cr * cp);
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
M[2] = (T)(cPitch_sYaw * cRoll + sPitch * sRoll);
|
||||
M[6] = (T)(cPitch_sYaw * sRoll - sPitch * cRoll);
|
||||
M[10] = (T)(cPitch * cYaw);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1015,9 +974,6 @@ inline CMatrix4<T> &CMatrix4<T>::setRotationAxisRadians(const T &angle, const ve
|
|||
M[9] = (T)(tz * axis.Y - sx);
|
||||
M[10] = (T)(tz * axis.Z + c);
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1028,9 +984,6 @@ inline CMatrix4<T> &CMatrix4<T>::makeIdentity()
|
|||
{
|
||||
memset(M, 0, 16 * sizeof(T));
|
||||
M[0] = M[5] = M[10] = M[15] = (T)1;
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = true;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1041,10 +994,6 @@ inline CMatrix4<T> &CMatrix4<T>::makeIdentity()
|
|||
template <class T>
|
||||
inline bool CMatrix4<T>::isIdentity() const
|
||||
{
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
if (definitelyIdentityMatrix)
|
||||
return true;
|
||||
#endif
|
||||
if (!core::equals(M[12], (T)0) || !core::equals(M[13], (T)0) || !core::equals(M[14], (T)0) || !core::equals(M[15], (T)1))
|
||||
return false;
|
||||
|
||||
|
@ -1068,9 +1017,6 @@ inline bool CMatrix4<T>::isIdentity() const
|
|||
if ((j != i) && (!iszero((*this)(i,j))))
|
||||
return false;
|
||||
*/
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = true;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1106,10 +1052,6 @@ inline bool CMatrix4<T>::isOrthogonal() const
|
|||
template <class T>
|
||||
inline bool CMatrix4<T>::isIdentity_integer_base() const
|
||||
{
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
if (definitelyIdentityMatrix)
|
||||
return true;
|
||||
#endif
|
||||
if (IR(M[0]) != F32_VALUE_1)
|
||||
return false;
|
||||
if (IR(M[1]) != 0)
|
||||
|
@ -1146,9 +1088,6 @@ inline bool CMatrix4<T>::isIdentity_integer_base() const
|
|||
if (IR(M[15]) != F32_VALUE_1)
|
||||
return false;
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = true;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1173,25 +1112,13 @@ inline vector3d<T> CMatrix4<T>::scaleThenInvRotVect(const vector3d<T> &v) const
|
|||
}
|
||||
|
||||
template <class T>
|
||||
inline void CMatrix4<T>::transformVect(vector3df &vect) const
|
||||
inline vector3d<T> CMatrix4<T>::transformVect(const vector3d<T> &v) const
|
||||
{
|
||||
T vector[3];
|
||||
|
||||
vector[0] = vect.X * M[0] + vect.Y * M[4] + vect.Z * M[8] + M[12];
|
||||
vector[1] = vect.X * M[1] + vect.Y * M[5] + vect.Z * M[9] + M[13];
|
||||
vector[2] = vect.X * M[2] + vect.Y * M[6] + vect.Z * M[10] + M[14];
|
||||
|
||||
vect.X = static_cast<f32>(vector[0]);
|
||||
vect.Y = static_cast<f32>(vector[1]);
|
||||
vect.Z = static_cast<f32>(vector[2]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void CMatrix4<T>::transformVect(vector3df &out, const vector3df &in) const
|
||||
{
|
||||
out.X = in.X * M[0] + in.Y * M[4] + in.Z * M[8] + M[12];
|
||||
out.Y = in.X * M[1] + in.Y * M[5] + in.Z * M[9] + M[13];
|
||||
out.Z = in.X * M[2] + in.Y * M[6] + in.Z * M[10] + M[14];
|
||||
return {
|
||||
v.X * M[0] + v.Y * M[4] + v.Z * M[8] + M[12],
|
||||
v.X * M[1] + v.Y * M[5] + v.Z * M[9] + M[13],
|
||||
v.X * M[2] + v.Y * M[6] + v.Z * M[10] + M[14],
|
||||
};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
@ -1402,9 +1329,6 @@ inline bool CMatrix4<T>::getInverse(CMatrix4<T> &out) const
|
|||
m[1] * (m[6] * m[8] - m[4] * m[10]) +
|
||||
m[2] * (m[4] * m[9] - m[5] * m[8]));
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
out.definitelyIdentityMatrix = definitelyIdentityMatrix;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1433,9 +1357,6 @@ inline bool CMatrix4<T>::getInversePrimitive(CMatrix4<T> &out) const
|
|||
out.M[14] = (T) - (M[12] * M[8] + M[13] * M[9] + M[14] * M[10]);
|
||||
out.M[15] = 1;
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
out.definitelyIdentityMatrix = definitelyIdentityMatrix;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1444,10 +1365,6 @@ inline bool CMatrix4<T>::getInversePrimitive(CMatrix4<T> &out) const
|
|||
template <class T>
|
||||
inline bool CMatrix4<T>::makeInverse()
|
||||
{
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
if (definitelyIdentityMatrix)
|
||||
return true;
|
||||
#endif
|
||||
CMatrix4<T> temp(EM4CONST_NOTHING);
|
||||
|
||||
if (getInverse(temp)) {
|
||||
|
@ -1464,9 +1381,6 @@ inline CMatrix4<T> &CMatrix4<T>::operator=(const T &scalar)
|
|||
for (s32 i = 0; i < 16; ++i)
|
||||
M[i] = scalar;
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1509,9 +1423,6 @@ inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH(
|
|||
M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar));
|
||||
}
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1554,9 +1465,6 @@ inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH(
|
|||
M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar));
|
||||
}
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1589,9 +1497,6 @@ inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveFovInfinityLH(
|
|||
M[14] = (T)(zNear * (epsilon - 1.f));
|
||||
M[15] = 0;
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1631,9 +1536,6 @@ inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixOrthoLH(
|
|||
M[14] = (T) - (zFar + zNear) / (zFar - zNear);
|
||||
}
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1673,9 +1575,6 @@ inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixOrthoRH(
|
|||
M[14] = (T) - (zFar + zNear) / (zFar - zNear);
|
||||
}
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1716,9 +1615,6 @@ inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveRH(
|
|||
M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar));
|
||||
}
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1759,9 +1655,6 @@ inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveLH(
|
|||
M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar));
|
||||
}
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1791,9 +1684,7 @@ inline CMatrix4<T> &CMatrix4<T>::buildShadowMatrix(const core::vector3df &light,
|
|||
M[13] = (T)(-plane.D * light.Y);
|
||||
M[14] = (T)(-plane.D * light.Z);
|
||||
M[15] = (T)(-plane.D * point + d);
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1831,9 +1722,7 @@ inline CMatrix4<T> &CMatrix4<T>::buildCameraLookAtMatrixLH(
|
|||
M[13] = (T)-yaxis.dotProduct(position);
|
||||
M[14] = (T)-zaxis.dotProduct(position);
|
||||
M[15] = 1;
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1871,9 +1760,7 @@ inline CMatrix4<T> &CMatrix4<T>::buildCameraLookAtMatrixRH(
|
|||
M[13] = (T)-yaxis.dotProduct(position);
|
||||
M[14] = (T)-zaxis.dotProduct(position);
|
||||
M[15] = 1;
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1924,9 +1811,6 @@ inline void CMatrix4<T>::getTransposed(CMatrix4<T> &o) const
|
|||
o[13] = M[7];
|
||||
o[14] = M[11];
|
||||
o[15] = M[15];
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
o.definitelyIdentityMatrix = definitelyIdentityMatrix;
|
||||
#endif
|
||||
}
|
||||
|
||||
// used to scale <-1,-1><1,1> to viewport
|
||||
|
@ -2064,9 +1948,6 @@ inline void CMatrix4<T>::setRotationCenter(const core::vector3df ¢er, const
|
|||
M[13] = -M[1] * center.X - M[5] * center.Y - M[9] * center.Z + (center.Y - translation.Y);
|
||||
M[14] = -M[2] * center.X - M[6] * center.Y - M[10] * center.Z + (center.Z - translation.Z);
|
||||
M[15] = (T)1.0;
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -2108,9 +1989,7 @@ inline CMatrix4<T> &CMatrix4<T>::buildTextureTransform(f32 rotateRad,
|
|||
M[13] = 0;
|
||||
M[14] = 0;
|
||||
M[15] = 1;
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -2129,9 +2008,6 @@ inline CMatrix4<T> &CMatrix4<T>::setTextureRotationCenter(f32 rotateRad)
|
|||
M[8] = (T)(0.5f * (s - c) + 0.5f);
|
||||
M[9] = (T)(-0.5f * (s + c) + 0.5f);
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad == 0.0f);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -2141,9 +2017,6 @@ inline CMatrix4<T> &CMatrix4<T>::setTextureTranslate(f32 x, f32 y)
|
|||
M[8] = (T)x;
|
||||
M[9] = (T)y;
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = definitelyIdentityMatrix && (x == 0.0f) && (y == 0.0f);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -2159,10 +2032,6 @@ inline CMatrix4<T> &CMatrix4<T>::setTextureTranslateTransposed(f32 x, f32 y)
|
|||
{
|
||||
M[2] = (T)x;
|
||||
M[6] = (T)y;
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = definitelyIdentityMatrix && (x == 0.0f) && (y == 0.0f);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -2171,9 +2040,6 @@ inline CMatrix4<T> &CMatrix4<T>::setTextureScale(f32 sx, f32 sy)
|
|||
{
|
||||
M[0] = (T)sx;
|
||||
M[5] = (T)sy;
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = definitelyIdentityMatrix && (sx == 1.0f) && (sy == 1.0f);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -2191,10 +2057,6 @@ inline CMatrix4<T> &CMatrix4<T>::setTextureScaleCenter(f32 sx, f32 sy)
|
|||
M[5] = (T)sy;
|
||||
M[8] = (T)(0.5f - 0.5f * sx);
|
||||
M[9] = (T)(0.5f - 0.5f * sy);
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = definitelyIdentityMatrix && (sx == 1.0f) && (sy == 1.0f);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -2203,43 +2065,13 @@ template <class T>
|
|||
inline CMatrix4<T> &CMatrix4<T>::setM(const T *data)
|
||||
{
|
||||
memcpy(M, data, 16 * sizeof(T));
|
||||
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = false;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
// sets if the matrix is definitely identity matrix
|
||||
template <class T>
|
||||
inline void CMatrix4<T>::setDefinitelyIdentityMatrix(bool isDefinitelyIdentityMatrix)
|
||||
{
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
definitelyIdentityMatrix = isDefinitelyIdentityMatrix;
|
||||
#else
|
||||
(void)isDefinitelyIdentityMatrix; // prevent compiler warning
|
||||
#endif
|
||||
}
|
||||
|
||||
// gets if the matrix is definitely identity matrix
|
||||
template <class T>
|
||||
inline bool CMatrix4<T>::getDefinitelyIdentityMatrix() const
|
||||
{
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
return definitelyIdentityMatrix;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
//! Compare two matrices using the equal method
|
||||
template <class T>
|
||||
inline bool CMatrix4<T>::equals(const core::CMatrix4<T> &other, const T tolerance) const
|
||||
{
|
||||
#if defined(USE_MATRIX_TEST)
|
||||
if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
|
||||
return true;
|
||||
#endif
|
||||
for (s32 i = 0; i < 16; ++i)
|
||||
if (!core::equals(M[i], other.M[i], tolerance))
|
||||
return false;
|
||||
|
|
|
@ -15,11 +15,18 @@
|
|||
#ifndef APIENTRYP
|
||||
#define APIENTRYP APIENTRY *
|
||||
#endif
|
||||
#ifndef GLAPI
|
||||
#define GLAPI extern
|
||||
// undefine a few names that can easily clash with system headers
|
||||
#ifdef NO_ERROR
|
||||
#undef NO_ERROR
|
||||
#endif
|
||||
#ifdef ZERO
|
||||
#undef ZERO
|
||||
#endif
|
||||
#ifdef ONE
|
||||
#undef ONE
|
||||
#endif
|
||||
|
||||
class OpenGLProcedures {
|
||||
class OpenGLProcedures final {
|
||||
private:
|
||||
// ./glcorearb.h
|
||||
typedef void GLvoid;
|
||||
|
@ -49,8 +56,6 @@ private:
|
|||
typedef khronos_int64_t GLint64EXT;
|
||||
|
||||
typedef void *GLeglClientBufferEXT;
|
||||
// The script will miss this particular typedef thinking it's a PFN,
|
||||
// so we have to paste it in manually. It's the only such type in OpenGL.
|
||||
typedef void (APIENTRY *GLDEBUGPROC)
|
||||
(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
|
||||
|
||||
|
@ -775,10 +780,12 @@ private:
|
|||
typedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTPROC_MT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
|
||||
|
||||
std::unordered_set<std::string> extensions;
|
||||
|
||||
public:
|
||||
// Call this once after creating the context.
|
||||
void LoadAllProcedures(irr::video::IContextManager *cmgr);
|
||||
// Check if an extension is supported.
|
||||
/// Check if an extension is supported.
|
||||
/// @param ext full extension name e.g. "GL_KHR_no_error"
|
||||
inline bool IsExtensionPresent(const std::string &ext) const
|
||||
{
|
||||
return extensions.count(ext) > 0;
|
||||
|
@ -3185,6 +3192,7 @@ public:
|
|||
static constexpr const GLenum STATE_RESTORE = 0x8BDC;
|
||||
static constexpr const GLenum SHADER_BINARY_VIV = 0x8FC4;
|
||||
|
||||
static constexpr const GLenum NO_ERROR = 0;
|
||||
static constexpr const GLenum ZERO = 0;
|
||||
static constexpr const GLenum ONE = 1;
|
||||
static constexpr const GLenum NONE = 0;
|
||||
|
|
|
@ -358,8 +358,6 @@ inline void quaternion::getMatrixFast(matrix4 &dest) const
|
|||
dest[13] = 0.f;
|
||||
dest[14] = 0.f;
|
||||
dest[15] = 1.f;
|
||||
|
||||
dest.setDefinitelyIdentityMatrix(false);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -397,8 +395,6 @@ inline void quaternion::getMatrix(matrix4 &dest,
|
|||
dest[13] = center.Y;
|
||||
dest[14] = center.Z;
|
||||
dest[15] = 1.f;
|
||||
|
||||
dest.setDefinitelyIdentityMatrix(false);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -471,8 +467,6 @@ inline void quaternion::getMatrix_transposed(matrix4 &dest) const
|
|||
dest[7] = 0.f;
|
||||
dest[11] = 0.f;
|
||||
dest[15] = 1.f;
|
||||
|
||||
dest.setDefinitelyIdentityMatrix(false);
|
||||
}
|
||||
|
||||
// Inverts this quaternion
|
||||
|
|
|
@ -219,11 +219,11 @@ local function ParseHeader( path, into, apiRegex, defs, consts, nameSet, noNewNa
|
|||
};
|
||||
end
|
||||
elseif ( line:find( "#" ) and not line:find( "#include" ) ) then
|
||||
local rawName, value = line:match( "#define%s+GL_([_%w]+)%s+0x(%w+)" );
|
||||
local rawName, value = line:match( "#define%s+GL_([_%w]+)%s+(0x%w+)" );
|
||||
if rawName and value then
|
||||
local name, vendor = StripVendorSuffix( rawName, true );
|
||||
if not constBanned[vendor] then
|
||||
consts:Add{ name = name, vendor = vendor, value = "0x"..value };
|
||||
consts:Add{ name = name, vendor = vendor, value = value };
|
||||
end
|
||||
end
|
||||
::skip::
|
||||
|
@ -359,21 +359,28 @@ f:write[[
|
|||
#ifndef APIENTRYP
|
||||
#define APIENTRYP APIENTRY *
|
||||
#endif
|
||||
#ifndef GLAPI
|
||||
#define GLAPI extern
|
||||
// undefine a few names that can easily clash with system headers
|
||||
#ifdef NO_ERROR
|
||||
#undef NO_ERROR
|
||||
#endif
|
||||
#ifdef ZERO
|
||||
#undef ZERO
|
||||
#endif
|
||||
#ifdef ONE
|
||||
#undef ONE
|
||||
#endif
|
||||
|
||||
]];
|
||||
|
||||
f:write[[
|
||||
class OpenGLProcedures {
|
||||
class OpenGLProcedures final {
|
||||
private:
|
||||
]];
|
||||
f:write( definitions:Concat( "\n" ) );
|
||||
f:write( "\n" );
|
||||
-- The script will miss this particular typedef thinking it's a PFN,
|
||||
-- so we have to paste it in manually. It's the only such type in OpenGL.
|
||||
f:write[[
|
||||
// The script will miss this particular typedef thinking it's a PFN,
|
||||
// so we have to paste it in manually. It's the only such type in OpenGL.
|
||||
typedef void (APIENTRY *GLDEBUGPROC)
|
||||
(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
|
||||
|
||||
|
@ -382,10 +389,12 @@ f:write( typedefs:Concat( "\n" ) );
|
|||
f:write( "\n\n" );
|
||||
f:write [[
|
||||
std::unordered_set<std::string> extensions;
|
||||
|
||||
public:
|
||||
// Call this once after creating the context.
|
||||
void LoadAllProcedures(irr::video::IContextManager *cmgr);
|
||||
// Check if an extension is supported.
|
||||
/// Check if an extension is supported.
|
||||
/// @param ext full extension name e.g. "GL_KHR_no_error"
|
||||
inline bool IsExtensionPresent(const std::string &ext) const
|
||||
{
|
||||
return extensions.count(ext) > 0;
|
||||
|
@ -396,7 +405,10 @@ f:write( pointers:Concat( "\n" ) );
|
|||
f:write( "\n\n" );
|
||||
f:write( cppConsts:Concat( "\n" ) );
|
||||
f:write( "\n\n" );
|
||||
-- We filter constants not in hex format to avoid the VERSION_X_X and extension
|
||||
-- defines, but that means we miss these.
|
||||
f:write[[
|
||||
static constexpr const GLenum NO_ERROR = 0;
|
||||
static constexpr const GLenum ZERO = 0;
|
||||
static constexpr const GLenum ONE = 1;
|
||||
static constexpr const GLenum NONE = 0;
|
||||
|
@ -416,7 +428,7 @@ f:write[[
|
|||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
OpenGLProcedures GL = OpenGLProcedures();
|
||||
OpenGLProcedures GL;
|
||||
|
||||
void OpenGLProcedures::LoadAllProcedures(irr::video::IContextManager *cmgr)
|
||||
{
|
||||
|
@ -425,9 +437,11 @@ void OpenGLProcedures::LoadAllProcedures(irr::video::IContextManager *cmgr)
|
|||
f:write( loader:Concat() );
|
||||
f:write[[
|
||||
|
||||
// OpenGL 3 way to enumerate extensions
|
||||
/* OpenGL 3 & ES 3 way to enumerate extensions */
|
||||
GLint ext_count = 0;
|
||||
GetIntegerv(NUM_EXTENSIONS, &ext_count);
|
||||
// clear error which is raised if unsupported
|
||||
while (GetError() != GL.NO_ERROR) {}
|
||||
extensions.reserve(ext_count);
|
||||
for (GLint k = 0; k < ext_count; k++) {
|
||||
auto tmp = GetStringi(EXTENSIONS, k);
|
||||
|
@ -437,16 +451,15 @@ f:write[[
|
|||
if (!extensions.empty())
|
||||
return;
|
||||
|
||||
// OpenGL 2 / ES 2 way to enumerate extensions
|
||||
/* OpenGL 2 / ES 2 way to enumerate extensions */
|
||||
auto ext_str = GetString(EXTENSIONS);
|
||||
if (!ext_str)
|
||||
return;
|
||||
// get the extension string, chop it up
|
||||
std::stringstream ext_ss((char*)ext_str);
|
||||
std::istringstream ext_ss((char*)ext_str);
|
||||
std::string tmp;
|
||||
while (std::getline(ext_ss, tmp, ' '))
|
||||
extensions.emplace(tmp);
|
||||
|
||||
}
|
||||
]];
|
||||
f:close();
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "ISceneManager.h"
|
||||
#include "S3DVertex.h"
|
||||
#include "os.h"
|
||||
#include "CSkinnedMesh.h"
|
||||
#include "SkinnedMesh.h"
|
||||
#include "IDummyTransformationSceneNode.h"
|
||||
#include "IBoneSceneNode.h"
|
||||
#include "IMaterialRenderer.h"
|
||||
|
@ -38,10 +38,6 @@ CAnimatedMeshSceneNode::CAnimatedMeshSceneNode(IAnimatedMesh *mesh,
|
|||
Looping(true), ReadOnlyMaterials(false), RenderFromIdentity(false),
|
||||
LoopCallBack(0), PassCount(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CAnimatedMeshSceneNode");
|
||||
#endif
|
||||
|
||||
setMesh(mesh);
|
||||
}
|
||||
|
||||
|
@ -165,12 +161,12 @@ IMesh *CAnimatedMeshSceneNode::getMeshForCurrentFrame()
|
|||
// As multiple scene nodes may be sharing the same skinned mesh, we have to
|
||||
// re-animate it every frame to ensure that this node gets the mesh that it needs.
|
||||
|
||||
CSkinnedMesh *skinnedMesh = static_cast<CSkinnedMesh *>(Mesh);
|
||||
SkinnedMesh *skinnedMesh = static_cast<SkinnedMesh *>(Mesh);
|
||||
|
||||
if (JointMode == EJUOR_CONTROL) // write to mesh
|
||||
skinnedMesh->transferJointsToMesh(JointChildSceneNodes);
|
||||
else
|
||||
skinnedMesh->animateMesh(getFrameNr(), 1.0f);
|
||||
skinnedMesh->animateMesh(getFrameNr());
|
||||
|
||||
// Update the skinned mesh for the current joint transforms.
|
||||
skinnedMesh->skinMesh();
|
||||
|
@ -227,7 +223,7 @@ void CAnimatedMeshSceneNode::render()
|
|||
Box = m->getBoundingBox();
|
||||
} else {
|
||||
#ifdef _DEBUG
|
||||
os::Printer::log("Animated Mesh returned no mesh to render.", Mesh->getDebugName(), ELL_WARNING);
|
||||
os::Printer::log("Animated Mesh returned no mesh to render.", ELL_WARNING);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
@ -299,12 +295,10 @@ void CAnimatedMeshSceneNode::render()
|
|||
if (Mesh->getMeshType() == EAMT_SKINNED) {
|
||||
// draw skeleton
|
||||
|
||||
for (u32 g = 0; g < ((ISkinnedMesh *)Mesh)->getAllJoints().size(); ++g) {
|
||||
ISkinnedMesh::SJoint *joint = ((ISkinnedMesh *)Mesh)->getAllJoints()[g];
|
||||
|
||||
for (u32 n = 0; n < joint->Children.size(); ++n) {
|
||||
for (auto *joint : ((SkinnedMesh *)Mesh)->getAllJoints()) {
|
||||
for (const auto *childJoint : joint->Children) {
|
||||
driver->draw3DLine(joint->GlobalAnimatedMatrix.getTranslation(),
|
||||
joint->Children[n]->GlobalAnimatedMatrix.getTranslation(),
|
||||
childJoint->GlobalAnimatedMatrix.getTranslation(),
|
||||
video::SColor(255, 51, 66, 255));
|
||||
}
|
||||
}
|
||||
|
@ -404,7 +398,7 @@ IBoneSceneNode *CAnimatedMeshSceneNode::getJointNode(const c8 *jointName)
|
|||
|
||||
checkJoints();
|
||||
|
||||
ISkinnedMesh *skinnedMesh = (ISkinnedMesh *)Mesh;
|
||||
auto *skinnedMesh = (SkinnedMesh *)Mesh;
|
||||
|
||||
const std::optional<u32> number = skinnedMesh->getJointNumber(jointName);
|
||||
|
||||
|
@ -446,7 +440,7 @@ u32 CAnimatedMeshSceneNode::getJointCount() const
|
|||
if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED)
|
||||
return 0;
|
||||
|
||||
ISkinnedMesh *skinnedMesh = (ISkinnedMesh *)Mesh;
|
||||
auto *skinnedMesh = (SkinnedMesh *)Mesh;
|
||||
|
||||
return skinnedMesh->getJointCount();
|
||||
}
|
||||
|
@ -596,10 +590,9 @@ void CAnimatedMeshSceneNode::animateJoints(bool CalculateAbsolutePositions)
|
|||
checkJoints();
|
||||
const f32 frame = getFrameNr(); // old?
|
||||
|
||||
CSkinnedMesh *skinnedMesh = static_cast<CSkinnedMesh *>(Mesh);
|
||||
SkinnedMesh *skinnedMesh = static_cast<SkinnedMesh *>(Mesh);
|
||||
|
||||
skinnedMesh->transferOnlyJointsHintsToMesh(JointChildSceneNodes);
|
||||
skinnedMesh->animateMesh(frame, 1.0f);
|
||||
skinnedMesh->animateMesh(frame);
|
||||
skinnedMesh->recoverJointsFromMesh(JointChildSceneNodes);
|
||||
|
||||
//-----------------------------------------
|
||||
|
@ -671,8 +664,8 @@ void CAnimatedMeshSceneNode::checkJoints()
|
|||
JointChildSceneNodes.clear();
|
||||
|
||||
// Create joints for SkinnedMesh
|
||||
((CSkinnedMesh *)Mesh)->addJoints(JointChildSceneNodes, this, SceneManager);
|
||||
((CSkinnedMesh *)Mesh)->recoverJointsFromMesh(JointChildSceneNodes);
|
||||
((SkinnedMesh *)Mesh)->addJoints(JointChildSceneNodes, this, SceneManager);
|
||||
((SkinnedMesh *)Mesh)->recoverJointsFromMesh(JointChildSceneNodes);
|
||||
|
||||
JointsUsed = true;
|
||||
JointMode = EJUOR_READ;
|
||||
|
|
|
@ -169,7 +169,7 @@ private:
|
|||
IAnimationEndCallBack *LoopCallBack;
|
||||
s32 PassCount;
|
||||
|
||||
core::array<IBoneSceneNode *> JointChildSceneNodes;
|
||||
std::vector<IBoneSceneNode *> JointChildSceneNodes;
|
||||
core::array<core::matrix4> PretransitingSave;
|
||||
};
|
||||
|
||||
|
|
|
@ -12,12 +12,7 @@ namespace irr
|
|||
namespace io
|
||||
{
|
||||
|
||||
CAttributes::CAttributes()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CAttributes");
|
||||
#endif
|
||||
}
|
||||
CAttributes::CAttributes() {}
|
||||
|
||||
CAttributes::~CAttributes()
|
||||
{
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "IVideoDriver.h"
|
||||
#include "IFileSystem.h"
|
||||
#include "SkinnedMesh.h"
|
||||
#include "coreutil.h"
|
||||
#include "os.h"
|
||||
|
||||
|
@ -28,11 +29,7 @@ namespace scene
|
|||
CB3DMeshFileLoader::CB3DMeshFileLoader(scene::ISceneManager *smgr) :
|
||||
AnimatedMesh(0), B3DFile(0), VerticesStart(0), NormalsInFile(false),
|
||||
HasVertexColors(false), ShowWarning(true)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CB3DMeshFileLoader");
|
||||
#endif
|
||||
}
|
||||
{}
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".bsp")
|
||||
|
@ -51,12 +48,12 @@ IAnimatedMesh *CB3DMeshFileLoader::createMesh(io::IReadFile *file)
|
|||
return 0;
|
||||
|
||||
B3DFile = file;
|
||||
AnimatedMesh = new scene::CSkinnedMesh();
|
||||
AnimatedMesh = new scene::SkinnedMeshBuilder();
|
||||
ShowWarning = true; // If true a warning is issued if too many textures are used
|
||||
VerticesStart = 0;
|
||||
|
||||
if (load()) {
|
||||
AnimatedMesh->finalize();
|
||||
return AnimatedMesh->finalize();
|
||||
} else {
|
||||
AnimatedMesh->drop();
|
||||
AnimatedMesh = 0;
|
||||
|
@ -111,7 +108,7 @@ bool CB3DMeshFileLoader::load()
|
|||
if (!readChunkBRUS())
|
||||
return false;
|
||||
} else if (strncmp(B3dStack.getLast().name, "NODE", 4) == 0) {
|
||||
if (!readChunkNODE((CSkinnedMesh::SJoint *)0))
|
||||
if (!readChunkNODE((SkinnedMesh::SJoint *)0))
|
||||
return false;
|
||||
} else {
|
||||
os::Printer::log("Unknown chunk found in mesh base - skipping");
|
||||
|
@ -133,9 +130,9 @@ bool CB3DMeshFileLoader::load()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *inJoint)
|
||||
bool CB3DMeshFileLoader::readChunkNODE(SkinnedMesh::SJoint *inJoint)
|
||||
{
|
||||
CSkinnedMesh::SJoint *joint = AnimatedMesh->addJoint(inJoint);
|
||||
SkinnedMesh::SJoint *joint = AnimatedMesh->addJoint(inJoint);
|
||||
joint->Name = readString();
|
||||
|
||||
#ifdef _B3D_READER_DEBUG
|
||||
|
@ -211,7 +208,7 @@ bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *inJoint)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *inJoint)
|
||||
bool CB3DMeshFileLoader::readChunkMESH(SkinnedMesh::SJoint *inJoint)
|
||||
{
|
||||
#ifdef _B3D_READER_DEBUG
|
||||
core::stringc logStr;
|
||||
|
@ -254,7 +251,7 @@ bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *inJoint)
|
|||
meshBuffer->Material = Materials[brushID].Material;
|
||||
}
|
||||
|
||||
if (readChunkTRIS(meshBuffer, AnimatedMesh->getMeshBuffers().size() - 1, VerticesStart) == false)
|
||||
if (readChunkTRIS(meshBuffer, AnimatedMesh->getMeshBufferCount() - 1, VerticesStart) == false)
|
||||
return false;
|
||||
|
||||
if (!NormalsInFile) {
|
||||
|
@ -302,7 +299,7 @@ VRTS:
|
|||
float tex_coords[tex_coord_sets][tex_coord_set_size] ;tex coords
|
||||
}
|
||||
*/
|
||||
bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *inJoint)
|
||||
bool CB3DMeshFileLoader::readChunkVRTS(SkinnedMesh::SJoint *inJoint)
|
||||
{
|
||||
#ifdef _B3D_READER_DEBUG
|
||||
core::stringc logStr;
|
||||
|
@ -521,7 +518,7 @@ bool CB3DMeshFileLoader::readChunkTRIS(scene::SSkinMeshBuffer *meshBuffer, u32 m
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *inJoint)
|
||||
bool CB3DMeshFileLoader::readChunkBONE(SkinnedMesh::SJoint *inJoint)
|
||||
{
|
||||
#ifdef _B3D_READER_DEBUG
|
||||
core::stringc logStr;
|
||||
|
@ -552,7 +549,7 @@ bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *inJoint)
|
|||
if (AnimatedVertices_VertexID[globalVertexID] == -1) {
|
||||
os::Printer::log("B3dMeshLoader: Weight has bad vertex id (no link to meshbuffer index found)");
|
||||
} else if (strength > 0) {
|
||||
CSkinnedMesh::SWeight *weight = AnimatedMesh->addWeight(inJoint);
|
||||
SkinnedMesh::SWeight *weight = AnimatedMesh->addWeight(inJoint);
|
||||
weight->strength = strength;
|
||||
// Find the meshbuffer and Vertex index from the Global Vertex ID:
|
||||
weight->vertex_id = AnimatedVertices_VertexID[globalVertexID];
|
||||
|
@ -565,11 +562,11 @@ bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *inJoint)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *inJoint)
|
||||
bool CB3DMeshFileLoader::readChunkKEYS(SkinnedMesh::SJoint *inJoint)
|
||||
{
|
||||
#ifdef _B3D_READER_DEBUG
|
||||
// Only print first, that's just too much output otherwise
|
||||
if (!inJoint || (inJoint->PositionKeys.empty() && inJoint->ScaleKeys.empty() && inJoint->RotationKeys.empty())) {
|
||||
if (!inJoint || inJoint->keys.empty()) {
|
||||
core::stringc logStr;
|
||||
for (u32 i = 1; i < B3dStack.size(); ++i)
|
||||
logStr += "-";
|
||||
|
@ -584,13 +581,6 @@ bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *inJoint)
|
|||
flags = os::Byteswap::byteswap(flags);
|
||||
#endif
|
||||
|
||||
CSkinnedMesh::SPositionKey *oldPosKey = 0;
|
||||
core::vector3df oldPos[2];
|
||||
CSkinnedMesh::SScaleKey *oldScaleKey = 0;
|
||||
core::vector3df oldScale[2];
|
||||
CSkinnedMesh::SRotationKey *oldRotKey = 0;
|
||||
core::quaternion oldRot[2];
|
||||
bool isFirst[3] = {true, true, true};
|
||||
while ((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats
|
||||
{
|
||||
s32 frame;
|
||||
|
@ -600,91 +590,24 @@ bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *inJoint)
|
|||
frame = os::Byteswap::byteswap(frame);
|
||||
#endif
|
||||
|
||||
if (frame < 1) {
|
||||
os::Printer::log("Illegal frame number found", B3DFile->getFileName(), ELL_ERROR);
|
||||
frame = 1;
|
||||
}
|
||||
|
||||
// Add key frames, frames in Irrlicht are zero-based
|
||||
f32 data[4];
|
||||
if (flags & 1) {
|
||||
readFloats(data, 3);
|
||||
if ((oldPosKey != 0) && (oldPos[0] == oldPos[1])) {
|
||||
const core::vector3df pos(data[0], data[1], data[2]);
|
||||
if (oldPos[1] == pos)
|
||||
oldPosKey->frame = (f32)frame - 1;
|
||||
else {
|
||||
oldPos[0] = oldPos[1];
|
||||
oldPosKey = AnimatedMesh->addPositionKey(inJoint);
|
||||
oldPosKey->frame = (f32)frame - 1;
|
||||
oldPos[1].set(oldPosKey->position.set(pos));
|
||||
}
|
||||
} else if (oldPosKey == 0 && isFirst[0]) {
|
||||
oldPosKey = AnimatedMesh->addPositionKey(inJoint);
|
||||
oldPosKey->frame = (f32)frame - 1;
|
||||
oldPos[0].set(oldPosKey->position.set(data[0], data[1], data[2]));
|
||||
oldPosKey = 0;
|
||||
isFirst[0] = false;
|
||||
} else {
|
||||
if (oldPosKey != 0)
|
||||
oldPos[0] = oldPos[1];
|
||||
oldPosKey = AnimatedMesh->addPositionKey(inJoint);
|
||||
oldPosKey->frame = (f32)frame - 1;
|
||||
oldPos[1].set(oldPosKey->position.set(data[0], data[1], data[2]));
|
||||
}
|
||||
AnimatedMesh->addPositionKey(inJoint, frame - 1, {data[0], data[1], data[2]});
|
||||
}
|
||||
if (flags & 2) {
|
||||
readFloats(data, 3);
|
||||
if ((oldScaleKey != 0) && (oldScale[0] == oldScale[1])) {
|
||||
const core::vector3df scale(data[0], data[1], data[2]);
|
||||
if (oldScale[1] == scale)
|
||||
oldScaleKey->frame = (f32)frame - 1;
|
||||
else {
|
||||
oldScale[0] = oldScale[1];
|
||||
oldScaleKey = AnimatedMesh->addScaleKey(inJoint);
|
||||
oldScaleKey->frame = (f32)frame - 1;
|
||||
oldScale[1].set(oldScaleKey->scale.set(scale));
|
||||
}
|
||||
} else if (oldScaleKey == 0 && isFirst[1]) {
|
||||
oldScaleKey = AnimatedMesh->addScaleKey(inJoint);
|
||||
oldScaleKey->frame = (f32)frame - 1;
|
||||
oldScale[0].set(oldScaleKey->scale.set(data[0], data[1], data[2]));
|
||||
oldScaleKey = 0;
|
||||
isFirst[1] = false;
|
||||
} else {
|
||||
if (oldScaleKey != 0)
|
||||
oldScale[0] = oldScale[1];
|
||||
oldScaleKey = AnimatedMesh->addScaleKey(inJoint);
|
||||
oldScaleKey->frame = (f32)frame - 1;
|
||||
oldScale[1].set(oldScaleKey->scale.set(data[0], data[1], data[2]));
|
||||
}
|
||||
AnimatedMesh->addScaleKey(inJoint, frame - 1, {data[0], data[1], data[2]});
|
||||
}
|
||||
if (flags & 4) {
|
||||
readFloats(data, 4);
|
||||
if ((oldRotKey != 0) && (oldRot[0] == oldRot[1])) {
|
||||
// meant to be in this order since b3d stores W first
|
||||
const core::quaternion rot(data[1], data[2], data[3], data[0]);
|
||||
if (oldRot[1] == rot)
|
||||
oldRotKey->frame = (f32)frame - 1;
|
||||
else {
|
||||
oldRot[0] = oldRot[1];
|
||||
oldRotKey = AnimatedMesh->addRotationKey(inJoint);
|
||||
oldRotKey->frame = (f32)frame - 1;
|
||||
oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0]));
|
||||
oldRot[1].normalize();
|
||||
}
|
||||
} else if (oldRotKey == 0 && isFirst[2]) {
|
||||
oldRotKey = AnimatedMesh->addRotationKey(inJoint);
|
||||
oldRotKey->frame = (f32)frame - 1;
|
||||
// meant to be in this order since b3d stores W first
|
||||
oldRot[0].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0]));
|
||||
oldRot[0].normalize();
|
||||
oldRotKey = 0;
|
||||
isFirst[2] = false;
|
||||
} else {
|
||||
if (oldRotKey != 0)
|
||||
oldRot[0] = oldRot[1];
|
||||
oldRotKey = AnimatedMesh->addRotationKey(inJoint);
|
||||
oldRotKey->frame = (f32)frame - 1;
|
||||
// meant to be in this order since b3d stores W first
|
||||
oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0]));
|
||||
oldRot[1].normalize();
|
||||
}
|
||||
AnimatedMesh->addRotationKey(inJoint, frame - 1, core::quaternion(data[1], data[2], data[3], data[0]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include "IMeshLoader.h"
|
||||
#include "ISceneManager.h"
|
||||
#include "CSkinnedMesh.h"
|
||||
#include "SkinnedMesh.h"
|
||||
#include "SB3DStructs.h"
|
||||
#include "IReadFile.h"
|
||||
|
||||
|
@ -39,12 +39,12 @@ public:
|
|||
|
||||
private:
|
||||
bool load();
|
||||
bool readChunkNODE(CSkinnedMesh::SJoint *InJoint);
|
||||
bool readChunkMESH(CSkinnedMesh::SJoint *InJoint);
|
||||
bool readChunkVRTS(CSkinnedMesh::SJoint *InJoint);
|
||||
bool readChunkNODE(SkinnedMesh::SJoint *InJoint);
|
||||
bool readChunkMESH(SkinnedMesh::SJoint *InJoint);
|
||||
bool readChunkVRTS(SkinnedMesh::SJoint *InJoint);
|
||||
bool readChunkTRIS(scene::SSkinMeshBuffer *MeshBuffer, u32 MeshBufferID, s32 Vertices_Start);
|
||||
bool readChunkBONE(CSkinnedMesh::SJoint *InJoint);
|
||||
bool readChunkKEYS(CSkinnedMesh::SJoint *InJoint);
|
||||
bool readChunkBONE(SkinnedMesh::SJoint *InJoint);
|
||||
bool readChunkKEYS(SkinnedMesh::SJoint *InJoint);
|
||||
bool readChunkANIM();
|
||||
bool readChunkTEXS();
|
||||
bool readChunkBRUS();
|
||||
|
@ -63,7 +63,7 @@ private:
|
|||
|
||||
core::array<video::S3DVertex2TCoords> BaseVertices;
|
||||
|
||||
CSkinnedMesh *AnimatedMesh;
|
||||
SkinnedMeshBuilder *AnimatedMesh;
|
||||
io::IReadFile *B3DFile;
|
||||
|
||||
// B3Ds have Vertex ID's local within the mesh I don't want this
|
||||
|
|
|
@ -20,10 +20,6 @@ CBillboardSceneNode::CBillboardSceneNode(ISceneNode *parent, ISceneManager *mgr,
|
|||
IBillboardSceneNode(parent, mgr, id, position),
|
||||
Buffer(new SMeshBuffer())
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CBillboardSceneNode");
|
||||
#endif
|
||||
|
||||
setSize(size);
|
||||
|
||||
auto &Vertices = Buffer->Vertices->Data;
|
||||
|
|
|
@ -18,9 +18,6 @@ CBoneSceneNode::CBoneSceneNode(ISceneNode *parent, ISceneManager *mgr, s32 id,
|
|||
BoneIndex(boneIndex),
|
||||
AnimationMode(EBAM_AUTOMATIC), SkinningSpace(EBSS_LOCAL)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CBoneSceneNode");
|
||||
#endif
|
||||
setName(boneName);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,10 +20,6 @@ CCameraSceneNode::CCameraSceneNode(ISceneNode *parent, ISceneManager *mgr, s32 i
|
|||
Target(lookat), UpVector(0.0f, 1.0f, 0.0f), ZNear(1.0f), ZFar(3000.0f),
|
||||
InputReceiverEnabled(true), TargetAndRotationAreBound(false)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CCameraSceneNode");
|
||||
#endif
|
||||
|
||||
// set default projection
|
||||
Fovy = core::PI / 2.5f; // Field of view, in radians.
|
||||
Aspect = 4.0f / 3.0f; // Aspect ratio.
|
||||
|
|
|
@ -7,6 +7,15 @@
|
|||
#include "os.h"
|
||||
#include "irrString.h"
|
||||
|
||||
// Warning: The naming of Irrlicht color formats
|
||||
// is not consistent regarding actual component order in memory.
|
||||
// E.g. in CImage, ECF_R8G8B8 is handled per-byte and stored as [R][G][B] in memory
|
||||
// while ECF_A8R8G8B8 is handled as an u32 0xAARRGGBB so [B][G][R][A] (little endian) in memory.
|
||||
// The conversions suffer from the same inconsistencies, e.g.
|
||||
// convert_R8G8B8toA8R8G8B8 converts [R][G][B] into 0xFFRRGGBB = [B][G][R][FF] (little endian);
|
||||
// convert_A1R5G5B5toR8G8B8 converts 0bARRRRRGGGGGBBBBB into [R][G][B].
|
||||
// This also means many conversions may be broken on big endian.
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
|
@ -393,19 +402,6 @@ void CColorConverter::convert_R8G8B8toA1R5G5B5(const void *sP, s32 sN, void *dP)
|
|||
}
|
||||
}
|
||||
|
||||
void CColorConverter::convert_B8G8R8toA8R8G8B8(const void *sP, s32 sN, void *dP)
|
||||
{
|
||||
u8 *sB = (u8 *)sP;
|
||||
u32 *dB = (u32 *)dP;
|
||||
|
||||
for (s32 x = 0; x < sN; ++x) {
|
||||
*dB = 0xff000000 | (sB[2] << 16) | (sB[1] << 8) | sB[0];
|
||||
|
||||
sB += 3;
|
||||
++dB;
|
||||
}
|
||||
}
|
||||
|
||||
void CColorConverter::convert_A8R8G8B8toR8G8B8A8(const void *sP, s32 sN, void *dP)
|
||||
{
|
||||
const u32 *sB = (const u32 *)sP;
|
||||
|
@ -428,22 +424,6 @@ void CColorConverter::convert_A8R8G8B8toA8B8G8R8(const void *sP, s32 sN, void *d
|
|||
}
|
||||
}
|
||||
|
||||
void CColorConverter::convert_B8G8R8A8toA8R8G8B8(const void *sP, s32 sN, void *dP)
|
||||
{
|
||||
u8 *sB = (u8 *)sP;
|
||||
u8 *dB = (u8 *)dP;
|
||||
|
||||
for (s32 x = 0; x < sN; ++x) {
|
||||
dB[0] = sB[3];
|
||||
dB[1] = sB[2];
|
||||
dB[2] = sB[1];
|
||||
dB[3] = sB[0];
|
||||
|
||||
sB += 4;
|
||||
dB += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void CColorConverter::convert_R8G8B8toB8G8R8(const void *sP, s32 sN, void *dP)
|
||||
{
|
||||
u8 *sB = (u8 *)sP;
|
||||
|
|
|
@ -66,8 +66,6 @@ public:
|
|||
static void convert_R8G8B8toA1R5G5B5(const void *sP, s32 sN, void *dP);
|
||||
static void convert_R8G8B8toB8G8R8(const void *sP, s32 sN, void *dP);
|
||||
static void convert_R8G8B8toR5G6B5(const void *sP, s32 sN, void *dP);
|
||||
static void convert_B8G8R8toA8R8G8B8(const void *sP, s32 sN, void *dP);
|
||||
static void convert_B8G8R8A8toA8R8G8B8(const void *sP, s32 sN, void *dP);
|
||||
static void convert_A8R8G8B8toR8G8B8A8(const void *sP, s32 sN, void *dP);
|
||||
static void convert_A8R8G8B8toA8B8G8R8(const void *sP, s32 sN, void *dP);
|
||||
|
||||
|
|
|
@ -15,10 +15,6 @@ CDummyTransformationSceneNode::CDummyTransformationSceneNode(
|
|||
ISceneNode *parent, ISceneManager *mgr, s32 id) :
|
||||
IDummyTransformationSceneNode(parent, mgr, id)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CDummyTransformationSceneNode");
|
||||
#endif
|
||||
|
||||
setAutomaticCulling(scene::EAC_OFF);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,7 @@ namespace video
|
|||
CEGLManager::CEGLManager() :
|
||||
IContextManager(), EglWindow(0), EglDisplay(EGL_NO_DISPLAY),
|
||||
EglSurface(EGL_NO_SURFACE), EglContext(EGL_NO_CONTEXT), EglConfig(0), MajorVersion(0), MinorVersion(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CEGLManager");
|
||||
#endif
|
||||
}
|
||||
{}
|
||||
|
||||
CEGLManager::~CEGLManager()
|
||||
{
|
||||
|
|
|
@ -14,10 +14,6 @@ namespace scene
|
|||
CEmptySceneNode::CEmptySceneNode(ISceneNode *parent, ISceneManager *mgr, s32 id) :
|
||||
ISceneNode(parent, mgr, id)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CEmptySceneNode");
|
||||
#endif
|
||||
|
||||
setAutomaticCulling(scene::EAC_OFF);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,10 +18,6 @@ static const io::path emptyFileListEntry;
|
|||
CFileList::CFileList(const io::path &path, bool ignoreCase, bool ignorePaths) :
|
||||
IgnorePaths(ignorePaths), IgnoreCase(ignoreCase), Path(path)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CFileList");
|
||||
#endif
|
||||
|
||||
Path.replace('\\', '/');
|
||||
}
|
||||
|
||||
|
|
|
@ -43,10 +43,6 @@ namespace io
|
|||
//! constructor
|
||||
CFileSystem::CFileSystem()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CFileSystem");
|
||||
#endif
|
||||
|
||||
setFileListSystem(FILESYSTEM_NATIVE);
|
||||
//! reset current working directory
|
||||
getWorkingDirectory();
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "SMaterialLayer.h"
|
||||
#include "coreutil.h"
|
||||
#include "CSkinnedMesh.h"
|
||||
#include "SkinnedMesh.h"
|
||||
#include "IAnimatedMesh.h"
|
||||
#include "IReadFile.h"
|
||||
#include "irrTypes.h"
|
||||
|
@ -305,7 +305,7 @@ SelfType::createNormalizedValuesAccessor(
|
|||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
template <std::size_t N, bool validate>
|
||||
std::array<f32, N> SelfType::getNormalizedValues(
|
||||
const NormalizedValuesAccessor<N> &accessor,
|
||||
const std::size_t i)
|
||||
|
@ -313,19 +313,21 @@ std::array<f32, N> SelfType::getNormalizedValues(
|
|||
std::array<f32, N> values;
|
||||
if (std::holds_alternative<Accessor<std::array<u8, N>>>(accessor)) {
|
||||
const auto u8s = std::get<Accessor<std::array<u8, N>>>(accessor).get(i);
|
||||
for (u8 i = 0; i < N; ++i)
|
||||
values[i] = static_cast<f32>(u8s[i]) / std::numeric_limits<u8>::max();
|
||||
for (std::size_t j = 0; j < N; ++j)
|
||||
values[j] = static_cast<f32>(u8s[j]) / std::numeric_limits<u8>::max();
|
||||
} else if (std::holds_alternative<Accessor<std::array<u16, N>>>(accessor)) {
|
||||
const auto u16s = std::get<Accessor<std::array<u16, N>>>(accessor).get(i);
|
||||
for (u8 i = 0; i < N; ++i)
|
||||
values[i] = static_cast<f32>(u16s[i]) / std::numeric_limits<u16>::max();
|
||||
for (std::size_t j = 0; j < N; ++j)
|
||||
values[j] = static_cast<f32>(u16s[j]) / std::numeric_limits<u16>::max();
|
||||
} else {
|
||||
values = std::get<Accessor<std::array<f32, N>>>(accessor).get(i);
|
||||
for (u8 i = 0; i < N; ++i) {
|
||||
if (values[i] < 0 || values[i] > 1)
|
||||
if constexpr (validate) {
|
||||
for (std::size_t j = 0; j < N; ++j) {
|
||||
if (values[j] < 0 || values[j] > 1)
|
||||
throw std::runtime_error("invalid normalized value");
|
||||
}
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
|
@ -344,14 +346,14 @@ IAnimatedMesh* SelfType::createMesh(io::IReadFile* file)
|
|||
const char *filename = file->getFileName().c_str();
|
||||
try {
|
||||
tiniergltf::GlTF model = parseGLTF(file);
|
||||
irr_ptr<CSkinnedMesh> mesh(new CSkinnedMesh());
|
||||
irr_ptr<SkinnedMeshBuilder> mesh(new SkinnedMeshBuilder());
|
||||
MeshExtractor extractor(std::move(model), mesh.get());
|
||||
try {
|
||||
extractor.load();
|
||||
for (const auto &warning : extractor.getWarnings()) {
|
||||
os::Printer::log(filename, warning.c_str(), ELL_WARNING);
|
||||
}
|
||||
return mesh.release();
|
||||
return mesh.release()->finalize();
|
||||
} catch (const std::runtime_error &e) {
|
||||
os::Printer::log("error converting gltf to irrlicht mesh", e.what(), ELL_ERROR);
|
||||
}
|
||||
|
@ -410,7 +412,7 @@ static video::E_TEXTURE_CLAMP convertTextureWrap(const Wrap wrap) {
|
|||
void SelfType::MeshExtractor::addPrimitive(
|
||||
const tiniergltf::MeshPrimitive &primitive,
|
||||
const std::optional<std::size_t> skinIdx,
|
||||
CSkinnedMesh::SJoint *parent)
|
||||
SkinnedMesh::SJoint *parent)
|
||||
{
|
||||
auto vertices = getVertices(primitive);
|
||||
if (!vertices.has_value())
|
||||
|
@ -493,6 +495,7 @@ void SelfType::MeshExtractor::addPrimitive(
|
|||
|
||||
const auto weightAccessor = createNormalizedValuesAccessor<4>(m_gltf_model, weights->at(set));
|
||||
|
||||
bool negative_weights = false;
|
||||
for (std::size_t v = 0; v < n_vertices; ++v) {
|
||||
std::array<u16, 4> jointIdxs;
|
||||
if (std::holds_alternative<Accessor<std::array<u8, 4>>>(jointAccessor)) {
|
||||
|
@ -501,21 +504,27 @@ void SelfType::MeshExtractor::addPrimitive(
|
|||
} else if (std::holds_alternative<Accessor<std::array<u16, 4>>>(jointAccessor)) {
|
||||
jointIdxs = std::get<Accessor<std::array<u16, 4>>>(jointAccessor).get(v);
|
||||
}
|
||||
std::array<f32, 4> strengths = getNormalizedValues(weightAccessor, v);
|
||||
|
||||
// Be lax: We can allow weights that aren't normalized. Irrlicht already normalizes them.
|
||||
// The glTF spec only requires that these be "as close to 1 as reasonably possible".
|
||||
auto strengths = getNormalizedValues<4, false>(weightAccessor, v);
|
||||
|
||||
// 4 joints per set
|
||||
for (std::size_t in_set = 0; in_set < 4; ++in_set) {
|
||||
u16 jointIdx = jointIdxs[in_set];
|
||||
f32 strength = strengths[in_set];
|
||||
if (strength == 0)
|
||||
continue;
|
||||
negative_weights = negative_weights || (strength < 0);
|
||||
if (strength <= 0)
|
||||
continue; // note: also ignores negative weights
|
||||
|
||||
CSkinnedMesh::SWeight *weight = m_irr_model->addWeight(m_loaded_nodes.at(skin.joints.at(jointIdx)));
|
||||
SkinnedMesh::SWeight *weight = m_irr_model->addWeight(m_loaded_nodes.at(skin.joints.at(jointIdx)));
|
||||
weight->buffer_id = meshbufNr;
|
||||
weight->vertex_id = v;
|
||||
weight->strength = strength;
|
||||
}
|
||||
}
|
||||
if (negative_weights)
|
||||
warn("negative weights");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -527,7 +536,7 @@ void SelfType::MeshExtractor::addPrimitive(
|
|||
void SelfType::MeshExtractor::deferAddMesh(
|
||||
const std::size_t meshIdx,
|
||||
const std::optional<std::size_t> skinIdx,
|
||||
CSkinnedMesh::SJoint *parent)
|
||||
SkinnedMesh::SJoint *parent)
|
||||
{
|
||||
m_mesh_loaders.emplace_back([=] {
|
||||
for (std::size_t pi = 0; pi < getPrimitiveCount(meshIdx); ++pi) {
|
||||
|
@ -547,7 +556,7 @@ static const core::matrix4 leftToRight = core::matrix4(
|
|||
);
|
||||
static const core::matrix4 rightToLeft = leftToRight;
|
||||
|
||||
static core::matrix4 loadTransform(const tiniergltf::Node::Matrix &m, CSkinnedMesh::SJoint *joint)
|
||||
static core::matrix4 loadTransform(const tiniergltf::Node::Matrix &m, SkinnedMesh::SJoint *joint)
|
||||
{
|
||||
// Note: Under the hood, this casts these doubles to floats.
|
||||
core::matrix4 mat = convertHandedness(core::matrix4(
|
||||
|
@ -576,7 +585,7 @@ static core::matrix4 loadTransform(const tiniergltf::Node::Matrix &m, CSkinnedMe
|
|||
return mat;
|
||||
}
|
||||
|
||||
static core::matrix4 loadTransform(const tiniergltf::Node::TRS &trs, CSkinnedMesh::SJoint *joint)
|
||||
static core::matrix4 loadTransform(const tiniergltf::Node::TRS &trs, SkinnedMesh::SJoint *joint)
|
||||
{
|
||||
const auto &trans = trs.translation;
|
||||
const auto &rot = trs.rotation;
|
||||
|
@ -594,7 +603,7 @@ static core::matrix4 loadTransform(const tiniergltf::Node::TRS &trs, CSkinnedMes
|
|||
}
|
||||
|
||||
static core::matrix4 loadTransform(std::optional<std::variant<tiniergltf::Node::Matrix, tiniergltf::Node::TRS>> transform,
|
||||
CSkinnedMesh::SJoint *joint) {
|
||||
SkinnedMesh::SJoint *joint) {
|
||||
if (!transform.has_value()) {
|
||||
return core::matrix4();
|
||||
}
|
||||
|
@ -603,7 +612,7 @@ static core::matrix4 loadTransform(std::optional<std::variant<tiniergltf::Node::
|
|||
|
||||
void SelfType::MeshExtractor::loadNode(
|
||||
const std::size_t nodeIdx,
|
||||
CSkinnedMesh::SJoint *parent)
|
||||
SkinnedMesh::SJoint *parent)
|
||||
{
|
||||
const auto &node = m_gltf_model.nodes->at(nodeIdx);
|
||||
auto *joint = m_irr_model->addJoint(parent);
|
||||
|
@ -626,7 +635,7 @@ void SelfType::MeshExtractor::loadNode(
|
|||
|
||||
void SelfType::MeshExtractor::loadNodes()
|
||||
{
|
||||
m_loaded_nodes = std::vector<CSkinnedMesh::SJoint *>(m_gltf_model.nodes->size());
|
||||
m_loaded_nodes = std::vector<SkinnedMesh::SJoint *>(m_gltf_model.nodes->size());
|
||||
|
||||
std::vector<bool> isChild(m_gltf_model.nodes->size());
|
||||
for (const auto &node : *m_gltf_model.nodes) {
|
||||
|
@ -682,27 +691,27 @@ void SelfType::MeshExtractor::loadAnimation(const std::size_t animIdx)
|
|||
case tiniergltf::AnimationChannelTarget::Path::TRANSLATION: {
|
||||
const auto outputAccessor = Accessor<core::vector3df>::make(m_gltf_model, sampler.output);
|
||||
for (std::size_t i = 0; i < n_frames; ++i) {
|
||||
auto *key = m_irr_model->addPositionKey(joint);
|
||||
key->frame = inputAccessor.get(i);
|
||||
key->position = convertHandedness(outputAccessor.get(i));
|
||||
f32 frame = inputAccessor.get(i);
|
||||
core::vector3df position = outputAccessor.get(i);
|
||||
m_irr_model->addPositionKey(joint, frame, convertHandedness(position));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tiniergltf::AnimationChannelTarget::Path::ROTATION: {
|
||||
const auto outputAccessor = Accessor<core::quaternion>::make(m_gltf_model, sampler.output);
|
||||
for (std::size_t i = 0; i < n_frames; ++i) {
|
||||
auto *key = m_irr_model->addRotationKey(joint);
|
||||
key->frame = inputAccessor.get(i);
|
||||
key->rotation = convertHandedness(outputAccessor.get(i));
|
||||
f32 frame = inputAccessor.get(i);
|
||||
core::quaternion rotation = outputAccessor.get(i);
|
||||
m_irr_model->addRotationKey(joint, frame, convertHandedness(rotation));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tiniergltf::AnimationChannelTarget::Path::SCALE: {
|
||||
const auto outputAccessor = Accessor<core::vector3df>::make(m_gltf_model, sampler.output);
|
||||
for (std::size_t i = 0; i < n_frames; ++i) {
|
||||
auto *key = m_irr_model->addScaleKey(joint);
|
||||
key->frame = inputAccessor.get(i);
|
||||
key->scale = outputAccessor.get(i);
|
||||
f32 frame = inputAccessor.get(i);
|
||||
core::vector3df scale = outputAccessor.get(i);
|
||||
m_irr_model->addScaleKey(joint, frame, scale);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -747,8 +756,6 @@ void SelfType::MeshExtractor::load()
|
|||
} catch (const std::bad_optional_access &e) {
|
||||
throw std::runtime_error(e.what());
|
||||
}
|
||||
|
||||
m_irr_model->finalize();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -791,7 +798,8 @@ std::optional<std::vector<u16>> SelfType::MeshExtractor::getIndices(
|
|||
index = std::get<Accessor<u16>>(accessor).get(elemIdx);
|
||||
if (index == std::numeric_limits<u16>::max())
|
||||
throw std::runtime_error("invalid index");
|
||||
} else if (std::holds_alternative<Accessor<u32>>(accessor)) {
|
||||
} else {
|
||||
_IRR_DEBUG_BREAK_IF(!std::holds_alternative<Accessor<u32>>(accessor));
|
||||
u32 indexWide = std::get<Accessor<u32>>(accessor).get(elemIdx);
|
||||
// Use >= here for consistency.
|
||||
if (indexWide >= std::numeric_limits<u16>::max())
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "CSkinnedMesh.h"
|
||||
#include "SkinnedMesh.h"
|
||||
#include "IMeshLoader.h"
|
||||
#include "IReadFile.h"
|
||||
#include "irrTypes.h"
|
||||
|
@ -91,7 +91,7 @@ private:
|
|||
const tiniergltf::GlTF &model,
|
||||
const std::size_t accessorIdx);
|
||||
|
||||
template <std::size_t N>
|
||||
template <std::size_t N, bool validate = true>
|
||||
static std::array<f32, N> getNormalizedValues(
|
||||
const NormalizedValuesAccessor<N> &accessor,
|
||||
const std::size_t i);
|
||||
|
@ -100,7 +100,7 @@ private:
|
|||
{
|
||||
public:
|
||||
MeshExtractor(tiniergltf::GlTF &&model,
|
||||
CSkinnedMesh *mesh) noexcept
|
||||
SkinnedMeshBuilder *mesh) noexcept
|
||||
: m_gltf_model(std::move(model)), m_irr_model(mesh) {};
|
||||
|
||||
/* Gets indices for the given mesh/primitive.
|
||||
|
@ -118,20 +118,20 @@ private:
|
|||
std::size_t getPrimitiveCount(const std::size_t meshIdx) const;
|
||||
|
||||
void load();
|
||||
const std::vector<std::string> &getWarnings() {
|
||||
const std::unordered_set<std::string> &getWarnings() {
|
||||
return warnings;
|
||||
}
|
||||
|
||||
private:
|
||||
const tiniergltf::GlTF m_gltf_model;
|
||||
CSkinnedMesh *m_irr_model;
|
||||
SkinnedMeshBuilder *m_irr_model;
|
||||
|
||||
std::vector<std::function<void()>> m_mesh_loaders;
|
||||
std::vector<CSkinnedMesh::SJoint *> m_loaded_nodes;
|
||||
std::vector<SkinnedMesh::SJoint *> m_loaded_nodes;
|
||||
|
||||
std::vector<std::string> warnings;
|
||||
std::unordered_set<std::string> warnings;
|
||||
void warn(const std::string &warning) {
|
||||
warnings.push_back(warning);
|
||||
warnings.insert(warning);
|
||||
}
|
||||
|
||||
void copyPositions(const std::size_t accessorIdx,
|
||||
|
@ -145,13 +145,13 @@ private:
|
|||
|
||||
void addPrimitive(const tiniergltf::MeshPrimitive &primitive,
|
||||
const std::optional<std::size_t> skinIdx,
|
||||
CSkinnedMesh::SJoint *parent);
|
||||
SkinnedMesh::SJoint *parent);
|
||||
|
||||
void deferAddMesh(const std::size_t meshIdx,
|
||||
const std::optional<std::size_t> skinIdx,
|
||||
CSkinnedMesh::SJoint *parentJoint);
|
||||
SkinnedMesh::SJoint *parentJoint);
|
||||
|
||||
void loadNode(const std::size_t nodeIdx, CSkinnedMesh::SJoint *parentJoint);
|
||||
void loadNode(const std::size_t nodeIdx, SkinnedMesh::SJoint *parentJoint);
|
||||
|
||||
void loadNodes();
|
||||
|
||||
|
|
|
@ -23,10 +23,6 @@ namespace video
|
|||
CGLXManager::CGLXManager(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &videodata, int screennr) :
|
||||
Params(params), PrimaryContext(videodata), VisualInfo(0), glxFBConfig(0), GlxWin(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGLXManager");
|
||||
#endif
|
||||
|
||||
CurrentContext.OpenGLLinux.X11Display = PrimaryContext.OpenGLLinux.X11Display;
|
||||
|
||||
int major, minor;
|
||||
|
|
|
@ -26,9 +26,6 @@ CGUIButton::CGUIButton(IGUIEnvironment *environment, IGUIElement *parent,
|
|||
IsPushButton(false), Pressed(false),
|
||||
UseAlphaChannel(false), DrawBorder(true), ScaleImage(false)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUIButton");
|
||||
#endif
|
||||
setNotClipped(noclip);
|
||||
|
||||
// This element can be tabbed.
|
||||
|
|
|
@ -19,10 +19,6 @@ namespace gui
|
|||
CGUICheckBox::CGUICheckBox(bool checked, IGUIEnvironment *environment, IGUIElement *parent, s32 id, core::rect<s32> rectangle) :
|
||||
IGUICheckBox(environment, parent, id, rectangle), CheckTime(0), Pressed(false), Checked(checked), Border(false), Background(false)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUICheckBox");
|
||||
#endif
|
||||
|
||||
// this element can be tabbed into
|
||||
setTabStop(true);
|
||||
setTabOrder(-1);
|
||||
|
|
|
@ -26,10 +26,6 @@ CGUIComboBox::CGUIComboBox(IGUIEnvironment *environment, IGUIElement *parent,
|
|||
Selected(-1), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), MaxSelectionRows(5), HasFocus(false),
|
||||
ActiveFont(nullptr)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUIComboBox");
|
||||
#endif
|
||||
|
||||
IGUISkin *skin = Environment->getSkin();
|
||||
|
||||
ListButton = Environment->addButton(core::recti(0, 0, 1, 1), this, -1, L"");
|
||||
|
|
|
@ -39,10 +39,6 @@ CGUIEditBox::CGUIEditBox(const wchar_t *text, bool border,
|
|||
PasswordChar(L'*'), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER),
|
||||
CurrentTextRect(0, 0, 1, 1), FrameRect(rectangle)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUIEditBox");
|
||||
#endif
|
||||
|
||||
Text = text;
|
||||
|
||||
if (Environment)
|
||||
|
|
|
@ -50,10 +50,6 @@ CGUIEnvironment::CGUIEnvironment(io::IFileSystem *fs, video::IVideoDriver *drive
|
|||
if (Operator)
|
||||
Operator->grab();
|
||||
|
||||
#ifdef _DEBUG
|
||||
IGUIEnvironment::setDebugName("CGUIEnvironment");
|
||||
#endif
|
||||
|
||||
loadBuiltInFont();
|
||||
|
||||
IGUISkin *skin = createSkin(gui::EGST_WINDOWS_METALLIC);
|
||||
|
|
|
@ -33,10 +33,6 @@ CGUIFileOpenDialog::CGUIFileOpenDialog(const wchar_t *title,
|
|||
(parent->getAbsolutePosition().getHeight() - FOD_HEIGHT) / 2 + FOD_HEIGHT)),
|
||||
FileNameText(0), FileList(0), Dragging(false)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
IGUIElement::setDebugName("CGUIFileOpenDialog");
|
||||
#endif
|
||||
|
||||
Text = title;
|
||||
|
||||
FileSystem = Environment ? Environment->getFileSystem() : 0;
|
||||
|
|
|
@ -21,10 +21,6 @@ CGUIFont::CGUIFont(IGUIEnvironment *env, const io::path &filename) :
|
|||
Driver(0), SpriteBank(0), Environment(env), WrongCharacter(0),
|
||||
MaxHeight(0), GlobalKerningWidth(0), GlobalKerningHeight(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUIFont");
|
||||
#endif
|
||||
|
||||
if (Environment) {
|
||||
// don't grab environment, to avoid circular references
|
||||
Driver = Environment->getVideoDriver();
|
||||
|
|
|
@ -17,11 +17,7 @@ namespace gui
|
|||
CGUIImage::CGUIImage(IGUIEnvironment *environment, IGUIElement *parent, s32 id, core::rect<s32> rectangle) :
|
||||
IGUIImage(environment, parent, id, rectangle), Texture(0), Color(255, 255, 255, 255),
|
||||
UseAlphaChannel(false), ScaleImage(false), DrawBounds(0.f, 0.f, 1.f, 1.f), DrawBackground(true)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUIImage");
|
||||
#endif
|
||||
}
|
||||
{}
|
||||
|
||||
//! destructor
|
||||
CGUIImage::~CGUIImage()
|
||||
|
|
|
@ -18,10 +18,6 @@ CGUIImageList::CGUIImageList(video::IVideoDriver *driver) :
|
|||
ImagesPerRow(0),
|
||||
UseAlphaChannel(false)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUIImageList");
|
||||
#endif
|
||||
|
||||
if (Driver) {
|
||||
Driver->grab();
|
||||
}
|
||||
|
|
|
@ -29,10 +29,6 @@ CGUIListBox::CGUIListBox(IGUIEnvironment *environment, IGUIElement *parent,
|
|||
ScrollBar(0), selectTime(0), LastKeyTime(0), Selecting(false), DrawBack(drawBack),
|
||||
MoveOverSelect(moveOverSelect), AutoScroll(true), HighlightWhenNotFocused(true)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUIListBox");
|
||||
#endif
|
||||
|
||||
IGUISkin *skin = Environment->getSkin();
|
||||
|
||||
ScrollBar = new CGUIScrollBar(false, Environment, this, -1,
|
||||
|
|
|
@ -28,10 +28,6 @@ CGUIScrollBar::CGUIScrollBar(bool horizontal, IGUIEnvironment *environment,
|
|||
DrawHeight(0), Min(0), Max(100), SmallStep(10), LargeStep(50), DesiredPos(0),
|
||||
LastChange(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUIScrollBar");
|
||||
#endif
|
||||
|
||||
refreshControls();
|
||||
|
||||
setNotClipped(noclip);
|
||||
|
|
|
@ -20,10 +20,6 @@ namespace gui
|
|||
CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver)
|
||||
: SpriteBank(0), Driver(driver), Type(type)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUISkin");
|
||||
#endif
|
||||
|
||||
if ((Type == EGST_WINDOWS_CLASSIC) || (Type == EGST_WINDOWS_METALLIC))
|
||||
{
|
||||
Colors[EGDC_3D_DARK_SHADOW] = video::SColor(101,50,50,50);
|
||||
|
|
|
@ -16,10 +16,6 @@ namespace gui
|
|||
CGUISpriteBank::CGUISpriteBank(IGUIEnvironment *env) :
|
||||
Environment(env), Driver(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUISpriteBank");
|
||||
#endif
|
||||
|
||||
if (Environment) {
|
||||
Driver = Environment->getVideoDriver();
|
||||
if (Driver)
|
||||
|
|
|
@ -27,10 +27,6 @@ CGUIStaticText::CGUIStaticText(const wchar_t *text, bool border,
|
|||
OverrideColor(video::SColor(101, 255, 255, 255)), BGColor(video::SColor(101, 210, 210, 210)),
|
||||
OverrideFont(0), LastBreakFont(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUIStaticText");
|
||||
#endif
|
||||
|
||||
Text = text;
|
||||
if (environment && environment->getSkin()) {
|
||||
BGColor = environment->getSkin()->getColor(gui::EGDC_3D_FACE);
|
||||
|
|
|
@ -29,10 +29,6 @@ CGUITab::CGUITab(IGUIEnvironment *environment,
|
|||
BackColor(0, 0, 0, 0), OverrideTextColorEnabled(false), TextColor(255, 0, 0, 0),
|
||||
DrawBackground(false)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUITab");
|
||||
#endif
|
||||
|
||||
const IGUISkin *const skin = environment->getSkin();
|
||||
if (skin)
|
||||
TextColor = skin->getColor(EGDC_BUTTON_TEXT);
|
||||
|
@ -104,10 +100,6 @@ CGUITabControl::CGUITabControl(IGUIEnvironment *environment,
|
|||
Border(border), FillBackground(fillbackground), ScrollControl(false), TabHeight(0), VerticalAlignment(EGUIA_UPPERLEFT),
|
||||
UpButton(0), DownButton(0), TabMaxWidth(0), CurrentScrollTabIndex(0), TabExtraWidth(20)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUITabControl");
|
||||
#endif
|
||||
|
||||
IGUISkin *skin = Environment->getSkin();
|
||||
IGUISpriteBank *sprites = 0;
|
||||
|
||||
|
|
|
@ -95,6 +95,8 @@ SColor CImage::getPixel(u32 x, u32 y) const
|
|||
case ECF_A8R8G8B8:
|
||||
return ((u32 *)Data)[y * Size.Width + x];
|
||||
case ECF_R8G8B8: {
|
||||
// FIXME this interprets the memory as [R][G][B], whereas SColor is stored as
|
||||
// 0xAARRGGBB, meaning it is lies in memory as [B][G][R][A] on a little endian machine.
|
||||
u8 *p = Data + (y * 3) * Size.Width + (x * 3);
|
||||
return SColor(255, p[0], p[1], p[2]);
|
||||
}
|
||||
|
|
|
@ -19,9 +19,6 @@ namespace video
|
|||
//! constructor
|
||||
CImageLoaderJPG::CImageLoaderJPG()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CImageLoaderJPG");
|
||||
#endif
|
||||
}
|
||||
|
||||
//! destructor
|
||||
|
|
|
@ -93,6 +93,25 @@ bool CImageLoaderTGA::isALoadableFileFormat(io::IReadFile *file) const
|
|||
return (!strcmp(footer.Signature, "TRUEVISION-XFILE.")); // very old tgas are refused.
|
||||
}
|
||||
|
||||
/// Converts *byte order* BGR to *endianness order* ARGB (SColor "=" u32)
|
||||
static void convert_BGR8_to_SColor(const u8 *src, u32 n, u32 *dst)
|
||||
{
|
||||
for (u32 i = 0; i < n; ++i) {
|
||||
const u8 *bgr = &src[3 * i];
|
||||
dst[i] = 0xff000000 | (bgr[2] << 16) | (bgr[1] << 8) | bgr[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts *byte order* BGRA to *endianness order* ARGB (SColor "=" u32)
|
||||
/// Note: This just copies from src to dst on little endian.
|
||||
static void convert_BGRA8_to_SColor(const u8 *src, u32 n, u32 *dst)
|
||||
{
|
||||
for (u32 i = 0; i < n; ++i) {
|
||||
const u8 *bgra = &src[4 * i];
|
||||
dst[i] = (bgra[3] << 24) | (bgra[2] << 16) | (bgra[1] << 8) | bgra[0];
|
||||
}
|
||||
}
|
||||
|
||||
//! creates a surface from the file
|
||||
IImage *CImageLoaderTGA::loadImage(io::IReadFile *file) const
|
||||
{
|
||||
|
@ -139,10 +158,10 @@ IImage *CImageLoaderTGA::loadImage(io::IReadFile *file) const
|
|||
CColorConverter::convert_A1R5G5B5toA8R8G8B8(colorMap, header.ColorMapLength, palette);
|
||||
break;
|
||||
case 24:
|
||||
CColorConverter::convert_B8G8R8toA8R8G8B8(colorMap, header.ColorMapLength, palette);
|
||||
convert_BGR8_to_SColor(colorMap, header.ColorMapLength, palette);
|
||||
break;
|
||||
case 32:
|
||||
CColorConverter::convert_B8G8R8A8toA8R8G8B8(colorMap, header.ColorMapLength, palette);
|
||||
convert_BGRA8_to_SColor(colorMap, header.ColorMapLength, palette);
|
||||
break;
|
||||
}
|
||||
delete[] colorMap;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "os.h"
|
||||
|
||||
#include <cstdio> // IWYU pragma: keep (required for jpeglib.h)
|
||||
#include <memory>
|
||||
#include <jpeglib.h>
|
||||
#include <jerror.h>
|
||||
|
||||
|
@ -130,32 +131,28 @@ static bool writeJPEGFile(io::IWriteFile *file, IImage *image, u32 quality)
|
|||
jpeg_set_quality(&cinfo, quality, TRUE);
|
||||
jpeg_start_compress(&cinfo, TRUE);
|
||||
|
||||
u8 *dest = new u8[dim.Width * 3];
|
||||
std::unique_ptr<u8[]> dest{new u8[dim.Width * 3]};
|
||||
|
||||
if (dest) {
|
||||
const u32 pitch = image->getPitch();
|
||||
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
|
||||
row_pointer[0] = dest;
|
||||
row_pointer[0] = dest.get();
|
||||
|
||||
u8 *src = (u8 *)image->getData();
|
||||
|
||||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
// convert next line
|
||||
format(src, dim.Width, dest);
|
||||
format(src, dim.Width, dest.get());
|
||||
src += pitch;
|
||||
jpeg_write_scanlines(&cinfo, row_pointer, 1);
|
||||
}
|
||||
|
||||
delete[] dest;
|
||||
|
||||
/* Step 6: Finish compression */
|
||||
jpeg_finish_compress(&cinfo);
|
||||
}
|
||||
|
||||
/* Step 7: Destroy */
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
|
||||
return (dest != 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace video
|
||||
|
@ -172,11 +169,7 @@ IImageWriter *createImageWriterJPG()
|
|||
}
|
||||
|
||||
CImageWriterJPG::CImageWriterJPG()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CImageWriterJPG");
|
||||
#endif
|
||||
}
|
||||
{}
|
||||
|
||||
bool CImageWriterJPG::isAWriteableFileExtension(const io::path &filename) const
|
||||
{
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "os.h" // for logging
|
||||
|
||||
#include <png.h> // use system lib png
|
||||
#include <memory>
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
@ -53,11 +54,7 @@ void PNGAPI user_write_data_fcn(png_structp png_ptr, png_bytep data, png_size_t
|
|||
}
|
||||
|
||||
CImageWriterPNG::CImageWriterPNG()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CImageWriterPNG");
|
||||
#endif
|
||||
}
|
||||
{}
|
||||
|
||||
bool CImageWriterPNG::isAWriteableFileExtension(const io::path &filename) const
|
||||
{
|
||||
|
@ -94,22 +91,23 @@ bool CImageWriterPNG::writeImage(io::IWriteFile *file, IImage *image, u32 param)
|
|||
png_set_write_fn(png_ptr, file, user_write_data_fcn, NULL);
|
||||
|
||||
// Set info
|
||||
core::dimension2d<u32> img_dim = image->getDimension();
|
||||
switch (image->getColorFormat()) {
|
||||
case ECF_A8R8G8B8:
|
||||
case ECF_A1R5G5B5:
|
||||
png_set_IHDR(png_ptr, info_ptr,
|
||||
image->getDimension().Width, image->getDimension().Height,
|
||||
img_dim.Width, img_dim.Height,
|
||||
8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
break;
|
||||
default:
|
||||
png_set_IHDR(png_ptr, info_ptr,
|
||||
image->getDimension().Width, image->getDimension().Height,
|
||||
img_dim.Width, img_dim.Height,
|
||||
8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
}
|
||||
|
||||
s32 lineWidth = image->getDimension().Width;
|
||||
s32 lineWidth = img_dim.Width;
|
||||
switch (image->getColorFormat()) {
|
||||
case ECF_R8G8B8:
|
||||
case ECF_R5G6B5:
|
||||
|
@ -123,61 +121,52 @@ bool CImageWriterPNG::writeImage(io::IWriteFile *file, IImage *image, u32 param)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
u8 *tmpImage = new u8[image->getDimension().Height * lineWidth];
|
||||
if (!tmpImage) {
|
||||
os::Printer::log("PNGWriter: Internal PNG create image failure", file->getFileName(), ELL_ERROR);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
return false;
|
||||
}
|
||||
std::unique_ptr<u8[]> tmpImage{new u8[img_dim.Height * lineWidth]};
|
||||
|
||||
auto num_pixels = img_dim.Height * img_dim.Width;
|
||||
u8 *data = (u8 *)image->getData();
|
||||
switch (image->getColorFormat()) {
|
||||
case ECF_R8G8B8:
|
||||
CColorConverter::convert_R8G8B8toR8G8B8(data, image->getDimension().Height * image->getDimension().Width, tmpImage);
|
||||
CColorConverter::convert_R8G8B8toR8G8B8(data, num_pixels,
|
||||
tmpImage.get());
|
||||
break;
|
||||
case ECF_A8R8G8B8:
|
||||
CColorConverter::convert_A8R8G8B8toA8R8G8B8(data, image->getDimension().Height * image->getDimension().Width, tmpImage);
|
||||
CColorConverter::convert_A8R8G8B8toA8R8G8B8(data, num_pixels,
|
||||
tmpImage.get());
|
||||
break;
|
||||
case ECF_R5G6B5:
|
||||
CColorConverter::convert_R5G6B5toR8G8B8(data, image->getDimension().Height * image->getDimension().Width, tmpImage);
|
||||
CColorConverter::convert_R5G6B5toR8G8B8(data, num_pixels,
|
||||
tmpImage.get());
|
||||
break;
|
||||
case ECF_A1R5G5B5:
|
||||
CColorConverter::convert_A1R5G5B5toA8R8G8B8(data, image->getDimension().Height * image->getDimension().Width, tmpImage);
|
||||
CColorConverter::convert_A1R5G5B5toA8R8G8B8(data, num_pixels,
|
||||
tmpImage.get());
|
||||
break;
|
||||
// TODO: Error handling in case of unsupported color format
|
||||
default:
|
||||
os::Printer::log("CImageWriterPNG does not support image format", ColorFormatNames[image->getColorFormat()], ELL_WARNING);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
delete[] tmpImage;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create array of pointers to rows in image data
|
||||
|
||||
// Used to point to image rows
|
||||
u8 **RowPointers = new png_bytep[image->getDimension().Height];
|
||||
if (!RowPointers) {
|
||||
os::Printer::log("PNGWriter: Internal PNG create row pointers failure", file->getFileName(), ELL_ERROR);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
delete[] tmpImage;
|
||||
return false;
|
||||
}
|
||||
std::unique_ptr<u8*[]> RowPointers{new u8*[img_dim.Height]};
|
||||
|
||||
data = tmpImage;
|
||||
data = tmpImage.get();
|
||||
// Fill array of pointers to rows in image data
|
||||
for (u32 i = 0; i < image->getDimension().Height; ++i) {
|
||||
for (u32 i = 0; i < img_dim.Height; ++i) {
|
||||
RowPointers[i] = data;
|
||||
data += lineWidth;
|
||||
}
|
||||
// for proper error handling
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
delete[] RowPointers;
|
||||
delete[] tmpImage;
|
||||
return false;
|
||||
}
|
||||
|
||||
png_set_rows(png_ptr, info_ptr, RowPointers);
|
||||
png_set_rows(png_ptr, info_ptr, RowPointers.get());
|
||||
|
||||
if (image->getColorFormat() == ECF_A8R8G8B8 || image->getColorFormat() == ECF_A1R5G5B5)
|
||||
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR, NULL);
|
||||
|
@ -185,8 +174,6 @@ bool CImageWriterPNG::writeImage(io::IWriteFile *file, IImage *image, u32 param)
|
|||
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
|
||||
}
|
||||
|
||||
delete[] RowPointers;
|
||||
delete[] tmpImage;
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -105,10 +105,6 @@ CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters ¶m) :
|
|||
WindowHasFocus(false), WindowMinimized(false), WindowMaximized(param.WindowMaximized),
|
||||
ExternalWindow(false), AutorepeatSupport(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CIrrDeviceLinux");
|
||||
#endif
|
||||
|
||||
// print version, distribution etc.
|
||||
// thx to LynxLuna for pointing me to the uname function
|
||||
core::stringc linuxversion;
|
||||
|
@ -1951,7 +1947,8 @@ Cursor CIrrDeviceLinux::TextureToMonochromeCursor(irr::video::ITexture *tex, con
|
|||
XPutPixel(sourceImage, x, y, 0);
|
||||
} else // color
|
||||
{
|
||||
if (pixelCol.getAverage() >= 127)
|
||||
if ((pixelCol.getRed() + pixelCol.getGreen() +
|
||||
pixelCol.getBlue()) / 3 >= 127)
|
||||
XPutPixel(sourceImage, x, y, 1);
|
||||
else
|
||||
XPutPixel(sourceImage, x, y, 0);
|
||||
|
|
|
@ -524,10 +524,6 @@ CIrrDeviceMacOSX::CIrrDeviceMacOSX(const SIrrlichtCreationParameters ¶m) :
|
|||
{
|
||||
struct utsname name;
|
||||
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CIrrDeviceMacOSX");
|
||||
#endif
|
||||
|
||||
if (firstLaunch) {
|
||||
firstLaunch = false;
|
||||
|
||||
|
|
|
@ -253,10 +253,6 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters ¶m) :
|
|||
Resizable(param.WindowResizable == 1 ? true : false), CurrentTouchCount(0),
|
||||
IsInBackground(false)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CIrrDeviceSDL");
|
||||
#endif
|
||||
|
||||
if (++SDLDeviceInstances == 1) {
|
||||
#ifdef __ANDROID__
|
||||
// Blocking on pause causes problems with multiplayer.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue