textures.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. -- Node texture tests
  2. local S = core.get_translator("testnodes")
  3. core.register_node("testnodes:6sides", {
  4. description = S("Six Textures Test Node").."\n"..
  5. S("Has 1 texture per face"),
  6. tiles = {
  7. "testnodes_normal1.png",
  8. "testnodes_normal2.png",
  9. "testnodes_normal3.png",
  10. "testnodes_normal4.png",
  11. "testnodes_normal5.png",
  12. "testnodes_normal6.png",
  13. },
  14. groups = { dig_immediate = 2 },
  15. })
  16. core.register_node("testnodes:anim", {
  17. description = S("Animated Test Node").."\n"..
  18. S("Tiles animate from A to D in 4s cycle"),
  19. tiles = {
  20. { name = "testnodes_anim.png",
  21. animation = {
  22. type = "vertical_frames",
  23. aspect_w = 16,
  24. aspect_h = 16,
  25. length = 4.0,
  26. }, },
  27. },
  28. groups = { dig_immediate = 2 },
  29. })
  30. core.register_node("testnodes:fill_positioning", {
  31. description = S("Fill Modifier Test Node") .. "\n" ..
  32. S("The node should have the same look as " ..
  33. "testnodes:fill_positioning_reference."),
  34. drawtype = "glasslike",
  35. paramtype = "light",
  36. tiles = {"[fill:16x16:#ffffff^[fill:6x6:1,1:#00ffdc" ..
  37. "^[fill:6x6:1,9:#00ffdc^[fill:6x6:9,1:#00ffdc^[fill:6x6:9,9:#00ffdc"},
  38. groups = {dig_immediate = 3},
  39. })
  40. core.register_node("testnodes:fill_positioning_reference", {
  41. description = S("Fill Modifier Test Node Reference"),
  42. drawtype = "glasslike",
  43. paramtype = "light",
  44. tiles = {"testnodes_fill_positioning_reference.png"},
  45. groups = {dig_immediate = 3},
  46. })
  47. core.register_node("testnodes:modifier_mask", {
  48. description = S("[mask Modifier Test Node"),
  49. tiles = {"testnodes_128x128_rgb.png^[mask:testnodes_mask_WRGBKW.png"},
  50. groups = {dig_immediate = 3},
  51. })
  52. -- Node texture transparency test
  53. local alphas = { 64, 128, 191 }
  54. for a=1,#alphas do
  55. local alpha = alphas[a]
  56. -- Transparency taken from texture
  57. core.register_node("testnodes:alpha_texture_"..alpha, {
  58. description = S("Texture Alpha Test Node (@1)", alpha).."\n"..
  59. S("Semi-transparent"),
  60. drawtype = "glasslike",
  61. paramtype = "light",
  62. tiles = {
  63. "testnodes_alpha"..alpha..".png",
  64. },
  65. use_texture_alpha = "blend",
  66. groups = { dig_immediate = 3 },
  67. })
  68. -- Transparency set via texture modifier
  69. core.register_node("testnodes:alpha_"..alpha, {
  70. description = S("Alpha Test Node (@1)", alpha).."\n"..
  71. S("Semi-transparent"),
  72. drawtype = "glasslike",
  73. paramtype = "light",
  74. tiles = {
  75. "testnodes_alpha.png^[opacity:" .. alpha,
  76. },
  77. use_texture_alpha = "blend",
  78. groups = { dig_immediate = 3 },
  79. })
  80. end
  81. core.register_node("testnodes:alpha_compositing", {
  82. description = S("Texture Overlay Test Node") .. "\n" ..
  83. S("A regular grid should be visible where each cell contains two " ..
  84. "texels with the same color.") .. "\n" ..
  85. S("Texture overlay is gamma-incorrect, " ..
  86. "and in general it does not do alpha compositing, " ..
  87. "both for backwards compatibility."),
  88. drawtype = "glasslike",
  89. paramtype = "light",
  90. tiles = {"testnodes_alpha_compositing_bottom.png^" ..
  91. "testnodes_alpha_compositing_top.png"},
  92. use_texture_alpha = "blend",
  93. groups = {dig_immediate = 3},
  94. })
  95. -- Generate PNG textures
  96. local function mandelbrot(w, h, iterations)
  97. local r = {}
  98. for y=0, h-1 do
  99. for x=0, w-1 do
  100. local re = (x - w/2) * 4/w
  101. local im = (y - h/2) * 4/h
  102. -- zoom in on a nice view
  103. re = re / 128 - 0.23
  104. im = im / 128 - 0.82
  105. local px, py = 0, 0
  106. local i = 0
  107. while px*px + py*py <= 4 and i < iterations do
  108. px, py = px*px - py*py + re, 2 * px * py + im
  109. i = i + 1
  110. end
  111. r[w*y+x+1] = i / iterations
  112. end
  113. end
  114. return r
  115. end
  116. local function gen_checkers(w, h, tile)
  117. local r = {}
  118. for y=0, h-1 do
  119. for x=0, w-1 do
  120. local hori = math.floor(x / tile) % 2 == 0
  121. local vert = math.floor(y / tile) % 2 == 0
  122. r[w*y+x+1] = hori ~= vert and 1 or 0
  123. end
  124. end
  125. return r
  126. end
  127. -- The engine should perform color reduction of the generated PNG in certain
  128. -- cases, so we have this helper to check the result
  129. local function encode_and_check(w, h, ctype, data)
  130. local ret = core.encode_png(w, h, data)
  131. assert(ret:sub(1, 8) == "\137PNG\r\n\026\n", "missing png signature")
  132. assert(ret:sub(9, 16) == "\000\000\000\rIHDR", "didn't find ihdr chunk")
  133. local ctype_actual = ret:byte(26) -- Color Type (1 byte)
  134. ctype = ({rgba=6, rgb=2, gray=0})[ctype]
  135. assert(ctype_actual == ctype, "png should have color type " .. ctype ..
  136. " but actually has " .. ctype_actual)
  137. return ret
  138. end
  139. local fractal = mandelbrot(512, 512, 128)
  140. local frac_emb = mandelbrot(64, 64, 64)
  141. local checker = gen_checkers(512, 512, 32)
  142. local floor = math.floor
  143. local abs = math.abs
  144. local data_emb = {}
  145. local data_mb = {}
  146. local data_ck = {}
  147. for i=1, #frac_emb do
  148. data_emb[i] = {
  149. r = floor(abs(frac_emb[i] * 2 - 1) * 255),
  150. g = floor(abs(1 - frac_emb[i]) * 255),
  151. b = floor(frac_emb[i] * 255),
  152. a = frac_emb[i] < 0.95 and 255 or 0,
  153. }
  154. end
  155. for i=1, #fractal do
  156. data_mb[i] = {
  157. r = floor(fractal[i] * 255),
  158. g = floor(abs(fractal[i] * 2 - 1) * 255),
  159. b = floor(abs(1 - fractal[i]) * 255),
  160. a = 255,
  161. }
  162. data_ck[i] = checker[i] > 0 and "#888" or "#000"
  163. end
  164. fractal = nil
  165. frac_emb = nil
  166. checker = nil
  167. local textures_path = core.get_worldpath() .. "/"
  168. core.safe_file_write(
  169. textures_path .. "testnodes1.png",
  170. encode_and_check(512, 512, "rgb", data_mb)
  171. )
  172. local png_ck = encode_and_check(512, 512, "gray", data_ck)
  173. core.dynamic_add_media({
  174. filename = "testnodes_generated_mb.png",
  175. filepath = textures_path .. "testnodes1.png"
  176. })
  177. core.dynamic_add_media({
  178. filename = "testnodes_generated_ck.png",
  179. filedata = png_ck,
  180. })
  181. core.register_node("testnodes:generated_png_mb", {
  182. description = S("Generated Mandelbrot PNG Test Node"),
  183. tiles = { "testnodes_generated_mb.png" },
  184. groups = { dig_immediate = 2 },
  185. })
  186. core.register_node("testnodes:generated_png_ck", {
  187. description = S("Generated Checker PNG Test Node"),
  188. tiles = { "testnodes_generated_ck.png" },
  189. groups = { dig_immediate = 2 },
  190. })
  191. local png_emb = "[png:" .. core.encode_base64(
  192. encode_and_check(64, 64, "rgba", data_emb))
  193. core.register_node("testnodes:generated_png_emb", {
  194. description = S("Generated In-Band Mandelbrot PNG Test Node"),
  195. tiles = { png_emb },
  196. drawtype = "allfaces", -- required because of transparent pixels
  197. use_texture_alpha = "clip",
  198. paramtype = "light",
  199. groups = { dig_immediate = 2 },
  200. })
  201. core.register_node("testnodes:generated_png_src_emb", {
  202. description = S("Generated In-Band Source Blit Mandelbrot PNG Test Node"),
  203. tiles = { png_emb .. "^testnodes_damage_neg.png" },
  204. drawtype = "allfaces", -- required because of transparent pixels
  205. use_texture_alpha = "clip",
  206. paramtype = "light",
  207. groups = { dig_immediate = 2 },
  208. })
  209. core.register_node("testnodes:generated_png_dst_emb", {
  210. description = S("Generated In-Band Dest Blit Mandelbrot PNG Test Node"),
  211. tiles = { "testnodes_generated_ck.png^" .. png_emb },
  212. groups = { dig_immediate = 2 },
  213. })
  214. png_ck = nil
  215. png_emb = nil
  216. data_emb = nil
  217. data_mb = nil
  218. data_ck = nil
  219. --[[
  220. The following nodes can be used to demonstrate the TGA format support.
  221. Luanti supports TGA types 1, 2, 3 & 10. While adding the support for
  222. TGA type 9 (RLE-compressed, color-mapped) is easy, it is not advisable
  223. to do so, as it is not backwards compatible with any engine version pre-5.5;
  224. content creators should therefore either use TGA type 1 or 10, or PNG.
  225. TODO: Types 1, 2 & 10 should have two test nodes each (i.e. bottom-top
  226. and top-bottom) for 16bpp (A1R5G5B5), 24bpp (B8G8R8), 32bpp (B8G8R8A8)
  227. colors.
  228. Note: Luanti requires the optional TGA footer for a texture to load.
  229. If a TGA image does not load in Luanti, append eight (8) null bytes,
  230. then the string “TRUEVISION-XFILE.”, then another null byte.
  231. ]]--
  232. core.register_node("testnodes:tga_type1_24bpp_bt", {
  233. description = S("TGA Type 1 (color-mapped RGB) 24bpp bottom-top Test Node"),
  234. drawtype = "glasslike",
  235. paramtype = "light",
  236. sunlight_propagates = true,
  237. tiles = { "testnodes_tga_type1_24bpp_bt.tga" },
  238. groups = { dig_immediate = 2 },
  239. })
  240. core.register_node("testnodes:tga_type1_24bpp_tb", {
  241. description = S("TGA Type 1 (color-mapped RGB) 24bpp top-bottom Test Node"),
  242. drawtype = "glasslike",
  243. paramtype = "light",
  244. sunlight_propagates = true,
  245. tiles = { "testnodes_tga_type1_24bpp_tb.tga" },
  246. groups = { dig_immediate = 2 },
  247. })
  248. core.register_node("testnodes:tga_type2_16bpp_bt", {
  249. description = S("TGA Type 2 (uncompressed RGB) 16bpp bottom-top Test Node"),
  250. drawtype = "glasslike",
  251. paramtype = "light",
  252. sunlight_propagates = true,
  253. tiles = { "testnodes_tga_type2_16bpp_bt.tga" },
  254. use_texture_alpha = "clip",
  255. groups = { dig_immediate = 2 },
  256. })
  257. core.register_node("testnodes:tga_type2_16bpp_tb", {
  258. description = S("TGA Type 2 (uncompressed RGB) 16bpp top-bottom Test Node"),
  259. drawtype = "glasslike",
  260. paramtype = "light",
  261. sunlight_propagates = true,
  262. tiles = { "testnodes_tga_type2_16bpp_tb.tga" },
  263. use_texture_alpha = "clip",
  264. groups = { dig_immediate = 2 },
  265. })
  266. core.register_node("testnodes:tga_type2_32bpp_bt", {
  267. description = S("TGA Type 2 (uncompressed RGB) 32bpp bottom-top Test Node"),
  268. drawtype = "glasslike",
  269. paramtype = "light",
  270. sunlight_propagates = true,
  271. tiles = { "testnodes_tga_type2_32bpp_bt.tga" },
  272. use_texture_alpha = "blend",
  273. groups = { dig_immediate = 2 },
  274. })
  275. core.register_node("testnodes:tga_type2_32bpp_tb", {
  276. description = S("TGA Type 2 (uncompressed RGB) 32bpp top-bottom Test Node"),
  277. drawtype = "glasslike",
  278. paramtype = "light",
  279. sunlight_propagates = true,
  280. tiles = { "testnodes_tga_type2_32bpp_tb.tga" },
  281. use_texture_alpha = "blend",
  282. groups = { dig_immediate = 2 },
  283. })
  284. core.register_node("testnodes:tga_type3_16bpp_bt", {
  285. description = S("TGA Type 3 (uncompressed grayscale) 16bpp bottom-top Test Node"),
  286. drawtype = "glasslike",
  287. paramtype = "light",
  288. sunlight_propagates = true,
  289. tiles = { "testnodes_tga_type3_16bpp_bt.tga" },
  290. use_texture_alpha = "blend",
  291. groups = { dig_immediate = 2 },
  292. })
  293. core.register_node("testnodes:tga_type3_16bpp_tb", {
  294. description = S("TGA Type 3 (uncompressed grayscale) 16bpp top-bottom Test Node"),
  295. drawtype = "glasslike",
  296. paramtype = "light",
  297. sunlight_propagates = true,
  298. tiles = { "testnodes_tga_type3_16bpp_tb.tga" },
  299. use_texture_alpha = "blend",
  300. groups = { dig_immediate = 2 },
  301. })
  302. core.register_node("testnodes:tga_type10_32bpp_bt", {
  303. description = S("TGA Type 10 (RLE-compressed RGB) 32bpp bottom-top Test Node"),
  304. tiles = { "testnodes_tga_type10_32bpp_bt.tga" },
  305. drawtype = "glasslike",
  306. paramtype = "light",
  307. sunlight_propagates = true,
  308. use_texture_alpha = "blend",
  309. groups = { dig_immediate = 2 },
  310. })
  311. core.register_node("testnodes:tga_type10_32bpp_tb", {
  312. description = S("TGA Type 10 (RLE-compressed RGB) 32bpp top-bottom Test Node"),
  313. drawtype = "glasslike",
  314. paramtype = "light",
  315. sunlight_propagates = true,
  316. tiles = { "testnodes_tga_type10_32bpp_tb.tga" },
  317. use_texture_alpha = "blend",
  318. groups = { dig_immediate = 2 },
  319. })