Jump to content

Correct way to generate a texture in code.


reepblue
 Share

Recommended Posts

It seems I can't generate a texture without the editor also making a normal map for each texture which I do not want. I decided to make an extension that would convert the image to a DDS using the code found below.

But I'm now getting the "Mipchain contains mipmaps with dimensions smaller than the format's block size" error. 

How would I fix my code?

local extension = {}

function CreateNewMaterial()
    local defaultpath = CurrentDir().."Materials/"
    local file = RequestFile("Select Material Location", defaultpath, "Ultra Engine Material File (*.mat):mat", 0, true)
    if file ~= nil then
        local mat = CreateMaterial()
        if mat ~= nil then
            mat:SetColor(1,1,1,1)
            local shaderfamily = LoadShaderFamily("Shaders/PBR.fam")
            if shaderfamily then
                mat:SetShaderFamily(shaderfamily)
                shaderfamily = nil
            end
            mat:Save(file);
        end
    end
end

function GenerateTexture()
    local defaultpath = CurrentDir().."Materials/"
    local file = RequestFile("Select Image", defaultpath, "Image:png,tga,jpg,jpeg,bmp", 0, false)

    --Load image
    local pixmap = LoadPixmap(file)
    if pixmap==nil then Print("Error: Failed to generate texture " ..file) return end
    local mipchain = {}
    table.insert(mipchain,pixmap)

    --Generate mipmaps
    local w = pixmap.size.x
    local h = pixmap.size.y
    local mipmap = pixmap
    while (w > 1 and h > 1) do
        w = math.max(1, w / 2)
        h = math.max(1, h / 2)
        mipmap = mipmap:Resize(w,h)
        table.insert(mipchain,mipmap)
    end

    --Convert each image to BC7 compression
    for n=1, #mipchain do
        mipchain[n] = mipchain[n]:Convert(TEXTURE_BC7)
    end

    --Save mipchain to texture file
    local output = StripExt(file)..".dds"
    SaveTexture(output, TEXTURE_2D, mipchain, 1, SAVE_DEFAULT)
end

function extension.hook(event, extension)
    if event.id == EVENT_WIDGETACTION then
        if event.source == extension.menuitem_newmaterial then
            CreateNewMaterial()
        elseif event.source == extension.menuitem_newDDS then
            GenerateTexture()
        end
    end
end

--------------------------------------------------------------------
-- Add menu item
--------------------------------------------------------------------
local menu = program.menu:FindChild("Scripting", false)
if menu == nil then
    Print("Error: Could not find \"Scripting\" menu.")
    return
end

local submenu = menu:FindChild("Utilities", false)
if submenu == nil then
    submenu = CreateMenu("Utilities", menu)
end
extension.menuitem_newmaterial = CreateMenu("Create blank material", submenu)
extension.menuitem_newDDS = CreateMenu("Convert image to DDS", submenu)
ListenEvent(EVENT_WIDGETACTION, extension.menuitem_newmaterial, extension.hook, extension)
ListenEvent(EVENT_WIDGETACTION, extension.menuitem_newDDS, extension.hook, extension)

 

  • Like 1

Cyclone - Ultra Game System - Component PreprocessorTex2TGA - Darkness Awaits Template (Leadwerks)

If you like my work, consider supporting me on Patreon!

Link to comment
Share on other sites

If you are using a compressed texture format then the smallest mipmap should be 4x4.

    while (w > 4 and h > 4) do
        w = math.max(4, w / 2)
        h = math.max(4, h / 2)
        mipmap = mipmap:Resize(w,h)
        table.insert(mipchain,mipmap)
    end
18 minutes ago, reepblue said:

It seems I can't generate a texture without the editor also making a normal map for each texture which I do not want.

I don't understand this.

  • Like 1

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

19 minutes ago, Josh said:

If you are using a compressed texture format then the smallest mipmap should be 4x4.

    while (w > 4 and h > 4) do
        w = math.max(4, w / 2)
        h = math.max(4, h / 2)
        mipmap = mipmap:Resize(w,h)
        table.insert(mipchain,mipmap)
    end

I don't understand this.

Everytime I right click on a PNG image to generate a material, it creates the DDS and a normal map. I just want to simply convert the image to a texture. 

Cyclone - Ultra Game System - Component PreprocessorTex2TGA - Darkness Awaits Template (Leadwerks)

If you like my work, consider supporting me on Patreon!

Link to comment
Share on other sites

It works better as a converter. Works exactly how Leadwerks behaves. I understand the reason for texture creation for being manual since DDS doesn't cover all needs. 

local converter = {}
converter.informat = "png"
converter.outformat = "dds"

function converter:Convert(path, output)
    --Load image
    local pixmap = LoadPixmap(path)
    if pixmap==nil then Print("Error: Failed to generate texture " ..path) return false end
    local mipchain = {}
    table.insert(mipchain,pixmap)

    --Generate mipmaps
    local w = pixmap.size.x
    local h = pixmap.size.y
    local mipmap = pixmap
    while (w > 4 and h > 4) do
        w = math.max(4, w / 2)
        h = math.max(4, h / 2)
        mipmap = mipmap:Resize(w,h)
        table.insert(mipchain,mipmap)
    end
    
    --Convert each image to BC1 (DXT1) compression
    for n=1, #mipchain do
        mipchain[n] = mipchain[n]:Convert(TEXTURE_BC1)
    end
    
    --Save mipchain to texture file
    SaveTexture(output, TEXTURE_2D, mipchain, 1, SAVE_DEFAULT)

    return true
end

program:AddConverter(converter)

 

Cyclone - Ultra Game System - Component PreprocessorTex2TGA - Darkness Awaits Template (Leadwerks)

If you like my work, consider supporting me on Patreon!

Link to comment
Share on other sites

Revisited my extension to generate basic materials from images and textures. This is good if you want non-game image formats part of your file blacklist. It was very helpful with the conversion script above to convert ten or so basic textures. 

local extension = {}

function extension:CreateBlankMaterial()
    local defaultpath = CurrentDir().."/Materials/"
    local file = RequestFile("Select Material Location", defaultpath, "Ultra Engine Material File (*.mat):mat", 0, true)
    if file ~= nil then
        local mat = CreateMaterial()
        if mat ~= nil then
            mat:SetColor(1,1,1,1)
            local shaderfamily = LoadShaderFamily("Shaders/PBR.fam")
            if shaderfamily then
                mat:SetShaderFamily(shaderfamily)
                shaderfamily = nil
            end
            mat:Save(file);
        end
    end
end

function extension:Image2DDS(path)
    --Load image
    local pixmap = LoadPixmap(path)
    if pixmap==nil then Print("Error: Failed to generate texture \"" .. FixPath(output) .. "\"") return false end
    local mipchain = {}
    table.insert(mipchain,pixmap)

    --Generate mipmaps
    local w = pixmap.size.x
    local h = pixmap.size.y
    local mipmap = pixmap
    while (w > 4 and h > 4) do
        w = math.max(4, w / 2)
        h = math.max(4, h / 2)
        mipmap = mipmap:Resize(w,h)
        table.insert(mipchain,mipmap)
    end
    
    --Convert each image to BC1 (DXT1) compression
    for n=1, #mipchain do
        mipchain[n] = mipchain[n]:Convert(TEXTURE_BC1)
    end
    
    --Save mipchain to texture file
    local output = StripExt(path)..".dds"
    SaveTexture(output, TEXTURE_2D, mipchain, 1, SAVE_DEFAULT)
    return output
end

function extension:GenerateMaterialFromTexture()
    local defaultpath = CurrentDir().."/Materials/"
    local file = RequestFile("Select Texture", defaultpath, "Supported Files:dds,basis,png,jpg,jpeg,tga,bmp", 0)

    -- If we're not a texture, convert it
    if (ExtractExt(file) == "png" or ExtractExt(file) == "jpg" or ExtractExt(file) == "jpeg" or ExtractExt(file) == "tga" or ExtractExt(file) == "bmp") then
        local image = file
        file = extension:Image2DDS(image)
    end

    local output = StripExt(file)..".mat"
    if file ~= nil then
        local mat = CreateMaterial()
        if mat ~= nil then
            local tex = LoadTexture(file)
            if tex~=nil then 
                mat:SetTexture(tex)  
                mat:SetColor(1,1,1,1)
                local shaderfamily = LoadShaderFamily("Shaders/PBR.fam")
                if shaderfamily then
                    mat:SetShaderFamily(shaderfamily)
                    shaderfamily = nil
                end
                if mat:Save(output) then
                    Print("Successfully saved \"" .. output .. "\"")
                end
            else
                Print("Failed to save \"" .. output .. "\" as texture is invaild!")
            end
        end
        mat = nil
    else
        Print("Failed to save \"" .. output .. "\" as file is invaild!")
    end
end

function extension.hook(event, extension)
    if event.id == EVENT_WIDGETACTION then
        if event.source == extension.menuitem_blankmaterial then
            extension:CreateBlankMaterial()
        elseif event.source == extension.menuitem_matfromtex then
            extension:GenerateMaterialFromTexture()
        end
    end
end

--------------------------------------------------------------------
-- Add menu item
--------------------------------------------------------------------
local menu = program.menu:FindChild("Scripting", false)
if menu == nil then
    Print("Error: Could not find \"Scripting\" menu.")
    return
end

local submenu = menu:FindChild("Generate Material", false)
if submenu == nil then
    submenu = CreateMenu("Generate Material", menu)
end

extension.menuitem_blankmaterial = CreateMenu("New Blank Material", submenu)
extension.menuitem_matfromtex = CreateMenu("New Material From Texture/Image", submenu)
ListenEvent(EVENT_WIDGETACTION, extension.menuitem_blankmaterial, extension.hook, extension)
ListenEvent(EVENT_WIDGETACTION, extension.menuitem_matfromtex, extension.hook, extension)

 

  • Like 2

Cyclone - Ultra Game System - Component PreprocessorTex2TGA - Darkness Awaits Template (Leadwerks)

If you like my work, consider supporting me on Patreon!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...