Difference between revisions of "Gradients (日本語)"

(Created page with "==gradient== === 概要 === <source lang="lua">gradient {color1, color2, color3, ..., direction = 'horizontal' or 'vertical'}</source> 引数テーブルの "direction" によ...")
 
m
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
==gradient==
+
== gradient (Mesh 版) ==
 +
=== 概要 ===
 +
<source lang="lua">mesh = gradientMesh( direction, color1, color2, ... )</source>
 +
階調度全体を一定間隔で均一に配置を行った配色テーブルからグラデーションのオブジェクト (中身は [[Mesh (日本語)|Mesh]]) を作成します。 これは後述のグラデーション関数よりも性能が良いです。
 +
=== 引数 ===
 +
{{param|string|direction|グラデーションの方向 ('''horizontal''' または '''vertical''')。}}
 +
{{param|table|color1|最初の配色テーブル。}}
 +
{{param|table|color2|第二の配色テーブル。}}
 +
{{param|table|...|追加の配色テーブル。}}
 +
=== 返値 ===
 +
{{param|Mesh|mesh|gradient オブジェクト。}}
 +
=== ソース ===
 +
<source lang="lua">
 +
-- 色の乗算
 +
local COLOR_MUL = love._version >= "11.0" and 1 or 255
 +
 
 +
function gradientMesh(dir, ...)
 +
    -- 方向の判定
 +
    local isHorizontal = true
 +
    if dir == "vertical" then
 +
        isHorizontal = false
 +
    elseif dir ~= "horizontal" then
 +
        error("bad argument #1 to 'gradient' (invalid value)", 2)
 +
    end
 +
 
 +
    -- 色の判定
 +
    local colorLen = select("#", ...)
 +
    if colorLen < 2 then
 +
        error("color list is less than two", 2)
 +
    end
 +
 
 +
    -- メッシュの生成
 +
    local meshData = {}
 +
    if isHorizontal then
 +
        for i = 1, colorLen do
 +
            local color = select(i, ...)
 +
            local x = (i - 1) / (colorLen - 1)
 +
 
 +
            meshData[#meshData + 1] = {x, 1, x, 1, color[1], color[2], color[3], color[4] or (1 * COLOR_MUL)}
 +
            meshData[#meshData + 1] = {x, 0, x, 0, color[1], color[2], color[3], color[4] or (1 * COLOR_MUL)}
 +
        end
 +
    else
 +
        for i = 1, colorLen do
 +
            local color = select(i, ...)
 +
            local y = (i - 1) / (colorLen - 1)
 +
 
 +
            meshData[#meshData + 1] = {1, y, 1, y, color[1], color[2], color[3], color[4] or (1 * COLOR_MUL)}
 +
            meshData[#meshData + 1] = {0, y, 0, y, color[1], color[2], color[3], color[4] or (1 * COLOR_MUL)}
 +
        end
 +
    end
 +
 
 +
    -- 1x1 の画像寸法から成るメッシュを返します
 +
    return love.graphics.newMesh(meshData, "strip", "static")
 +
end
 +
</source>
 +
 
 +
=== 注釈 ===
 +
生成された [[Mesh (日本語)|Mesh]] の寸法は 1x1 となります。グラデーションの寸法は [[love.graphics.draw (日本語)|love.graphics.draw]] の尺度係数で決定されます。この異形を使うときは後述の [[#drawinrect|drawinrect]] 関数は不要です (本当に使用する必要はありません)。
 +
 
 +
== gradient (Image 版) ==
 
=== 概要 ===
 
=== 概要 ===
 
<source lang="lua">gradient {color1, color2, color3, ..., direction = 'horizontal' or 'vertical'}</source>
 
<source lang="lua">gradient {color1, color2, color3, ..., direction = 'horizontal' or 'vertical'}</source>
引数テーブルの "direction" により指定された方向へ、階調度全体を一定間隔で均一に配置を行った配色テーブルからグラデーションのオブジェクト (実際は単なる画像) を作成します。
+
引数テーブルの "direction" により指定された方向へ、階調度全体を一定間隔で均一に配置を行った配色テーブルからグラデーションのオブジェクト (中身は [[Image (日本語)|Image]]) を作成します。
===Source===
+
=== ソース ===
 
<source lang="lua">
 
<source lang="lua">
 
function gradient(colors)
 
function gradient(colors)
Line 12: Line 71:
 
         direction = false
 
         direction = false
 
     else
 
     else
         error("Invalid direction '" .. tostring(direction) "' for gradient.  Horizontal or vertical expected.")
+
         error("Invalid direction '" .. tostring(direction) .. "' for gradient.  Horizontal or vertical expected.")
 
     end
 
     end
 
     local result = love.image.newImageData(direction and 1 or #colors, direction and #colors or 1)
 
     local result = love.image.newImageData(direction and 1 or #colors, direction and #colors or 1)
Line 29: Line 88:
 
end
 
end
 
</source>
 
</source>
==drawinrect==
+
 
 +
== drawinrect ==
 
=== 概要 ===
 
=== 概要 ===
 
<source lang="lua">drawinrect(img, x, y, w, h, r, ox, oy, kx, ky)</source>
 
<source lang="lua">drawinrect(img, x, y, w, h, r, ox, oy, kx, ky)</source>
Line 40: Line 100:
 
end
 
end
 
</source>
 
</source>
 +
 
== 用例 ==
 
== 用例 ==
 +
=== drawing horizontal rainbow that fills the entire screen using Mesh variant ===
 +
<source lang="lua">
 +
-- assume you already have gradientMesh function
 +
local rainbow
 +
 +
function love.load()
 +
    rainbow = gradientMesh("horizontal",
 +
        {255, 0, 0};
 +
        {255, 255, 0};
 +
        {0, 255, 0};
 +
        {0, 255, 255};
 +
        {0, 0, 255};
 +
        {255, 0, 0};
 +
    )
 +
end
 +
 +
function love.draw()
 +
    love.graphics.draw(rainbow, 0, 0, 0, love.graphics.getDimensions())
 +
end
 +
</source>
 +
 
=== 画面中央に 100 x 100 ピクセルの水平方向の虹 (すなわち、上部は赤であり、下部は紫) を描画します。 ===
 
=== 画面中央に 100 x 100 ピクセルの水平方向の虹 (すなわち、上部は赤であり、下部は紫) を描画します。 ===
 
<source lang="lua">
 
<source lang="lua">
Line 59: Line 141:
 
end
 
end
 
</source>
 
</source>
 +
 
=== 画面全体を塗りつぶす垂直方向の白黒領域 (すなわち、左部は黒であり、右部は白) を描画します。 ===
 
=== 画面全体を塗りつぶす垂直方向の白黒領域 (すなわち、左部は黒であり、右部は白) を描画します。 ===
 
<source lang="lua">
 
<source lang="lua">
Line 75: Line 158:
 
[[Category:Snippets (日本語)]]
 
[[Category:Snippets (日本語)]]
 
{{#set:Author=SelectricSimian}}
 
{{#set:Author=SelectricSimian}}
 +
{{#set:LOVE Version=any}}
 
{{#set:Description=画像と補間を使用してグラデーションを高速描画します。}}
 
{{#set:Description=画像と補間を使用してグラデーションを高速描画します。}}

Latest revision as of 09:52, 17 December 2019

gradient (Mesh 版)

概要

mesh = gradientMesh( direction, color1, color2, ... )

階調度全体を一定間隔で均一に配置を行った配色テーブルからグラデーションのオブジェクト (中身は Mesh) を作成します。 これは後述のグラデーション関数よりも性能が良いです。

引数

string direction
グラデーションの方向 (horizontal または vertical)。
table color1
最初の配色テーブル。
table color2
第二の配色テーブル。
table ...
追加の配色テーブル。

返値

Mesh mesh
gradient オブジェクト。

ソース

-- 色の乗算
local COLOR_MUL = love._version >= "11.0" and 1 or 255

function gradientMesh(dir, ...)
    -- 方向の判定
    local isHorizontal = true
    if dir == "vertical" then
        isHorizontal = false
    elseif dir ~= "horizontal" then
        error("bad argument #1 to 'gradient' (invalid value)", 2)
    end

    -- 色の判定
    local colorLen = select("#", ...)
    if colorLen < 2 then
        error("color list is less than two", 2)
    end

    -- メッシュの生成
    local meshData = {}
    if isHorizontal then
        for i = 1, colorLen do
            local color = select(i, ...)
            local x = (i - 1) / (colorLen - 1)

            meshData[#meshData + 1] = {x, 1, x, 1, color[1], color[2], color[3], color[4] or (1 * COLOR_MUL)}
            meshData[#meshData + 1] = {x, 0, x, 0, color[1], color[2], color[3], color[4] or (1 * COLOR_MUL)}
        end
    else
        for i = 1, colorLen do
            local color = select(i, ...)
            local y = (i - 1) / (colorLen - 1)

            meshData[#meshData + 1] = {1, y, 1, y, color[1], color[2], color[3], color[4] or (1 * COLOR_MUL)}
            meshData[#meshData + 1] = {0, y, 0, y, color[1], color[2], color[3], color[4] or (1 * COLOR_MUL)}
        end
    end

    -- 1x1 の画像寸法から成るメッシュを返します
    return love.graphics.newMesh(meshData, "strip", "static")
end

注釈

生成された Mesh の寸法は 1x1 となります。グラデーションの寸法は love.graphics.draw の尺度係数で決定されます。この異形を使うときは後述の drawinrect 関数は不要です (本当に使用する必要はありません)。

gradient (Image 版)

概要

gradient {color1, color2, color3, ..., direction = 'horizontal' or 'vertical'}

引数テーブルの "direction" により指定された方向へ、階調度全体を一定間隔で均一に配置を行った配色テーブルからグラデーションのオブジェクト (中身は Image) を作成します。

ソース

function gradient(colors)
    local direction = colors.direction or "horizontal"
    if direction == "horizontal" then
        direction = true
    elseif direction == "vertical" then
        direction = false
    else
        error("Invalid direction '" .. tostring(direction) .. "' for gradient.  Horizontal or vertical expected.")
    end
    local result = love.image.newImageData(direction and 1 or #colors, direction and #colors or 1)
    for i, color in ipairs(colors) do
        local x, y
        if direction then
            x, y = 0, i - 1
        else
            x, y = i - 1, 0
        end
        result:setPixel(x, y, color[1], color[2], color[3], color[4] or 255)
    end
    result = love.graphics.newImage(result)
    result:setFilter('linear', 'linear')
    return result
end

drawinrect

概要

drawinrect(img, x, y, w, h, r, ox, oy, kx, ky)

絶対的な大きさの長方形にて拡大・縮小された画像を描画する便利な関数です(画像の大きさとは相対的な大きさではなく、 love.graphics.draw() が処理するものです)。ほぼに常に拡大・縮小されたものを描画したい理由があるとき、および配色数により境界が変更されることを望まない場合、グラデーションに対して有用です。

ソース

function drawinrect(img, x, y, w, h, r, ox, oy, kx, ky)
    return -- 効率的にするためのちょっとした付け足しのための末尾の呼び出し。
    love.graphics.draw(img, x, y, r, w / img:getWidth(), h / img:getHeight(), ox, oy, kx, ky)
end

用例

drawing horizontal rainbow that fills the entire screen using Mesh variant

-- assume you already have gradientMesh function
local rainbow

function love.load()
    rainbow = gradientMesh("horizontal",
        {255, 0, 0};
        {255, 255, 0};
        {0, 255, 0};
        {0, 255, 255};
        {0, 0, 255};
        {255, 0, 0};
    )
end

function love.draw()
    love.graphics.draw(rainbow, 0, 0, 0, love.graphics.getDimensions())
end

画面中央に 100 x 100 ピクセルの水平方向の虹 (すなわち、上部は赤であり、下部は紫) を描画します。

require "gradient"

local rainbow = gradient {
    direction = 'horizontal';
    {255, 0, 0};
    {255, 255, 0};
    {0, 255, 0};
    {0, 255, 255};
    {0, 0, 255};
    {255, 0, 0};
}

function love.draw()
    drawinrect(rainbow, love.graphics.getWidth() / 2 - 50, love.graphics.getHeight() / 2 - 50, 100)
end

画面全体を塗りつぶす垂直方向の白黒領域 (すなわち、左部は黒であり、右部は白) を描画します。

require "gradient"

local greyscale = gradient {
    direction = 'vertical';
    {0, 0, 0};
    {255, 255, 255};
}

function love.draw()
    drawinrect(greyscale, 0, 0, love.graphics.getWidth(), love.graphics.getHeight())
end