Skip to content

Commit

Permalink
Merge branch 'bitmap'
Browse files Browse the repository at this point in the history
  • Loading branch information
cfillion committed Nov 27, 2022
2 parents b1cb82d + efe5554 commit cc6087e
Show file tree
Hide file tree
Showing 37 changed files with 1,240 additions and 225 deletions.
5 changes: 4 additions & 1 deletion .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ for:
install-deps() {
local arch="$1"; shift
local native=("$@" php-cli qemu-user-binfmt)
local target=(libboost-dev libboost-filesystem-dev libgtk-3-dev)
local target=(libboost-dev libboost-filesystem-dev libgtk-3-dev libjpeg-dev)
sudo dpkg --add-architecture $arch
sudo apt-get update -qq
Expand Down Expand Up @@ -87,6 +87,9 @@ for:
# https://letsencrypt.org/docs/dst-root-ca-x3-expiration-september-2021/
- sudo curl -k https://curl.se/ca/cacert.pem -o /etc/ssl/cert.pem

# don't use libjpeg from Mono
- sudo rm -r /Library/Frameworks/Mono.framework

# update to cmark 0.30.1 for static linkage
- git -C ~/vcpkg fetch origin 790418c9037196ef499b642decc2cd880e15db30
- git -C ~/vcpkg restore -s 790418c9037196ef499b642decc2cd880e15db30 ports/cmark
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,15 @@ them separately):
- [GDK3](https://developer.gnome.org/gdk3/stable/) (3.22 or newer)
- [GoogleTest](https://github.com/google/googletest)
- [libepoxy](https://github.com/anholt/libepoxy)
- [libjpeg-turbo](https://www.libjpeg-turbo.org/)
- [libpng](http://www.libpng.org/pub/png/libpng.html)

#### macOS

Install Boost, FreeType and GoogleTest using [Homebrew](https://brew.sh) (recommended).
Using [Homebrew](https://brew.sh) (recommended):
```sh
brew install boost cmark freetype googletest jpeg-turbo libpng
```
The build tools can be installed using `xcode-select --install` or the Xcode IDE.

#### Windows
Expand Down
1 change: 1 addition & 0 deletions api/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_library(api OBJECT
dragndrop.cpp
drawlist.cpp
font.cpp
image.cpp
indev.cpp
input.cpp
item.cpp
Expand Down
27 changes: 27 additions & 0 deletions api/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,33 @@ GetDeltaTime), in frame per second. Solely for convenience.)",
return ctx->IO().Framerate;
});

DEFINE_API(void, Attach, (ImGui_Context*,ctx)(ImGui_Resource*,obj),
R"(Link the object's lifetime to the given context.
Objects can be draw list splitters, fonts, images, list clippers, etc.
Call Detach to let the object be garbage-collected after unuse again.
List clipper objects may only be attached to the context they were created for.
Fonts are (currently) a special case: they must be attached to the context
before usage. Furthermore, fonts may only be attached or detached immediately
after the context is created or before any other function calls modifying the
context per defer cycle. See "limitations" in the font API documentation.)",
{
assertValid(ctx);
assertValid(obj);
ctx->attach(obj);
});
DEFINE_API(void, Detach, (ImGui_Context*,ctx)(ImGui_Resource*,obj),
R"(Unlink the object's lifetime. Unattached objects are automatically destroyed
when left unused. You may check whether an object has been destroyed using
ValidatePtr.)",
{
assertValid(ctx);
assertValid(obj);
ctx->detach(obj);
});

API_SUBSECTION("Options");

// expose most settings from ImGuiIO
Expand Down
57 changes: 57 additions & 0 deletions api/drawlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "color.hpp"
#include "drawlist.hpp"
#include "font.hpp"
#include "image.hpp"
#include "resource_proxy.hpp"

#include <reaper_plugin_secrets.h> // reaper_array
Expand Down Expand Up @@ -372,6 +373,62 @@ DEFINE_API(void, DrawList_AddBezierQuadratic, (ImGui_DrawList*,draw_list)
Color::fromBigEndian(col_rgba), thickness, API_RO_GET(num_segments));
});

DEFINE_API(void, DrawList_AddImage, (ImGui_DrawList*,draw_list)
(ImGui_Image*,img)
(double,p_min_x)(double,p_min_y)(double,p_max_x)(double,p_max_y)
(double*,API_RO(uv_min_x),0.0)(double*,API_RO(uv_min_y),0.0)
(double*,API_RO(uv_max_x),1.0)(double*,API_RO(uv_max_y),1.0)
(int*,API_RO(col_rgba),0xFFFFFFFF),
"",
{
Context *ctx;
ImDrawList *dl { draw_list->get(&ctx) };
assertValid(img);
dl->AddImage(img->makeTexture(ctx->textureManager()),
ImVec2(p_min_x, p_min_y), ImVec2(p_max_x, p_max_y),
ImVec2(API_RO_GET(uv_min_x), API_RO_GET(uv_min_y)),
ImVec2(API_RO_GET(uv_max_x), API_RO_GET(uv_max_y)),
Color::fromBigEndian(API_RO_GET(col_rgba)));
});

DEFINE_API(void, DrawList_AddImageQuad, (ImGui_DrawList*,draw_list)
(ImGui_Image*,img)(double,p1_x)(double,p1_y)(double,p2_x)(double,p2_y)
(double,p3_x)(double,p3_y)(double,p4_x)(double,p4_y)
(double*,API_RO(uv1_x),0.0)(double*,API_RO(uv1_y),0.0)
(double*,API_RO(uv2_x),1.0)(double*,API_RO(uv2_y),0.0)
(double*,API_RO(uv3_x),1.0)(double*,API_RO(uv3_y),1.0)
(double*,API_RO(uv4_x),0.0)(double*,API_RO(uv4_y),1.0)
(int*,API_RO(col_rgba),0xFFFFFFFF),
"",
{
Context *ctx;
ImDrawList *dl { draw_list->get(&ctx) };
assertValid(img);
dl->AddImageQuad(img->makeTexture(ctx->textureManager()),
ImVec2(p1_x, p1_y), ImVec2(p2_x, p2_y),
ImVec2(p3_x, p3_y), ImVec2(p4_x, p4_y),
ImVec2(API_RO_GET(uv1_x), API_RO_GET(uv1_y)),
ImVec2(API_RO_GET(uv2_x), API_RO_GET(uv2_y)),
ImVec2(API_RO_GET(uv3_x), API_RO_GET(uv3_y)),
ImVec2(API_RO_GET(uv4_x), API_RO_GET(uv4_y)),
Color::fromBigEndian(API_RO_GET(col_rgba)));
});

DEFINE_API(void, DrawList_AddImageRounded, (ImGui_DrawList*,draw_list)
(ImGui_Image*,img)(double,p_min_x)(double,p_min_y)(double,p_max_x)(double,p_max_y)
(double,uv_min_x)(double,uv_min_y)(double,uv_max_x)(double,uv_max_y)
(int,col_rgba)(double,rounding)(int*,API_RO(flags),ImDrawFlags_None),
"",
{
Context *ctx;
ImDrawList *dl { draw_list->get(&ctx) };
assertValid(img);
dl->AddImageRounded(img->makeTexture(ctx->textureManager()),
ImVec2(p_min_x, p_min_y), ImVec2(p_max_x, p_max_y),
ImVec2(uv_min_x, uv_min_y), ImVec2(uv_max_x, uv_max_y),
Color::fromBigEndian(col_rgba), rounding, API_RO_GET(flags));
});

API_SUBSECTION("Stateful Path",
"Stateful path API, add points then finish with PathFillConvex() or PathStroke().");

Expand Down
2 changes: 2 additions & 0 deletions api/drawlist.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class DrawListSplitter : public Resource {
ImDrawList *drawList() const;
ImDrawListSplitter *operator->();

bool attachable(const Context *) const override { return true; }

protected:
bool isValid() const override;

Expand Down
40 changes: 6 additions & 34 deletions api/font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ This API currently has multiple limitations (v1.0 blockers):
however characters outside those blocks are displayed as '?'.
See [issue #5](https://github.com/cfillion/reaimgui/issues/5).
- Dear ImGui does not support using new fonts in the middle of a frame.
Because of this, fonts must first be registered using AttachFont before any
Because of this, fonts must first be registered using Attach before any
other context functions are used in the same defer cycle.
(Attaching a font is a heavy operation and should ideally be done outside
of the defer loop.))");

DEFINE_API(ImGui_Font*, CreateFont,
(const char*,family_or_file)(int,size)(int*,API_RO(flags),ReaImGuiFontFlags_None),
R"(Load a font matching a font family name or from a font file.
The font will remain valid while it's attached to a context. See AttachFont.
The font will remain valid while it's attached to a context. See Attach.
The family name can be an installed font or one of the generic fonts:
sans-serif, serif, monospace, cursive, fantasy.
Expand All @@ -49,36 +49,6 @@ If 'family_or_file' specifies a path to a font file (contains a / or \):
return new Font { family_or_file, size, API_RO_GET(flags) };
});
static void outOfFrameCheck(Context *ctx)
{
if(ctx->inFrame())
throw reascript_error { "cannot modify font texture: a frame has already begun" };
}
DEFINE_API(void, AttachFont, (ImGui_Context*,ctx)
(ImGui_Font*,font),
R"(Enable a font for use in the given context.Fonts must be attached as soon
as possible after creating the context or on a new defer cycle.)",
{
assertValid(ctx);
assertValid(font);
outOfFrameCheck(ctx);
ctx->fonts().add(font);
});
DEFINE_API(void, DetachFont, (ImGui_Context*,ctx)
(ImGui_Font*,font),
R"(Unload a font from the given context. The font will be destroyed if is not
attached to any context.)",
{
assertValid(ctx);
assertValid(font);
outOfFrameCheck(ctx);
ctx->fonts().remove(font);
});
DEFINE_API(ImGui_Font*, GetFont, (ImGui_Context*,ctx),
"Get the current font",
{
Expand All @@ -88,7 +58,8 @@ DEFINE_API(ImGui_Font*, GetFont, (ImGui_Context*,ctx),
DEFINE_API(void, PushFont, (ImGui_Context*,ctx)
(ImGui_Font*,font),
"Change the current font. Use nil to push the default font. See PopFont.",
R"(Change the current font. Use nil to push the default font.
The font object must have been registered using Attach. See PopFont.)",
{
FRAME_GUARD;
ImGui::PushFont(ctx->fonts().instanceOf(font));
Expand All @@ -102,7 +73,8 @@ DEFINE_API(void, PopFont, (ImGui_Context*,ctx),
});
DEFINE_API(double, GetFontSize, (ImGui_Context*,ctx),
"Get current font size (= height in pixels) of current font with current scale applied",
R"(Get current font size (= height in pixels) of current font with current scale
applied.)",
{
FRAME_GUARD;
return ImGui::GetFontSize();
Expand Down
2 changes: 1 addition & 1 deletion api/helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ using DefArgVal = std::conditional_t<
BOOST_PP_EXPR_IF( \
BOOST_PP_GREATER_EQUAL(BOOST_PP_TUPLE_SIZE(arg), 3), \
constexpr DefArgVal<_ARG_TYPE(arg)> \
_DEFARG_ID(_ARG_NAME(arg)) { _ARG_DEFV(arg) }; \
_DEFARG_ID(_ARG_NAME(arg))(_ARG_DEFV(arg)); \
)

#define _API_CATCH(name, type, except) \
Expand Down
127 changes: 127 additions & 0 deletions api/image.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/* ReaImGui: ReaScript binding for Dear ImGui
* Copyright (C) 2021-2022 Christian Fillion
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "helper.hpp"

#include "color.hpp"
#include "image.hpp"

API_SECTION("Image",
R"(ReaImGui currently supports loading PNG and JPEG bitmap images.
Flat vector images may be loaded as fonts, see CreateFont.
UV parameters are texture coordinates in a scale of 0.0 (top/left) to 1.0
(bottom/right). Use values below 0.0 or above 1.0 to tile the image.
There are also image functions in the DrawList API such as
DrawList_AddImageQuad and DrawList_AddImageRounded.)");

// TODO: Attach/Detach API
DEFINE_API(ImGui_Image*, CreateImage,
(const char*,file)(int*,API_RO(flags)),
R"(The returned object is valid as long as it is used in each defer cycle
unless attached to a context (see Attach).

('flags' currently unused and reserved for future expansion))",
{
return Image::fromFile(file);
});

DEFINE_API(ImGui_Image*, CreateImageFromMem,
(const char*,data)(int,data_sz),
R"(Requires REAPER v6.44 or newer for EEL and Lua. Load from a file using
CreateImage or explicitely specify data_sz if supporting older versions.)",
{
// data_sz is inaccurate before REAPER 6.44
return Image::fromMemory(data, data_sz);
});

DEFINE_API(void, Image_GetSize, (ImGui_Image*,img)
(double*,API_W(w))(double*,API_W(h)),
"",
{
assertValid(img);
if(API_W(w)) *API_W(w) = img->width();
if(API_W(h)) *API_W(h) = img->height();
});

DEFINE_API(void, Image, (ImGui_Context*,ctx)
(ImGui_Image*,img)(double,size_w)(double,size_h)
(double*,API_RO(uv0_x),0.0)(double*,API_RO(uv0_y),0.0)
(double*,API_RO(uv1_x),1.0)(double*,API_RO(uv1_y),1.0)
(int*,API_RO(tint_col_rgba),0xFFFFFFFF)(int*,API_RO(border_col_rgba),0x00000000),
"",
{
FRAME_GUARD;
assertValid(img);

const ImTextureID tex { img->makeTexture(ctx->textureManager()) };
ImGui::Image(tex, ImVec2(size_w, size_h),
ImVec2(API_RO_GET(uv0_x), API_RO_GET(uv0_y)),
ImVec2(API_RO_GET(uv1_x), API_RO_GET(uv1_y)),
Color(API_RO_GET(tint_col_rgba)), Color(API_RO_GET(border_col_rgba)));
});

DEFINE_API(bool, ImageButton, (ImGui_Context*,ctx)
(const char*,str_id)(ImGui_Image*,img)(double,size_w)(double,size_h)
(double*,API_RO(uv0_x),0.0)(double*,API_RO(uv0_y),0.0)
(double*,API_RO(uv1_x),1.0)(double*,API_RO(uv1_y),1.0)
(int*,API_RO(bg_col_rgba),0x00000000)(int*,API_RO(tint_col_rgba),0xFFFFFFFF),
"",
{
FRAME_GUARD;
assertValid(img);

const ImTextureID tex { img->makeTexture(ctx->textureManager()) };
return ImGui::ImageButton(str_id, tex, ImVec2(size_w, size_h),
ImVec2(API_RO_GET(uv0_x), API_RO_GET(uv0_y)),
ImVec2(API_RO_GET(uv1_x), API_RO_GET(uv1_y)),
Color(API_RO_GET(bg_col_rgba)), Color(API_RO_GET(tint_col_rgba)));
});

API_SUBSECTION("Image Set",
R"(Helper to automatically select and scale an image to the DPI scale of
the current window upon usage.
ImGui_ImageSet objects can be given to any function that expect an image as
parameter.
Usage:
local set = reaper.ImGui_CreateImageSet()
reaper.ImGui_ImageSet_Add(set, 1.0, reaper.ImGui_CreateImage('32x32.png'))
reaper.ImGui_ImageSet_Add(set, 2.0, reaper.ImGui_CreateImage('64x64.png'))
local function frame()
reaper.ImGui_Image(ctx, set, reaper.ImGui_Image_GetSize(set))
-- ...
end)");

DEFINE_API(ImGui_ImageSet*, CreateImageSet, NO_ARGS,
"",
{
return new ImageSet;
});

DEFINE_API(void, ImageSet_Add, (ImGui_ImageSet*,set)
(double,scale)(ImGui_Image*,img),
"'img' cannot be another ImageSet.",
{
assertValid(set);
assertValid(img);
set->add(scale, img);
});
2 changes: 1 addition & 1 deletion api/listclipper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Generally what happens is:

DEFINE_API(ImGui_ListClipper*, CreateListClipper, (ImGui_Context*,ctx),
R"(The returned clipper object is only valid for the given context and is valid
as long as it is used in each defer cycle. See ListClipper_Begin.)",
as long as it is used in each defer cycle unless attached (see Attach).)",
{
assertValid(ctx);
return new ListClipper { ctx };
Expand Down
2 changes: 1 addition & 1 deletion api/textfilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Filter usage:

DEFINE_API(ImGui_TextFilter*, CreateTextFilter,
(const char*,API_RO(default_filter),""),
"Valid while used every frame.",
"Valid while used every frame unless attached to a context (see Attach).",
{
return new TextFilter { API_RO_GET(default_filter) };
});
Expand Down
2 changes: 2 additions & 0 deletions api/textfilter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class TextFilter : public Resource {
void set(const char *filter);
ImGuiTextFilter *operator->();

bool attachable(const Context *) const override { return true; }

private:
ImGuiTextFilter m_filter;
};
Expand Down
Loading

0 comments on commit cc6087e

Please sign in to comment.