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"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Irrlicht device
|
||||
description:
|
||||
placeholder: "Example: X11"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
attributes:
|
||||
label: Operating system and version
|
||||
|
@ -69,7 +62,7 @@ body:
|
|||
attributes:
|
||||
label: Active renderer
|
||||
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:
|
||||
required: false
|
||||
- type: textarea
|
||||
|
|
|
@ -32,6 +32,27 @@ local function get_credits()
|
|||
return json
|
||||
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 {
|
||||
name = "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/]" ..
|
||||
"hypertext[5.5,0.25;9.75,6.6;credits;" .. core.formspec_escape(hypertext) .. "]"
|
||||
|
||||
-- Render information
|
||||
local active_renderer_info = fgettext("Active renderer:") .. " " ..
|
||||
core.formspec_escape(core.get_active_renderer())
|
||||
local active_renderer_info = fgettext("Active renderer:") .. "\n" ..
|
||||
core.formspec_escape(get_renderer_info())
|
||||
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 .. "]"
|
||||
|
||||
-- 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
|
||||
fs = fs .. "button[0.5,5.1;4.5,0.8;share_debug;" .. fgettext("Share debug log") .. "]"
|
||||
else
|
||||
|
|
|
@ -112,6 +112,7 @@ local function get_formspec(tabview, name, tabdata)
|
|||
local retval =
|
||||
-- Search
|
||||
"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]" ..
|
||||
"container[7.25,0.25]" ..
|
||||
"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)
|
||||
menudata.search_result = nil
|
||||
if #serverlistmgr.servers < 2 then
|
||||
return
|
||||
end
|
||||
|
||||
-- setup the keyword list
|
||||
local keywords = {}
|
||||
for word in input:gmatch("%S+") do
|
||||
table.insert(keywords, word:lower())
|
||||
end
|
||||
|
||||
if #keywords == 0 then
|
||||
-- setup the search query
|
||||
local query = parse_search_input(input)
|
||||
if not query then
|
||||
return
|
||||
end
|
||||
|
||||
|
@ -292,16 +380,9 @@ local function search_server_list(input)
|
|||
-- Search the serverlist
|
||||
local search_result = {}
|
||||
for i, server in ipairs(serverlistmgr.servers) do
|
||||
local name_matches, description_matches = true, true
|
||||
for _, keyword in ipairs(keywords) do
|
||||
name_matches = name_matches and not not
|
||||
(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)
|
||||
local match = matches_query(server, query)
|
||||
if match then
|
||||
server.points = #serverlistmgr.servers - i + match
|
||||
table.insert(search_result, server)
|
||||
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
|
||||
tabdata.search_for = fields.te_search
|
||||
search_server_list(fields.te_search:lower())
|
||||
search_server_list(fields.te_search)
|
||||
if menudata.search_result then
|
||||
-- Note: This clears the selection if there are no results
|
||||
set_selected_server(menudata.search_result[1])
|
||||
|
|
|
@ -406,6 +406,7 @@ bilinear_filter (Bilinear filtering) bool false
|
|||
trilinear_filter (Trilinear filtering) bool false
|
||||
|
||||
# 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
|
||||
|
||||
# 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.
|
||||
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
|
||||
# False = 128
|
||||
# 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!
|
||||
autoscale_mode (Autoscaling mode) enum disable disable,enable,force
|
||||
|
||||
# When using bilinear/trilinear/anisotropic filters, low-resolution textures
|
||||
# can be blurred, so automatically upscale them with nearest-neighbor
|
||||
# interpolation to preserve crisp pixels. This sets the minimum texture size
|
||||
# for the upscaled textures; higher values look sharper, but require more
|
||||
# memory. Powers of 2 are recommended. This setting is ONLY applied if
|
||||
# bilinear/trilinear/anisotropic filtering is enabled.
|
||||
# When using bilinear/trilinear filtering, low-resolution textures
|
||||
# can be blurred, so this option automatically upscales them to preserve
|
||||
# crisp pixels. This defines the minimum texture size for the upscaled textures;
|
||||
# higher values look sharper, but require more memory.
|
||||
# This setting is ONLY applied if any of the mentioned filters are enabled.
|
||||
# This is also used as the base node texture size for world-aligned
|
||||
# texture autoscaling.
|
||||
texture_min_size (Base texture size) int 64 1 32768
|
||||
|
|
|
@ -9,6 +9,7 @@ attribute vec2 inTexCoord0;
|
|||
/* Uniforms */
|
||||
|
||||
uniform float uThickness;
|
||||
uniform mat4 uProjection;
|
||||
|
||||
/* Varyings */
|
||||
|
||||
|
@ -17,7 +18,7 @@ varying vec4 vVertexColor;
|
|||
|
||||
void main()
|
||||
{
|
||||
gl_Position = inVertexPosition;
|
||||
gl_Position = uProjection * inVertexPosition;
|
||||
gl_PointSize = uThickness;
|
||||
vTextureCoord = inTexCoord0;
|
||||
vVertexColor = inVertexColor.bgra;
|
||||
|
|
|
@ -23,7 +23,12 @@ void main(void)
|
|||
vec2 uv = varTexCoord.st;
|
||||
vec3 color = texture2D(rendered, uv).rgb;
|
||||
// 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));
|
||||
#else
|
||||
color = pow(color, vec3(2.2));
|
||||
#endif
|
||||
|
||||
color *= exposureParams.compensationFactor * bloomStrength;
|
||||
|
||||
|
|
|
@ -43,11 +43,14 @@ varying vec3 vPosition;
|
|||
// cameraOffset + worldPosition (for large coordinates the limits of float
|
||||
// precision must be considered).
|
||||
varying vec3 worldPosition;
|
||||
varying lowp vec4 varColor;
|
||||
#ifdef GL_ES
|
||||
varying lowp vec4 varColor;
|
||||
varying mediump vec2 varTexCoord;
|
||||
varying float nightRatio;
|
||||
#else
|
||||
centroid varying lowp vec4 varColor;
|
||||
centroid varying vec2 varTexCoord;
|
||||
centroid varying float nightRatio;
|
||||
#endif
|
||||
varying highp vec3 eyeVec;
|
||||
varying float nightRatio;
|
||||
|
|
|
@ -14,14 +14,17 @@ varying vec3 vPosition;
|
|||
// cameraOffset + worldPosition (for large coordinates the limits of float
|
||||
// precision must be considered).
|
||||
varying vec3 worldPosition;
|
||||
varying lowp vec4 varColor;
|
||||
// The centroid keyword ensures that after interpolation the texture coordinates
|
||||
// lie within the same bounds when MSAA is en- and disabled.
|
||||
// This fixes the stripes problem with nearest-neighbor textures and MSAA.
|
||||
#ifdef GL_ES
|
||||
varying lowp vec4 varColor;
|
||||
varying mediump vec2 varTexCoord;
|
||||
varying float nightRatio;
|
||||
#else
|
||||
centroid varying lowp vec4 varColor;
|
||||
centroid varying vec2 varTexCoord;
|
||||
centroid varying float nightRatio;
|
||||
#endif
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
// shadow uniforms
|
||||
|
@ -47,6 +50,7 @@ varying highp vec3 eyeVec;
|
|||
varying float nightRatio;
|
||||
varying vec3 sunTint;
|
||||
varying float nightFactor;
|
||||
|
||||
// Color of the light emitted by the light sources.
|
||||
uniform vec3 artificialLight;
|
||||
const float e = 2.718281828459;
|
||||
|
|
|
@ -188,7 +188,6 @@ Mod directory structure
|
|||
│ ├── models
|
||||
│ ├── textures
|
||||
│ │ ├── modname_stuff.png
|
||||
│ │ ├── modname_stuff_normal.png
|
||||
│ │ ├── modname_something_else.png
|
||||
│ │ ├── subfolder_foo
|
||||
│ │ │ ├── modname_more_stuff.png
|
||||
|
@ -318,7 +317,7 @@ Many glTF features are not supported *yet*, including:
|
|||
|
||||
* Animations
|
||||
* Only a single animation is supported, use frame ranges within this animation.
|
||||
* Only linear interpolation is supported.
|
||||
* `CUBICSPLINE` interpolation is not supported.
|
||||
* Cameras
|
||||
* Materials
|
||||
* Only base color textures are supported
|
||||
|
|
|
@ -55,6 +55,20 @@ core.register_entity("gltf:simple_skin", {
|
|||
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:
|
||||
-- They use an unsupported double-sided material.
|
||||
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
|
||||
SIndexBuffer *Indices;
|
||||
//! Bounding box of this meshbuffer.
|
||||
core::aabbox3d<f32> BoundingBox;
|
||||
core::aabbox3d<f32> BoundingBox{{0, 0, 0}};
|
||||
//! Primitive type used for rendering (triangles, lines, ...)
|
||||
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
|
||||
|
||||
#include "EShaderTypes.h"
|
||||
#include "EMaterialTypes.h"
|
||||
#include "EPrimitiveTypes.h"
|
||||
#include "path.h"
|
||||
|
@ -31,26 +30,15 @@ public:
|
|||
virtual ~IGPUProgrammingServices() {}
|
||||
|
||||
//! 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
|
||||
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
|
||||
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
|
||||
geometry shader program. This can be 0 if no geometry shader shall be
|
||||
used.
|
||||
\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 shaderName Name of the shader for debug purposes
|
||||
\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
|
||||
|
@ -73,108 +61,43 @@ public:
|
|||
error log and can be caught with a custom event receiver. */
|
||||
virtual s32 addHighLevelShaderMaterial(
|
||||
const c8 *vertexShaderProgram,
|
||||
const c8 *vertexShaderEntryPointName,
|
||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
||||
const c8 *pixelShaderProgram,
|
||||
const c8 *pixelShaderEntryPointName,
|
||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
||||
const c8 *geometryShaderProgram,
|
||||
const c8 *geometryShaderEntryPointName = "main",
|
||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
|
||||
const c8 *shaderName = nullptr,
|
||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||
u32 verticesOut = 0,
|
||||
IShaderConstantSetCallBack *callback = 0,
|
||||
IShaderConstantSetCallBack *callback = nullptr,
|
||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||
s32 userData = 0) = 0;
|
||||
|
||||
//! convenience function for use without geometry shaders
|
||||
s32 addHighLevelShaderMaterial(
|
||||
const c8 *vertexShaderProgram,
|
||||
const c8 *vertexShaderEntryPointName = "main",
|
||||
E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1,
|
||||
const c8 *pixelShaderProgram = 0,
|
||||
const c8 *pixelShaderEntryPointName = "main",
|
||||
E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1,
|
||||
IShaderConstantSetCallBack *callback = 0,
|
||||
const c8 *pixelShaderProgram = nullptr,
|
||||
const c8 *shaderName = nullptr,
|
||||
IShaderConstantSetCallBack *callback = nullptr,
|
||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||
s32 userData = 0)
|
||||
{
|
||||
return addHighLevelShaderMaterial(
|
||||
vertexShaderProgram, vertexShaderEntryPointName,
|
||||
vsCompileTarget, pixelShaderProgram,
|
||||
pixelShaderEntryPointName, psCompileTarget,
|
||||
0, "main", EGST_GS_4_0,
|
||||
vertexShaderProgram, pixelShaderProgram,
|
||||
nullptr, shaderName,
|
||||
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 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.
|
||||
/** \param vertexShaderProgramFileName Text file containing the source
|
||||
of the vertex shader program. Set to empty string if no vertex shader
|
||||
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
|
||||
the pixel shader program. Set to empty string 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 geometryShaderProgramFileName Name of the source of
|
||||
the geometry shader program. Set to empty string 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 shaderName Name of the shader for debug purposes
|
||||
\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
|
||||
|
@ -197,164 +120,16 @@ public:
|
|||
error log and can be caught with a custom event receiver. */
|
||||
virtual s32 addHighLevelShaderMaterialFromFiles(
|
||||
const io::path &vertexShaderProgramFileName,
|
||||
const c8 *vertexShaderEntryPointName,
|
||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
||||
const io::path &pixelShaderProgramFileName,
|
||||
const c8 *pixelShaderEntryPointName,
|
||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
||||
const io::path &geometryShaderProgramFileName,
|
||||
const c8 *geometryShaderEntryPointName = "main",
|
||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
|
||||
const c8 *shaderName = nullptr,
|
||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||
u32 verticesOut = 0,
|
||||
IShaderConstantSetCallBack *callback = 0,
|
||||
IShaderConstantSetCallBack *callback = nullptr,
|
||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||
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.
|
||||
/**
|
||||
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.
|
||||
/** \return Returns width and height of the area covered by the text if
|
||||
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.
|
||||
/** \param text: Text string.
|
||||
|
@ -82,10 +82,7 @@ public:
|
|||
which supports kerning pairs a string such as 'Wo' may have the 'o'
|
||||
tucked neatly under the 'W'.
|
||||
*/
|
||||
virtual s32 getKerningWidth(const wchar_t *thisLetter = 0, const wchar_t *previousLetter = 0) const = 0;
|
||||
|
||||
//! Returns the distance between letters
|
||||
virtual s32 getKerningHeight() const = 0;
|
||||
virtual core::vector2di getKerning(const wchar_t thisLetter = 0, const wchar_t previousLetter = 0) const = 0;
|
||||
|
||||
//! Define which characters should not be drawn by the font.
|
||||
/** 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
|
||||
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
|
||||
|
|
|
@ -108,7 +108,7 @@ public:
|
|||
if (!mesh)
|
||||
return true;
|
||||
bool result = true;
|
||||
core::aabbox3df bufferbox;
|
||||
core::aabbox3df bufferbox{{0, 0, 0}};
|
||||
for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
|
||||
result &= apply(func, mesh->getMeshBuffer(i), boundingBoxUpdate);
|
||||
if (boundingBoxUpdate) {
|
||||
|
@ -136,7 +136,7 @@ protected:
|
|||
if (!buffer)
|
||||
return true;
|
||||
|
||||
core::aabbox3df bufferbox;
|
||||
core::aabbox3df bufferbox{{0, 0, 0}};
|
||||
for (u32 i = 0; i < buffer->getVertexCount(); ++i) {
|
||||
switch (buffer->getVertexType()) {
|
||||
case video::EVT_STANDARD: {
|
||||
|
|
|
@ -61,8 +61,8 @@ struct SFrameStats {
|
|||
u32 PrimitivesDrawn = 0;
|
||||
//! Number of hardware buffers uploaded (new or updated)
|
||||
u32 HWBuffersUploaded = 0;
|
||||
//! Sum of uploaded hardware buffer size
|
||||
u32 HWBuffersUploadedSize = 0;
|
||||
//! Number of active hardware buffers
|
||||
u32 HWBuffersActive = 0;
|
||||
};
|
||||
|
||||
//! Interface to driver which is able to perform 2d and 3d graphics functions.
|
||||
|
@ -310,6 +310,18 @@ public:
|
|||
0 or another texture first. */
|
||||
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
|
||||
virtual void removeHardwareBuffer(const scene::IVertexBuffer *vb) = 0;
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ struct SAnimatedMesh final : public IAnimatedMesh
|
|||
std::vector<IMesh *> Meshes;
|
||||
|
||||
//! 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.
|
||||
f32 FramesPerSecond;
|
||||
|
|
|
@ -133,7 +133,7 @@ struct SMesh final : public IMesh
|
|||
std::vector<u32> TextureSlots;
|
||||
|
||||
//! The bounding box of this mesh
|
||||
core::aabbox3d<f32> BoundingBox;
|
||||
core::aabbox3d<f32> BoundingBox{{0, 0, 0}};
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
|
|
|
@ -228,7 +228,7 @@ public:
|
|||
video::SMaterial Material;
|
||||
video::E_VERTEX_TYPE VertexType;
|
||||
|
||||
core::aabbox3d<f32> BoundingBox;
|
||||
core::aabbox3d<f32> BoundingBox{{0, 0, 0}};
|
||||
|
||||
//! Primitive type used for rendering (triangles, lines, ...)
|
||||
E_PRIMITIVE_TYPE PrimitiveType;
|
||||
|
|
|
@ -117,7 +117,7 @@ struct SViewFrustum
|
|||
core::plane3d<f32> planes[VF_PLANE_COUNT];
|
||||
|
||||
//! bounding box around the view frustum
|
||||
core::aabbox3d<f32> boundingBox;
|
||||
core::aabbox3d<f32> boundingBox{{0, 0, 0}};
|
||||
|
||||
private:
|
||||
//! Hold a copy of important transform matrices
|
||||
|
|
|
@ -137,7 +137,7 @@ public:
|
|||
//! Moves the mesh into static position.
|
||||
void resetAnimation();
|
||||
|
||||
virtual void updateBoundingBox();
|
||||
void updateBoundingBox();
|
||||
|
||||
//! Recovers the joints from the mesh
|
||||
void recoverJointsFromMesh(std::vector<IBoneSceneNode *> &jointChildSceneNodes);
|
||||
|
@ -370,7 +370,7 @@ protected:
|
|||
// doesn't allow taking a reference to individual elements.
|
||||
std::vector<std::vector<char>> Vertices_Moved;
|
||||
|
||||
core::aabbox3d<f32> BoundingBox;
|
||||
core::aabbox3d<f32> BoundingBox{{0, 0, 0}};
|
||||
|
||||
f32 EndFrame;
|
||||
f32 FramesPerSecond;
|
||||
|
|
|
@ -20,9 +20,7 @@ template <class T>
|
|||
class aabbox3d
|
||||
{
|
||||
public:
|
||||
//! Default Constructor.
|
||||
constexpr aabbox3d() :
|
||||
MinEdge(-1, -1, -1), MaxEdge(1, 1, 1) {}
|
||||
constexpr aabbox3d() = delete;
|
||||
//! Constructor with min edge and max edge.
|
||||
constexpr aabbox3d(const vector3d<T> &min, const vector3d<T> &max) :
|
||||
MinEdge(min), MaxEdge(max) {}
|
||||
|
|
|
@ -145,7 +145,7 @@ private:
|
|||
void beginTransition();
|
||||
|
||||
core::array<video::SMaterial> Materials;
|
||||
core::aabbox3d<f32> Box;
|
||||
core::aabbox3d<f32> Box{{0.0f, 0.0f, 0.0f}};
|
||||
IAnimatedMesh *Mesh;
|
||||
|
||||
f32 StartFrame;
|
||||
|
|
|
@ -104,7 +104,7 @@ private:
|
|||
/** 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
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -60,7 +60,7 @@ private:
|
|||
|
||||
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_SKINNING_SPACE SkinningSpace;
|
||||
|
|
|
@ -48,7 +48,7 @@ private:
|
|||
void setPosition(const core::vector3df &newpos) override;
|
||||
|
||||
core::matrix4 RelativeTransformationMatrix;
|
||||
core::aabbox3d<f32> Box;
|
||||
core::aabbox3d<f32> Box{{0, 0, 0}};
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
ISceneNode *clone(ISceneNode *newParent = 0, ISceneManager *newManager = 0) override;
|
||||
|
||||
private:
|
||||
core::aabbox3d<f32> Box;
|
||||
core::aabbox3d<f32> Box{{0, 0, 0}};
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
|
|
|
@ -677,8 +677,17 @@ void SelfType::MeshExtractor::loadAnimation(const std::size_t animIdx)
|
|||
for (const auto &channel : anim.channels) {
|
||||
|
||||
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 n_frames = inputAccessor.getCount();
|
||||
|
@ -686,32 +695,38 @@ void SelfType::MeshExtractor::loadAnimation(const std::size_t animIdx)
|
|||
if (!channel.target.node.has_value())
|
||||
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) {
|
||||
case tiniergltf::AnimationChannelTarget::Path::TRANSLATION: {
|
||||
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) {
|
||||
f32 frame = inputAccessor.get(i);
|
||||
core::vector3df position = outputAccessor.get(i);
|
||||
m_irr_model->addPositionKey(joint, frame, convertHandedness(position));
|
||||
channel.pushBack(frame, convertHandedness(position));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tiniergltf::AnimationChannelTarget::Path::ROTATION: {
|
||||
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) {
|
||||
f32 frame = inputAccessor.get(i);
|
||||
core::quaternion rotation = outputAccessor.get(i);
|
||||
m_irr_model->addRotationKey(joint, frame, convertHandedness(rotation));
|
||||
channel.pushBack(frame, convertHandedness(rotation));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tiniergltf::AnimationChannelTarget::Path::SCALE: {
|
||||
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) {
|
||||
f32 frame = inputAccessor.get(i);
|
||||
core::vector3df scale = outputAccessor.get(i);
|
||||
m_irr_model->addScaleKey(joint, frame, scale);
|
||||
channel.pushBack(frame, scale);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -788,9 +788,9 @@ void CGUIEditBox::draw()
|
|||
mbegin = font->getDimension(s.c_str()).Width;
|
||||
|
||||
// deal with kerning
|
||||
mbegin += font->getKerningWidth(
|
||||
&((*txtLine)[realmbgn - startPos]),
|
||||
realmbgn - startPos > 0 ? &((*txtLine)[realmbgn - startPos - 1]) : 0);
|
||||
mbegin += font->getKerning(
|
||||
(*txtLine)[realmbgn - startPos],
|
||||
realmbgn - startPos > 0 ? (*txtLine)[realmbgn - startPos - 1] : 0).X;
|
||||
|
||||
lineStartPos = realmbgn - startPos;
|
||||
}
|
||||
|
@ -832,7 +832,8 @@ void CGUIEditBox::draw()
|
|||
}
|
||||
s = txtLine->subString(0, CursorPos - startPos);
|
||||
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)) {
|
||||
setTextRect(cursorLine);
|
||||
|
@ -1194,7 +1195,7 @@ void CGUIEditBox::setTextRect(s32 line)
|
|||
d = font->getDimension(Text.c_str());
|
||||
d.Height = AbsoluteRect.getHeight();
|
||||
}
|
||||
d.Height += font->getKerningHeight();
|
||||
d.Height += font->getKerning(L'A').Y;
|
||||
|
||||
// justification
|
||||
switch (HAlign) {
|
||||
|
@ -1382,7 +1383,7 @@ void CGUIEditBox::calculateScrollPos()
|
|||
|
||||
// calculate vertical scrolling
|
||||
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?
|
||||
if (lineHeight >= (irr::u32)FrameRect.getHeight()) {
|
||||
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()
|
||||
{
|
||||
if (!SpriteBank)
|
||||
|
@ -365,17 +230,15 @@ void CGUIFont::setKerningWidth(s32 kerning)
|
|||
GlobalKerningWidth = kerning;
|
||||
}
|
||||
|
||||
//! set an Pixel Offset on Drawing ( scale position on width )
|
||||
s32 CGUIFont::getKerningWidth(const wchar_t *thisLetter, const wchar_t *previousLetter) const
|
||||
core::vector2di CGUIFont::getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const
|
||||
{
|
||||
s32 ret = GlobalKerningWidth;
|
||||
core::vector2di ret(GlobalKerningWidth, GlobalKerningHeight);
|
||||
|
||||
if (thisLetter) {
|
||||
ret += Areas[getAreaFromCharacter(*thisLetter)].overhang;
|
||||
ret.X += Areas[getAreaFromCharacter(thisLetter)].overhang;
|
||||
|
||||
if (previousLetter) {
|
||||
ret += Areas[getAreaFromCharacter(*previousLetter)].underhang;
|
||||
}
|
||||
if (previousLetter)
|
||||
ret.X += Areas[getAreaFromCharacter(previousLetter)].underhang;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -387,12 +250,6 @@ void CGUIFont::setKerningHeight(s32 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
|
||||
u32 CGUIFont::getSpriteNoFromChar(const wchar_t *c) const
|
||||
{
|
||||
|
|
|
@ -58,8 +58,7 @@ public:
|
|||
void setKerningHeight(s32 kerning) override;
|
||||
|
||||
//! set an Pixel Offset on Drawing ( scale position on width )
|
||||
s32 getKerningWidth(const wchar_t *thisLetter = 0, const wchar_t *previousLetter = 0) const override;
|
||||
s32 getKerningHeight() const override;
|
||||
core::vector2di getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const override;
|
||||
|
||||
//! gets the sprite bank
|
||||
IGUISpriteBank *getSpriteBank() const override;
|
||||
|
|
|
@ -74,10 +74,12 @@ void CGUIStaticText::draw()
|
|||
IGUIFont *font = getActiveFont();
|
||||
|
||||
if (font) {
|
||||
s32 kerningHeight = font->getKerning(L'A').Y;
|
||||
|
||||
if (!WordWrap) {
|
||||
if (VAlign == EGUIA_LOWERRIGHT) {
|
||||
frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y -
|
||||
font->getDimension(L"A").Height - font->getKerningHeight();
|
||||
font->getDimension(L"A").Height - kerningHeight;
|
||||
}
|
||||
if (HAlign == EGUIA_LOWERRIGHT) {
|
||||
frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
|
||||
|
@ -92,7 +94,7 @@ void CGUIStaticText::draw()
|
|||
breakText();
|
||||
|
||||
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();
|
||||
if (VAlign == EGUIA_CENTER) {
|
||||
r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
|
||||
|
@ -471,7 +473,7 @@ s32 CGUIStaticText::getTextHeight() const
|
|||
return 0;
|
||||
|
||||
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();
|
||||
} else {
|
||||
// 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/MaterialRenderer.cpp
|
||||
OpenGL/Renderer2D.cpp
|
||||
OpenGL/VBO.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ protected:
|
|||
void copyMaterials();
|
||||
|
||||
core::array<video::SMaterial> Materials;
|
||||
core::aabbox3d<f32> Box;
|
||||
core::aabbox3d<f32> Box{{0, 0, 0}};
|
||||
video::SMaterial ReadOnlyMaterial;
|
||||
|
||||
IMesh *Mesh;
|
||||
|
|
|
@ -218,7 +218,7 @@ bool CNullDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u
|
|||
bool CNullDriver::endScene()
|
||||
{
|
||||
FPSCounter.registerFrame(os::Timer::getRealTime());
|
||||
updateAllHardwareBuffers();
|
||||
expireHardwareBuffers();
|
||||
updateAllOcclusionQueries();
|
||||
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
|
||||
}
|
||||
|
||||
//! Update all hardware buffers, remove unused ones
|
||||
void CNullDriver::updateAllHardwareBuffers()
|
||||
void CNullDriver::registerHardwareBuffer(SHWBufferLink *HWBuffer)
|
||||
{
|
||||
auto it = HWBufferList.begin();
|
||||
while (it != HWBufferList.end()) {
|
||||
SHWBufferLink *Link = *it;
|
||||
++it;
|
||||
_IRR_DEBUG_BREAK_IF(!HWBuffer)
|
||||
HWBuffer->ListPosition = HWBufferList.size();
|
||||
HWBufferList.push_back(HWBuffer);
|
||||
}
|
||||
|
||||
if (Link->IsVertex) {
|
||||
if (!Link->VertexBuffer || Link->VertexBuffer->getReferenceCount() == 1)
|
||||
deleteHardwareBuffer(Link);
|
||||
} else {
|
||||
if (!Link->IndexBuffer || Link->IndexBuffer->getReferenceCount() == 1)
|
||||
void CNullDriver::expireHardwareBuffers()
|
||||
{
|
||||
for (size_t i = 0; i < HWBufferList.size(); ) {
|
||||
auto *Link = HWBufferList[i];
|
||||
|
||||
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)
|
||||
{
|
||||
if (!HWBuffer)
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!vb)
|
||||
|
@ -1484,34 +1520,24 @@ IGPUProgrammingServices *CNullDriver::getGPUProgrammingServices()
|
|||
//! Adds a new material renderer to the VideoDriver, based on a high level shading language.
|
||||
s32 CNullDriver::addHighLevelShaderMaterial(
|
||||
const c8 *vertexShaderProgram,
|
||||
const c8 *vertexShaderEntryPointName,
|
||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
||||
const c8 *pixelShaderProgram,
|
||||
const c8 *pixelShaderEntryPointName,
|
||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
||||
const c8 *geometryShaderProgram,
|
||||
const c8 *geometryShaderEntryPointName,
|
||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
|
||||
const c8 *shaderName,
|
||||
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
|
||||
u32 verticesOut,
|
||||
IShaderConstantSetCallBack *callback,
|
||||
E_MATERIAL_TYPE baseMaterial,
|
||||
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;
|
||||
}
|
||||
|
||||
s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
|
||||
const io::path &vertexShaderProgramFileName,
|
||||
const c8 *vertexShaderEntryPointName,
|
||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
||||
const io::path &pixelShaderProgramFileName,
|
||||
const c8 *pixelShaderEntryPointName,
|
||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
||||
const io::path &geometryShaderProgramFileName,
|
||||
const c8 *geometryShaderEntryPointName,
|
||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
|
||||
const c8 *shaderName,
|
||||
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
|
||||
u32 verticesOut,
|
||||
IShaderConstantSetCallBack *callback,
|
||||
|
@ -1547,9 +1573,7 @@ s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
|
|||
}
|
||||
|
||||
s32 result = addHighLevelShaderMaterialFromFiles(
|
||||
vsfile, vertexShaderEntryPointName, vsCompileTarget,
|
||||
psfile, pixelShaderEntryPointName, psCompileTarget,
|
||||
gsfile, geometryShaderEntryPointName, gsCompileTarget,
|
||||
vsfile, psfile, gsfile, shaderName,
|
||||
inType, outType, verticesOut,
|
||||
callback, baseMaterial, userData);
|
||||
|
||||
|
@ -1567,14 +1591,9 @@ s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
|
|||
|
||||
s32 CNullDriver::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,
|
||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
|
||||
const c8 *shaderName,
|
||||
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
|
||||
u32 verticesOut,
|
||||
IShaderConstantSetCallBack *callback,
|
||||
|
@ -1620,9 +1639,7 @@ s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
|
|||
}
|
||||
|
||||
s32 result = this->addHighLevelShaderMaterial(
|
||||
vs, vertexShaderEntryPointName, vsCompileTarget,
|
||||
ps, pixelShaderEntryPointName, psCompileTarget,
|
||||
gs, geometryShaderEntryPointName, gsCompileTarget,
|
||||
vs, ps, gs, shaderName,
|
||||
inType, outType, verticesOut,
|
||||
callback, baseMaterial, userData);
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "S3DVertex.h"
|
||||
#include "SVertexIndex.h"
|
||||
#include "SExposedVideoData.h"
|
||||
#include <list>
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
@ -293,7 +292,7 @@ protected:
|
|||
struct SHWBufferLink
|
||||
{
|
||||
SHWBufferLink(const scene::IVertexBuffer *vb) :
|
||||
VertexBuffer(vb), ChangedID(0), IsVertex(true)
|
||||
VertexBuffer(vb), IsVertex(true)
|
||||
{
|
||||
if (VertexBuffer) {
|
||||
VertexBuffer->grab();
|
||||
|
@ -301,7 +300,7 @@ protected:
|
|||
}
|
||||
}
|
||||
SHWBufferLink(const scene::IIndexBuffer *ib) :
|
||||
IndexBuffer(ib), ChangedID(0), IsVertex(false)
|
||||
IndexBuffer(ib), IsVertex(false)
|
||||
{
|
||||
if (IndexBuffer) {
|
||||
IndexBuffer->grab();
|
||||
|
@ -324,9 +323,9 @@ protected:
|
|||
const scene::IVertexBuffer *VertexBuffer;
|
||||
const scene::IIndexBuffer *IndexBuffer;
|
||||
};
|
||||
u32 ChangedID;
|
||||
size_t ListPosition = static_cast<size_t>(-1);
|
||||
u32 ChangedID = 0;
|
||||
bool IsVertex;
|
||||
std::list<SHWBufferLink*>::iterator listPosition;
|
||||
};
|
||||
|
||||
//! 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; }
|
||||
|
||||
public:
|
||||
virtual void updateHardwareBuffer(const scene::IVertexBuffer *vb) override;
|
||||
|
||||
virtual void updateHardwareBuffer(const scene::IIndexBuffer *ib) override;
|
||||
|
||||
//! Remove hardware buffer
|
||||
void removeHardwareBuffer(const scene::IVertexBuffer *vb) override;
|
||||
|
||||
|
@ -357,8 +360,8 @@ public:
|
|||
//! Remove all hardware buffers
|
||||
void removeAllHardwareBuffers() override;
|
||||
|
||||
//! Update all hardware buffers, remove unused ones
|
||||
virtual void updateAllHardwareBuffers();
|
||||
//! Run garbage-collection on all HW buffers
|
||||
void expireHardwareBuffers();
|
||||
|
||||
//! is vbo recommended?
|
||||
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.
|
||||
virtual s32 addHighLevelShaderMaterial(
|
||||
const c8 *vertexShaderProgram,
|
||||
const c8 *vertexShaderEntryPointName = 0,
|
||||
E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1,
|
||||
const c8 *pixelShaderProgram = 0,
|
||||
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,
|
||||
const c8 *pixelShaderProgram,
|
||||
const c8 *geometryShaderProgram,
|
||||
const c8 *shaderName = nullptr,
|
||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||
u32 verticesOut = 0,
|
||||
IShaderConstantSetCallBack *callback = 0,
|
||||
IShaderConstantSetCallBack *callback = nullptr,
|
||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||
s32 userData = 0) override;
|
||||
s32 userData = 0)override;
|
||||
|
||||
virtual s32 addHighLevelShaderMaterialFromFiles(
|
||||
const io::path &vertexShaderProgramFile,
|
||||
const c8 *vertexShaderEntryPointName = "main",
|
||||
E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1,
|
||||
const io::path &pixelShaderProgramFile = "",
|
||||
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,
|
||||
const io::path &vertexShaderProgramFileName,
|
||||
const io::path &pixelShaderProgramFileName,
|
||||
const io::path &geometryShaderProgramFileName,
|
||||
const c8 *shaderName = nullptr,
|
||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||
u32 verticesOut = 0,
|
||||
IShaderConstantSetCallBack *callback = 0,
|
||||
IShaderConstantSetCallBack *callback = nullptr,
|
||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||
s32 userData = 0) override;
|
||||
|
||||
virtual s32 addHighLevelShaderMaterialFromFiles(
|
||||
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,
|
||||
io::IReadFile *geometryShaderProgram = 0,
|
||||
const c8 *geometryShaderEntryPointName = "main",
|
||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
|
||||
const c8 *shaderName = nullptr,
|
||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||
u32 verticesOut = 0,
|
||||
IShaderConstantSetCallBack *callback = 0,
|
||||
IShaderConstantSetCallBack *callback = nullptr,
|
||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||
s32 userData = 0) override;
|
||||
s32 userData = 0);
|
||||
|
||||
virtual void deleteShaderMaterial(s32 material) override;
|
||||
|
||||
|
@ -578,13 +566,16 @@ protected:
|
|||
//! deletes all material renderers
|
||||
void deleteMaterialRenders();
|
||||
|
||||
// adds a created hardware buffer to the relevant data structure
|
||||
void registerHardwareBuffer(SHWBufferLink *HWBuffer);
|
||||
|
||||
// prints renderer version
|
||||
void printVersion();
|
||||
|
||||
inline void accountHWBufferUpload(u32 size)
|
||||
{
|
||||
FrameStats.HWBuffersUploaded++;
|
||||
FrameStats.HWBuffersUploadedSize += size;
|
||||
(void)size;
|
||||
}
|
||||
|
||||
inline bool getWriteZBuffer(const SMaterial &material) const
|
||||
|
@ -701,7 +692,7 @@ protected:
|
|||
core::array<video::IImageWriter *> SurfaceWriter;
|
||||
core::array<SMaterialRenderer> MaterialRenderers;
|
||||
|
||||
std::list<SHWBufferLink *> HWBufferList;
|
||||
std::vector<SHWBufferLink *> HWBufferList;
|
||||
|
||||
io::IFileSystem *FileSystem;
|
||||
|
||||
|
|
|
@ -430,9 +430,7 @@ COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::I
|
|||
return 0;
|
||||
|
||||
SHWBufferLink_opengl *HWBuffer = new SHWBufferLink_opengl(vb);
|
||||
|
||||
// add to map
|
||||
HWBuffer->listPosition = HWBufferList.insert(HWBufferList.end(), HWBuffer);
|
||||
registerHardwareBuffer(HWBuffer);
|
||||
|
||||
if (!updateVertexHardwareBuffer(HWBuffer)) {
|
||||
deleteHardwareBuffer(HWBuffer);
|
||||
|
@ -453,9 +451,7 @@ COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::I
|
|||
return 0;
|
||||
|
||||
SHWBufferLink_opengl *HWBuffer = new SHWBufferLink_opengl(ib);
|
||||
|
||||
// add to map
|
||||
HWBuffer->listPosition = HWBufferList.insert(HWBufferList.end(), HWBuffer);
|
||||
registerHardwareBuffer(HWBuffer);
|
||||
|
||||
if (!updateIndexHardwareBuffer(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.
|
||||
s32 COpenGLDriver::addHighLevelShaderMaterial(
|
||||
const c8 *vertexShaderProgram,
|
||||
const c8 *vertexShaderEntryPointName,
|
||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
||||
const c8 *pixelShaderProgram,
|
||||
const c8 *pixelShaderEntryPointName,
|
||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
||||
const c8 *geometryShaderProgram,
|
||||
const c8 *geometryShaderEntryPointName,
|
||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
|
||||
const c8 *shaderName,
|
||||
scene::E_PRIMITIVE_TYPE inType,
|
||||
scene::E_PRIMITIVE_TYPE outType,
|
||||
u32 verticesOut,
|
||||
|
@ -2677,9 +2668,9 @@ s32 COpenGLDriver::addHighLevelShaderMaterial(
|
|||
|
||||
COpenGLSLMaterialRenderer *r = new COpenGLSLMaterialRenderer(
|
||||
this, nr,
|
||||
vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget,
|
||||
pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget,
|
||||
geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget,
|
||||
vertexShaderProgram,
|
||||
pixelShaderProgram,
|
||||
geometryShaderProgram,
|
||||
inType, outType, verticesOut,
|
||||
callback, baseMaterial, userData);
|
||||
|
||||
|
|
|
@ -240,18 +240,13 @@ public:
|
|||
//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.
|
||||
virtual s32 addHighLevelShaderMaterial(
|
||||
const c8 *vertexShaderProgram,
|
||||
const c8 *vertexShaderEntryPointName,
|
||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
||||
const c8 *pixelShaderProgram,
|
||||
const c8 *pixelShaderEntryPointName,
|
||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
||||
const c8 *geometryShaderProgram,
|
||||
const c8 *geometryShaderEntryPointName = "main",
|
||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
|
||||
const c8 *shaderName = nullptr,
|
||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||
u32 verticesOut = 0,
|
||||
IShaderConstantSetCallBack *callback = 0,
|
||||
IShaderConstantSetCallBack *callback = nullptr,
|
||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||
s32 userData = 0) override;
|
||||
|
||||
|
|
|
@ -34,14 +34,8 @@ namespace video
|
|||
//! Constructor
|
||||
COpenGLSLMaterialRenderer::COpenGLSLMaterialRenderer(video::COpenGLDriver *driver,
|
||||
s32 &outMaterialTypeNr, const c8 *vertexShaderProgram,
|
||||
const c8 *vertexShaderEntryPointName,
|
||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
||||
const c8 *pixelShaderProgram,
|
||||
const c8 *pixelShaderEntryPointName,
|
||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
||||
const c8 *geometryShaderProgram,
|
||||
const c8 *geometryShaderEntryPointName,
|
||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
|
||||
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
|
||||
u32 verticesOut,
|
||||
IShaderConstantSetCallBack *callback,
|
||||
|
|
|
@ -33,14 +33,8 @@ public:
|
|||
COpenGLDriver *driver,
|
||||
s32 &outMaterialTypeNr,
|
||||
const c8 *vertexShaderProgram = 0,
|
||||
const c8 *vertexShaderEntryPointName = 0,
|
||||
E_VERTEX_SHADER_TYPE vsCompileTarget = video::EVST_VS_1_1,
|
||||
const c8 *pixelShaderProgram = 0,
|
||||
const c8 *pixelShaderEntryPointName = 0,
|
||||
E_PIXEL_SHADER_TYPE psCompileTarget = video::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 outType = scene::EPT_TRIANGLE_STRIP,
|
||||
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.
|
||||
|
||||
static const core::aabbox3d<f32> dummy;
|
||||
static const core::aabbox3d<f32> dummy{{0.0f, 0.0f, 0.0f}};
|
||||
return dummy;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@ typedef COpenGLCoreTexture<COpenGL3DriverBase> COpenGL3Texture;
|
|||
typedef COpenGLCoreRenderTarget<COpenGL3DriverBase, COpenGL3Texture> COpenGL3RenderTarget;
|
||||
typedef COpenGLCoreCacheHandler<COpenGL3DriverBase, COpenGL3Texture> COpenGL3CacheHandler;
|
||||
|
||||
class OpenGLVBO;
|
||||
|
||||
enum OpenGLSpec : u8
|
||||
{
|
||||
Core,
|
||||
|
|
|
@ -177,6 +177,8 @@ COpenGL3DriverBase::COpenGL3DriverBase(const SIrrlichtCreationParameters ¶ms
|
|||
|
||||
COpenGL3DriverBase::~COpenGL3DriverBase()
|
||||
{
|
||||
QuadIndexVBO.destroy();
|
||||
|
||||
deleteMaterialRenders();
|
||||
|
||||
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;
|
||||
std::vector<GLushort> QuadsIndices;
|
||||
QuadsIndices.reserve(6 * max_quad_count);
|
||||
for (int k = 0; k < max_quad_count; k++) {
|
||||
u32 max_quad_count = max_vertex_count / 4;
|
||||
u32 indices_size = 6 * max_quad_count;
|
||||
if (indices_size == QuadIndexVBO.getSize() * sizeof(u16))
|
||||
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 + 1);
|
||||
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 + 3);
|
||||
}
|
||||
GL.GenBuffers(1, &QuadIndexBuffer);
|
||||
GL.BindBuffer(GL_ARRAY_BUFFER, QuadIndexBuffer);
|
||||
GL.BufferData(GL_ARRAY_BUFFER, sizeof(QuadsIndices[0]) * QuadsIndices.size(), QuadsIndices.data(), GL_STATIC_DRAW);
|
||||
GL.BindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
QuadIndexCount = QuadsIndices.size();
|
||||
QuadIndexVBO.upload(QuadsIndices.data(), QuadsIndices.size() * sizeof(u16),
|
||||
0, GL_STATIC_DRAW, true);
|
||||
}
|
||||
|
||||
void COpenGL3DriverBase::initVersion()
|
||||
|
@ -383,28 +386,28 @@ void COpenGL3DriverBase::createMaterialRenderers()
|
|||
|
||||
// EMT_SOLID
|
||||
core::stringc FragmentShader = OGLES2ShaderPath + "Solid.fsh";
|
||||
addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
|
||||
EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, SolidCB, EMT_SOLID, 0);
|
||||
addHighLevelShaderMaterialFromFiles(VertexShader, FragmentShader, "", "Solid",
|
||||
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, SolidCB, EMT_SOLID, 0);
|
||||
|
||||
// EMT_TRANSPARENT_ALPHA_CHANNEL
|
||||
FragmentShader = OGLES2ShaderPath + "TransparentAlphaChannel.fsh";
|
||||
addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
|
||||
EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAlphaChannelCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0);
|
||||
addHighLevelShaderMaterialFromFiles(VertexShader, FragmentShader, "", "TransparentAlphaChannel",
|
||||
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAlphaChannelCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0);
|
||||
|
||||
// EMT_TRANSPARENT_ALPHA_CHANNEL_REF
|
||||
FragmentShader = OGLES2ShaderPath + "TransparentAlphaChannelRef.fsh";
|
||||
addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
|
||||
EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAlphaChannelRefCB, EMT_SOLID, 0);
|
||||
addHighLevelShaderMaterialFromFiles(VertexShader, FragmentShader, "", "TransparentAlphaChannelRef",
|
||||
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAlphaChannelRefCB, EMT_SOLID, 0);
|
||||
|
||||
// EMT_TRANSPARENT_VERTEX_ALPHA
|
||||
FragmentShader = OGLES2ShaderPath + "TransparentVertexAlpha.fsh";
|
||||
addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
|
||||
EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentVertexAlphaCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0);
|
||||
addHighLevelShaderMaterialFromFiles(VertexShader, FragmentShader, "", "TransparentVertexAlpha",
|
||||
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentVertexAlphaCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0);
|
||||
|
||||
// EMT_ONETEXTURE_BLEND
|
||||
FragmentShader = OGLES2ShaderPath + "OneTextureBlend.fsh";
|
||||
addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
|
||||
EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, OneTextureBlendCB, EMT_ONETEXTURE_BLEND, 0);
|
||||
addHighLevelShaderMaterialFromFiles(VertexShader, FragmentShader, "", "OneTextureBlend",
|
||||
scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, OneTextureBlendCB, EMT_ONETEXTURE_BLEND, 0);
|
||||
|
||||
// Drop callbacks.
|
||||
|
||||
|
@ -474,41 +477,18 @@ void COpenGL3DriverBase::setTransform(E_TRANSFORMATION_STATE state, const core::
|
|||
Transformation3DChanged = true;
|
||||
}
|
||||
|
||||
bool COpenGL3DriverBase::updateHardwareBuffer(SHWBufferLink_opengl *HWBuffer,
|
||||
bool COpenGL3DriverBase::uploadHardwareBuffer(OpenGLVBO &vbo,
|
||||
const void *buffer, size_t bufferSize, scene::E_HARDWARE_MAPPING hint)
|
||||
{
|
||||
assert(HWBuffer);
|
||||
|
||||
accountHWBufferUpload(bufferSize);
|
||||
|
||||
// get or create buffer
|
||||
bool newBuffer = false;
|
||||
if (!HWBuffer->vbo_ID) {
|
||||
GL.GenBuffers(1, &HWBuffer->vbo_ID);
|
||||
if (!HWBuffer->vbo_ID)
|
||||
return false;
|
||||
newBuffer = true;
|
||||
} else if (HWBuffer->vbo_Size < bufferSize) {
|
||||
newBuffer = true;
|
||||
}
|
||||
|
||||
GL.BindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_ID);
|
||||
|
||||
// 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);
|
||||
vbo.upload(buffer, bufferSize, 0, usage);
|
||||
|
||||
return (!TEST_GL_ERROR(this));
|
||||
}
|
||||
|
@ -525,7 +505,8 @@ bool COpenGL3DriverBase::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuff
|
|||
const u32 vertexSize = getVertexPitchFromType(vb->getType());
|
||||
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)
|
||||
|
@ -551,7 +532,8 @@ bool COpenGL3DriverBase::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffe
|
|||
|
||||
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)
|
||||
|
@ -563,14 +545,14 @@ bool COpenGL3DriverBase::updateHardwareBuffer(SHWBufferLink *HWBuffer)
|
|||
|
||||
if (b->IsVertex) {
|
||||
assert(b->VertexBuffer);
|
||||
if (b->ChangedID != b->VertexBuffer->getChangedID() || !b->vbo_ID) {
|
||||
if (b->ChangedID != b->VertexBuffer->getChangedID() || !b->Vbo.exists()) {
|
||||
if (!updateVertexHardwareBuffer(b))
|
||||
return false;
|
||||
b->ChangedID = b->VertexBuffer->getChangedID();
|
||||
}
|
||||
} else {
|
||||
assert(b->IndexBuffer);
|
||||
if (b->ChangedID != b->IndexBuffer->getChangedID() || !b->vbo_ID) {
|
||||
if (b->ChangedID != b->IndexBuffer->getChangedID() || !b->Vbo.exists()) {
|
||||
if (!updateIndexHardwareBuffer(b))
|
||||
return false;
|
||||
b->ChangedID = b->IndexBuffer->getChangedID();
|
||||
|
@ -584,10 +566,8 @@ COpenGL3DriverBase::SHWBufferLink *COpenGL3DriverBase::createHardwareBuffer(cons
|
|||
if (!vb || vb->getHardwareMappingHint() == scene::EHM_NEVER)
|
||||
return 0;
|
||||
|
||||
SHWBufferLink_opengl *HWBuffer = new SHWBufferLink_opengl(vb);
|
||||
|
||||
// add to map
|
||||
HWBuffer->listPosition = HWBufferList.insert(HWBufferList.end(), HWBuffer);
|
||||
auto *HWBuffer = new SHWBufferLink_opengl(vb);
|
||||
registerHardwareBuffer(HWBuffer);
|
||||
|
||||
if (!updateVertexHardwareBuffer(HWBuffer)) {
|
||||
deleteHardwareBuffer(HWBuffer);
|
||||
|
@ -602,10 +582,8 @@ COpenGL3DriverBase::SHWBufferLink *COpenGL3DriverBase::createHardwareBuffer(cons
|
|||
if (!ib || ib->getHardwareMappingHint() == scene::EHM_NEVER)
|
||||
return 0;
|
||||
|
||||
SHWBufferLink_opengl *HWBuffer = new SHWBufferLink_opengl(ib);
|
||||
|
||||
// add to map
|
||||
HWBuffer->listPosition = HWBufferList.insert(HWBufferList.end(), HWBuffer);
|
||||
auto *HWBuffer = new SHWBufferLink_opengl(ib);
|
||||
registerHardwareBuffer(HWBuffer);
|
||||
|
||||
if (!updateIndexHardwareBuffer(HWBuffer)) {
|
||||
deleteHardwareBuffer(HWBuffer);
|
||||
|
@ -621,10 +599,7 @@ void COpenGL3DriverBase::deleteHardwareBuffer(SHWBufferLink *HWBuffer)
|
|||
return;
|
||||
|
||||
auto *b = static_cast<SHWBufferLink_opengl *>(HWBuffer);
|
||||
if (b->vbo_ID) {
|
||||
GL.DeleteBuffers(1, &b->vbo_ID);
|
||||
b->vbo_ID = 0;
|
||||
}
|
||||
b->Vbo.destroy();
|
||||
|
||||
CNullDriver::deleteHardwareBuffer(HWBuffer);
|
||||
}
|
||||
|
@ -644,14 +619,14 @@ void COpenGL3DriverBase::drawBuffers(const scene::IVertexBuffer *vb,
|
|||
const void *vertices = vb->getData();
|
||||
if (hwvert) {
|
||||
assert(hwvert->IsVertex);
|
||||
GL.BindBuffer(GL_ARRAY_BUFFER, hwvert->vbo_ID);
|
||||
GL.BindBuffer(GL_ARRAY_BUFFER, hwvert->Vbo.getName());
|
||||
vertices = nullptr;
|
||||
}
|
||||
|
||||
const void *indexList = ib->getData();
|
||||
if (hwidx) {
|
||||
assert(!hwidx->IsVertex);
|
||||
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, hwidx->vbo_ID);
|
||||
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, hwidx->Vbo.getName());
|
||||
indexList = nullptr;
|
||||
}
|
||||
|
||||
|
@ -710,58 +685,32 @@ void COpenGL3DriverBase::drawVertexPrimitiveList(const void *vertices, u32 verte
|
|||
|
||||
setRenderStates3DMode();
|
||||
|
||||
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);
|
||||
drawGeneric(vertices, indexList, primitiveCount, vType, pType, iType);
|
||||
}
|
||||
|
||||
//! draws a vertex primitive list in 2d
|
||||
void COpenGL3DriverBase::draw2DVertexPrimitiveList(const void *vertices, u32 vertexCount,
|
||||
const void *indexList, u32 primitiveCount,
|
||||
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,
|
||||
|
@ -824,10 +773,10 @@ void COpenGL3DriverBase::draw2DImage(const video::ITexture *texture, const core:
|
|||
clipRect->getWidth(), clipRect->getHeight());
|
||||
}
|
||||
|
||||
f32 left = (f32)destRect.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
||||
f32 right = (f32)destRect.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
||||
f32 down = 2.f - (f32)destRect.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
||||
f32 top = 2.f - (f32)destRect.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
||||
f32 left = (f32)destRect.UpperLeftCorner.X;
|
||||
f32 right = (f32)destRect.LowerRightCorner.X;
|
||||
f32 down = (f32)destRect.LowerRightCorner.Y;
|
||||
f32 top = (f32)destRect.UpperLeftCorner.Y;
|
||||
|
||||
S3DVertex vertices[4];
|
||||
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());
|
||||
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;
|
||||
vtx.reserve(drawCount * 4);
|
||||
|
@ -924,10 +873,10 @@ void COpenGL3DriverBase::draw2DImageBatch(const video::ITexture *texture,
|
|||
|
||||
const core::rect<s32> poss(targetPos, sourceSize);
|
||||
|
||||
f32 left = (f32)poss.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
||||
f32 right = (f32)poss.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
||||
f32 down = 2.f - (f32)poss.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
||||
f32 top = 2.f - (f32)poss.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
|
||||
f32 left = (f32)poss.UpperLeftCorner.X;
|
||||
f32 right = (f32)poss.LowerRightCorner.X;
|
||||
f32 down = (f32)poss.LowerRightCorner.Y;
|
||||
f32 top = (f32)poss.UpperLeftCorner.Y;
|
||||
|
||||
vtx.emplace_back(left, top, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, color,
|
||||
|
@ -943,7 +892,7 @@ void COpenGL3DriverBase::draw2DImageBatch(const video::ITexture *texture,
|
|||
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);
|
||||
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> *clip)
|
||||
{
|
||||
chooseMaterial2D();
|
||||
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);
|
||||
draw2DRectangle(position, color, color, color, color, clip);
|
||||
}
|
||||
|
||||
//! draw an 2d rectangle
|
||||
|
@ -1008,12 +931,10 @@ void COpenGL3DriverBase::draw2DRectangle(const core::rect<s32> &position,
|
|||
colorRightDown.getAlpha() < 255,
|
||||
false, false);
|
||||
|
||||
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;
|
||||
f32 left = (f32)pos.UpperLeftCorner.X;
|
||||
f32 right = (f32)pos.LowerRightCorner.X;
|
||||
f32 down = (f32)pos.LowerRightCorner.Y;
|
||||
f32 top = (f32)pos.UpperLeftCorner.Y;
|
||||
|
||||
S3DVertex vertices[4];
|
||||
vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, colorLeftUp, 0, 0);
|
||||
|
@ -1034,12 +955,10 @@ void COpenGL3DriverBase::draw2DLine(const core::position2d<s32> &start,
|
|||
|
||||
setRenderStates2DMode(color.getAlpha() < 255, false, false);
|
||||
|
||||
const core::dimension2d<u32> &renderTargetSize = getCurrentRenderTargetSize();
|
||||
|
||||
f32 startX = (f32)start.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
||||
f32 endX = (f32)end.X / (f32)renderTargetSize.Width * 2.f - 1.f;
|
||||
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;
|
||||
f32 startX = (f32)start.X;
|
||||
f32 endX = (f32)end.X;
|
||||
f32 startY = (f32)start.Y;
|
||||
f32 endY = (f32)end.Y;
|
||||
|
||||
S3DVertex vertices[2];
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
for (auto &attr : vertexType) {
|
||||
|
@ -1372,60 +1340,74 @@ void COpenGL3DriverBase::setTextureRenderStates(const SMaterial &material, bool
|
|||
|
||||
CacheHandler->setActiveTexture(GL_TEXTURE0 + i);
|
||||
|
||||
if (resetAllRenderstates)
|
||||
tmpTexture->getStatesCache().IsCached = false;
|
||||
const auto &layer = material.TextureLayers[i];
|
||||
auto &states = tmpTexture->getStatesCache();
|
||||
|
||||
if (!tmpTexture->getStatesCache().IsCached || material.TextureLayers[i].MagFilter != tmpTexture->getStatesCache().MagFilter) {
|
||||
E_TEXTURE_MAG_FILTER magFilter = material.TextureLayers[i].MagFilter;
|
||||
if (resetAllRenderstates)
|
||||
states.IsCached = false;
|
||||
|
||||
if (!states.IsCached || layer.MagFilter != states.MagFilter) {
|
||||
E_TEXTURE_MAG_FILTER magFilter = layer.MagFilter;
|
||||
GL.TexParameteri(tmpTextureType, GL_TEXTURE_MAG_FILTER,
|
||||
magFilter == ETMAGF_NEAREST ? GL_NEAREST : (assert(magFilter == ETMAGF_LINEAR), GL_LINEAR));
|
||||
|
||||
tmpTexture->getStatesCache().MagFilter = magFilter;
|
||||
states.MagFilter = magFilter;
|
||||
}
|
||||
|
||||
if (material.UseMipMaps && tmpTexture->hasMipMaps()) {
|
||||
if (!tmpTexture->getStatesCache().IsCached || material.TextureLayers[i].MinFilter != tmpTexture->getStatesCache().MinFilter ||
|
||||
!tmpTexture->getStatesCache().MipMapStatus) {
|
||||
E_TEXTURE_MIN_FILTER minFilter = material.TextureLayers[i].MinFilter;
|
||||
if (!states.IsCached || layer.MinFilter != states.MinFilter ||
|
||||
!states.MipMapStatus) {
|
||||
E_TEXTURE_MIN_FILTER minFilter = layer.MinFilter;
|
||||
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_LINEAR ? GL_NEAREST_MIPMAP_LINEAR
|
||||
: (assert(minFilter == ETMINF_LINEAR_MIPMAP_LINEAR), GL_LINEAR_MIPMAP_LINEAR));
|
||||
|
||||
tmpTexture->getStatesCache().MinFilter = minFilter;
|
||||
tmpTexture->getStatesCache().MipMapStatus = true;
|
||||
states.MinFilter = minFilter;
|
||||
states.MipMapStatus = true;
|
||||
}
|
||||
} else {
|
||||
if (!tmpTexture->getStatesCache().IsCached || material.TextureLayers[i].MinFilter != tmpTexture->getStatesCache().MinFilter ||
|
||||
tmpTexture->getStatesCache().MipMapStatus) {
|
||||
E_TEXTURE_MIN_FILTER minFilter = material.TextureLayers[i].MinFilter;
|
||||
if (!states.IsCached || layer.MinFilter != states.MinFilter ||
|
||||
states.MipMapStatus) {
|
||||
E_TEXTURE_MIN_FILTER minFilter = layer.MinFilter;
|
||||
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));
|
||||
|
||||
tmpTexture->getStatesCache().MinFilter = minFilter;
|
||||
tmpTexture->getStatesCache().MipMapStatus = false;
|
||||
states.MinFilter = minFilter;
|
||||
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 &&
|
||||
(!tmpTexture->getStatesCache().IsCached || material.TextureLayers[i].AnisotropicFilter != tmpTexture->getStatesCache().AnisotropicFilter)) {
|
||||
(!states.IsCached || layer.AnisotropicFilter != states.AnisotropicFilter)) {
|
||||
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) {
|
||||
GL.TexParameteri(tmpTextureType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayers[i].TextureWrapU));
|
||||
tmpTexture->getStatesCache().WrapU = material.TextureLayers[i].TextureWrapU;
|
||||
if (!states.IsCached || layer.TextureWrapU != states.WrapU) {
|
||||
GL.TexParameteri(tmpTextureType, GL_TEXTURE_WRAP_S, getTextureWrapMode(layer.TextureWrapU));
|
||||
states.WrapU = layer.TextureWrapU;
|
||||
}
|
||||
|
||||
if (!tmpTexture->getStatesCache().IsCached || material.TextureLayers[i].TextureWrapV != tmpTexture->getStatesCache().WrapV) {
|
||||
GL.TexParameteri(tmpTextureType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayers[i].TextureWrapV));
|
||||
tmpTexture->getStatesCache().WrapV = material.TextureLayers[i].TextureWrapV;
|
||||
if (!states.IsCached || layer.TextureWrapV != states.WrapV) {
|
||||
GL.TexParameteri(tmpTextureType, GL_TEXTURE_WRAP_T, getTextureWrapMode(layer.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.
|
||||
s32 COpenGL3DriverBase::addHighLevelShaderMaterial(
|
||||
const c8 *vertexShaderProgram,
|
||||
const c8 *vertexShaderEntryPointName,
|
||||
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
||||
const c8 *pixelShaderProgram,
|
||||
const c8 *pixelShaderEntryPointName,
|
||||
E_PIXEL_SHADER_TYPE psCompileTarget,
|
||||
const c8 *geometryShaderProgram,
|
||||
const c8 *geometryShaderEntryPointName,
|
||||
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
|
||||
const c8 *shaderName,
|
||||
scene::E_PRIMITIVE_TYPE inType,
|
||||
scene::E_PRIMITIVE_TYPE outType,
|
||||
u32 verticesOut,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "SIrrCreationParameters.h"
|
||||
#include "Common.h"
|
||||
#include "VBO.h"
|
||||
#include "CNullDriver.h"
|
||||
#include "IMaterialRendererServices.h"
|
||||
#include "EDriverFeatures.h"
|
||||
|
@ -49,8 +50,7 @@ public:
|
|||
SHWBufferLink_opengl(const scene::IVertexBuffer *vb) : SHWBufferLink(vb) {}
|
||||
SHWBufferLink_opengl(const scene::IIndexBuffer *ib) : SHWBufferLink(ib) {}
|
||||
|
||||
GLuint vbo_ID = 0;
|
||||
u32 vbo_Size = 0;
|
||||
OpenGLVBO Vbo;
|
||||
};
|
||||
|
||||
bool updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer);
|
||||
|
@ -189,18 +189,13 @@ public:
|
|||
//! Adds a new material renderer to the VideoDriver
|
||||
virtual s32 addHighLevelShaderMaterial(
|
||||
const c8 *vertexShaderProgram,
|
||||
const c8 *vertexShaderEntryPointName = 0,
|
||||
E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1,
|
||||
const c8 *pixelShaderProgram = 0,
|
||||
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,
|
||||
const c8 *pixelShaderProgram,
|
||||
const c8 *geometryShaderProgram = nullptr,
|
||||
const c8 *shaderName = nullptr,
|
||||
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
|
||||
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
|
||||
u32 verticesOut = 0,
|
||||
IShaderConstantSetCallBack *callback = 0,
|
||||
IShaderConstantSetCallBack *callback = nullptr,
|
||||
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
|
||||
s32 userData = 0) override;
|
||||
|
||||
|
@ -300,7 +295,7 @@ protected:
|
|||
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();
|
||||
|
||||
|
@ -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, 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 endDraw(const VertexType &vertexType);
|
||||
|
||||
|
@ -372,9 +370,8 @@ private:
|
|||
|
||||
bool EnableErrorTest;
|
||||
|
||||
unsigned QuadIndexCount;
|
||||
GLuint QuadIndexBuffer = 0;
|
||||
void initQuadsIndices(int max_vertex_count = 65536);
|
||||
OpenGLVBO QuadIndexVBO;
|
||||
void initQuadsIndices(u32 max_vertex_count = 65536);
|
||||
|
||||
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);
|
||||
|
|
|
@ -161,6 +161,7 @@ public:
|
|||
GL.BlendEquation(mode);
|
||||
}
|
||||
|
||||
bool LODBiasSupported = false;
|
||||
bool AnisotropicFilterSupported = false;
|
||||
bool BlendMinMaxSupported = false;
|
||||
bool TextureMultisampleSupported = false;
|
||||
|
|
|
@ -32,6 +32,7 @@ COpenGL3Renderer2D::COpenGL3Renderer2D(const c8 *vertexShaderProgram, const c8 *
|
|||
|
||||
// These states don't change later.
|
||||
|
||||
ProjectionID = getPixelShaderConstantID("uProjection");
|
||||
ThicknessID = getPixelShaderConstantID("uThickness");
|
||||
if (WithTexture) {
|
||||
TextureUsageID = getPixelShaderConstantID("uTextureUsage");
|
||||
|
@ -62,6 +63,17 @@ void COpenGL3Renderer2D::OnSetMaterial(const video::SMaterial &material,
|
|||
f32 Thickness = (material.Thickness > 0.f) ? material.Thickness : 1.f;
|
||||
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) {
|
||||
s32 TextureUsage = material.TextureLayers[0].Texture ? 1 : 0;
|
||||
setPixelShaderConstant(TextureUsageID, &TextureUsage, 1);
|
||||
|
|
|
@ -24,6 +24,7 @@ public:
|
|||
|
||||
protected:
|
||||
bool WithTexture;
|
||||
s32 ProjectionID;
|
||||
s32 ThicknessID;
|
||||
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};
|
||||
|
||||
AnisotropicFilterSupported = isVersionAtLeast(4, 6) || queryExtension("GL_ARB_texture_filter_anisotropic") || queryExtension("GL_EXT_texture_filter_anisotropic");
|
||||
LODBiasSupported = true;
|
||||
BlendMinMaxSupported = true;
|
||||
TextureMultisampleSupported = true;
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace video
|
|||
/// OpenGL 3+ driver
|
||||
///
|
||||
/// 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);
|
||||
|
||||
|
|
|
@ -120,10 +120,10 @@ void COpenGLES2Driver::initFeatures()
|
|||
}
|
||||
|
||||
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");
|
||||
BlendMinMaxSupported = (Version.Major >= 3) || FeatureAvailable[IRR_GL_EXT_blend_minmax];
|
||||
TextureMultisampleSupported = isVersionAtLeast(3, 1);
|
||||
const bool TextureLODBiasSupported = queryExtension("GL_EXT_texture_lod_bias");
|
||||
|
||||
// COGLESCoreExtensionHandler::Feature
|
||||
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"))
|
||||
MaxIndices = GetInteger(GL_MAX_ELEMENTS_INDICES);
|
||||
MaxTextureSize = GetInteger(GL_MAX_TEXTURE_SIZE);
|
||||
if (TextureLODBiasSupported)
|
||||
if (LODBiasSupported)
|
||||
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_POINT_SIZE_RANGE, DimAliasedPoint);
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace video
|
|||
/// OpenGL ES 2+ driver
|
||||
///
|
||||
/// 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);
|
||||
|
||||
|
|
|
@ -573,7 +573,7 @@ SkinnedMesh *SkinnedMeshBuilder::finalize()
|
|||
return this;
|
||||
}
|
||||
|
||||
void SkinnedMesh::updateBoundingBox(void)
|
||||
void SkinnedMesh::updateBoundingBox()
|
||||
{
|
||||
if (!SkinningBuffers)
|
||||
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.
|
||||
// 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 start = 0;
|
||||
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;
|
||||
}
|
||||
__android_log_print(LogLevel, "Irrlicht", "%s\n", &message[start]);
|
||||
|
|
|
@ -101,7 +101,7 @@ std::vector<DistanceSortedActiveObject> ActiveObjectMgr::getActiveSelectableObje
|
|||
if (!obj)
|
||||
continue;
|
||||
|
||||
aabb3f selection_box;
|
||||
aabb3f selection_box{{0.0f, 0.0f, 0.0f}};
|
||||
if (!obj->getSelectionBox(&selection_box))
|
||||
continue;
|
||||
|
||||
|
|
|
@ -430,7 +430,7 @@ void ClientEnvironment::getSelectedActiveObjects(
|
|||
|
||||
for (const auto &allObject : allObjects) {
|
||||
ClientActiveObject *obj = allObject.obj;
|
||||
aabb3f selection_box;
|
||||
aabb3f selection_box{{0.0f, 0.0f, 0.0f}};
|
||||
if (!obj->getSelectionBox(&selection_box))
|
||||
continue;
|
||||
|
||||
|
|
|
@ -301,24 +301,29 @@ void ClientLauncher::init_input()
|
|||
else
|
||||
input = new RealInputHandler(receiver);
|
||||
|
||||
if (g_settings->getBool("enable_joysticks")) {
|
||||
if (g_settings->getBool("enable_joysticks"))
|
||||
init_joysticks();
|
||||
}
|
||||
|
||||
void ClientLauncher::init_joysticks()
|
||||
{
|
||||
irr::core::array<irr::SJoystickInfo> infos;
|
||||
std::vector<irr::SJoystickInfo> joystick_infos;
|
||||
|
||||
// Make sure this is called maximum once per
|
||||
// irrlicht device, otherwise it will give you
|
||||
// multiple events for the same joystick.
|
||||
if (m_rendering_engine->get_raw_device()->activateJoysticks(infos)) {
|
||||
if (!m_rendering_engine->get_raw_device()->activateJoysticks(infos)) {
|
||||
errorstream << "Could not activate joystick support." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
errorstream << "Could not activate joystick support." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
bool init_engine();
|
||||
void init_input();
|
||||
void init_joysticks();
|
||||
|
||||
static void setting_changed_callback(const std::string &name, void *data);
|
||||
void config_guienv();
|
||||
|
|
|
@ -22,16 +22,27 @@
|
|||
#include <queue>
|
||||
|
||||
namespace {
|
||||
// A helper struct
|
||||
// data structure that groups block meshes by material
|
||||
struct MeshBufListMaps
|
||||
{
|
||||
using MeshBufListMap = std::unordered_map<
|
||||
video::SMaterial,
|
||||
std::vector<std::pair<v3s16, scene::IMeshBuffer *>>
|
||||
>;
|
||||
// first = block pos
|
||||
using MeshBuf = 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;
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
for (auto &map : maps) {
|
||||
if (!map.empty())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (auto &map : maps)
|
||||
|
@ -48,7 +59,67 @@ namespace {
|
|||
auto &bufs = map[m]; // default constructs if non-existent
|
||||
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.
|
||||
*/
|
||||
Name = "ClientMap";
|
||||
m_box = aabb3f(-BS*1000000,-BS*1000000,-BS*1000000,
|
||||
BS*1000000,BS*1000000,BS*1000000);
|
||||
setAutomaticCulling(scene::EAC_OFF);
|
||||
|
||||
for (const auto &name : ClientMap_settings)
|
||||
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);
|
||||
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();
|
||||
|
||||
|
@ -692,23 +762,132 @@ void ClientMap::touchMapBlocks()
|
|||
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)
|
||||
{
|
||||
ZoneScoped;
|
||||
|
||||
bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
|
||||
const bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
|
||||
|
||||
std::string prefix;
|
||||
if (pass == scene::ESNRP_SOLID)
|
||||
prefix = "renderMap(SOLID): ";
|
||||
else
|
||||
prefix = "renderMap(TRANSPARENT): ";
|
||||
|
||||
/*
|
||||
This is called two times per frame, reset on the non-transparent one
|
||||
*/
|
||||
if (pass == scene::ESNRP_SOLID)
|
||||
m_last_drawn_sectors.clear();
|
||||
prefix = "renderMap(TRANS): ";
|
||||
|
||||
/*
|
||||
Get animation parameters
|
||||
|
@ -719,16 +898,16 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||
|
||||
const v3f camera_position = m_camera_position;
|
||||
|
||||
/*
|
||||
Get all blocks and draw all visible ones
|
||||
*/
|
||||
const auto mesh_grid = m_client->getMeshGrid();
|
||||
// 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 drawcall_count = 0;
|
||||
u32 merged_count = 0;
|
||||
|
||||
// For limiting number of mesh animations per frame
|
||||
u32 mesh_animate_count = 0;
|
||||
//u32 mesh_animate_count_far = 0;
|
||||
|
||||
/*
|
||||
Update transparent meshes
|
||||
|
@ -737,18 +916,18 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||
updateTransparentMeshBuffers();
|
||||
|
||||
/*
|
||||
Draw the selected MapBlocks
|
||||
Collect everything we need to draw
|
||||
*/
|
||||
TimeTaker tt_collect("");
|
||||
|
||||
MeshBufListMaps grouped_buffers;
|
||||
std::vector<DrawDescriptor> draw_order;
|
||||
video::SMaterial previous_material;
|
||||
std::vector<scene::IMeshBuffer*> buffer_trash;
|
||||
DrawDescriptorList draw_order;
|
||||
|
||||
auto is_frustum_culled = m_client->getCamera()->getFrustumCuller();
|
||||
|
||||
const MeshGrid mesh_grid = m_client->getMeshGrid();
|
||||
for (auto &i : m_drawlist) {
|
||||
v3s16 block_pos = i.first;
|
||||
const v3s16 block_pos = i.first;
|
||||
MapBlock *block = i.second;
|
||||
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
|
||||
// the partial buffers in the correct order
|
||||
for (auto &buffer : block_mesh->getTransparentBuffers())
|
||||
draw_order.emplace_back(block_pos, &buffer);
|
||||
}
|
||||
else {
|
||||
// otherwise, group buffers across meshes
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
draw_order.emplace_back(get_block_wpos(block_pos), &buffer);
|
||||
} else {
|
||||
// Otherwise, group them
|
||||
grouped_buffers.addFromBlock(block_pos, block_mesh, driver);
|
||||
}
|
||||
}
|
||||
|
||||
// Capture draw order for all solid meshes
|
||||
assert(!is_transparent_pass || grouped_buffers.empty());
|
||||
for (auto &map : grouped_buffers.maps) {
|
||||
for (auto &list : map) {
|
||||
// iterate in reverse to draw closest blocks first
|
||||
for (auto it = list.second.rbegin(); it != list.second.rend(); ++it) {
|
||||
draw_order.emplace_back(it->first, it->second, it != list.second.rbegin());
|
||||
}
|
||||
merged_count += transformBuffersToDrawOrder(
|
||||
list.second, draw_order, get_block_wpos, buffer_trash);
|
||||
}
|
||||
}
|
||||
|
||||
TimeTaker draw("Drawing mesh buffers");
|
||||
g_profiler->avg(prefix + "collecting [ms]", tt_collect.stop(true));
|
||||
|
||||
TimeTaker tt_draw("");
|
||||
|
||||
core::matrix4 m; // Model matrix
|
||||
v3f offset = intToFloat(m_camera_offset, BS);
|
||||
u32 vertex_count = 0;
|
||||
u32 drawcall_count = 0;
|
||||
u32 material_swaps = 0;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
v3f block_wpos = intToFloat(mesh_grid.getMeshPos(descriptor.m_pos) * MAP_BLOCKSIZE, BS);
|
||||
m.setTranslation(block_wpos - offset);
|
||||
|
||||
m.setTranslation(descriptor.m_pos);
|
||||
driver->setTransform(video::ETS_WORLD, m);
|
||||
|
||||
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) {
|
||||
g_profiler->avg("renderMap(): animated meshes [#]", mesh_animate_count);
|
||||
g_profiler->avg(prefix + "merged buffers [#]", merged_count);
|
||||
}
|
||||
|
||||
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 + "drawcalls [#]", drawcall_count);
|
||||
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,
|
||||
|
@ -1096,12 +1256,15 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
|
|||
else
|
||||
prefix = "renderMap(SHADOW SOLID): ";
|
||||
|
||||
u32 drawcall_count = 0;
|
||||
u32 vertex_count = 0;
|
||||
const auto mesh_grid = m_client->getMeshGrid();
|
||||
// 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;
|
||||
std::vector<DrawDescriptor> draw_order;
|
||||
|
||||
std::vector<scene::IMeshBuffer*> buffer_trash;
|
||||
DrawDescriptorList draw_order;
|
||||
|
||||
std::size_t count = 0;
|
||||
std::size_t meshes_per_frame = m_drawlist_shadow.size() / total_frames + 1;
|
||||
|
@ -1113,7 +1276,6 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
|
|||
return;
|
||||
}
|
||||
|
||||
const MeshGrid mesh_grid = m_client->getMeshGrid();
|
||||
for (const auto &i : m_drawlist_shadow) {
|
||||
// only process specific part of the list & break early
|
||||
++count;
|
||||
|
@ -1136,52 +1298,25 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
|
|||
// In transparent pass, the mesh will give us
|
||||
// the partial buffers in the correct order
|
||||
for (auto &buffer : block->mesh->getTransparentBuffers())
|
||||
draw_order.emplace_back(block_pos, &buffer);
|
||||
}
|
||||
else {
|
||||
// otherwise, group buffers across meshes
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
draw_order.emplace_back(get_block_wpos(block_pos), &buffer);
|
||||
} else {
|
||||
// Otherwise, group them
|
||||
grouped_buffers.addFromBlock(block_pos, block->mesh, driver);
|
||||
}
|
||||
}
|
||||
|
||||
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 &list : map) {
|
||||
// iterate in reverse to draw closest blocks first
|
||||
for (auto it = list.second.rbegin(); it != list.second.rend(); ++it)
|
||||
draw_order.emplace_back(it->first, it->second, it != list.second.rbegin());
|
||||
transformBuffersToDrawOrder(
|
||||
list.second, draw_order, get_block_wpos, buffer_trash);
|
||||
}
|
||||
}
|
||||
|
||||
TimeTaker draw("Drawing shadow mesh buffers");
|
||||
TimeTaker draw("");
|
||||
|
||||
core::matrix4 m; // Model matrix
|
||||
v3f offset = intToFloat(m_camera_offset, BS);
|
||||
u32 drawcall_count = 0;
|
||||
u32 vertex_count = 0;
|
||||
u32 material_swaps = 0;
|
||||
|
||||
// Render all mesh buffers in order
|
||||
|
@ -1221,8 +1356,7 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
|
|||
++material_swaps;
|
||||
}
|
||||
|
||||
v3f block_wpos = intToFloat(mesh_grid.getMeshPos(descriptor.m_pos) * MAP_BLOCKSIZE, BS);
|
||||
m.setTranslation(block_wpos - offset);
|
||||
m.setTranslation(descriptor.m_pos);
|
||||
|
||||
driver->setTransform(video::ETS_WORLD, m);
|
||||
vertex_count += descriptor.draw(driver);
|
||||
|
@ -1232,12 +1366,16 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
|
|||
video::SMaterial clean;
|
||||
clean.BlendOperation = video::EBO_ADD;
|
||||
driver->setMaterial(clean); // reset material to defaults
|
||||
// FIXME: why is this here?
|
||||
driver->draw3DLine(v3f(), v3f(), video::SColor(0));
|
||||
|
||||
g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));
|
||||
g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
|
||||
g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
|
||||
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;
|
||||
}
|
||||
|
||||
video::SMaterial &ClientMap::DrawDescriptor::getMaterial()
|
||||
video::SMaterial &DrawDescriptor::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) {
|
||||
m_partial_buffer->draw(driver);
|
||||
|
|
|
@ -115,7 +115,6 @@ private:
|
|||
// update the vertex order in transparent mesh buffers
|
||||
void updateTransparentMeshBuffers();
|
||||
|
||||
|
||||
// Orders blocks by distance to the camera
|
||||
class MapBlockComparer
|
||||
{
|
||||
|
@ -133,30 +132,6 @@ private:
|
|||
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;
|
||||
RenderingEngine *m_rendering_engine;
|
||||
|
||||
|
@ -177,8 +152,6 @@ private:
|
|||
std::map<v3s16, MapBlock*> m_drawlist_shadow;
|
||||
bool m_needs_update_drawlist;
|
||||
|
||||
std::set<v2s16> m_last_drawn_sectors;
|
||||
|
||||
bool m_cache_trilinear_filter;
|
||||
bool m_cache_bilinear_filter;
|
||||
bool m_cache_anistropic_filter;
|
||||
|
|
|
@ -160,7 +160,7 @@ private:
|
|||
// Was the mesh ever generated?
|
||||
bool m_mesh_valid = false;
|
||||
|
||||
aabb3f m_box;
|
||||
aabb3f m_box{{0.0f, 0.0f, 0.0f}};
|
||||
v2f m_origin;
|
||||
u16 m_cloud_radius_i;
|
||||
u32 m_seed;
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "nodedef.h"
|
||||
#include "client/tile.h"
|
||||
#include "mesh.h"
|
||||
#include <IMeshManipulator.h>
|
||||
#include "client/meshgen/collector.h"
|
||||
#include "client/renderingengine.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";
|
||||
|
||||
MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output,
|
||||
scene::IMeshManipulator *mm):
|
||||
MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output):
|
||||
data(input),
|
||||
collector(output),
|
||||
nodedef(data->nodedef),
|
||||
meshmanip(mm),
|
||||
blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE),
|
||||
smooth_liquids(g_settings->getBool("enable_water_reflections"))
|
||||
{
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "nodedef.h"
|
||||
#include <IMeshManipulator.h>
|
||||
|
||||
struct MeshMakeData;
|
||||
struct MeshCollector;
|
||||
|
@ -46,8 +45,7 @@ struct LightFrame {
|
|||
class MapblockMeshGenerator
|
||||
{
|
||||
public:
|
||||
MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output,
|
||||
scene::IMeshManipulator *mm);
|
||||
MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output);
|
||||
void generate();
|
||||
void renderSingle(content_t node, u8 param2 = 0x00);
|
||||
|
||||
|
@ -56,7 +54,6 @@ private:
|
|||
MeshCollector *const collector;
|
||||
|
||||
const NodeDefManager *const nodedef;
|
||||
scene::IMeshManipulator *const meshmanip;
|
||||
|
||||
const v3s16 blockpos_nodes;
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ unsigned int FontEngine::getLineHeight(const FontSpec &spec)
|
|||
gui::IGUIFont *font = getFont(spec);
|
||||
|
||||
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)
|
||||
g_profiler->avg("Irr: primitives per drawcall",
|
||||
stats2.PrimitivesDrawn / float(stats2.Drawcalls));
|
||||
g_profiler->avg("Irr: buffers uploaded", stats2.HWBuffersUploaded);
|
||||
g_profiler->avg("Irr: buffers uploaded (bytes)", stats2.HWBuffersUploadedSize);
|
||||
g_profiler->avg("Irr: HW buffers uploaded", stats2.HWBuffersUploaded);
|
||||
g_profiler->avg("Irr: HW buffers active", stats2.HWBuffersActive);
|
||||
}
|
||||
|
||||
void Game::updateStats(RunStats *stats, const FpsControl &draw_times,
|
||||
|
@ -3246,7 +3246,7 @@ PointedThing Game::updatePointedThing(
|
|||
hud->pointing_at_object = true;
|
||||
|
||||
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() &&
|
||||
runData.selected_object->getSelectionBox(&selection_box)) {
|
||||
v3f pos = runData.selected_object->getPosition();
|
||||
|
|
|
@ -104,11 +104,11 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
|
|||
os << std::fixed
|
||||
<< PROJECT_NAME_C " " << g_version_hash
|
||||
<< " | FPS: " << fps
|
||||
<< std::setprecision(0)
|
||||
<< std::setprecision(fps >= 100 ? 1 : 0)
|
||||
<< " | drawtime: " << m_drawtime_avg << "ms"
|
||||
<< std::setprecision(1)
|
||||
<< " | dtime jitter: "
|
||||
<< (stats.dtime_jitter.max_fraction * 100.0) << "%"
|
||||
<< (stats.dtime_jitter.max_fraction * 100.0f) << "%"
|
||||
<< std::setprecision(1)
|
||||
<< " | view 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))
|
||||
return;
|
||||
const video::SMaterial oldmaterial = driver->getMaterial2D();
|
||||
driver->setMaterial(m_selection_material);
|
||||
const core::matrix4 oldtransform = driver->getTransform(video::ETS_WORLD);
|
||||
|
||||
|
@ -910,7 +909,6 @@ void Hud::drawSelectionMesh()
|
|||
driver->drawMeshBuffer(buf);
|
||||
}
|
||||
}
|
||||
driver->setMaterial(oldmaterial);
|
||||
driver->setTransform(video::ETS_WORLD, oldtransform);
|
||||
}
|
||||
|
||||
|
@ -935,17 +933,11 @@ void Hud::drawBlockBounds()
|
|||
return;
|
||||
}
|
||||
|
||||
video::SMaterial old_material = driver->getMaterial2D();
|
||||
driver->setMaterial(m_block_bounds_material);
|
||||
|
||||
u16 mesh_chunk_size = std::max<u16>(1, g_settings->getU16("client_mesh_chunk"));
|
||||
|
||||
v3s16 pos = player->getStandingNodePos();
|
||||
v3s16 block_pos(
|
||||
floorf((float) pos.X / MAP_BLOCKSIZE),
|
||||
floorf((float) pos.Y / MAP_BLOCKSIZE),
|
||||
floorf((float) pos.Z / MAP_BLOCKSIZE)
|
||||
);
|
||||
v3s16 block_pos = getContainerPos(player->getStandingNodePos(), MAP_BLOCKSIZE);
|
||||
|
||||
v3f cam_offset = intToFloat(client->getCamera()->getOffset(), BS);
|
||||
|
||||
|
@ -988,8 +980,6 @@ void Hud::drawBlockBounds()
|
|||
choose_color(block_pos.Y, block_pos.Z)
|
||||
);
|
||||
}
|
||||
|
||||
driver->setMaterial(old_material);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (src->getColorFormat() == video::ECF_A8R8G8B8)
|
||||
|
@ -167,13 +156,109 @@ void imageCleanTransparent(video::IImage *src, u32 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
|
||||
* some blending at the edges where pixels don't line up perfectly, but this
|
||||
* filter is designed to produce the most accurate results for both upscaling
|
||||
* and downscaling.
|
||||
*/
|
||||
/**********************************/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
double sx, sy, minsx, maxsx, minsy, maxsy, area, ra, ga, ba, aa, pw, ph, pa;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "irrlichttypes.h"
|
||||
#include <rect.h>
|
||||
#include <SColor.h>
|
||||
|
||||
namespace irr::video
|
||||
{
|
||||
|
@ -26,6 +27,10 @@ namespace irr::video
|
|||
*/
|
||||
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
|
||||
* anti-aliasing; treat pixels as crisp rectangles, but blend them at boundaries
|
||||
* 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
|
||||
// Remove old image
|
||||
std::map<std::string, video::IImage*>::iterator n;
|
||||
n = m_images.find(name);
|
||||
auto n = m_images.find(name);
|
||||
if (n != m_images.end()){
|
||||
if (n->second)
|
||||
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)
|
||||
{
|
||||
std::map<std::string, video::IImage*>::iterator n;
|
||||
n = m_images.find(name);
|
||||
auto n = m_images.find(name);
|
||||
if (n != m_images.end())
|
||||
return n->second;
|
||||
return nullptr;
|
||||
|
@ -73,8 +71,7 @@ video::IImage* SourceImageCache::get(const std::string &name)
|
|||
// Primarily fetches from cache, secondarily tries to read from filesystem
|
||||
video::IImage* SourceImageCache::getOrLoad(const std::string &name)
|
||||
{
|
||||
std::map<std::string, video::IImage*>::iterator n;
|
||||
n = m_images.find(name);
|
||||
auto n = m_images.find(name);
|
||||
if (n != m_images.end()){
|
||||
n->second->grab(); // Grab for caller
|
||||
return n->second;
|
||||
|
@ -166,13 +163,13 @@ static void draw_crack(video::IImage *crack, video::IImage *dst,
|
|||
video::IVideoDriver *driver, u8 tiles = 1);
|
||||
|
||||
// Brighten image
|
||||
void brighten(video::IImage *image);
|
||||
static void brighten(video::IImage *image);
|
||||
// Parse a transform name
|
||||
u32 parseImageTransform(std::string_view s);
|
||||
static u32 parseImageTransform(std::string_view s);
|
||||
// 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
|
||||
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)
|
||||
{
|
||||
|
@ -289,7 +286,7 @@ static video::IImage *createInventoryCubeImage(
|
|||
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;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
out += str.substr(pos, cpos - pos) + str[cpos + 1];
|
||||
out += str.substr(pos, cpos - pos);
|
||||
out += str[cpos + 1];
|
||||
pos = cpos + 2;
|
||||
}
|
||||
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
|
||||
get dropped and switched with a new image.
|
||||
*/
|
||||
void upscaleImagesToMatchLargest(video::IImage *& img1,
|
||||
static void upscaleImagesToMatchLargest(video::IImage *& img1,
|
||||
video::IImage *& img2)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace (anonymous)
|
||||
|
||||
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)
|
||||
{
|
||||
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::IImage *src_converted = driver->createImage(video::ECF_A8R8G8B8,
|
||||
src_dim);
|
||||
if (!src_converted)
|
||||
throw BaseException("blit_with_alpha() failed to convert the "
|
||||
"source image to ECF_A8R8G8B8.");
|
||||
sanity_check(src_converted != nullptr);
|
||||
src->copyTo(src_converted);
|
||||
src = src_converted;
|
||||
drop_src = true;
|
||||
}
|
||||
|
||||
video::SColor *pixels_src =
|
||||
reinterpret_cast<video::SColor *>(src->getData());
|
||||
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++]);
|
||||
}
|
||||
}
|
||||
|
||||
if (drop_src)
|
||||
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> strip_size = crack->getDimension();
|
||||
|
@ -804,7 +803,7 @@ static void draw_crack(video::IImage *crack, video::IImage *dst,
|
|||
crack_scaled->drop();
|
||||
}
|
||||
|
||||
void brighten(video::IImage *image)
|
||||
static void brighten(video::IImage *image)
|
||||
{
|
||||
if (image == NULL)
|
||||
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;
|
||||
|
||||
|
@ -872,15 +871,15 @@ u32 parseImageTransform(std::string_view s)
|
|||
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)
|
||||
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)
|
||||
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 //
|
||||
|
@ -1017,18 +974,12 @@ bool ImageSource::generateImagePart(std::string_view part_of_name,
|
|||
std::string part_s(part_of_name);
|
||||
source_image_names.insert(part_s);
|
||||
video::IImage *image = m_sourcecache.getOrLoad(part_s);
|
||||
|
||||
if (!image) {
|
||||
// Do not create the dummy texture
|
||||
if (part_of_name.empty())
|
||||
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 \""
|
||||
<< part_of_name << "\" while building texture; "
|
||||
"Creating a dummy image" << std::endl;
|
||||
|
@ -1040,16 +991,15 @@ bool ImageSource::generateImagePart(std::string_view part_of_name,
|
|||
myrand()%256,myrand()%256));
|
||||
}
|
||||
|
||||
// If base image is NULL, load as base.
|
||||
if (baseimg == NULL)
|
||||
// load as base or blit
|
||||
if (!baseimg)
|
||||
{
|
||||
/*
|
||||
Copy it this way to get an alpha channel.
|
||||
Otherwise images with alpha cannot be blitted on
|
||||
images that don't have alpha in the original file.
|
||||
*/
|
||||
core::dimension2d<u32> dim = image->getDimension();
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, image->getDimension());
|
||||
image->copyTo(baseimg);
|
||||
}
|
||||
// Else blit on base.
|
||||
|
@ -1705,14 +1655,17 @@ bool ImageSource::generateImagePart(std::string_view part_of_name,
|
|||
return false;
|
||||
}
|
||||
|
||||
// blit or use as base
|
||||
if (baseimg) {
|
||||
blitBaseImage(pngimg, baseimg);
|
||||
} else {
|
||||
core::dimension2d<u32> dim = pngimg->getDimension();
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
pngimg->copyTo(baseimg);
|
||||
}
|
||||
pngimg->drop();
|
||||
} else if (pngimg->getColorFormat() != video::ECF_A8R8G8B8) {
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, pngimg->getDimension());
|
||||
pngimg->copyTo(baseimg);
|
||||
pngimg->drop();
|
||||
} else {
|
||||
baseimg = pngimg;
|
||||
}
|
||||
}
|
||||
/*
|
||||
[hsl:hue:saturation:lightness
|
||||
|
@ -1945,32 +1898,7 @@ video::IImage* ImageSource::generateImage(std::string_view name,
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <IImage.h>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
|
@ -28,7 +28,7 @@ public:
|
|||
// Primarily fetches from cache, secondarily tries to read from filesystem.
|
||||
video::IImage *getOrLoad(const std::string &name);
|
||||
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.
|
||||
|
@ -45,9 +45,6 @@ struct ImageSource {
|
|||
// Insert a source image into the cache without touching the filesystem.
|
||||
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:
|
||||
|
||||
// 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())
|
||||
return aabb3f(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
aabb3f b_max;
|
||||
|
||||
std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
|
||||
b_max = aabb3f(it->MinEdge, it->MaxEdge);
|
||||
auto it = nodeboxes.begin();
|
||||
aabb3f b_max(it->MinEdge, it->MaxEdge);
|
||||
|
||||
++it;
|
||||
for (; it != nodeboxes.end(); ++it)
|
||||
|
|
|
@ -633,8 +633,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
|
|||
*/
|
||||
|
||||
{
|
||||
MapblockMeshGenerator(data, &collector,
|
||||
client->getSceneManager()->getMeshManipulator()).generate();
|
||||
MapblockMeshGenerator(data, &collector).generate();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -105,8 +105,7 @@ void scaleMesh(scene::IMesh *mesh, v3f scale)
|
|||
if (mesh == NULL)
|
||||
return;
|
||||
|
||||
aabb3f bbox;
|
||||
bbox.reset(0, 0, 0);
|
||||
aabb3f bbox{{0.0f, 0.0f, 0.0f}};
|
||||
|
||||
u32 mc = mesh->getMeshBufferCount();
|
||||
for (u32 j = 0; j < mc; j++) {
|
||||
|
@ -134,8 +133,7 @@ void translateMesh(scene::IMesh *mesh, v3f vec)
|
|||
if (mesh == NULL)
|
||||
return;
|
||||
|
||||
aabb3f bbox;
|
||||
bbox.reset(0, 0, 0);
|
||||
aabb3f bbox{{0.0f, 0.0f, 0.0f}};
|
||||
|
||||
u32 mc = mesh->getMeshBufferCount();
|
||||
for (u32 j = 0; j < mc; j++) {
|
||||
|
@ -296,8 +294,7 @@ void rotateMeshBy6dFacedir(scene::IMesh *mesh, u8 facedir)
|
|||
|
||||
void recalculateBoundingBox(scene::IMesh *src_mesh)
|
||||
{
|
||||
aabb3f bbox;
|
||||
bbox.reset(0,0,0);
|
||||
aabb3f bbox{{0.0f, 0.0f, 0.0f}};
|
||||
for (u16 j = 0; j < src_mesh->getMeshBufferCount(); j++) {
|
||||
scene::IMeshBuffer *buf = src_mesh->getMeshBuffer(j);
|
||||
buf->recalculateBoundingBox();
|
||||
|
|
|
@ -619,15 +619,22 @@ const core::aabbox3df &ParticleBuffer::getBoundingBox() const
|
|||
if (!m_bounding_box_dirty)
|
||||
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++) {
|
||||
// check if this index is used
|
||||
static_assert(quad_indices[1] != 0);
|
||||
if (m_mesh_buffer->getIndices()[6 * i + 1] == 0)
|
||||
continue;
|
||||
|
||||
for (u16 j = 0; j < 4; j++)
|
||||
box.addInternalPoint(m_mesh_buffer->getPosition(i * 4 + j));
|
||||
for (u16 j = 0; j < 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;
|
||||
|
|
|
@ -135,7 +135,7 @@ static irr::IrrlichtDevice *createDevice(SIrrlichtCreationParameters params, std
|
|||
{
|
||||
if (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))
|
||||
return device;
|
||||
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)
|
||||
continue;
|
||||
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))
|
||||
return device;
|
||||
}
|
||||
|
@ -374,16 +374,16 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
|
|||
std::vector<video::E_DRIVER_TYPE> RenderingEngine::getSupportedVideoDrivers()
|
||||
{
|
||||
// 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[] = {
|
||||
video::EDT_OPENGL,
|
||||
video::EDT_OPENGL3,
|
||||
video::EDT_OPENGL,
|
||||
video::EDT_OGLES2,
|
||||
video::EDT_NULL,
|
||||
};
|
||||
std::vector<video::E_DRIVER_TYPE> drivers;
|
||||
|
||||
for (video::E_DRIVER_TYPE driver: glDrivers) {
|
||||
for (auto driver : glDrivers) {
|
||||
if (IrrlichtDevice::isDriverSupported(driver))
|
||||
drivers.push_back(driver);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <IMaterialRendererServices.h>
|
||||
#include <IShaderConstantSetCallBack.h>
|
||||
#include "client/renderingengine.h"
|
||||
#include <EShaderTypes.h>
|
||||
#include "gettext.h"
|
||||
#include "log.h"
|
||||
#include "gamedef.h"
|
||||
|
@ -615,10 +614,16 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
|||
#define textureFlags texture2
|
||||
)";
|
||||
|
||||
/// Unique name of this shader, for debug/logging
|
||||
std::string log_name = name;
|
||||
|
||||
/* Define constants for node and object shaders */
|
||||
const bool node_shader = drawtype != NodeDrawType_END;
|
||||
if (node_shader) {
|
||||
|
||||
log_name.append(" mat=").append(itos(material_type))
|
||||
.append(" draw=").append(itos(drawtype));
|
||||
|
||||
bool use_discard = fully_programmable;
|
||||
if (!use_discard) {
|
||||
// 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();
|
||||
}
|
||||
|
||||
irr_ptr<ShaderCallback> cb{new ShaderCallback(m_setter_factories)};
|
||||
infostream<<"Compiling high level shaders for "<<name<<std::endl;
|
||||
auto cb = make_irr<ShaderCallback>(m_setter_factories);
|
||||
infostream << "Compiling high level shaders for " << log_name << std::endl;
|
||||
s32 shadermat = gpu->addHighLevelShaderMaterial(
|
||||
vertex_shader.c_str(), nullptr, video::EVST_VS_1_1,
|
||||
fragment_shader.c_str(), nullptr, video::EPST_PS_1_1,
|
||||
geometry_shader_ptr, nullptr, video::EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLES, 0,
|
||||
cb.get(), shaderinfo.base_material, 1);
|
||||
vertex_shader.c_str(), fragment_shader.c_str(), geometry_shader_ptr,
|
||||
log_name.c_str(), scene::EPT_TRIANGLES, scene::EPT_TRIANGLES, 0,
|
||||
cb.get(), shaderinfo.base_material);
|
||||
if (shadermat == -1) {
|
||||
errorstream<<"generate_shader(): "
|
||||
"failed to generate \""<<name<<"\", "
|
||||
"addHighLevelShaderMaterial failed."
|
||||
<<std::endl;
|
||||
errorstream << "generateShader(): failed to generate shaders for "
|
||||
<< log_name << ", addHighLevelShaderMaterial failed." << std::endl;
|
||||
dumpShaderProgram(warningstream, "Vertex", vertex_shader);
|
||||
dumpShaderProgram(warningstream, "Fragment", fragment_shader);
|
||||
dumpShaderProgram(warningstream, "Geometry", geometry_shader);
|
||||
|
|
|
@ -14,10 +14,9 @@
|
|||
#include "client/client.h"
|
||||
#include "client/clientmap.h"
|
||||
#include "profiler.h"
|
||||
#include "EShaderTypes.h"
|
||||
#include "IGPUProgrammingServices.h"
|
||||
#include "IMaterialRenderer.h"
|
||||
#include <IVideoDriver.h>
|
||||
#include "IVideoDriver.h"
|
||||
|
||||
ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) :
|
||||
m_smgr(device->getSceneManager()), m_driver(device->getVideoDriver()),
|
||||
|
@ -539,10 +538,9 @@ void ShadowRenderer::createShaders()
|
|||
m_shadow_depth_cb = new ShadowDepthShaderCB();
|
||||
|
||||
depth_shader = gpu->addHighLevelShaderMaterial(
|
||||
readShaderFile(depth_shader_vs).c_str(), "vertexMain",
|
||||
video::EVST_VS_1_1,
|
||||
readShaderFile(depth_shader_fs).c_str(), "pixelMain",
|
||||
video::EPST_PS_1_2, m_shadow_depth_cb, video::EMT_ONETEXTURE_BLEND);
|
||||
readShaderFile(depth_shader_vs).c_str(),
|
||||
readShaderFile(depth_shader_fs).c_str(), nullptr,
|
||||
m_shadow_depth_cb, video::EMT_ONETEXTURE_BLEND);
|
||||
|
||||
if (depth_shader == -1) {
|
||||
// upsi, something went wrong loading shader.
|
||||
|
@ -578,10 +576,9 @@ void ShadowRenderer::createShaders()
|
|||
m_shadow_depth_entity_cb = new ShadowDepthShaderCB();
|
||||
|
||||
depth_shader_entities = gpu->addHighLevelShaderMaterial(
|
||||
readShaderFile(depth_shader_vs).c_str(), "vertexMain",
|
||||
video::EVST_VS_1_1,
|
||||
readShaderFile(depth_shader_fs).c_str(), "pixelMain",
|
||||
video::EPST_PS_1_2, m_shadow_depth_entity_cb);
|
||||
readShaderFile(depth_shader_vs).c_str(),
|
||||
readShaderFile(depth_shader_fs).c_str(), nullptr,
|
||||
m_shadow_depth_entity_cb);
|
||||
|
||||
if (depth_shader_entities == -1) {
|
||||
// upsi, something went wrong loading shader.
|
||||
|
@ -616,10 +613,9 @@ void ShadowRenderer::createShaders()
|
|||
m_shadow_mix_cb = new shadowScreenQuadCB();
|
||||
m_screen_quad = new shadowScreenQuad();
|
||||
mixcsm_shader = gpu->addHighLevelShaderMaterial(
|
||||
readShaderFile(depth_shader_vs).c_str(), "vertexMain",
|
||||
video::EVST_VS_1_1,
|
||||
readShaderFile(depth_shader_fs).c_str(), "pixelMain",
|
||||
video::EPST_PS_1_2, m_shadow_mix_cb);
|
||||
readShaderFile(depth_shader_vs).c_str(),
|
||||
readShaderFile(depth_shader_fs).c_str(), nullptr,
|
||||
m_shadow_mix_cb);
|
||||
|
||||
m_screen_quad->getMaterial().MaterialType =
|
||||
(video::E_MATERIAL_TYPE)mixcsm_shader;
|
||||
|
@ -655,10 +651,9 @@ void ShadowRenderer::createShaders()
|
|||
m_shadow_depth_trans_cb = new ShadowDepthShaderCB();
|
||||
|
||||
depth_shader_trans = gpu->addHighLevelShaderMaterial(
|
||||
readShaderFile(depth_shader_vs).c_str(), "vertexMain",
|
||||
video::EVST_VS_1_1,
|
||||
readShaderFile(depth_shader_fs).c_str(), "pixelMain",
|
||||
video::EPST_PS_1_2, m_shadow_depth_trans_cb);
|
||||
readShaderFile(depth_shader_vs).c_str(),
|
||||
readShaderFile(depth_shader_fs).c_str(), nullptr,
|
||||
m_shadow_depth_trans_cb);
|
||||
|
||||
if (depth_shader_trans == -1) {
|
||||
// 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();
|
||||
|
||||
setAutomaticCulling(scene::EAC_OFF);
|
||||
m_box.MaxEdge.set(0, 0, 0);
|
||||
m_box.MinEdge.set(0, 0, 0);
|
||||
|
||||
m_sky_params = SkyboxDefaults::getSkyDefaults();
|
||||
m_sun_params = SkyboxDefaults::getSunDefaults();
|
||||
|
|
|
@ -122,7 +122,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
aabb3f m_box;
|
||||
aabb3f m_box{{0.0f, 0.0f, 0.0f}};
|
||||
video::SMaterial m_materials[SKY_MATERIAL_COUNT];
|
||||
// How much sun & moon transition should affect horizon color
|
||||
float m_horizon_blend()
|
||||
|
|
|
@ -121,7 +121,6 @@ public:
|
|||
// Shall be called from the main thread.
|
||||
void rebuildImagesAndTextures();
|
||||
|
||||
video::ITexture* getNormalTexture(const std::string &name);
|
||||
video::SColor getTextureAverageColor(const std::string &name);
|
||||
|
||||
private:
|
||||
|
@ -488,40 +487,20 @@ void TextureSource::rebuildTexture(video::IVideoDriver *driver, TextureInfo &ti)
|
|||
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::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
||||
video::ITexture *texture = getTexture(name);
|
||||
if (!texture)
|
||||
return {0, 0, 0, 0};
|
||||
// Note: this downloads the texture back from the GPU, which is pointless
|
||||
video::IImage *image = driver->createImage(texture,
|
||||
core::position2d<s32>(0, 0),
|
||||
texture->getOriginalSize());
|
||||
if (!image)
|
||||
return {0, 0, 0, 0};
|
||||
|
||||
video::SColor c = ImageSource::getImageAverageColor(*image);
|
||||
video::SColor c = imageAverageColor(image);
|
||||
image->drop();
|
||||
|
||||
return c;
|
||||
|
|
|
@ -54,7 +54,6 @@ public:
|
|||
*/
|
||||
virtual Palette* getPalette(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;
|
||||
};
|
||||
|
||||
|
@ -75,7 +74,6 @@ public:
|
|||
virtual void processQueue()=0;
|
||||
virtual void insertSourceImage(const std::string &name, video::IImage *img)=0;
|
||||
virtual void rebuildImagesAndTextures()=0;
|
||||
virtual video::ITexture* getNormalTexture(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;
|
||||
|
||||
/// @return is this layer semi-transparent?
|
||||
bool isTransparent() const
|
||||
{
|
||||
// see also: the mapping in ShaderSource::generateShader()
|
||||
switch (material_type) {
|
||||
case TILE_MATERIAL_ALPHA:
|
||||
case TILE_MATERIAL_PLAIN_ALPHA:
|
||||
case TILE_MATERIAL_LIQUID_TRANSPARENT:
|
||||
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
|
||||
return true;
|
||||
|
|
|
@ -195,8 +195,7 @@ WieldMeshSceneNode::WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id):
|
|||
else
|
||||
g_extrusion_mesh_cache->grab();
|
||||
|
||||
// Disable bounding box culling for this scene node
|
||||
// since we won't calculate the bounding box.
|
||||
// This class doesn't render anything, so disable culling.
|
||||
setAutomaticCulling(scene::EAC_OFF);
|
||||
|
||||
// Create the child scene node
|
||||
|
@ -299,8 +298,7 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
|
|||
MeshMakeData mesh_make_data(client->ndef(), 1);
|
||||
MeshCollector collector(v3f(0.0f * BS), v3f());
|
||||
mesh_make_data.setSmoothLighting(false);
|
||||
MapblockMeshGenerator gen(&mesh_make_data, &collector,
|
||||
client->getSceneManager()->getMeshManipulator());
|
||||
MapblockMeshGenerator gen(&mesh_make_data, &collector);
|
||||
|
||||
if (n.getParam2()) {
|
||||
// keep it
|
||||
|
|
|
@ -134,7 +134,7 @@ private:
|
|||
// Bounding box culling is disabled for this type of scene node,
|
||||
// so this variable is just required so we can implement
|
||||
// getBoundingBox() and is set to an empty box.
|
||||
aabb3f m_bounding_box;
|
||||
aabb3f m_bounding_box{{0, 0, 0}};
|
||||
|
||||
ShadowRenderer *m_shadow;
|
||||
};
|
||||
|
|
|
@ -262,7 +262,7 @@ static void add_object_boxes(Environment *env,
|
|||
{
|
||||
auto process_object = [&cinfo] (ActiveObject *object) {
|
||||
if (object && object->collideWithObjects()) {
|
||||
aabb3f box;
|
||||
aabb3f box{{0.0f, 0.0f, 0.0f}};
|
||||
if (object->getCollisionBox(&box))
|
||||
cinfo.emplace_back(object, 0, box);
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ void set_default_settings()
|
|||
settings->setDefault("sound_extensions_blacklist", "");
|
||||
settings->setDefault("mesh_generation_interval", "0");
|
||||
settings->setDefault("mesh_generation_threads", "0");
|
||||
settings->setDefault("mesh_buffer_min_vertices", "100");
|
||||
settings->setDefault("free_move", "false");
|
||||
settings->setDefault("pitch_move", "false");
|
||||
settings->setDefault("fast_move", "false");
|
||||
|
@ -311,7 +312,7 @@ void set_default_settings()
|
|||
|
||||
// Effects
|
||||
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("inventory_items_animations", "false");
|
||||
settings->setDefault("mip_map", "false");
|
||||
|
|
|
@ -194,9 +194,9 @@ void GUIEditBoxWithScrollBar::draw()
|
|||
mbegin = font->getDimension(s.c_str()).Width;
|
||||
|
||||
// deal with kerning
|
||||
mbegin += font->getKerningWidth(
|
||||
&((*txt_line)[realmbgn - start_pos]),
|
||||
realmbgn - start_pos > 0 ? &((*txt_line)[realmbgn - start_pos - 1]) : 0);
|
||||
mbegin += font->getKerning(
|
||||
(*txt_line)[realmbgn - start_pos],
|
||||
realmbgn - start_pos > 0 ? (*txt_line)[realmbgn - start_pos - 1] : 0).X;
|
||||
|
||||
lineStartPos = realmbgn - start_pos;
|
||||
}
|
||||
|
@ -242,7 +242,8 @@ void GUIEditBoxWithScrollBar::draw()
|
|||
}
|
||||
s = txt_line->subString(0, m_cursor_pos - start_pos);
|
||||
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) {
|
||||
setTextRect(cursor_line);
|
||||
|
@ -431,7 +432,7 @@ void GUIEditBoxWithScrollBar::setTextRect(s32 line)
|
|||
d = font->getDimension(Text.c_str());
|
||||
d.Height = AbsoluteRect.getHeight();
|
||||
}
|
||||
d.Height += font->getKerningHeight();
|
||||
d.Height += font->getKerning(L'A').Y;
|
||||
|
||||
// justification
|
||||
switch (m_halign) {
|
||||
|
@ -536,7 +537,7 @@ void GUIEditBoxWithScrollBar::calculateScrollPos()
|
|||
|
||||
// calculate vertical scrolling
|
||||
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?
|
||||
if (line_height >= (irr::u32)m_frame_rect.getHeight()) {
|
||||
m_vscroll_pos = 0;
|
||||
|
|
|
@ -79,7 +79,7 @@
|
|||
*/
|
||||
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)
|
||||
|
|
|
@ -85,8 +85,8 @@ void GUIInventoryList::draw()
|
|||
v2s32 p((i % m_geom.X) * m_slot_spacing.X,
|
||||
(i / m_geom.X) * m_slot_spacing.Y);
|
||||
core::rect<s32> rect = imgrect + base_pos + p;
|
||||
ItemStack item = ilist->getItem(item_i);
|
||||
ItemStack orig_item = item;
|
||||
const ItemStack &orig_item = ilist->getItem(item_i);
|
||||
ItemStack item = orig_item;
|
||||
|
||||
bool selected = selected_item
|
||||
&& m_invmgr->getInventory(selected_item->inventoryloc) == inv
|
||||
|
@ -137,12 +137,26 @@ void GUIInventoryList::draw()
|
|||
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;
|
||||
// Make it possible to see item tooltips on touchscreens
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (show_tooltip) {
|
||||
std::string tooltip = orig_item.getDescription(client->idef());
|
||||
if (m_fs_menu->doTooltipAppendItemname())
|
||||
|
|
|
@ -29,52 +29,47 @@
|
|||
|
||||
TouchControls *g_touchcontrols;
|
||||
|
||||
static void load_button_texture(IGUIImage *gui_button, const std::string &path,
|
||||
const recti &button_rect, ISimpleTextureSource *tsrc, video::IVideoDriver *driver)
|
||||
void TouchControls::emitKeyboardEvent(EKEY_CODE keycode, bool pressed)
|
||||
{
|
||||
video::ITexture *texture = guiScalingImageButton(driver,
|
||||
tsrc->getTexture(path), button_rect.getWidth(),
|
||||
button_rect.getHeight());
|
||||
SEvent e{};
|
||||
e.EventType = EET_KEY_INPUT_EVENT;
|
||||
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->setScaleImage(true);
|
||||
}
|
||||
|
||||
void button_info::emitAction(bool action, video::IVideoDriver *driver,
|
||||
IEventReceiver *receiver, ISimpleTextureSource *tsrc)
|
||||
void TouchControls::buttonEmitAction(button_info &btn, bool action)
|
||||
{
|
||||
if (keycode == KEY_UNKNOWN)
|
||||
if (btn.keycode == KEY_UNKNOWN)
|
||||
return;
|
||||
|
||||
SEvent translated{};
|
||||
translated.EventType = EET_KEY_INPUT_EVENT;
|
||||
translated.KeyInput.Key = keycode;
|
||||
translated.KeyInput.Control = false;
|
||||
translated.KeyInput.Shift = false;
|
||||
translated.KeyInput.Char = 0;
|
||||
emitKeyboardEvent(btn.keycode, action);
|
||||
|
||||
if (action) {
|
||||
translated.KeyInput.PressedDown = true;
|
||||
receiver->OnEvent(translated);
|
||||
if (btn.toggleable == button_info::FIRST_TEXTURE) {
|
||||
btn.toggleable = button_info::SECOND_TEXTURE;
|
||||
loadButtonTexture(btn.gui_button.get(), btn.toggle_textures[1]);
|
||||
|
||||
if (toggleable == button_info::FIRST_TEXTURE) {
|
||||
toggleable = button_info::SECOND_TEXTURE;
|
||||
load_button_texture(gui_button.get(), toggle_textures[1],
|
||||
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 if (btn.toggleable == button_info::SECOND_TEXTURE) {
|
||||
btn.toggleable = button_info::FIRST_TEXTURE;
|
||||
loadButtonTexture(btn.gui_button.get(), btn.toggle_textures[0]);
|
||||
}
|
||||
} else {
|
||||
translated.KeyInput.PressedDown = false;
|
||||
receiver->OnEvent(translated);
|
||||
}
|
||||
}
|
||||
|
||||
static bool buttons_handlePress(std::vector<button_info> &buttons, size_t pointer_id, IGUIElement *element,
|
||||
video::IVideoDriver *driver, IEventReceiver *receiver, ISimpleTextureSource *tsrc)
|
||||
bool TouchControls::buttonsHandlePress(std::vector<button_info> &buttons, size_t pointer_id, IGUIElement *element)
|
||||
{
|
||||
if (!element)
|
||||
return false;
|
||||
|
@ -87,7 +82,7 @@ static bool buttons_handlePress(std::vector<button_info> &buttons, size_t pointe
|
|||
if (btn.pointer_ids.size() > 1)
|
||||
return true;
|
||||
|
||||
btn.emitAction(true, driver, receiver, tsrc);
|
||||
buttonEmitAction(btn, true);
|
||||
btn.repeat_counter = -BUTTON_REPEAT_DELAY;
|
||||
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,
|
||||
video::IVideoDriver *driver, IEventReceiver *receiver, ISimpleTextureSource *tsrc)
|
||||
bool TouchControls::buttonsHandleRelease(std::vector<button_info> &buttons, size_t pointer_id)
|
||||
{
|
||||
for (button_info &btn : buttons) {
|
||||
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())
|
||||
return true;
|
||||
|
||||
btn.emitAction(false, driver, receiver, tsrc);
|
||||
buttonEmitAction(btn, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -116,8 +110,7 @@ static bool buttons_handleRelease(std::vector<button_info> &buttons, size_t poin
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool buttons_step(std::vector<button_info> &buttons, float dtime,
|
||||
video::IVideoDriver *driver, IEventReceiver *receiver, ISimpleTextureSource *tsrc)
|
||||
bool TouchControls::buttonsStep(std::vector<button_info> &buttons, float dtime)
|
||||
{
|
||||
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)
|
||||
continue;
|
||||
|
||||
btn.emitAction(false, driver, receiver, tsrc);
|
||||
btn.emitAction(true, driver, receiver, tsrc);
|
||||
buttonEmitAction(btn, false);
|
||||
buttonEmitAction(btn, true);
|
||||
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);
|
||||
btn_gui_button->setVisible(visible);
|
||||
load_button_texture(btn_gui_button, image, rect,
|
||||
m_texturesource, m_device->getVideoDriver());
|
||||
loadButtonTexture(btn_gui_button, image);
|
||||
|
||||
button_info &btn = buttons.emplace_back();
|
||||
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);
|
||||
btn_gui_button->setVisible(visible);
|
||||
load_button_texture(btn_gui_button, button_image_names[id], rect,
|
||||
m_texturesource, m_device->getVideoDriver());
|
||||
loadButtonTexture(btn_gui_button, button_image_names[id]);
|
||||
|
||||
return btn_gui_button;
|
||||
}
|
||||
|
@ -399,11 +390,9 @@ void TouchControls::handleReleaseEvent(size_t pointer_id)
|
|||
m_pointer_pos.erase(pointer_id);
|
||||
|
||||
// handle buttons
|
||||
if (buttons_handleRelease(m_buttons, pointer_id, m_device->getVideoDriver(),
|
||||
m_receiver, m_texturesource))
|
||||
if (buttonsHandleRelease(m_buttons, pointer_id))
|
||||
return;
|
||||
if (buttons_handleRelease(m_overflow_buttons, pointer_id, m_device->getVideoDriver(),
|
||||
m_receiver, m_texturesource))
|
||||
if (buttonsHandleRelease(m_overflow_buttons, pointer_id))
|
||||
return;
|
||||
|
||||
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,
|
||||
m_device->getVideoDriver(), m_receiver, m_texturesource))
|
||||
if (buttonsHandlePress(m_overflow_buttons, pointer_id, element))
|
||||
return;
|
||||
|
||||
toggleOverflowMenu();
|
||||
|
@ -494,8 +482,7 @@ void TouchControls::translateEvent(const SEvent &event)
|
|||
}
|
||||
|
||||
// handle buttons
|
||||
if (buttons_handlePress(m_buttons, pointer_id, element,
|
||||
m_device->getVideoDriver(), m_receiver, m_texturesource))
|
||||
if (buttonsHandlePress(m_buttons, pointer_id, element))
|
||||
return;
|
||||
|
||||
// handle hotbar
|
||||
|
@ -614,16 +601,10 @@ void TouchControls::translateEvent(const SEvent &event)
|
|||
void TouchControls::applyJoystickStatus()
|
||||
{
|
||||
if (m_joystick_triggers_aux1) {
|
||||
SEvent translated{};
|
||||
translated.EventType = EET_KEY_INPUT_EVENT;
|
||||
translated.KeyInput.Key = id_to_keycode(aux1_id);
|
||||
translated.KeyInput.PressedDown = false;
|
||||
m_receiver->OnEvent(translated);
|
||||
|
||||
if (m_joystick_status_aux1) {
|
||||
translated.KeyInput.PressedDown = true;
|
||||
m_receiver->OnEvent(translated);
|
||||
}
|
||||
auto key = id_to_keycode(aux1_id);
|
||||
emitKeyboardEvent(key, false);
|
||||
if (m_joystick_status_aux1)
|
||||
emitKeyboardEvent(key, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -639,8 +620,8 @@ void TouchControls::step(float dtime)
|
|||
}
|
||||
|
||||
// simulate keyboard repeats
|
||||
buttons_step(m_buttons, dtime, m_device->getVideoDriver(), m_receiver, m_texturesource);
|
||||
buttons_step(m_overflow_buttons, dtime, m_device->getVideoDriver(), m_receiver, m_texturesource);
|
||||
buttonsStep(m_buttons, dtime);
|
||||
buttonsStep(m_overflow_buttons, dtime);
|
||||
|
||||
// joystick
|
||||
applyJoystickStatus();
|
||||
|
|
|
@ -67,9 +67,6 @@ struct button_info
|
|||
SECOND_TEXTURE
|
||||
} toggleable = NOT_TOGGLEABLE;
|
||||
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;
|
||||
|
||||
// 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 updateVisibility();
|
||||
void releaseAll();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
CGUITTFont FreeType class for Irrlicht
|
||||
Copyright (c) 2009-2010 John Norman
|
||||
with changes from Luanti contributors:
|
||||
Copyright (c) 2016 Nathanaëlle Courant
|
||||
Copyright (c) 2023 Caleb Butler
|
||||
|
||||
|
@ -31,14 +32,13 @@
|
|||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "log.h"
|
||||
#include "filesys.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "CGUITTFont.h"
|
||||
#include "CMeshBuffer.h"
|
||||
#include "IFileSystem.h"
|
||||
#include "IGUIEnvironment.h"
|
||||
#include "IMeshManipulator.h"
|
||||
#include "IMeshSceneNode.h"
|
||||
#include "ISceneManager.h"
|
||||
#include "ISceneNode.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
@ -46,9 +46,9 @@ namespace gui
|
|||
{
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
@ -56,46 +56,29 @@ struct SGUITTFace : public virtual irr::IReferenceCounted
|
|||
~SGUITTFace()
|
||||
{
|
||||
FT_Done_Face(face);
|
||||
delete[] face_buffer;
|
||||
}
|
||||
|
||||
FT_Face face;
|
||||
FT_Byte* face_buffer;
|
||||
FT_Long face_buffer_size;
|
||||
std::string face_buffer;
|
||||
};
|
||||
|
||||
// Static variables.
|
||||
FT_Library CGUITTFont::c_library;
|
||||
std::map<io::path, SGUITTFace*> CGUITTFont::c_faces;
|
||||
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
|
||||
{
|
||||
// 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.
|
||||
// Add 1 because textures are inclusive-exclusive.
|
||||
core::dimension2du d(bits.width + 1, bits.rows + 1);
|
||||
core::dimension2du texture_size;
|
||||
//core::dimension2du texture_size(bits.width + 1, bits.rows + 1);
|
||||
|
||||
// Create and load our image now.
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// TODO: error message?
|
||||
errorstream << "CGUITTFont: unknown pixel mode " << (int)bits.pixel_mode << std::endl;
|
||||
return 0;
|
||||
}
|
||||
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.
|
||||
FT_Set_Pixel_Sizes(face, 0, font_size);
|
||||
|
||||
// Attempt to load the glyph.
|
||||
if (FT_Load_Glyph(face, char_index, loadFlags) != FT_Err_Ok)
|
||||
// TODO: error message?
|
||||
auto err = FT_Load_Glyph(face, char_index, loadFlags);
|
||||
if (err != FT_Err_Ok) {
|
||||
warningstream << "SGUITTGlyph: failed to load glyph " << char_index
|
||||
<< " with error: " << (int)err << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
FT_GlyphSlot glyph = face->glyph;
|
||||
FT_Bitmap bits = glyph->bitmap;
|
||||
const FT_Bitmap &bits = glyph->bitmap;
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
if (!page)
|
||||
// TODO: add error message?
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -205,10 +187,7 @@ void SGUITTGlyph::preload(u32 char_index, FT_Face face, video::IVideoDriver* dri
|
|||
--page->available_slots;
|
||||
|
||||
// We grab the glyph bitmap here so the data won't be removed when the next glyph is loaded.
|
||||
surface = createGlyphImage(bits, driver);
|
||||
|
||||
// Set our glyph as loaded.
|
||||
isLoaded = true;
|
||||
surface = createGlyphImage(bits, parent->getDriver());
|
||||
}
|
||||
|
||||
void SGUITTGlyph::unload()
|
||||
|
@ -218,7 +197,8 @@ void SGUITTGlyph::unload()
|
|||
surface->drop();
|
||||
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.
|
||||
CGUITTFont::CGUITTFont(IGUIEnvironment *env)
|
||||
: 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)
|
||||
{
|
||||
|
||||
if (Environment)
|
||||
{
|
||||
if (env) {
|
||||
// don't grab environment, to avoid circular references
|
||||
Driver = Environment->getVideoDriver();
|
||||
Driver = env->getVideoDriver();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Some sanity checks.
|
||||
if (Environment == 0 || Driver == 0) return false;
|
||||
if (!Driver) 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->filename = filename;
|
||||
|
||||
|
@ -285,62 +261,33 @@ bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antia
|
|||
this->use_transparency = transparency;
|
||||
update_load_flags();
|
||||
|
||||
// Log.
|
||||
if (logger)
|
||||
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);
|
||||
infostream << "CGUITTFont: Creating new font: " << filename.c_str() << " "
|
||||
<< size << "pt " << (antialias ? "+antialias " : "-antialias ")
|
||||
<< (transparency ? "+transparency" : "-transparency") << std::endl;
|
||||
|
||||
// Grab the face.
|
||||
SGUITTFace* face = 0;
|
||||
SGUITTFace* face = nullptr;
|
||||
auto node = c_faces.find(filename);
|
||||
if (node == c_faces.end())
|
||||
{
|
||||
if (node == c_faces.end()) {
|
||||
face = new SGUITTFace();
|
||||
c_faces.emplace(filename, face);
|
||||
|
||||
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);
|
||||
if (!fs::ReadFile(filename.c_str(), face->face_buffer, true)) {
|
||||
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 (FT_New_Memory_Face(c_library,
|
||||
reinterpret_cast<const FT_Byte*>(face->face_buffer.data()),
|
||||
face->face_buffer.size(), 0, &face->face))
|
||||
{
|
||||
if (logger) logger->log("CGUITTFont", "FT_New_Memory_Face failed.", irr::ELL_INFORMATION);
|
||||
|
||||
c_faces.erase(filename);
|
||||
errorstream << "CGUITTFont: FT_New_Memory_Face failed." << std::endl;
|
||||
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
|
||||
{
|
||||
c_faces.emplace(filename, face);
|
||||
} else {
|
||||
// Using another instance of this face.
|
||||
face = node->second;
|
||||
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);
|
||||
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.
|
||||
Glyphs.clear();
|
||||
Glyphs.reallocate(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.
|
||||
u32 old_size = batch_load_size;
|
||||
|
@ -444,7 +383,7 @@ CGUITTGlyphPage* CGUITTFont::getLastGlyphPage() const
|
|||
return page;
|
||||
}
|
||||
|
||||
CGUITTGlyphPage* CGUITTFont::createGlyphPage(const u8& pixel_mode)
|
||||
CGUITTGlyphPage* CGUITTFont::createGlyphPage(const u8 pixel_mode)
|
||||
{
|
||||
CGUITTGlyphPage* page = 0;
|
||||
|
||||
|
@ -481,7 +420,8 @@ CGUITTGlyphPage* CGUITTFont::createGlyphPage(const u8& pixel_mode)
|
|||
page_texture_size = max_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;
|
||||
return 0;
|
||||
}
|
||||
|
@ -622,13 +562,12 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
|
|||
else if (fallback != 0)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// Apply kerning.
|
||||
offset.X += fallback->getKerningWidth(l1, &l2);
|
||||
offset.Y += fallback->getKerningHeight();
|
||||
offset += fallback->getKerning(*l1, (wchar_t) previousChar);
|
||||
|
||||
const u32 current_color = iter - utext.begin();
|
||||
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
|
||||
{
|
||||
return getDimension(convertWCharToU32String(text));
|
||||
|
@ -759,21 +693,12 @@ core::dimension2d<u32> CGUITTFont::getDimension(const std::u32string& text) cons
|
|||
return text_dimension;
|
||||
}
|
||||
|
||||
inline u32 CGUITTFont::getWidthFromCharacter(wchar_t c) const
|
||||
{
|
||||
return getWidthFromCharacter((char32_t)c);
|
||||
}
|
||||
|
||||
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);
|
||||
if (n > 0)
|
||||
{
|
||||
int w = Glyphs[n-1].advance.x / 64;
|
||||
int w = Glyphs[n-1].advance.X / 64;
|
||||
return w;
|
||||
}
|
||||
if (fallback != 0)
|
||||
|
@ -787,17 +712,8 @@ inline u32 CGUITTFont::getWidthFromCharacter(char32_t c) const
|
|||
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
|
||||
{
|
||||
// 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);
|
||||
if (n > 0)
|
||||
{
|
||||
|
@ -816,11 +732,6 @@ inline u32 CGUITTFont::getHeightFromCharacter(char32_t c) const
|
|||
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
|
||||
{
|
||||
// Get the glyph.
|
||||
|
@ -831,7 +742,7 @@ u32 CGUITTFont::getGlyphIndexByChar(char32_t c) const
|
|||
return 0;
|
||||
|
||||
// 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;
|
||||
|
||||
// Determine our batch loading positions.
|
||||
|
@ -850,9 +761,10 @@ u32 CGUITTFont::getGlyphIndexByChar(char32_t c) const
|
|||
if (char_index)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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 x = 0;
|
||||
//s32 idx = 0;
|
||||
|
||||
u32 character = 0;
|
||||
char32_t previousChar = 0;
|
||||
std::u32string::const_iterator iter = text.begin();
|
||||
auto iter = text.begin();
|
||||
while (iter != text.end())
|
||||
{
|
||||
char32_t c = *iter;
|
||||
|
@ -906,28 +817,6 @@ void CGUITTFont::setKerningHeight(s32 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
|
||||
{
|
||||
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 (n == 0)
|
||||
{
|
||||
if (fallback != 0) {
|
||||
wchar_t l1 = (wchar_t) thisLetter, l2 = (wchar_t) previousLetter;
|
||||
ret.X = fallback->getKerningWidth(&l1, &l2);
|
||||
ret.Y = fallback->getKerningHeight();
|
||||
}
|
||||
if (fallback)
|
||||
ret = fallback->getKerning((wchar_t) thisLetter, (wchar_t) previousLetter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1029,196 +915,6 @@ video::ITexture* CGUITTFont::getPageTextureByIndex(const u32& page_index) const
|
|||
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
|
||||
{
|
||||
static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "unexpected wchar size");
|
||||
|
|
|
@ -32,17 +32,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <ft2build.h>
|
||||
#include <map>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#include "IGUIEnvironment.h"
|
||||
#include "IGUIFont.h"
|
||||
#include "ISceneManager.h"
|
||||
#include "IVideoDriver.h"
|
||||
#include "IrrlichtDevice.h"
|
||||
#include "SMesh.h"
|
||||
#include "util/enriched_string.h"
|
||||
#include "util/basic_macros.h"
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
@ -56,26 +56,22 @@ namespace gui
|
|||
{
|
||||
//! Constructor.
|
||||
SGUITTGlyph() :
|
||||
isLoaded(false),
|
||||
glyph_page(0),
|
||||
source_rect(),
|
||||
offset(),
|
||||
advance(),
|
||||
surface(0),
|
||||
parent(0)
|
||||
surface(0)
|
||||
{}
|
||||
|
||||
DISABLE_CLASS_COPY(SGUITTGlyph);
|
||||
|
||||
//! This class would be trivially copyable except for the reference count on `surface`.
|
||||
SGUITTGlyph(SGUITTGlyph &&other) noexcept :
|
||||
isLoaded(other.isLoaded),
|
||||
glyph_page(other.glyph_page),
|
||||
source_rect(other.source_rect),
|
||||
offset(other.offset),
|
||||
advance(other.advance),
|
||||
surface(other.surface),
|
||||
parent(other.parent)
|
||||
surface(other.surface)
|
||||
{
|
||||
other.surface = 0;
|
||||
}
|
||||
|
@ -83,12 +79,17 @@ namespace gui
|
|||
//! Destructor.
|
||||
~SGUITTGlyph() { unload(); }
|
||||
|
||||
//! If true, the glyph has been loaded.
|
||||
inline bool isLoaded() const {
|
||||
return source_rect != core::recti();
|
||||
}
|
||||
|
||||
//! Preload the glyph.
|
||||
//! 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
|
||||
//! textures if necessary. The actual creation of the textures should only occur right
|
||||
//! 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.
|
||||
void unload();
|
||||
|
@ -96,9 +97,6 @@ namespace gui
|
|||
//! Creates the IImage object from the FT_Bitmap.
|
||||
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.
|
||||
u32 glyph_page;
|
||||
|
||||
|
@ -109,14 +107,11 @@ namespace gui
|
|||
core::vector2di offset;
|
||||
|
||||
//! Glyph advance information.
|
||||
FT_Vector advance;
|
||||
core::vector2di advance;
|
||||
|
||||
//! This is just the temporary image holder. After this glyph is paged,
|
||||
//! it will be dropped.
|
||||
mutable video::IImage* surface;
|
||||
|
||||
//! The pointer pointing to the parent (CGUITTFont)
|
||||
CGUITTFont* parent;
|
||||
};
|
||||
|
||||
//! Holds a sheet of glyphs.
|
||||
|
@ -130,7 +125,8 @@ namespace gui
|
|||
{
|
||||
if (driver)
|
||||
driver->removeTexture(texture);
|
||||
else texture->drop();
|
||||
else
|
||||
texture->drop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,20 +180,12 @@ namespace gui
|
|||
for (u32 i = 0; i < glyph_to_be_paged.size(); ++i)
|
||||
{
|
||||
const SGUITTGlyph* glyph = glyph_to_be_paged[i];
|
||||
if (glyph && glyph->isLoaded)
|
||||
{
|
||||
if (glyph->surface)
|
||||
if (glyph && glyph->surface)
|
||||
{
|
||||
glyph->surface->copyTo(pageholder, glyph->source_rect.UpperLeftCorner);
|
||||
glyph->surface->drop();
|
||||
glyph->surface = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
; // TODO: add error message?
|
||||
//currently, if we failed to create the image, just ignore this operation.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pageholder->drop();
|
||||
|
@ -238,77 +226,70 @@ namespace gui
|
|||
virtual ~CGUITTFont();
|
||||
|
||||
//! 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.
|
||||
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.
|
||||
virtual u32 getFontSize() const { return size; }
|
||||
u32 getFontSize() const { return size; }
|
||||
|
||||
//! 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.
|
||||
//! 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.
|
||||
virtual bool useHinting() const { return use_hinting; }
|
||||
bool useHinting() const { return use_hinting; }
|
||||
|
||||
//! 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.
|
||||
virtual bool useMonochrome() const { return use_monochrome; }
|
||||
bool useMonochrome() const { return use_monochrome; }
|
||||
|
||||
//! Tells the font to allow transparency when rendering.
|
||||
//! Default: true.
|
||||
//! \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.
|
||||
//! Default: false.
|
||||
//! \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.
|
||||
//! Default: Hinting and auto-hinting true.
|
||||
//! \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.
|
||||
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.
|
||||
virtual void draw(const core::stringw& text, const core::rect<s32>& position,
|
||||
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,
|
||||
bool hcenter=false, bool vcenter=false,
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
virtual void setKerningWidth(s32 kerning);
|
||||
virtual void setKerningWidth(s32 kerning) override;
|
||||
|
||||
//! Sets global kerning height for the font.
|
||||
virtual void setKerningHeight(s32 kerning);
|
||||
|
||||
//! 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;
|
||||
virtual void setKerningHeight(s32 kerning) override;
|
||||
|
||||
//! 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.
|
||||
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.
|
||||
//! If not, it will return zero.
|
||||
|
@ -317,7 +298,7 @@ namespace gui
|
|||
//! Create a new glyph page texture.
|
||||
//! \param pixel_mode the pixel mode defined by FT_Pixel_Mode
|
||||
//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.
|
||||
u32 getLastGlyphPageIndex() const { return Glyph_Pages.size() - 1; }
|
||||
|
@ -328,16 +309,13 @@ namespace gui
|
|||
//! Create corresponding character's software image copy from the font,
|
||||
//! so you can use this data just like any ordinary video::IImage.
|
||||
//! \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.
|
||||
//! \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.
|
||||
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 video::IVideoDriver *getDriver() const { return Driver; }
|
||||
|
||||
inline s32 getAscender() const { return font_metrics.ascender; }
|
||||
|
||||
|
@ -355,8 +333,6 @@ namespace gui
|
|||
static FT_Library c_library;
|
||||
static std::map<io::path, SGUITTFace*> c_faces;
|
||||
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
|
||||
// (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;
|
||||
else load_flags |= FT_LOAD_TARGET_NORMAL;
|
||||
}
|
||||
u32 getWidthFromCharacter(wchar_t c) const;
|
||||
u32 getWidthFromCharacter(char32_t c) const;
|
||||
u32 getHeightFromCharacter(wchar_t c) const;
|
||||
u32 getHeightFromCharacter(char32_t c) const;
|
||||
u32 getGlyphIndexByChar(wchar_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::dimension2d<u32> getDimensionUntilEndOfLine(const wchar_t* p) const;
|
||||
|
||||
void createSharedPlane();
|
||||
|
||||
irr::IrrlichtDevice* Device;
|
||||
gui::IGUIEnvironment* Environment;
|
||||
video::IVideoDriver* Driver;
|
||||
io::path filename;
|
||||
FT_Face tt_face;
|
||||
|
|
|
@ -74,7 +74,7 @@ void StaticText::draw()
|
|||
updateText();
|
||||
|
||||
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();
|
||||
if (VAlign == EGUIA_CENTER && WordWrap)
|
||||
{
|
||||
|
@ -546,7 +546,7 @@ s32 StaticText::getTextHeight() const
|
|||
return 0;
|
||||
|
||||
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();
|
||||
}
|
||||
// There may be intentional new lines without WordWrap
|
||||
|
|
|
@ -88,12 +88,11 @@ void ItemStackMetadata::deSerialize(std::istream &is)
|
|||
void ItemStackMetadata::updateToolCapabilities()
|
||||
{
|
||||
if (contains(TOOLCAP_KEY)) {
|
||||
toolcaps_overridden = true;
|
||||
toolcaps_override = ToolCapabilities();
|
||||
std::istringstream is(getString(TOOLCAP_KEY));
|
||||
toolcaps_override.deserializeJson(is);
|
||||
toolcaps_override->deserializeJson(is);
|
||||
} else {
|
||||
toolcaps_overridden = false;
|
||||
toolcaps_override = std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@ class IItemDefManager;
|
|||
class ItemStackMetadata : public SimpleMetadata
|
||||
{
|
||||
public:
|
||||
ItemStackMetadata():
|
||||
toolcaps_overridden(false)
|
||||
ItemStackMetadata()
|
||||
{}
|
||||
|
||||
// Overrides
|
||||
|
@ -29,7 +28,7 @@ public:
|
|||
const ToolCapabilities &getToolCapabilities(
|
||||
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);
|
||||
|
@ -40,7 +39,6 @@ public:
|
|||
return wear_bar_override;
|
||||
}
|
||||
|
||||
|
||||
void setWearBarParams(const WearBarParams ¶ms);
|
||||
void clearWearBarParams();
|
||||
|
||||
|
@ -48,7 +46,6 @@ private:
|
|||
void updateToolCapabilities();
|
||||
void updateWearBarParams();
|
||||
|
||||
bool toolcaps_overridden;
|
||||
ToolCapabilities toolcaps_override;
|
||||
std::optional<ToolCapabilities> toolcaps_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