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
78de371f2d
123 changed files with 1506 additions and 1956 deletions
9
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
9
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
|
@ -34,13 +34,6 @@ body:
|
||||||
render: "true"
|
render: "true"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: Irrlicht device
|
|
||||||
description:
|
|
||||||
placeholder: "Example: X11"
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: Operating system and version
|
label: Operating system and version
|
||||||
|
@ -69,7 +62,7 @@ body:
|
||||||
attributes:
|
attributes:
|
||||||
label: Active renderer
|
label: Active renderer
|
||||||
description: You can find this in the "About" tab in the main menu.
|
description: You can find this in the "About" tab in the main menu.
|
||||||
placeholder: "Example: OpenGL 4.6.0"
|
placeholder: "Example: ES 3.2 / ogles2 / X11"
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|
|
@ -32,6 +32,27 @@ local function get_credits()
|
||||||
return json
|
return json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function get_renderer_info()
|
||||||
|
local ret = {}
|
||||||
|
|
||||||
|
-- OpenGL version, stripped to just the important part
|
||||||
|
local s1 = core.get_active_renderer()
|
||||||
|
if s1:sub(1, 7) == "OpenGL " then
|
||||||
|
s1 = s1:sub(8)
|
||||||
|
end
|
||||||
|
local m = s1:match("^[%d.]+")
|
||||||
|
if not m then
|
||||||
|
m = s1:match("^ES [%d.]+")
|
||||||
|
end
|
||||||
|
ret[#ret+1] = m or s1
|
||||||
|
-- video driver
|
||||||
|
ret[#ret+1] = core.get_active_driver():lower()
|
||||||
|
-- irrlicht device
|
||||||
|
ret[#ret+1] = core.get_active_irrlicht_device():upper()
|
||||||
|
|
||||||
|
return table.concat(ret, " / ")
|
||||||
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name = "about",
|
name = "about",
|
||||||
caption = fgettext("About"),
|
caption = fgettext("About"),
|
||||||
|
@ -81,20 +102,12 @@ return {
|
||||||
"button_url[1.5,4.1;2.5,0.8;homepage;luanti.org;https://www.luanti.org/]" ..
|
"button_url[1.5,4.1;2.5,0.8;homepage;luanti.org;https://www.luanti.org/]" ..
|
||||||
"hypertext[5.5,0.25;9.75,6.6;credits;" .. core.formspec_escape(hypertext) .. "]"
|
"hypertext[5.5,0.25;9.75,6.6;credits;" .. core.formspec_escape(hypertext) .. "]"
|
||||||
|
|
||||||
-- Render information
|
local active_renderer_info = fgettext("Active renderer:") .. "\n" ..
|
||||||
local active_renderer_info = fgettext("Active renderer:") .. " " ..
|
core.formspec_escape(get_renderer_info())
|
||||||
core.formspec_escape(core.get_active_renderer())
|
|
||||||
fs = fs .. "style[label_button2;border=false]" ..
|
fs = fs .. "style[label_button2;border=false]" ..
|
||||||
"button[0.1,6;5.3,0.5;label_button2;" .. active_renderer_info .. "]"..
|
"button[0.1,6;5.3,1;label_button2;" .. active_renderer_info .. "]"..
|
||||||
"tooltip[label_button2;" .. active_renderer_info .. "]"
|
"tooltip[label_button2;" .. active_renderer_info .. "]"
|
||||||
|
|
||||||
-- Irrlicht device information
|
|
||||||
local irrlicht_device_info = fgettext("Irrlicht device:") .. " " ..
|
|
||||||
core.formspec_escape(core.get_active_irrlicht_device())
|
|
||||||
fs = fs .. "style[label_button3;border=false]" ..
|
|
||||||
"button[0.1,6.5;5.3,0.5;label_button3;" .. irrlicht_device_info .. "]"..
|
|
||||||
"tooltip[label_button3;" .. irrlicht_device_info .. "]"
|
|
||||||
|
|
||||||
if PLATFORM == "Android" then
|
if PLATFORM == "Android" then
|
||||||
fs = fs .. "button[0.5,5.1;4.5,0.8;share_debug;" .. fgettext("Share debug log") .. "]"
|
fs = fs .. "button[0.5,5.1;4.5,0.8;share_debug;" .. fgettext("Share debug log") .. "]"
|
||||||
else
|
else
|
||||||
|
|
|
@ -112,6 +112,7 @@ local function get_formspec(tabview, name, tabdata)
|
||||||
local retval =
|
local retval =
|
||||||
-- Search
|
-- Search
|
||||||
"field[0.25,0.25;7,0.75;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" ..
|
"field[0.25,0.25;7,0.75;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" ..
|
||||||
|
"tooltip[te_search;" .. fgettext("Possible filters\ngame:<name>\nmod:<name>\nplayer:<name>") .. "]" ..
|
||||||
"field_enter_after_edit[te_search;true]" ..
|
"field_enter_after_edit[te_search;true]" ..
|
||||||
"container[7.25,0.25]" ..
|
"container[7.25,0.25]" ..
|
||||||
"image_button[0,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "search.png") .. ";btn_mp_search;]" ..
|
"image_button[0,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "search.png") .. ";btn_mp_search;]" ..
|
||||||
|
@ -271,19 +272,106 @@ end
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local function parse_search_input(input)
|
||||||
|
if not input:find("%S") then
|
||||||
|
return -- Return nil if nothing to search for
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Search is not case sensitive
|
||||||
|
input = input:lower()
|
||||||
|
|
||||||
|
local query = {keywords = {}, mods = {}, players = {}}
|
||||||
|
|
||||||
|
-- Process quotation enclosed parts
|
||||||
|
input = input:gsub('(%S?)"([^"]*)"(%S?)', function(before, match, after)
|
||||||
|
if before == "" and after == "" then -- Also have be separated by spaces
|
||||||
|
table.insert(query.keywords, match)
|
||||||
|
return " "
|
||||||
|
end
|
||||||
|
return before..'"'..match..'"'..after
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Separate by space characters and handle special prefixes
|
||||||
|
-- (words with special prefixes need an exact match and none of them can contain spaces)
|
||||||
|
for word in input:gmatch("%S+") do
|
||||||
|
local mod = word:match("^mod:(.*)")
|
||||||
|
table.insert(query.mods, mod)
|
||||||
|
local player = word:match("^player:(.*)")
|
||||||
|
table.insert(query.players, player)
|
||||||
|
local game = word:match("^game:(.*)")
|
||||||
|
query.game = query.game or game
|
||||||
|
if not (mod or player or game) then
|
||||||
|
table.insert(query.keywords, word)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return query
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Prepares the server to be used for searching
|
||||||
|
local function uncapitalize_server(server)
|
||||||
|
local function table_lower(t)
|
||||||
|
local r = {}
|
||||||
|
for i, s in ipairs(t or {}) do
|
||||||
|
r[i] = s:lower()
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
name = (server.name or ""):lower(),
|
||||||
|
description = (server.description or ""):lower(),
|
||||||
|
gameid = (server.gameid or ""):lower(),
|
||||||
|
mods = table_lower(server.mods),
|
||||||
|
clients_list = table_lower(server.clients_list),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Returns false if the query does not match
|
||||||
|
-- otherwise returns a number to adjust the sorting priority
|
||||||
|
local function matches_query(server, query)
|
||||||
|
-- Search is not case sensitive
|
||||||
|
server = uncapitalize_server(server)
|
||||||
|
|
||||||
|
-- Check if mods found
|
||||||
|
for _, mod in ipairs(query.mods) do
|
||||||
|
if table.indexof(server.mods, mod) < 0 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if players found
|
||||||
|
for _, player in ipairs(query.players) do
|
||||||
|
if table.indexof(server.clients_list, player) < 0 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if game matches
|
||||||
|
if query.game and query.game ~= server.gameid then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if keyword found
|
||||||
|
local name_matches = true
|
||||||
|
local description_matches = true
|
||||||
|
for _, keyword in ipairs(query.keywords) do
|
||||||
|
name_matches = name_matches and server.name:find(keyword, 1, true)
|
||||||
|
description_matches = description_matches and server.description:find(keyword, 1, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
return name_matches and 50 or description_matches and 0
|
||||||
|
end
|
||||||
|
|
||||||
local function search_server_list(input)
|
local function search_server_list(input)
|
||||||
menudata.search_result = nil
|
menudata.search_result = nil
|
||||||
if #serverlistmgr.servers < 2 then
|
if #serverlistmgr.servers < 2 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- setup the keyword list
|
-- setup the search query
|
||||||
local keywords = {}
|
local query = parse_search_input(input)
|
||||||
for word in input:gmatch("%S+") do
|
if not query then
|
||||||
table.insert(keywords, word:lower())
|
|
||||||
end
|
|
||||||
|
|
||||||
if #keywords == 0 then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -292,16 +380,9 @@ local function search_server_list(input)
|
||||||
-- Search the serverlist
|
-- Search the serverlist
|
||||||
local search_result = {}
|
local search_result = {}
|
||||||
for i, server in ipairs(serverlistmgr.servers) do
|
for i, server in ipairs(serverlistmgr.servers) do
|
||||||
local name_matches, description_matches = true, true
|
local match = matches_query(server, query)
|
||||||
for _, keyword in ipairs(keywords) do
|
if match then
|
||||||
name_matches = name_matches and not not
|
server.points = #serverlistmgr.servers - i + match
|
||||||
(server.name or ""):lower():find(keyword, 1, true)
|
|
||||||
description_matches = description_matches and not not
|
|
||||||
(server.description or ""):lower():find(keyword, 1, true)
|
|
||||||
end
|
|
||||||
if name_matches or description_matches then
|
|
||||||
server.points = #serverlistmgr.servers - i
|
|
||||||
+ (name_matches and 50 or 0)
|
|
||||||
table.insert(search_result, server)
|
table.insert(search_result, server)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -395,7 +476,7 @@ local function main_button_handler(tabview, fields, name, tabdata)
|
||||||
|
|
||||||
if fields.btn_mp_search or fields.key_enter_field == "te_search" then
|
if fields.btn_mp_search or fields.key_enter_field == "te_search" then
|
||||||
tabdata.search_for = fields.te_search
|
tabdata.search_for = fields.te_search
|
||||||
search_server_list(fields.te_search:lower())
|
search_server_list(fields.te_search)
|
||||||
if menudata.search_result then
|
if menudata.search_result then
|
||||||
-- Note: This clears the selection if there are no results
|
-- Note: This clears the selection if there are no results
|
||||||
set_selected_server(menudata.search_result[1])
|
set_selected_server(menudata.search_result[1])
|
||||||
|
|
|
@ -406,6 +406,7 @@ bilinear_filter (Bilinear filtering) bool false
|
||||||
trilinear_filter (Trilinear filtering) bool false
|
trilinear_filter (Trilinear filtering) bool false
|
||||||
|
|
||||||
# Use anisotropic filtering when looking at textures from an angle.
|
# Use anisotropic filtering when looking at textures from an angle.
|
||||||
|
# This provides a significant improvement when used together with mipmapping.
|
||||||
anisotropic_filter (Anisotropic filtering) bool false
|
anisotropic_filter (Anisotropic filtering) bool false
|
||||||
|
|
||||||
# Select the antialiasing method to apply.
|
# Select the antialiasing method to apply.
|
||||||
|
@ -1881,6 +1882,10 @@ mesh_generation_interval (Mapblock mesh generation delay) int 0 0 50
|
||||||
# Value of 0 (default) will let Luanti autodetect the number of available threads.
|
# Value of 0 (default) will let Luanti autodetect the number of available threads.
|
||||||
mesh_generation_threads (Mapblock mesh generation threads) int 0 0 8
|
mesh_generation_threads (Mapblock mesh generation threads) int 0 0 8
|
||||||
|
|
||||||
|
# All mesh buffers with less than this number of vertices will be merged
|
||||||
|
# during map rendering. This improves rendering performance.
|
||||||
|
mesh_buffer_min_vertices (Minimum vertex count for mesh buffers) int 100 0 1000
|
||||||
|
|
||||||
# True = 256
|
# True = 256
|
||||||
# False = 128
|
# False = 128
|
||||||
# Usable to make minimap smoother on slower machines.
|
# Usable to make minimap smoother on slower machines.
|
||||||
|
@ -1902,12 +1907,11 @@ world_aligned_mode (World-aligned textures mode) enum enable disable,enable,forc
|
||||||
# Warning: This option is EXPERIMENTAL!
|
# Warning: This option is EXPERIMENTAL!
|
||||||
autoscale_mode (Autoscaling mode) enum disable disable,enable,force
|
autoscale_mode (Autoscaling mode) enum disable disable,enable,force
|
||||||
|
|
||||||
# When using bilinear/trilinear/anisotropic filters, low-resolution textures
|
# When using bilinear/trilinear filtering, low-resolution textures
|
||||||
# can be blurred, so automatically upscale them with nearest-neighbor
|
# can be blurred, so this option automatically upscales them to preserve
|
||||||
# interpolation to preserve crisp pixels. This sets the minimum texture size
|
# crisp pixels. This defines the minimum texture size for the upscaled textures;
|
||||||
# for the upscaled textures; higher values look sharper, but require more
|
# higher values look sharper, but require more memory.
|
||||||
# memory. Powers of 2 are recommended. This setting is ONLY applied if
|
# This setting is ONLY applied if any of the mentioned filters are enabled.
|
||||||
# bilinear/trilinear/anisotropic filtering is enabled.
|
|
||||||
# This is also used as the base node texture size for world-aligned
|
# This is also used as the base node texture size for world-aligned
|
||||||
# texture autoscaling.
|
# texture autoscaling.
|
||||||
texture_min_size (Base texture size) int 64 1 32768
|
texture_min_size (Base texture size) int 64 1 32768
|
||||||
|
|
|
@ -9,6 +9,7 @@ attribute vec2 inTexCoord0;
|
||||||
/* Uniforms */
|
/* Uniforms */
|
||||||
|
|
||||||
uniform float uThickness;
|
uniform float uThickness;
|
||||||
|
uniform mat4 uProjection;
|
||||||
|
|
||||||
/* Varyings */
|
/* Varyings */
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ varying vec4 vVertexColor;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = inVertexPosition;
|
gl_Position = uProjection * inVertexPosition;
|
||||||
gl_PointSize = uThickness;
|
gl_PointSize = uThickness;
|
||||||
vTextureCoord = inTexCoord0;
|
vTextureCoord = inTexCoord0;
|
||||||
vVertexColor = inVertexColor.bgra;
|
vVertexColor = inVertexColor.bgra;
|
||||||
|
|
|
@ -23,7 +23,12 @@ void main(void)
|
||||||
vec2 uv = varTexCoord.st;
|
vec2 uv = varTexCoord.st;
|
||||||
vec3 color = texture2D(rendered, uv).rgb;
|
vec3 color = texture2D(rendered, uv).rgb;
|
||||||
// translate to linear colorspace (approximate)
|
// translate to linear colorspace (approximate)
|
||||||
|
#ifdef GL_ES
|
||||||
|
// clamp color to [0,1] range in lieu of centroids
|
||||||
color = pow(clamp(color, 0.0, 1.0), vec3(2.2));
|
color = pow(clamp(color, 0.0, 1.0), vec3(2.2));
|
||||||
|
#else
|
||||||
|
color = pow(color, vec3(2.2));
|
||||||
|
#endif
|
||||||
|
|
||||||
color *= exposureParams.compensationFactor * bloomStrength;
|
color *= exposureParams.compensationFactor * bloomStrength;
|
||||||
|
|
||||||
|
|
|
@ -43,11 +43,14 @@ varying vec3 vPosition;
|
||||||
// cameraOffset + worldPosition (for large coordinates the limits of float
|
// cameraOffset + worldPosition (for large coordinates the limits of float
|
||||||
// precision must be considered).
|
// precision must be considered).
|
||||||
varying vec3 worldPosition;
|
varying vec3 worldPosition;
|
||||||
varying lowp vec4 varColor;
|
|
||||||
#ifdef GL_ES
|
#ifdef GL_ES
|
||||||
|
varying lowp vec4 varColor;
|
||||||
varying mediump vec2 varTexCoord;
|
varying mediump vec2 varTexCoord;
|
||||||
|
varying float nightRatio;
|
||||||
#else
|
#else
|
||||||
|
centroid varying lowp vec4 varColor;
|
||||||
centroid varying vec2 varTexCoord;
|
centroid varying vec2 varTexCoord;
|
||||||
|
centroid varying float nightRatio;
|
||||||
#endif
|
#endif
|
||||||
varying highp vec3 eyeVec;
|
varying highp vec3 eyeVec;
|
||||||
varying float nightRatio;
|
varying float nightRatio;
|
||||||
|
|
|
@ -14,14 +14,17 @@ varying vec3 vPosition;
|
||||||
// cameraOffset + worldPosition (for large coordinates the limits of float
|
// cameraOffset + worldPosition (for large coordinates the limits of float
|
||||||
// precision must be considered).
|
// precision must be considered).
|
||||||
varying vec3 worldPosition;
|
varying vec3 worldPosition;
|
||||||
varying lowp vec4 varColor;
|
|
||||||
// The centroid keyword ensures that after interpolation the texture coordinates
|
// The centroid keyword ensures that after interpolation the texture coordinates
|
||||||
// lie within the same bounds when MSAA is en- and disabled.
|
// lie within the same bounds when MSAA is en- and disabled.
|
||||||
// This fixes the stripes problem with nearest-neighbor textures and MSAA.
|
// This fixes the stripes problem with nearest-neighbor textures and MSAA.
|
||||||
#ifdef GL_ES
|
#ifdef GL_ES
|
||||||
|
varying lowp vec4 varColor;
|
||||||
varying mediump vec2 varTexCoord;
|
varying mediump vec2 varTexCoord;
|
||||||
|
varying float nightRatio;
|
||||||
#else
|
#else
|
||||||
|
centroid varying lowp vec4 varColor;
|
||||||
centroid varying vec2 varTexCoord;
|
centroid varying vec2 varTexCoord;
|
||||||
|
centroid varying float nightRatio;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||||
// shadow uniforms
|
// shadow uniforms
|
||||||
|
@ -47,6 +50,7 @@ varying highp vec3 eyeVec;
|
||||||
varying float nightRatio;
|
varying float nightRatio;
|
||||||
varying vec3 sunTint;
|
varying vec3 sunTint;
|
||||||
varying float nightFactor;
|
varying float nightFactor;
|
||||||
|
|
||||||
// Color of the light emitted by the light sources.
|
// Color of the light emitted by the light sources.
|
||||||
uniform vec3 artificialLight;
|
uniform vec3 artificialLight;
|
||||||
const float e = 2.718281828459;
|
const float e = 2.718281828459;
|
||||||
|
|
|
@ -188,7 +188,6 @@ Mod directory structure
|
||||||
│ ├── models
|
│ ├── models
|
||||||
│ ├── textures
|
│ ├── textures
|
||||||
│ │ ├── modname_stuff.png
|
│ │ ├── modname_stuff.png
|
||||||
│ │ ├── modname_stuff_normal.png
|
|
||||||
│ │ ├── modname_something_else.png
|
│ │ ├── modname_something_else.png
|
||||||
│ │ ├── subfolder_foo
|
│ │ ├── subfolder_foo
|
||||||
│ │ │ ├── modname_more_stuff.png
|
│ │ │ ├── modname_more_stuff.png
|
||||||
|
@ -318,7 +317,7 @@ Many glTF features are not supported *yet*, including:
|
||||||
|
|
||||||
* Animations
|
* Animations
|
||||||
* Only a single animation is supported, use frame ranges within this animation.
|
* Only a single animation is supported, use frame ranges within this animation.
|
||||||
* Only linear interpolation is supported.
|
* `CUBICSPLINE` interpolation is not supported.
|
||||||
* Cameras
|
* Cameras
|
||||||
* Materials
|
* Materials
|
||||||
* Only base color textures are supported
|
* Only base color textures are supported
|
||||||
|
|
|
@ -55,6 +55,20 @@ core.register_entity("gltf:simple_skin", {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
core.register_entity("gltf:simple_skin_step", {
|
||||||
|
initial_properties = {
|
||||||
|
infotext = "Simple skin, but using STEP interpolation",
|
||||||
|
visual = "mesh",
|
||||||
|
visual_size = vector.new(5, 5, 5),
|
||||||
|
mesh = "gltf_simple_skin_step.gltf",
|
||||||
|
textures = {},
|
||||||
|
backface_culling = false
|
||||||
|
},
|
||||||
|
on_activate = function(self)
|
||||||
|
self.object:set_animation({x = 0, y = 5.5}, 1)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
-- The claws rendering incorrectly from one side is expected behavior:
|
-- The claws rendering incorrectly from one side is expected behavior:
|
||||||
-- They use an unsupported double-sided material.
|
-- They use an unsupported double-sided material.
|
||||||
core.register_entity("gltf:frog", {
|
core.register_entity("gltf:frog", {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{"scene":0,"scenes":[{"nodes":[0,1]}],"nodes":[{"skin":0,"mesh":0},{"children":[2]},{"translation":[0.0,1.0,0.0],"rotation":[0.0,0.0,0.0,1.0]}],"meshes":[{"primitives":[{"attributes":{"POSITION":1,"JOINTS_0":2,"WEIGHTS_0":3},"indices":0}]}],"skins":[{"inverseBindMatrices":4,"joints":[1,2]}],"animations":[{"channels":[{"sampler":0,"target":{"node":2,"path":"rotation"}}],"samplers":[{"input":5,"interpolation":"STEP","output":6}]}],"buffers":[{"uri":"data:application/gltf-buffer;base64,AAABAAMAAAADAAIAAgADAAUAAgAFAAQABAAFAAcABAAHAAYABgAHAAkABgAJAAgAAAAAvwAAAAAAAAAAAAAAPwAAAAAAAAAAAAAAvwAAAD8AAAAAAAAAPwAAAD8AAAAAAAAAvwAAgD8AAAAAAAAAPwAAgD8AAAAAAAAAvwAAwD8AAAAAAAAAPwAAwD8AAAAAAAAAvwAAAEAAAAAAAAAAPwAAAEAAAAAA","byteLength":168},{"uri":"data:application/gltf-buffer;base64,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAABAPwAAgD4AAAAAAAAAAAAAQD8AAIA+AAAAAAAAAAAAAAA/AAAAPwAAAAAAAAAAAAAAPwAAAD8AAAAAAAAAAAAAgD4AAEA/AAAAAAAAAAAAAIA+AABAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAA=","byteLength":320},{"uri":"data:application/gltf-buffer;base64,AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAgD8=","byteLength":128},{"uri":"data:application/gltf-buffer;base64,AAAAAAAAAD8AAIA/AADAPwAAAEAAACBAAABAQAAAYEAAAIBAAACQQAAAoEAAALBAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAPT9ND/0/TQ/AAAAAAAAAAD0/TQ/9P00PwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAPT9NL/0/TQ/AAAAAAAAAAD0/TS/9P00PwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAAAAAAAAAIA/","byteLength":240}],"bufferViews":[{"buffer":0,"byteLength":48,"target":34963},{"buffer":0,"byteOffset":48,"byteLength":120,"target":34962},{"buffer":1,"byteLength":320,"byteStride":16},{"buffer":2,"byteLength":128},{"buffer":3,"byteLength":240}],"accessors":[{"bufferView":0,"componentType":5123,"count":24,"type":"SCALAR"},{"bufferView":1,"componentType":5126,"count":10,"type":"VEC3","max":[0.5,2.0,0.0],"min":[-0.5,0.0,0.0]},{"bufferView":2,"componentType":5123,"count":10,"type":"VEC4"},{"bufferView":2,"byteOffset":160,"componentType":5126,"count":10,"type":"VEC4"},{"bufferView":3,"componentType":5126,"count":2,"type":"MAT4"},{"bufferView":4,"componentType":5126,"count":12,"type":"SCALAR","max":[5.5],"min":[0.0]},{"bufferView":4,"byteOffset":48,"componentType":5126,"count":12,"type":"VEC4","max":[0.0,0.0,0.707,1.0],"min":[0.0,0.0,-0.707,0.707]}],"asset":{"version":"2.0"}}
|
|
@ -134,7 +134,7 @@ public:
|
||||||
//! Index buffer
|
//! Index buffer
|
||||||
SIndexBuffer *Indices;
|
SIndexBuffer *Indices;
|
||||||
//! Bounding box of this meshbuffer.
|
//! Bounding box of this meshbuffer.
|
||||||
core::aabbox3d<f32> BoundingBox;
|
core::aabbox3d<f32> BoundingBox{{0, 0, 0}};
|
||||||
//! Primitive type used for rendering (triangles, lines, ...)
|
//! Primitive type used for rendering (triangles, lines, ...)
|
||||||
E_PRIMITIVE_TYPE PrimitiveType;
|
E_PRIMITIVE_TYPE PrimitiveType;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "irrTypes.h"
|
|
||||||
|
|
||||||
namespace irr
|
|
||||||
{
|
|
||||||
namespace video
|
|
||||||
{
|
|
||||||
|
|
||||||
//! Compile target enumeration for the addHighLevelShaderMaterial() method.
|
|
||||||
enum E_VERTEX_SHADER_TYPE
|
|
||||||
{
|
|
||||||
EVST_VS_1_1 = 0,
|
|
||||||
EVST_VS_2_0,
|
|
||||||
EVST_VS_2_a,
|
|
||||||
EVST_VS_3_0,
|
|
||||||
EVST_VS_4_0,
|
|
||||||
EVST_VS_4_1,
|
|
||||||
EVST_VS_5_0,
|
|
||||||
|
|
||||||
//! This is not a type, but a value indicating how much types there are.
|
|
||||||
EVST_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Names for all vertex shader types, each entry corresponds to a E_VERTEX_SHADER_TYPE entry.
|
|
||||||
const c8 *const VERTEX_SHADER_TYPE_NAMES[] = {
|
|
||||||
"vs_1_1",
|
|
||||||
"vs_2_0",
|
|
||||||
"vs_2_a",
|
|
||||||
"vs_3_0",
|
|
||||||
"vs_4_0",
|
|
||||||
"vs_4_1",
|
|
||||||
"vs_5_0",
|
|
||||||
0};
|
|
||||||
|
|
||||||
//! Compile target enumeration for the addHighLevelShaderMaterial() method.
|
|
||||||
enum E_PIXEL_SHADER_TYPE
|
|
||||||
{
|
|
||||||
EPST_PS_1_1 = 0,
|
|
||||||
EPST_PS_1_2,
|
|
||||||
EPST_PS_1_3,
|
|
||||||
EPST_PS_1_4,
|
|
||||||
EPST_PS_2_0,
|
|
||||||
EPST_PS_2_a,
|
|
||||||
EPST_PS_2_b,
|
|
||||||
EPST_PS_3_0,
|
|
||||||
EPST_PS_4_0,
|
|
||||||
EPST_PS_4_1,
|
|
||||||
EPST_PS_5_0,
|
|
||||||
|
|
||||||
//! This is not a type, but a value indicating how much types there are.
|
|
||||||
EPST_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Names for all pixel shader types, each entry corresponds to a E_PIXEL_SHADER_TYPE entry.
|
|
||||||
const c8 *const PIXEL_SHADER_TYPE_NAMES[] = {
|
|
||||||
"ps_1_1",
|
|
||||||
"ps_1_2",
|
|
||||||
"ps_1_3",
|
|
||||||
"ps_1_4",
|
|
||||||
"ps_2_0",
|
|
||||||
"ps_2_a",
|
|
||||||
"ps_2_b",
|
|
||||||
"ps_3_0",
|
|
||||||
"ps_4_0",
|
|
||||||
"ps_4_1",
|
|
||||||
"ps_5_0",
|
|
||||||
0};
|
|
||||||
|
|
||||||
//! Enum for supported geometry shader types
|
|
||||||
enum E_GEOMETRY_SHADER_TYPE
|
|
||||||
{
|
|
||||||
EGST_GS_4_0 = 0,
|
|
||||||
|
|
||||||
//! This is not a type, but a value indicating how much types there are.
|
|
||||||
EGST_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
//! String names for supported geometry shader types
|
|
||||||
const c8 *const GEOMETRY_SHADER_TYPE_NAMES[] = {
|
|
||||||
"gs_4_0",
|
|
||||||
0};
|
|
||||||
|
|
||||||
} // end namespace video
|
|
||||||
} // end namespace irr
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "EShaderTypes.h"
|
|
||||||
#include "EMaterialTypes.h"
|
#include "EMaterialTypes.h"
|
||||||
#include "EPrimitiveTypes.h"
|
#include "EPrimitiveTypes.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
|
@ -31,26 +30,15 @@ public:
|
||||||
virtual ~IGPUProgrammingServices() {}
|
virtual ~IGPUProgrammingServices() {}
|
||||||
|
|
||||||
//! Adds a new high-level shading material renderer to the VideoDriver.
|
//! Adds a new high-level shading material renderer to the VideoDriver.
|
||||||
/** Currently only HLSL/D3D9 and GLSL/OpenGL are supported.
|
/**
|
||||||
\param vertexShaderProgram String containing the source of the vertex
|
\param vertexShaderProgram String containing the source of the vertex
|
||||||
shader program. This can be 0 if no vertex program shall be used.
|
shader program. This can be 0 if no vertex program shall be used.
|
||||||
\param vertexShaderEntryPointName Name of the entry function of the
|
|
||||||
vertexShaderProgram (p.e. "main")
|
|
||||||
\param vsCompileTarget Vertex shader version the high level shader
|
|
||||||
shall be compiled to.
|
|
||||||
\param pixelShaderProgram String containing the source of the pixel
|
\param pixelShaderProgram String containing the source of the pixel
|
||||||
shader program. This can be 0 if no pixel shader shall be used.
|
shader program. This can be 0 if no pixel shader shall be used.
|
||||||
\param pixelShaderEntryPointName Entry name of the function of the
|
|
||||||
pixelShaderProgram (p.e. "main")
|
|
||||||
\param psCompileTarget Pixel shader version the high level shader
|
|
||||||
shall be compiled to.
|
|
||||||
\param geometryShaderProgram String containing the source of the
|
\param geometryShaderProgram String containing the source of the
|
||||||
geometry shader program. This can be 0 if no geometry shader shall be
|
geometry shader program. This can be 0 if no geometry shader shall be
|
||||||
used.
|
used.
|
||||||
\param geometryShaderEntryPointName Entry name of the function of the
|
\param shaderName Name of the shader for debug purposes
|
||||||
geometryShaderProgram (p.e. "main")
|
|
||||||
\param gsCompileTarget Geometry shader version the high level shader
|
|
||||||
shall be compiled to.
|
|
||||||
\param inType Type of vertices passed to geometry shader
|
\param inType Type of vertices passed to geometry shader
|
||||||
\param outType Type of vertices created by geometry shader
|
\param outType Type of vertices created by geometry shader
|
||||||
\param verticesOut Maximal number of vertices created by geometry
|
\param verticesOut Maximal number of vertices created by geometry
|
||||||
|
@ -73,108 +61,43 @@ public:
|
||||||
error log and can be caught with a custom event receiver. */
|
error log and can be caught with a custom event receiver. */
|
||||||
virtual s32 addHighLevelShaderMaterial(
|
virtual s32 addHighLevelShaderMaterial(
|
||||||
const c8 *vertexShaderProgram,
|
const c8 *vertexShaderProgram,
|
||||||
const c8 *vertexShaderEntryPointName,
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
|
||||||
const c8 *pixelShaderProgram,
|
const c8 *pixelShaderProgram,
|
||||||
const c8 *pixelShaderEntryPointName,
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
|
||||||
const c8 *geometryShaderProgram,
|
const c8 *geometryShaderProgram,
|
||||||
const c8 *geometryShaderEntryPointName = "main",
|
const c8 *shaderName = nullptr,
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||||
u32 verticesOut = 0,
|
u32 verticesOut = 0,
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
IShaderConstantSetCallBack *callback = nullptr,
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||||
s32 userData = 0) = 0;
|
s32 userData = 0) = 0;
|
||||||
|
|
||||||
//! convenience function for use without geometry shaders
|
//! convenience function for use without geometry shaders
|
||||||
s32 addHighLevelShaderMaterial(
|
s32 addHighLevelShaderMaterial(
|
||||||
const c8 *vertexShaderProgram,
|
const c8 *vertexShaderProgram,
|
||||||
const c8 *vertexShaderEntryPointName = "main",
|
const c8 *pixelShaderProgram = nullptr,
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1,
|
const c8 *shaderName = nullptr,
|
||||||
const c8 *pixelShaderProgram = 0,
|
IShaderConstantSetCallBack *callback = nullptr,
|
||||||
const c8 *pixelShaderEntryPointName = "main",
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1,
|
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||||
s32 userData = 0)
|
s32 userData = 0)
|
||||||
{
|
{
|
||||||
return addHighLevelShaderMaterial(
|
return addHighLevelShaderMaterial(
|
||||||
vertexShaderProgram, vertexShaderEntryPointName,
|
vertexShaderProgram, pixelShaderProgram,
|
||||||
vsCompileTarget, pixelShaderProgram,
|
nullptr, shaderName,
|
||||||
pixelShaderEntryPointName, psCompileTarget,
|
|
||||||
0, "main", EGST_GS_4_0,
|
|
||||||
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0,
|
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0,
|
||||||
callback, baseMaterial, userData);
|
callback, baseMaterial, userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! convenience function for use with many defaults, without geometry shader
|
|
||||||
/** All shader names are set to "main" and compile targets are shader
|
|
||||||
type 1.1.
|
|
||||||
*/
|
|
||||||
s32 addHighLevelShaderMaterial(
|
|
||||||
const c8 *vertexShaderProgram,
|
|
||||||
const c8 *pixelShaderProgram = 0,
|
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
|
||||||
s32 userData = 0)
|
|
||||||
{
|
|
||||||
return addHighLevelShaderMaterial(
|
|
||||||
vertexShaderProgram, "main",
|
|
||||||
EVST_VS_1_1, pixelShaderProgram,
|
|
||||||
"main", EPST_PS_1_1,
|
|
||||||
0, "main", EGST_GS_4_0,
|
|
||||||
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0,
|
|
||||||
callback, baseMaterial, userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! convenience function for use with many defaults, with geometry shader
|
|
||||||
/** All shader names are set to "main" and compile targets are shader
|
|
||||||
type 1.1 and geometry shader 4.0.
|
|
||||||
*/
|
|
||||||
s32 addHighLevelShaderMaterial(
|
|
||||||
const c8 *vertexShaderProgram,
|
|
||||||
const c8 *pixelShaderProgram = 0,
|
|
||||||
const c8 *geometryShaderProgram = 0,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
|
||||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
|
||||||
u32 verticesOut = 0,
|
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
|
||||||
s32 userData = 0)
|
|
||||||
{
|
|
||||||
return addHighLevelShaderMaterial(
|
|
||||||
vertexShaderProgram, "main",
|
|
||||||
EVST_VS_1_1, pixelShaderProgram,
|
|
||||||
"main", EPST_PS_1_1,
|
|
||||||
geometryShaderProgram, "main", EGST_GS_4_0,
|
|
||||||
inType, outType, verticesOut,
|
|
||||||
callback, baseMaterial, userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Like addHighLevelShaderMaterial(), but loads from files.
|
//! Like addHighLevelShaderMaterial(), but loads from files.
|
||||||
/** \param vertexShaderProgramFileName Text file containing the source
|
/** \param vertexShaderProgramFileName Text file containing the source
|
||||||
of the vertex shader program. Set to empty string if no vertex shader
|
of the vertex shader program. Set to empty string if no vertex shader
|
||||||
shall be created.
|
shall be created.
|
||||||
\param vertexShaderEntryPointName Name of the entry function of the
|
|
||||||
vertexShaderProgram (p.e. "main")
|
|
||||||
\param vsCompileTarget Vertex shader version the high level shader
|
|
||||||
shall be compiled to.
|
|
||||||
\param pixelShaderProgramFileName Text file containing the source of
|
\param pixelShaderProgramFileName Text file containing the source of
|
||||||
the pixel shader program. Set to empty string if no pixel shader shall
|
the pixel shader program. Set to empty string if no pixel shader shall
|
||||||
be created.
|
be created.
|
||||||
\param pixelShaderEntryPointName Entry name of the function of the
|
|
||||||
pixelShaderProgram (p.e. "main")
|
|
||||||
\param psCompileTarget Pixel shader version the high level shader
|
|
||||||
shall be compiled to.
|
|
||||||
\param geometryShaderProgramFileName Name of the source of
|
\param geometryShaderProgramFileName Name of the source of
|
||||||
the geometry shader program. Set to empty string if no geometry shader
|
the geometry shader program. Set to empty string if no geometry shader
|
||||||
shall be created.
|
shall be created.
|
||||||
\param geometryShaderEntryPointName Entry name of the function of the
|
\param shaderName Name of the shader for debug purposes
|
||||||
geometryShaderProgram (p.e. "main")
|
|
||||||
\param gsCompileTarget Geometry shader version the high level shader
|
|
||||||
shall be compiled to.
|
|
||||||
\param inType Type of vertices passed to geometry shader
|
\param inType Type of vertices passed to geometry shader
|
||||||
\param outType Type of vertices created by geometry shader
|
\param outType Type of vertices created by geometry shader
|
||||||
\param verticesOut Maximal number of vertices created by geometry
|
\param verticesOut Maximal number of vertices created by geometry
|
||||||
|
@ -197,164 +120,16 @@ public:
|
||||||
error log and can be caught with a custom event receiver. */
|
error log and can be caught with a custom event receiver. */
|
||||||
virtual s32 addHighLevelShaderMaterialFromFiles(
|
virtual s32 addHighLevelShaderMaterialFromFiles(
|
||||||
const io::path &vertexShaderProgramFileName,
|
const io::path &vertexShaderProgramFileName,
|
||||||
const c8 *vertexShaderEntryPointName,
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
|
||||||
const io::path &pixelShaderProgramFileName,
|
const io::path &pixelShaderProgramFileName,
|
||||||
const c8 *pixelShaderEntryPointName,
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
|
||||||
const io::path &geometryShaderProgramFileName,
|
const io::path &geometryShaderProgramFileName,
|
||||||
const c8 *geometryShaderEntryPointName = "main",
|
const c8 *shaderName = nullptr,
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||||
u32 verticesOut = 0,
|
u32 verticesOut = 0,
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
IShaderConstantSetCallBack *callback = nullptr,
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||||
s32 userData = 0) = 0;
|
s32 userData = 0) = 0;
|
||||||
|
|
||||||
//! convenience function for use without geometry shaders
|
|
||||||
s32 addHighLevelShaderMaterialFromFiles(
|
|
||||||
const io::path &vertexShaderProgramFileName,
|
|
||||||
const c8 *vertexShaderEntryPointName = "main",
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1,
|
|
||||||
const io::path &pixelShaderProgramFileName = "",
|
|
||||||
const c8 *pixelShaderEntryPointName = "main",
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1,
|
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
|
||||||
s32 userData = 0)
|
|
||||||
{
|
|
||||||
return addHighLevelShaderMaterialFromFiles(
|
|
||||||
vertexShaderProgramFileName, vertexShaderEntryPointName,
|
|
||||||
vsCompileTarget, pixelShaderProgramFileName,
|
|
||||||
pixelShaderEntryPointName, psCompileTarget,
|
|
||||||
"", "main", EGST_GS_4_0,
|
|
||||||
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0,
|
|
||||||
callback, baseMaterial, userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! convenience function for use with many defaults, without geometry shader
|
|
||||||
/** All shader names are set to "main" and compile targets are shader
|
|
||||||
type 1.1.
|
|
||||||
*/
|
|
||||||
s32 addHighLevelShaderMaterialFromFiles(
|
|
||||||
const io::path &vertexShaderProgramFileName,
|
|
||||||
const io::path &pixelShaderProgramFileName = "",
|
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
|
||||||
s32 userData = 0)
|
|
||||||
{
|
|
||||||
return addHighLevelShaderMaterialFromFiles(
|
|
||||||
vertexShaderProgramFileName, "main",
|
|
||||||
EVST_VS_1_1, pixelShaderProgramFileName,
|
|
||||||
"main", EPST_PS_1_1,
|
|
||||||
"", "main", EGST_GS_4_0,
|
|
||||||
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0,
|
|
||||||
callback, baseMaterial, userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! convenience function for use with many defaults, with geometry shader
|
|
||||||
/** All shader names are set to "main" and compile targets are shader
|
|
||||||
type 1.1 and geometry shader 4.0.
|
|
||||||
*/
|
|
||||||
s32 addHighLevelShaderMaterialFromFiles(
|
|
||||||
const io::path &vertexShaderProgramFileName,
|
|
||||||
const io::path &pixelShaderProgramFileName = "",
|
|
||||||
const io::path &geometryShaderProgramFileName = "",
|
|
||||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
|
||||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
|
||||||
u32 verticesOut = 0,
|
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
|
||||||
s32 userData = 0)
|
|
||||||
{
|
|
||||||
return addHighLevelShaderMaterialFromFiles(
|
|
||||||
vertexShaderProgramFileName, "main",
|
|
||||||
EVST_VS_1_1, pixelShaderProgramFileName,
|
|
||||||
"main", EPST_PS_1_1,
|
|
||||||
geometryShaderProgramFileName, "main", EGST_GS_4_0,
|
|
||||||
inType, outType, verticesOut,
|
|
||||||
callback, baseMaterial, userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Like addHighLevelShaderMaterial(), but loads from files.
|
|
||||||
/** \param vertexShaderProgram Text file handle containing the source
|
|
||||||
of the vertex shader program. Set to 0 if no vertex shader shall be
|
|
||||||
created.
|
|
||||||
\param vertexShaderEntryPointName Name of the entry function of the
|
|
||||||
vertexShaderProgram
|
|
||||||
\param vsCompileTarget Vertex shader version the high level shader
|
|
||||||
shall be compiled to.
|
|
||||||
\param pixelShaderProgram Text file handle containing the source of
|
|
||||||
the pixel shader program. Set to 0 if no pixel shader shall be created.
|
|
||||||
\param pixelShaderEntryPointName Entry name of the function of the
|
|
||||||
pixelShaderProgram (p.e. "main")
|
|
||||||
\param psCompileTarget Pixel shader version the high level shader
|
|
||||||
shall be compiled to.
|
|
||||||
\param geometryShaderProgram Text file handle containing the source of
|
|
||||||
the geometry shader program. Set to 0 if no geometry shader shall be
|
|
||||||
created.
|
|
||||||
\param geometryShaderEntryPointName Entry name of the function of the
|
|
||||||
geometryShaderProgram (p.e. "main")
|
|
||||||
\param gsCompileTarget Geometry shader version the high level shader
|
|
||||||
shall be compiled to.
|
|
||||||
\param inType Type of vertices passed to geometry shader
|
|
||||||
\param outType Type of vertices created by geometry shader
|
|
||||||
\param verticesOut Maximal number of vertices created by geometry
|
|
||||||
shader. If 0, maximal number supported is assumed.
|
|
||||||
\param callback Pointer to an implementation of
|
|
||||||
IShaderConstantSetCallBack in which you can set the needed vertex and
|
|
||||||
pixel shader program constants. Set this to 0 if you don't need this.
|
|
||||||
\param baseMaterial Base material which renderstates will be used to
|
|
||||||
shade the material.
|
|
||||||
\param userData a user data int. This int can be set to any value and
|
|
||||||
will be set as parameter in the callback method when calling
|
|
||||||
OnSetConstants(). In this way it is easily possible to use the same
|
|
||||||
callback method for multiple materials and distinguish between them
|
|
||||||
during the call.
|
|
||||||
\return Number of the material type which can be set in
|
|
||||||
SMaterial::MaterialType to use the renderer. -1 is returned if an
|
|
||||||
error occurred, e.g. if a shader program could not be compiled or a
|
|
||||||
compile target is not reachable. The error strings are then printed to
|
|
||||||
the error log and can be caught with a custom event receiver. */
|
|
||||||
virtual s32 addHighLevelShaderMaterialFromFiles(
|
|
||||||
io::IReadFile *vertexShaderProgram,
|
|
||||||
const c8 *vertexShaderEntryPointName,
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
|
||||||
io::IReadFile *pixelShaderProgram,
|
|
||||||
const c8 *pixelShaderEntryPointName,
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
|
||||||
io::IReadFile *geometryShaderProgram,
|
|
||||||
const c8 *geometryShaderEntryPointName = "main",
|
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
|
||||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
|
||||||
u32 verticesOut = 0,
|
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
|
||||||
s32 userData = 0) = 0;
|
|
||||||
|
|
||||||
//! convenience function for use without geometry shaders
|
|
||||||
s32 addHighLevelShaderMaterialFromFiles(
|
|
||||||
io::IReadFile *vertexShaderProgram,
|
|
||||||
const c8 *vertexShaderEntryPointName = "main",
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1,
|
|
||||||
io::IReadFile *pixelShaderProgram = 0,
|
|
||||||
const c8 *pixelShaderEntryPointName = "main",
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1,
|
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
|
||||||
s32 userData = 0)
|
|
||||||
{
|
|
||||||
return addHighLevelShaderMaterialFromFiles(
|
|
||||||
vertexShaderProgram, vertexShaderEntryPointName,
|
|
||||||
vsCompileTarget, pixelShaderProgram,
|
|
||||||
pixelShaderEntryPointName, psCompileTarget,
|
|
||||||
0, "main", EGST_GS_4_0,
|
|
||||||
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0,
|
|
||||||
callback, baseMaterial, userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Delete a shader material and associated data.
|
//! Delete a shader material and associated data.
|
||||||
/**
|
/**
|
||||||
After you have deleted a material it is invalid to still use and doing
|
After you have deleted a material it is invalid to still use and doing
|
||||||
|
|
|
@ -53,7 +53,7 @@ public:
|
||||||
//! Calculates the width and height of a given string of text.
|
//! Calculates the width and height of a given string of text.
|
||||||
/** \return Returns width and height of the area covered by the text if
|
/** \return Returns width and height of the area covered by the text if
|
||||||
it would be drawn. */
|
it would be drawn. */
|
||||||
virtual core::dimension2d<u32> getDimension(const wchar_t *text) const = 0;
|
virtual core::dimension2du getDimension(const wchar_t *text) const = 0;
|
||||||
|
|
||||||
//! Calculates the index of the character in the text which is on a specific position.
|
//! Calculates the index of the character in the text which is on a specific position.
|
||||||
/** \param text: Text string.
|
/** \param text: Text string.
|
||||||
|
@ -82,10 +82,7 @@ public:
|
||||||
which supports kerning pairs a string such as 'Wo' may have the 'o'
|
which supports kerning pairs a string such as 'Wo' may have the 'o'
|
||||||
tucked neatly under the 'W'.
|
tucked neatly under the 'W'.
|
||||||
*/
|
*/
|
||||||
virtual s32 getKerningWidth(const wchar_t *thisLetter = 0, const wchar_t *previousLetter = 0) const = 0;
|
virtual core::vector2di getKerning(const wchar_t thisLetter = 0, const wchar_t previousLetter = 0) const = 0;
|
||||||
|
|
||||||
//! Returns the distance between letters
|
|
||||||
virtual s32 getKerningHeight() const = 0;
|
|
||||||
|
|
||||||
//! Define which characters should not be drawn by the font.
|
//! Define which characters should not be drawn by the font.
|
||||||
/** For example " " would not draw any space which is usually blank in
|
/** For example " " would not draw any space which is usually blank in
|
||||||
|
|
|
@ -24,17 +24,6 @@ public:
|
||||||
|
|
||||||
//! returns the sprite number from a given character
|
//! returns the sprite number from a given character
|
||||||
virtual u32 getSpriteNoFromChar(const wchar_t *c) const = 0;
|
virtual u32 getSpriteNoFromChar(const wchar_t *c) const = 0;
|
||||||
|
|
||||||
//! Gets kerning values (distance between letters) for the font. If no parameters are provided,
|
|
||||||
/** the global kerning distance is returned.
|
|
||||||
\param thisLetter: If this parameter is provided, the left side kerning for this letter is added
|
|
||||||
to the global kerning value. For example, a space might only be one pixel wide, but it may
|
|
||||||
be displayed as several pixels.
|
|
||||||
\param previousLetter: If provided, kerning is calculated for both letters and added to the global
|
|
||||||
kerning value. For example, EGFT_BITMAP will add the right kerning value of previousLetter to the
|
|
||||||
left side kerning value of thisLetter, then add the global value.
|
|
||||||
*/
|
|
||||||
s32 getKerningWidth(const wchar_t *thisLetter = 0, const wchar_t *previousLetter = 0) const override = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace gui
|
} // end namespace gui
|
||||||
|
|
|
@ -108,7 +108,7 @@ public:
|
||||||
if (!mesh)
|
if (!mesh)
|
||||||
return true;
|
return true;
|
||||||
bool result = true;
|
bool result = true;
|
||||||
core::aabbox3df bufferbox;
|
core::aabbox3df bufferbox{{0, 0, 0}};
|
||||||
for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
|
for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
|
||||||
result &= apply(func, mesh->getMeshBuffer(i), boundingBoxUpdate);
|
result &= apply(func, mesh->getMeshBuffer(i), boundingBoxUpdate);
|
||||||
if (boundingBoxUpdate) {
|
if (boundingBoxUpdate) {
|
||||||
|
@ -136,7 +136,7 @@ protected:
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
core::aabbox3df bufferbox;
|
core::aabbox3df bufferbox{{0, 0, 0}};
|
||||||
for (u32 i = 0; i < buffer->getVertexCount(); ++i) {
|
for (u32 i = 0; i < buffer->getVertexCount(); ++i) {
|
||||||
switch (buffer->getVertexType()) {
|
switch (buffer->getVertexType()) {
|
||||||
case video::EVT_STANDARD: {
|
case video::EVT_STANDARD: {
|
||||||
|
|
|
@ -61,8 +61,8 @@ struct SFrameStats {
|
||||||
u32 PrimitivesDrawn = 0;
|
u32 PrimitivesDrawn = 0;
|
||||||
//! Number of hardware buffers uploaded (new or updated)
|
//! Number of hardware buffers uploaded (new or updated)
|
||||||
u32 HWBuffersUploaded = 0;
|
u32 HWBuffersUploaded = 0;
|
||||||
//! Sum of uploaded hardware buffer size
|
//! Number of active hardware buffers
|
||||||
u32 HWBuffersUploadedSize = 0;
|
u32 HWBuffersActive = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Interface to driver which is able to perform 2d and 3d graphics functions.
|
//! Interface to driver which is able to perform 2d and 3d graphics functions.
|
||||||
|
@ -310,6 +310,18 @@ public:
|
||||||
0 or another texture first. */
|
0 or another texture first. */
|
||||||
virtual void removeAllTextures() = 0;
|
virtual void removeAllTextures() = 0;
|
||||||
|
|
||||||
|
//! Eagerly upload buffer to hardware
|
||||||
|
/** This can be a good idea if you have a newly created or modified buffer,
|
||||||
|
which you know you will draw in the near future (e.g. end of same frame,
|
||||||
|
or next frame), because it gives the GPU driver to copy the contents. */
|
||||||
|
virtual void updateHardwareBuffer(const scene::IVertexBuffer *vb) = 0;
|
||||||
|
|
||||||
|
//! Eagerly upload buffer to hardware
|
||||||
|
/** This can be a good idea if you have a newly created or modified buffer,
|
||||||
|
which you know you will draw in the near future (e.g. end of same frame,
|
||||||
|
or next frame), because it gives the GPU driver to copy the contents. */
|
||||||
|
virtual void updateHardwareBuffer(const scene::IIndexBuffer *ib) = 0;
|
||||||
|
|
||||||
//! Remove hardware buffer
|
//! Remove hardware buffer
|
||||||
virtual void removeHardwareBuffer(const scene::IVertexBuffer *vb) = 0;
|
virtual void removeHardwareBuffer(const scene::IVertexBuffer *vb) = 0;
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,7 @@ struct SAnimatedMesh final : public IAnimatedMesh
|
||||||
std::vector<IMesh *> Meshes;
|
std::vector<IMesh *> Meshes;
|
||||||
|
|
||||||
//! The bounding box of this mesh
|
//! The bounding box of this mesh
|
||||||
core::aabbox3d<f32> Box;
|
core::aabbox3d<f32> Box{{0.0f, 0.0f, 0.0f}};
|
||||||
|
|
||||||
//! Default animation speed of this mesh.
|
//! Default animation speed of this mesh.
|
||||||
f32 FramesPerSecond;
|
f32 FramesPerSecond;
|
||||||
|
|
|
@ -133,7 +133,7 @@ struct SMesh final : public IMesh
|
||||||
std::vector<u32> TextureSlots;
|
std::vector<u32> TextureSlots;
|
||||||
|
|
||||||
//! The bounding box of this mesh
|
//! The bounding box of this mesh
|
||||||
core::aabbox3d<f32> BoundingBox;
|
core::aabbox3d<f32> BoundingBox{{0, 0, 0}};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace scene
|
} // end namespace scene
|
||||||
|
|
|
@ -228,7 +228,7 @@ public:
|
||||||
video::SMaterial Material;
|
video::SMaterial Material;
|
||||||
video::E_VERTEX_TYPE VertexType;
|
video::E_VERTEX_TYPE VertexType;
|
||||||
|
|
||||||
core::aabbox3d<f32> BoundingBox;
|
core::aabbox3d<f32> BoundingBox{{0, 0, 0}};
|
||||||
|
|
||||||
//! Primitive type used for rendering (triangles, lines, ...)
|
//! Primitive type used for rendering (triangles, lines, ...)
|
||||||
E_PRIMITIVE_TYPE PrimitiveType;
|
E_PRIMITIVE_TYPE PrimitiveType;
|
||||||
|
|
|
@ -117,7 +117,7 @@ struct SViewFrustum
|
||||||
core::plane3d<f32> planes[VF_PLANE_COUNT];
|
core::plane3d<f32> planes[VF_PLANE_COUNT];
|
||||||
|
|
||||||
//! bounding box around the view frustum
|
//! bounding box around the view frustum
|
||||||
core::aabbox3d<f32> boundingBox;
|
core::aabbox3d<f32> boundingBox{{0, 0, 0}};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! Hold a copy of important transform matrices
|
//! Hold a copy of important transform matrices
|
||||||
|
|
|
@ -137,7 +137,7 @@ public:
|
||||||
//! Moves the mesh into static position.
|
//! Moves the mesh into static position.
|
||||||
void resetAnimation();
|
void resetAnimation();
|
||||||
|
|
||||||
virtual void updateBoundingBox();
|
void updateBoundingBox();
|
||||||
|
|
||||||
//! Recovers the joints from the mesh
|
//! Recovers the joints from the mesh
|
||||||
void recoverJointsFromMesh(std::vector<IBoneSceneNode *> &jointChildSceneNodes);
|
void recoverJointsFromMesh(std::vector<IBoneSceneNode *> &jointChildSceneNodes);
|
||||||
|
@ -370,7 +370,7 @@ protected:
|
||||||
// doesn't allow taking a reference to individual elements.
|
// doesn't allow taking a reference to individual elements.
|
||||||
std::vector<std::vector<char>> Vertices_Moved;
|
std::vector<std::vector<char>> Vertices_Moved;
|
||||||
|
|
||||||
core::aabbox3d<f32> BoundingBox;
|
core::aabbox3d<f32> BoundingBox{{0, 0, 0}};
|
||||||
|
|
||||||
f32 EndFrame;
|
f32 EndFrame;
|
||||||
f32 FramesPerSecond;
|
f32 FramesPerSecond;
|
||||||
|
|
|
@ -20,9 +20,7 @@ template <class T>
|
||||||
class aabbox3d
|
class aabbox3d
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//! Default Constructor.
|
constexpr aabbox3d() = delete;
|
||||||
constexpr aabbox3d() :
|
|
||||||
MinEdge(-1, -1, -1), MaxEdge(1, 1, 1) {}
|
|
||||||
//! Constructor with min edge and max edge.
|
//! Constructor with min edge and max edge.
|
||||||
constexpr aabbox3d(const vector3d<T> &min, const vector3d<T> &max) :
|
constexpr aabbox3d(const vector3d<T> &min, const vector3d<T> &max) :
|
||||||
MinEdge(min), MaxEdge(max) {}
|
MinEdge(min), MaxEdge(max) {}
|
||||||
|
|
|
@ -145,7 +145,7 @@ private:
|
||||||
void beginTransition();
|
void beginTransition();
|
||||||
|
|
||||||
core::array<video::SMaterial> Materials;
|
core::array<video::SMaterial> Materials;
|
||||||
core::aabbox3d<f32> Box;
|
core::aabbox3d<f32> Box{{0.0f, 0.0f, 0.0f}};
|
||||||
IAnimatedMesh *Mesh;
|
IAnimatedMesh *Mesh;
|
||||||
|
|
||||||
f32 StartFrame;
|
f32 StartFrame;
|
||||||
|
|
|
@ -104,7 +104,7 @@ private:
|
||||||
/** Note that we can't use the real boundingbox for culling because at that point
|
/** Note that we can't use the real boundingbox for culling because at that point
|
||||||
the camera which is used to calculate the billboard is not yet updated. So we only
|
the camera which is used to calculate the billboard is not yet updated. So we only
|
||||||
know the real boundingbox after rendering - which is too late for culling. */
|
know the real boundingbox after rendering - which is too late for culling. */
|
||||||
core::aabbox3d<f32> BBoxSafe;
|
core::aabbox3d<f32> BBoxSafe{{0.0f, 0.0f, 0.0f}};
|
||||||
|
|
||||||
scene::SMeshBuffer *Buffer;
|
scene::SMeshBuffer *Buffer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,7 +60,7 @@ private:
|
||||||
|
|
||||||
u32 BoneIndex;
|
u32 BoneIndex;
|
||||||
|
|
||||||
core::aabbox3d<f32> Box;
|
core::aabbox3d<f32> Box{-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f};
|
||||||
|
|
||||||
E_BONE_ANIMATION_MODE AnimationMode;
|
E_BONE_ANIMATION_MODE AnimationMode;
|
||||||
E_BONE_SKINNING_SPACE SkinningSpace;
|
E_BONE_SKINNING_SPACE SkinningSpace;
|
||||||
|
|
|
@ -48,7 +48,7 @@ private:
|
||||||
void setPosition(const core::vector3df &newpos) override;
|
void setPosition(const core::vector3df &newpos) override;
|
||||||
|
|
||||||
core::matrix4 RelativeTransformationMatrix;
|
core::matrix4 RelativeTransformationMatrix;
|
||||||
core::aabbox3d<f32> Box;
|
core::aabbox3d<f32> Box{{0, 0, 0}};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace scene
|
} // end namespace scene
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
ISceneNode *clone(ISceneNode *newParent = 0, ISceneManager *newManager = 0) override;
|
ISceneNode *clone(ISceneNode *newParent = 0, ISceneManager *newManager = 0) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
core::aabbox3d<f32> Box;
|
core::aabbox3d<f32> Box{{0, 0, 0}};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace scene
|
} // end namespace scene
|
||||||
|
|
|
@ -677,8 +677,17 @@ void SelfType::MeshExtractor::loadAnimation(const std::size_t animIdx)
|
||||||
for (const auto &channel : anim.channels) {
|
for (const auto &channel : anim.channels) {
|
||||||
|
|
||||||
const auto &sampler = anim.samplers.at(channel.sampler);
|
const auto &sampler = anim.samplers.at(channel.sampler);
|
||||||
if (sampler.interpolation != tiniergltf::AnimationSampler::Interpolation::LINEAR)
|
|
||||||
throw std::runtime_error("unsupported interpolation, only linear interpolation is supported");
|
bool interpolate = ([&]() {
|
||||||
|
switch (sampler.interpolation) {
|
||||||
|
case tiniergltf::AnimationSampler::Interpolation::STEP:
|
||||||
|
return false;
|
||||||
|
case tiniergltf::AnimationSampler::Interpolation::LINEAR:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Only STEP and LINEAR keyframe interpolation are supported");
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
const auto inputAccessor = Accessor<f32>::make(m_gltf_model, sampler.input);
|
const auto inputAccessor = Accessor<f32>::make(m_gltf_model, sampler.input);
|
||||||
const auto n_frames = inputAccessor.getCount();
|
const auto n_frames = inputAccessor.getCount();
|
||||||
|
@ -686,32 +695,38 @@ void SelfType::MeshExtractor::loadAnimation(const std::size_t animIdx)
|
||||||
if (!channel.target.node.has_value())
|
if (!channel.target.node.has_value())
|
||||||
throw std::runtime_error("no animated node");
|
throw std::runtime_error("no animated node");
|
||||||
|
|
||||||
const auto &joint = m_loaded_nodes.at(*channel.target.node);
|
auto *joint = m_loaded_nodes.at(*channel.target.node);
|
||||||
switch (channel.target.path) {
|
switch (channel.target.path) {
|
||||||
case tiniergltf::AnimationChannelTarget::Path::TRANSLATION: {
|
case tiniergltf::AnimationChannelTarget::Path::TRANSLATION: {
|
||||||
const auto outputAccessor = Accessor<core::vector3df>::make(m_gltf_model, sampler.output);
|
const auto outputAccessor = Accessor<core::vector3df>::make(m_gltf_model, sampler.output);
|
||||||
|
auto &channel = joint->keys.position;
|
||||||
|
channel.interpolate = interpolate;
|
||||||
for (std::size_t i = 0; i < n_frames; ++i) {
|
for (std::size_t i = 0; i < n_frames; ++i) {
|
||||||
f32 frame = inputAccessor.get(i);
|
f32 frame = inputAccessor.get(i);
|
||||||
core::vector3df position = outputAccessor.get(i);
|
core::vector3df position = outputAccessor.get(i);
|
||||||
m_irr_model->addPositionKey(joint, frame, convertHandedness(position));
|
channel.pushBack(frame, convertHandedness(position));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case tiniergltf::AnimationChannelTarget::Path::ROTATION: {
|
case tiniergltf::AnimationChannelTarget::Path::ROTATION: {
|
||||||
const auto outputAccessor = Accessor<core::quaternion>::make(m_gltf_model, sampler.output);
|
const auto outputAccessor = Accessor<core::quaternion>::make(m_gltf_model, sampler.output);
|
||||||
|
auto &channel = joint->keys.rotation;
|
||||||
|
channel.interpolate = interpolate;
|
||||||
for (std::size_t i = 0; i < n_frames; ++i) {
|
for (std::size_t i = 0; i < n_frames; ++i) {
|
||||||
f32 frame = inputAccessor.get(i);
|
f32 frame = inputAccessor.get(i);
|
||||||
core::quaternion rotation = outputAccessor.get(i);
|
core::quaternion rotation = outputAccessor.get(i);
|
||||||
m_irr_model->addRotationKey(joint, frame, convertHandedness(rotation));
|
channel.pushBack(frame, convertHandedness(rotation));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case tiniergltf::AnimationChannelTarget::Path::SCALE: {
|
case tiniergltf::AnimationChannelTarget::Path::SCALE: {
|
||||||
const auto outputAccessor = Accessor<core::vector3df>::make(m_gltf_model, sampler.output);
|
const auto outputAccessor = Accessor<core::vector3df>::make(m_gltf_model, sampler.output);
|
||||||
|
auto &channel = joint->keys.scale;
|
||||||
|
channel.interpolate = interpolate;
|
||||||
for (std::size_t i = 0; i < n_frames; ++i) {
|
for (std::size_t i = 0; i < n_frames; ++i) {
|
||||||
f32 frame = inputAccessor.get(i);
|
f32 frame = inputAccessor.get(i);
|
||||||
core::vector3df scale = outputAccessor.get(i);
|
core::vector3df scale = outputAccessor.get(i);
|
||||||
m_irr_model->addScaleKey(joint, frame, scale);
|
channel.pushBack(frame, scale);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -788,9 +788,9 @@ void CGUIEditBox::draw()
|
||||||
mbegin = font->getDimension(s.c_str()).Width;
|
mbegin = font->getDimension(s.c_str()).Width;
|
||||||
|
|
||||||
// deal with kerning
|
// deal with kerning
|
||||||
mbegin += font->getKerningWidth(
|
mbegin += font->getKerning(
|
||||||
&((*txtLine)[realmbgn - startPos]),
|
(*txtLine)[realmbgn - startPos],
|
||||||
realmbgn - startPos > 0 ? &((*txtLine)[realmbgn - startPos - 1]) : 0);
|
realmbgn - startPos > 0 ? (*txtLine)[realmbgn - startPos - 1] : 0).X;
|
||||||
|
|
||||||
lineStartPos = realmbgn - startPos;
|
lineStartPos = realmbgn - startPos;
|
||||||
}
|
}
|
||||||
|
@ -832,7 +832,8 @@ void CGUIEditBox::draw()
|
||||||
}
|
}
|
||||||
s = txtLine->subString(0, CursorPos - startPos);
|
s = txtLine->subString(0, CursorPos - startPos);
|
||||||
charcursorpos = font->getDimension(s.c_str()).Width +
|
charcursorpos = font->getDimension(s.c_str()).Width +
|
||||||
font->getKerningWidth(CursorChar.c_str(), CursorPos - startPos > 0 ? &((*txtLine)[CursorPos - startPos - 1]) : 0);
|
font->getKerning(CursorChar[0],
|
||||||
|
CursorPos - startPos > 0 ? (*txtLine)[CursorPos - startPos - 1] : 0).X;
|
||||||
|
|
||||||
if (focus && (CursorBlinkTime == 0 || (os::Timer::getTime() - BlinkStartTime) % (2 * CursorBlinkTime) < CursorBlinkTime)) {
|
if (focus && (CursorBlinkTime == 0 || (os::Timer::getTime() - BlinkStartTime) % (2 * CursorBlinkTime) < CursorBlinkTime)) {
|
||||||
setTextRect(cursorLine);
|
setTextRect(cursorLine);
|
||||||
|
@ -1194,7 +1195,7 @@ void CGUIEditBox::setTextRect(s32 line)
|
||||||
d = font->getDimension(Text.c_str());
|
d = font->getDimension(Text.c_str());
|
||||||
d.Height = AbsoluteRect.getHeight();
|
d.Height = AbsoluteRect.getHeight();
|
||||||
}
|
}
|
||||||
d.Height += font->getKerningHeight();
|
d.Height += font->getKerning(L'A').Y;
|
||||||
|
|
||||||
// justification
|
// justification
|
||||||
switch (HAlign) {
|
switch (HAlign) {
|
||||||
|
@ -1382,7 +1383,7 @@ void CGUIEditBox::calculateScrollPos()
|
||||||
|
|
||||||
// calculate vertical scrolling
|
// calculate vertical scrolling
|
||||||
if (hasBrokenText) {
|
if (hasBrokenText) {
|
||||||
irr::u32 lineHeight = font->getDimension(L"A").Height + font->getKerningHeight();
|
irr::u32 lineHeight = font->getDimension(L"A").Height + font->getKerning(L'A').Y;
|
||||||
// only up to 1 line fits?
|
// only up to 1 line fits?
|
||||||
if (lineHeight >= (irr::u32)FrameRect.getHeight()) {
|
if (lineHeight >= (irr::u32)FrameRect.getHeight()) {
|
||||||
VScrollPos = 0;
|
VScrollPos = 0;
|
||||||
|
|
|
@ -53,141 +53,6 @@ CGUIFont::~CGUIFont()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
//! loads a font file from xml
|
|
||||||
bool CGUIFont::load(io::IXMLReader* xml, const io::path& directory)
|
|
||||||
{
|
|
||||||
if (!SpriteBank)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SpriteBank->clear();
|
|
||||||
|
|
||||||
while (xml->read())
|
|
||||||
{
|
|
||||||
if (io::EXN_ELEMENT == xml->getNodeType())
|
|
||||||
{
|
|
||||||
if (core::stringw(L"Texture") == xml->getNodeName())
|
|
||||||
{
|
|
||||||
// add a texture
|
|
||||||
core::stringc fn = xml->getAttributeValue(L"filename");
|
|
||||||
u32 i = (u32)xml->getAttributeValueAsInt(L"index");
|
|
||||||
core::stringw alpha = xml->getAttributeValue(L"hasAlpha");
|
|
||||||
|
|
||||||
while (i+1 > SpriteBank->getTextureCount())
|
|
||||||
SpriteBank->addTexture(0);
|
|
||||||
|
|
||||||
bool flags[3];
|
|
||||||
pushTextureCreationFlags(flags);
|
|
||||||
|
|
||||||
// load texture
|
|
||||||
io::path textureFullName = core::mergeFilename(directory, fn);
|
|
||||||
SpriteBank->setTexture(i, Driver->getTexture(textureFullName));
|
|
||||||
|
|
||||||
popTextureCreationFlags(flags);
|
|
||||||
|
|
||||||
// couldn't load texture, abort.
|
|
||||||
if (!SpriteBank->getTexture(i))
|
|
||||||
{
|
|
||||||
os::Printer::log("Unable to load all textures in the font, aborting", ELL_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// colorkey texture rather than alpha channel?
|
|
||||||
if (alpha == core::stringw("false"))
|
|
||||||
Driver->makeColorKeyTexture(SpriteBank->getTexture(i), core::position2di(0,0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (core::stringw(L"c") == xml->getNodeName())
|
|
||||||
{
|
|
||||||
// adding a character to this font
|
|
||||||
SFontArea a;
|
|
||||||
SGUISpriteFrame f;
|
|
||||||
SGUISprite s;
|
|
||||||
core::rect<s32> rectangle;
|
|
||||||
|
|
||||||
a.underhang = xml->getAttributeValueAsInt(L"u");
|
|
||||||
a.overhang = xml->getAttributeValueAsInt(L"o");
|
|
||||||
a.spriteno = SpriteBank->getSprites().size();
|
|
||||||
s32 texno = xml->getAttributeValueAsInt(L"i");
|
|
||||||
|
|
||||||
// parse rectangle
|
|
||||||
core::stringc rectstr = xml->getAttributeValue(L"r");
|
|
||||||
wchar_t ch = xml->getAttributeValue(L"c")[0];
|
|
||||||
|
|
||||||
const c8 *c = rectstr.c_str();
|
|
||||||
s32 val;
|
|
||||||
val = 0;
|
|
||||||
while (*c >= '0' && *c <= '9')
|
|
||||||
{
|
|
||||||
val *= 10;
|
|
||||||
val += *c - '0';
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
rectangle.UpperLeftCorner.X = val;
|
|
||||||
while (*c == L' ' || *c == L',') c++;
|
|
||||||
|
|
||||||
val = 0;
|
|
||||||
while (*c >= '0' && *c <= '9')
|
|
||||||
{
|
|
||||||
val *= 10;
|
|
||||||
val += *c - '0';
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
rectangle.UpperLeftCorner.Y = val;
|
|
||||||
while (*c == L' ' || *c == L',') c++;
|
|
||||||
|
|
||||||
val = 0;
|
|
||||||
while (*c >= '0' && *c <= '9')
|
|
||||||
{
|
|
||||||
val *= 10;
|
|
||||||
val += *c - '0';
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
rectangle.LowerRightCorner.X = val;
|
|
||||||
while (*c == L' ' || *c == L',') c++;
|
|
||||||
|
|
||||||
val = 0;
|
|
||||||
while (*c >= '0' && *c <= '9')
|
|
||||||
{
|
|
||||||
val *= 10;
|
|
||||||
val += *c - '0';
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
rectangle.LowerRightCorner.Y = val;
|
|
||||||
|
|
||||||
CharacterMap.emplace(ch, Areas.size());
|
|
||||||
|
|
||||||
// make frame
|
|
||||||
f.rectNumber = SpriteBank->getPositions().size();
|
|
||||||
f.textureNumber = texno;
|
|
||||||
|
|
||||||
// add frame to sprite
|
|
||||||
s.Frames.push_back(f);
|
|
||||||
s.frameTime = 0;
|
|
||||||
|
|
||||||
// add rectangle to sprite bank
|
|
||||||
SpriteBank->getPositions().push_back(rectangle);
|
|
||||||
a.width = rectangle.getWidth();
|
|
||||||
|
|
||||||
// add sprite to sprite bank
|
|
||||||
SpriteBank->getSprites().push_back(s);
|
|
||||||
|
|
||||||
// add character to font
|
|
||||||
Areas.push_back(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set bad character
|
|
||||||
WrongCharacter = getAreaFromCharacter(L' ');
|
|
||||||
|
|
||||||
setMaxHeight();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void CGUIFont::setMaxHeight()
|
void CGUIFont::setMaxHeight()
|
||||||
{
|
{
|
||||||
if (!SpriteBank)
|
if (!SpriteBank)
|
||||||
|
@ -365,17 +230,15 @@ void CGUIFont::setKerningWidth(s32 kerning)
|
||||||
GlobalKerningWidth = kerning;
|
GlobalKerningWidth = kerning;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! set an Pixel Offset on Drawing ( scale position on width )
|
core::vector2di CGUIFont::getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const
|
||||||
s32 CGUIFont::getKerningWidth(const wchar_t *thisLetter, const wchar_t *previousLetter) const
|
|
||||||
{
|
{
|
||||||
s32 ret = GlobalKerningWidth;
|
core::vector2di ret(GlobalKerningWidth, GlobalKerningHeight);
|
||||||
|
|
||||||
if (thisLetter) {
|
if (thisLetter) {
|
||||||
ret += Areas[getAreaFromCharacter(*thisLetter)].overhang;
|
ret.X += Areas[getAreaFromCharacter(thisLetter)].overhang;
|
||||||
|
|
||||||
if (previousLetter) {
|
if (previousLetter)
|
||||||
ret += Areas[getAreaFromCharacter(*previousLetter)].underhang;
|
ret.X += Areas[getAreaFromCharacter(previousLetter)].underhang;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -387,12 +250,6 @@ void CGUIFont::setKerningHeight(s32 kerning)
|
||||||
GlobalKerningHeight = kerning;
|
GlobalKerningHeight = kerning;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! set an Pixel Offset on Drawing ( scale position on height )
|
|
||||||
s32 CGUIFont::getKerningHeight() const
|
|
||||||
{
|
|
||||||
return GlobalKerningHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! returns the sprite number from a given character
|
//! returns the sprite number from a given character
|
||||||
u32 CGUIFont::getSpriteNoFromChar(const wchar_t *c) const
|
u32 CGUIFont::getSpriteNoFromChar(const wchar_t *c) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,8 +58,7 @@ public:
|
||||||
void setKerningHeight(s32 kerning) override;
|
void setKerningHeight(s32 kerning) override;
|
||||||
|
|
||||||
//! set an Pixel Offset on Drawing ( scale position on width )
|
//! set an Pixel Offset on Drawing ( scale position on width )
|
||||||
s32 getKerningWidth(const wchar_t *thisLetter = 0, const wchar_t *previousLetter = 0) const override;
|
core::vector2di getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const override;
|
||||||
s32 getKerningHeight() const override;
|
|
||||||
|
|
||||||
//! gets the sprite bank
|
//! gets the sprite bank
|
||||||
IGUISpriteBank *getSpriteBank() const override;
|
IGUISpriteBank *getSpriteBank() const override;
|
||||||
|
|
|
@ -74,10 +74,12 @@ void CGUIStaticText::draw()
|
||||||
IGUIFont *font = getActiveFont();
|
IGUIFont *font = getActiveFont();
|
||||||
|
|
||||||
if (font) {
|
if (font) {
|
||||||
|
s32 kerningHeight = font->getKerning(L'A').Y;
|
||||||
|
|
||||||
if (!WordWrap) {
|
if (!WordWrap) {
|
||||||
if (VAlign == EGUIA_LOWERRIGHT) {
|
if (VAlign == EGUIA_LOWERRIGHT) {
|
||||||
frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y -
|
frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y -
|
||||||
font->getDimension(L"A").Height - font->getKerningHeight();
|
font->getDimension(L"A").Height - kerningHeight;
|
||||||
}
|
}
|
||||||
if (HAlign == EGUIA_LOWERRIGHT) {
|
if (HAlign == EGUIA_LOWERRIGHT) {
|
||||||
frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
|
frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
|
||||||
|
@ -92,7 +94,7 @@ void CGUIStaticText::draw()
|
||||||
breakText();
|
breakText();
|
||||||
|
|
||||||
core::rect<s32> r = frameRect;
|
core::rect<s32> r = frameRect;
|
||||||
s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
|
s32 height = font->getDimension(L"A").Height + kerningHeight;
|
||||||
s32 totalHeight = height * BrokenText.size();
|
s32 totalHeight = height * BrokenText.size();
|
||||||
if (VAlign == EGUIA_CENTER) {
|
if (VAlign == EGUIA_CENTER) {
|
||||||
r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
|
r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
|
||||||
|
@ -471,7 +473,7 @@ s32 CGUIStaticText::getTextHeight() const
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (WordWrap) {
|
if (WordWrap) {
|
||||||
s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
|
s32 height = font->getDimension(L"A").Height + font->getKerning(L'A').Y;
|
||||||
return height * BrokenText.size();
|
return height * BrokenText.size();
|
||||||
} else {
|
} else {
|
||||||
// TODO: Text can have multiple lines which are not in BrokenText
|
// TODO: Text can have multiple lines which are not in BrokenText
|
||||||
|
|
|
@ -348,6 +348,7 @@ if(ENABLE_OPENGL3 OR ENABLE_GLES2)
|
||||||
OpenGL/FixedPipelineRenderer.cpp
|
OpenGL/FixedPipelineRenderer.cpp
|
||||||
OpenGL/MaterialRenderer.cpp
|
OpenGL/MaterialRenderer.cpp
|
||||||
OpenGL/Renderer2D.cpp
|
OpenGL/Renderer2D.cpp
|
||||||
|
OpenGL/VBO.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ protected:
|
||||||
void copyMaterials();
|
void copyMaterials();
|
||||||
|
|
||||||
core::array<video::SMaterial> Materials;
|
core::array<video::SMaterial> Materials;
|
||||||
core::aabbox3d<f32> Box;
|
core::aabbox3d<f32> Box{{0, 0, 0}};
|
||||||
video::SMaterial ReadOnlyMaterial;
|
video::SMaterial ReadOnlyMaterial;
|
||||||
|
|
||||||
IMesh *Mesh;
|
IMesh *Mesh;
|
||||||
|
|
|
@ -218,7 +218,7 @@ bool CNullDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u
|
||||||
bool CNullDriver::endScene()
|
bool CNullDriver::endScene()
|
||||||
{
|
{
|
||||||
FPSCounter.registerFrame(os::Timer::getRealTime());
|
FPSCounter.registerFrame(os::Timer::getRealTime());
|
||||||
updateAllHardwareBuffers();
|
expireHardwareBuffers();
|
||||||
updateAllOcclusionQueries();
|
updateAllOcclusionQueries();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1141,32 +1141,68 @@ CNullDriver::SHWBufferLink *CNullDriver::getBufferLink(const scene::IIndexBuffer
|
||||||
return createHardwareBuffer(ib); // no hardware links, and mesh wants one, create it
|
return createHardwareBuffer(ib); // no hardware links, and mesh wants one, create it
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Update all hardware buffers, remove unused ones
|
void CNullDriver::registerHardwareBuffer(SHWBufferLink *HWBuffer)
|
||||||
void CNullDriver::updateAllHardwareBuffers()
|
|
||||||
{
|
{
|
||||||
auto it = HWBufferList.begin();
|
_IRR_DEBUG_BREAK_IF(!HWBuffer)
|
||||||
while (it != HWBufferList.end()) {
|
HWBuffer->ListPosition = HWBufferList.size();
|
||||||
SHWBufferLink *Link = *it;
|
HWBufferList.push_back(HWBuffer);
|
||||||
++it;
|
}
|
||||||
|
|
||||||
if (Link->IsVertex) {
|
void CNullDriver::expireHardwareBuffers()
|
||||||
if (!Link->VertexBuffer || Link->VertexBuffer->getReferenceCount() == 1)
|
{
|
||||||
deleteHardwareBuffer(Link);
|
for (size_t i = 0; i < HWBufferList.size(); ) {
|
||||||
} else {
|
auto *Link = HWBufferList[i];
|
||||||
if (!Link->IndexBuffer || Link->IndexBuffer->getReferenceCount() == 1)
|
|
||||||
deleteHardwareBuffer(Link);
|
bool del;
|
||||||
}
|
if (Link->IsVertex)
|
||||||
|
del = !Link->VertexBuffer || Link->VertexBuffer->getReferenceCount() == 1;
|
||||||
|
else
|
||||||
|
del = !Link->IndexBuffer || Link->IndexBuffer->getReferenceCount() == 1;
|
||||||
|
// deleting can reorder, so don't advance in list
|
||||||
|
if (del)
|
||||||
|
deleteHardwareBuffer(Link);
|
||||||
|
else
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FrameStats.HWBuffersActive = HWBufferList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNullDriver::deleteHardwareBuffer(SHWBufferLink *HWBuffer)
|
void CNullDriver::deleteHardwareBuffer(SHWBufferLink *HWBuffer)
|
||||||
{
|
{
|
||||||
if (!HWBuffer)
|
if (!HWBuffer)
|
||||||
return;
|
return;
|
||||||
HWBufferList.erase(HWBuffer->listPosition);
|
const size_t pos = HWBuffer->ListPosition;
|
||||||
|
_IRR_DEBUG_BREAK_IF(HWBufferList.at(pos) != HWBuffer)
|
||||||
|
if (HWBufferList.size() < 2 || pos == HWBufferList.size() - 1) {
|
||||||
|
HWBufferList.erase(HWBufferList.begin() + pos);
|
||||||
|
} else {
|
||||||
|
// swap with last
|
||||||
|
std::swap(HWBufferList[pos], HWBufferList.back());
|
||||||
|
HWBufferList.pop_back();
|
||||||
|
HWBufferList[pos]->ListPosition = pos;
|
||||||
|
}
|
||||||
delete HWBuffer;
|
delete HWBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CNullDriver::updateHardwareBuffer(const scene::IVertexBuffer *vb)
|
||||||
|
{
|
||||||
|
if (!vb)
|
||||||
|
return;
|
||||||
|
auto *link = getBufferLink(vb);
|
||||||
|
if (link)
|
||||||
|
updateHardwareBuffer(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNullDriver::updateHardwareBuffer(const scene::IIndexBuffer *ib)
|
||||||
|
{
|
||||||
|
if (!ib)
|
||||||
|
return;
|
||||||
|
auto *link = getBufferLink(ib);
|
||||||
|
if (link)
|
||||||
|
updateHardwareBuffer(link);
|
||||||
|
}
|
||||||
|
|
||||||
void CNullDriver::removeHardwareBuffer(const scene::IVertexBuffer *vb)
|
void CNullDriver::removeHardwareBuffer(const scene::IVertexBuffer *vb)
|
||||||
{
|
{
|
||||||
if (!vb)
|
if (!vb)
|
||||||
|
@ -1484,34 +1520,24 @@ IGPUProgrammingServices *CNullDriver::getGPUProgrammingServices()
|
||||||
//! Adds a new material renderer to the VideoDriver, based on a high level shading language.
|
//! Adds a new material renderer to the VideoDriver, based on a high level shading language.
|
||||||
s32 CNullDriver::addHighLevelShaderMaterial(
|
s32 CNullDriver::addHighLevelShaderMaterial(
|
||||||
const c8 *vertexShaderProgram,
|
const c8 *vertexShaderProgram,
|
||||||
const c8 *vertexShaderEntryPointName,
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
|
||||||
const c8 *pixelShaderProgram,
|
const c8 *pixelShaderProgram,
|
||||||
const c8 *pixelShaderEntryPointName,
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
|
||||||
const c8 *geometryShaderProgram,
|
const c8 *geometryShaderProgram,
|
||||||
const c8 *geometryShaderEntryPointName,
|
const c8 *shaderName,
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
|
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
|
||||||
u32 verticesOut,
|
u32 verticesOut,
|
||||||
IShaderConstantSetCallBack *callback,
|
IShaderConstantSetCallBack *callback,
|
||||||
E_MATERIAL_TYPE baseMaterial,
|
E_MATERIAL_TYPE baseMaterial,
|
||||||
s32 userData)
|
s32 userData)
|
||||||
{
|
{
|
||||||
os::Printer::log("High level shader materials not available (yet) in this driver, sorry");
|
os::Printer::log("Shader materials not available in this driver", ELL_ERROR);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
|
s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
|
||||||
const io::path &vertexShaderProgramFileName,
|
const io::path &vertexShaderProgramFileName,
|
||||||
const c8 *vertexShaderEntryPointName,
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
|
||||||
const io::path &pixelShaderProgramFileName,
|
const io::path &pixelShaderProgramFileName,
|
||||||
const c8 *pixelShaderEntryPointName,
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
|
||||||
const io::path &geometryShaderProgramFileName,
|
const io::path &geometryShaderProgramFileName,
|
||||||
const c8 *geometryShaderEntryPointName,
|
const c8 *shaderName,
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
|
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
|
||||||
u32 verticesOut,
|
u32 verticesOut,
|
||||||
IShaderConstantSetCallBack *callback,
|
IShaderConstantSetCallBack *callback,
|
||||||
|
@ -1547,9 +1573,7 @@ s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 result = addHighLevelShaderMaterialFromFiles(
|
s32 result = addHighLevelShaderMaterialFromFiles(
|
||||||
vsfile, vertexShaderEntryPointName, vsCompileTarget,
|
vsfile, psfile, gsfile, shaderName,
|
||||||
psfile, pixelShaderEntryPointName, psCompileTarget,
|
|
||||||
gsfile, geometryShaderEntryPointName, gsCompileTarget,
|
|
||||||
inType, outType, verticesOut,
|
inType, outType, verticesOut,
|
||||||
callback, baseMaterial, userData);
|
callback, baseMaterial, userData);
|
||||||
|
|
||||||
|
@ -1567,14 +1591,9 @@ s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
|
||||||
|
|
||||||
s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
|
s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
|
||||||
io::IReadFile *vertexShaderProgram,
|
io::IReadFile *vertexShaderProgram,
|
||||||
const c8 *vertexShaderEntryPointName,
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
|
||||||
io::IReadFile *pixelShaderProgram,
|
io::IReadFile *pixelShaderProgram,
|
||||||
const c8 *pixelShaderEntryPointName,
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
|
||||||
io::IReadFile *geometryShaderProgram,
|
io::IReadFile *geometryShaderProgram,
|
||||||
const c8 *geometryShaderEntryPointName,
|
const c8 *shaderName,
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
|
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
|
||||||
u32 verticesOut,
|
u32 verticesOut,
|
||||||
IShaderConstantSetCallBack *callback,
|
IShaderConstantSetCallBack *callback,
|
||||||
|
@ -1620,9 +1639,7 @@ s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 result = this->addHighLevelShaderMaterial(
|
s32 result = this->addHighLevelShaderMaterial(
|
||||||
vs, vertexShaderEntryPointName, vsCompileTarget,
|
vs, ps, gs, shaderName,
|
||||||
ps, pixelShaderEntryPointName, psCompileTarget,
|
|
||||||
gs, geometryShaderEntryPointName, gsCompileTarget,
|
|
||||||
inType, outType, verticesOut,
|
inType, outType, verticesOut,
|
||||||
callback, baseMaterial, userData);
|
callback, baseMaterial, userData);
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include "S3DVertex.h"
|
#include "S3DVertex.h"
|
||||||
#include "SVertexIndex.h"
|
#include "SVertexIndex.h"
|
||||||
#include "SExposedVideoData.h"
|
#include "SExposedVideoData.h"
|
||||||
#include <list>
|
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
|
@ -293,7 +292,7 @@ protected:
|
||||||
struct SHWBufferLink
|
struct SHWBufferLink
|
||||||
{
|
{
|
||||||
SHWBufferLink(const scene::IVertexBuffer *vb) :
|
SHWBufferLink(const scene::IVertexBuffer *vb) :
|
||||||
VertexBuffer(vb), ChangedID(0), IsVertex(true)
|
VertexBuffer(vb), IsVertex(true)
|
||||||
{
|
{
|
||||||
if (VertexBuffer) {
|
if (VertexBuffer) {
|
||||||
VertexBuffer->grab();
|
VertexBuffer->grab();
|
||||||
|
@ -301,7 +300,7 @@ protected:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SHWBufferLink(const scene::IIndexBuffer *ib) :
|
SHWBufferLink(const scene::IIndexBuffer *ib) :
|
||||||
IndexBuffer(ib), ChangedID(0), IsVertex(false)
|
IndexBuffer(ib), IsVertex(false)
|
||||||
{
|
{
|
||||||
if (IndexBuffer) {
|
if (IndexBuffer) {
|
||||||
IndexBuffer->grab();
|
IndexBuffer->grab();
|
||||||
|
@ -324,9 +323,9 @@ protected:
|
||||||
const scene::IVertexBuffer *VertexBuffer;
|
const scene::IVertexBuffer *VertexBuffer;
|
||||||
const scene::IIndexBuffer *IndexBuffer;
|
const scene::IIndexBuffer *IndexBuffer;
|
||||||
};
|
};
|
||||||
u32 ChangedID;
|
size_t ListPosition = static_cast<size_t>(-1);
|
||||||
|
u32 ChangedID = 0;
|
||||||
bool IsVertex;
|
bool IsVertex;
|
||||||
std::list<SHWBufferLink*>::iterator listPosition;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Gets hardware buffer link from a vertex buffer (may create or update buffer)
|
//! Gets hardware buffer link from a vertex buffer (may create or update buffer)
|
||||||
|
@ -348,6 +347,10 @@ protected:
|
||||||
virtual SHWBufferLink *createHardwareBuffer(const scene::IIndexBuffer *ib) { return 0; }
|
virtual SHWBufferLink *createHardwareBuffer(const scene::IIndexBuffer *ib) { return 0; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
virtual void updateHardwareBuffer(const scene::IVertexBuffer *vb) override;
|
||||||
|
|
||||||
|
virtual void updateHardwareBuffer(const scene::IIndexBuffer *ib) override;
|
||||||
|
|
||||||
//! Remove hardware buffer
|
//! Remove hardware buffer
|
||||||
void removeHardwareBuffer(const scene::IVertexBuffer *vb) override;
|
void removeHardwareBuffer(const scene::IVertexBuffer *vb) override;
|
||||||
|
|
||||||
|
@ -357,8 +360,8 @@ public:
|
||||||
//! Remove all hardware buffers
|
//! Remove all hardware buffers
|
||||||
void removeAllHardwareBuffers() override;
|
void removeAllHardwareBuffers() override;
|
||||||
|
|
||||||
//! Update all hardware buffers, remove unused ones
|
//! Run garbage-collection on all HW buffers
|
||||||
virtual void updateAllHardwareBuffers();
|
void expireHardwareBuffers();
|
||||||
|
|
||||||
//! is vbo recommended?
|
//! is vbo recommended?
|
||||||
virtual bool isHardwareBufferRecommend(const scene::IVertexBuffer *mb);
|
virtual bool isHardwareBufferRecommend(const scene::IVertexBuffer *mb);
|
||||||
|
@ -446,54 +449,39 @@ public:
|
||||||
//! Adds a new material renderer to the VideoDriver, based on a high level shading language.
|
//! Adds a new material renderer to the VideoDriver, based on a high level shading language.
|
||||||
virtual s32 addHighLevelShaderMaterial(
|
virtual s32 addHighLevelShaderMaterial(
|
||||||
const c8 *vertexShaderProgram,
|
const c8 *vertexShaderProgram,
|
||||||
const c8 *vertexShaderEntryPointName = 0,
|
const c8 *pixelShaderProgram,
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1,
|
const c8 *geometryShaderProgram,
|
||||||
const c8 *pixelShaderProgram = 0,
|
const c8 *shaderName = nullptr,
|
||||||
const c8 *pixelShaderEntryPointName = 0,
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1,
|
|
||||||
const c8 *geometryShaderProgram = 0,
|
|
||||||
const c8 *geometryShaderEntryPointName = "main",
|
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||||
u32 verticesOut = 0,
|
u32 verticesOut = 0,
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
IShaderConstantSetCallBack *callback = nullptr,
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||||
s32 userData = 0) override;
|
s32 userData = 0)override;
|
||||||
|
|
||||||
virtual s32 addHighLevelShaderMaterialFromFiles(
|
virtual s32 addHighLevelShaderMaterialFromFiles(
|
||||||
const io::path &vertexShaderProgramFile,
|
const io::path &vertexShaderProgramFileName,
|
||||||
const c8 *vertexShaderEntryPointName = "main",
|
const io::path &pixelShaderProgramFileName,
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1,
|
const io::path &geometryShaderProgramFileName,
|
||||||
const io::path &pixelShaderProgramFile = "",
|
const c8 *shaderName = nullptr,
|
||||||
const c8 *pixelShaderEntryPointName = "main",
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1,
|
|
||||||
const io::path &geometryShaderProgramFileName = "",
|
|
||||||
const c8 *geometryShaderEntryPointName = "main",
|
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||||
u32 verticesOut = 0,
|
u32 verticesOut = 0,
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
IShaderConstantSetCallBack *callback = nullptr,
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||||
s32 userData = 0) override;
|
s32 userData = 0) override;
|
||||||
|
|
||||||
virtual s32 addHighLevelShaderMaterialFromFiles(
|
s32 addHighLevelShaderMaterialFromFiles(
|
||||||
io::IReadFile *vertexShaderProgram,
|
io::IReadFile *vertexShaderProgram,
|
||||||
const c8 *vertexShaderEntryPointName = "main",
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1,
|
|
||||||
io::IReadFile *pixelShaderProgram = 0,
|
io::IReadFile *pixelShaderProgram = 0,
|
||||||
const c8 *pixelShaderEntryPointName = "main",
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1,
|
|
||||||
io::IReadFile *geometryShaderProgram = 0,
|
io::IReadFile *geometryShaderProgram = 0,
|
||||||
const c8 *geometryShaderEntryPointName = "main",
|
const c8 *shaderName = nullptr,
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||||
u32 verticesOut = 0,
|
u32 verticesOut = 0,
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
IShaderConstantSetCallBack *callback = nullptr,
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||||
s32 userData = 0) override;
|
s32 userData = 0);
|
||||||
|
|
||||||
virtual void deleteShaderMaterial(s32 material) override;
|
virtual void deleteShaderMaterial(s32 material) override;
|
||||||
|
|
||||||
|
@ -578,13 +566,16 @@ protected:
|
||||||
//! deletes all material renderers
|
//! deletes all material renderers
|
||||||
void deleteMaterialRenders();
|
void deleteMaterialRenders();
|
||||||
|
|
||||||
|
// adds a created hardware buffer to the relevant data structure
|
||||||
|
void registerHardwareBuffer(SHWBufferLink *HWBuffer);
|
||||||
|
|
||||||
// prints renderer version
|
// prints renderer version
|
||||||
void printVersion();
|
void printVersion();
|
||||||
|
|
||||||
inline void accountHWBufferUpload(u32 size)
|
inline void accountHWBufferUpload(u32 size)
|
||||||
{
|
{
|
||||||
FrameStats.HWBuffersUploaded++;
|
FrameStats.HWBuffersUploaded++;
|
||||||
FrameStats.HWBuffersUploadedSize += size;
|
(void)size;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool getWriteZBuffer(const SMaterial &material) const
|
inline bool getWriteZBuffer(const SMaterial &material) const
|
||||||
|
@ -701,7 +692,7 @@ protected:
|
||||||
core::array<video::IImageWriter *> SurfaceWriter;
|
core::array<video::IImageWriter *> SurfaceWriter;
|
||||||
core::array<SMaterialRenderer> MaterialRenderers;
|
core::array<SMaterialRenderer> MaterialRenderers;
|
||||||
|
|
||||||
std::list<SHWBufferLink *> HWBufferList;
|
std::vector<SHWBufferLink *> HWBufferList;
|
||||||
|
|
||||||
io::IFileSystem *FileSystem;
|
io::IFileSystem *FileSystem;
|
||||||
|
|
||||||
|
|
|
@ -430,9 +430,7 @@ COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::I
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
SHWBufferLink_opengl *HWBuffer = new SHWBufferLink_opengl(vb);
|
SHWBufferLink_opengl *HWBuffer = new SHWBufferLink_opengl(vb);
|
||||||
|
registerHardwareBuffer(HWBuffer);
|
||||||
// add to map
|
|
||||||
HWBuffer->listPosition = HWBufferList.insert(HWBufferList.end(), HWBuffer);
|
|
||||||
|
|
||||||
if (!updateVertexHardwareBuffer(HWBuffer)) {
|
if (!updateVertexHardwareBuffer(HWBuffer)) {
|
||||||
deleteHardwareBuffer(HWBuffer);
|
deleteHardwareBuffer(HWBuffer);
|
||||||
|
@ -453,9 +451,7 @@ COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::I
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
SHWBufferLink_opengl *HWBuffer = new SHWBufferLink_opengl(ib);
|
SHWBufferLink_opengl *HWBuffer = new SHWBufferLink_opengl(ib);
|
||||||
|
registerHardwareBuffer(HWBuffer);
|
||||||
// add to map
|
|
||||||
HWBuffer->listPosition = HWBufferList.insert(HWBufferList.end(), HWBuffer);
|
|
||||||
|
|
||||||
if (!updateIndexHardwareBuffer(HWBuffer)) {
|
if (!updateIndexHardwareBuffer(HWBuffer)) {
|
||||||
deleteHardwareBuffer(HWBuffer);
|
deleteHardwareBuffer(HWBuffer);
|
||||||
|
@ -2658,14 +2654,9 @@ bool COpenGLDriver::setPixelShaderConstant(s32 index, const u32 *ints, int count
|
||||||
//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.
|
//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.
|
||||||
s32 COpenGLDriver::addHighLevelShaderMaterial(
|
s32 COpenGLDriver::addHighLevelShaderMaterial(
|
||||||
const c8 *vertexShaderProgram,
|
const c8 *vertexShaderProgram,
|
||||||
const c8 *vertexShaderEntryPointName,
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
|
||||||
const c8 *pixelShaderProgram,
|
const c8 *pixelShaderProgram,
|
||||||
const c8 *pixelShaderEntryPointName,
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
|
||||||
const c8 *geometryShaderProgram,
|
const c8 *geometryShaderProgram,
|
||||||
const c8 *geometryShaderEntryPointName,
|
const c8 *shaderName,
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType,
|
scene::E_PRIMITIVE_TYPE inType,
|
||||||
scene::E_PRIMITIVE_TYPE outType,
|
scene::E_PRIMITIVE_TYPE outType,
|
||||||
u32 verticesOut,
|
u32 verticesOut,
|
||||||
|
@ -2677,9 +2668,9 @@ s32 COpenGLDriver::addHighLevelShaderMaterial(
|
||||||
|
|
||||||
COpenGLSLMaterialRenderer *r = new COpenGLSLMaterialRenderer(
|
COpenGLSLMaterialRenderer *r = new COpenGLSLMaterialRenderer(
|
||||||
this, nr,
|
this, nr,
|
||||||
vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget,
|
vertexShaderProgram,
|
||||||
pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget,
|
pixelShaderProgram,
|
||||||
geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget,
|
geometryShaderProgram,
|
||||||
inType, outType, verticesOut,
|
inType, outType, verticesOut,
|
||||||
callback, baseMaterial, userData);
|
callback, baseMaterial, userData);
|
||||||
|
|
||||||
|
|
|
@ -240,18 +240,13 @@ public:
|
||||||
//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.
|
//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.
|
||||||
virtual s32 addHighLevelShaderMaterial(
|
virtual s32 addHighLevelShaderMaterial(
|
||||||
const c8 *vertexShaderProgram,
|
const c8 *vertexShaderProgram,
|
||||||
const c8 *vertexShaderEntryPointName,
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
|
||||||
const c8 *pixelShaderProgram,
|
const c8 *pixelShaderProgram,
|
||||||
const c8 *pixelShaderEntryPointName,
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
|
||||||
const c8 *geometryShaderProgram,
|
const c8 *geometryShaderProgram,
|
||||||
const c8 *geometryShaderEntryPointName = "main",
|
const c8 *shaderName = nullptr,
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||||
u32 verticesOut = 0,
|
u32 verticesOut = 0,
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
IShaderConstantSetCallBack *callback = nullptr,
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||||
s32 userData = 0) override;
|
s32 userData = 0) override;
|
||||||
|
|
||||||
|
|
|
@ -34,14 +34,8 @@ namespace video
|
||||||
//! Constructor
|
//! Constructor
|
||||||
COpenGLSLMaterialRenderer::COpenGLSLMaterialRenderer(video::COpenGLDriver *driver,
|
COpenGLSLMaterialRenderer::COpenGLSLMaterialRenderer(video::COpenGLDriver *driver,
|
||||||
s32 &outMaterialTypeNr, const c8 *vertexShaderProgram,
|
s32 &outMaterialTypeNr, const c8 *vertexShaderProgram,
|
||||||
const c8 *vertexShaderEntryPointName,
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
|
||||||
const c8 *pixelShaderProgram,
|
const c8 *pixelShaderProgram,
|
||||||
const c8 *pixelShaderEntryPointName,
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
|
||||||
const c8 *geometryShaderProgram,
|
const c8 *geometryShaderProgram,
|
||||||
const c8 *geometryShaderEntryPointName,
|
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
|
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
|
||||||
u32 verticesOut,
|
u32 verticesOut,
|
||||||
IShaderConstantSetCallBack *callback,
|
IShaderConstantSetCallBack *callback,
|
||||||
|
|
|
@ -33,14 +33,8 @@ public:
|
||||||
COpenGLDriver *driver,
|
COpenGLDriver *driver,
|
||||||
s32 &outMaterialTypeNr,
|
s32 &outMaterialTypeNr,
|
||||||
const c8 *vertexShaderProgram = 0,
|
const c8 *vertexShaderProgram = 0,
|
||||||
const c8 *vertexShaderEntryPointName = 0,
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget = video::EVST_VS_1_1,
|
|
||||||
const c8 *pixelShaderProgram = 0,
|
const c8 *pixelShaderProgram = 0,
|
||||||
const c8 *pixelShaderEntryPointName = 0,
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget = video::EPST_PS_1_1,
|
|
||||||
const c8 *geometryShaderProgram = 0,
|
const c8 *geometryShaderProgram = 0,
|
||||||
const c8 *geometryShaderEntryPointName = "main",
|
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||||
u32 verticesOut = 0,
|
u32 verticesOut = 0,
|
||||||
|
|
|
@ -307,7 +307,7 @@ const core::aabbox3d<f32> &CSceneManager::getBoundingBox() const
|
||||||
{
|
{
|
||||||
_IRR_DEBUG_BREAK_IF(true) // Bounding Box of Scene Manager should never be used.
|
_IRR_DEBUG_BREAK_IF(true) // Bounding Box of Scene Manager should never be used.
|
||||||
|
|
||||||
static const core::aabbox3d<f32> dummy;
|
static const core::aabbox3d<f32> dummy{{0.0f, 0.0f, 0.0f}};
|
||||||
return dummy;
|
return dummy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ typedef COpenGLCoreTexture<COpenGL3DriverBase> COpenGL3Texture;
|
||||||
typedef COpenGLCoreRenderTarget<COpenGL3DriverBase, COpenGL3Texture> COpenGL3RenderTarget;
|
typedef COpenGLCoreRenderTarget<COpenGL3DriverBase, COpenGL3Texture> COpenGL3RenderTarget;
|
||||||
typedef COpenGLCoreCacheHandler<COpenGL3DriverBase, COpenGL3Texture> COpenGL3CacheHandler;
|
typedef COpenGLCoreCacheHandler<COpenGL3DriverBase, COpenGL3Texture> COpenGL3CacheHandler;
|
||||||
|
|
||||||
|
class OpenGLVBO;
|
||||||
|
|
||||||
enum OpenGLSpec : u8
|
enum OpenGLSpec : u8
|
||||||
{
|
{
|
||||||
Core,
|
Core,
|
||||||
|
|
|
@ -177,6 +177,8 @@ COpenGL3DriverBase::COpenGL3DriverBase(const SIrrlichtCreationParameters ¶ms
|
||||||
|
|
||||||
COpenGL3DriverBase::~COpenGL3DriverBase()
|
COpenGL3DriverBase::~COpenGL3DriverBase()
|
||||||
{
|
{
|
||||||
|
QuadIndexVBO.destroy();
|
||||||
|
|
||||||
deleteMaterialRenders();
|
deleteMaterialRenders();
|
||||||
|
|
||||||
CacheHandler->getTextureCache().clear();
|
CacheHandler->getTextureCache().clear();
|
||||||
|
@ -198,12 +200,16 @@ COpenGL3DriverBase::~COpenGL3DriverBase()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void COpenGL3DriverBase::initQuadsIndices(int max_vertex_count)
|
void COpenGL3DriverBase::initQuadsIndices(u32 max_vertex_count)
|
||||||
{
|
{
|
||||||
int max_quad_count = max_vertex_count / 4;
|
u32 max_quad_count = max_vertex_count / 4;
|
||||||
std::vector<GLushort> QuadsIndices;
|
u32 indices_size = 6 * max_quad_count;
|
||||||
QuadsIndices.reserve(6 * max_quad_count);
|
if (indices_size == QuadIndexVBO.getSize() * sizeof(u16))
|
||||||
for (int k = 0; k < max_quad_count; k++) {
|
return;
|
||||||
|
// initialize buffer contents
|
||||||
|
std::vector<u16> QuadsIndices;
|
||||||
|
QuadsIndices.reserve(indices_size);
|
||||||
|
for (u32 k = 0; k < max_quad_count; k++) {
|
||||||
QuadsIndices.push_back(4 * k + 0);
|
QuadsIndices.push_back(4 * k + 0);
|
||||||
QuadsIndices.push_back(4 * k + 1);
|
QuadsIndices.push_back(4 * k + 1);
|
||||||
QuadsIndices.push_back(4 * k + 2);
|
QuadsIndices.push_back(4 * k + 2);
|
||||||
|
@ -211,11 +217,8 @@ void COpenGL3DriverBase::initQuadsIndices(int max_vertex_count)
|
||||||
QuadsIndices.push_back(4 * k + 2);
|
QuadsIndices.push_back(4 * k + 2);
|
||||||
QuadsIndices.push_back(4 * k + 3);
|
QuadsIndices.push_back(4 * k + 3);
|
||||||
}
|
}
|
||||||
GL.GenBuffers(1, &QuadIndexBuffer);
|
QuadIndexVBO.upload(QuadsIndices.data(), QuadsIndices.size() * sizeof(u16),
|
||||||
GL.BindBuffer(GL_ARRAY_BUFFER, QuadIndexBuffer);
|
0, GL_STATIC_DRAW, true);
|
||||||
GL.BufferData(GL_ARRAY_BUFFER, sizeof(QuadsIndices[0]) * QuadsIndices.size(), QuadsIndices.data(), GL_STATIC_DRAW);
|
|
||||||
GL.BindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
QuadIndexCount = QuadsIndices.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void COpenGL3DriverBase::initVersion()
|
void COpenGL3DriverBase::initVersion()
|
||||||
|
@ -383,28 +386,28 @@ void COpenGL3DriverBase::createMaterialRenderers()
|
||||||
|
|
||||||
// EMT_SOLID
|
// EMT_SOLID
|
||||||
core::stringc FragmentShader = OGLES2ShaderPath + "Solid.fsh";
|
core::stringc FragmentShader = OGLES2ShaderPath + "Solid.fsh";
|
||||||
addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
|
addHighLevelShaderMaterialFromFiles(VertexShader, FragmentShader, "", "Solid",
|
||||||
EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, SolidCB, EMT_SOLID, 0);
|
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, SolidCB, EMT_SOLID, 0);
|
||||||
|
|
||||||
// EMT_TRANSPARENT_ALPHA_CHANNEL
|
// EMT_TRANSPARENT_ALPHA_CHANNEL
|
||||||
FragmentShader = OGLES2ShaderPath + "TransparentAlphaChannel.fsh";
|
FragmentShader = OGLES2ShaderPath + "TransparentAlphaChannel.fsh";
|
||||||
addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
|
addHighLevelShaderMaterialFromFiles(VertexShader, FragmentShader, "", "TransparentAlphaChannel",
|
||||||
EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAlphaChannelCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0);
|
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAlphaChannelCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0);
|
||||||
|
|
||||||
// EMT_TRANSPARENT_ALPHA_CHANNEL_REF
|
// EMT_TRANSPARENT_ALPHA_CHANNEL_REF
|
||||||
FragmentShader = OGLES2ShaderPath + "TransparentAlphaChannelRef.fsh";
|
FragmentShader = OGLES2ShaderPath + "TransparentAlphaChannelRef.fsh";
|
||||||
addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
|
addHighLevelShaderMaterialFromFiles(VertexShader, FragmentShader, "", "TransparentAlphaChannelRef",
|
||||||
EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAlphaChannelRefCB, EMT_SOLID, 0);
|
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAlphaChannelRefCB, EMT_SOLID, 0);
|
||||||
|
|
||||||
// EMT_TRANSPARENT_VERTEX_ALPHA
|
// EMT_TRANSPARENT_VERTEX_ALPHA
|
||||||
FragmentShader = OGLES2ShaderPath + "TransparentVertexAlpha.fsh";
|
FragmentShader = OGLES2ShaderPath + "TransparentVertexAlpha.fsh";
|
||||||
addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
|
addHighLevelShaderMaterialFromFiles(VertexShader, FragmentShader, "", "TransparentVertexAlpha",
|
||||||
EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentVertexAlphaCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0);
|
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentVertexAlphaCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0);
|
||||||
|
|
||||||
// EMT_ONETEXTURE_BLEND
|
// EMT_ONETEXTURE_BLEND
|
||||||
FragmentShader = OGLES2ShaderPath + "OneTextureBlend.fsh";
|
FragmentShader = OGLES2ShaderPath + "OneTextureBlend.fsh";
|
||||||
addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
|
addHighLevelShaderMaterialFromFiles(VertexShader, FragmentShader, "", "OneTextureBlend",
|
||||||
EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, OneTextureBlendCB, EMT_ONETEXTURE_BLEND, 0);
|
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, OneTextureBlendCB, EMT_ONETEXTURE_BLEND, 0);
|
||||||
|
|
||||||
// Drop callbacks.
|
// Drop callbacks.
|
||||||
|
|
||||||
|
@ -474,41 +477,18 @@ void COpenGL3DriverBase::setTransform(E_TRANSFORMATION_STATE state, const core::
|
||||||
Transformation3DChanged = true;
|
Transformation3DChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool COpenGL3DriverBase::updateHardwareBuffer(SHWBufferLink_opengl *HWBuffer,
|
bool COpenGL3DriverBase::uploadHardwareBuffer(OpenGLVBO &vbo,
|
||||||
const void *buffer, size_t bufferSize, scene::E_HARDWARE_MAPPING hint)
|
const void *buffer, size_t bufferSize, scene::E_HARDWARE_MAPPING hint)
|
||||||
{
|
{
|
||||||
assert(HWBuffer);
|
|
||||||
|
|
||||||
accountHWBufferUpload(bufferSize);
|
accountHWBufferUpload(bufferSize);
|
||||||
|
|
||||||
// get or create buffer
|
GLenum usage = GL_STATIC_DRAW;
|
||||||
bool newBuffer = false;
|
if (hint == scene::EHM_STREAM)
|
||||||
if (!HWBuffer->vbo_ID) {
|
usage = GL_STREAM_DRAW;
|
||||||
GL.GenBuffers(1, &HWBuffer->vbo_ID);
|
else if (hint == scene::EHM_DYNAMIC)
|
||||||
if (!HWBuffer->vbo_ID)
|
usage = GL_DYNAMIC_DRAW;
|
||||||
return false;
|
|
||||||
newBuffer = true;
|
|
||||||
} else if (HWBuffer->vbo_Size < bufferSize) {
|
|
||||||
newBuffer = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.BindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_ID);
|
vbo.upload(buffer, bufferSize, 0, usage);
|
||||||
|
|
||||||
// copy data to graphics card
|
|
||||||
if (!newBuffer)
|
|
||||||
GL.BufferSubData(GL_ARRAY_BUFFER, 0, bufferSize, buffer);
|
|
||||||
else {
|
|
||||||
HWBuffer->vbo_Size = bufferSize;
|
|
||||||
|
|
||||||
GLenum usage = GL_STATIC_DRAW;
|
|
||||||
if (hint == scene::EHM_STREAM)
|
|
||||||
usage = GL_STREAM_DRAW;
|
|
||||||
else if (hint == scene::EHM_DYNAMIC)
|
|
||||||
usage = GL_DYNAMIC_DRAW;
|
|
||||||
GL.BufferData(GL_ARRAY_BUFFER, bufferSize, buffer, usage);
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.BindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
|
|
||||||
return (!TEST_GL_ERROR(this));
|
return (!TEST_GL_ERROR(this));
|
||||||
}
|
}
|
||||||
|
@ -525,7 +505,8 @@ bool COpenGL3DriverBase::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuff
|
||||||
const u32 vertexSize = getVertexPitchFromType(vb->getType());
|
const u32 vertexSize = getVertexPitchFromType(vb->getType());
|
||||||
const size_t bufferSize = vertexSize * vb->getCount();
|
const size_t bufferSize = vertexSize * vb->getCount();
|
||||||
|
|
||||||
return updateHardwareBuffer(HWBuffer, vb->getData(), bufferSize, vb->getHardwareMappingHint());
|
return uploadHardwareBuffer(HWBuffer->Vbo, vb->getData(),
|
||||||
|
bufferSize, vb->getHardwareMappingHint());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool COpenGL3DriverBase::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
|
bool COpenGL3DriverBase::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
|
||||||
|
@ -551,7 +532,8 @@ bool COpenGL3DriverBase::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffe
|
||||||
|
|
||||||
const size_t bufferSize = ib->getCount() * indexSize;
|
const size_t bufferSize = ib->getCount() * indexSize;
|
||||||
|
|
||||||
return updateHardwareBuffer(HWBuffer, ib->getData(), bufferSize, ib->getHardwareMappingHint());
|
return uploadHardwareBuffer(HWBuffer->Vbo, ib->getData(),
|
||||||
|
bufferSize, ib->getHardwareMappingHint());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool COpenGL3DriverBase::updateHardwareBuffer(SHWBufferLink *HWBuffer)
|
bool COpenGL3DriverBase::updateHardwareBuffer(SHWBufferLink *HWBuffer)
|
||||||
|
@ -563,14 +545,14 @@ bool COpenGL3DriverBase::updateHardwareBuffer(SHWBufferLink *HWBuffer)
|
||||||
|
|
||||||
if (b->IsVertex) {
|
if (b->IsVertex) {
|
||||||
assert(b->VertexBuffer);
|
assert(b->VertexBuffer);
|
||||||
if (b->ChangedID != b->VertexBuffer->getChangedID() || !b->vbo_ID) {
|
if (b->ChangedID != b->VertexBuffer->getChangedID() || !b->Vbo.exists()) {
|
||||||
if (!updateVertexHardwareBuffer(b))
|
if (!updateVertexHardwareBuffer(b))
|
||||||
return false;
|
return false;
|
||||||
b->ChangedID = b->VertexBuffer->getChangedID();
|
b->ChangedID = b->VertexBuffer->getChangedID();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(b->IndexBuffer);
|
assert(b->IndexBuffer);
|
||||||
if (b->ChangedID != b->IndexBuffer->getChangedID() || !b->vbo_ID) {
|
if (b->ChangedID != b->IndexBuffer->getChangedID() || !b->Vbo.exists()) {
|
||||||
if (!updateIndexHardwareBuffer(b))
|
if (!updateIndexHardwareBuffer(b))
|
||||||
return false;
|
return false;
|
||||||
b->ChangedID = b->IndexBuffer->getChangedID();
|
b->ChangedID = b->IndexBuffer->getChangedID();
|
||||||
|
@ -584,10 +566,8 @@ COpenGL3DriverBase::SHWBufferLink *COpenGL3DriverBase::createHardwareBuffer(cons
|
||||||
if (!vb || vb->getHardwareMappingHint() == scene::EHM_NEVER)
|
if (!vb || vb->getHardwareMappingHint() == scene::EHM_NEVER)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
SHWBufferLink_opengl *HWBuffer = new SHWBufferLink_opengl(vb);
|
auto *HWBuffer = new SHWBufferLink_opengl(vb);
|
||||||
|
registerHardwareBuffer(HWBuffer);
|
||||||
// add to map
|
|
||||||
HWBuffer->listPosition = HWBufferList.insert(HWBufferList.end(), HWBuffer);
|
|
||||||
|
|
||||||
if (!updateVertexHardwareBuffer(HWBuffer)) {
|
if (!updateVertexHardwareBuffer(HWBuffer)) {
|
||||||
deleteHardwareBuffer(HWBuffer);
|
deleteHardwareBuffer(HWBuffer);
|
||||||
|
@ -602,10 +582,8 @@ COpenGL3DriverBase::SHWBufferLink *COpenGL3DriverBase::createHardwareBuffer(cons
|
||||||
if (!ib || ib->getHardwareMappingHint() == scene::EHM_NEVER)
|
if (!ib || ib->getHardwareMappingHint() == scene::EHM_NEVER)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
SHWBufferLink_opengl *HWBuffer = new SHWBufferLink_opengl(ib);
|
auto *HWBuffer = new SHWBufferLink_opengl(ib);
|
||||||
|
registerHardwareBuffer(HWBuffer);
|
||||||
// add to map
|
|
||||||
HWBuffer->listPosition = HWBufferList.insert(HWBufferList.end(), HWBuffer);
|
|
||||||
|
|
||||||
if (!updateIndexHardwareBuffer(HWBuffer)) {
|
if (!updateIndexHardwareBuffer(HWBuffer)) {
|
||||||
deleteHardwareBuffer(HWBuffer);
|
deleteHardwareBuffer(HWBuffer);
|
||||||
|
@ -621,10 +599,7 @@ void COpenGL3DriverBase::deleteHardwareBuffer(SHWBufferLink *HWBuffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto *b = static_cast<SHWBufferLink_opengl *>(HWBuffer);
|
auto *b = static_cast<SHWBufferLink_opengl *>(HWBuffer);
|
||||||
if (b->vbo_ID) {
|
b->Vbo.destroy();
|
||||||
GL.DeleteBuffers(1, &b->vbo_ID);
|
|
||||||
b->vbo_ID = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CNullDriver::deleteHardwareBuffer(HWBuffer);
|
CNullDriver::deleteHardwareBuffer(HWBuffer);
|
||||||
}
|
}
|
||||||
|
@ -644,14 +619,14 @@ void COpenGL3DriverBase::drawBuffers(const scene::IVertexBuffer *vb,
|
||||||
const void *vertices = vb->getData();
|
const void *vertices = vb->getData();
|
||||||
if (hwvert) {
|
if (hwvert) {
|
||||||
assert(hwvert->IsVertex);
|
assert(hwvert->IsVertex);
|
||||||
GL.BindBuffer(GL_ARRAY_BUFFER, hwvert->vbo_ID);
|
GL.BindBuffer(GL_ARRAY_BUFFER, hwvert->Vbo.getName());
|
||||||
vertices = nullptr;
|
vertices = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *indexList = ib->getData();
|
const void *indexList = ib->getData();
|
||||||
if (hwidx) {
|
if (hwidx) {
|
||||||
assert(!hwidx->IsVertex);
|
assert(!hwidx->IsVertex);
|
||||||
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, hwidx->vbo_ID);
|
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, hwidx->Vbo.getName());
|
||||||
indexList = nullptr;
|
indexList = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -710,58 +685,32 @@ void COpenGL3DriverBase::drawVertexPrimitiveList(const void *vertices, u32 verte
|
||||||
|
|
||||||
setRenderStates3DMode();
|
setRenderStates3DMode();
|
||||||
|
|
||||||
auto &vTypeDesc = getVertexTypeDescription(vType);
|
drawGeneric(vertices, indexList, primitiveCount, vType, pType, iType);
|
||||||
beginDraw(vTypeDesc, reinterpret_cast<uintptr_t>(vertices));
|
|
||||||
GLenum indexSize = 0;
|
|
||||||
|
|
||||||
switch (iType) {
|
|
||||||
case (EIT_16BIT): {
|
|
||||||
indexSize = GL_UNSIGNED_SHORT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case (EIT_32BIT): {
|
|
||||||
indexSize = GL_UNSIGNED_INT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (pType) {
|
|
||||||
case scene::EPT_POINTS:
|
|
||||||
case scene::EPT_POINT_SPRITES:
|
|
||||||
GL.DrawArrays(GL_POINTS, 0, primitiveCount);
|
|
||||||
break;
|
|
||||||
case scene::EPT_LINE_STRIP:
|
|
||||||
GL.DrawElements(GL_LINE_STRIP, primitiveCount + 1, indexSize, indexList);
|
|
||||||
break;
|
|
||||||
case scene::EPT_LINE_LOOP:
|
|
||||||
GL.DrawElements(GL_LINE_LOOP, primitiveCount, indexSize, indexList);
|
|
||||||
break;
|
|
||||||
case scene::EPT_LINES:
|
|
||||||
GL.DrawElements(GL_LINES, primitiveCount * 2, indexSize, indexList);
|
|
||||||
break;
|
|
||||||
case scene::EPT_TRIANGLE_STRIP:
|
|
||||||
GL.DrawElements(GL_TRIANGLE_STRIP, primitiveCount + 2, indexSize, indexList);
|
|
||||||
break;
|
|
||||||
case scene::EPT_TRIANGLE_FAN:
|
|
||||||
GL.DrawElements(GL_TRIANGLE_FAN, primitiveCount + 2, indexSize, indexList);
|
|
||||||
break;
|
|
||||||
case scene::EPT_TRIANGLES:
|
|
||||||
GL.DrawElements((LastMaterial.Wireframe) ? GL_LINES : (LastMaterial.PointCloud) ? GL_POINTS
|
|
||||||
: GL_TRIANGLES,
|
|
||||||
primitiveCount * 3, indexSize, indexList);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
endDraw(vTypeDesc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! draws a vertex primitive list in 2d
|
||||||
void COpenGL3DriverBase::draw2DVertexPrimitiveList(const void *vertices, u32 vertexCount,
|
void COpenGL3DriverBase::draw2DVertexPrimitiveList(const void *vertices, u32 vertexCount,
|
||||||
const void *indexList, u32 primitiveCount,
|
const void *indexList, u32 primitiveCount,
|
||||||
E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
|
E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
|
||||||
{
|
{
|
||||||
os::Printer::log("draw2DVertexPrimitiveList unimplemented", ELL_ERROR);
|
if (!primitiveCount || !vertexCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!vertices)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!checkPrimitiveCount(primitiveCount))
|
||||||
|
return;
|
||||||
|
|
||||||
|
CNullDriver::draw2DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType);
|
||||||
|
|
||||||
|
setRenderStates2DMode(
|
||||||
|
Material.MaterialType == EMT_TRANSPARENT_VERTEX_ALPHA,
|
||||||
|
Material.getTexture(0),
|
||||||
|
Material.MaterialType == EMT_TRANSPARENT_ALPHA_CHANNEL
|
||||||
|
);
|
||||||
|
|
||||||
|
drawGeneric(vertices, indexList, primitiveCount, vType, pType, iType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void COpenGL3DriverBase::draw2DImage(const video::ITexture *texture, const core::position2d<s32> &destPos,
|
void COpenGL3DriverBase::draw2DImage(const video::ITexture *texture, const core::position2d<s32> &destPos,
|
||||||
|
@ -824,10 +773,10 @@ void COpenGL3DriverBase::draw2DImage(const video::ITexture *texture, const core:
|
||||||
clipRect->getWidth(), clipRect->getHeight());
|
clipRect->getWidth(), clipRect->getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
f32 left = (f32)destRect.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
f32 left = (f32)destRect.UpperLeftCorner.X;
|
||||||
f32 right = (f32)destRect.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
f32 right = (f32)destRect.LowerRightCorner.X;
|
||||||
f32 down = 2.f - (f32)destRect.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
f32 down = (f32)destRect.LowerRightCorner.Y;
|
||||||
f32 top = 2.f - (f32)destRect.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
f32 top = (f32)destRect.UpperLeftCorner.Y;
|
||||||
|
|
||||||
S3DVertex vertices[4];
|
S3DVertex vertices[4];
|
||||||
vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, useColor[0], tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
|
vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, useColor[0], tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
|
||||||
|
@ -903,7 +852,7 @@ void COpenGL3DriverBase::draw2DImageBatch(const video::ITexture *texture,
|
||||||
}
|
}
|
||||||
|
|
||||||
const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
|
const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
|
||||||
assert(6 * drawCount <= QuadIndexCount); // FIXME split the batch? or let it crash?
|
assert(6 * drawCount * sizeof(u16) <= QuadIndexVBO.getSize()); // FIXME split the batch? or let it crash?
|
||||||
|
|
||||||
std::vector<S3DVertex> vtx;
|
std::vector<S3DVertex> vtx;
|
||||||
vtx.reserve(drawCount * 4);
|
vtx.reserve(drawCount * 4);
|
||||||
|
@ -924,10 +873,10 @@ void COpenGL3DriverBase::draw2DImageBatch(const video::ITexture *texture,
|
||||||
|
|
||||||
const core::rect<s32> poss(targetPos, sourceSize);
|
const core::rect<s32> poss(targetPos, sourceSize);
|
||||||
|
|
||||||
f32 left = (f32)poss.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
f32 left = (f32)poss.UpperLeftCorner.X;
|
||||||
f32 right = (f32)poss.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
f32 right = (f32)poss.LowerRightCorner.X;
|
||||||
f32 down = 2.f - (f32)poss.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
f32 down = (f32)poss.LowerRightCorner.Y;
|
||||||
f32 top = 2.f - (f32)poss.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
f32 top = (f32)poss.UpperLeftCorner.Y;
|
||||||
|
|
||||||
vtx.emplace_back(left, top, 0.0f,
|
vtx.emplace_back(left, top, 0.0f,
|
||||||
0.0f, 0.0f, 0.0f, color,
|
0.0f, 0.0f, 0.0f, color,
|
||||||
|
@ -943,7 +892,7 @@ void COpenGL3DriverBase::draw2DImageBatch(const video::ITexture *texture,
|
||||||
tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
|
tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, QuadIndexBuffer);
|
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, QuadIndexVBO.getName());
|
||||||
drawElements(GL_TRIANGLES, vt2DImage, vtx.data(), vtx.size(), 0, 6 * drawCount);
|
drawElements(GL_TRIANGLES, vt2DImage, vtx.data(), vtx.size(), 0, 6 * drawCount);
|
||||||
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
@ -956,33 +905,7 @@ void COpenGL3DriverBase::draw2DRectangle(SColor color,
|
||||||
const core::rect<s32> &position,
|
const core::rect<s32> &position,
|
||||||
const core::rect<s32> *clip)
|
const core::rect<s32> *clip)
|
||||||
{
|
{
|
||||||
chooseMaterial2D();
|
draw2DRectangle(position, color, color, color, color, clip);
|
||||||
setMaterialTexture(0, 0);
|
|
||||||
|
|
||||||
setRenderStates2DMode(color.getAlpha() < 255, false, false);
|
|
||||||
|
|
||||||
core::rect<s32> pos = position;
|
|
||||||
|
|
||||||
if (clip)
|
|
||||||
pos.clipAgainst(*clip);
|
|
||||||
|
|
||||||
if (!pos.isValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const core::dimension2d<u32> &renderTargetSize = getCurrentRenderTargetSize();
|
|
||||||
|
|
||||||
f32 left = (f32)pos.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
|
||||||
f32 right = (f32)pos.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
|
||||||
f32 down = 2.f - (f32)pos.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
|
||||||
f32 top = 2.f - (f32)pos.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
|
||||||
|
|
||||||
S3DVertex vertices[4];
|
|
||||||
vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, color, 0, 0);
|
|
||||||
vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, color, 0, 0);
|
|
||||||
vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, color, 0, 0);
|
|
||||||
vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, color, 0, 0);
|
|
||||||
|
|
||||||
drawQuad(vtPrimitive, vertices);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! draw an 2d rectangle
|
//! draw an 2d rectangle
|
||||||
|
@ -1008,18 +931,16 @@ void COpenGL3DriverBase::draw2DRectangle(const core::rect<s32> &position,
|
||||||
colorRightDown.getAlpha() < 255,
|
colorRightDown.getAlpha() < 255,
|
||||||
false, false);
|
false, false);
|
||||||
|
|
||||||
const core::dimension2d<u32> &renderTargetSize = getCurrentRenderTargetSize();
|
f32 left = (f32)pos.UpperLeftCorner.X;
|
||||||
|
f32 right = (f32)pos.LowerRightCorner.X;
|
||||||
f32 left = (f32)pos.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
f32 down = (f32)pos.LowerRightCorner.Y;
|
||||||
f32 right = (f32)pos.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
f32 top = (f32)pos.UpperLeftCorner.Y;
|
||||||
f32 down = 2.f - (f32)pos.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
|
||||||
f32 top = 2.f - (f32)pos.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
|
||||||
|
|
||||||
S3DVertex vertices[4];
|
S3DVertex vertices[4];
|
||||||
vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, colorLeftUp, 0, 0);
|
vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, colorLeftUp, 0, 0);
|
||||||
vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, colorRightUp, 0, 0);
|
vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, colorRightUp, 0, 0);
|
||||||
vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, colorRightDown, 0, 0);
|
vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, colorRightDown, 0, 0);
|
||||||
vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, colorLeftDown, 0, 0);
|
vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, colorLeftDown, 0, 0);
|
||||||
|
|
||||||
drawQuad(vtPrimitive, vertices);
|
drawQuad(vtPrimitive, vertices);
|
||||||
}
|
}
|
||||||
|
@ -1034,12 +955,10 @@ void COpenGL3DriverBase::draw2DLine(const core::position2d<s32> &start,
|
||||||
|
|
||||||
setRenderStates2DMode(color.getAlpha() < 255, false, false);
|
setRenderStates2DMode(color.getAlpha() < 255, false, false);
|
||||||
|
|
||||||
const core::dimension2d<u32> &renderTargetSize = getCurrentRenderTargetSize();
|
f32 startX = (f32)start.X;
|
||||||
|
f32 endX = (f32)end.X;
|
||||||
f32 startX = (f32)start.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
f32 startY = (f32)start.Y;
|
||||||
f32 endX = (f32)end.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
f32 endY = (f32)end.Y;
|
||||||
f32 startY = 2.f - (f32)start.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
|
||||||
f32 endY = 2.f - (f32)end.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
|
||||||
|
|
||||||
S3DVertex vertices[2];
|
S3DVertex vertices[2];
|
||||||
vertices[0] = S3DVertex(startX, startY, 0, 0, 0, 1, color, 0, 0);
|
vertices[0] = S3DVertex(startX, startY, 0, 0, 0, 1, color, 0, 0);
|
||||||
|
@ -1068,6 +987,55 @@ void COpenGL3DriverBase::drawElements(GLenum primitiveType, const VertexType &ve
|
||||||
endDraw(vertexType);
|
endDraw(vertexType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void COpenGL3DriverBase::drawGeneric(const void *vertices, const void *indexList,
|
||||||
|
u32 primitiveCount,
|
||||||
|
E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
|
||||||
|
{
|
||||||
|
auto &vTypeDesc = getVertexTypeDescription(vType);
|
||||||
|
beginDraw(vTypeDesc, reinterpret_cast<uintptr_t>(vertices));
|
||||||
|
GLenum indexSize = 0;
|
||||||
|
|
||||||
|
switch (iType) {
|
||||||
|
case EIT_16BIT:
|
||||||
|
indexSize = GL_UNSIGNED_SHORT;
|
||||||
|
break;
|
||||||
|
case EIT_32BIT:
|
||||||
|
indexSize = GL_UNSIGNED_INT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (pType) {
|
||||||
|
case scene::EPT_POINTS:
|
||||||
|
case scene::EPT_POINT_SPRITES:
|
||||||
|
GL.DrawArrays(GL_POINTS, 0, primitiveCount);
|
||||||
|
break;
|
||||||
|
case scene::EPT_LINE_STRIP:
|
||||||
|
GL.DrawElements(GL_LINE_STRIP, primitiveCount + 1, indexSize, indexList);
|
||||||
|
break;
|
||||||
|
case scene::EPT_LINE_LOOP:
|
||||||
|
GL.DrawElements(GL_LINE_LOOP, primitiveCount, indexSize, indexList);
|
||||||
|
break;
|
||||||
|
case scene::EPT_LINES:
|
||||||
|
GL.DrawElements(GL_LINES, primitiveCount * 2, indexSize, indexList);
|
||||||
|
break;
|
||||||
|
case scene::EPT_TRIANGLE_STRIP:
|
||||||
|
GL.DrawElements(GL_TRIANGLE_STRIP, primitiveCount + 2, indexSize, indexList);
|
||||||
|
break;
|
||||||
|
case scene::EPT_TRIANGLE_FAN:
|
||||||
|
GL.DrawElements(GL_TRIANGLE_FAN, primitiveCount + 2, indexSize, indexList);
|
||||||
|
break;
|
||||||
|
case scene::EPT_TRIANGLES:
|
||||||
|
GL.DrawElements((LastMaterial.Wireframe) ? GL_LINES : (LastMaterial.PointCloud) ? GL_POINTS
|
||||||
|
: GL_TRIANGLES,
|
||||||
|
primitiveCount * 3, indexSize, indexList);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
endDraw(vTypeDesc);
|
||||||
|
}
|
||||||
|
|
||||||
void COpenGL3DriverBase::beginDraw(const VertexType &vertexType, uintptr_t verticesBase)
|
void COpenGL3DriverBase::beginDraw(const VertexType &vertexType, uintptr_t verticesBase)
|
||||||
{
|
{
|
||||||
for (auto &attr : vertexType) {
|
for (auto &attr : vertexType) {
|
||||||
|
@ -1372,60 +1340,74 @@ void COpenGL3DriverBase::setTextureRenderStates(const SMaterial &material, bool
|
||||||
|
|
||||||
CacheHandler->setActiveTexture(GL_TEXTURE0 + i);
|
CacheHandler->setActiveTexture(GL_TEXTURE0 + i);
|
||||||
|
|
||||||
if (resetAllRenderstates)
|
const auto &layer = material.TextureLayers[i];
|
||||||
tmpTexture->getStatesCache().IsCached = false;
|
auto &states = tmpTexture->getStatesCache();
|
||||||
|
|
||||||
if (!tmpTexture->getStatesCache().IsCached || material.TextureLayers[i].MagFilter != tmpTexture->getStatesCache().MagFilter) {
|
if (resetAllRenderstates)
|
||||||
E_TEXTURE_MAG_FILTER magFilter = material.TextureLayers[i].MagFilter;
|
states.IsCached = false;
|
||||||
|
|
||||||
|
if (!states.IsCached || layer.MagFilter != states.MagFilter) {
|
||||||
|
E_TEXTURE_MAG_FILTER magFilter = layer.MagFilter;
|
||||||
GL.TexParameteri(tmpTextureType, GL_TEXTURE_MAG_FILTER,
|
GL.TexParameteri(tmpTextureType, GL_TEXTURE_MAG_FILTER,
|
||||||
magFilter == ETMAGF_NEAREST ? GL_NEAREST : (assert(magFilter == ETMAGF_LINEAR), GL_LINEAR));
|
magFilter == ETMAGF_NEAREST ? GL_NEAREST : (assert(magFilter == ETMAGF_LINEAR), GL_LINEAR));
|
||||||
|
|
||||||
tmpTexture->getStatesCache().MagFilter = magFilter;
|
states.MagFilter = magFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (material.UseMipMaps && tmpTexture->hasMipMaps()) {
|
if (material.UseMipMaps && tmpTexture->hasMipMaps()) {
|
||||||
if (!tmpTexture->getStatesCache().IsCached || material.TextureLayers[i].MinFilter != tmpTexture->getStatesCache().MinFilter ||
|
if (!states.IsCached || layer.MinFilter != states.MinFilter ||
|
||||||
!tmpTexture->getStatesCache().MipMapStatus) {
|
!states.MipMapStatus) {
|
||||||
E_TEXTURE_MIN_FILTER minFilter = material.TextureLayers[i].MinFilter;
|
E_TEXTURE_MIN_FILTER minFilter = layer.MinFilter;
|
||||||
GL.TexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER,
|
GL.TexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER,
|
||||||
minFilter == ETMINF_NEAREST_MIPMAP_NEAREST ? GL_NEAREST_MIPMAP_NEAREST : minFilter == ETMINF_LINEAR_MIPMAP_NEAREST ? GL_LINEAR_MIPMAP_NEAREST
|
minFilter == ETMINF_NEAREST_MIPMAP_NEAREST ? GL_NEAREST_MIPMAP_NEAREST : minFilter == ETMINF_LINEAR_MIPMAP_NEAREST ? GL_LINEAR_MIPMAP_NEAREST
|
||||||
: minFilter == ETMINF_NEAREST_MIPMAP_LINEAR ? GL_NEAREST_MIPMAP_LINEAR
|
: minFilter == ETMINF_NEAREST_MIPMAP_LINEAR ? GL_NEAREST_MIPMAP_LINEAR
|
||||||
: (assert(minFilter == ETMINF_LINEAR_MIPMAP_LINEAR), GL_LINEAR_MIPMAP_LINEAR));
|
: (assert(minFilter == ETMINF_LINEAR_MIPMAP_LINEAR), GL_LINEAR_MIPMAP_LINEAR));
|
||||||
|
|
||||||
tmpTexture->getStatesCache().MinFilter = minFilter;
|
states.MinFilter = minFilter;
|
||||||
tmpTexture->getStatesCache().MipMapStatus = true;
|
states.MipMapStatus = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!tmpTexture->getStatesCache().IsCached || material.TextureLayers[i].MinFilter != tmpTexture->getStatesCache().MinFilter ||
|
if (!states.IsCached || layer.MinFilter != states.MinFilter ||
|
||||||
tmpTexture->getStatesCache().MipMapStatus) {
|
states.MipMapStatus) {
|
||||||
E_TEXTURE_MIN_FILTER minFilter = material.TextureLayers[i].MinFilter;
|
E_TEXTURE_MIN_FILTER minFilter = layer.MinFilter;
|
||||||
GL.TexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER,
|
GL.TexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER,
|
||||||
(minFilter == ETMINF_NEAREST_MIPMAP_NEAREST || minFilter == ETMINF_NEAREST_MIPMAP_LINEAR) ? GL_NEAREST : (assert(minFilter == ETMINF_LINEAR_MIPMAP_NEAREST || minFilter == ETMINF_LINEAR_MIPMAP_LINEAR), GL_LINEAR));
|
(minFilter == ETMINF_NEAREST_MIPMAP_NEAREST || minFilter == ETMINF_NEAREST_MIPMAP_LINEAR) ? GL_NEAREST : (assert(minFilter == ETMINF_LINEAR_MIPMAP_NEAREST || minFilter == ETMINF_LINEAR_MIPMAP_LINEAR), GL_LINEAR));
|
||||||
|
|
||||||
tmpTexture->getStatesCache().MinFilter = minFilter;
|
states.MinFilter = minFilter;
|
||||||
tmpTexture->getStatesCache().MipMapStatus = false;
|
states.MipMapStatus = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (LODBiasSupported &&
|
||||||
|
(!states.IsCached || layer.LODBias != states.LODBias)) {
|
||||||
|
if (layer.LODBias) {
|
||||||
|
const float tmp = core::clamp(layer.LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);
|
||||||
|
GL.TexParameterf(tmpTextureType, GL.TEXTURE_LOD_BIAS, tmp);
|
||||||
|
} else
|
||||||
|
GL.TexParameterf(tmpTextureType, GL.TEXTURE_LOD_BIAS, 0.f);
|
||||||
|
|
||||||
|
states.LODBias = layer.LODBias;
|
||||||
|
}
|
||||||
|
|
||||||
if (AnisotropicFilterSupported &&
|
if (AnisotropicFilterSupported &&
|
||||||
(!tmpTexture->getStatesCache().IsCached || material.TextureLayers[i].AnisotropicFilter != tmpTexture->getStatesCache().AnisotropicFilter)) {
|
(!states.IsCached || layer.AnisotropicFilter != states.AnisotropicFilter)) {
|
||||||
GL.TexParameteri(tmpTextureType, GL.TEXTURE_MAX_ANISOTROPY,
|
GL.TexParameteri(tmpTextureType, GL.TEXTURE_MAX_ANISOTROPY,
|
||||||
material.TextureLayers[i].AnisotropicFilter > 1 ? core::min_(MaxAnisotropy, material.TextureLayers[i].AnisotropicFilter) : 1);
|
layer.AnisotropicFilter > 1 ? core::min_(MaxAnisotropy, layer.AnisotropicFilter) : 1);
|
||||||
|
|
||||||
tmpTexture->getStatesCache().AnisotropicFilter = material.TextureLayers[i].AnisotropicFilter;
|
states.AnisotropicFilter = layer.AnisotropicFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tmpTexture->getStatesCache().IsCached || material.TextureLayers[i].TextureWrapU != tmpTexture->getStatesCache().WrapU) {
|
if (!states.IsCached || layer.TextureWrapU != states.WrapU) {
|
||||||
GL.TexParameteri(tmpTextureType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayers[i].TextureWrapU));
|
GL.TexParameteri(tmpTextureType, GL_TEXTURE_WRAP_S, getTextureWrapMode(layer.TextureWrapU));
|
||||||
tmpTexture->getStatesCache().WrapU = material.TextureLayers[i].TextureWrapU;
|
states.WrapU = layer.TextureWrapU;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tmpTexture->getStatesCache().IsCached || material.TextureLayers[i].TextureWrapV != tmpTexture->getStatesCache().WrapV) {
|
if (!states.IsCached || layer.TextureWrapV != states.WrapV) {
|
||||||
GL.TexParameteri(tmpTextureType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayers[i].TextureWrapV));
|
GL.TexParameteri(tmpTextureType, GL_TEXTURE_WRAP_T, getTextureWrapMode(layer.TextureWrapV));
|
||||||
tmpTexture->getStatesCache().WrapV = material.TextureLayers[i].TextureWrapV;
|
states.WrapV = layer.TextureWrapV;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpTexture->getStatesCache().IsCached = true;
|
states.IsCached = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1620,14 +1602,9 @@ bool COpenGL3DriverBase::setPixelShaderConstant(s32 index, const u32 *ints, int
|
||||||
//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.
|
//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.
|
||||||
s32 COpenGL3DriverBase::addHighLevelShaderMaterial(
|
s32 COpenGL3DriverBase::addHighLevelShaderMaterial(
|
||||||
const c8 *vertexShaderProgram,
|
const c8 *vertexShaderProgram,
|
||||||
const c8 *vertexShaderEntryPointName,
|
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
|
||||||
const c8 *pixelShaderProgram,
|
const c8 *pixelShaderProgram,
|
||||||
const c8 *pixelShaderEntryPointName,
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
|
||||||
const c8 *geometryShaderProgram,
|
const c8 *geometryShaderProgram,
|
||||||
const c8 *geometryShaderEntryPointName,
|
const c8 *shaderName,
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType,
|
scene::E_PRIMITIVE_TYPE inType,
|
||||||
scene::E_PRIMITIVE_TYPE outType,
|
scene::E_PRIMITIVE_TYPE outType,
|
||||||
u32 verticesOut,
|
u32 verticesOut,
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "SIrrCreationParameters.h"
|
#include "SIrrCreationParameters.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "VBO.h"
|
||||||
#include "CNullDriver.h"
|
#include "CNullDriver.h"
|
||||||
#include "IMaterialRendererServices.h"
|
#include "IMaterialRendererServices.h"
|
||||||
#include "EDriverFeatures.h"
|
#include "EDriverFeatures.h"
|
||||||
|
@ -49,8 +50,7 @@ public:
|
||||||
SHWBufferLink_opengl(const scene::IVertexBuffer *vb) : SHWBufferLink(vb) {}
|
SHWBufferLink_opengl(const scene::IVertexBuffer *vb) : SHWBufferLink(vb) {}
|
||||||
SHWBufferLink_opengl(const scene::IIndexBuffer *ib) : SHWBufferLink(ib) {}
|
SHWBufferLink_opengl(const scene::IIndexBuffer *ib) : SHWBufferLink(ib) {}
|
||||||
|
|
||||||
GLuint vbo_ID = 0;
|
OpenGLVBO Vbo;
|
||||||
u32 vbo_Size = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer);
|
bool updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer);
|
||||||
|
@ -189,18 +189,13 @@ public:
|
||||||
//! Adds a new material renderer to the VideoDriver
|
//! Adds a new material renderer to the VideoDriver
|
||||||
virtual s32 addHighLevelShaderMaterial(
|
virtual s32 addHighLevelShaderMaterial(
|
||||||
const c8 *vertexShaderProgram,
|
const c8 *vertexShaderProgram,
|
||||||
const c8 *vertexShaderEntryPointName = 0,
|
const c8 *pixelShaderProgram,
|
||||||
E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1,
|
const c8 *geometryShaderProgram = nullptr,
|
||||||
const c8 *pixelShaderProgram = 0,
|
const c8 *shaderName = nullptr,
|
||||||
const c8 *pixelShaderEntryPointName = 0,
|
|
||||||
E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1,
|
|
||||||
const c8 *geometryShaderProgram = 0,
|
|
||||||
const c8 *geometryShaderEntryPointName = "main",
|
|
||||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
|
|
||||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||||
u32 verticesOut = 0,
|
u32 verticesOut = 0,
|
||||||
IShaderConstantSetCallBack *callback = 0,
|
IShaderConstantSetCallBack *callback = nullptr,
|
||||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||||
s32 userData = 0) override;
|
s32 userData = 0) override;
|
||||||
|
|
||||||
|
@ -300,7 +295,7 @@ protected:
|
||||||
LockRenderStateMode = false;
|
LockRenderStateMode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool updateHardwareBuffer(SHWBufferLink_opengl *b, const void *buffer, size_t bufferSize, scene::E_HARDWARE_MAPPING hint);
|
bool uploadHardwareBuffer(OpenGLVBO &vbo, const void *buffer, size_t bufferSize, scene::E_HARDWARE_MAPPING hint);
|
||||||
|
|
||||||
void createMaterialRenderers();
|
void createMaterialRenderers();
|
||||||
|
|
||||||
|
@ -316,6 +311,9 @@ protected:
|
||||||
void drawElements(GLenum primitiveType, const VertexType &vertexType, const void *vertices, int vertexCount, const u16 *indices, int indexCount);
|
void drawElements(GLenum primitiveType, const VertexType &vertexType, const void *vertices, int vertexCount, const u16 *indices, int indexCount);
|
||||||
void drawElements(GLenum primitiveType, const VertexType &vertexType, uintptr_t vertices, uintptr_t indices, int indexCount);
|
void drawElements(GLenum primitiveType, const VertexType &vertexType, uintptr_t vertices, uintptr_t indices, int indexCount);
|
||||||
|
|
||||||
|
void drawGeneric(const void *vertices, const void *indexList, u32 primitiveCount,
|
||||||
|
E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType);
|
||||||
|
|
||||||
void beginDraw(const VertexType &vertexType, uintptr_t verticesBase);
|
void beginDraw(const VertexType &vertexType, uintptr_t verticesBase);
|
||||||
void endDraw(const VertexType &vertexType);
|
void endDraw(const VertexType &vertexType);
|
||||||
|
|
||||||
|
@ -372,9 +370,8 @@ private:
|
||||||
|
|
||||||
bool EnableErrorTest;
|
bool EnableErrorTest;
|
||||||
|
|
||||||
unsigned QuadIndexCount;
|
OpenGLVBO QuadIndexVBO;
|
||||||
GLuint QuadIndexBuffer = 0;
|
void initQuadsIndices(u32 max_vertex_count = 65536);
|
||||||
void initQuadsIndices(int max_vertex_count = 65536);
|
|
||||||
|
|
||||||
void debugCb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message);
|
void debugCb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message);
|
||||||
static void APIENTRY debugCb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam);
|
static void APIENTRY debugCb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam);
|
||||||
|
|
|
@ -161,6 +161,7 @@ public:
|
||||||
GL.BlendEquation(mode);
|
GL.BlendEquation(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LODBiasSupported = false;
|
||||||
bool AnisotropicFilterSupported = false;
|
bool AnisotropicFilterSupported = false;
|
||||||
bool BlendMinMaxSupported = false;
|
bool BlendMinMaxSupported = false;
|
||||||
bool TextureMultisampleSupported = false;
|
bool TextureMultisampleSupported = false;
|
||||||
|
|
|
@ -32,6 +32,7 @@ COpenGL3Renderer2D::COpenGL3Renderer2D(const c8 *vertexShaderProgram, const c8 *
|
||||||
|
|
||||||
// These states don't change later.
|
// These states don't change later.
|
||||||
|
|
||||||
|
ProjectionID = getPixelShaderConstantID("uProjection");
|
||||||
ThicknessID = getPixelShaderConstantID("uThickness");
|
ThicknessID = getPixelShaderConstantID("uThickness");
|
||||||
if (WithTexture) {
|
if (WithTexture) {
|
||||||
TextureUsageID = getPixelShaderConstantID("uTextureUsage");
|
TextureUsageID = getPixelShaderConstantID("uTextureUsage");
|
||||||
|
@ -62,6 +63,17 @@ void COpenGL3Renderer2D::OnSetMaterial(const video::SMaterial &material,
|
||||||
f32 Thickness = (material.Thickness > 0.f) ? material.Thickness : 1.f;
|
f32 Thickness = (material.Thickness > 0.f) ? material.Thickness : 1.f;
|
||||||
setPixelShaderConstant(ThicknessID, &Thickness, 1);
|
setPixelShaderConstant(ThicknessID, &Thickness, 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
// Update projection matrix
|
||||||
|
const core::dimension2d<u32> renderTargetSize = Driver->getCurrentRenderTargetSize();
|
||||||
|
core::matrix4 proj;
|
||||||
|
float xInv2 = 2.0f / renderTargetSize.Width;
|
||||||
|
float yInv2 = 2.0f / renderTargetSize.Height;
|
||||||
|
proj.setScale({ xInv2, -yInv2, 0.0f });
|
||||||
|
proj.setTranslation({ -1.0f, 1.0f, 0.0f });
|
||||||
|
setPixelShaderConstant(ProjectionID, proj.pointer(), 4 * 4);
|
||||||
|
}
|
||||||
|
|
||||||
if (WithTexture) {
|
if (WithTexture) {
|
||||||
s32 TextureUsage = material.TextureLayers[0].Texture ? 1 : 0;
|
s32 TextureUsage = material.TextureLayers[0].Texture ? 1 : 0;
|
||||||
setPixelShaderConstant(TextureUsageID, &TextureUsage, 1);
|
setPixelShaderConstant(TextureUsageID, &TextureUsage, 1);
|
||||||
|
|
|
@ -24,6 +24,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool WithTexture;
|
bool WithTexture;
|
||||||
|
s32 ProjectionID;
|
||||||
s32 ThicknessID;
|
s32 ThicknessID;
|
||||||
s32 TextureUsageID;
|
s32 TextureUsageID;
|
||||||
};
|
};
|
||||||
|
|
51
irr/src/OpenGL/VBO.cpp
Normal file
51
irr/src/OpenGL/VBO.cpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// Copyright (C) 2024 sfan5
|
||||||
|
// This file is part of the "Irrlicht Engine".
|
||||||
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||||
|
|
||||||
|
#include "VBO.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <mt_opengl.h>
|
||||||
|
|
||||||
|
namespace irr
|
||||||
|
{
|
||||||
|
namespace video
|
||||||
|
{
|
||||||
|
|
||||||
|
void OpenGLVBO::upload(const void *data, size_t size, size_t offset,
|
||||||
|
GLenum usage, bool mustShrink)
|
||||||
|
{
|
||||||
|
bool newBuffer = false;
|
||||||
|
assert(!(mustShrink && offset > 0)); // forbidden usage
|
||||||
|
if (!m_name) {
|
||||||
|
GL.GenBuffers(1, &m_name);
|
||||||
|
if (!m_name)
|
||||||
|
return;
|
||||||
|
newBuffer = true;
|
||||||
|
} else if (size > m_size || mustShrink) {
|
||||||
|
newBuffer = size != m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.BindBuffer(GL_ARRAY_BUFFER, m_name);
|
||||||
|
|
||||||
|
if (newBuffer) {
|
||||||
|
assert(offset == 0);
|
||||||
|
GL.BufferData(GL_ARRAY_BUFFER, size, data, usage);
|
||||||
|
m_size = size;
|
||||||
|
} else {
|
||||||
|
GL.BufferSubData(GL_ARRAY_BUFFER, offset, size, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.BindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVBO::destroy()
|
||||||
|
{
|
||||||
|
if (m_name)
|
||||||
|
GL.DeleteBuffers(1, &m_name);
|
||||||
|
m_name = 0;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
57
irr/src/OpenGL/VBO.h
Normal file
57
irr/src/OpenGL/VBO.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright (C) 2024 sfan5
|
||||||
|
// This file is part of the "Irrlicht Engine".
|
||||||
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace irr
|
||||||
|
{
|
||||||
|
namespace video
|
||||||
|
{
|
||||||
|
|
||||||
|
class OpenGLVBO
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// @note does not create on GL side
|
||||||
|
OpenGLVBO() = default;
|
||||||
|
/// @note does not free on GL side
|
||||||
|
~OpenGLVBO() = default;
|
||||||
|
|
||||||
|
/// @return "name" (ID) of this buffer in GL
|
||||||
|
GLuint getName() const { return m_name; }
|
||||||
|
/// @return does this refer to an existing GL buffer?
|
||||||
|
bool exists() const { return m_name != 0; }
|
||||||
|
|
||||||
|
/// @return size of this buffer in bytes
|
||||||
|
size_t getSize() const { return m_size; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload buffer data to GL.
|
||||||
|
*
|
||||||
|
* Changing the size of the buffer is only possible when `offset == 0`.
|
||||||
|
* @param data data pointer
|
||||||
|
* @param size number of bytes
|
||||||
|
* @param offset offset to upload at
|
||||||
|
* @param usage usage pattern passed to GL (only if buffer is new)
|
||||||
|
* @param mustShrink force re-create of buffer if it became smaller
|
||||||
|
* @note modifies GL_ARRAY_BUFFER binding
|
||||||
|
*/
|
||||||
|
void upload(const void *data, size_t size, size_t offset,
|
||||||
|
GLenum usage, bool mustShrink = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free buffer in GL.
|
||||||
|
* @note modifies GL_ARRAY_BUFFER binding
|
||||||
|
*/
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
private:
|
||||||
|
GLuint m_name = 0;
|
||||||
|
size_t m_size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,6 +69,7 @@ void COpenGL3Driver::initFeatures()
|
||||||
TextureFormats[ECF_D24S8] = {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8};
|
TextureFormats[ECF_D24S8] = {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8};
|
||||||
|
|
||||||
AnisotropicFilterSupported = isVersionAtLeast(4, 6) || queryExtension("GL_ARB_texture_filter_anisotropic") || queryExtension("GL_EXT_texture_filter_anisotropic");
|
AnisotropicFilterSupported = isVersionAtLeast(4, 6) || queryExtension("GL_ARB_texture_filter_anisotropic") || queryExtension("GL_EXT_texture_filter_anisotropic");
|
||||||
|
LODBiasSupported = true;
|
||||||
BlendMinMaxSupported = true;
|
BlendMinMaxSupported = true;
|
||||||
TextureMultisampleSupported = true;
|
TextureMultisampleSupported = true;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace video
|
||||||
/// OpenGL 3+ driver
|
/// OpenGL 3+ driver
|
||||||
///
|
///
|
||||||
/// For OpenGL 3.2 and higher. Compatibility profile is required currently.
|
/// For OpenGL 3.2 and higher. Compatibility profile is required currently.
|
||||||
class COpenGL3Driver : public COpenGL3DriverBase
|
class COpenGL3Driver final : public COpenGL3DriverBase
|
||||||
{
|
{
|
||||||
friend IVideoDriver *createOpenGL3Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager);
|
friend IVideoDriver *createOpenGL3Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager);
|
||||||
|
|
||||||
|
|
|
@ -120,10 +120,10 @@ void COpenGLES2Driver::initFeatures()
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool MRTSupported = Version.Major >= 3 || queryExtension("GL_EXT_draw_buffers");
|
const bool MRTSupported = Version.Major >= 3 || queryExtension("GL_EXT_draw_buffers");
|
||||||
|
LODBiasSupported = queryExtension("GL_EXT_texture_lod_bias");
|
||||||
AnisotropicFilterSupported = queryExtension("GL_EXT_texture_filter_anisotropic");
|
AnisotropicFilterSupported = queryExtension("GL_EXT_texture_filter_anisotropic");
|
||||||
BlendMinMaxSupported = (Version.Major >= 3) || FeatureAvailable[IRR_GL_EXT_blend_minmax];
|
BlendMinMaxSupported = (Version.Major >= 3) || FeatureAvailable[IRR_GL_EXT_blend_minmax];
|
||||||
TextureMultisampleSupported = isVersionAtLeast(3, 1);
|
TextureMultisampleSupported = isVersionAtLeast(3, 1);
|
||||||
const bool TextureLODBiasSupported = queryExtension("GL_EXT_texture_lod_bias");
|
|
||||||
|
|
||||||
// COGLESCoreExtensionHandler::Feature
|
// COGLESCoreExtensionHandler::Feature
|
||||||
static_assert(MATERIAL_MAX_TEXTURES <= 8, "Only up to 8 textures are guaranteed");
|
static_assert(MATERIAL_MAX_TEXTURES <= 8, "Only up to 8 textures are guaranteed");
|
||||||
|
@ -141,7 +141,7 @@ void COpenGLES2Driver::initFeatures()
|
||||||
if (Version.Major >= 3 || queryExtension("GL_EXT_draw_range_elements"))
|
if (Version.Major >= 3 || queryExtension("GL_EXT_draw_range_elements"))
|
||||||
MaxIndices = GetInteger(GL_MAX_ELEMENTS_INDICES);
|
MaxIndices = GetInteger(GL_MAX_ELEMENTS_INDICES);
|
||||||
MaxTextureSize = GetInteger(GL_MAX_TEXTURE_SIZE);
|
MaxTextureSize = GetInteger(GL_MAX_TEXTURE_SIZE);
|
||||||
if (TextureLODBiasSupported)
|
if (LODBiasSupported)
|
||||||
GL.GetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &MaxTextureLODBias);
|
GL.GetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &MaxTextureLODBias);
|
||||||
GL.GetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, DimAliasedLine); // NOTE: this is not in the OpenGL ES 2.0 spec...
|
GL.GetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, DimAliasedLine); // NOTE: this is not in the OpenGL ES 2.0 spec...
|
||||||
GL.GetFloatv(GL_ALIASED_POINT_SIZE_RANGE, DimAliasedPoint);
|
GL.GetFloatv(GL_ALIASED_POINT_SIZE_RANGE, DimAliasedPoint);
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace video
|
||||||
/// OpenGL ES 2+ driver
|
/// OpenGL ES 2+ driver
|
||||||
///
|
///
|
||||||
/// For OpenGL ES 2.0 and higher.
|
/// For OpenGL ES 2.0 and higher.
|
||||||
class COpenGLES2Driver : public COpenGL3DriverBase
|
class COpenGLES2Driver final : public COpenGL3DriverBase
|
||||||
{
|
{
|
||||||
friend IVideoDriver *createOGLES2Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager);
|
friend IVideoDriver *createOGLES2Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager);
|
||||||
|
|
||||||
|
|
|
@ -573,7 +573,7 @@ SkinnedMesh *SkinnedMeshBuilder::finalize()
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkinnedMesh::updateBoundingBox(void)
|
void SkinnedMesh::updateBoundingBox()
|
||||||
{
|
{
|
||||||
if (!SkinningBuffers)
|
if (!SkinningBuffers)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -160,11 +160,12 @@ void Printer::print(const c8 *message, ELOG_LEVEL ll)
|
||||||
|
|
||||||
// Android logcat restricts log-output and cuts the rest of the message away. But we want it all.
|
// Android logcat restricts log-output and cuts the rest of the message away. But we want it all.
|
||||||
// On my device max-len is 1023 (+ 0 byte). Some websites claim a limit of 4096 so maybe different numbers on different devices.
|
// On my device max-len is 1023 (+ 0 byte). Some websites claim a limit of 4096 so maybe different numbers on different devices.
|
||||||
const size_t maxLogLen = 1023;
|
constexpr size_t maxLogLen = 1023;
|
||||||
size_t msgLen = strlen(message);
|
size_t msgLen = strlen(message);
|
||||||
size_t start = 0;
|
size_t start = 0;
|
||||||
while (msgLen - start > maxLogLen) {
|
while (msgLen - start > maxLogLen) {
|
||||||
__android_log_print(LogLevel, "Irrlicht", "%.*s\n", maxLogLen, &message[start]);
|
__android_log_print(LogLevel, "Irrlicht", "%.*s\n",
|
||||||
|
static_cast<int>(maxLogLen), &message[start]);
|
||||||
start += maxLogLen;
|
start += maxLogLen;
|
||||||
}
|
}
|
||||||
__android_log_print(LogLevel, "Irrlicht", "%s\n", &message[start]);
|
__android_log_print(LogLevel, "Irrlicht", "%s\n", &message[start]);
|
||||||
|
|
|
@ -101,7 +101,7 @@ std::vector<DistanceSortedActiveObject> ActiveObjectMgr::getActiveSelectableObje
|
||||||
if (!obj)
|
if (!obj)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
aabb3f selection_box;
|
aabb3f selection_box{{0.0f, 0.0f, 0.0f}};
|
||||||
if (!obj->getSelectionBox(&selection_box))
|
if (!obj->getSelectionBox(&selection_box))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -430,7 +430,7 @@ void ClientEnvironment::getSelectedActiveObjects(
|
||||||
|
|
||||||
for (const auto &allObject : allObjects) {
|
for (const auto &allObject : allObjects) {
|
||||||
ClientActiveObject *obj = allObject.obj;
|
ClientActiveObject *obj = allObject.obj;
|
||||||
aabb3f selection_box;
|
aabb3f selection_box{{0.0f, 0.0f, 0.0f}};
|
||||||
if (!obj->getSelectionBox(&selection_box))
|
if (!obj->getSelectionBox(&selection_box))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -301,24 +301,29 @@ void ClientLauncher::init_input()
|
||||||
else
|
else
|
||||||
input = new RealInputHandler(receiver);
|
input = new RealInputHandler(receiver);
|
||||||
|
|
||||||
if (g_settings->getBool("enable_joysticks")) {
|
if (g_settings->getBool("enable_joysticks"))
|
||||||
irr::core::array<irr::SJoystickInfo> infos;
|
init_joysticks();
|
||||||
std::vector<irr::SJoystickInfo> joystick_infos;
|
}
|
||||||
|
|
||||||
// Make sure this is called maximum once per
|
void ClientLauncher::init_joysticks()
|
||||||
// irrlicht device, otherwise it will give you
|
{
|
||||||
// multiple events for the same joystick.
|
irr::core::array<irr::SJoystickInfo> infos;
|
||||||
if (m_rendering_engine->get_raw_device()->activateJoysticks(infos)) {
|
std::vector<irr::SJoystickInfo> joystick_infos;
|
||||||
infostream << "Joystick support enabled" << std::endl;
|
|
||||||
joystick_infos.reserve(infos.size());
|
// Make sure this is called maximum once per
|
||||||
for (u32 i = 0; i < infos.size(); i++) {
|
// irrlicht device, otherwise it will give you
|
||||||
joystick_infos.push_back(infos[i]);
|
// multiple events for the same joystick.
|
||||||
}
|
if (!m_rendering_engine->get_raw_device()->activateJoysticks(infos)) {
|
||||||
input->joystick.onJoystickConnect(joystick_infos);
|
errorstream << "Could not activate joystick support." << std::endl;
|
||||||
} else {
|
return;
|
||||||
errorstream << "Could not activate joystick support." << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infostream << "Joystick support enabled" << std::endl;
|
||||||
|
joystick_infos.reserve(infos.size());
|
||||||
|
for (u32 i = 0; i < infos.size(); i++) {
|
||||||
|
joystick_infos.push_back(infos[i]);
|
||||||
|
}
|
||||||
|
input->joystick.onJoystickConnect(joystick_infos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientLauncher::setting_changed_callback(const std::string &name, void *data)
|
void ClientLauncher::setting_changed_callback(const std::string &name, void *data)
|
||||||
|
|
|
@ -26,6 +26,7 @@ private:
|
||||||
void init_args(GameStartData &start_data, const Settings &cmd_args);
|
void init_args(GameStartData &start_data, const Settings &cmd_args);
|
||||||
bool init_engine();
|
bool init_engine();
|
||||||
void init_input();
|
void init_input();
|
||||||
|
void init_joysticks();
|
||||||
|
|
||||||
static void setting_changed_callback(const std::string &name, void *data);
|
static void setting_changed_callback(const std::string &name, void *data);
|
||||||
void config_guienv();
|
void config_guienv();
|
||||||
|
|
|
@ -22,16 +22,27 @@
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// A helper struct
|
// data structure that groups block meshes by material
|
||||||
struct MeshBufListMaps
|
struct MeshBufListMaps
|
||||||
{
|
{
|
||||||
using MeshBufListMap = std::unordered_map<
|
// first = block pos
|
||||||
video::SMaterial,
|
using MeshBuf = std::pair<v3s16, scene::IMeshBuffer*>;
|
||||||
std::vector<std::pair<v3s16, scene::IMeshBuffer *>>
|
|
||||||
>;
|
using MeshBufList = std::vector<MeshBuf>;
|
||||||
|
|
||||||
|
using MeshBufListMap = std::unordered_map<video::SMaterial, MeshBufList>;
|
||||||
|
|
||||||
std::array<MeshBufListMap, MAX_TILE_LAYERS> maps;
|
std::array<MeshBufListMap, MAX_TILE_LAYERS> maps;
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
for (auto &map : maps) {
|
||||||
|
if (!map.empty())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
for (auto &map : maps)
|
for (auto &map : maps)
|
||||||
|
@ -48,7 +59,67 @@ namespace {
|
||||||
auto &bufs = map[m]; // default constructs if non-existent
|
auto &bufs = map[m]; // default constructs if non-existent
|
||||||
bufs.emplace_back(position, buf);
|
bufs.emplace_back(position, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addFromBlock(v3s16 block_pos, MapBlockMesh *block_mesh,
|
||||||
|
video::IVideoDriver *driver);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// reference to a mesh buffer used when rendering the map.
|
||||||
|
struct DrawDescriptor {
|
||||||
|
v3f m_pos; // world translation
|
||||||
|
bool m_reuse_material:1;
|
||||||
|
bool m_use_partial_buffer:1;
|
||||||
|
union {
|
||||||
|
scene::IMeshBuffer *m_buffer;
|
||||||
|
const PartialMeshBuffer *m_partial_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
DrawDescriptor(v3f pos, scene::IMeshBuffer *buffer, bool reuse_material = true) :
|
||||||
|
m_pos(pos), m_reuse_material(reuse_material), m_use_partial_buffer(false),
|
||||||
|
m_buffer(buffer)
|
||||||
|
{}
|
||||||
|
|
||||||
|
DrawDescriptor(v3f pos, const PartialMeshBuffer *buffer) :
|
||||||
|
m_pos(pos), m_reuse_material(false), m_use_partial_buffer(true),
|
||||||
|
m_partial_buffer(buffer)
|
||||||
|
{}
|
||||||
|
|
||||||
|
video::SMaterial &getMaterial();
|
||||||
|
/// @return number of vertices drawn
|
||||||
|
u32 draw(video::IVideoDriver* driver);
|
||||||
|
};
|
||||||
|
|
||||||
|
using DrawDescriptorList = std::vector<DrawDescriptor>;
|
||||||
|
|
||||||
|
/// @brief Append vertices to a mesh buffer
|
||||||
|
/// @note does not update bounding box!
|
||||||
|
void appendToMeshBuffer(scene::SMeshBuffer *dst, const scene::IMeshBuffer *src, v3f translate)
|
||||||
|
{
|
||||||
|
const size_t vcount = dst->Vertices->Data.size();
|
||||||
|
const size_t icount = dst->Indices->Data.size();
|
||||||
|
|
||||||
|
assert(src->getVertexType() == video::EVT_STANDARD);
|
||||||
|
const auto vptr = static_cast<const video::S3DVertex*>(src->getVertices());
|
||||||
|
dst->Vertices->Data.insert(dst->Vertices->Data.end(),
|
||||||
|
vptr, vptr + src->getVertexCount());
|
||||||
|
// apply translation
|
||||||
|
for (size_t j = vcount; j < dst->Vertices->Data.size(); j++)
|
||||||
|
dst->Vertices->Data[j].Pos += translate;
|
||||||
|
|
||||||
|
const auto iptr = src->getIndices();
|
||||||
|
dst->Indices->Data.insert(dst->Indices->Data.end(),
|
||||||
|
iptr, iptr + src->getIndexCount());
|
||||||
|
// fixup indices
|
||||||
|
if (vcount != 0) {
|
||||||
|
for (size_t j = icount; j < dst->Indices->Data.size(); j++)
|
||||||
|
dst->Indices->Data[j] += vcount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T subtract_or_zero(T a, T b) {
|
||||||
|
return b >= a ? T(0) : (a - b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -90,8 +161,7 @@ ClientMap::ClientMap(
|
||||||
* the class is whith a name ;) Name property cames from ISceneNode base class.
|
* the class is whith a name ;) Name property cames from ISceneNode base class.
|
||||||
*/
|
*/
|
||||||
Name = "ClientMap";
|
Name = "ClientMap";
|
||||||
m_box = aabb3f(-BS*1000000,-BS*1000000,-BS*1000000,
|
setAutomaticCulling(scene::EAC_OFF);
|
||||||
BS*1000000,BS*1000000,BS*1000000);
|
|
||||||
|
|
||||||
for (const auto &name : ClientMap_settings)
|
for (const auto &name : ClientMap_settings)
|
||||||
g_settings->registerChangedCallback(name, on_settings_changed, this);
|
g_settings->registerChangedCallback(name, on_settings_changed, this);
|
||||||
|
@ -299,7 +369,7 @@ void ClientMap::updateDrawList()
|
||||||
}
|
}
|
||||||
|
|
||||||
const v3s16 camera_block = getContainerPos(cam_pos_nodes, MAP_BLOCKSIZE);
|
const v3s16 camera_block = getContainerPos(cam_pos_nodes, MAP_BLOCKSIZE);
|
||||||
m_drawlist = std::map<v3s16, MapBlock*, MapBlockComparer>(MapBlockComparer(camera_block));
|
m_drawlist = decltype(m_drawlist)(MapBlockComparer(camera_block));
|
||||||
|
|
||||||
auto is_frustum_culled = m_client->getCamera()->getFrustumCuller();
|
auto is_frustum_culled = m_client->getCamera()->getFrustumCuller();
|
||||||
|
|
||||||
|
@ -692,23 +762,132 @@ void ClientMap::touchMapBlocks()
|
||||||
g_profiler->avg("MapBlocks loaded [#]", blocks_loaded);
|
g_profiler->avg("MapBlocks loaded [#]", blocks_loaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MeshBufListMaps::addFromBlock(v3s16 block_pos, MapBlockMesh *block_mesh,
|
||||||
|
video::IVideoDriver *driver)
|
||||||
|
{
|
||||||
|
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
|
||||||
|
scene::IMesh *mesh = block_mesh->getMesh(layer);
|
||||||
|
assert(mesh);
|
||||||
|
|
||||||
|
u32 c = mesh->getMeshBufferCount();
|
||||||
|
for (u32 i = 0; i < c; i++) {
|
||||||
|
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
|
||||||
|
|
||||||
|
auto &material = buf->getMaterial();
|
||||||
|
auto *rnd = driver->getMaterialRenderer(material.MaterialType);
|
||||||
|
bool transparent = rnd && rnd->isTransparent();
|
||||||
|
if (!transparent)
|
||||||
|
add(buf, block_pos, layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy a list of mesh buffers into the draw order, while potentially
|
||||||
|
* merging some.
|
||||||
|
* @param src buffer list
|
||||||
|
* @param dst draw order
|
||||||
|
* @param get_world_pos returns translation for a buffer
|
||||||
|
* @param buffer_trash output container for temporary mesh buffers
|
||||||
|
* @return number of buffers that were merged
|
||||||
|
*/
|
||||||
|
template <typename F, typename C>
|
||||||
|
static u32 transformBuffersToDrawOrder(
|
||||||
|
const MeshBufListMaps::MeshBufList &src, DrawDescriptorList &draw_order,
|
||||||
|
F get_world_pos, C &buffer_trash)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* This is a tradeoff between time spent merging buffers and time spent
|
||||||
|
* due to excess drawcalls.
|
||||||
|
* Testing has shown that the ideal value is in the low hundreds, as extra
|
||||||
|
* CPU work quickly eats up the benefits.
|
||||||
|
* In MTG landscape scenes this was found to save around 20-40% of drawcalls.
|
||||||
|
*
|
||||||
|
* NOTE: if you attempt to test this with quicktune, it won't give you valid
|
||||||
|
* results since HW buffers stick around and Irrlicht handles large amounts
|
||||||
|
* inefficiently.
|
||||||
|
*
|
||||||
|
* TODO: as a next step we should cache merged meshes, so they do not need
|
||||||
|
* to be re-built *and* can be kept in GPU memory.
|
||||||
|
*/
|
||||||
|
const u32 target_min_vertices = g_settings->getU32("mesh_buffer_min_vertices");
|
||||||
|
|
||||||
|
const auto draw_order_pre = draw_order.size();
|
||||||
|
auto *driver = RenderingEngine::get_video_driver();
|
||||||
|
|
||||||
|
// check if we can even merge anything
|
||||||
|
u32 can_merge = 0;
|
||||||
|
u32 total_vtx = 0, total_idx = 0;
|
||||||
|
for (auto &pair : src) {
|
||||||
|
if (pair.second->getVertexCount() < target_min_vertices) {
|
||||||
|
can_merge++;
|
||||||
|
total_vtx += pair.second->getVertexCount();
|
||||||
|
total_idx += pair.second->getIndexCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scene::SMeshBuffer *tmp = nullptr;
|
||||||
|
const auto &finish_buf = [&] () {
|
||||||
|
if (tmp) {
|
||||||
|
draw_order.emplace_back(v3f(0), tmp);
|
||||||
|
total_vtx = subtract_or_zero(total_vtx, tmp->getVertexCount());
|
||||||
|
total_idx = subtract_or_zero(total_idx, tmp->getIndexCount());
|
||||||
|
|
||||||
|
// Upload buffer here explicitly to give the driver some
|
||||||
|
// extra time to get it ready before drawing.
|
||||||
|
tmp->setHardwareMappingHint(scene::EHM_STREAM);
|
||||||
|
driver->updateHardwareBuffer(tmp->getVertexBuffer());
|
||||||
|
driver->updateHardwareBuffer(tmp->getIndexBuffer());
|
||||||
|
}
|
||||||
|
tmp = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// iterate in reverse to get closest blocks first
|
||||||
|
for (auto it = src.rbegin(); it != src.rend(); ++it) {
|
||||||
|
v3f translate = get_world_pos(it->first);
|
||||||
|
auto *buf = it->second;
|
||||||
|
if (can_merge < 2 || buf->getVertexCount() >= target_min_vertices) {
|
||||||
|
draw_order.emplace_back(translate, buf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool new_buffer = false;
|
||||||
|
if (!tmp)
|
||||||
|
new_buffer = true;
|
||||||
|
else if (tmp->getVertexCount() + buf->getVertexCount() > U16_MAX)
|
||||||
|
new_buffer = true;
|
||||||
|
if (new_buffer) {
|
||||||
|
finish_buf();
|
||||||
|
tmp = new scene::SMeshBuffer();
|
||||||
|
buffer_trash.push_back(tmp);
|
||||||
|
assert(tmp->getPrimitiveType() == buf->getPrimitiveType());
|
||||||
|
tmp->Material = buf->getMaterial();
|
||||||
|
// preallocate
|
||||||
|
tmp->Vertices->Data.reserve(total_vtx);
|
||||||
|
tmp->Indices->Data.reserve(total_idx);
|
||||||
|
}
|
||||||
|
appendToMeshBuffer(tmp, buf, translate);
|
||||||
|
}
|
||||||
|
finish_buf();
|
||||||
|
|
||||||
|
// first call needs to set the material
|
||||||
|
if (draw_order.size() > draw_order_pre)
|
||||||
|
draw_order[draw_order_pre].m_reuse_material = false;
|
||||||
|
|
||||||
|
return can_merge < 2 ? 0 : can_merge;
|
||||||
|
}
|
||||||
|
|
||||||
void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
{
|
{
|
||||||
ZoneScoped;
|
ZoneScoped;
|
||||||
|
|
||||||
bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
|
const bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
|
||||||
|
|
||||||
std::string prefix;
|
std::string prefix;
|
||||||
if (pass == scene::ESNRP_SOLID)
|
if (pass == scene::ESNRP_SOLID)
|
||||||
prefix = "renderMap(SOLID): ";
|
prefix = "renderMap(SOLID): ";
|
||||||
else
|
else
|
||||||
prefix = "renderMap(TRANSPARENT): ";
|
prefix = "renderMap(TRANS): ";
|
||||||
|
|
||||||
/*
|
|
||||||
This is called two times per frame, reset on the non-transparent one
|
|
||||||
*/
|
|
||||||
if (pass == scene::ESNRP_SOLID)
|
|
||||||
m_last_drawn_sectors.clear();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get animation parameters
|
Get animation parameters
|
||||||
|
@ -719,16 +898,16 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
|
|
||||||
const v3f camera_position = m_camera_position;
|
const v3f camera_position = m_camera_position;
|
||||||
|
|
||||||
/*
|
const auto mesh_grid = m_client->getMeshGrid();
|
||||||
Get all blocks and draw all visible ones
|
// Gets world position from block map position
|
||||||
*/
|
const auto get_block_wpos = [&] (v3s16 pos) -> v3f {
|
||||||
|
return intToFloat(mesh_grid.getMeshPos(pos) * MAP_BLOCKSIZE - m_camera_offset, BS);
|
||||||
|
};
|
||||||
|
|
||||||
u32 vertex_count = 0;
|
u32 merged_count = 0;
|
||||||
u32 drawcall_count = 0;
|
|
||||||
|
|
||||||
// For limiting number of mesh animations per frame
|
// For limiting number of mesh animations per frame
|
||||||
u32 mesh_animate_count = 0;
|
u32 mesh_animate_count = 0;
|
||||||
//u32 mesh_animate_count_far = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Update transparent meshes
|
Update transparent meshes
|
||||||
|
@ -737,18 +916,18 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
updateTransparentMeshBuffers();
|
updateTransparentMeshBuffers();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Draw the selected MapBlocks
|
Collect everything we need to draw
|
||||||
*/
|
*/
|
||||||
|
TimeTaker tt_collect("");
|
||||||
|
|
||||||
MeshBufListMaps grouped_buffers;
|
MeshBufListMaps grouped_buffers;
|
||||||
std::vector<DrawDescriptor> draw_order;
|
std::vector<scene::IMeshBuffer*> buffer_trash;
|
||||||
video::SMaterial previous_material;
|
DrawDescriptorList draw_order;
|
||||||
|
|
||||||
auto is_frustum_culled = m_client->getCamera()->getFrustumCuller();
|
auto is_frustum_culled = m_client->getCamera()->getFrustumCuller();
|
||||||
|
|
||||||
const MeshGrid mesh_grid = m_client->getMeshGrid();
|
|
||||||
for (auto &i : m_drawlist) {
|
for (auto &i : m_drawlist) {
|
||||||
v3s16 block_pos = i.first;
|
const v3s16 block_pos = i.first;
|
||||||
MapBlock *block = i.second;
|
MapBlock *block = i.second;
|
||||||
MapBlockMesh *block_mesh = block->mesh;
|
MapBlockMesh *block_mesh = block->mesh;
|
||||||
|
|
||||||
|
@ -789,49 +968,28 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
// In transparent pass, the mesh will give us
|
// In transparent pass, the mesh will give us
|
||||||
// the partial buffers in the correct order
|
// the partial buffers in the correct order
|
||||||
for (auto &buffer : block_mesh->getTransparentBuffers())
|
for (auto &buffer : block_mesh->getTransparentBuffers())
|
||||||
draw_order.emplace_back(block_pos, &buffer);
|
draw_order.emplace_back(get_block_wpos(block_pos), &buffer);
|
||||||
}
|
} else {
|
||||||
else {
|
// Otherwise, group them
|
||||||
// otherwise, group buffers across meshes
|
grouped_buffers.addFromBlock(block_pos, block_mesh, driver);
|
||||||
// using MeshBufListMaps
|
|
||||||
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
|
|
||||||
scene::IMesh *mesh = block_mesh->getMesh(layer);
|
|
||||||
assert(mesh);
|
|
||||||
|
|
||||||
u32 c = mesh->getMeshBufferCount();
|
|
||||||
for (u32 i = 0; i < c; i++) {
|
|
||||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
|
|
||||||
|
|
||||||
video::SMaterial& material = buf->getMaterial();
|
|
||||||
video::IMaterialRenderer* rnd =
|
|
||||||
driver->getMaterialRenderer(material.MaterialType);
|
|
||||||
bool transparent = (rnd && rnd->isTransparent());
|
|
||||||
if (!transparent) {
|
|
||||||
if (buf->getVertexCount() == 0)
|
|
||||||
errorstream << "Block [" << analyze_block(block)
|
|
||||||
<< "] contains an empty meshbuf" << std::endl;
|
|
||||||
|
|
||||||
grouped_buffers.add(buf, block_pos, layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capture draw order for all solid meshes
|
assert(!is_transparent_pass || grouped_buffers.empty());
|
||||||
for (auto &map : grouped_buffers.maps) {
|
for (auto &map : grouped_buffers.maps) {
|
||||||
for (auto &list : map) {
|
for (auto &list : map) {
|
||||||
// iterate in reverse to draw closest blocks first
|
merged_count += transformBuffersToDrawOrder(
|
||||||
for (auto it = list.second.rbegin(); it != list.second.rend(); ++it) {
|
list.second, draw_order, get_block_wpos, buffer_trash);
|
||||||
draw_order.emplace_back(it->first, it->second, it != list.second.rbegin());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeTaker draw("Drawing mesh buffers");
|
g_profiler->avg(prefix + "collecting [ms]", tt_collect.stop(true));
|
||||||
|
|
||||||
|
TimeTaker tt_draw("");
|
||||||
|
|
||||||
core::matrix4 m; // Model matrix
|
core::matrix4 m; // Model matrix
|
||||||
v3f offset = intToFloat(m_camera_offset, BS);
|
u32 vertex_count = 0;
|
||||||
|
u32 drawcall_count = 0;
|
||||||
u32 material_swaps = 0;
|
u32 material_swaps = 0;
|
||||||
|
|
||||||
// Render all mesh buffers in order
|
// Render all mesh buffers in order
|
||||||
|
@ -867,18 +1025,17 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
material.TextureLayers[ShadowRenderer::TEXTURE_LAYER_SHADOW].Texture = nullptr;
|
material.TextureLayers[ShadowRenderer::TEXTURE_LAYER_SHADOW].Texture = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
v3f block_wpos = intToFloat(mesh_grid.getMeshPos(descriptor.m_pos) * MAP_BLOCKSIZE, BS);
|
m.setTranslation(descriptor.m_pos);
|
||||||
m.setTranslation(block_wpos - offset);
|
|
||||||
|
|
||||||
driver->setTransform(video::ETS_WORLD, m);
|
driver->setTransform(video::ETS_WORLD, m);
|
||||||
|
|
||||||
vertex_count += descriptor.draw(driver);
|
vertex_count += descriptor.draw(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));
|
g_profiler->avg(prefix + "draw meshes [ms]", tt_draw.stop(true));
|
||||||
|
|
||||||
// Log only on solid pass because values are the same
|
|
||||||
if (pass == scene::ESNRP_SOLID) {
|
if (pass == scene::ESNRP_SOLID) {
|
||||||
g_profiler->avg("renderMap(): animated meshes [#]", mesh_animate_count);
|
g_profiler->avg("renderMap(): animated meshes [#]", mesh_animate_count);
|
||||||
|
g_profiler->avg(prefix + "merged buffers [#]", merged_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pass == scene::ESNRP_TRANSPARENT) {
|
if (pass == scene::ESNRP_TRANSPARENT) {
|
||||||
|
@ -888,6 +1045,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
|
g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
|
||||||
g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
|
g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
|
||||||
g_profiler->avg(prefix + "material swaps [#]", material_swaps);
|
g_profiler->avg(prefix + "material swaps [#]", material_swaps);
|
||||||
|
|
||||||
|
for (auto &x : buffer_trash)
|
||||||
|
x->drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
|
static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
|
||||||
|
@ -1096,12 +1256,15 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
|
||||||
else
|
else
|
||||||
prefix = "renderMap(SHADOW SOLID): ";
|
prefix = "renderMap(SHADOW SOLID): ";
|
||||||
|
|
||||||
u32 drawcall_count = 0;
|
const auto mesh_grid = m_client->getMeshGrid();
|
||||||
u32 vertex_count = 0;
|
// Gets world position from block map position
|
||||||
|
const auto get_block_wpos = [&] (v3s16 pos) -> v3f {
|
||||||
|
return intToFloat(mesh_grid.getMeshPos(pos) * MAP_BLOCKSIZE - m_camera_offset, BS);
|
||||||
|
};
|
||||||
|
|
||||||
MeshBufListMaps grouped_buffers;
|
MeshBufListMaps grouped_buffers;
|
||||||
std::vector<DrawDescriptor> draw_order;
|
std::vector<scene::IMeshBuffer*> buffer_trash;
|
||||||
|
DrawDescriptorList draw_order;
|
||||||
|
|
||||||
std::size_t count = 0;
|
std::size_t count = 0;
|
||||||
std::size_t meshes_per_frame = m_drawlist_shadow.size() / total_frames + 1;
|
std::size_t meshes_per_frame = m_drawlist_shadow.size() / total_frames + 1;
|
||||||
|
@ -1113,7 +1276,6 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MeshGrid mesh_grid = m_client->getMeshGrid();
|
|
||||||
for (const auto &i : m_drawlist_shadow) {
|
for (const auto &i : m_drawlist_shadow) {
|
||||||
// only process specific part of the list & break early
|
// only process specific part of the list & break early
|
||||||
++count;
|
++count;
|
||||||
|
@ -1136,52 +1298,25 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
|
||||||
// In transparent pass, the mesh will give us
|
// In transparent pass, the mesh will give us
|
||||||
// the partial buffers in the correct order
|
// the partial buffers in the correct order
|
||||||
for (auto &buffer : block->mesh->getTransparentBuffers())
|
for (auto &buffer : block->mesh->getTransparentBuffers())
|
||||||
draw_order.emplace_back(block_pos, &buffer);
|
draw_order.emplace_back(get_block_wpos(block_pos), &buffer);
|
||||||
}
|
} else {
|
||||||
else {
|
// Otherwise, group them
|
||||||
// otherwise, group buffers across meshes
|
grouped_buffers.addFromBlock(block_pos, block->mesh, driver);
|
||||||
// using MeshBufListMaps
|
|
||||||
MapBlockMesh *mapBlockMesh = block->mesh;
|
|
||||||
assert(mapBlockMesh);
|
|
||||||
|
|
||||||
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
|
|
||||||
scene::IMesh *mesh = mapBlockMesh->getMesh(layer);
|
|
||||||
assert(mesh);
|
|
||||||
|
|
||||||
u32 c = mesh->getMeshBufferCount();
|
|
||||||
for (u32 i = 0; i < c; i++) {
|
|
||||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
|
|
||||||
|
|
||||||
video::SMaterial &mat = buf->getMaterial();
|
|
||||||
auto rnd = driver->getMaterialRenderer(mat.MaterialType);
|
|
||||||
bool transparent = rnd && rnd->isTransparent();
|
|
||||||
if (!transparent)
|
|
||||||
grouped_buffers.add(buf, block_pos, layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 buffer_count = 0;
|
|
||||||
for (auto &map : grouped_buffers.maps)
|
|
||||||
for (auto &list : map)
|
|
||||||
buffer_count += list.second.size();
|
|
||||||
|
|
||||||
draw_order.reserve(draw_order.size() + buffer_count);
|
|
||||||
|
|
||||||
// Capture draw order for all solid meshes
|
|
||||||
for (auto &map : grouped_buffers.maps) {
|
for (auto &map : grouped_buffers.maps) {
|
||||||
for (auto &list : map) {
|
for (auto &list : map) {
|
||||||
// iterate in reverse to draw closest blocks first
|
transformBuffersToDrawOrder(
|
||||||
for (auto it = list.second.rbegin(); it != list.second.rend(); ++it)
|
list.second, draw_order, get_block_wpos, buffer_trash);
|
||||||
draw_order.emplace_back(it->first, it->second, it != list.second.rbegin());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeTaker draw("Drawing shadow mesh buffers");
|
TimeTaker draw("");
|
||||||
|
|
||||||
core::matrix4 m; // Model matrix
|
core::matrix4 m; // Model matrix
|
||||||
v3f offset = intToFloat(m_camera_offset, BS);
|
u32 drawcall_count = 0;
|
||||||
|
u32 vertex_count = 0;
|
||||||
u32 material_swaps = 0;
|
u32 material_swaps = 0;
|
||||||
|
|
||||||
// Render all mesh buffers in order
|
// Render all mesh buffers in order
|
||||||
|
@ -1221,8 +1356,7 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
|
||||||
++material_swaps;
|
++material_swaps;
|
||||||
}
|
}
|
||||||
|
|
||||||
v3f block_wpos = intToFloat(mesh_grid.getMeshPos(descriptor.m_pos) * MAP_BLOCKSIZE, BS);
|
m.setTranslation(descriptor.m_pos);
|
||||||
m.setTranslation(block_wpos - offset);
|
|
||||||
|
|
||||||
driver->setTransform(video::ETS_WORLD, m);
|
driver->setTransform(video::ETS_WORLD, m);
|
||||||
vertex_count += descriptor.draw(driver);
|
vertex_count += descriptor.draw(driver);
|
||||||
|
@ -1232,12 +1366,16 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
|
||||||
video::SMaterial clean;
|
video::SMaterial clean;
|
||||||
clean.BlendOperation = video::EBO_ADD;
|
clean.BlendOperation = video::EBO_ADD;
|
||||||
driver->setMaterial(clean); // reset material to defaults
|
driver->setMaterial(clean); // reset material to defaults
|
||||||
|
// FIXME: why is this here?
|
||||||
driver->draw3DLine(v3f(), v3f(), video::SColor(0));
|
driver->draw3DLine(v3f(), v3f(), video::SColor(0));
|
||||||
|
|
||||||
g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));
|
g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));
|
||||||
g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
|
g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
|
||||||
g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
|
g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
|
||||||
g_profiler->avg(prefix + "material swaps [#]", material_swaps);
|
g_profiler->avg(prefix + "material swaps [#]", material_swaps);
|
||||||
|
|
||||||
|
for (auto &x : buffer_trash)
|
||||||
|
x->drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1347,12 +1485,12 @@ void ClientMap::updateTransparentMeshBuffers()
|
||||||
m_needs_update_transparent_meshes = false;
|
m_needs_update_transparent_meshes = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
video::SMaterial &ClientMap::DrawDescriptor::getMaterial()
|
video::SMaterial &DrawDescriptor::getMaterial()
|
||||||
{
|
{
|
||||||
return (m_use_partial_buffer ? m_partial_buffer->getBuffer() : m_buffer)->getMaterial();
|
return (m_use_partial_buffer ? m_partial_buffer->getBuffer() : m_buffer)->getMaterial();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ClientMap::DrawDescriptor::draw(video::IVideoDriver* driver)
|
u32 DrawDescriptor::draw(video::IVideoDriver* driver)
|
||||||
{
|
{
|
||||||
if (m_use_partial_buffer) {
|
if (m_use_partial_buffer) {
|
||||||
m_partial_buffer->draw(driver);
|
m_partial_buffer->draw(driver);
|
||||||
|
|
|
@ -115,7 +115,6 @@ private:
|
||||||
// update the vertex order in transparent mesh buffers
|
// update the vertex order in transparent mesh buffers
|
||||||
void updateTransparentMeshBuffers();
|
void updateTransparentMeshBuffers();
|
||||||
|
|
||||||
|
|
||||||
// Orders blocks by distance to the camera
|
// Orders blocks by distance to the camera
|
||||||
class MapBlockComparer
|
class MapBlockComparer
|
||||||
{
|
{
|
||||||
|
@ -133,30 +132,6 @@ private:
|
||||||
v3s16 m_camera_block;
|
v3s16 m_camera_block;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// reference to a mesh buffer used when rendering the map.
|
|
||||||
struct DrawDescriptor {
|
|
||||||
v3s16 m_pos;
|
|
||||||
union {
|
|
||||||
scene::IMeshBuffer *m_buffer;
|
|
||||||
const PartialMeshBuffer *m_partial_buffer;
|
|
||||||
};
|
|
||||||
bool m_reuse_material:1;
|
|
||||||
bool m_use_partial_buffer:1;
|
|
||||||
|
|
||||||
DrawDescriptor(v3s16 pos, scene::IMeshBuffer *buffer, bool reuse_material) :
|
|
||||||
m_pos(pos), m_buffer(buffer), m_reuse_material(reuse_material), m_use_partial_buffer(false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
DrawDescriptor(v3s16 pos, const PartialMeshBuffer *buffer) :
|
|
||||||
m_pos(pos), m_partial_buffer(buffer), m_reuse_material(false), m_use_partial_buffer(true)
|
|
||||||
{}
|
|
||||||
|
|
||||||
video::SMaterial &getMaterial();
|
|
||||||
/// @return index count
|
|
||||||
u32 draw(video::IVideoDriver* driver);
|
|
||||||
};
|
|
||||||
|
|
||||||
Client *m_client;
|
Client *m_client;
|
||||||
RenderingEngine *m_rendering_engine;
|
RenderingEngine *m_rendering_engine;
|
||||||
|
|
||||||
|
@ -177,8 +152,6 @@ private:
|
||||||
std::map<v3s16, MapBlock*> m_drawlist_shadow;
|
std::map<v3s16, MapBlock*> m_drawlist_shadow;
|
||||||
bool m_needs_update_drawlist;
|
bool m_needs_update_drawlist;
|
||||||
|
|
||||||
std::set<v2s16> m_last_drawn_sectors;
|
|
||||||
|
|
||||||
bool m_cache_trilinear_filter;
|
bool m_cache_trilinear_filter;
|
||||||
bool m_cache_bilinear_filter;
|
bool m_cache_bilinear_filter;
|
||||||
bool m_cache_anistropic_filter;
|
bool m_cache_anistropic_filter;
|
||||||
|
|
|
@ -160,7 +160,7 @@ private:
|
||||||
// Was the mesh ever generated?
|
// Was the mesh ever generated?
|
||||||
bool m_mesh_valid = false;
|
bool m_mesh_valid = false;
|
||||||
|
|
||||||
aabb3f m_box;
|
aabb3f m_box{{0.0f, 0.0f, 0.0f}};
|
||||||
v2f m_origin;
|
v2f m_origin;
|
||||||
u16 m_cloud_radius_i;
|
u16 m_cloud_radius_i;
|
||||||
u32 m_seed;
|
u32 m_seed;
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include "nodedef.h"
|
#include "nodedef.h"
|
||||||
#include "client/tile.h"
|
#include "client/tile.h"
|
||||||
#include "mesh.h"
|
#include "mesh.h"
|
||||||
#include <IMeshManipulator.h>
|
|
||||||
#include "client/meshgen/collector.h"
|
#include "client/meshgen/collector.h"
|
||||||
#include "client/renderingengine.h"
|
#include "client/renderingengine.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
@ -60,12 +59,10 @@ static const auto &quad_indices = quad_indices_02;
|
||||||
|
|
||||||
const std::string MapblockMeshGenerator::raillike_groupname = "connect_to_raillike";
|
const std::string MapblockMeshGenerator::raillike_groupname = "connect_to_raillike";
|
||||||
|
|
||||||
MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output,
|
MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output):
|
||||||
scene::IMeshManipulator *mm):
|
|
||||||
data(input),
|
data(input),
|
||||||
collector(output),
|
collector(output),
|
||||||
nodedef(data->nodedef),
|
nodedef(data->nodedef),
|
||||||
meshmanip(mm),
|
|
||||||
blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE),
|
blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE),
|
||||||
smooth_liquids(g_settings->getBool("enable_water_reflections"))
|
smooth_liquids(g_settings->getBool("enable_water_reflections"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "nodedef.h"
|
#include "nodedef.h"
|
||||||
#include <IMeshManipulator.h>
|
|
||||||
|
|
||||||
struct MeshMakeData;
|
struct MeshMakeData;
|
||||||
struct MeshCollector;
|
struct MeshCollector;
|
||||||
|
@ -46,8 +45,7 @@ struct LightFrame {
|
||||||
class MapblockMeshGenerator
|
class MapblockMeshGenerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output,
|
MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output);
|
||||||
scene::IMeshManipulator *mm);
|
|
||||||
void generate();
|
void generate();
|
||||||
void renderSingle(content_t node, u8 param2 = 0x00);
|
void renderSingle(content_t node, u8 param2 = 0x00);
|
||||||
|
|
||||||
|
@ -56,7 +54,6 @@ private:
|
||||||
MeshCollector *const collector;
|
MeshCollector *const collector;
|
||||||
|
|
||||||
const NodeDefManager *const nodedef;
|
const NodeDefManager *const nodedef;
|
||||||
scene::IMeshManipulator *const meshmanip;
|
|
||||||
|
|
||||||
const v3s16 blockpos_nodes;
|
const v3s16 blockpos_nodes;
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ unsigned int FontEngine::getLineHeight(const FontSpec &spec)
|
||||||
gui::IGUIFont *font = getFont(spec);
|
gui::IGUIFont *font = getFont(spec);
|
||||||
|
|
||||||
return font->getDimension(L"Some unimportant example String").Height
|
return font->getDimension(L"Some unimportant example String").Height
|
||||||
+ font->getKerningHeight();
|
+ font->getKerning(L'S').Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
|
@ -1752,8 +1752,8 @@ void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times,
|
||||||
if (stats2.Drawcalls > 0)
|
if (stats2.Drawcalls > 0)
|
||||||
g_profiler->avg("Irr: primitives per drawcall",
|
g_profiler->avg("Irr: primitives per drawcall",
|
||||||
stats2.PrimitivesDrawn / float(stats2.Drawcalls));
|
stats2.PrimitivesDrawn / float(stats2.Drawcalls));
|
||||||
g_profiler->avg("Irr: buffers uploaded", stats2.HWBuffersUploaded);
|
g_profiler->avg("Irr: HW buffers uploaded", stats2.HWBuffersUploaded);
|
||||||
g_profiler->avg("Irr: buffers uploaded (bytes)", stats2.HWBuffersUploadedSize);
|
g_profiler->avg("Irr: HW buffers active", stats2.HWBuffersActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::updateStats(RunStats *stats, const FpsControl &draw_times,
|
void Game::updateStats(RunStats *stats, const FpsControl &draw_times,
|
||||||
|
@ -3246,7 +3246,7 @@ PointedThing Game::updatePointedThing(
|
||||||
hud->pointing_at_object = true;
|
hud->pointing_at_object = true;
|
||||||
|
|
||||||
runData.selected_object = client->getEnv().getActiveObject(result.object_id);
|
runData.selected_object = client->getEnv().getActiveObject(result.object_id);
|
||||||
aabb3f selection_box;
|
aabb3f selection_box{{0.0f, 0.0f, 0.0f}};
|
||||||
if (show_entity_selectionbox && runData.selected_object->doShowSelectionBox() &&
|
if (show_entity_selectionbox && runData.selected_object->doShowSelectionBox() &&
|
||||||
runData.selected_object->getSelectionBox(&selection_box)) {
|
runData.selected_object->getSelectionBox(&selection_box)) {
|
||||||
v3f pos = runData.selected_object->getPosition();
|
v3f pos = runData.selected_object->getPosition();
|
||||||
|
|
|
@ -104,11 +104,11 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
|
||||||
os << std::fixed
|
os << std::fixed
|
||||||
<< PROJECT_NAME_C " " << g_version_hash
|
<< PROJECT_NAME_C " " << g_version_hash
|
||||||
<< " | FPS: " << fps
|
<< " | FPS: " << fps
|
||||||
<< std::setprecision(0)
|
<< std::setprecision(fps >= 100 ? 1 : 0)
|
||||||
<< " | drawtime: " << m_drawtime_avg << "ms"
|
<< " | drawtime: " << m_drawtime_avg << "ms"
|
||||||
<< std::setprecision(1)
|
<< std::setprecision(1)
|
||||||
<< " | dtime jitter: "
|
<< " | dtime jitter: "
|
||||||
<< (stats.dtime_jitter.max_fraction * 100.0) << "%"
|
<< (stats.dtime_jitter.max_fraction * 100.0f) << "%"
|
||||||
<< std::setprecision(1)
|
<< std::setprecision(1)
|
||||||
<< " | view range: "
|
<< " | view range: "
|
||||||
<< (draw_control->range_all ? "All" : itos(draw_control->wanted_range))
|
<< (draw_control->range_all ? "All" : itos(draw_control->wanted_range))
|
||||||
|
|
|
@ -874,7 +874,6 @@ void Hud::drawSelectionMesh()
|
||||||
{
|
{
|
||||||
if (m_mode == HIGHLIGHT_NONE || (m_mode == HIGHLIGHT_HALO && !m_selection_mesh))
|
if (m_mode == HIGHLIGHT_NONE || (m_mode == HIGHLIGHT_HALO && !m_selection_mesh))
|
||||||
return;
|
return;
|
||||||
const video::SMaterial oldmaterial = driver->getMaterial2D();
|
|
||||||
driver->setMaterial(m_selection_material);
|
driver->setMaterial(m_selection_material);
|
||||||
const core::matrix4 oldtransform = driver->getTransform(video::ETS_WORLD);
|
const core::matrix4 oldtransform = driver->getTransform(video::ETS_WORLD);
|
||||||
|
|
||||||
|
@ -910,7 +909,6 @@ void Hud::drawSelectionMesh()
|
||||||
driver->drawMeshBuffer(buf);
|
driver->drawMeshBuffer(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
driver->setMaterial(oldmaterial);
|
|
||||||
driver->setTransform(video::ETS_WORLD, oldtransform);
|
driver->setTransform(video::ETS_WORLD, oldtransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -935,17 +933,11 @@ void Hud::drawBlockBounds()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
video::SMaterial old_material = driver->getMaterial2D();
|
|
||||||
driver->setMaterial(m_block_bounds_material);
|
driver->setMaterial(m_block_bounds_material);
|
||||||
|
|
||||||
u16 mesh_chunk_size = std::max<u16>(1, g_settings->getU16("client_mesh_chunk"));
|
u16 mesh_chunk_size = std::max<u16>(1, g_settings->getU16("client_mesh_chunk"));
|
||||||
|
|
||||||
v3s16 pos = player->getStandingNodePos();
|
v3s16 block_pos = getContainerPos(player->getStandingNodePos(), MAP_BLOCKSIZE);
|
||||||
v3s16 block_pos(
|
|
||||||
floorf((float) pos.X / MAP_BLOCKSIZE),
|
|
||||||
floorf((float) pos.Y / MAP_BLOCKSIZE),
|
|
||||||
floorf((float) pos.Z / MAP_BLOCKSIZE)
|
|
||||||
);
|
|
||||||
|
|
||||||
v3f cam_offset = intToFloat(client->getCamera()->getOffset(), BS);
|
v3f cam_offset = intToFloat(client->getCamera()->getOffset(), BS);
|
||||||
|
|
||||||
|
@ -988,8 +980,6 @@ void Hud::drawBlockBounds()
|
||||||
choose_color(block_pos.Y, block_pos.Z)
|
choose_color(block_pos.Y, block_pos.Z)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
driver->setMaterial(old_material);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hud::updateSelectionMesh(const v3s16 &camera_offset)
|
void Hud::updateSelectionMesh(const v3s16 &camera_offset)
|
||||||
|
|
|
@ -148,17 +148,6 @@ static void imageCleanTransparentWithInlining(video::IImage *src, u32 threshold)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in RGB values for transparent pixels, to correct for odd colors
|
|
||||||
* appearing at borders when blending. This is because many PNG optimizers
|
|
||||||
* like to discard RGB values of transparent pixels, but when blending then
|
|
||||||
* with non-transparent neighbors, their RGB values will show up nonetheless.
|
|
||||||
*
|
|
||||||
* This function modifies the original image in-place.
|
|
||||||
*
|
|
||||||
* Parameter "threshold" is the alpha level below which pixels are considered
|
|
||||||
* transparent. Should be 127 when the texture is used with ALPHA_CHANNEL_REF,
|
|
||||||
* 0 when alpha blending is used.
|
|
||||||
*/
|
|
||||||
void imageCleanTransparent(video::IImage *src, u32 threshold)
|
void imageCleanTransparent(video::IImage *src, u32 threshold)
|
||||||
{
|
{
|
||||||
if (src->getColorFormat() == video::ECF_A8R8G8B8)
|
if (src->getColorFormat() == video::ECF_A8R8G8B8)
|
||||||
|
@ -167,13 +156,109 @@ void imageCleanTransparent(video::IImage *src, u32 threshold)
|
||||||
imageCleanTransparentWithInlining<false>(src, threshold);
|
imageCleanTransparentWithInlining<false>(src, threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scale a region of an image into another image, using nearest-neighbor with
|
/**********************************/
|
||||||
* anti-aliasing; treat pixels as crisp rectangles, but blend them at boundaries
|
|
||||||
* to prevent non-integer scaling ratio artifacts. Note that this may cause
|
namespace {
|
||||||
* some blending at the edges where pixels don't line up perfectly, but this
|
// For more colorspace transformations, see for example
|
||||||
* filter is designed to produce the most accurate results for both upscaling
|
// <https://github.com/tobspr/GLSL-Color-Spaces/blob/master/ColorSpaces.inc.glsl>
|
||||||
* and downscaling.
|
|
||||||
*/
|
inline float linear_to_srgb_component(float v)
|
||||||
|
{
|
||||||
|
if (v > 0.0031308f)
|
||||||
|
return 1.055f * powf(v, 1.0f / 2.4f) - 0.055f;
|
||||||
|
return 12.92f * v;
|
||||||
|
}
|
||||||
|
inline float srgb_to_linear_component(float v)
|
||||||
|
{
|
||||||
|
if (v > 0.04045f)
|
||||||
|
return powf((v + 0.055f) / 1.055f, 2.4f);
|
||||||
|
return v / 12.92f;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <float (*F)(float)>
|
||||||
|
struct LUT8 {
|
||||||
|
std::array<float, 256> t;
|
||||||
|
LUT8() {
|
||||||
|
for (size_t i = 0; i < t.size(); i++)
|
||||||
|
t[i] = F(i / 255.0f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
LUT8<srgb_to_linear_component> srgb_to_linear_lut;
|
||||||
|
|
||||||
|
v3f srgb_to_linear(const video::SColor col_srgb)
|
||||||
|
{
|
||||||
|
v3f col(srgb_to_linear_lut.t[col_srgb.getRed()],
|
||||||
|
srgb_to_linear_lut.t[col_srgb.getGreen()],
|
||||||
|
srgb_to_linear_lut.t[col_srgb.getBlue()]);
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::SColor linear_to_srgb(const v3f col_linear)
|
||||||
|
{
|
||||||
|
v3f col;
|
||||||
|
// we can't LUT this without losing precision, but thankfully we call
|
||||||
|
// it just once :)
|
||||||
|
col.X = linear_to_srgb_component(col_linear.X);
|
||||||
|
col.Y = linear_to_srgb_component(col_linear.Y);
|
||||||
|
col.Z = linear_to_srgb_component(col_linear.Z);
|
||||||
|
col *= 255.0f;
|
||||||
|
col.X = core::clamp<float>(col.X, 0.0f, 255.0f);
|
||||||
|
col.Y = core::clamp<float>(col.Y, 0.0f, 255.0f);
|
||||||
|
col.Z = core::clamp<float>(col.Z, 0.0f, 255.0f);
|
||||||
|
return video::SColor(0xff, myround(col.X), myround(col.Y),
|
||||||
|
myround(col.Z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool IS_A8R8G8B8>
|
||||||
|
static video::SColor imageAverageColorInline(const video::IImage *src)
|
||||||
|
{
|
||||||
|
void *const src_data = src->getData();
|
||||||
|
const core::dimension2du dim = src->getDimension();
|
||||||
|
|
||||||
|
auto get_pixel = [=](u32 x, u32 y) -> video::SColor {
|
||||||
|
if constexpr (IS_A8R8G8B8) {
|
||||||
|
return reinterpret_cast<u32 *>(src_data)[y*dim.Width + x];
|
||||||
|
} else {
|
||||||
|
return src->getPixel(x, y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 total = 0;
|
||||||
|
v3f col_acc;
|
||||||
|
// limit runtime cost
|
||||||
|
const u32 stepx = std::max(1U, dim.Width / 16),
|
||||||
|
stepy = std::max(1U, dim.Height / 16);
|
||||||
|
for (u32 x = 0; x < dim.Width; x += stepx) {
|
||||||
|
for (u32 y = 0; y < dim.Height; y += stepy) {
|
||||||
|
video::SColor c = get_pixel(x, y);
|
||||||
|
if (c.getAlpha() > 0) {
|
||||||
|
total++;
|
||||||
|
col_acc += srgb_to_linear(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
video::SColor ret(0, 0, 0, 0);
|
||||||
|
if (total > 0) {
|
||||||
|
col_acc /= total;
|
||||||
|
ret = linear_to_srgb(col_acc);
|
||||||
|
}
|
||||||
|
ret.setAlpha(255);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::SColor imageAverageColor(const video::IImage *img)
|
||||||
|
{
|
||||||
|
if (img->getColorFormat() == video::ECF_A8R8G8B8)
|
||||||
|
return imageAverageColorInline<true>(img);
|
||||||
|
else
|
||||||
|
return imageAverageColorInline<false>(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************/
|
||||||
|
|
||||||
void imageScaleNNAA(video::IImage *src, const core::rect<s32> &srcrect, video::IImage *dest)
|
void imageScaleNNAA(video::IImage *src, const core::rect<s32> &srcrect, video::IImage *dest)
|
||||||
{
|
{
|
||||||
double sx, sy, minsx, maxsx, minsy, maxsy, area, ra, ga, ba, aa, pw, ph, pa;
|
double sx, sy, minsx, maxsx, minsy, maxsy, area, ra, ga, ba, aa, pw, ph, pa;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "irrlichttypes.h"
|
#include "irrlichttypes.h"
|
||||||
#include <rect.h>
|
#include <rect.h>
|
||||||
|
#include <SColor.h>
|
||||||
|
|
||||||
namespace irr::video
|
namespace irr::video
|
||||||
{
|
{
|
||||||
|
@ -26,6 +27,10 @@ namespace irr::video
|
||||||
*/
|
*/
|
||||||
void imageCleanTransparent(video::IImage *src, u32 threshold);
|
void imageCleanTransparent(video::IImage *src, u32 threshold);
|
||||||
|
|
||||||
|
/* Returns the gamma-correct average color of the image, with transparent pixels
|
||||||
|
* ignored. */
|
||||||
|
video::SColor imageAverageColor(const video::IImage *img);
|
||||||
|
|
||||||
/* Scale a region of an image into another image, using nearest-neighbor with
|
/* Scale a region of an image into another image, using nearest-neighbor with
|
||||||
* anti-aliasing; treat pixels as crisp rectangles, but blend them at boundaries
|
* anti-aliasing; treat pixels as crisp rectangles, but blend them at boundaries
|
||||||
* to prevent non-integer scaling ratio artifacts. Note that this may cause
|
* to prevent non-integer scaling ratio artifacts. Note that this may cause
|
||||||
|
|
|
@ -31,8 +31,7 @@ void SourceImageCache::insert(const std::string &name, video::IImage *img, bool
|
||||||
{
|
{
|
||||||
assert(img); // Pre-condition
|
assert(img); // Pre-condition
|
||||||
// Remove old image
|
// Remove old image
|
||||||
std::map<std::string, video::IImage*>::iterator n;
|
auto n = m_images.find(name);
|
||||||
n = m_images.find(name);
|
|
||||||
if (n != m_images.end()){
|
if (n != m_images.end()){
|
||||||
if (n->second)
|
if (n->second)
|
||||||
n->second->drop();
|
n->second->drop();
|
||||||
|
@ -63,8 +62,7 @@ void SourceImageCache::insert(const std::string &name, video::IImage *img, bool
|
||||||
|
|
||||||
video::IImage* SourceImageCache::get(const std::string &name)
|
video::IImage* SourceImageCache::get(const std::string &name)
|
||||||
{
|
{
|
||||||
std::map<std::string, video::IImage*>::iterator n;
|
auto n = m_images.find(name);
|
||||||
n = m_images.find(name);
|
|
||||||
if (n != m_images.end())
|
if (n != m_images.end())
|
||||||
return n->second;
|
return n->second;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -73,8 +71,7 @@ video::IImage* SourceImageCache::get(const std::string &name)
|
||||||
// Primarily fetches from cache, secondarily tries to read from filesystem
|
// Primarily fetches from cache, secondarily tries to read from filesystem
|
||||||
video::IImage* SourceImageCache::getOrLoad(const std::string &name)
|
video::IImage* SourceImageCache::getOrLoad(const std::string &name)
|
||||||
{
|
{
|
||||||
std::map<std::string, video::IImage*>::iterator n;
|
auto n = m_images.find(name);
|
||||||
n = m_images.find(name);
|
|
||||||
if (n != m_images.end()){
|
if (n != m_images.end()){
|
||||||
n->second->grab(); // Grab for caller
|
n->second->grab(); // Grab for caller
|
||||||
return n->second;
|
return n->second;
|
||||||
|
@ -166,13 +163,13 @@ static void draw_crack(video::IImage *crack, video::IImage *dst,
|
||||||
video::IVideoDriver *driver, u8 tiles = 1);
|
video::IVideoDriver *driver, u8 tiles = 1);
|
||||||
|
|
||||||
// Brighten image
|
// Brighten image
|
||||||
void brighten(video::IImage *image);
|
static void brighten(video::IImage *image);
|
||||||
// Parse a transform name
|
// Parse a transform name
|
||||||
u32 parseImageTransform(std::string_view s);
|
static u32 parseImageTransform(std::string_view s);
|
||||||
// Apply transform to image dimension
|
// Apply transform to image dimension
|
||||||
core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<u32> dim);
|
static core::dimension2du imageTransformDimension(u32 transform, core::dimension2du dim);
|
||||||
// Apply transform to image data
|
// Apply transform to image data
|
||||||
void imageTransform(u32 transform, video::IImage *src, video::IImage *dst);
|
static void imageTransform(u32 transform, video::IImage *src, video::IImage *dst);
|
||||||
|
|
||||||
inline static void applyShadeFactor(video::SColor &color, u32 factor)
|
inline static void applyShadeFactor(video::SColor &color, u32 factor)
|
||||||
{
|
{
|
||||||
|
@ -289,7 +286,7 @@ static video::IImage *createInventoryCubeImage(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string unescape_string(const std::string &str, const char esc = '\\')
|
static std::string unescape_string(std::string_view str, const char esc = '\\')
|
||||||
{
|
{
|
||||||
std::string out;
|
std::string out;
|
||||||
size_t pos = 0, cpos;
|
size_t pos = 0, cpos;
|
||||||
|
@ -300,7 +297,8 @@ static std::string unescape_string(const std::string &str, const char esc = '\\'
|
||||||
out += str.substr(pos);
|
out += str.substr(pos);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
out += str.substr(pos, cpos - pos) + str[cpos + 1];
|
out += str.substr(pos, cpos - pos);
|
||||||
|
out += str[cpos + 1];
|
||||||
pos = cpos + 2;
|
pos = cpos + 2;
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
|
@ -312,7 +310,7 @@ static std::string unescape_string(const std::string &str, const char esc = '\\'
|
||||||
Ensure no other references to these images are being held, as one may
|
Ensure no other references to these images are being held, as one may
|
||||||
get dropped and switched with a new image.
|
get dropped and switched with a new image.
|
||||||
*/
|
*/
|
||||||
void upscaleImagesToMatchLargest(video::IImage *& img1,
|
static void upscaleImagesToMatchLargest(video::IImage *& img1,
|
||||||
video::IImage *& img2)
|
video::IImage *& img2)
|
||||||
{
|
{
|
||||||
core::dimension2d<u32> dim1 = img1->getDimension();
|
core::dimension2d<u32> dim1 = img1->getDimension();
|
||||||
|
@ -340,7 +338,7 @@ void upscaleImagesToMatchLargest(video::IImage *& img1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void blitBaseImage(video::IImage* &src, video::IImage* &dst)
|
static void blitBaseImage(video::IImage* &src, video::IImage* &dst)
|
||||||
{
|
{
|
||||||
//infostream<<"Blitting "<<part_of_name<<" on base"<<std::endl;
|
//infostream<<"Blitting "<<part_of_name<<" on base"<<std::endl;
|
||||||
upscaleImagesToMatchLargest(dst, src);
|
upscaleImagesToMatchLargest(dst, src);
|
||||||
|
@ -411,9 +409,10 @@ void blit_pixel(video::SColor src_col, video::SColor &dst_col)
|
||||||
dst_col.set(dst_a, dst.r, dst.g, dst.b);
|
dst_col.set(dst_a, dst.r, dst.g, dst.b);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace (anonymous)
|
||||||
|
|
||||||
template<bool overlay>
|
template<bool overlay>
|
||||||
void blit_with_alpha(video::IImage *src, video::IImage *dst, v2s32 dst_pos,
|
static void blit_with_alpha(video::IImage *src, video::IImage *dst, v2s32 dst_pos,
|
||||||
v2u32 size)
|
v2u32 size)
|
||||||
{
|
{
|
||||||
if (dst->getColorFormat() != video::ECF_A8R8G8B8)
|
if (dst->getColorFormat() != video::ECF_A8R8G8B8)
|
||||||
|
@ -427,13 +426,12 @@ void blit_with_alpha(video::IImage *src, video::IImage *dst, v2s32 dst_pos,
|
||||||
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
||||||
video::IImage *src_converted = driver->createImage(video::ECF_A8R8G8B8,
|
video::IImage *src_converted = driver->createImage(video::ECF_A8R8G8B8,
|
||||||
src_dim);
|
src_dim);
|
||||||
if (!src_converted)
|
sanity_check(src_converted != nullptr);
|
||||||
throw BaseException("blit_with_alpha() failed to convert the "
|
|
||||||
"source image to ECF_A8R8G8B8.");
|
|
||||||
src->copyTo(src_converted);
|
src->copyTo(src_converted);
|
||||||
src = src_converted;
|
src = src_converted;
|
||||||
drop_src = true;
|
drop_src = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
video::SColor *pixels_src =
|
video::SColor *pixels_src =
|
||||||
reinterpret_cast<video::SColor *>(src->getData());
|
reinterpret_cast<video::SColor *>(src->getData());
|
||||||
video::SColor *pixels_dst =
|
video::SColor *pixels_dst =
|
||||||
|
@ -453,6 +451,7 @@ void blit_with_alpha(video::IImage *src, video::IImage *dst, v2s32 dst_pos,
|
||||||
blit_pixel<overlay>(pixels_src[i_src++], pixels_dst[i_dst++]);
|
blit_pixel<overlay>(pixels_src[i_src++], pixels_dst[i_dst++]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drop_src)
|
if (drop_src)
|
||||||
src->drop();
|
src->drop();
|
||||||
}
|
}
|
||||||
|
@ -726,7 +725,7 @@ static void apply_mask(video::IImage *mask, video::IImage *dst,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
video::IImage *create_crack_image(video::IImage *crack, s32 frame_index,
|
static video::IImage *create_crack_image(video::IImage *crack, s32 frame_index,
|
||||||
core::dimension2d<u32> size, u8 tiles, video::IVideoDriver *driver)
|
core::dimension2d<u32> size, u8 tiles, video::IVideoDriver *driver)
|
||||||
{
|
{
|
||||||
core::dimension2d<u32> strip_size = crack->getDimension();
|
core::dimension2d<u32> strip_size = crack->getDimension();
|
||||||
|
@ -804,7 +803,7 @@ static void draw_crack(video::IImage *crack, video::IImage *dst,
|
||||||
crack_scaled->drop();
|
crack_scaled->drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void brighten(video::IImage *image)
|
static void brighten(video::IImage *image)
|
||||||
{
|
{
|
||||||
if (image == NULL)
|
if (image == NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -822,7 +821,7 @@ void brighten(video::IImage *image)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 parseImageTransform(std::string_view s)
|
static u32 parseImageTransform(std::string_view s)
|
||||||
{
|
{
|
||||||
int total_transform = 0;
|
int total_transform = 0;
|
||||||
|
|
||||||
|
@ -872,15 +871,15 @@ u32 parseImageTransform(std::string_view s)
|
||||||
return total_transform;
|
return total_transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<u32> dim)
|
static core::dimension2du imageTransformDimension(u32 transform, core::dimension2du dim)
|
||||||
{
|
{
|
||||||
if (transform % 2 == 0)
|
if (transform % 2 == 0)
|
||||||
return dim;
|
return dim;
|
||||||
|
|
||||||
return core::dimension2d<u32>(dim.Height, dim.Width);
|
return core::dimension2du(dim.Height, dim.Width);
|
||||||
}
|
}
|
||||||
|
|
||||||
void imageTransform(u32 transform, video::IImage *src, video::IImage *dst)
|
static void imageTransform(u32 transform, video::IImage *src, video::IImage *dst)
|
||||||
{
|
{
|
||||||
if (src == NULL || dst == NULL)
|
if (src == NULL || dst == NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -925,48 +924,6 @@ void imageTransform(u32 transform, video::IImage *src, video::IImage *dst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
// For more colorspace transformations, see for example
|
|
||||||
// https://github.com/tobspr/GLSL-Color-Spaces/blob/master/ColorSpaces.inc.glsl
|
|
||||||
|
|
||||||
inline float linear_to_srgb_component(float v)
|
|
||||||
{
|
|
||||||
if (v > 0.0031308f)
|
|
||||||
return 1.055f * powf(v, 1.0f / 2.4f) - 0.055f;
|
|
||||||
return 12.92f * v;
|
|
||||||
}
|
|
||||||
inline float srgb_to_linear_component(float v)
|
|
||||||
{
|
|
||||||
if (v > 0.04045f)
|
|
||||||
return powf((v + 0.055f) / 1.055f, 2.4f);
|
|
||||||
return v / 12.92f;
|
|
||||||
}
|
|
||||||
|
|
||||||
v3f srgb_to_linear(const video::SColor col_srgb)
|
|
||||||
{
|
|
||||||
v3f col(col_srgb.getRed(), col_srgb.getGreen(), col_srgb.getBlue());
|
|
||||||
col /= 255.0f;
|
|
||||||
col.X = srgb_to_linear_component(col.X);
|
|
||||||
col.Y = srgb_to_linear_component(col.Y);
|
|
||||||
col.Z = srgb_to_linear_component(col.Z);
|
|
||||||
return col;
|
|
||||||
}
|
|
||||||
|
|
||||||
video::SColor linear_to_srgb(const v3f col_linear)
|
|
||||||
{
|
|
||||||
v3f col;
|
|
||||||
col.X = linear_to_srgb_component(col_linear.X);
|
|
||||||
col.Y = linear_to_srgb_component(col_linear.Y);
|
|
||||||
col.Z = linear_to_srgb_component(col_linear.Z);
|
|
||||||
col *= 255.0f;
|
|
||||||
col.X = core::clamp<float>(col.X, 0.0f, 255.0f);
|
|
||||||
col.Y = core::clamp<float>(col.Y, 0.0f, 255.0f);
|
|
||||||
col.Z = core::clamp<float>(col.Z, 0.0f, 255.0f);
|
|
||||||
return video::SColor(0xff, myround(col.X), myround(col.Y),
|
|
||||||
myround(col.Z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////
|
///////////////////////////
|
||||||
// ImageSource Functions //
|
// ImageSource Functions //
|
||||||
|
@ -1017,18 +974,12 @@ bool ImageSource::generateImagePart(std::string_view part_of_name,
|
||||||
std::string part_s(part_of_name);
|
std::string part_s(part_of_name);
|
||||||
source_image_names.insert(part_s);
|
source_image_names.insert(part_s);
|
||||||
video::IImage *image = m_sourcecache.getOrLoad(part_s);
|
video::IImage *image = m_sourcecache.getOrLoad(part_s);
|
||||||
|
|
||||||
if (!image) {
|
if (!image) {
|
||||||
// Do not create the dummy texture
|
// Do not create the dummy texture
|
||||||
if (part_of_name.empty())
|
if (part_of_name.empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Do not create normalmap dummies
|
|
||||||
if (str_ends_with(part_of_name, "_normal.png")) {
|
|
||||||
warningstream << "generateImagePart(): Could not load normal map \""
|
|
||||||
<< part_of_name << "\"" << std::endl;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
errorstream << "generateImagePart(): Could not load image \""
|
errorstream << "generateImagePart(): Could not load image \""
|
||||||
<< part_of_name << "\" while building texture; "
|
<< part_of_name << "\" while building texture; "
|
||||||
"Creating a dummy image" << std::endl;
|
"Creating a dummy image" << std::endl;
|
||||||
|
@ -1040,16 +991,15 @@ bool ImageSource::generateImagePart(std::string_view part_of_name,
|
||||||
myrand()%256,myrand()%256));
|
myrand()%256,myrand()%256));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If base image is NULL, load as base.
|
// load as base or blit
|
||||||
if (baseimg == NULL)
|
if (!baseimg)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Copy it this way to get an alpha channel.
|
Copy it this way to get an alpha channel.
|
||||||
Otherwise images with alpha cannot be blitted on
|
Otherwise images with alpha cannot be blitted on
|
||||||
images that don't have alpha in the original file.
|
images that don't have alpha in the original file.
|
||||||
*/
|
*/
|
||||||
core::dimension2d<u32> dim = image->getDimension();
|
baseimg = driver->createImage(video::ECF_A8R8G8B8, image->getDimension());
|
||||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
|
||||||
image->copyTo(baseimg);
|
image->copyTo(baseimg);
|
||||||
}
|
}
|
||||||
// Else blit on base.
|
// Else blit on base.
|
||||||
|
@ -1705,14 +1655,17 @@ bool ImageSource::generateImagePart(std::string_view part_of_name,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// blit or use as base
|
||||||
if (baseimg) {
|
if (baseimg) {
|
||||||
blitBaseImage(pngimg, baseimg);
|
blitBaseImage(pngimg, baseimg);
|
||||||
} else {
|
pngimg->drop();
|
||||||
core::dimension2d<u32> dim = pngimg->getDimension();
|
} else if (pngimg->getColorFormat() != video::ECF_A8R8G8B8) {
|
||||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
baseimg = driver->createImage(video::ECF_A8R8G8B8, pngimg->getDimension());
|
||||||
pngimg->copyTo(baseimg);
|
pngimg->copyTo(baseimg);
|
||||||
|
pngimg->drop();
|
||||||
|
} else {
|
||||||
|
baseimg = pngimg;
|
||||||
}
|
}
|
||||||
pngimg->drop();
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
[hsl:hue:saturation:lightness
|
[hsl:hue:saturation:lightness
|
||||||
|
@ -1945,32 +1898,7 @@ video::IImage* ImageSource::generateImage(std::string_view name,
|
||||||
return baseimg;
|
return baseimg;
|
||||||
}
|
}
|
||||||
|
|
||||||
video::SColor ImageSource::getImageAverageColor(const video::IImage &image)
|
void ImageSource::insertSourceImage(const std::string &name, video::IImage *img, bool prefer_local)
|
||||||
{
|
{
|
||||||
video::SColor c(0, 0, 0, 0);
|
|
||||||
u32 total = 0;
|
|
||||||
v3f col_acc(0, 0, 0);
|
|
||||||
core::dimension2d<u32> dim = image.getDimension();
|
|
||||||
u16 step = 1;
|
|
||||||
if (dim.Width > 16)
|
|
||||||
step = dim.Width / 16;
|
|
||||||
for (u16 x = 0; x < dim.Width; x += step) {
|
|
||||||
for (u16 y = 0; y < dim.Width; y += step) {
|
|
||||||
c = image.getPixel(x,y);
|
|
||||||
if (c.getAlpha() > 0) {
|
|
||||||
total++;
|
|
||||||
col_acc += srgb_to_linear(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (total > 0) {
|
|
||||||
col_acc /= total;
|
|
||||||
c = linear_to_srgb(col_acc);
|
|
||||||
}
|
|
||||||
c.setAlpha(255);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageSource::insertSourceImage(const std::string &name, video::IImage *img, bool prefer_local) {
|
|
||||||
m_sourcecache.insert(name, img, prefer_local);
|
m_sourcecache.insert(name, img, prefer_local);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <IImage.h>
|
#include <IImage.h>
|
||||||
#include <map>
|
#include <unordered_map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ public:
|
||||||
// Primarily fetches from cache, secondarily tries to read from filesystem.
|
// Primarily fetches from cache, secondarily tries to read from filesystem.
|
||||||
video::IImage *getOrLoad(const std::string &name);
|
video::IImage *getOrLoad(const std::string &name);
|
||||||
private:
|
private:
|
||||||
std::map<std::string, video::IImage*> m_images;
|
std::unordered_map<std::string, video::IImage*> m_images;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generates images using texture modifiers, and caches source images.
|
// Generates images using texture modifiers, and caches source images.
|
||||||
|
@ -45,9 +45,6 @@ struct ImageSource {
|
||||||
// Insert a source image into the cache without touching the filesystem.
|
// Insert a source image into the cache without touching the filesystem.
|
||||||
void insertSourceImage(const std::string &name, video::IImage *img, bool prefer_local);
|
void insertSourceImage(const std::string &name, video::IImage *img, bool prefer_local);
|
||||||
|
|
||||||
// TODO should probably be moved elsewhere
|
|
||||||
static video::SColor getImageAverageColor(const video::IImage &image);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Generate image based on a string like "stone.png" or "[crack:1:0".
|
// Generate image based on a string like "stone.png" or "[crack:1:0".
|
||||||
|
|
|
@ -75,10 +75,8 @@ static aabb3f getNodeBoundingBox(const std::vector<aabb3f> &nodeboxes)
|
||||||
if (nodeboxes.empty())
|
if (nodeboxes.empty())
|
||||||
return aabb3f(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
return aabb3f(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
aabb3f b_max;
|
auto it = nodeboxes.begin();
|
||||||
|
aabb3f b_max(it->MinEdge, it->MaxEdge);
|
||||||
std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
|
|
||||||
b_max = aabb3f(it->MinEdge, it->MaxEdge);
|
|
||||||
|
|
||||||
++it;
|
++it;
|
||||||
for (; it != nodeboxes.end(); ++it)
|
for (; it != nodeboxes.end(); ++it)
|
||||||
|
|
|
@ -633,8 +633,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
|
||||||
*/
|
*/
|
||||||
|
|
||||||
{
|
{
|
||||||
MapblockMeshGenerator(data, &collector,
|
MapblockMeshGenerator(data, &collector).generate();
|
||||||
client->getSceneManager()->getMeshManipulator()).generate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -105,8 +105,7 @@ void scaleMesh(scene::IMesh *mesh, v3f scale)
|
||||||
if (mesh == NULL)
|
if (mesh == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
aabb3f bbox;
|
aabb3f bbox{{0.0f, 0.0f, 0.0f}};
|
||||||
bbox.reset(0, 0, 0);
|
|
||||||
|
|
||||||
u32 mc = mesh->getMeshBufferCount();
|
u32 mc = mesh->getMeshBufferCount();
|
||||||
for (u32 j = 0; j < mc; j++) {
|
for (u32 j = 0; j < mc; j++) {
|
||||||
|
@ -134,8 +133,7 @@ void translateMesh(scene::IMesh *mesh, v3f vec)
|
||||||
if (mesh == NULL)
|
if (mesh == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
aabb3f bbox;
|
aabb3f bbox{{0.0f, 0.0f, 0.0f}};
|
||||||
bbox.reset(0, 0, 0);
|
|
||||||
|
|
||||||
u32 mc = mesh->getMeshBufferCount();
|
u32 mc = mesh->getMeshBufferCount();
|
||||||
for (u32 j = 0; j < mc; j++) {
|
for (u32 j = 0; j < mc; j++) {
|
||||||
|
@ -296,8 +294,7 @@ void rotateMeshBy6dFacedir(scene::IMesh *mesh, u8 facedir)
|
||||||
|
|
||||||
void recalculateBoundingBox(scene::IMesh *src_mesh)
|
void recalculateBoundingBox(scene::IMesh *src_mesh)
|
||||||
{
|
{
|
||||||
aabb3f bbox;
|
aabb3f bbox{{0.0f, 0.0f, 0.0f}};
|
||||||
bbox.reset(0,0,0);
|
|
||||||
for (u16 j = 0; j < src_mesh->getMeshBufferCount(); j++) {
|
for (u16 j = 0; j < src_mesh->getMeshBufferCount(); j++) {
|
||||||
scene::IMeshBuffer *buf = src_mesh->getMeshBuffer(j);
|
scene::IMeshBuffer *buf = src_mesh->getMeshBuffer(j);
|
||||||
buf->recalculateBoundingBox();
|
buf->recalculateBoundingBox();
|
||||||
|
|
|
@ -619,15 +619,22 @@ const core::aabbox3df &ParticleBuffer::getBoundingBox() const
|
||||||
if (!m_bounding_box_dirty)
|
if (!m_bounding_box_dirty)
|
||||||
return m_mesh_buffer->BoundingBox;
|
return m_mesh_buffer->BoundingBox;
|
||||||
|
|
||||||
core::aabbox3df box;
|
core::aabbox3df box{{0, 0, 0}};
|
||||||
|
bool first = true;
|
||||||
for (u16 i = 0; i < m_count; i++) {
|
for (u16 i = 0; i < m_count; i++) {
|
||||||
// check if this index is used
|
// check if this index is used
|
||||||
static_assert(quad_indices[1] != 0);
|
static_assert(quad_indices[1] != 0);
|
||||||
if (m_mesh_buffer->getIndices()[6 * i + 1] == 0)
|
if (m_mesh_buffer->getIndices()[6 * i + 1] == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (u16 j = 0; j < 4; j++)
|
for (u16 j = 0; j < 4; j++) {
|
||||||
box.addInternalPoint(m_mesh_buffer->getPosition(i * 4 + j));
|
const auto pos = m_mesh_buffer->getPosition(i * 4 + j);
|
||||||
|
if (first)
|
||||||
|
box.reset(pos);
|
||||||
|
else
|
||||||
|
box.addInternalPoint(pos);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_mesh_buffer->BoundingBox = box;
|
m_mesh_buffer->BoundingBox = box;
|
||||||
|
|
|
@ -135,7 +135,7 @@ static irr::IrrlichtDevice *createDevice(SIrrlichtCreationParameters params, std
|
||||||
{
|
{
|
||||||
if (requested_driver) {
|
if (requested_driver) {
|
||||||
params.DriverType = *requested_driver;
|
params.DriverType = *requested_driver;
|
||||||
verbosestream << "Trying video driver " << getVideoDriverName(params.DriverType) << std::endl;
|
infostream << "Trying video driver " << getVideoDriverName(params.DriverType) << std::endl;
|
||||||
if (auto *device = createDeviceEx(params))
|
if (auto *device = createDeviceEx(params))
|
||||||
return device;
|
return device;
|
||||||
errorstream << "Failed to initialize the " << getVideoDriverName(params.DriverType) << " video driver" << std::endl;
|
errorstream << "Failed to initialize the " << getVideoDriverName(params.DriverType) << " video driver" << std::endl;
|
||||||
|
@ -147,7 +147,7 @@ static irr::IrrlichtDevice *createDevice(SIrrlichtCreationParameters params, std
|
||||||
if (fallback_driver == video::EDT_NULL || fallback_driver == requested_driver)
|
if (fallback_driver == video::EDT_NULL || fallback_driver == requested_driver)
|
||||||
continue;
|
continue;
|
||||||
params.DriverType = fallback_driver;
|
params.DriverType = fallback_driver;
|
||||||
verbosestream << "Trying video driver " << getVideoDriverName(params.DriverType) << std::endl;
|
infostream << "Trying video driver " << getVideoDriverName(params.DriverType) << std::endl;
|
||||||
if (auto *device = createDeviceEx(params))
|
if (auto *device = createDeviceEx(params))
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
@ -374,16 +374,16 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
|
||||||
std::vector<video::E_DRIVER_TYPE> RenderingEngine::getSupportedVideoDrivers()
|
std::vector<video::E_DRIVER_TYPE> RenderingEngine::getSupportedVideoDrivers()
|
||||||
{
|
{
|
||||||
// Only check these drivers. We do not support software and D3D in any capacity.
|
// Only check these drivers. We do not support software and D3D in any capacity.
|
||||||
// Order by preference (best first)
|
// ordered by preference (best first)
|
||||||
static const video::E_DRIVER_TYPE glDrivers[] = {
|
static const video::E_DRIVER_TYPE glDrivers[] = {
|
||||||
video::EDT_OPENGL,
|
|
||||||
video::EDT_OPENGL3,
|
video::EDT_OPENGL3,
|
||||||
|
video::EDT_OPENGL,
|
||||||
video::EDT_OGLES2,
|
video::EDT_OGLES2,
|
||||||
video::EDT_NULL,
|
video::EDT_NULL,
|
||||||
};
|
};
|
||||||
std::vector<video::E_DRIVER_TYPE> drivers;
|
std::vector<video::E_DRIVER_TYPE> drivers;
|
||||||
|
|
||||||
for (video::E_DRIVER_TYPE driver: glDrivers) {
|
for (auto driver : glDrivers) {
|
||||||
if (IrrlichtDevice::isDriverSupported(driver))
|
if (IrrlichtDevice::isDriverSupported(driver))
|
||||||
drivers.push_back(driver);
|
drivers.push_back(driver);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include <IMaterialRendererServices.h>
|
#include <IMaterialRendererServices.h>
|
||||||
#include <IShaderConstantSetCallBack.h>
|
#include <IShaderConstantSetCallBack.h>
|
||||||
#include "client/renderingengine.h"
|
#include "client/renderingengine.h"
|
||||||
#include <EShaderTypes.h>
|
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "gamedef.h"
|
#include "gamedef.h"
|
||||||
|
@ -615,10 +614,16 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
||||||
#define textureFlags texture2
|
#define textureFlags texture2
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
/// Unique name of this shader, for debug/logging
|
||||||
|
std::string log_name = name;
|
||||||
|
|
||||||
/* Define constants for node and object shaders */
|
/* Define constants for node and object shaders */
|
||||||
const bool node_shader = drawtype != NodeDrawType_END;
|
const bool node_shader = drawtype != NodeDrawType_END;
|
||||||
if (node_shader) {
|
if (node_shader) {
|
||||||
|
|
||||||
|
log_name.append(" mat=").append(itos(material_type))
|
||||||
|
.append(" draw=").append(itos(drawtype));
|
||||||
|
|
||||||
bool use_discard = fully_programmable;
|
bool use_discard = fully_programmable;
|
||||||
if (!use_discard) {
|
if (!use_discard) {
|
||||||
// workaround for a certain OpenGL implementation lacking GL_ALPHA_TEST
|
// workaround for a certain OpenGL implementation lacking GL_ALPHA_TEST
|
||||||
|
@ -775,18 +780,15 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
||||||
geometry_shader_ptr = geometry_shader.c_str();
|
geometry_shader_ptr = geometry_shader.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
irr_ptr<ShaderCallback> cb{new ShaderCallback(m_setter_factories)};
|
auto cb = make_irr<ShaderCallback>(m_setter_factories);
|
||||||
infostream<<"Compiling high level shaders for "<<name<<std::endl;
|
infostream << "Compiling high level shaders for " << log_name << std::endl;
|
||||||
s32 shadermat = gpu->addHighLevelShaderMaterial(
|
s32 shadermat = gpu->addHighLevelShaderMaterial(
|
||||||
vertex_shader.c_str(), nullptr, video::EVST_VS_1_1,
|
vertex_shader.c_str(), fragment_shader.c_str(), geometry_shader_ptr,
|
||||||
fragment_shader.c_str(), nullptr, video::EPST_PS_1_1,
|
log_name.c_str(), scene::EPT_TRIANGLES, scene::EPT_TRIANGLES, 0,
|
||||||
geometry_shader_ptr, nullptr, video::EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLES, 0,
|
cb.get(), shaderinfo.base_material);
|
||||||
cb.get(), shaderinfo.base_material, 1);
|
|
||||||
if (shadermat == -1) {
|
if (shadermat == -1) {
|
||||||
errorstream<<"generate_shader(): "
|
errorstream << "generateShader(): failed to generate shaders for "
|
||||||
"failed to generate \""<<name<<"\", "
|
<< log_name << ", addHighLevelShaderMaterial failed." << std::endl;
|
||||||
"addHighLevelShaderMaterial failed."
|
|
||||||
<<std::endl;
|
|
||||||
dumpShaderProgram(warningstream, "Vertex", vertex_shader);
|
dumpShaderProgram(warningstream, "Vertex", vertex_shader);
|
||||||
dumpShaderProgram(warningstream, "Fragment", fragment_shader);
|
dumpShaderProgram(warningstream, "Fragment", fragment_shader);
|
||||||
dumpShaderProgram(warningstream, "Geometry", geometry_shader);
|
dumpShaderProgram(warningstream, "Geometry", geometry_shader);
|
||||||
|
|
|
@ -14,10 +14,9 @@
|
||||||
#include "client/client.h"
|
#include "client/client.h"
|
||||||
#include "client/clientmap.h"
|
#include "client/clientmap.h"
|
||||||
#include "profiler.h"
|
#include "profiler.h"
|
||||||
#include "EShaderTypes.h"
|
|
||||||
#include "IGPUProgrammingServices.h"
|
#include "IGPUProgrammingServices.h"
|
||||||
#include "IMaterialRenderer.h"
|
#include "IMaterialRenderer.h"
|
||||||
#include <IVideoDriver.h>
|
#include "IVideoDriver.h"
|
||||||
|
|
||||||
ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) :
|
ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) :
|
||||||
m_smgr(device->getSceneManager()), m_driver(device->getVideoDriver()),
|
m_smgr(device->getSceneManager()), m_driver(device->getVideoDriver()),
|
||||||
|
@ -539,10 +538,9 @@ void ShadowRenderer::createShaders()
|
||||||
m_shadow_depth_cb = new ShadowDepthShaderCB();
|
m_shadow_depth_cb = new ShadowDepthShaderCB();
|
||||||
|
|
||||||
depth_shader = gpu->addHighLevelShaderMaterial(
|
depth_shader = gpu->addHighLevelShaderMaterial(
|
||||||
readShaderFile(depth_shader_vs).c_str(), "vertexMain",
|
readShaderFile(depth_shader_vs).c_str(),
|
||||||
video::EVST_VS_1_1,
|
readShaderFile(depth_shader_fs).c_str(), nullptr,
|
||||||
readShaderFile(depth_shader_fs).c_str(), "pixelMain",
|
m_shadow_depth_cb, video::EMT_ONETEXTURE_BLEND);
|
||||||
video::EPST_PS_1_2, m_shadow_depth_cb, video::EMT_ONETEXTURE_BLEND);
|
|
||||||
|
|
||||||
if (depth_shader == -1) {
|
if (depth_shader == -1) {
|
||||||
// upsi, something went wrong loading shader.
|
// upsi, something went wrong loading shader.
|
||||||
|
@ -578,10 +576,9 @@ void ShadowRenderer::createShaders()
|
||||||
m_shadow_depth_entity_cb = new ShadowDepthShaderCB();
|
m_shadow_depth_entity_cb = new ShadowDepthShaderCB();
|
||||||
|
|
||||||
depth_shader_entities = gpu->addHighLevelShaderMaterial(
|
depth_shader_entities = gpu->addHighLevelShaderMaterial(
|
||||||
readShaderFile(depth_shader_vs).c_str(), "vertexMain",
|
readShaderFile(depth_shader_vs).c_str(),
|
||||||
video::EVST_VS_1_1,
|
readShaderFile(depth_shader_fs).c_str(), nullptr,
|
||||||
readShaderFile(depth_shader_fs).c_str(), "pixelMain",
|
m_shadow_depth_entity_cb);
|
||||||
video::EPST_PS_1_2, m_shadow_depth_entity_cb);
|
|
||||||
|
|
||||||
if (depth_shader_entities == -1) {
|
if (depth_shader_entities == -1) {
|
||||||
// upsi, something went wrong loading shader.
|
// upsi, something went wrong loading shader.
|
||||||
|
@ -616,10 +613,9 @@ void ShadowRenderer::createShaders()
|
||||||
m_shadow_mix_cb = new shadowScreenQuadCB();
|
m_shadow_mix_cb = new shadowScreenQuadCB();
|
||||||
m_screen_quad = new shadowScreenQuad();
|
m_screen_quad = new shadowScreenQuad();
|
||||||
mixcsm_shader = gpu->addHighLevelShaderMaterial(
|
mixcsm_shader = gpu->addHighLevelShaderMaterial(
|
||||||
readShaderFile(depth_shader_vs).c_str(), "vertexMain",
|
readShaderFile(depth_shader_vs).c_str(),
|
||||||
video::EVST_VS_1_1,
|
readShaderFile(depth_shader_fs).c_str(), nullptr,
|
||||||
readShaderFile(depth_shader_fs).c_str(), "pixelMain",
|
m_shadow_mix_cb);
|
||||||
video::EPST_PS_1_2, m_shadow_mix_cb);
|
|
||||||
|
|
||||||
m_screen_quad->getMaterial().MaterialType =
|
m_screen_quad->getMaterial().MaterialType =
|
||||||
(video::E_MATERIAL_TYPE)mixcsm_shader;
|
(video::E_MATERIAL_TYPE)mixcsm_shader;
|
||||||
|
@ -655,10 +651,9 @@ void ShadowRenderer::createShaders()
|
||||||
m_shadow_depth_trans_cb = new ShadowDepthShaderCB();
|
m_shadow_depth_trans_cb = new ShadowDepthShaderCB();
|
||||||
|
|
||||||
depth_shader_trans = gpu->addHighLevelShaderMaterial(
|
depth_shader_trans = gpu->addHighLevelShaderMaterial(
|
||||||
readShaderFile(depth_shader_vs).c_str(), "vertexMain",
|
readShaderFile(depth_shader_vs).c_str(),
|
||||||
video::EVST_VS_1_1,
|
readShaderFile(depth_shader_fs).c_str(), nullptr,
|
||||||
readShaderFile(depth_shader_fs).c_str(), "pixelMain",
|
m_shadow_depth_trans_cb);
|
||||||
video::EPST_PS_1_2, m_shadow_depth_trans_cb);
|
|
||||||
|
|
||||||
if (depth_shader_trans == -1) {
|
if (depth_shader_trans == -1) {
|
||||||
// upsi, something went wrong loading shader.
|
// upsi, something went wrong loading shader.
|
||||||
|
|
|
@ -50,8 +50,6 @@ Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShade
|
||||||
m_seed = (u64)myrand() << 32 | myrand();
|
m_seed = (u64)myrand() << 32 | myrand();
|
||||||
|
|
||||||
setAutomaticCulling(scene::EAC_OFF);
|
setAutomaticCulling(scene::EAC_OFF);
|
||||||
m_box.MaxEdge.set(0, 0, 0);
|
|
||||||
m_box.MinEdge.set(0, 0, 0);
|
|
||||||
|
|
||||||
m_sky_params = SkyboxDefaults::getSkyDefaults();
|
m_sky_params = SkyboxDefaults::getSkyDefaults();
|
||||||
m_sun_params = SkyboxDefaults::getSunDefaults();
|
m_sun_params = SkyboxDefaults::getSunDefaults();
|
||||||
|
|
|
@ -122,7 +122,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
aabb3f m_box;
|
aabb3f m_box{{0.0f, 0.0f, 0.0f}};
|
||||||
video::SMaterial m_materials[SKY_MATERIAL_COUNT];
|
video::SMaterial m_materials[SKY_MATERIAL_COUNT];
|
||||||
// How much sun & moon transition should affect horizon color
|
// How much sun & moon transition should affect horizon color
|
||||||
float m_horizon_blend()
|
float m_horizon_blend()
|
||||||
|
|
|
@ -121,7 +121,6 @@ public:
|
||||||
// Shall be called from the main thread.
|
// Shall be called from the main thread.
|
||||||
void rebuildImagesAndTextures();
|
void rebuildImagesAndTextures();
|
||||||
|
|
||||||
video::ITexture* getNormalTexture(const std::string &name);
|
|
||||||
video::SColor getTextureAverageColor(const std::string &name);
|
video::SColor getTextureAverageColor(const std::string &name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -488,40 +487,20 @@ void TextureSource::rebuildTexture(video::IVideoDriver *driver, TextureInfo &ti)
|
||||||
m_texture_trash.push_back(t_old);
|
m_texture_trash.push_back(t_old);
|
||||||
}
|
}
|
||||||
|
|
||||||
video::ITexture* TextureSource::getNormalTexture(const std::string &name)
|
|
||||||
{
|
|
||||||
if (isKnownSourceImage("override_normal.png"))
|
|
||||||
return getTexture("override_normal.png");
|
|
||||||
std::string fname_base = name;
|
|
||||||
static const char *normal_ext = "_normal.png";
|
|
||||||
static const u32 normal_ext_size = strlen(normal_ext);
|
|
||||||
size_t pos = fname_base.find('.');
|
|
||||||
std::string fname_normal = fname_base.substr(0, pos) + normal_ext;
|
|
||||||
if (isKnownSourceImage(fname_normal)) {
|
|
||||||
// look for image extension and replace it
|
|
||||||
size_t i = 0;
|
|
||||||
while ((i = fname_base.find('.', i)) != std::string::npos) {
|
|
||||||
fname_base.replace(i, 4, normal_ext);
|
|
||||||
i += normal_ext_size;
|
|
||||||
}
|
|
||||||
return getTexture(fname_base);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
video::SColor TextureSource::getTextureAverageColor(const std::string &name)
|
video::SColor TextureSource::getTextureAverageColor(const std::string &name)
|
||||||
{
|
{
|
||||||
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
||||||
video::ITexture *texture = getTexture(name);
|
video::ITexture *texture = getTexture(name);
|
||||||
if (!texture)
|
if (!texture)
|
||||||
return {0, 0, 0, 0};
|
return {0, 0, 0, 0};
|
||||||
|
// Note: this downloads the texture back from the GPU, which is pointless
|
||||||
video::IImage *image = driver->createImage(texture,
|
video::IImage *image = driver->createImage(texture,
|
||||||
core::position2d<s32>(0, 0),
|
core::position2d<s32>(0, 0),
|
||||||
texture->getOriginalSize());
|
texture->getOriginalSize());
|
||||||
if (!image)
|
if (!image)
|
||||||
return {0, 0, 0, 0};
|
return {0, 0, 0, 0};
|
||||||
|
|
||||||
video::SColor c = ImageSource::getImageAverageColor(*image);
|
video::SColor c = imageAverageColor(image);
|
||||||
image->drop();
|
image->drop();
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
|
|
|
@ -54,7 +54,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual Palette* getPalette(const std::string &name) = 0;
|
virtual Palette* getPalette(const std::string &name) = 0;
|
||||||
virtual bool isKnownSourceImage(const std::string &name)=0;
|
virtual bool isKnownSourceImage(const std::string &name)=0;
|
||||||
virtual video::ITexture* getNormalTexture(const std::string &name)=0;
|
|
||||||
virtual video::SColor getTextureAverageColor(const std::string &name)=0;
|
virtual video::SColor getTextureAverageColor(const std::string &name)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -75,7 +74,6 @@ public:
|
||||||
virtual void processQueue()=0;
|
virtual void processQueue()=0;
|
||||||
virtual void insertSourceImage(const std::string &name, video::IImage *img)=0;
|
virtual void insertSourceImage(const std::string &name, video::IImage *img)=0;
|
||||||
virtual void rebuildImagesAndTextures()=0;
|
virtual void rebuildImagesAndTextures()=0;
|
||||||
virtual video::ITexture* getNormalTexture(const std::string &name)=0;
|
|
||||||
virtual video::SColor getTextureAverageColor(const std::string &name)=0;
|
virtual video::SColor getTextureAverageColor(const std::string &name)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -83,10 +83,13 @@ struct TileLayer
|
||||||
|
|
||||||
void applyMaterialOptionsWithShaders(video::SMaterial &material) const;
|
void applyMaterialOptionsWithShaders(video::SMaterial &material) const;
|
||||||
|
|
||||||
|
/// @return is this layer semi-transparent?
|
||||||
bool isTransparent() const
|
bool isTransparent() const
|
||||||
{
|
{
|
||||||
|
// see also: the mapping in ShaderSource::generateShader()
|
||||||
switch (material_type) {
|
switch (material_type) {
|
||||||
case TILE_MATERIAL_ALPHA:
|
case TILE_MATERIAL_ALPHA:
|
||||||
|
case TILE_MATERIAL_PLAIN_ALPHA:
|
||||||
case TILE_MATERIAL_LIQUID_TRANSPARENT:
|
case TILE_MATERIAL_LIQUID_TRANSPARENT:
|
||||||
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
|
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -195,8 +195,7 @@ WieldMeshSceneNode::WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id):
|
||||||
else
|
else
|
||||||
g_extrusion_mesh_cache->grab();
|
g_extrusion_mesh_cache->grab();
|
||||||
|
|
||||||
// Disable bounding box culling for this scene node
|
// This class doesn't render anything, so disable culling.
|
||||||
// since we won't calculate the bounding box.
|
|
||||||
setAutomaticCulling(scene::EAC_OFF);
|
setAutomaticCulling(scene::EAC_OFF);
|
||||||
|
|
||||||
// Create the child scene node
|
// Create the child scene node
|
||||||
|
@ -299,8 +298,7 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
|
||||||
MeshMakeData mesh_make_data(client->ndef(), 1);
|
MeshMakeData mesh_make_data(client->ndef(), 1);
|
||||||
MeshCollector collector(v3f(0.0f * BS), v3f());
|
MeshCollector collector(v3f(0.0f * BS), v3f());
|
||||||
mesh_make_data.setSmoothLighting(false);
|
mesh_make_data.setSmoothLighting(false);
|
||||||
MapblockMeshGenerator gen(&mesh_make_data, &collector,
|
MapblockMeshGenerator gen(&mesh_make_data, &collector);
|
||||||
client->getSceneManager()->getMeshManipulator());
|
|
||||||
|
|
||||||
if (n.getParam2()) {
|
if (n.getParam2()) {
|
||||||
// keep it
|
// keep it
|
||||||
|
|
|
@ -134,7 +134,7 @@ private:
|
||||||
// Bounding box culling is disabled for this type of scene node,
|
// Bounding box culling is disabled for this type of scene node,
|
||||||
// so this variable is just required so we can implement
|
// so this variable is just required so we can implement
|
||||||
// getBoundingBox() and is set to an empty box.
|
// getBoundingBox() and is set to an empty box.
|
||||||
aabb3f m_bounding_box;
|
aabb3f m_bounding_box{{0, 0, 0}};
|
||||||
|
|
||||||
ShadowRenderer *m_shadow;
|
ShadowRenderer *m_shadow;
|
||||||
};
|
};
|
||||||
|
|
|
@ -262,7 +262,7 @@ static void add_object_boxes(Environment *env,
|
||||||
{
|
{
|
||||||
auto process_object = [&cinfo] (ActiveObject *object) {
|
auto process_object = [&cinfo] (ActiveObject *object) {
|
||||||
if (object && object->collideWithObjects()) {
|
if (object && object->collideWithObjects()) {
|
||||||
aabb3f box;
|
aabb3f box{{0.0f, 0.0f, 0.0f}};
|
||||||
if (object->getCollisionBox(&box))
|
if (object->getCollisionBox(&box))
|
||||||
cinfo.emplace_back(object, 0, box);
|
cinfo.emplace_back(object, 0, box);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,7 @@ void set_default_settings()
|
||||||
settings->setDefault("sound_extensions_blacklist", "");
|
settings->setDefault("sound_extensions_blacklist", "");
|
||||||
settings->setDefault("mesh_generation_interval", "0");
|
settings->setDefault("mesh_generation_interval", "0");
|
||||||
settings->setDefault("mesh_generation_threads", "0");
|
settings->setDefault("mesh_generation_threads", "0");
|
||||||
|
settings->setDefault("mesh_buffer_min_vertices", "100");
|
||||||
settings->setDefault("free_move", "false");
|
settings->setDefault("free_move", "false");
|
||||||
settings->setDefault("pitch_move", "false");
|
settings->setDefault("pitch_move", "false");
|
||||||
settings->setDefault("fast_move", "false");
|
settings->setDefault("fast_move", "false");
|
||||||
|
@ -311,7 +312,7 @@ void set_default_settings()
|
||||||
|
|
||||||
// Effects
|
// Effects
|
||||||
settings->setDefault("enable_post_processing", "true");
|
settings->setDefault("enable_post_processing", "true");
|
||||||
settings->setDefault("post_processing_texture_bits", "16");
|
settings->setDefault("post_processing_texture_bits", "10");
|
||||||
settings->setDefault("directional_colored_fog", "true");
|
settings->setDefault("directional_colored_fog", "true");
|
||||||
settings->setDefault("inventory_items_animations", "false");
|
settings->setDefault("inventory_items_animations", "false");
|
||||||
settings->setDefault("mip_map", "false");
|
settings->setDefault("mip_map", "false");
|
||||||
|
|
|
@ -194,9 +194,9 @@ void GUIEditBoxWithScrollBar::draw()
|
||||||
mbegin = font->getDimension(s.c_str()).Width;
|
mbegin = font->getDimension(s.c_str()).Width;
|
||||||
|
|
||||||
// deal with kerning
|
// deal with kerning
|
||||||
mbegin += font->getKerningWidth(
|
mbegin += font->getKerning(
|
||||||
&((*txt_line)[realmbgn - start_pos]),
|
(*txt_line)[realmbgn - start_pos],
|
||||||
realmbgn - start_pos > 0 ? &((*txt_line)[realmbgn - start_pos - 1]) : 0);
|
realmbgn - start_pos > 0 ? (*txt_line)[realmbgn - start_pos - 1] : 0).X;
|
||||||
|
|
||||||
lineStartPos = realmbgn - start_pos;
|
lineStartPos = realmbgn - start_pos;
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,8 @@ void GUIEditBoxWithScrollBar::draw()
|
||||||
}
|
}
|
||||||
s = txt_line->subString(0, m_cursor_pos - start_pos);
|
s = txt_line->subString(0, m_cursor_pos - start_pos);
|
||||||
charcursorpos = font->getDimension(s.c_str()).Width +
|
charcursorpos = font->getDimension(s.c_str()).Width +
|
||||||
font->getKerningWidth(L"_", m_cursor_pos - start_pos > 0 ? &((*txt_line)[m_cursor_pos - start_pos - 1]) : 0);
|
font->getKerning(L'_',
|
||||||
|
m_cursor_pos - start_pos > 0 ? (*txt_line)[m_cursor_pos - start_pos - 1] : 0).X;
|
||||||
|
|
||||||
if (focus && (porting::getTimeMs() - m_blink_start_time) % 700 < 350) {
|
if (focus && (porting::getTimeMs() - m_blink_start_time) % 700 < 350) {
|
||||||
setTextRect(cursor_line);
|
setTextRect(cursor_line);
|
||||||
|
@ -431,7 +432,7 @@ void GUIEditBoxWithScrollBar::setTextRect(s32 line)
|
||||||
d = font->getDimension(Text.c_str());
|
d = font->getDimension(Text.c_str());
|
||||||
d.Height = AbsoluteRect.getHeight();
|
d.Height = AbsoluteRect.getHeight();
|
||||||
}
|
}
|
||||||
d.Height += font->getKerningHeight();
|
d.Height += font->getKerning(L'A').Y;
|
||||||
|
|
||||||
// justification
|
// justification
|
||||||
switch (m_halign) {
|
switch (m_halign) {
|
||||||
|
@ -536,7 +537,7 @@ void GUIEditBoxWithScrollBar::calculateScrollPos()
|
||||||
|
|
||||||
// calculate vertical scrolling
|
// calculate vertical scrolling
|
||||||
if (has_broken_text) {
|
if (has_broken_text) {
|
||||||
irr::u32 line_height = font->getDimension(L"A").Height + font->getKerningHeight();
|
irr::u32 line_height = font->getDimension(L"A").Height + font->getKerning(L'A').Y;
|
||||||
// only up to 1 line fits?
|
// only up to 1 line fits?
|
||||||
if (line_height >= (irr::u32)m_frame_rect.getHeight()) {
|
if (line_height >= (irr::u32)m_frame_rect.getHeight()) {
|
||||||
m_vscroll_pos = 0;
|
m_vscroll_pos = 0;
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
*/
|
*/
|
||||||
static unsigned int font_line_height(gui::IGUIFont *font)
|
static unsigned int font_line_height(gui::IGUIFont *font)
|
||||||
{
|
{
|
||||||
return font->getDimension(L"Ay").Height + font->getKerningHeight();
|
return font->getDimension(L"Ay").Height + font->getKerning(L'A').Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline u32 clamp_u8(s32 value)
|
inline u32 clamp_u8(s32 value)
|
||||||
|
|
|
@ -85,8 +85,8 @@ void GUIInventoryList::draw()
|
||||||
v2s32 p((i % m_geom.X) * m_slot_spacing.X,
|
v2s32 p((i % m_geom.X) * m_slot_spacing.X,
|
||||||
(i / m_geom.X) * m_slot_spacing.Y);
|
(i / m_geom.X) * m_slot_spacing.Y);
|
||||||
core::rect<s32> rect = imgrect + base_pos + p;
|
core::rect<s32> rect = imgrect + base_pos + p;
|
||||||
ItemStack item = ilist->getItem(item_i);
|
const ItemStack &orig_item = ilist->getItem(item_i);
|
||||||
ItemStack orig_item = item;
|
ItemStack item = orig_item;
|
||||||
|
|
||||||
bool selected = selected_item
|
bool selected = selected_item
|
||||||
&& m_invmgr->getInventory(selected_item->inventoryloc) == inv
|
&& m_invmgr->getInventory(selected_item->inventoryloc) == inv
|
||||||
|
@ -137,12 +137,26 @@ void GUIInventoryList::draw()
|
||||||
client, rotation_kind);
|
client, rotation_kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add hovering tooltip
|
// Add hovering tooltip. The tooltip disappears if any item is selected,
|
||||||
|
// including the currently hovered one.
|
||||||
bool show_tooltip = !item.empty() && hovering && !selected_item;
|
bool show_tooltip = !item.empty() && hovering && !selected_item;
|
||||||
// Make it possible to see item tooltips on touchscreens
|
|
||||||
if (RenderingEngine::getLastPointerType() == PointerType::Touch) {
|
if (RenderingEngine::getLastPointerType() == PointerType::Touch) {
|
||||||
|
// Touchscreen users cannot hover over an item without selecting it.
|
||||||
|
// To allow touchscreen users to see item tooltips, we also show the
|
||||||
|
// tooltip if the item is selected and the finger is still on the
|
||||||
|
// source slot.
|
||||||
|
// The selected amount may be 0 in rare cases during "left-dragging"
|
||||||
|
// (used to distribute items evenly).
|
||||||
|
// In this case, the user doesn't see an item being dragged,
|
||||||
|
// so we don't show the tooltip.
|
||||||
|
// Note: `m_fs_menu->getSelectedAmount() != 0` below refers to the
|
||||||
|
// part of the selected item the user is dragging.
|
||||||
|
// `!item.empty()` would refer to the part of the selected item
|
||||||
|
// remaining in the source slot.
|
||||||
show_tooltip |= hovering && selected && m_fs_menu->getSelectedAmount() != 0;
|
show_tooltip |= hovering && selected && m_fs_menu->getSelectedAmount() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show_tooltip) {
|
if (show_tooltip) {
|
||||||
std::string tooltip = orig_item.getDescription(client->idef());
|
std::string tooltip = orig_item.getDescription(client->idef());
|
||||||
if (m_fs_menu->doTooltipAppendItemname())
|
if (m_fs_menu->doTooltipAppendItemname())
|
||||||
|
|
|
@ -29,52 +29,47 @@
|
||||||
|
|
||||||
TouchControls *g_touchcontrols;
|
TouchControls *g_touchcontrols;
|
||||||
|
|
||||||
static void load_button_texture(IGUIImage *gui_button, const std::string &path,
|
void TouchControls::emitKeyboardEvent(EKEY_CODE keycode, bool pressed)
|
||||||
const recti &button_rect, ISimpleTextureSource *tsrc, video::IVideoDriver *driver)
|
|
||||||
{
|
{
|
||||||
video::ITexture *texture = guiScalingImageButton(driver,
|
SEvent e{};
|
||||||
tsrc->getTexture(path), button_rect.getWidth(),
|
e.EventType = EET_KEY_INPUT_EVENT;
|
||||||
button_rect.getHeight());
|
e.KeyInput.Key = keycode;
|
||||||
|
e.KeyInput.Control = false;
|
||||||
|
e.KeyInput.Shift = false;
|
||||||
|
e.KeyInput.Char = 0;
|
||||||
|
e.KeyInput.PressedDown = pressed;
|
||||||
|
m_receiver->OnEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TouchControls::loadButtonTexture(IGUIImage *gui_button, const std::string &path)
|
||||||
|
{
|
||||||
|
auto rect = gui_button->getRelativePosition();
|
||||||
|
video::ITexture *texture = guiScalingImageButton(m_device->getVideoDriver(),
|
||||||
|
m_texturesource->getTexture(path), rect.getWidth(), rect.getHeight());
|
||||||
gui_button->setImage(texture);
|
gui_button->setImage(texture);
|
||||||
gui_button->setScaleImage(true);
|
gui_button->setScaleImage(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void button_info::emitAction(bool action, video::IVideoDriver *driver,
|
void TouchControls::buttonEmitAction(button_info &btn, bool action)
|
||||||
IEventReceiver *receiver, ISimpleTextureSource *tsrc)
|
|
||||||
{
|
{
|
||||||
if (keycode == KEY_UNKNOWN)
|
if (btn.keycode == KEY_UNKNOWN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SEvent translated{};
|
emitKeyboardEvent(btn.keycode, action);
|
||||||
translated.EventType = EET_KEY_INPUT_EVENT;
|
|
||||||
translated.KeyInput.Key = keycode;
|
|
||||||
translated.KeyInput.Control = false;
|
|
||||||
translated.KeyInput.Shift = false;
|
|
||||||
translated.KeyInput.Char = 0;
|
|
||||||
|
|
||||||
if (action) {
|
if (action) {
|
||||||
translated.KeyInput.PressedDown = true;
|
if (btn.toggleable == button_info::FIRST_TEXTURE) {
|
||||||
receiver->OnEvent(translated);
|
btn.toggleable = button_info::SECOND_TEXTURE;
|
||||||
|
loadButtonTexture(btn.gui_button.get(), btn.toggle_textures[1]);
|
||||||
|
|
||||||
if (toggleable == button_info::FIRST_TEXTURE) {
|
} else if (btn.toggleable == button_info::SECOND_TEXTURE) {
|
||||||
toggleable = button_info::SECOND_TEXTURE;
|
btn.toggleable = button_info::FIRST_TEXTURE;
|
||||||
load_button_texture(gui_button.get(), toggle_textures[1],
|
loadButtonTexture(btn.gui_button.get(), btn.toggle_textures[0]);
|
||||||
gui_button->getRelativePosition(),
|
|
||||||
tsrc, driver);
|
|
||||||
} else if (toggleable == button_info::SECOND_TEXTURE) {
|
|
||||||
toggleable = button_info::FIRST_TEXTURE;
|
|
||||||
load_button_texture(gui_button.get(), toggle_textures[0],
|
|
||||||
gui_button->getRelativePosition(),
|
|
||||||
tsrc, driver);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
translated.KeyInput.PressedDown = false;
|
|
||||||
receiver->OnEvent(translated);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool buttons_handlePress(std::vector<button_info> &buttons, size_t pointer_id, IGUIElement *element,
|
bool TouchControls::buttonsHandlePress(std::vector<button_info> &buttons, size_t pointer_id, IGUIElement *element)
|
||||||
video::IVideoDriver *driver, IEventReceiver *receiver, ISimpleTextureSource *tsrc)
|
|
||||||
{
|
{
|
||||||
if (!element)
|
if (!element)
|
||||||
return false;
|
return false;
|
||||||
|
@ -87,7 +82,7 @@ static bool buttons_handlePress(std::vector<button_info> &buttons, size_t pointe
|
||||||
if (btn.pointer_ids.size() > 1)
|
if (btn.pointer_ids.size() > 1)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
btn.emitAction(true, driver, receiver, tsrc);
|
buttonEmitAction(btn, true);
|
||||||
btn.repeat_counter = -BUTTON_REPEAT_DELAY;
|
btn.repeat_counter = -BUTTON_REPEAT_DELAY;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -97,8 +92,7 @@ static bool buttons_handlePress(std::vector<button_info> &buttons, size_t pointe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool buttons_handleRelease(std::vector<button_info> &buttons, size_t pointer_id,
|
bool TouchControls::buttonsHandleRelease(std::vector<button_info> &buttons, size_t pointer_id)
|
||||||
video::IVideoDriver *driver, IEventReceiver *receiver, ISimpleTextureSource *tsrc)
|
|
||||||
{
|
{
|
||||||
for (button_info &btn : buttons) {
|
for (button_info &btn : buttons) {
|
||||||
auto it = std::find(btn.pointer_ids.begin(), btn.pointer_ids.end(), pointer_id);
|
auto it = std::find(btn.pointer_ids.begin(), btn.pointer_ids.end(), pointer_id);
|
||||||
|
@ -108,7 +102,7 @@ static bool buttons_handleRelease(std::vector<button_info> &buttons, size_t poin
|
||||||
if (!btn.pointer_ids.empty())
|
if (!btn.pointer_ids.empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
btn.emitAction(false, driver, receiver, tsrc);
|
buttonEmitAction(btn, false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,8 +110,7 @@ static bool buttons_handleRelease(std::vector<button_info> &buttons, size_t poin
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool buttons_step(std::vector<button_info> &buttons, float dtime,
|
bool TouchControls::buttonsStep(std::vector<button_info> &buttons, float dtime)
|
||||||
video::IVideoDriver *driver, IEventReceiver *receiver, ISimpleTextureSource *tsrc)
|
|
||||||
{
|
{
|
||||||
bool has_pointers = false;
|
bool has_pointers = false;
|
||||||
|
|
||||||
|
@ -130,8 +123,8 @@ static bool buttons_step(std::vector<button_info> &buttons, float dtime,
|
||||||
if (btn.repeat_counter < BUTTON_REPEAT_INTERVAL)
|
if (btn.repeat_counter < BUTTON_REPEAT_INTERVAL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
btn.emitAction(false, driver, receiver, tsrc);
|
buttonEmitAction(btn, false);
|
||||||
btn.emitAction(true, driver, receiver, tsrc);
|
buttonEmitAction(btn, true);
|
||||||
btn.repeat_counter = 0.0f;
|
btn.repeat_counter = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,8 +333,7 @@ void TouchControls::addButton(std::vector<button_info> &buttons, touch_gui_butto
|
||||||
{
|
{
|
||||||
IGUIImage *btn_gui_button = m_guienv->addImage(rect, nullptr, id);
|
IGUIImage *btn_gui_button = m_guienv->addImage(rect, nullptr, id);
|
||||||
btn_gui_button->setVisible(visible);
|
btn_gui_button->setVisible(visible);
|
||||||
load_button_texture(btn_gui_button, image, rect,
|
loadButtonTexture(btn_gui_button, image);
|
||||||
m_texturesource, m_device->getVideoDriver());
|
|
||||||
|
|
||||||
button_info &btn = buttons.emplace_back();
|
button_info &btn = buttons.emplace_back();
|
||||||
btn.keycode = id_to_keycode(id);
|
btn.keycode = id_to_keycode(id);
|
||||||
|
@ -363,8 +355,7 @@ IGUIImage *TouchControls::makeButtonDirect(touch_gui_button_id id,
|
||||||
{
|
{
|
||||||
IGUIImage *btn_gui_button = m_guienv->addImage(rect, nullptr, id);
|
IGUIImage *btn_gui_button = m_guienv->addImage(rect, nullptr, id);
|
||||||
btn_gui_button->setVisible(visible);
|
btn_gui_button->setVisible(visible);
|
||||||
load_button_texture(btn_gui_button, button_image_names[id], rect,
|
loadButtonTexture(btn_gui_button, button_image_names[id]);
|
||||||
m_texturesource, m_device->getVideoDriver());
|
|
||||||
|
|
||||||
return btn_gui_button;
|
return btn_gui_button;
|
||||||
}
|
}
|
||||||
|
@ -399,11 +390,9 @@ void TouchControls::handleReleaseEvent(size_t pointer_id)
|
||||||
m_pointer_pos.erase(pointer_id);
|
m_pointer_pos.erase(pointer_id);
|
||||||
|
|
||||||
// handle buttons
|
// handle buttons
|
||||||
if (buttons_handleRelease(m_buttons, pointer_id, m_device->getVideoDriver(),
|
if (buttonsHandleRelease(m_buttons, pointer_id))
|
||||||
m_receiver, m_texturesource))
|
|
||||||
return;
|
return;
|
||||||
if (buttons_handleRelease(m_overflow_buttons, pointer_id, m_device->getVideoDriver(),
|
if (buttonsHandleRelease(m_overflow_buttons, pointer_id))
|
||||||
m_receiver, m_texturesource))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_has_move_id && pointer_id == m_move_id) {
|
if (m_has_move_id && pointer_id == m_move_id) {
|
||||||
|
@ -481,8 +470,7 @@ void TouchControls::translateEvent(const SEvent &event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buttons_handlePress(m_overflow_buttons, pointer_id, element,
|
if (buttonsHandlePress(m_overflow_buttons, pointer_id, element))
|
||||||
m_device->getVideoDriver(), m_receiver, m_texturesource))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
toggleOverflowMenu();
|
toggleOverflowMenu();
|
||||||
|
@ -494,8 +482,7 @@ void TouchControls::translateEvent(const SEvent &event)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle buttons
|
// handle buttons
|
||||||
if (buttons_handlePress(m_buttons, pointer_id, element,
|
if (buttonsHandlePress(m_buttons, pointer_id, element))
|
||||||
m_device->getVideoDriver(), m_receiver, m_texturesource))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// handle hotbar
|
// handle hotbar
|
||||||
|
@ -614,16 +601,10 @@ void TouchControls::translateEvent(const SEvent &event)
|
||||||
void TouchControls::applyJoystickStatus()
|
void TouchControls::applyJoystickStatus()
|
||||||
{
|
{
|
||||||
if (m_joystick_triggers_aux1) {
|
if (m_joystick_triggers_aux1) {
|
||||||
SEvent translated{};
|
auto key = id_to_keycode(aux1_id);
|
||||||
translated.EventType = EET_KEY_INPUT_EVENT;
|
emitKeyboardEvent(key, false);
|
||||||
translated.KeyInput.Key = id_to_keycode(aux1_id);
|
if (m_joystick_status_aux1)
|
||||||
translated.KeyInput.PressedDown = false;
|
emitKeyboardEvent(key, true);
|
||||||
m_receiver->OnEvent(translated);
|
|
||||||
|
|
||||||
if (m_joystick_status_aux1) {
|
|
||||||
translated.KeyInput.PressedDown = true;
|
|
||||||
m_receiver->OnEvent(translated);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,8 +620,8 @@ void TouchControls::step(float dtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulate keyboard repeats
|
// simulate keyboard repeats
|
||||||
buttons_step(m_buttons, dtime, m_device->getVideoDriver(), m_receiver, m_texturesource);
|
buttonsStep(m_buttons, dtime);
|
||||||
buttons_step(m_overflow_buttons, dtime, m_device->getVideoDriver(), m_receiver, m_texturesource);
|
buttonsStep(m_overflow_buttons, dtime);
|
||||||
|
|
||||||
// joystick
|
// joystick
|
||||||
applyJoystickStatus();
|
applyJoystickStatus();
|
||||||
|
|
|
@ -67,9 +67,6 @@ struct button_info
|
||||||
SECOND_TEXTURE
|
SECOND_TEXTURE
|
||||||
} toggleable = NOT_TOGGLEABLE;
|
} toggleable = NOT_TOGGLEABLE;
|
||||||
std::string toggle_textures[2];
|
std::string toggle_textures[2];
|
||||||
|
|
||||||
void emitAction(bool action, video::IVideoDriver *driver,
|
|
||||||
IEventReceiver *receiver, ISimpleTextureSource *tsrc);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -186,6 +183,19 @@ private:
|
||||||
|
|
||||||
std::shared_ptr<IGUIStaticText> m_status_text;
|
std::shared_ptr<IGUIStaticText> m_status_text;
|
||||||
|
|
||||||
|
// Note: TouchControls intentionally uses IGUIImage instead of IGUIButton
|
||||||
|
// for its buttons. We only want static image display, not interactivity,
|
||||||
|
// from Irrlicht.
|
||||||
|
|
||||||
|
void emitKeyboardEvent(EKEY_CODE keycode, bool pressed);
|
||||||
|
|
||||||
|
void loadButtonTexture(IGUIImage *gui_button, const std::string &path);
|
||||||
|
void buttonEmitAction(button_info &btn, bool action);
|
||||||
|
|
||||||
|
bool buttonsHandlePress(std::vector<button_info> &buttons, size_t pointer_id, IGUIElement *element);
|
||||||
|
bool buttonsHandleRelease(std::vector<button_info> &buttons, size_t pointer_id);
|
||||||
|
bool buttonsStep(std::vector<button_info> &buttons, float dtime);
|
||||||
|
|
||||||
void toggleOverflowMenu();
|
void toggleOverflowMenu();
|
||||||
void updateVisibility();
|
void updateVisibility();
|
||||||
void releaseAll();
|
void releaseAll();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
CGUITTFont FreeType class for Irrlicht
|
CGUITTFont FreeType class for Irrlicht
|
||||||
Copyright (c) 2009-2010 John Norman
|
Copyright (c) 2009-2010 John Norman
|
||||||
|
with changes from Luanti contributors:
|
||||||
Copyright (c) 2016 Nathanaëlle Courant
|
Copyright (c) 2016 Nathanaëlle Courant
|
||||||
Copyright (c) 2023 Caleb Butler
|
Copyright (c) 2023 Caleb Butler
|
||||||
|
|
||||||
|
@ -31,14 +32,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "log.h"
|
||||||
|
#include "filesys.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
#include "CGUITTFont.h"
|
#include "CGUITTFont.h"
|
||||||
#include "CMeshBuffer.h"
|
|
||||||
#include "IFileSystem.h"
|
#include "IFileSystem.h"
|
||||||
#include "IGUIEnvironment.h"
|
#include "IGUIEnvironment.h"
|
||||||
#include "IMeshManipulator.h"
|
|
||||||
#include "IMeshSceneNode.h"
|
|
||||||
#include "ISceneManager.h"
|
|
||||||
#include "ISceneNode.h"
|
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
|
@ -46,9 +46,9 @@ namespace gui
|
||||||
{
|
{
|
||||||
|
|
||||||
// Manages the FT_Face cache.
|
// Manages the FT_Face cache.
|
||||||
struct SGUITTFace : public virtual irr::IReferenceCounted
|
struct SGUITTFace : public irr::IReferenceCounted
|
||||||
{
|
{
|
||||||
SGUITTFace() : face_buffer(0), face_buffer_size(0)
|
SGUITTFace()
|
||||||
{
|
{
|
||||||
memset((void*)&face, 0, sizeof(FT_Face));
|
memset((void*)&face, 0, sizeof(FT_Face));
|
||||||
}
|
}
|
||||||
|
@ -56,46 +56,29 @@ struct SGUITTFace : public virtual irr::IReferenceCounted
|
||||||
~SGUITTFace()
|
~SGUITTFace()
|
||||||
{
|
{
|
||||||
FT_Done_Face(face);
|
FT_Done_Face(face);
|
||||||
delete[] face_buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
FT_Byte* face_buffer;
|
std::string face_buffer;
|
||||||
FT_Long face_buffer_size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Static variables.
|
// Static variables.
|
||||||
FT_Library CGUITTFont::c_library;
|
FT_Library CGUITTFont::c_library;
|
||||||
std::map<io::path, SGUITTFace*> CGUITTFont::c_faces;
|
std::map<io::path, SGUITTFace*> CGUITTFont::c_faces;
|
||||||
bool CGUITTFont::c_libraryLoaded = false;
|
bool CGUITTFont::c_libraryLoaded = false;
|
||||||
scene::IMesh* CGUITTFont::shared_plane_ptr_ = 0;
|
|
||||||
scene::SMesh CGUITTFont::shared_plane_;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
/** Checks that no dimension of the FT_BitMap object is negative. If either is
|
|
||||||
* negative, abort execution.
|
|
||||||
*/
|
|
||||||
inline void checkFontBitmapSize(const FT_Bitmap &bits)
|
|
||||||
{
|
|
||||||
if ((s32)bits.rows < 0 || (s32)bits.width < 0) {
|
|
||||||
std::cout << "Insane font glyph size. File: "
|
|
||||||
<< __FILE__ << " Line " << __LINE__
|
|
||||||
<< std::endl;
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
video::IImage* SGUITTGlyph::createGlyphImage(const FT_Bitmap& bits, video::IVideoDriver* driver) const
|
video::IImage* SGUITTGlyph::createGlyphImage(const FT_Bitmap& bits, video::IVideoDriver* driver) const
|
||||||
{
|
{
|
||||||
// Make sure our casts to s32 in the loops below will not cause problems
|
// Make sure our casts to s32 in the loops below will not cause problems
|
||||||
checkFontBitmapSize(bits);
|
if ((s32)bits.rows < 0 || (s32)bits.width < 0)
|
||||||
|
FATAL_ERROR("Insane font glyph size");
|
||||||
|
|
||||||
// Determine what our texture size should be.
|
// Determine what our texture size should be.
|
||||||
// Add 1 because textures are inclusive-exclusive.
|
// Add 1 because textures are inclusive-exclusive.
|
||||||
core::dimension2du d(bits.width + 1, bits.rows + 1);
|
core::dimension2du d(bits.width + 1, bits.rows + 1);
|
||||||
core::dimension2du texture_size;
|
core::dimension2du texture_size;
|
||||||
//core::dimension2du texture_size(bits.width + 1, bits.rows + 1);
|
|
||||||
|
|
||||||
// Create and load our image now.
|
// Create and load our image now.
|
||||||
video::IImage* image = 0;
|
video::IImage* image = 0;
|
||||||
|
@ -147,36 +130,36 @@ video::IImage* SGUITTGlyph::createGlyphImage(const FT_Bitmap& bits, video::IVide
|
||||||
for (s32 x = 0; x < (s32)bits.width; ++x)
|
for (s32 x = 0; x < (s32)bits.width; ++x)
|
||||||
{
|
{
|
||||||
image_data[y * image_pitch + x] |= static_cast<u32>(255.0f * (static_cast<float>(*row++) / gray_count)) << 24;
|
image_data[y * image_pitch + x] |= static_cast<u32>(255.0f * (static_cast<float>(*row++) / gray_count)) << 24;
|
||||||
//data[y * image_pitch + x] |= ((u32)(*bitsdata++) << 24);
|
|
||||||
}
|
}
|
||||||
glyph_data += bits.pitch;
|
glyph_data += bits.pitch;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// TODO: error message?
|
errorstream << "CGUITTFont: unknown pixel mode " << (int)bits.pixel_mode << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGUITTGlyph::preload(u32 char_index, FT_Face face, video::IVideoDriver* driver, u32 font_size, const FT_Int32 loadFlags)
|
void SGUITTGlyph::preload(u32 char_index, FT_Face face, CGUITTFont *parent, u32 font_size, const FT_Int32 loadFlags)
|
||||||
{
|
{
|
||||||
if (isLoaded) return;
|
|
||||||
|
|
||||||
// Set the size of the glyph.
|
// Set the size of the glyph.
|
||||||
FT_Set_Pixel_Sizes(face, 0, font_size);
|
FT_Set_Pixel_Sizes(face, 0, font_size);
|
||||||
|
|
||||||
// Attempt to load the glyph.
|
// Attempt to load the glyph.
|
||||||
if (FT_Load_Glyph(face, char_index, loadFlags) != FT_Err_Ok)
|
auto err = FT_Load_Glyph(face, char_index, loadFlags);
|
||||||
// TODO: error message?
|
if (err != FT_Err_Ok) {
|
||||||
|
warningstream << "SGUITTGlyph: failed to load glyph " << char_index
|
||||||
|
<< " with error: " << (int)err << std::endl;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
FT_GlyphSlot glyph = face->glyph;
|
FT_GlyphSlot glyph = face->glyph;
|
||||||
FT_Bitmap bits = glyph->bitmap;
|
const FT_Bitmap &bits = glyph->bitmap;
|
||||||
|
|
||||||
// Setup the glyph information here:
|
// Setup the glyph information here:
|
||||||
advance = glyph->advance;
|
advance = core::vector2di(glyph->advance.x, glyph->advance.y);
|
||||||
offset = core::vector2di(glyph->bitmap_left, glyph->bitmap_top);
|
offset = core::vector2di(glyph->bitmap_left, glyph->bitmap_top);
|
||||||
|
|
||||||
// Try to get the last page with available slots.
|
// Try to get the last page with available slots.
|
||||||
|
@ -187,7 +170,6 @@ void SGUITTGlyph::preload(u32 char_index, FT_Face face, video::IVideoDriver* dri
|
||||||
{
|
{
|
||||||
page = parent->createGlyphPage(bits.pixel_mode);
|
page = parent->createGlyphPage(bits.pixel_mode);
|
||||||
if (!page)
|
if (!page)
|
||||||
// TODO: add error message?
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,10 +187,7 @@ void SGUITTGlyph::preload(u32 char_index, FT_Face face, video::IVideoDriver* dri
|
||||||
--page->available_slots;
|
--page->available_slots;
|
||||||
|
|
||||||
// We grab the glyph bitmap here so the data won't be removed when the next glyph is loaded.
|
// We grab the glyph bitmap here so the data won't be removed when the next glyph is loaded.
|
||||||
surface = createGlyphImage(bits, driver);
|
surface = createGlyphImage(bits, parent->getDriver());
|
||||||
|
|
||||||
// Set our glyph as loaded.
|
|
||||||
isLoaded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGUITTGlyph::unload()
|
void SGUITTGlyph::unload()
|
||||||
|
@ -218,7 +197,8 @@ void SGUITTGlyph::unload()
|
||||||
surface->drop();
|
surface->drop();
|
||||||
surface = 0;
|
surface = 0;
|
||||||
}
|
}
|
||||||
isLoaded = false;
|
// reset isLoaded to false
|
||||||
|
source_rect = core::recti();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
|
@ -251,14 +231,13 @@ CGUITTFont* CGUITTFont::createTTFont(IGUIEnvironment *env, const io::path& filen
|
||||||
//! Constructor.
|
//! Constructor.
|
||||||
CGUITTFont::CGUITTFont(IGUIEnvironment *env)
|
CGUITTFont::CGUITTFont(IGUIEnvironment *env)
|
||||||
: use_monochrome(false), use_transparency(true), use_hinting(true), use_auto_hinting(true),
|
: use_monochrome(false), use_transparency(true), use_hinting(true), use_auto_hinting(true),
|
||||||
batch_load_size(1), Device(0), Environment(env), Driver(0), GlobalKerningWidth(0), GlobalKerningHeight(0),
|
batch_load_size(1), Driver(0), GlobalKerningWidth(0), GlobalKerningHeight(0),
|
||||||
shadow_offset(0), shadow_alpha(0), fallback(0)
|
shadow_offset(0), shadow_alpha(0), fallback(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (Environment)
|
if (env) {
|
||||||
{
|
|
||||||
// don't grab environment, to avoid circular references
|
// don't grab environment, to avoid circular references
|
||||||
Driver = Environment->getVideoDriver();
|
Driver = env->getVideoDriver();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Driver)
|
if (Driver)
|
||||||
|
@ -270,13 +249,10 @@ shadow_offset(0), shadow_alpha(0), fallback(0)
|
||||||
bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antialias, const bool transparency)
|
bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antialias, const bool transparency)
|
||||||
{
|
{
|
||||||
// Some sanity checks.
|
// Some sanity checks.
|
||||||
if (Environment == 0 || Driver == 0) return false;
|
if (!Driver) return false;
|
||||||
if (size == 0) return false;
|
if (size == 0) return false;
|
||||||
if (filename.size() == 0) return false;
|
if (filename.empty()) return false;
|
||||||
|
|
||||||
io::IFileSystem* filesystem = Environment->getFileSystem();
|
|
||||||
irr::ILogger* logger = (Device != 0 ? Device->getLogger() : 0);
|
|
||||||
// FIXME: this is always null ^
|
|
||||||
this->size = size;
|
this->size = size;
|
||||||
this->filename = filename;
|
this->filename = filename;
|
||||||
|
|
||||||
|
@ -285,62 +261,33 @@ bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antia
|
||||||
this->use_transparency = transparency;
|
this->use_transparency = transparency;
|
||||||
update_load_flags();
|
update_load_flags();
|
||||||
|
|
||||||
// Log.
|
infostream << "CGUITTFont: Creating new font: " << filename.c_str() << " "
|
||||||
if (logger)
|
<< size << "pt " << (antialias ? "+antialias " : "-antialias ")
|
||||||
logger->log("CGUITTFont", (core::stringc(L"Creating new font: ") + filename + " " + core::stringc(size) + "pt " + (antialias ? "+antialias " : "-antialias ") + (transparency ? "+transparency" : "-transparency")).c_str(), irr::ELL_INFORMATION);
|
<< (transparency ? "+transparency" : "-transparency") << std::endl;
|
||||||
|
|
||||||
// Grab the face.
|
// Grab the face.
|
||||||
SGUITTFace* face = 0;
|
SGUITTFace* face = nullptr;
|
||||||
auto node = c_faces.find(filename);
|
auto node = c_faces.find(filename);
|
||||||
if (node == c_faces.end())
|
if (node == c_faces.end()) {
|
||||||
{
|
|
||||||
face = new SGUITTFace();
|
face = new SGUITTFace();
|
||||||
|
|
||||||
|
if (!fs::ReadFile(filename.c_str(), face->face_buffer, true)) {
|
||||||
|
delete face;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the face.
|
||||||
|
if (FT_New_Memory_Face(c_library,
|
||||||
|
reinterpret_cast<const FT_Byte*>(face->face_buffer.data()),
|
||||||
|
face->face_buffer.size(), 0, &face->face))
|
||||||
|
{
|
||||||
|
errorstream << "CGUITTFont: FT_New_Memory_Face failed." << std::endl;
|
||||||
|
delete face;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
c_faces.emplace(filename, face);
|
c_faces.emplace(filename, face);
|
||||||
|
} else {
|
||||||
if (filesystem)
|
|
||||||
{
|
|
||||||
// Read in the file data.
|
|
||||||
io::IReadFile* file = filesystem->createAndOpenFile(filename);
|
|
||||||
if (file == 0)
|
|
||||||
{
|
|
||||||
if (logger) logger->log("CGUITTFont", "Failed to open the file.", irr::ELL_INFORMATION);
|
|
||||||
|
|
||||||
c_faces.erase(filename);
|
|
||||||
delete face;
|
|
||||||
face = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
face->face_buffer = new FT_Byte[file->getSize()];
|
|
||||||
file->read(face->face_buffer, file->getSize());
|
|
||||||
face->face_buffer_size = file->getSize();
|
|
||||||
file->drop();
|
|
||||||
|
|
||||||
// Create the face.
|
|
||||||
if (FT_New_Memory_Face(c_library, face->face_buffer, face->face_buffer_size, 0, &face->face))
|
|
||||||
{
|
|
||||||
if (logger) logger->log("CGUITTFont", "FT_New_Memory_Face failed.", irr::ELL_INFORMATION);
|
|
||||||
|
|
||||||
c_faces.erase(filename);
|
|
||||||
delete face;
|
|
||||||
face = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (FT_New_Face(c_library, reinterpret_cast<const char*>(filename.c_str()), 0, &face->face))
|
|
||||||
{
|
|
||||||
if (logger) logger->log("CGUITTFont", "FT_New_Face failed.", irr::ELL_INFORMATION);
|
|
||||||
|
|
||||||
c_faces.erase(filename);
|
|
||||||
delete face;
|
|
||||||
face = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Using another instance of this face.
|
// Using another instance of this face.
|
||||||
face = node->second;
|
face = node->second;
|
||||||
face->grab();
|
face->grab();
|
||||||
|
@ -353,20 +300,12 @@ bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antia
|
||||||
FT_Set_Pixel_Sizes(tt_face, size, 0);
|
FT_Set_Pixel_Sizes(tt_face, size, 0);
|
||||||
font_metrics = tt_face->size->metrics;
|
font_metrics = tt_face->size->metrics;
|
||||||
|
|
||||||
|
verbosestream << tt_face->num_glyphs << " glyphs, ascender=" << font_metrics.ascender
|
||||||
|
<< " height=" << font_metrics.height << std::endl;
|
||||||
|
|
||||||
// Allocate our glyphs.
|
// Allocate our glyphs.
|
||||||
Glyphs.clear();
|
Glyphs.clear();
|
||||||
Glyphs.reallocate(tt_face->num_glyphs);
|
|
||||||
Glyphs.set_used(tt_face->num_glyphs);
|
Glyphs.set_used(tt_face->num_glyphs);
|
||||||
for (FT_Long i = 0; i < tt_face->num_glyphs; ++i)
|
|
||||||
{
|
|
||||||
Glyphs[i].isLoaded = false;
|
|
||||||
Glyphs[i].glyph_page = 0;
|
|
||||||
Glyphs[i].source_rect = core::recti();
|
|
||||||
Glyphs[i].offset = core::vector2di();
|
|
||||||
Glyphs[i].advance = FT_Vector();
|
|
||||||
Glyphs[i].surface = 0;
|
|
||||||
Glyphs[i].parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache the first 127 ascii characters.
|
// Cache the first 127 ascii characters.
|
||||||
u32 old_size = batch_load_size;
|
u32 old_size = batch_load_size;
|
||||||
|
@ -444,7 +383,7 @@ CGUITTGlyphPage* CGUITTFont::getLastGlyphPage() const
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGUITTGlyphPage* CGUITTFont::createGlyphPage(const u8& pixel_mode)
|
CGUITTGlyphPage* CGUITTFont::createGlyphPage(const u8 pixel_mode)
|
||||||
{
|
{
|
||||||
CGUITTGlyphPage* page = 0;
|
CGUITTGlyphPage* page = 0;
|
||||||
|
|
||||||
|
@ -481,7 +420,8 @@ CGUITTGlyphPage* CGUITTFont::createGlyphPage(const u8& pixel_mode)
|
||||||
page_texture_size = max_texture_size;
|
page_texture_size = max_texture_size;
|
||||||
|
|
||||||
if (!page->createPageTexture(pixel_mode, page_texture_size)) {
|
if (!page->createPageTexture(pixel_mode, page_texture_size)) {
|
||||||
// TODO: add error message?
|
errorstream << "CGUITTGlyphPage: failed to create texture ("
|
||||||
|
<< page_texture_size.Width << "x" << page_texture_size.Height << ")" << std::endl;
|
||||||
delete page;
|
delete page;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -622,13 +562,12 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
|
||||||
else if (fallback != 0)
|
else if (fallback != 0)
|
||||||
{
|
{
|
||||||
// Let the fallback font draw it, this isn't super efficient but hopefully that doesn't matter
|
// Let the fallback font draw it, this isn't super efficient but hopefully that doesn't matter
|
||||||
wchar_t l1[] = { (wchar_t) currentChar, 0 }, l2 = (wchar_t) previousChar;
|
wchar_t l1[] = { (wchar_t) currentChar, 0 };
|
||||||
|
|
||||||
if (visible)
|
if (visible)
|
||||||
{
|
{
|
||||||
// Apply kerning.
|
// Apply kerning.
|
||||||
offset.X += fallback->getKerningWidth(l1, &l2);
|
offset += fallback->getKerning(*l1, (wchar_t) previousChar);
|
||||||
offset.Y += fallback->getKerningHeight();
|
|
||||||
|
|
||||||
const u32 current_color = iter - utext.begin();
|
const u32 current_color = iter - utext.begin();
|
||||||
fallback->draw(core::stringw(l1),
|
fallback->draw(core::stringw(l1),
|
||||||
|
@ -688,11 +627,6 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
core::dimension2d<u32> CGUITTFont::getCharDimension(const wchar_t ch) const
|
|
||||||
{
|
|
||||||
return core::dimension2d<u32>(getWidthFromCharacter(ch), getHeightFromCharacter(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
core::dimension2d<u32> CGUITTFont::getDimension(const wchar_t* text) const
|
core::dimension2d<u32> CGUITTFont::getDimension(const wchar_t* text) const
|
||||||
{
|
{
|
||||||
return getDimension(convertWCharToU32String(text));
|
return getDimension(convertWCharToU32String(text));
|
||||||
|
@ -759,21 +693,12 @@ core::dimension2d<u32> CGUITTFont::getDimension(const std::u32string& text) cons
|
||||||
return text_dimension;
|
return text_dimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline u32 CGUITTFont::getWidthFromCharacter(wchar_t c) const
|
|
||||||
{
|
|
||||||
return getWidthFromCharacter((char32_t)c);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 CGUITTFont::getWidthFromCharacter(char32_t c) const
|
inline u32 CGUITTFont::getWidthFromCharacter(char32_t c) const
|
||||||
{
|
{
|
||||||
// Set the size of the face.
|
|
||||||
// This is because we cache faces and the face may have been set to a different size.
|
|
||||||
//FT_Set_Pixel_Sizes(tt_face, 0, size);
|
|
||||||
|
|
||||||
u32 n = getGlyphIndexByChar(c);
|
u32 n = getGlyphIndexByChar(c);
|
||||||
if (n > 0)
|
if (n > 0)
|
||||||
{
|
{
|
||||||
int w = Glyphs[n-1].advance.x / 64;
|
int w = Glyphs[n-1].advance.X / 64;
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
if (fallback != 0)
|
if (fallback != 0)
|
||||||
|
@ -787,17 +712,8 @@ inline u32 CGUITTFont::getWidthFromCharacter(char32_t c) const
|
||||||
else return (font_metrics.ascender / 64) / 2;
|
else return (font_metrics.ascender / 64) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline u32 CGUITTFont::getHeightFromCharacter(wchar_t c) const
|
|
||||||
{
|
|
||||||
return getHeightFromCharacter((char32_t)c);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 CGUITTFont::getHeightFromCharacter(char32_t c) const
|
inline u32 CGUITTFont::getHeightFromCharacter(char32_t c) const
|
||||||
{
|
{
|
||||||
// Set the size of the face.
|
|
||||||
// This is because we cache faces and the face may have been set to a different size.
|
|
||||||
//FT_Set_Pixel_Sizes(tt_face, 0, size);
|
|
||||||
|
|
||||||
u32 n = getGlyphIndexByChar(c);
|
u32 n = getGlyphIndexByChar(c);
|
||||||
if (n > 0)
|
if (n > 0)
|
||||||
{
|
{
|
||||||
|
@ -816,11 +732,6 @@ inline u32 CGUITTFont::getHeightFromCharacter(char32_t c) const
|
||||||
else return (font_metrics.ascender / 64) / 2;
|
else return (font_metrics.ascender / 64) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CGUITTFont::getGlyphIndexByChar(wchar_t c) const
|
|
||||||
{
|
|
||||||
return getGlyphIndexByChar((char32_t)c);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 CGUITTFont::getGlyphIndexByChar(char32_t c) const
|
u32 CGUITTFont::getGlyphIndexByChar(char32_t c) const
|
||||||
{
|
{
|
||||||
// Get the glyph.
|
// Get the glyph.
|
||||||
|
@ -831,7 +742,7 @@ u32 CGUITTFont::getGlyphIndexByChar(char32_t c) const
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// If our glyph is already loaded, don't bother doing any batch loading code.
|
// If our glyph is already loaded, don't bother doing any batch loading code.
|
||||||
if (glyph != 0 && Glyphs[glyph - 1].isLoaded)
|
if (glyph != 0 && Glyphs[glyph - 1].isLoaded())
|
||||||
return glyph;
|
return glyph;
|
||||||
|
|
||||||
// Determine our batch loading positions.
|
// Determine our batch loading positions.
|
||||||
|
@ -850,9 +761,10 @@ u32 CGUITTFont::getGlyphIndexByChar(char32_t c) const
|
||||||
if (char_index)
|
if (char_index)
|
||||||
{
|
{
|
||||||
SGUITTGlyph& glyph = Glyphs[char_index - 1];
|
SGUITTGlyph& glyph = Glyphs[char_index - 1];
|
||||||
if (!glyph.isLoaded)
|
if (!glyph.isLoaded())
|
||||||
{
|
{
|
||||||
glyph.preload(char_index, tt_face, Driver, size, load_flags);
|
auto *this2 = const_cast<CGUITTFont*>(this); // oh well
|
||||||
|
glyph.preload(char_index, tt_face, this2, size, load_flags);
|
||||||
Glyph_Pages[glyph.glyph_page]->pushGlyphToBePaged(&glyph);
|
Glyph_Pages[glyph.glyph_page]->pushGlyphToBePaged(&glyph);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -871,11 +783,10 @@ s32 CGUITTFont::getCharacterFromPos(const wchar_t* text, s32 pixel_x) const
|
||||||
s32 CGUITTFont::getCharacterFromPos(const std::u32string& text, s32 pixel_x) const
|
s32 CGUITTFont::getCharacterFromPos(const std::u32string& text, s32 pixel_x) const
|
||||||
{
|
{
|
||||||
s32 x = 0;
|
s32 x = 0;
|
||||||
//s32 idx = 0;
|
|
||||||
|
|
||||||
u32 character = 0;
|
u32 character = 0;
|
||||||
char32_t previousChar = 0;
|
char32_t previousChar = 0;
|
||||||
std::u32string::const_iterator iter = text.begin();
|
auto iter = text.begin();
|
||||||
while (iter != text.end())
|
while (iter != text.end())
|
||||||
{
|
{
|
||||||
char32_t c = *iter;
|
char32_t c = *iter;
|
||||||
|
@ -906,28 +817,6 @@ void CGUITTFont::setKerningHeight(s32 kerning)
|
||||||
GlobalKerningHeight = kerning;
|
GlobalKerningHeight = kerning;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 CGUITTFont::getKerningWidth(const wchar_t* thisLetter, const wchar_t* previousLetter) const
|
|
||||||
{
|
|
||||||
if (tt_face == 0)
|
|
||||||
return GlobalKerningWidth;
|
|
||||||
if (thisLetter == 0 || previousLetter == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return getKerningWidth((char32_t)*thisLetter, (char32_t)*previousLetter);
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 CGUITTFont::getKerningWidth(const char32_t thisLetter, const char32_t previousLetter) const
|
|
||||||
{
|
|
||||||
// Return only the kerning width.
|
|
||||||
return getKerning(thisLetter, previousLetter).X;
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 CGUITTFont::getKerningHeight() const
|
|
||||||
{
|
|
||||||
// FreeType 2 currently doesn't return any height kerning information.
|
|
||||||
return GlobalKerningHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
core::vector2di CGUITTFont::getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const
|
core::vector2di CGUITTFont::getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const
|
||||||
{
|
{
|
||||||
return getKerning((char32_t)thisLetter, (char32_t)previousLetter);
|
return getKerning((char32_t)thisLetter, (char32_t)previousLetter);
|
||||||
|
@ -949,11 +838,8 @@ core::vector2di CGUITTFont::getKerning(const char32_t thisLetter, const char32_t
|
||||||
// If we don't have this glyph, ask fallback font
|
// If we don't have this glyph, ask fallback font
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
{
|
{
|
||||||
if (fallback != 0) {
|
if (fallback)
|
||||||
wchar_t l1 = (wchar_t) thisLetter, l2 = (wchar_t) previousLetter;
|
ret = fallback->getKerning((wchar_t) thisLetter, (wchar_t) previousLetter);
|
||||||
ret.X = fallback->getKerningWidth(&l1, &l2);
|
|
||||||
ret.Y = fallback->getKerningHeight();
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1029,196 +915,6 @@ video::ITexture* CGUITTFont::getPageTextureByIndex(const u32& page_index) const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGUITTFont::createSharedPlane()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
2___3
|
|
||||||
| /|
|
|
||||||
| / | <-- plane mesh is like this, point 2 is (0,0), point 0 is (0, -1)
|
|
||||||
|/ | <-- the texture coords of point 2 is (0,0, point 0 is (0, 1)
|
|
||||||
0---1
|
|
||||||
*/
|
|
||||||
|
|
||||||
using namespace core;
|
|
||||||
using namespace video;
|
|
||||||
using namespace scene;
|
|
||||||
S3DVertex vertices[4];
|
|
||||||
u16 indices[6] = {0,2,3,3,1,0};
|
|
||||||
vertices[0] = S3DVertex(vector3df(0,-1,0), vector3df(0,0,-1), SColor(255,255,255,255), vector2df(0,1));
|
|
||||||
vertices[1] = S3DVertex(vector3df(1,-1,0), vector3df(0,0,-1), SColor(255,255,255,255), vector2df(1,1));
|
|
||||||
vertices[2] = S3DVertex(vector3df(0, 0,0), vector3df(0,0,-1), SColor(255,255,255,255), vector2df(0,0));
|
|
||||||
vertices[3] = S3DVertex(vector3df(1, 0,0), vector3df(0,0,-1), SColor(255,255,255,255), vector2df(1,0));
|
|
||||||
|
|
||||||
SMeshBuffer* buf = new SMeshBuffer();
|
|
||||||
buf->append(vertices, 4, indices, 6);
|
|
||||||
|
|
||||||
shared_plane_.addMeshBuffer( buf );
|
|
||||||
shared_plane_.setHardwareMappingHint(EHM_STATIC);
|
|
||||||
|
|
||||||
shared_plane_ptr_ = &shared_plane_;
|
|
||||||
buf->drop(); //the addMeshBuffer method will grab it, so we can drop this ptr.
|
|
||||||
}
|
|
||||||
|
|
||||||
core::dimension2d<u32> CGUITTFont::getDimensionUntilEndOfLine(const wchar_t* p) const
|
|
||||||
{
|
|
||||||
core::stringw s;
|
|
||||||
for (const wchar_t* temp = p; temp && *temp != '\0' && *temp != L'\r' && *temp != L'\n'; ++temp )
|
|
||||||
s.append(*temp);
|
|
||||||
|
|
||||||
return getDimension(s.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
core::array<scene::ISceneNode*> CGUITTFont::addTextSceneNode(const wchar_t* text, scene::ISceneManager* smgr, scene::ISceneNode* parent, const video::SColor& color, bool center)
|
|
||||||
{
|
|
||||||
using namespace core;
|
|
||||||
using namespace video;
|
|
||||||
using namespace scene;
|
|
||||||
|
|
||||||
array<scene::ISceneNode*> container;
|
|
||||||
|
|
||||||
if (!Driver || !smgr) return container;
|
|
||||||
if (!parent)
|
|
||||||
parent = smgr->addEmptySceneNode(smgr->getRootSceneNode(), -1);
|
|
||||||
// if you don't specify parent, then we add an empty node attached to the root node
|
|
||||||
// this is generally undesirable.
|
|
||||||
|
|
||||||
if (!shared_plane_ptr_) //this points to a static mesh that contains the plane
|
|
||||||
createSharedPlane(); //if it's not initialized, we create one.
|
|
||||||
|
|
||||||
dimension2d<s32> text_size(getDimension(text)); //convert from unsigned to signed.
|
|
||||||
vector3df start_point(0, 0, 0), offset;
|
|
||||||
|
|
||||||
/** NOTICE:
|
|
||||||
Because we are considering adding texts into 3D world, all Y axis vectors are inverted.
|
|
||||||
**/
|
|
||||||
|
|
||||||
// There's currently no "vertical center" concept when you apply text scene node to the 3D world.
|
|
||||||
if (center)
|
|
||||||
{
|
|
||||||
offset.X = start_point.X = -text_size.Width / 2.f;
|
|
||||||
offset.Y = start_point.Y = +text_size.Height/ 2.f;
|
|
||||||
offset.X += (text_size.Width - getDimensionUntilEndOfLine(text).Width) >> 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the default font material
|
|
||||||
SMaterial mat;
|
|
||||||
mat.ZWriteEnable = video::EZW_OFF;
|
|
||||||
mat.MaterialType = use_transparency ? video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_SOLID;
|
|
||||||
mat.MaterialTypeParam = 0.01f;
|
|
||||||
|
|
||||||
wchar_t current_char = 0, previous_char = 0;
|
|
||||||
u32 n = 0;
|
|
||||||
|
|
||||||
array<u32> glyph_indices;
|
|
||||||
|
|
||||||
while (*text)
|
|
||||||
{
|
|
||||||
current_char = *text;
|
|
||||||
bool line_break=false;
|
|
||||||
if (current_char == L'\r') // Mac or Windows breaks
|
|
||||||
{
|
|
||||||
line_break = true;
|
|
||||||
if (*(text + 1) == L'\n') // Windows line breaks.
|
|
||||||
current_char = *(++text);
|
|
||||||
}
|
|
||||||
else if (current_char == L'\n') // Unix breaks
|
|
||||||
{
|
|
||||||
line_break = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line_break)
|
|
||||||
{
|
|
||||||
previous_char = 0;
|
|
||||||
offset.Y -= tt_face->size->metrics.ascender / 64;
|
|
||||||
offset.X = start_point.X;
|
|
||||||
if (center)
|
|
||||||
offset.X += (text_size.Width - getDimensionUntilEndOfLine(text+1).Width) >> 1;
|
|
||||||
++text;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n = getGlyphIndexByChar(current_char);
|
|
||||||
if (n > 0)
|
|
||||||
{
|
|
||||||
glyph_indices.push_back( n );
|
|
||||||
|
|
||||||
// Store glyph size and offset informations.
|
|
||||||
SGUITTGlyph const& glyph = Glyphs[n-1];
|
|
||||||
u32 texw = glyph.source_rect.getWidth();
|
|
||||||
u32 texh = glyph.source_rect.getHeight();
|
|
||||||
s32 offx = glyph.offset.X;
|
|
||||||
s32 offy = (font_metrics.ascender / 64) - glyph.offset.Y;
|
|
||||||
|
|
||||||
// Apply kerning.
|
|
||||||
vector2di k = getKerning(current_char, previous_char);
|
|
||||||
offset.X += k.X;
|
|
||||||
offset.Y += k.Y;
|
|
||||||
|
|
||||||
vector3df current_pos(offset.X + offx, offset.Y - offy, 0);
|
|
||||||
dimension2d<u32> letter_size = dimension2d<u32>(texw, texh);
|
|
||||||
|
|
||||||
// Now we copy planes corresponding to the letter size.
|
|
||||||
IMeshManipulator* mani = smgr->getMeshManipulator();
|
|
||||||
IMesh* meshcopy = mani->createMeshCopy(shared_plane_ptr_);
|
|
||||||
mani->scale(meshcopy, vector3df((f32)letter_size.Width, (f32)letter_size.Height, 1));
|
|
||||||
|
|
||||||
ISceneNode* current_node = smgr->addMeshSceneNode(meshcopy, parent, -1, current_pos);
|
|
||||||
meshcopy->drop();
|
|
||||||
|
|
||||||
current_node->getMaterial(0) = mat;
|
|
||||||
current_node->setAutomaticCulling(EAC_OFF);
|
|
||||||
current_node->setIsDebugObject(true); //so the picking won't have any effect on individual letter
|
|
||||||
//current_node->setDebugDataVisible(EDS_BBOX); //de-comment this when debugging
|
|
||||||
|
|
||||||
container.push_back(current_node);
|
|
||||||
}
|
|
||||||
offset.X += getWidthFromCharacter(current_char);
|
|
||||||
// Note that fallback font handling is missing here (Minetest never uses this)
|
|
||||||
|
|
||||||
previous_char = current_char;
|
|
||||||
++text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update_glyph_pages();
|
|
||||||
//only after we update the textures can we use the glyph page textures.
|
|
||||||
|
|
||||||
for (u32 i = 0; i < glyph_indices.size(); ++i)
|
|
||||||
{
|
|
||||||
u32 n = glyph_indices[i];
|
|
||||||
SGUITTGlyph const& glyph = Glyphs[n-1];
|
|
||||||
ITexture* current_tex = Glyph_Pages[glyph.glyph_page]->texture;
|
|
||||||
f32 page_texture_size = (f32)current_tex->getSize().Width;
|
|
||||||
//Now we calculate the UV position according to the texture size and the source rect.
|
|
||||||
//
|
|
||||||
// 2___3
|
|
||||||
// | /|
|
|
||||||
// | / | <-- plane mesh is like this, point 2 is (0,0), point 0 is (0, -1)
|
|
||||||
// |/ | <-- the texture coords of point 2 is (0,0, point 0 is (0, 1)
|
|
||||||
// 0---1
|
|
||||||
//
|
|
||||||
f32 u1 = glyph.source_rect.UpperLeftCorner.X / page_texture_size;
|
|
||||||
f32 u2 = u1 + (glyph.source_rect.getWidth() / page_texture_size);
|
|
||||||
f32 v1 = glyph.source_rect.UpperLeftCorner.Y / page_texture_size;
|
|
||||||
f32 v2 = v1 + (glyph.source_rect.getHeight() / page_texture_size);
|
|
||||||
|
|
||||||
//we can be quite sure that this is IMeshSceneNode, because we just added them in the above loop.
|
|
||||||
IMeshSceneNode* node = static_cast<IMeshSceneNode*>(container[i]);
|
|
||||||
|
|
||||||
S3DVertex* pv = static_cast<S3DVertex*>(node->getMesh()->getMeshBuffer(0)->getVertices());
|
|
||||||
//pv[0].TCoords.Y = pv[1].TCoords.Y = (letter_size.Height - 1) / static_cast<f32>(letter_size.Height);
|
|
||||||
//pv[1].TCoords.X = pv[3].TCoords.X = (letter_size.Width - 1) / static_cast<f32>(letter_size.Width);
|
|
||||||
pv[0].TCoords = vector2df(u1, v2);
|
|
||||||
pv[1].TCoords = vector2df(u2, v2);
|
|
||||||
pv[2].TCoords = vector2df(u1, v1);
|
|
||||||
pv[3].TCoords = vector2df(u2, v1);
|
|
||||||
|
|
||||||
container[i]->getMaterial(0).setTexture(0, current_tex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::u32string CGUITTFont::convertWCharToU32String(const wchar_t* const charArray) const
|
std::u32string CGUITTFont::convertWCharToU32String(const wchar_t* const charArray) const
|
||||||
{
|
{
|
||||||
static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "unexpected wchar size");
|
static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "unexpected wchar size");
|
||||||
|
|
|
@ -32,17 +32,17 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ft2build.h>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
#include "IGUIEnvironment.h"
|
#include "IGUIEnvironment.h"
|
||||||
#include "IGUIFont.h"
|
#include "IGUIFont.h"
|
||||||
#include "ISceneManager.h"
|
|
||||||
#include "IVideoDriver.h"
|
#include "IVideoDriver.h"
|
||||||
#include "IrrlichtDevice.h"
|
#include "IrrlichtDevice.h"
|
||||||
#include "SMesh.h"
|
#include "SMesh.h"
|
||||||
#include "util/enriched_string.h"
|
#include "util/enriched_string.h"
|
||||||
#include "util/basic_macros.h"
|
#include "util/basic_macros.h"
|
||||||
#include FT_FREETYPE_H
|
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
|
@ -56,26 +56,22 @@ namespace gui
|
||||||
{
|
{
|
||||||
//! Constructor.
|
//! Constructor.
|
||||||
SGUITTGlyph() :
|
SGUITTGlyph() :
|
||||||
isLoaded(false),
|
|
||||||
glyph_page(0),
|
glyph_page(0),
|
||||||
source_rect(),
|
source_rect(),
|
||||||
offset(),
|
offset(),
|
||||||
advance(),
|
advance(),
|
||||||
surface(0),
|
surface(0)
|
||||||
parent(0)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
DISABLE_CLASS_COPY(SGUITTGlyph);
|
DISABLE_CLASS_COPY(SGUITTGlyph);
|
||||||
|
|
||||||
//! This class would be trivially copyable except for the reference count on `surface`.
|
//! This class would be trivially copyable except for the reference count on `surface`.
|
||||||
SGUITTGlyph(SGUITTGlyph &&other) noexcept :
|
SGUITTGlyph(SGUITTGlyph &&other) noexcept :
|
||||||
isLoaded(other.isLoaded),
|
|
||||||
glyph_page(other.glyph_page),
|
glyph_page(other.glyph_page),
|
||||||
source_rect(other.source_rect),
|
source_rect(other.source_rect),
|
||||||
offset(other.offset),
|
offset(other.offset),
|
||||||
advance(other.advance),
|
advance(other.advance),
|
||||||
surface(other.surface),
|
surface(other.surface)
|
||||||
parent(other.parent)
|
|
||||||
{
|
{
|
||||||
other.surface = 0;
|
other.surface = 0;
|
||||||
}
|
}
|
||||||
|
@ -83,12 +79,17 @@ namespace gui
|
||||||
//! Destructor.
|
//! Destructor.
|
||||||
~SGUITTGlyph() { unload(); }
|
~SGUITTGlyph() { unload(); }
|
||||||
|
|
||||||
|
//! If true, the glyph has been loaded.
|
||||||
|
inline bool isLoaded() const {
|
||||||
|
return source_rect != core::recti();
|
||||||
|
}
|
||||||
|
|
||||||
//! Preload the glyph.
|
//! Preload the glyph.
|
||||||
//! The preload process occurs when the program tries to cache the glyph from FT_Library.
|
//! The preload process occurs when the program tries to cache the glyph from FT_Library.
|
||||||
//! However, it simply defines the SGUITTGlyph's properties and will only create the page
|
//! However, it simply defines the SGUITTGlyph's properties and will only create the page
|
||||||
//! textures if necessary. The actual creation of the textures should only occur right
|
//! textures if necessary. The actual creation of the textures should only occur right
|
||||||
//! before the batch draw call.
|
//! before the batch draw call.
|
||||||
void preload(u32 char_index, FT_Face face, video::IVideoDriver* driver, u32 font_size, const FT_Int32 loadFlags);
|
void preload(u32 char_index, FT_Face face, CGUITTFont *parent, u32 font_size, const FT_Int32 loadFlags);
|
||||||
|
|
||||||
//! Unloads the glyph.
|
//! Unloads the glyph.
|
||||||
void unload();
|
void unload();
|
||||||
|
@ -96,9 +97,6 @@ namespace gui
|
||||||
//! Creates the IImage object from the FT_Bitmap.
|
//! Creates the IImage object from the FT_Bitmap.
|
||||||
video::IImage* createGlyphImage(const FT_Bitmap& bits, video::IVideoDriver* driver) const;
|
video::IImage* createGlyphImage(const FT_Bitmap& bits, video::IVideoDriver* driver) const;
|
||||||
|
|
||||||
//! If true, the glyph has been loaded.
|
|
||||||
bool isLoaded;
|
|
||||||
|
|
||||||
//! The page the glyph is on.
|
//! The page the glyph is on.
|
||||||
u32 glyph_page;
|
u32 glyph_page;
|
||||||
|
|
||||||
|
@ -109,14 +107,11 @@ namespace gui
|
||||||
core::vector2di offset;
|
core::vector2di offset;
|
||||||
|
|
||||||
//! Glyph advance information.
|
//! Glyph advance information.
|
||||||
FT_Vector advance;
|
core::vector2di advance;
|
||||||
|
|
||||||
//! This is just the temporary image holder. After this glyph is paged,
|
//! This is just the temporary image holder. After this glyph is paged,
|
||||||
//! it will be dropped.
|
//! it will be dropped.
|
||||||
mutable video::IImage* surface;
|
mutable video::IImage* surface;
|
||||||
|
|
||||||
//! The pointer pointing to the parent (CGUITTFont)
|
|
||||||
CGUITTFont* parent;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Holds a sheet of glyphs.
|
//! Holds a sheet of glyphs.
|
||||||
|
@ -130,7 +125,8 @@ namespace gui
|
||||||
{
|
{
|
||||||
if (driver)
|
if (driver)
|
||||||
driver->removeTexture(texture);
|
driver->removeTexture(texture);
|
||||||
else texture->drop();
|
else
|
||||||
|
texture->drop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,19 +180,11 @@ namespace gui
|
||||||
for (u32 i = 0; i < glyph_to_be_paged.size(); ++i)
|
for (u32 i = 0; i < glyph_to_be_paged.size(); ++i)
|
||||||
{
|
{
|
||||||
const SGUITTGlyph* glyph = glyph_to_be_paged[i];
|
const SGUITTGlyph* glyph = glyph_to_be_paged[i];
|
||||||
if (glyph && glyph->isLoaded)
|
if (glyph && glyph->surface)
|
||||||
{
|
{
|
||||||
if (glyph->surface)
|
glyph->surface->copyTo(pageholder, glyph->source_rect.UpperLeftCorner);
|
||||||
{
|
glyph->surface->drop();
|
||||||
glyph->surface->copyTo(pageholder, glyph->source_rect.UpperLeftCorner);
|
glyph->surface = 0;
|
||||||
glyph->surface->drop();
|
|
||||||
glyph->surface = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
; // TODO: add error message?
|
|
||||||
//currently, if we failed to create the image, just ignore this operation.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,77 +226,70 @@ namespace gui
|
||||||
virtual ~CGUITTFont();
|
virtual ~CGUITTFont();
|
||||||
|
|
||||||
//! Sets the amount of glyphs to batch load.
|
//! Sets the amount of glyphs to batch load.
|
||||||
virtual void setBatchLoadSize(u32 batch_size) { batch_load_size = batch_size; }
|
void setBatchLoadSize(u32 batch_size) { batch_load_size = batch_size; }
|
||||||
|
|
||||||
//! Sets the maximum texture size for a page of glyphs.
|
//! Sets the maximum texture size for a page of glyphs.
|
||||||
virtual void setMaxPageTextureSize(const core::dimension2du& texture_size) { max_page_texture_size = texture_size; }
|
void setMaxPageTextureSize(const core::dimension2du& texture_size) { max_page_texture_size = texture_size; }
|
||||||
|
|
||||||
//! Get the font size.
|
//! Get the font size.
|
||||||
virtual u32 getFontSize() const { return size; }
|
u32 getFontSize() const { return size; }
|
||||||
|
|
||||||
//! Check the font's transparency.
|
//! Check the font's transparency.
|
||||||
virtual bool isTransparent() const { return use_transparency; }
|
bool isTransparent() const { return use_transparency; }
|
||||||
|
|
||||||
//! Check if the font auto-hinting is enabled.
|
//! Check if the font auto-hinting is enabled.
|
||||||
//! Auto-hinting is FreeType's built-in font hinting engine.
|
//! Auto-hinting is FreeType's built-in font hinting engine.
|
||||||
virtual bool useAutoHinting() const { return use_auto_hinting; }
|
bool useAutoHinting() const { return use_auto_hinting; }
|
||||||
|
|
||||||
//! Check if the font hinting is enabled.
|
//! Check if the font hinting is enabled.
|
||||||
virtual bool useHinting() const { return use_hinting; }
|
bool useHinting() const { return use_hinting; }
|
||||||
|
|
||||||
//! Check if the font is being loaded as a monochrome font.
|
//! Check if the font is being loaded as a monochrome font.
|
||||||
//! The font can either be a 256 color grayscale font, or a 2 color monochrome font.
|
//! The font can either be a 256 color grayscale font, or a 2 color monochrome font.
|
||||||
virtual bool useMonochrome() const { return use_monochrome; }
|
bool useMonochrome() const { return use_monochrome; }
|
||||||
|
|
||||||
//! Tells the font to allow transparency when rendering.
|
//! Tells the font to allow transparency when rendering.
|
||||||
//! Default: true.
|
//! Default: true.
|
||||||
//! \param flag If true, the font draws using transparency.
|
//! \param flag If true, the font draws using transparency.
|
||||||
virtual void setTransparency(const bool flag);
|
void setTransparency(const bool flag);
|
||||||
|
|
||||||
//! Tells the font to use monochrome rendering.
|
//! Tells the font to use monochrome rendering.
|
||||||
//! Default: false.
|
//! Default: false.
|
||||||
//! \param flag If true, the font draws using a monochrome image. If false, the font uses a grayscale image.
|
//! \param flag If true, the font draws using a monochrome image. If false, the font uses a grayscale image.
|
||||||
virtual void setMonochrome(const bool flag);
|
void setMonochrome(const bool flag);
|
||||||
|
|
||||||
//! Enables or disables font hinting.
|
//! Enables or disables font hinting.
|
||||||
//! Default: Hinting and auto-hinting true.
|
//! Default: Hinting and auto-hinting true.
|
||||||
//! \param enable If false, font hinting is turned off. If true, font hinting is turned on.
|
//! \param enable If false, font hinting is turned off. If true, font hinting is turned on.
|
||||||
//! \param enable_auto_hinting If true, FreeType uses its own auto-hinting algorithm. If false, it tries to use the algorithm specified by the font.
|
//! \param enable_auto_hinting If true, FreeType uses its own auto-hinting algorithm. If false, it tries to use the algorithm specified by the font.
|
||||||
virtual void setFontHinting(const bool enable, const bool enable_auto_hinting = true);
|
void setFontHinting(const bool enable, const bool enable_auto_hinting = true);
|
||||||
|
|
||||||
//! Draws some text and clips it to the specified rectangle if wanted.
|
//! Draws some text and clips it to the specified rectangle if wanted.
|
||||||
virtual void draw(const core::stringw& text, const core::rect<s32>& position,
|
virtual void draw(const core::stringw& text, const core::rect<s32>& position,
|
||||||
video::SColor color, bool hcenter=false, bool vcenter=false,
|
video::SColor color, bool hcenter=false, bool vcenter=false,
|
||||||
const core::rect<s32>* clip=0);
|
const core::rect<s32>* clip=0) override;
|
||||||
|
|
||||||
void draw(const EnrichedString& text, const core::rect<s32>& position,
|
void draw(const EnrichedString& text, const core::rect<s32>& position,
|
||||||
bool hcenter=false, bool vcenter=false,
|
bool hcenter=false, bool vcenter=false,
|
||||||
const core::rect<s32>* clip=0);
|
const core::rect<s32>* clip=0);
|
||||||
|
|
||||||
//! Returns the dimension of a character produced by this font.
|
|
||||||
virtual core::dimension2d<u32> getCharDimension(const wchar_t ch) const;
|
|
||||||
|
|
||||||
//! Returns the dimension of a text string.
|
//! Returns the dimension of a text string.
|
||||||
virtual core::dimension2d<u32> getDimension(const wchar_t* text) const;
|
virtual core::dimension2du getDimension(const wchar_t* text) const override;
|
||||||
|
|
||||||
//! Calculates the index of the character in the text which is on a specific position.
|
//! Calculates the index of the character in the text which is on a specific position.
|
||||||
virtual s32 getCharacterFromPos(const wchar_t* text, s32 pixel_x) const;
|
virtual s32 getCharacterFromPos(const wchar_t* text, s32 pixel_x) const override;
|
||||||
|
|
||||||
//! Sets global kerning width for the font.
|
//! Sets global kerning width for the font.
|
||||||
virtual void setKerningWidth(s32 kerning);
|
virtual void setKerningWidth(s32 kerning) override;
|
||||||
|
|
||||||
//! Sets global kerning height for the font.
|
//! Sets global kerning height for the font.
|
||||||
virtual void setKerningHeight(s32 kerning);
|
virtual void setKerningHeight(s32 kerning) override;
|
||||||
|
|
||||||
//! Gets kerning values (distance between letters) for the font. If no parameters are provided,
|
|
||||||
virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const;
|
|
||||||
virtual s32 getKerningWidth(const char32_t thisLetter=0, const char32_t previousLetter=0) const;
|
|
||||||
|
|
||||||
//! Returns the distance between letters
|
//! Returns the distance between letters
|
||||||
virtual s32 getKerningHeight() const;
|
virtual core::vector2di getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const override;
|
||||||
|
|
||||||
//! Define which characters should not be drawn by the font.
|
//! Define which characters should not be drawn by the font.
|
||||||
virtual void setInvisibleCharacters(const wchar_t *s);
|
virtual void setInvisibleCharacters(const wchar_t *s) override;
|
||||||
|
|
||||||
//! Get the last glyph page if there's still available slots.
|
//! Get the last glyph page if there's still available slots.
|
||||||
//! If not, it will return zero.
|
//! If not, it will return zero.
|
||||||
|
@ -317,7 +298,7 @@ namespace gui
|
||||||
//! Create a new glyph page texture.
|
//! Create a new glyph page texture.
|
||||||
//! \param pixel_mode the pixel mode defined by FT_Pixel_Mode
|
//! \param pixel_mode the pixel mode defined by FT_Pixel_Mode
|
||||||
//should be better typed. fix later.
|
//should be better typed. fix later.
|
||||||
CGUITTGlyphPage* createGlyphPage(const u8& pixel_mode);
|
CGUITTGlyphPage* createGlyphPage(const u8 pixel_mode);
|
||||||
|
|
||||||
//! Get the last glyph page's index.
|
//! Get the last glyph page's index.
|
||||||
u32 getLastGlyphPageIndex() const { return Glyph_Pages.size() - 1; }
|
u32 getLastGlyphPageIndex() const { return Glyph_Pages.size() - 1; }
|
||||||
|
@ -328,16 +309,13 @@ namespace gui
|
||||||
//! Create corresponding character's software image copy from the font,
|
//! Create corresponding character's software image copy from the font,
|
||||||
//! so you can use this data just like any ordinary video::IImage.
|
//! so you can use this data just like any ordinary video::IImage.
|
||||||
//! \param ch The character you need
|
//! \param ch The character you need
|
||||||
virtual video::IImage* createTextureFromChar(const char32_t& ch);
|
video::IImage* createTextureFromChar(const char32_t& ch);
|
||||||
|
|
||||||
//! This function is for debugging mostly. If the page doesn't exist it returns zero.
|
//! This function is for debugging mostly. If the page doesn't exist it returns zero.
|
||||||
//! \param page_index Simply return the texture handle of a given page index.
|
//! \param page_index Simply return the texture handle of a given page index.
|
||||||
virtual video::ITexture* getPageTextureByIndex(const u32& page_index) const;
|
video::ITexture* getPageTextureByIndex(const u32& page_index) const;
|
||||||
|
|
||||||
//! Add a list of scene nodes generated by putting font textures on the 3D planes.
|
inline video::IVideoDriver *getDriver() const { return Driver; }
|
||||||
virtual core::array<scene::ISceneNode*> addTextSceneNode
|
|
||||||
(const wchar_t* text, scene::ISceneManager* smgr, scene::ISceneNode* parent = 0,
|
|
||||||
const video::SColor& color = video::SColor(255, 0, 0, 0), bool center = false );
|
|
||||||
|
|
||||||
inline s32 getAscender() const { return font_metrics.ascender; }
|
inline s32 getAscender() const { return font_metrics.ascender; }
|
||||||
|
|
||||||
|
@ -355,8 +333,6 @@ namespace gui
|
||||||
static FT_Library c_library;
|
static FT_Library c_library;
|
||||||
static std::map<io::path, SGUITTFace*> c_faces;
|
static std::map<io::path, SGUITTFace*> c_faces;
|
||||||
static bool c_libraryLoaded;
|
static bool c_libraryLoaded;
|
||||||
static scene::IMesh* shared_plane_ptr_;
|
|
||||||
static scene::SMesh shared_plane_;
|
|
||||||
|
|
||||||
// Helper functions for the same-named public member functions above
|
// Helper functions for the same-named public member functions above
|
||||||
// (Since std::u32string is nicer to work with than wchar_t *)
|
// (Since std::u32string is nicer to work with than wchar_t *)
|
||||||
|
@ -379,20 +355,11 @@ namespace gui
|
||||||
if (useMonochrome()) load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO;
|
if (useMonochrome()) load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO;
|
||||||
else load_flags |= FT_LOAD_TARGET_NORMAL;
|
else load_flags |= FT_LOAD_TARGET_NORMAL;
|
||||||
}
|
}
|
||||||
u32 getWidthFromCharacter(wchar_t c) const;
|
|
||||||
u32 getWidthFromCharacter(char32_t c) const;
|
u32 getWidthFromCharacter(char32_t c) const;
|
||||||
u32 getHeightFromCharacter(wchar_t c) const;
|
|
||||||
u32 getHeightFromCharacter(char32_t c) const;
|
u32 getHeightFromCharacter(char32_t c) const;
|
||||||
u32 getGlyphIndexByChar(wchar_t c) const;
|
|
||||||
u32 getGlyphIndexByChar(char32_t c) const;
|
u32 getGlyphIndexByChar(char32_t c) const;
|
||||||
core::vector2di getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const;
|
|
||||||
core::vector2di getKerning(const char32_t thisLetter, const char32_t previousLetter) const;
|
core::vector2di getKerning(const char32_t thisLetter, const char32_t previousLetter) const;
|
||||||
core::dimension2d<u32> getDimensionUntilEndOfLine(const wchar_t* p) const;
|
|
||||||
|
|
||||||
void createSharedPlane();
|
|
||||||
|
|
||||||
irr::IrrlichtDevice* Device;
|
|
||||||
gui::IGUIEnvironment* Environment;
|
|
||||||
video::IVideoDriver* Driver;
|
video::IVideoDriver* Driver;
|
||||||
io::path filename;
|
io::path filename;
|
||||||
FT_Face tt_face;
|
FT_Face tt_face;
|
||||||
|
|
|
@ -74,7 +74,7 @@ void StaticText::draw()
|
||||||
updateText();
|
updateText();
|
||||||
|
|
||||||
core::rect<s32> r = frameRect;
|
core::rect<s32> r = frameRect;
|
||||||
s32 height_line = font->getDimension(L"A").Height + font->getKerningHeight();
|
s32 height_line = font->getDimension(L"A").Height + font->getKerning(L'A').Y;
|
||||||
s32 height_total = height_line * BrokenText.size();
|
s32 height_total = height_line * BrokenText.size();
|
||||||
if (VAlign == EGUIA_CENTER && WordWrap)
|
if (VAlign == EGUIA_CENTER && WordWrap)
|
||||||
{
|
{
|
||||||
|
@ -546,7 +546,7 @@ s32 StaticText::getTextHeight() const
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (WordWrap) {
|
if (WordWrap) {
|
||||||
s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
|
s32 height = font->getDimension(L"A").Height + font->getKerning(L'A').Y;
|
||||||
return height * BrokenText.size();
|
return height * BrokenText.size();
|
||||||
}
|
}
|
||||||
// There may be intentional new lines without WordWrap
|
// There may be intentional new lines without WordWrap
|
||||||
|
|
|
@ -88,12 +88,11 @@ void ItemStackMetadata::deSerialize(std::istream &is)
|
||||||
void ItemStackMetadata::updateToolCapabilities()
|
void ItemStackMetadata::updateToolCapabilities()
|
||||||
{
|
{
|
||||||
if (contains(TOOLCAP_KEY)) {
|
if (contains(TOOLCAP_KEY)) {
|
||||||
toolcaps_overridden = true;
|
|
||||||
toolcaps_override = ToolCapabilities();
|
toolcaps_override = ToolCapabilities();
|
||||||
std::istringstream is(getString(TOOLCAP_KEY));
|
std::istringstream is(getString(TOOLCAP_KEY));
|
||||||
toolcaps_override.deserializeJson(is);
|
toolcaps_override->deserializeJson(is);
|
||||||
} else {
|
} else {
|
||||||
toolcaps_overridden = false;
|
toolcaps_override = std::nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,7 @@ class IItemDefManager;
|
||||||
class ItemStackMetadata : public SimpleMetadata
|
class ItemStackMetadata : public SimpleMetadata
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ItemStackMetadata():
|
ItemStackMetadata()
|
||||||
toolcaps_overridden(false)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// Overrides
|
// Overrides
|
||||||
|
@ -29,7 +28,7 @@ public:
|
||||||
const ToolCapabilities &getToolCapabilities(
|
const ToolCapabilities &getToolCapabilities(
|
||||||
const ToolCapabilities &default_caps) const
|
const ToolCapabilities &default_caps) const
|
||||||
{
|
{
|
||||||
return toolcaps_overridden ? toolcaps_override : default_caps;
|
return toolcaps_override.has_value() ? *toolcaps_override : default_caps;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setToolCapabilities(const ToolCapabilities &caps);
|
void setToolCapabilities(const ToolCapabilities &caps);
|
||||||
|
@ -40,7 +39,6 @@ public:
|
||||||
return wear_bar_override;
|
return wear_bar_override;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void setWearBarParams(const WearBarParams ¶ms);
|
void setWearBarParams(const WearBarParams ¶ms);
|
||||||
void clearWearBarParams();
|
void clearWearBarParams();
|
||||||
|
|
||||||
|
@ -48,7 +46,6 @@ private:
|
||||||
void updateToolCapabilities();
|
void updateToolCapabilities();
|
||||||
void updateWearBarParams();
|
void updateWearBarParams();
|
||||||
|
|
||||||
bool toolcaps_overridden;
|
std::optional<ToolCapabilities> toolcaps_override;
|
||||||
ToolCapabilities toolcaps_override;
|
|
||||||
std::optional<WearBarParams> wear_bar_override;
|
std::optional<WearBarParams> wear_bar_override;
|
||||||
};
|
};
|
||||||
|
|
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