Generating plots(heatmap, surf, mesh) using cimgui and Cuda libraries

I have a problem, in which I have to generate some physical Field(Magnetic Field) in plot which value is dependent of 3 cartesian coordinates(x,y,z) and position of inducing elements(wires, poles, cables - line elements). In Octave/Matlab it looked like this:
Octave
octave2
That’s two plots of two crossing routes(three-phased lines placed 0.2 m apart) placed on 1 m depth. The plots are different just by different direction of current in one route. Calculation are made on height of ground(0 m), on grid of X x Y(10m x 10m),
however I didn’t use GPU for this calculation, but just simple code in C(with console interface, where txt files with data generated by C program where displayed with octave script). Now i want to do it with Julia, but much more advanced.
Here’s the problem.
1) Should I generate mesh surf form table with all Magnetic Field Table or should I generate a pixel on my plot by all threads(which seems to be faster) which means that value of variable will be send to cimgui (which I will use) and be generated there and changed for color.
2) All elements(lines) are divided on segments(these segments have three coordinates xi, yi, zi). And i want to add these segments interactively. However the problem is should I push these segments into array(push only notice lists) or generate array all the time I do some element modification. And with these segments I want to use texture memory because in algorithm I often use xi and xi+1, yi and yi+1 and zi and zi+1 statements in one equation.

And one trivial problem:
Why this don’t work:

julia> Bx=0
0

julia> Bx
0

julia> for i=1:10
         Bx=Bx+10
       end
ERROR: UndefVarError: Bx not defined
Stacktrace:
 [1] top-level scope at ./REPL[5]:2 [inlined]
 [2] top-level scope at ./none:0

Ok, that last problem was compiler fault.
If it goes about my main problem.
I had code of this type:

if 2)
i=1
j=1
k=1
resultTab=Array{Float64}(undef, xsize,ysize,zsize)
for z=zmin:dZ:zmax
    i=1
    j=1
    for y=ymin:dY:ymax
    i=1
        for x=xmin:dX:xmax
           #some calculationloops
            resultX+=someIntegral*someXcoefficient
            resultY+=someIntegral*someYcoefficient
            resultZ+=someIntegral*someZcoefficient
            #here is the question:
            1)
            result=sqrt(resultX*resultX + resultY*resultY + resultZ*resultZ)
            someMethodThatAddValueToSomeGeneratedMap

            2)resultTab[i][j][k]=sqrt(resultX*resultX + resultY*resultY + resultZ*resultZ)
            i+=1
        end
     j+=1
    end
k+=1
end

if 2)
Some method that generate plot from Array resultTab(3D) or plots of planes of this table to be generated.

I have a cimgui code and in point " # show image example" I want to put B array which is img_width x img_height Float64 Array with values from 0.0 to 100.0(more or less, but it is certainly>1.0) and I want to get something like the plots on the start of topic(with legend, bar and axes however it don’t have to be exactly the same).

while !GLFW.WindowShouldClose(window)
    global demo_open # oh my global scope
    global image_id, img_width, img_height
    global B
    GLFW.PollEvents()
    # start the Dear ImGui frame
    ImGui_ImplOpenGL3_NewFrame()
    ImGui_ImplGlfw_NewFrame()
    CImGui.NewFrame()

    demo_open && @c ShowDemoWindow(&demo_open)

    # show image example
    CImGui.Begin("Image Demo")
    image = B
    ImGui_ImplOpenGL3_UpdateImageTexture(image_id, image, img_width, img_height)
    CImGui.Image(Ptr{Cvoid}(image_id), (img_width, img_height))
    CImGui.End()

    # rendering
    CImGui.Render()
    GLFW.MakeContextCurrent(window)
    display_w, display_h = GLFW.GetFramebufferSize(window)
    glViewport(0, 0, display_w, display_h)
    glClearColor(clear_color...)
    glClear(GL_COLOR_BUFFER_BIT)
    ImGui_ImplOpenGL3_RenderDrawData(CImGui.GetDrawData())

    GLFW.MakeContextCurrent(window)
    GLFW.SwapBuffers(window)
end

What should I do to get nice plot from array?

When I compile this: B=Array{Float64}(undef,200,200)

for i=1:length(B)
  if i<length(B)/16
    B[i]=0.99
  elseif i<length(B)/8
    B[i]=0.7
  else
    if i<length(B)/4
      B[i]=15.0
    elseif i<length(B)/3
      B[i]=0.1
    else
      B[i]=16.0
    end
  end
end

into this:

CImGui.Begin("Image Demo")
    image = B
    ImGui_ImplOpenGL3_UpdateImageTexture(image_id, image, img_width, img_height)
    CImGui.Image(Ptr{Cvoid}(image_id), (img_width, img_height))
    CImGui.End()

I get :obraz

Hi, I just worked out some things.
I plotted this:


by this code:

low=colorant"navyblue";
medium=colorant"limegreen";
high=colorant"yellow";

Bcolormap = colorsigned(low,medium,high) ∘ scalesigned(minimum(B),(minimum(B)+maximum(B))/2,maximum(B))

Bimage=Bcolormap.(B[:,:,1])

B was Array with float values.
I wanted to show it in imgui application:

# setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(window, true)
ImGui_ImplOpenGL3_Init(glsl_version)
# demo_open = true
clear_color = Cfloat[0.45, 0.55, 0.60, 1.00]
while !GLFW.WindowShouldClose(window)
    global demo_open # oh my global scope
    global image_id, img_width, img_height
    global Bimage
    GLFW.PollEvents()
    # start the Dear ImGui frame
    ImGui_ImplOpenGL3_NewFrame()
    ImGui_ImplGlfw_NewFrame()
    CImGui.NewFrame()

    # demo_open && @c ShowDemoWindow(&demo_open)

    # show image example
    CImGui.Begin("Image Demo")
    image = Bimage
    ImGui_ImplOpenGL3_UpdateImageTexture(image_id, image, img_width, img_height)
    CImGui.Image(Ptr{Cvoid}(image_id), (img_width, img_height))
    CImGui.End()

    # rendering
    CImGui.Render()
    GLFW.MakeContextCurrent(window)
    display_w, display_h = GLFW.GetFramebufferSize(window)
    glViewport(0, 0, display_w, display_h)
    glClearColor(clear_color...)
    glClear(GL_COLOR_BUFFER_BIT)
    ImGui_ImplOpenGL3_RenderDrawData(CImGui.GetDrawData())

    GLFW.MakeContextCurrent(window)
    GLFW.SwapBuffers(window)
end

That # show image example line is part where I put Bimage into window, but in result I get this:

whatIsPlotted
How to put plot into imgui window?

When I changed variables img_width and img_height to actual image size I get this:
nextEvolution
It’s still not that what I want, but it’s one step forward however I checked type of Bimage(5-th post image (Julia Plots (8/8) )) and I get:

typeof(Bimage)
Array{RGB{Normed{UInt8,8}},2}

This Bimage is putted here in code:

CImGui.Begin("Image Demo")
    image = Bimage
    ImGui_ImplOpenGL3_UpdateImageTexture(image_id, image, img_width, img_height)
    CImGui.Image(Ptr{Cvoid}(image_id), (img_width, img_height))
    CImGui.End()

If somebody knew how to put this plot/image in imgui i would be very grateful.

Hi Wiktor,

By default the ImGui_ImplOpenGL3_CreateImageTexture and ImGui_ImplOpenGL3_UpdateImageTexture functions assume that the keyword parameter format = GL_RGBA. However, you are working with 3 channels (RGB).

Another issue you have to consider is that the aforementioned functions want to interpret the layout of the data so that the first dimension corresponds to width and the second dimension correspond to height. They also expect an Array{UInt8,3} and not a wrapped type such as Array{RGB{Normed{UInt8,8}},2}.

Here is an example of how you could address all of these issues:

using Images, TestImage, CImGui etc.
img₀ = testimage("lighthouse")
img₁= transpose(img₀)
img_width, img_height = size(img₁)
image_id = ImGui_ImplOpenGL3_CreateImageTexture(img_width, img_height, format = GL_RGB)
img′ = unsafe_wrap(Array{UInt8,3}, convert(Ptr{UInt8}, pointer(img₁)), (Cint(3), Cint(img_width), Cint(img_height)))
ImGui_ImplOpenGL3_UpdateImageTexture(image_id, img′, img_width, img_height; format = GL_RGB)

# and then in your main loop
CImGui.Image(Ptr{Cvoid}(image_id), (img_width, img_height))

Here is a complete working example which you should be able to copy and paste into a script and run.

using CImGui
using CImGui.CSyntax
using CImGui.GLFWBackend
using CImGui.OpenGLBackend
using CImGui.GLFWBackend.GLFW
using CImGui.OpenGLBackend.ModernGL
using Printf
using Images
using TestImages

@static if Sys.isapple()
    # OpenGL 3.2 + GLSL 150
    const glsl_version = 150
    GLFW.WindowHint(GLFW.CONTEXT_VERSION_MAJOR, 3)
    GLFW.WindowHint(GLFW.CONTEXT_VERSION_MINOR, 2)
    GLFW.WindowHint(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE) # 3.2+ only
    GLFW.WindowHint(GLFW.OPENGL_FORWARD_COMPAT, GL_TRUE) # required on Mac
else
    # OpenGL 3.0 + GLSL 130
    const glsl_version = 130
    GLFW.WindowHint(GLFW.CONTEXT_VERSION_MAJOR, 3)
    GLFW.WindowHint(GLFW.CONTEXT_VERSION_MINOR, 0)
    # GLFW.WindowHint(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE) # 3.2+ only
    # GLFW.WindowHint(GLFW.OPENGL_FORWARD_COMPAT, GL_TRUE) # 3.0+ only
end

# setup GLFW error callback
error_callback(err::GLFW.GLFWError) = @error "GLFW ERROR: code $(err.code) msg: $(err.description)"
GLFW.SetErrorCallback(error_callback)

# create window
window = GLFW.CreateWindow(1280, 720, "Demo")
@assert window != C_NULL
GLFW.MakeContextCurrent(window)
GLFW.SwapInterval(1)  # enable vsync

# setup Dear ImGui context
ctx = CImGui.CreateContext()

# setup Dear ImGui style
CImGui.StyleColorsDark()


# creat texture for image drawing
img₀ = testimage("lighthouse")
img₁= transpose(img₀)
img_width, img_height = size(img₁)
image_id = ImGui_ImplOpenGL3_CreateImageTexture(img_width, img_height, format = GL_RGB)
img′ = unsafe_wrap(Array{UInt8,3}, convert(Ptr{UInt8}, pointer(img₁)), (Cint(3), Cint(img_width), Cint(img_height)))
ImGui_ImplOpenGL3_UpdateImageTexture(image_id, img′, img_width, img_height; format = GL_RGB)


# setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(window, true)
ImGui_ImplOpenGL3_Init(glsl_version)

demo_open = true
clear_color = Cfloat[0.45, 0.55, 0.60, 1.00]
while !GLFW.WindowShouldClose(window)
    global demo_open # oh my global scope
    global image_id, img_width, img_height

    GLFW.PollEvents()
    # start the Dear ImGui frame
    ImGui_ImplOpenGL3_NewFrame()
    ImGui_ImplGlfw_NewFrame()
    CImGui.NewFrame()

    # Generate a new random image
    if CImGui.Button("Generate Random Image")
        image = rand(UInt8, 3, img_width, img_height)
        ImGui_ImplOpenGL3_UpdateImageTexture(image_id, image, img_width, img_height; format = GL_RGB)
    end

    CImGui.Begin("Image Demo")
        CImGui.Image(Ptr{Cvoid}(image_id), (img_width, img_height))
    CImGui.End()

    # rendering
    CImGui.Render()
    GLFW.MakeContextCurrent(window)
    display_w, display_h = GLFW.GetFramebufferSize(window)
    glViewport(0, 0, display_w, display_h)
    glClearColor(clear_color...)
    glClear(GL_COLOR_BUFFER_BIT)
    ImGui_ImplOpenGL3_RenderDrawData(CImGui.GetDrawData())

    GLFW.MakeContextCurrent(window)
    GLFW.SwapBuffers(window)
end

# cleanup
ImGui_ImplOpenGL3_Shutdown()
ImGui_ImplGlfw_Shutdown()
CImGui.DestroyContext(ctx)
GLFW.DestroyWindow(window)

It should produce the following output:
lighthouse-cimgui

1 Like

It’s much closer now, but it’s still not this:
almost
Should be this:
thatShouldBePlotted
It looks like this cutted my image.
However I checked line by line code and on this:
BimageT=transpose(Bimage)
I get this:

Errors encountered while saving nothing.
All errors:
   ArgumentError("Package ImageMagick not found in current path:\n- Run `import Pkg; Pkg.add(\"ImageMagick\")` to install the ImageMagick package.\n")
   ErrorException("function save does not accept keyword arguments")
Fatal error:
Error showing value of type Array{RGB{Normed{UInt8,8}},2}:
ERROR: ArgumentError: Package ImageMagick not found in current path:
- Run `import Pkg; Pkg.add("ImageMagick")` to install the ImageMagick package.

I installed this and also installed this by terminal: sudo apt-get install ffmpeg cmake xorg-dev
However in console I have 72 warnings:

btw. your example works fine:

I’m not sure how you have configured your development environment and what your workflow is, but I suspect you may be running into issues that are somehow related to not recompiling certain functions, working in a global scope etc.

I think the code you posted for your definition for B is not the one that you are using, because even the raw data in the array doesn’t appear to have the shape that you are posting. As an alternative I’ve made a simple color ramp image analogous to what you are attempting to do.

For illustration purposes (and to avoid any global scope issues) I’ve put the code below into two functions: construct_B and example.

using CImGui
using CImGui.CSyntax
using CImGui.GLFWBackend
using CImGui.OpenGLBackend
using CImGui.GLFWBackend.GLFW
using CImGui.OpenGLBackend.ModernGL
using Printf
using ImageCore


function construct_B()
    B = repeat(1:200, 1,200)
    low = colorant"navyblue";
    medium = colorant"limegreen";
    high = colorant"yellow";
    Bcolormap = colorsigned(low,medium,high) ∘ scalesigned(minimum(B),(minimum(B)+maximum(B)) / 2, maximum(B))
    Bcolormap.(B)
end

function example(B::AbstractArray)
    @static if Sys.isapple()
        # OpenGL 3.2 + GLSL 150
        glsl_version = 150
        GLFW.WindowHint(GLFW.CONTEXT_VERSION_MAJOR, 3)
        GLFW.WindowHint(GLFW.CONTEXT_VERSION_MINOR, 2)
        GLFW.WindowHint(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE) # 3.2+ only
        GLFW.WindowHint(GLFW.OPENGL_FORWARD_COMPAT, GL_TRUE) # required on Mac
    else
        # OpenGL 3.0 + GLSL 130
        glsl_version = 130
        GLFW.WindowHint(GLFW.CONTEXT_VERSION_MAJOR, 3)
        GLFW.WindowHint(GLFW.CONTEXT_VERSION_MINOR, 0)
        # GLFW.WindowHint(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE) # 3.2+ only
        # GLFW.WindowHint(GLFW.OPENGL_FORWARD_COMPAT, GL_TRUE) # 3.0+ only
    end

    # setup GLFW error callback
    error_callback(err::GLFW.GLFWError) = @error "GLFW ERROR: code $(err.code) msg: $(err.description)"
    GLFW.SetErrorCallback(error_callback)

    # create window
    window = GLFW.CreateWindow(1280, 720, "Demo")
    @assert window != C_NULL
    GLFW.MakeContextCurrent(window)
    GLFW.SwapInterval(1)  # enable vsync

    # setup Dear ImGui context
    ctx = CImGui.CreateContext()

    # setup Dear ImGui style
    CImGui.StyleColorsDark()


    # creat texture for image drawing
    img₀ = B
    img₁= transpose(img₀)
    img_width, img_height = size(img₁)
    image_id = ImGui_ImplOpenGL3_CreateImageTexture(img_width, img_height, format = GL_RGB)
    img′ = unsafe_wrap(Array{UInt8,3}, convert(Ptr{UInt8}, pointer(img₁)), (Cint(3), Cint(img_width), Cint(img_height)))
    ImGui_ImplOpenGL3_UpdateImageTexture(image_id, img′, img_width, img_height; format = GL_RGB)


    # setup Platform/Renderer bindings
    ImGui_ImplGlfw_InitForOpenGL(window, true)
    ImGui_ImplOpenGL3_Init(glsl_version)

    demo_open = true
    clear_color = Cfloat[0.45, 0.55, 0.60, 1.00]
    while !GLFW.WindowShouldClose(window)
        demo_open # oh my global scope
        image_id, img_width, img_height

        GLFW.PollEvents()
        # start the Dear ImGui frame
        ImGui_ImplOpenGL3_NewFrame()
        ImGui_ImplGlfw_NewFrame()
        CImGui.NewFrame()

        # Generate a new random image
        if CImGui.Button("Generate Random Image")
            image = rand(UInt8, 3, img_width, img_height)
            ImGui_ImplOpenGL3_UpdateImageTexture(image_id, image, img_width, img_height; format = GL_RGB)
        end

        CImGui.Begin("Image Demo")
            CImGui.Image(Ptr{Cvoid}(image_id), (img_width, img_height))
        CImGui.End()

        # rendering
        CImGui.Render()
        GLFW.MakeContextCurrent(window)
        display_w, display_h = GLFW.GetFramebufferSize(window)
        glViewport(0, 0, display_w, display_h)
        glClearColor(clear_color...)
        glClear(GL_COLOR_BUFFER_BIT)
        ImGui_ImplOpenGL3_RenderDrawData(CImGui.GetDrawData())

        GLFW.MakeContextCurrent(window)
        GLFW.SwapBuffers(window)
    end

    # cleanup
    ImGui_ImplOpenGL3_Shutdown()
    ImGui_ImplGlfw_Shutdown()
    CImGui.DestroyContext(ctx)
    GLFW.DestroyWindow(window)
end

# Run the demo
example(construct_B())

It produces the following result:
cimgui-ramp

B data is the field of two crossed electric lines with direct current. So it is good shape.
Here is B transformation:

B=Array{Float64}(undef,length(x),length(y),length(z))
# B calculation ...
low=colorant"navyblue";
medium=colorant"limegreen";
high=colorant"yellow";
Bcolormap = colorsigned(low,medium,high) ∘ scalesigned(minimum(B),(minimum(B)+maximum(B))/2,maximum(B))
Bimage=Bcolormap.(B[:,:,1]) # I want only one plane
BimageT=transpose(Bimage)
img_width, img_height = size(BimageT)
image_id = ImGui_ImplOpenGL3_CreateImageTexture(img_width, img_height, format = GL_RGB)
BTr = unsafe_wrap(Array{UInt8,3}, convert(Ptr{UInt8}, pointer(BimageT)), (Cint(3), Cint(img_width), Cint(img_height)))
ImGui_ImplOpenGL3_UpdateImageTexture(image_id, BTr, img_width, img_height; format = GL_RGB)

When I said “shape” I meant that

for i=1:length(B)
  if i<length(B)/16
    B[i]=0.99
  elseif i<length(B)/8
    B[i]=0.7
  else
    if i<length(B)/4
      B[i]=15.0
    elseif i<length(B)/3
      B[i]=0.1
    else
      B[i]=16.0
    end
  end
end

was not product a “plus” like pattern. Putting that aside, as far as I can tell all the ingredients for the solution are there for you.

That code was just test calculation(Just to see if I get some other colors, than these I get from normal Float values). My calculation is more complex.
It’s more like:

for zi in zIndex
  for yi in yIndex
    for xi in xIndex
      Bx=0.0
      By=0.0
      Bz=0.0
      for j=1:E
        start=(j-1)*N+1
        over=j*N-1
        for i=start:over
          Sx=T[i+1,1]-T[i,1]
          Sy=T[i+1,2]-T[i,2]
          δx=x[xi]-T[i,1]
          δy=y[yi]-T[i,2]
          δz=z[zi]-zseg[div(i,N)+1]

          L=sqrt(Sx*Sx+Sy*Sy)

          p=(Sx*δx+Sy*δy)/L
          α=Sx/L
          β=Sy/L

          integral, err = quadgk(u -> ((u-p)^2-p*p+δx*δx+δy*δy+δz*δz)^(-3/2), 0, L, rtol=1e-8)

          Bx+=integral*β*δz
          By+=integral*α*δz
          Bz+=integral*(α*δy-β*δx)
        end
      end
      # B=sqrt(Bx*Bx+By*By+Bz*Bz)
      B[xi,yi,zi]=sqrt(Bx*Bx+By*By+Bz*Bz)
    end
  end
end

There’s only a graphic problem.

It’s very interesting, but I probably found the problem and it’s strange for me.
I generate array with: B = repeat(1:201, 1,201)
and I got this:


It’s strange, because I get this only for 201x201 Array(that was the Array size that I generate all the time). I low my B array to 200x200 and got this:

I’ve done some more tests and I get:
199x199:
199problem
202x202:

203x203:

204x204:

204x201:
204x201

I don’t know why, but I guess that one of dimensions(img_witdh,img_height) must be divided by 4.

I did a little more digging and discovered why some of the image dimensions were not working correctly. It turns out that we need to specify the alignment requirements for the start of each pixel row in memory.

I’ve quoted a relevant article below:

You create storage for a Texture and upload pixels to it with glTexImage2D (or similar functions, as appropriate to the type of texture). If your program crashes during the upload, or diagonal lines appear in the resulting image, this is because the alignment of each horizontal line of your pixel array is not multiple of 4. This typically happens to users loading an image that is of the RGB or BGR format (for example, 24 BPP images), depending on the source of your image data.

Example, your image width = 401 and height = 500. The height is irrelevant; what matters is the width. If we do the math, 401 pixels x 3 bytes = 1203, which is not divisible by 4. Some image file formats may inherently align each row to 4 bytes, but some do not. For those that don’t, each row will start exactly 1203 bytes from the start of the last. OpenGL’s row alignment can be changed to fit the row alignment for your image data. This is done by calling glPixelStorei(GL_UNPACK_ALIGNMENT, #), where # is the alignment you want. The default alignment is 4.

And if you are interested, most GPUs like chunks of 4 bytes. In other words, GL_RGBA or GL_BGRA is preferred when each component is a byte. GL_RGB and GL_BGR is considered bizarre since most GPUs, most CPUs and any other kind of chip don’t handle 24 bits. This means, the driver converts your GL_RGB or GL_BGR to what the GPU prefers, which typically is RGBA/BGRA.

Similarly, if you read a buffer with glReadPixels, you might get similar problems. There is a GL_PACK_ALIGNMENT just like the GL_UNPACK_ALIGNMENT. The default alignment is again 4 which means each horizontal line must be a multiple of 4 in size. If you read the buffer with a format such as GL_BGRA or GL_RGBA you won’t have any problems since the line will always be a multiple of 4. If you read it in a format such as GL_BGR or GL_RGB then you risk running into this problem.

The GL_PACK/UNPACK_ALIGNMENTs can only be 1, 2, 4, or 8. So an alignment of 3 is not allowed. If your intention really is to work with packed RGB/BGR data, you should set the alignment to 1 (or preferably, consider switching to RGBA/BGRA.)

It turns out that when you create the texture you can specify a GL_RGBA format even if you intend to upload only three components.

Image formats do not have to store each component. When the shader samples such a texture, it will still resolve to a 4-value RGBA vector. The components not stored by the image format are filled in automatically. Zeros are used if R, G, or B is missing, while a missing Alpha always resolves to 1.

In order to fix the problem all that we need to do is add glPixelStorei(GL_UNPACK_ALIGNMENT, 1) before the create the image texture, i.e.

    # create texture for image drawing
    img₀ = B
    img₁= transpose(img₀)
    img_width, img_height = size(img₁)
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
    image_id = ImGui_ImplOpenGL3_CreateImageTexture(img_width, img_height, format = GL_RGBA)
    img′ = unsafe_wrap(Array{UInt8,3}, convert(Ptr{UInt8}, pointer(img₁)), (Cint(3), Cint(img_width), Cint(img_height)))
    ImGui_ImplOpenGL3_UpdateImageTexture(image_id, img′, img_width, img_height; format = GL_RGB)

You can execute a self-contained example by running the following script:

using CImGui
using CImGui.CSyntax
using CImGui.GLFWBackend
using CImGui.OpenGLBackend
using CImGui.GLFWBackend.GLFW
using CImGui.OpenGLBackend.ModernGL
using Printf
using ImageCore


function construct_B()
    B = repeat(1:500, 1, 401)
    low = colorant"navyblue";
    medium = colorant"limegreen";
    high = colorant"yellow";
    Bcolormap = colorsigned(low,medium,high) ∘ scalesigned(minimum(B),(minimum(B)+maximum(B)) / 2, maximum(B))
    Bcolormap.(B)
end

function example(B::AbstractArray)
    @static if Sys.isapple()
        # OpenGL 3.2 + GLSL 150
        glsl_version = 150
        GLFW.WindowHint(GLFW.CONTEXT_VERSION_MAJOR, 3)
        GLFW.WindowHint(GLFW.CONTEXT_VERSION_MINOR, 2)
        GLFW.WindowHint(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE) # 3.2+ only
        GLFW.WindowHint(GLFW.OPENGL_FORWARD_COMPAT, GL_TRUE) # required on Mac
    else
        # OpenGL 3.0 + GLSL 130
        glsl_version = 130
        GLFW.WindowHint(GLFW.CONTEXT_VERSION_MAJOR, 3)
        GLFW.WindowHint(GLFW.CONTEXT_VERSION_MINOR, 0)
        # GLFW.WindowHint(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE) # 3.2+ only
        # GLFW.WindowHint(GLFW.OPENGL_FORWARD_COMPAT, GL_TRUE) # 3.0+ only
    end

    # setup GLFW error callback
    error_callback(err::GLFW.GLFWError) = @error "GLFW ERROR: code $(err.code) msg: $(err.description)"
    GLFW.SetErrorCallback(error_callback)

    # create window
    window = GLFW.CreateWindow(1280, 720, "Demo")
    @assert window != C_NULL
    GLFW.MakeContextCurrent(window)
    GLFW.SwapInterval(1)  # enable vsync

    # setup Dear ImGui context
    ctx = CImGui.CreateContext()

    # setup Dear ImGui style
    CImGui.StyleColorsDark()


    # create texture for image drawing
    img₀ = B
    img₁= transpose(img₀)
    img_width, img_height = size(img₁)
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
    image_id = ImGui_ImplOpenGL3_CreateImageTexture(img_width, img_height, format = GL_RGBA)
    img′ = unsafe_wrap(Array{UInt8,3}, convert(Ptr{UInt8}, pointer(img₁)), (Cint(3), Cint(img_width), Cint(img_height)))
    ImGui_ImplOpenGL3_UpdateImageTexture(image_id, img′, img_width, img_height; format = GL_RGB)


    # setup Platform/Renderer bindings
    ImGui_ImplGlfw_InitForOpenGL(window, true)
    ImGui_ImplOpenGL3_Init(glsl_version)

    demo_open = true
    clear_color = Cfloat[0.45, 0.55, 0.60, 1.00]
    while !GLFW.WindowShouldClose(window)
        demo_open # oh my global scope
        image_id, img_width, img_height

        GLFW.PollEvents()
        # start the Dear ImGui frame
        ImGui_ImplOpenGL3_NewFrame()
        ImGui_ImplGlfw_NewFrame()
        CImGui.NewFrame()

        CImGui.Begin("Image Demo")
            CImGui.Image(Ptr{Cvoid}(image_id), (img_width, img_height))
        CImGui.End()

        # rendering
        CImGui.Render()
        GLFW.MakeContextCurrent(window)
        display_w, display_h = GLFW.GetFramebufferSize(window)
        glViewport(0, 0, display_w, display_h)
        glClearColor(clear_color...)
        glClear(GL_COLOR_BUFFER_BIT)
        ImGui_ImplOpenGL3_RenderDrawData(CImGui.GetDrawData())

        GLFW.MakeContextCurrent(window)
        GLFW.SwapBuffers(window)
    end

    # cleanup
    ImGui_ImplOpenGL3_Shutdown()
    ImGui_ImplGlfw_Shutdown()
    CImGui.DestroyContext(ctx)
    GLFW.DestroyWindow(window)
end

# Run the demo
example(construct_B())

1 Like

It’s great, however now the question is which method:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1)

or:
transformate data to RGBA instead of RGB
is more efficient.
The second question is if I can scale the image. For example I have an image of 400x400 pixels, but I want to plot it on texture of 1280x720 pixels. However I want to do it proportionally, so I want that image to be plotted on 720x720 screen size(Texture still will be 1280x720 because it must be initialized before
while !GLFW.WindowShouldClose(window) loop
by this:

image_id = ImGui_ImplOpenGL3_CreateImageTexture(img_width, img_height, format = GL_RGBA)

I have one more question. How to update image with deleting the old one.
Here, what is I’m about:


After clicking Generate plot, I want to generate new image(without the old one).
Here is what is in the button:

if CImGui.Button("Generate plot")
              x=X[1]:X[2]:X[3]
              y=Y[1]:Y[2]:Y[3]
              z=Z[1]:Z[2]:Z[3]
              Btab=biotSavartCalculation(x,y,z,S,Itab,numberOnLine)
              BimagePlot=makeMap(Btab,low,medium,high,Zplane)
              img_width,img_height=size(BimagePlot)
              BTr = unsafe_wrap(Array{UInt8,3}, convert(Ptr{UInt8}, pointer(BimagePlot)), (Cint(3), Cint(img_width), Cint(img_height)))
              image=BTr
              ImGui_ImplOpenGL3_UpdateImageTexture(image_id, image, img_width, img_height; format = GL_RGB)
          end

The last line is the most important, however I don’t know how to modify that.