Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
FastNoise plugin — Gideros Forum

FastNoise plugin

rrraptorrrraptor Member
edited December 2019 in Plugins
So I created a binding of FastNoise .
Thats how it looks in gideros:






List of all methods:
Gideros only:
  • reset() - reset noise parameters to default
  • generateTexture(w, h, [filtering, zoff]) - returns grayscaled texture (no wrap support yet)
  • generateTileableTexture(w, h, [filtering, zoff]) - returns grayscaled seamless texture (no wrap support yet)
  • generateArray(n, [offset]) - returns a table with noise values (n - number of elements, offset - noise offset [optional])
Noise functions:
  • noise([x, y, z]) - get 1D or 2D or 3D noise value (all parameters optional, defaults: 0)
  • noise1D(x) - get 1D noise value
  • noise2D(x, y) - get 1D noise value
  • noise3D(x, y, z) - get 1D noise value
  • whiteNoise4D(x, y, z, w) - get 4D white noise value (others availiable using methods above, just set noise type to Noise.WHITE_NOISE)
  • whiteNoise1DInt(x) - get integer 1D white noise
  • whiteNoise2DInt(x, y) - get integer 2D white noise
  • whiteNoise3DInt(x, y, z) - get integer 3D white noise
  • whiteNoise4DInt(x, y, z, w) - get integer 4D white noise
  • simplex4D(x, y, z, w) - get 4D simplex noise
    This methods work a bit differently compared to original.
  • gradientPerturb1D(x) - returns modified x
  • gradientPerturb2D(x, y) - returns modified x, y
  • gradientPerturb3D(x, y, z) - returns modified x, y, z
  • gradientPerturbFractal1D(x) - same as gradientPerturb1D
  • gradientPerturbFractal2D(x, y) - same as gradientPerturb2D
  • gradientPerturbFractal3D(x, y, z) - same as gradientPerturb3D
Noise options (see https://github.com/Auburns/FastNoise/wiki):
  • Noise:setNoiseType(noiseType): Default: Noise.SIMPLEX
    Sets the type of noise returned by noise()
    Possible noise types:
    • Noise.VALUE
    • Noise.VALUE_FRACTAL
    • Noise.PERLIN
    • Noise.PERLIN_FRACTAL
    • Noise.SIMPLEX
    • Noise.SIMPLEX_FRACTAL
    • Noise.CELLULAR
    • Noise.WHITE_NOISE
    • Noise.CUBIC
    • Noise.CUBIC_FRACTAL
  • Noise:getNoiseType() returns noise type (number [VALUE = 0, VALUE_FRACTAL = 1, PERLIN = 2, PERLIN_FRACTAL = 3, SIMPLEX = 4, SIMPLEX_FRACTAL = 5, CELLULAR = 6, WHITE_NOISE = 7, CUBIC = 8, CUBIC_FRACTAL = 9])
  • Noise:setFractalOctaves(n): Default: 3
    The amount of noise layers used to create the fractal
    Used in all fractal noise generation
  • Noise:getFractalOctaves() returns number of fractal octaves
  • Noise:setInterp(interpolation): Default: Noise.QUINTIC
    Changes the interpolation method used to smooth between noise values
    Used in Value and Perlin Noise
    Possible interpolation methods (lowest to highest quality):
    • Noise.LINEAR
    • Noise.HERMITE
    • Noise.QUINTIC
  • Noise:getInterp() returns interpolation type (number [LINEAR = 0, HERMITE = 1, QUINTIC = 2])
  • Noise:setSeed(seed) Default: 1337
    Using different seeds will cause the noise output to change
    Used in all noise generation
  • Noise:getSeed() returns generator's seed
  • Noise:setFrequency(frequency): Default: 0.01
    Affects how coarse the noise output is
    Used in all noise generation except White Noise
  • Noise:getFrequency() returns noise frequency
  • Noise:setFractalLacunarity(lacunarity): Default: 2.0
    The frequency multiplier between each octave
    Used in all fractal noise generation
  • Noise:getFractalLacunarity() returns noise lacunarity
  • Noise:setFractalGain(gain): Default: 0.5
    The relative strength of noise from each layer when compared to the last
    Used in all fractal noise generation
  • Noise:getFractalGain() return noise gain
  • Noise:setFractalType(noiseType): Default: Noise.FBM
    Used in all fractal noise generation
    Possible fractal types:
    • Noise.FBM
    • Noise.BILLOW
    • Noise.RIGID_MULTI
  • Noise:getFractalType() returns noise type (number [FBM = 0, BILLOW = 1, RIGID_MULTI = 2])
  • Noise:setCellularDistanceFunction(distanceFunctionType): Default: Noise.EUCLIDEAN
    The distance function used to calculate the cell for a given point
    Possible distance functions:
    • Noise.EUCLIDEAN
    • Noise.MANHATTAN
    • Noise.NATURAL
    Natural is a blend of Euclidean and Manhattan to give curved cell boundaries
  • Noise:getCellularDistanceFunction() returns distance function type (number [EUCLIDEAN = 0, MANHATTAN = 1, NATURAL = 2])
  • Noise:setCellularReturnType(returnType): Default: Noise.CELL_VALUE
    What value does the cellular function return from its calculations
    Possible return types:
    • Noise.CELL_VALUE
    • Noise.NOISE_LOOKUP
    • Noise.DISTANCE
    • Noise.DISTANCE_2
    • Noise.DISTANCE_2_ADD
    • Noise.DISTANCE_2_SUB
    • Noise.DISTANCE_2_MUL
    • Noise.DISTANCE_2_DIV
    Only CellValue is bounded between -1.0 and 1.0, all distance return types have a minimum of 0 and varying maximums
    NoiseLookup requires another Noise object be set with setCellularNoiseLookup() to function
  • Noise:getCellularReturnType() returns cellular return type (number [CELL_VALUE = 0, NOISE_LOOKUP = 1, DISTANCE = 2, DISTANCE_2 = 3, DISTANCE_2_ADD = 4, DISTANCE_2_SUB = 5, DISTANCE_2_MUL = 6, DISTANCE_2_DIV = 7])

  • Noise:setCellularNoiseLookup(Noise): Noise used to calculate a cell value if cellular return type is NoiseLookup
    The lookup value is acquired through GetNoise() so ensure you SetNoiseType() on the noise lookup, value, perlin or simplex is recommended.
  • Noise:getCellularNoiseLookup() returns Noise object that was set by setCellularNoiseLookup() function
  • Noise:setCellularDistance2Indices(index0, index1): Default: 0, 1
    Sets the 2 distance indicies used for distance2 return types
    Note: index0 should be lower than index1
    Both indicies must be >= 0, index1 must be < 4

  • Noise:setCellularJitter(jitter): Default: 0.45
    Sets the maximum distance a cellular point can move from its grid position
    Note: Setting this high will make cellular grid artifacts more common
  • Noise:getCellularJitter() returns cellular jitter value
  • Noise:setGradientPerturbAmp(amp): Default: 1.0
    Sets the maximum perturb distance from original location when using gradientPerturb()
  • Noise:getGradientPerturbAmp() returns gradient perturb amplitude.
TestPlugin - Gideros Player.jpg
992 x 661 - 328K
FastNoise_lua_binding - Microsoft Visual Studio.jpg
1451 x 268 - 314K
+1 -1 (+3 / -0 )Share on Facebook
«13

Comments

  • hgy29hgy29 Maintainer
    You can’t use vs to compile plugins for gideros without a lot of trouble. You need to use qt compiler for windows and similarly the same tools gideros are compiled with

    Likes: rrraptor

    +1 -1 (+1 / -0 )Share on Facebook
  • hgy29hgy29 Maintainer
    For RT slowness, use a shader to draw all in a single call, or prepare the full texture in lua and upload it with Texture.new

    Likes: rrraptor

    +1 -1 (+1 / -0 )Share on Facebook
  • hgy29 said:

    You can’t use vs to compile plugins for gideros without a lot of trouble.

    Well, without g_createClass it works fine, no errors :smile:
    hgy29 said:

    You need to use qt compiler for windows and similarly the same tools gideros are compiled with

    Ok, I'll try.
    hgy29 said:

    For RT slowness, use a shader to draw all in a single call

    I dont understand how to do it xD
    hgy29 said:

    or prepare the full texture in lua and upload it with Texture.new

    Do you mean this: Texture.new(pixels, width, height) ?

    P.S. Playing around :smile:



    TestPlugin - Gideros Player_2.jpg
    1541 x 710 - 906K

    Likes: Apollo14, MoKaLux

    +1 -1 (+2 / -0 )Share on Facebook
  • antixantix Member
    edited December 2019
    @rrraptor looking nice! I think that will be handy as heck!

    Oh, does your library make fast 1D noise also? That's very handy for 2D games ;)
  • @antix no, it’s the binding of existing library, and there is no 1D noise.
    From readme:
    • Value Noise 2D, 3D
    • Perlin Noise 2D, 3D
    • Simplex Noise 2D, 3D, 4D
    • Cubic Noise 2D, 3D
    • Gradient Perturb 2D, 3D
    • Multiple fractal options for all of the above
    • Cellular (Voronoi) Noise 2D, 3D
    • White Noise 2D, 3D, 4D
    But I could try to add this feature :wink:
  • rrraptorrrraptor Member
    edited December 2019
    @antix ok, I have added 1D noise.
    @hgy29 well, I've spent all day trying to get VS to work, but no success :tired_face: I have compiled lua (5.1) from sources, but again, same error.
    hgy29 said:

    You need to use qt compiler for windows and similarly the same tools gideros are compiled with

    Is there any tutorial of how to build plugins with qt... I dont even know where to start. I installed qt-opensource-windows-x86-5.10.1 from http://master.qt.io/archive/qt/5.10/5.10.1/qt-opensource-windows-x86-5.10.1.exe
    But what now?)

    Likes: MoKaLux

    +1 -1 (+1 / -0 )Share on Facebook
  • hgy29hgy29 Maintainer
    Accepted Answer
    You need to write a project file for qt, .pro, take a look at other plugins. Then use qmake and make to build it (or qtcreator). There is a guide on the wiki, named how to build gideros from sources or something like that. It covers both main gideros and plugins iirc.

    Likes: MoKaLux

    +1 -1 (+1 / -0 )Share on Facebook
  • rrraptorrrraptor Member
    edited December 2019
    Didnt know that .pro files is qt project, ty.
    But, I cant open it?

    EDIT:
    Never mind! I've successfully compiled sample plugin, but my code from 1st post still does not work! Same errors...


    But clipper plugin compiles correctly. wtf is going on here...?
    gid_test.cpp gid_test - Qt Creator.jpg
    583 x 274 - 143K
  • hgy29hgy29 Maintainer
    Sounds like you forgot to link with gideros dll (gid.dll)
  • rrraptorrrraptor Member
    edited December 2019
    Hmm, seems like I missed something, because, my libs looks like:
    LIBS += -L"../../../Sdk/lib/desktop" -llua
    And I thought that it is the same as in clipper.pro, but it turns out that I have copied bitop libs path))))
    so I guess I just need to add -lgid to make it work :smile:

    Back to VS :D In order to link gid.dll in VS I need *.lib and *.dll files, there is no *.lib files in gideros folder (apart from \Gideros\All Plugins\steam\source\vs but it only contatin *.lib without *.dll), so I assume that I need to get it by myself. The question is - how?)
    There is a tutorial of how to build gideros from surces but seems like I will only get dll's. Any tips?)

    P.S. If you planning to release new version of gideros during this week, please let me know, I also want to add this binding with this release ;)

    EDIT:
    QT build works :blush:

    image.png
    634 x 252 - 17K
    +1 -1 (+4 / -0 )Share on Facebook
  • rrraptorrrraptor Member
    edited December 2019
    Trying to get it to work with gideros class system, but before making it public, I need some tests, if you interested, please take some time and do some tests, thanks! :wink:

    @antix can you test 1D noise?)

    I've attached a plugin. Put it into "Plugins" folder inside you Gideros installation folder.

    WORKS ONLY FOR WINDOWS

    API can be found here: https://github.com/Auburns/FastNoise/wiki
    But it is a little bit different.

    For noise functions use FNoise.Noise1D(x) or FNoise.Noise2D(x, y) or FNoise.Noise3D(x, y, z)

    For interpolation method (SetInterp) values are:
    • FNoise.LINEAR
    • FNoise.HERMITE
    • FNoise.QUINTIC
    Noise types (SetNoiseType):
    • FNoise.VALUE
    • FNoise.VALUE_FRACTAL
    • FNoise.PERLIN
    • FNoise.PERLIN_FRACTAL
    • FNoise.SIMPLEX
    • FNoise.SIMPLEX_FRACTAL
    • FNoise.CELLULAR
    • FNoise.WHITE_NOISE
    • FNoise.CUBIC
    • FNoise.CUBIC_FRACTAL
    Fractal type (SetFractalType):
    • FNoise.FBM
    • FNoise.BILLOW
    • FNoise.RIGID_MULTI
    Cellular distance functions (SetCellularDistanceFunction):
    • FNoise.EUCLIDEAN
    • FNoise.MANHATTAN
    • FNoise.NATURAL
    Ues FNoise.Reset() function to set parameters back to default.

    Binding for 4D WhiteNoise (WhiteNoiseInt) and 4D SimplexNoise is not implemented (sorry, I forgot about these).

    Quick "HowTo":
    require "FastNoise"
     
    local noise = FNoise.Noise2D
     
    FNoise.SetSeed(456)
    FNoise.SetFrequency(0.04)
    FNoise.SetInterp(FNoise.HERMITE)
    FNoise.SetNoiseType(FNoise.SIMPLEX)
     
     
    for y = 1, 32 do 
    	for x = 1, 32 do 
    		local v = noise(x, y)
    		print(v)
    	end
    end
    zip
    zip
    FastNoiseBinding.zip
    86K
  • hgy29hgy29 Maintainer
    rrraptor said:


    Back to VS :D In order to link gid.dll in VS I need *.lib and *.dll files, there is no *.lib files in gideros folder (apart from \Gideros\All Plugins\steam\source\vs but it only contatin *.lib without *.dll), so I assume that I need to get it by myself. The question is - how?)
    There is a tutorial of how to build gideros from surces but seems like I will only get dll's. Any tips?)

    Yes, VS needs import libraries to link against DLL, while gcc/mingw (backend for Gideros QT) doesn't (or generates .a files instead). I had to make one for steam plugin, kind of hand made using a function listing (the .def file) and the implib tool from VS tools. I followed a tutorial on the internet to do that.

    But you may face various issues if you want to use VS, in particular with C++: different compilers may organize C++ internal machinery differently, so interopertaing C++ code from different compilers may not work as expected. For steam the API was pretty much 'C' only between gideros and the plugin.

    Anyway, sincere congratulations for your first plugin!

    Likes: MoKaLux

    +1 -1 (+1 / -0 )Share on Facebook
  • hgy29 said:

    Yes, VS needs import libraries to link against DLL, while gcc/mingw (backend for Gideros QT) doesn't (or generates .a files instead). I had to make one for steam plugin, kind of hand made using a function listing (the .def file) and the implib tool from VS tools. I followed a tutorial on the internet to do that.

    But you may face various issues if you want to use VS, in particular with C++: different compilers may organize C++ internal machinery differently, so interopertaing C++ code from different compilers may not work as expected. For steam the API was pretty much 'C' only between gideros and the plugin.

    It is a little bit more complex than I thought :D In this case I'll use QT.
    hgy29 said:

    Anyway, sincere congratulations for your first plugin!

    Big thanks to you for tips ;)

    Likes: MoKaLux

    +1 -1 (+1 / -0 )Share on Facebook
  • @rrraptor Mate... I have no idea what to do with a random "binding.dll" file :d
  • hgy29hgy29 Maintainer
    Maybe some Gideros specific additions would be nice for this plugin:
    - being able to generate a full array of noise values in a single call
    - being able to make a texture from them, either greyscale or color if supplying a gradient pattern
  • rrraptorrrraptor Member
    edited December 2019
    hgy29 said:

    - being able to generate a full array of noise values in a single call

    Sounds good :)
    hgy29 said:

    - being able to make a texture from them, either greyscale or color if supplying a gradient pattern

    I have no idea of how to do it :D So far, we have only 2 plugins that have draw calls. That is: Spine and Box2D.

    I've found this in Box2D plugin:
    void b2DebugDraw::DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color)
    {
    	glPushColor();
    	glMultColor(color.r, color.g, color.b,1);
    	float				glVertices[] = {
    		p1.x,p1.y,p2.x,p2.y
    	};
    	gtexture_get_engine()->getDefault(ShaderEngine::STDP_BASIC)->setData(ShaderProgram::DataVertex,ShaderProgram::DFLOAT,2, glVertices, 2, true, NULL);
    	gtexture_get_engine()->getDefault(ShaderEngine::STDP_BASIC)->drawArrays(ShaderProgram::Lines, 0, 2);
    	glPopColor();
    }
    And I have no idea how it works :neutral:
  • hgy29hgy29 Maintainer
    Doing draw calls is a plugin requires a lot of work and in-depth understanding of how gideros works internally. I was thinking of being able to call texture creation routines directly (gtexture_xxx API), or through lua: you generate the 'data' string for Texture.new(data,...) call in C, then call Texture.new with it from C code. I can add it if you wish once the plugin is over.
  • Oh, you mean something like this?
    // generate data for texture
    lua_getglobal(L, "Texture")
    lua_getfield(L, "new")
    lua_push..//pass data to Texture.new( ) of what type?
    lua_call(L, 3, 1)
    That will work, but how to return texture instance and push data?
  • hgy29hgy29 Maintainer
    edited December 2019
    Yes, that is exactly what I meant.
    For args, the data is a string containing R,G,B,A values (one byte per channel) for each pixel, so a 4xWidthxHeight char array in C, then you'll just need to:
    / generate data for texture
    lua_getglobal(L, "Texture")
    lua_getfield(L, -1, "new")
    lua_pushlstring(L,data,4*width*height);
    lua_pushinteger(L,width);
    lua_pushinteger(L,height);
    lua_pushboolean(L,filtering);
    lua_call(L,4,1);
    // Newly created texture is on stack already, just return it
    return 1;
    +1 -1 (+2 / -0 )Share on Facebook
  • hgy29hgy29 Maintainer
    edited December 2019
    For stack correctness, my code above miss a
    lua_remove(L, -2);
    before the
    return 1;
    to remove the Texture table from the stack.

    Likes: rrraptor

    +1 -1 (+1 / -0 )Share on Facebook
  • rrraptorrrraptor Member
    edited December 2019
    I have finished with binding. But stacked with that texture data generation :D Since Im not a C/C++ programmer I need to learn how to work with char/unsigned char data types.

    In lua, its easy :D
    local str = ""
    function byteColor(r,g,b,a)
    	return string.char(r)..string.char(g)..string.char(b)..string.char(a)
    end
     
    local w, h = 10,10
    local clr = byteColor(255,0,0,255)
     
    for i = 1, w*h do 
    	str = str .. clr
    end
     
    local t = Texture.new(str, w, h)
    local btm = Bitmap.new(t)
    btm:setScale(50)
    stage:addChild(btm)
    EDIT:
    Hmm...why gideros Texture/RenderTarget dont have some sort of "loadPixels" function... It would be useful for realtime texture generation. Instead of creating new texture every time, we create pixel data for existing one.
  • hgy29hgy29 Maintainer
    It is not difficult either in C++:
    //Color values are unsigned char (0-255)
    //Allocate an array
    unsigned char *data=new unsigned char[w*h*4];
    unsigned char *ptr=data;
    //Fill it with noise
    for (int i=0;i<(w*h);i++) {
     float noise=getNoise(...);
     //Convert [-1,1] into [0,255]
     unsigned char lum=(unsigned char)((noise+1)*255/2);
     *ptr++=lum; //R
     *ptr++=lum; //G
     *ptr++=lum; //B
     *ptr++=255; //A
    }
    // Use our data array, eg: lua_pushlstring(L,(char *)data,w*h*4);
     
    //Delete our data array
    delete data;

    Likes: rrraptor

    +1 -1 (+1 / -0 )Share on Facebook
  • rrraptorrrraptor Member
    edited December 2019
    Thanks!
    hgy29 said:

    Convert [-1,1] into [0,255]

    That is the tricky one.
    All outputs are approximately bounded from -1.0 to 1.0, except for distance functions on cellular noise
    Also, 1D noise works strange :D I did a 5min test to see min and max output values, aaand its from -0.38660167548164 to 0.38577026785452 :neutral: Need to debug)))
  • rrraptorrrraptor Member
    edited December 2019
    Finally, its working :)
    The interface looks like that:
    Noise:generateTexture(width, height, [filtering, noiseScale, noiseZOffset])
    width, height - texture size (must be positive)
    filtering (boolean, default - false) indicate that the texture should be filtered [optional]
    noiseScale (number, default - 1) noise scale factor [optional]
    noiseZOffset (number, default - 0) noise z scroll [optional]

    1024x1024 texture generates in 0.3 seconds (i7-2600k).

    In realtime generating 256x256 texture EVERY frame drops fps to 40+ (classic Perlin noise)
    256x256 using simplex noise gives stable 60 fps

    Likes: MoKaLux

    +1 -1 (+1 / -0 )Share on Facebook
  • rrraptorrrraptor Member
    edited December 2019

    A bit of profiling:
    Number of tests: 10000000
    test1 6.0592579999998
    test2 1.9603821000005

    Number of tests: 1
    test3 0.041751500000146
    test4 0.13199930000019
    test5 0.49677059999999
    test6 1.9523522999998

    Test1: generate noise array from lua (len - 1000000)
    Test2: generate noise array from C (same len)
    Test3: generate single 128x128 texture
    Test4: generate single 256x256 texture
    Test5: generate single 512x512 texture
    Test6: generate single 1024x1024 texture
    noise.gif
    611 x 310 - 575K

    Likes: antix, MoKaLux

    +1 -1 (+2 / -0 )Share on Facebook
  • @rrraptor In what program - do you make GIFs?
    my games:
    https://play.google.com/store/apps/developer?id=razorback456
    мій блог по гідерос https://simartinfo.blogspot.com
    Слава Україні!
  • rrraptorrrraptor Member
    edited December 2019
    @hgy29
    https://github.com/MultiPain/Gideros_FastNoise_binding
    I've uploaded sources.

    Im absolutely not sure about this original methods:
    void SetCellularNoiseLookup(FastNoise* noise)
    FastNoise* GetCellularNoiseLookup() const { return m_cellularNoiseLookup; }
    If cellularReturnType is set to NoiseLookup then noise function is called on Lookup function.
    case NoiseLookup:
    		assert(m_cellularNoiseLookup);
    		return m_cellularNoiseLookup->GetNoise(...);
    I did it this way:
    GNoise(FastNoise *n) { noise = *n; }
    FastNoise* GetFNoise() { return &noise; }
    void setCellularNoiseLookup(GNoise *n) { noise.SetCellularNoiseLookup(n->GetFNoise()); }
    GNoise *getCellularNoiseLookup() { GNoise *n = new GNoise(noise.GetCellularNoiseLookup()); return n; }
    and binding:
    static int setCellularNoiseLookup(lua_State* L)
    {
        GNoise *n  = getNoiseInstance(L, 1);
        GNoise *sn = getNoiseInstance(L, 2);
        n->setCellularNoiseLookup(sn);
        return 0;
    }
     
    static int getCellularNoiseLookup(lua_State* L)
    {
        GNoise *n  = getNoiseInstance(L, 1);
        GNoise *ns = n->getCellularNoiseLookup();
     
        g_pushInstance(L, "Noise", ns->object());
     
        luaL_rawgetptr(L, LUA_REGISTRYINDEX, &keyWeak);
        lua_pushvalue(L, -2);
        luaL_rawsetptr(L, -2, n);
        lua_pop(L, 1);
     
        lua_pushvalue(L, -1);
        return 1;
    }
    I did some tests, and seems like it works as expected, but I feel like I f***d up with pointers and references :D

    Also, 1D noise still broken, idk how to fix it. I think I'll just add Perlin and simplex noises for it, without fractals and other stuff.
Sign In or Register to comment.