initial commit

first public release
This commit is contained in:
ArthurFerreira2 2021-07-07 17:03:12 +02:00 committed by GitHub
parent 4c8b396e53
commit 62651e6e21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 62500 additions and 0 deletions

View File

@ -0,0 +1,11 @@
# Contributing
Pull requests are welcome, feel free to contribute if you have implemented something which might be useful for the general audience of this little piece of software. Apparently, it became kind of a community project now. :)
Whem contributing, please follow the following guidelines. I will keep it updated as we bump into something which worth doing better.
- Try to follow the same coding and naming conventions you find in the source already. I know that everyone has its own preference/taste in coding, but please keep the source consistent in style.
- Please submit to the 'dev' branch first for testing, and it will be merged to 'main' if it seems to work fine. I would like try keep 'master' in a good working condition, as more and more people are using it.
- Please send your submissions in small, well defined requests, i. e. do not accumulate many unrelated changes in one large pull request. Keep your submissions as small as possible, it will make everyone's life easier.
- Avoid using ImGui internal since it would make the source fragile against internal changes in ImGui.
- Try to keep the perormance high within the render function. Try to avoid doing anything which leads to memory allocations (like using temporary std::string, std::vector variables), or complex algorithm. If you really have to, try to amortise it between frames.
Thank you. :)

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 BalazsJako
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,33 @@
# ImGuiColorTextEdit
Syntax highlighting text editor for ImGui
![Screenshot](https://github.com/BalazsJako/ImGuiColorTextEdit/wiki/ImGuiTextEdit.png "Screenshot")
Demo project: https://github.com/BalazsJako/ColorTextEditorDemo
This started as my attempt to write a relatively simple widget which provides text editing functionality with syntax highlighting. Now there are other contributors who provide valuable additions.
While it relies on Omar Cornut's https://github.com/ocornut/imgui, it does not follow the "pure" one widget - one function approach. Since the editor has to maintain a relatively complex and large internal state, it did not seem to be practical to try and enforce fully immediate mode. It stores its internal state in an object instance which is reused across frames.
The code is (still) work in progress, please report if you find any issues.
# Main features
- approximates typical code editor look and feel (essential mouse/keyboard commands work - I mean, the commands _I_ normally use :))
- undo/redo
- UTF-8 support
- works with both fixed and variable-width fonts
- extensible syntax highlighting for multiple languages
- identifier declarations: a small piece of description can be associated with an identifier. The editor displays it in a tooltip when the mouse cursor is hovered over the identifier
- error markers: the user can specify a list of error messages together the line of occurence, the editor will highligh the lines with red backround and display error message in a tooltip when the mouse cursor is hovered over the line
- large files: there is no explicit limit set on file size or number of lines (below 2GB, performance is not affected when large files are loaded (except syntax coloring, see below)
- color palette support: you can switch between different color palettes, or even define your own
- whitespace indicators (TAB, space)
# Known issues
- syntax highligthing of most languages - except C/C++ - is based on std::regex, which is diasppointingly slow. Because of that, the highlighting process is amortized between multiple frames. C/C++ has a hand-written tokenizer which is much faster.
Please post your screenshots if you find this little piece of software useful. :)
# Contribute
If you want to contribute, please refer to CONTRIBUTE file.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,392 @@
#pragma once
#include <string>
#include <vector>
#include <array>
#include <memory>
#include <unordered_set>
#include <unordered_map>
#include <map>
#include <regex>
#include "imgui.h"
class TextEditor
{
public:
enum class PaletteIndex
{
Default,
Keyword,
Number,
String,
CharLiteral,
Punctuation,
Preprocessor,
Identifier,
KnownIdentifier,
PreprocIdentifier,
Comment,
MultiLineComment,
Background,
Cursor,
Selection,
ErrorMarker,
Breakpoint,
LineNumber,
CurrentLineFill,
CurrentLineFillInactive,
CurrentLineEdge,
Max
};
enum class SelectionMode
{
Normal,
Word,
Line
};
struct Breakpoint
{
int mLine;
bool mEnabled;
std::string mCondition;
Breakpoint()
: mLine(-1)
, mEnabled(false)
{}
};
// Represents a character coordinate from the user's point of view,
// i. e. consider an uniform grid (assuming fixed-width font) on the
// screen as it is rendered, and each cell has its own coordinate, starting from 0.
// Tabs are counted as [1..mTabSize] count empty spaces, depending on
// how many space is necessary to reach the next tab stop.
// For example, coordinate (1, 5) represents the character 'B' in a line "\tABC", when mTabSize = 4,
// because it is rendered as " ABC" on the screen.
struct Coordinates
{
int mLine, mColumn;
Coordinates() : mLine(0), mColumn(0) {}
Coordinates(int aLine, int aColumn) : mLine(aLine), mColumn(aColumn)
{
assert(aLine >= 0);
assert(aColumn >= 0);
}
static Coordinates Invalid() { static Coordinates invalid(-1, -1); return invalid; }
bool operator ==(const Coordinates& o) const
{
return
mLine == o.mLine &&
mColumn == o.mColumn;
}
bool operator !=(const Coordinates& o) const
{
return
mLine != o.mLine ||
mColumn != o.mColumn;
}
bool operator <(const Coordinates& o) const
{
if (mLine != o.mLine)
return mLine < o.mLine;
return mColumn < o.mColumn;
}
bool operator >(const Coordinates& o) const
{
if (mLine != o.mLine)
return mLine > o.mLine;
return mColumn > o.mColumn;
}
bool operator <=(const Coordinates& o) const
{
if (mLine != o.mLine)
return mLine < o.mLine;
return mColumn <= o.mColumn;
}
bool operator >=(const Coordinates& o) const
{
if (mLine != o.mLine)
return mLine > o.mLine;
return mColumn >= o.mColumn;
}
};
struct Identifier
{
Coordinates mLocation;
std::string mDeclaration;
};
typedef std::string String;
typedef std::unordered_map<std::string, Identifier> Identifiers;
typedef std::unordered_set<std::string> Keywords;
typedef std::map<int, std::string> ErrorMarkers;
typedef std::unordered_set<int> Breakpoints;
typedef std::array<ImU32, (unsigned)PaletteIndex::Max> Palette;
typedef uint8_t Char;
struct Glyph
{
Char mChar;
PaletteIndex mColorIndex = PaletteIndex::Default;
bool mComment : 1;
bool mMultiLineComment : 1;
bool mPreprocessor : 1;
Glyph(Char aChar, PaletteIndex aColorIndex) : mChar(aChar), mColorIndex(aColorIndex),
mComment(false), mMultiLineComment(false), mPreprocessor(false) {}
};
typedef std::vector<Glyph> Line;
typedef std::vector<Line> Lines;
struct LanguageDefinition
{
typedef std::pair<std::string, PaletteIndex> TokenRegexString;
typedef std::vector<TokenRegexString> TokenRegexStrings;
typedef bool(*TokenizeCallback)(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end, PaletteIndex & paletteIndex);
std::string mName;
Keywords mKeywords;
Identifiers mIdentifiers;
Identifiers mPreprocIdentifiers;
std::string mCommentStart, mCommentEnd, mSingleLineComment;
char mPreprocChar;
bool mAutoIndentation;
TokenizeCallback mTokenize;
TokenRegexStrings mTokenRegexStrings;
bool mCaseSensitive;
LanguageDefinition()
: mPreprocChar('#'), mAutoIndentation(true), mTokenize(nullptr), mCaseSensitive(true)
{
}
static const LanguageDefinition& CPlusPlus();
static const LanguageDefinition& HLSL();
static const LanguageDefinition& GLSL();
static const LanguageDefinition& C();
static const LanguageDefinition& SQL();
static const LanguageDefinition& AngelScript();
static const LanguageDefinition& Lua();
static const LanguageDefinition& AppleSoft(); // added by Arthur Ferreira for reinette May 26th 2021
};
TextEditor();
~TextEditor();
void SetLanguageDefinition(const LanguageDefinition& aLanguageDef);
const LanguageDefinition& GetLanguageDefinition() const { return mLanguageDefinition; }
const Palette& GetPalette() const { return mPaletteBase; }
void SetPalette(const Palette& aValue);
void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; }
void SetBreakpoints(const Breakpoints& aMarkers) { mBreakpoints = aMarkers; }
void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false);
void SetText(const std::string& aText);
std::string GetText() const;
void SetTextLines(const std::vector<std::string>& aLines);
std::vector<std::string> GetTextLines() const;
std::string GetSelectedText() const;
std::string GetCurrentLineText()const;
int GetTotalLines() const { return (int)mLines.size(); }
bool IsOverwrite() const { return mOverwrite; }
void SetReadOnly(bool aValue);
bool IsReadOnly() const { return mReadOnly; }
bool IsTextChanged() const { return mTextChanged; }
bool IsCursorPositionChanged() const { return mCursorPositionChanged; }
bool IsColorizerEnabled() const { return mColorizerEnabled; }
void SetColorizerEnable(bool aValue);
Coordinates GetCursorPosition() const { return GetActualCursorCoordinates(); }
void SetCursorPosition(const Coordinates& aPosition);
inline void SetHandleMouseInputs (bool aValue){ mHandleMouseInputs = aValue;}
inline bool IsHandleMouseInputsEnabled() const { return mHandleKeyboardInputs; }
inline void SetHandleKeyboardInputs (bool aValue){ mHandleKeyboardInputs = aValue;}
inline bool IsHandleKeyboardInputsEnabled() const { return mHandleKeyboardInputs; }
inline void SetImGuiChildIgnored (bool aValue){ mIgnoreImGuiChild = aValue;}
inline bool IsImGuiChildIgnored() const { return mIgnoreImGuiChild; }
inline void SetShowWhitespaces(bool aValue) { mShowWhitespaces = aValue; }
inline bool IsShowingWhitespaces() const { return mShowWhitespaces; }
void SetTabSize(int aValue);
inline int GetTabSize() const { return mTabSize; }
void InsertText(const std::string& aValue);
void InsertText(const char* aValue);
void MoveUp(int aAmount = 1, bool aSelect = false);
void MoveDown(int aAmount = 1, bool aSelect = false);
void MoveLeft(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
void MoveRight(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
void MoveTop(bool aSelect = false);
void MoveBottom(bool aSelect = false);
void MoveHome(bool aSelect = false);
void MoveEnd(bool aSelect = false);
void SetSelectionStart(const Coordinates& aPosition);
void SetSelectionEnd(const Coordinates& aPosition);
void SetSelection(const Coordinates& aStart, const Coordinates& aEnd, SelectionMode aMode = SelectionMode::Normal);
void SelectWordUnderCursor();
void SelectAll();
bool HasSelection() const;
void Copy();
void Cut();
void Paste();
void Delete();
bool CanUndo() const;
bool CanRedo() const;
void Undo(int aSteps = 1);
void Redo(int aSteps = 1);
static const Palette& GetDarkPalette();
static const Palette& GetLightPalette();
static const Palette& GetRetroBluePalette();
private:
typedef std::vector<std::pair<std::regex, PaletteIndex>> RegexList;
struct EditorState
{
Coordinates mSelectionStart;
Coordinates mSelectionEnd;
Coordinates mCursorPosition;
};
class UndoRecord
{
public:
UndoRecord() {}
~UndoRecord() {}
UndoRecord(
const std::string& aAdded,
const TextEditor::Coordinates aAddedStart,
const TextEditor::Coordinates aAddedEnd,
const std::string& aRemoved,
const TextEditor::Coordinates aRemovedStart,
const TextEditor::Coordinates aRemovedEnd,
TextEditor::EditorState& aBefore,
TextEditor::EditorState& aAfter);
void Undo(TextEditor* aEditor);
void Redo(TextEditor* aEditor);
std::string mAdded;
Coordinates mAddedStart;
Coordinates mAddedEnd;
std::string mRemoved;
Coordinates mRemovedStart;
Coordinates mRemovedEnd;
EditorState mBefore;
EditorState mAfter;
};
typedef std::vector<UndoRecord> UndoBuffer;
void ProcessInputs();
void Colorize(int aFromLine = 0, int aCount = -1);
void ColorizeRange(int aFromLine = 0, int aToLine = 0);
void ColorizeInternal();
float TextDistanceToLineStart(const Coordinates& aFrom) const;
void EnsureCursorVisible();
int GetPageSize() const;
std::string GetText(const Coordinates& aStart, const Coordinates& aEnd) const;
Coordinates GetActualCursorCoordinates() const;
Coordinates SanitizeCoordinates(const Coordinates& aValue) const;
void Advance(Coordinates& aCoordinates) const;
void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd);
int InsertTextAt(Coordinates& aWhere, const char* aValue);
void AddUndo(UndoRecord& aValue);
Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const;
Coordinates FindWordStart(const Coordinates& aFrom) const;
Coordinates FindWordEnd(const Coordinates& aFrom) const;
Coordinates FindNextWord(const Coordinates& aFrom) const;
int GetCharacterIndex(const Coordinates& aCoordinates) const;
int GetCharacterColumn(int aLine, int aIndex) const;
int GetLineCharacterCount(int aLine) const;
int GetLineMaxColumn(int aLine) const;
bool IsOnWordBoundary(const Coordinates& aAt) const;
void RemoveLine(int aStart, int aEnd);
void RemoveLine(int aIndex);
Line& InsertLine(int aIndex);
void EnterCharacter(ImWchar aChar, bool aShift);
void Backspace();
void DeleteSelection();
std::string GetWordUnderCursor() const;
std::string GetWordAt(const Coordinates& aCoords) const;
ImU32 GetGlyphColor(const Glyph& aGlyph) const;
void HandleKeyboardInputs();
void HandleMouseInputs();
void Render();
float mLineSpacing;
Lines mLines;
EditorState mState;
UndoBuffer mUndoBuffer;
int mUndoIndex;
int mTabSize;
bool mOverwrite;
bool mReadOnly;
bool mWithinRender;
bool mScrollToCursor;
bool mScrollToTop;
bool mTextChanged;
bool mColorizerEnabled;
float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor.
int mLeftMargin;
bool mCursorPositionChanged;
int mColorRangeMin, mColorRangeMax;
SelectionMode mSelectionMode;
bool mHandleKeyboardInputs;
bool mHandleMouseInputs;
bool mIgnoreImGuiChild;
bool mShowWhitespaces;
Palette mPaletteBase;
Palette mPalette;
LanguageDefinition mLanguageDefinition;
RegexList mRegexList;
bool mCheckComments;
Breakpoints mBreakpoints;
ErrorMarkers mErrorMarkers;
ImVec2 mCharAdvance;
Coordinates mInteractiveStart, mInteractiveEnd;
std::string mLineBuffer;
uint64_t mStartTime;
float mLastClick;
};

View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014-2021 Omar Cornut
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,430 @@
// dear imgui: Renderer + Platform Backend for Allegro 5
// (Info: Allegro 5 is a cross-platform general purpose library for handling windows, inputs, graphics, etc.)
// Implemented features:
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Platform: Clipboard support (from Allegro 5.1.12)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// Issues:
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
// [ ] Platform: Missing gamepad support.
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-02-18: Change blending equation to preserve alpha in output buffer.
// 2020-08-10: Inputs: Fixed horizontal mouse wheel direction.
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
// 2019-05-11: Inputs: Don't filter character value from ALLEGRO_EVENT_KEY_CHAR before calling AddInputCharacter().
// 2019-04-30: Renderer: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2018-11-30: Platform: Added touchscreen support.
// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
// 2018-06-13: Platform: Added clipboard support (from Allegro 5.1.12).
// 2018-06-13: Renderer: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-06-13: Renderer: Backup/restore transform and clipping rectangle.
// 2018-06-11: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-04-18: Misc: Renamed file from imgui_impl_a5.cpp to imgui_impl_allegro5.cpp.
// 2018-04-18: Misc: Added support for 32-bit vertex indices to avoid conversion at runtime. Added imconfig_allegro5.h to enforce 32-bit indices when included from imgui.h.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplAllegro5_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
#include <stdint.h> // uint64_t
#include <cstring> // memcpy
#include "imgui.h"
#include "imgui_impl_allegro5.h"
// Allegro
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#ifdef _WIN32
#include <allegro5/allegro_windows.h>
#endif
#define ALLEGRO_HAS_CLIPBOARD (ALLEGRO_VERSION_INT >= ((5 << 24) | (1 << 16) | (12 << 8))) // Clipboard only supported from Allegro 5.1.12
// Visual Studio warnings
#ifdef _MSC_VER
#pragma warning (disable: 4127) // condition expression is constant
#endif
// Data
static ALLEGRO_DISPLAY* g_Display = NULL;
static ALLEGRO_BITMAP* g_Texture = NULL;
static double g_Time = 0.0;
static ALLEGRO_MOUSE_CURSOR* g_MouseCursorInvisible = NULL;
static ALLEGRO_VERTEX_DECL* g_VertexDecl = NULL;
static char* g_ClipboardTextData = NULL;
struct ImDrawVertAllegro
{
ImVec2 pos;
ImVec2 uv;
ALLEGRO_COLOR col;
};
static void ImGui_ImplAllegro5_SetupRenderState(ImDrawData* draw_data)
{
// Setup blending
al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
// Setup orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
{
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
ALLEGRO_TRANSFORM transform;
al_identity_transform(&transform);
al_use_transform(&transform);
al_orthographic_transform(&transform, L, T, 1.0f, R, B, -1.0f);
al_use_projection_transform(&transform);
}
}
// Render function.
void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
// Backup Allegro state that will be modified
ALLEGRO_TRANSFORM last_transform = *al_get_current_transform();
ALLEGRO_TRANSFORM last_projection_transform = *al_get_current_projection_transform();
int last_clip_x, last_clip_y, last_clip_w, last_clip_h;
al_get_clipping_rectangle(&last_clip_x, &last_clip_y, &last_clip_w, &last_clip_h);
int last_blender_op, last_blender_src, last_blender_dst;
al_get_blender(&last_blender_op, &last_blender_src, &last_blender_dst);
// Setup desired render state
ImGui_ImplAllegro5_SetupRenderState(draw_data);
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
// Allegro's implementation of al_draw_indexed_prim() for DX9 is completely broken. Unindex our buffers ourselves.
// FIXME-OPT: Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 float as well..
static ImVector<ImDrawVertAllegro> vertices;
vertices.resize(cmd_list->IdxBuffer.Size);
for (int i = 0; i < cmd_list->IdxBuffer.Size; i++)
{
const ImDrawVert* src_v = &cmd_list->VtxBuffer[cmd_list->IdxBuffer[i]];
ImDrawVertAllegro* dst_v = &vertices[i];
dst_v->pos = src_v->pos;
dst_v->uv = src_v->uv;
unsigned char* c = (unsigned char*)&src_v->col;
dst_v->col = al_map_rgba(c[0], c[1], c[2], c[3]);
}
const int* indices = NULL;
if (sizeof(ImDrawIdx) == 2)
{
// FIXME-OPT: Unfortunately Allegro doesn't support 16-bit indices.. You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices.
// Otherwise, we convert them from 16-bit to 32-bit at runtime here, which works perfectly but is a little wasteful.
static ImVector<int> indices_converted;
indices_converted.resize(cmd_list->IdxBuffer.Size);
for (int i = 0; i < cmd_list->IdxBuffer.Size; ++i)
indices_converted[i] = (int)cmd_list->IdxBuffer.Data[i];
indices = indices_converted.Data;
}
else if (sizeof(ImDrawIdx) == 4)
{
indices = (const int*)cmd_list->IdxBuffer.Data;
}
// Render command lists
int idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplAllegro5_SetupRenderState(draw_data);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Draw
ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->TextureId;
al_set_clipping_rectangle(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y, pcmd->ClipRect.z - pcmd->ClipRect.x, pcmd->ClipRect.w - pcmd->ClipRect.y);
al_draw_prim(&vertices[0], g_VertexDecl, texture, idx_offset, idx_offset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
}
idx_offset += pcmd->ElemCount;
}
}
// Restore modified Allegro state
al_set_blender(last_blender_op, last_blender_src, last_blender_dst);
al_set_clipping_rectangle(last_clip_x, last_clip_y, last_clip_w, last_clip_h);
al_use_transform(&last_transform);
al_use_projection_transform(&last_projection_transform);
}
bool ImGui_ImplAllegro5_CreateDeviceObjects()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// Create texture
int flags = al_get_new_bitmap_flags();
int fmt = al_get_new_bitmap_format();
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP | ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR);
al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE);
ALLEGRO_BITMAP* img = al_create_bitmap(width, height);
al_set_new_bitmap_flags(flags);
al_set_new_bitmap_format(fmt);
if (!img)
return false;
ALLEGRO_LOCKED_REGION* locked_img = al_lock_bitmap(img, al_get_bitmap_format(img), ALLEGRO_LOCK_WRITEONLY);
if (!locked_img)
{
al_destroy_bitmap(img);
return false;
}
memcpy(locked_img->data, pixels, sizeof(int) * width * height);
al_unlock_bitmap(img);
// Convert software texture to hardware texture.
ALLEGRO_BITMAP* cloned_img = al_clone_bitmap(img);
al_destroy_bitmap(img);
if (!cloned_img)
return false;
// Store our identifier
io.Fonts->SetTexID((void*)cloned_img);
g_Texture = cloned_img;
// Create an invisible mouse cursor
// Because al_hide_mouse_cursor() seems to mess up with the actual inputs..
ALLEGRO_BITMAP* mouse_cursor = al_create_bitmap(8, 8);
g_MouseCursorInvisible = al_create_mouse_cursor(mouse_cursor, 0, 0);
al_destroy_bitmap(mouse_cursor);
return true;
}
void ImGui_ImplAllegro5_InvalidateDeviceObjects()
{
if (g_Texture)
{
ImGuiIO& io = ImGui::GetIO();
io.Fonts->SetTexID(NULL);
al_destroy_bitmap(g_Texture);
g_Texture = NULL;
}
if (g_MouseCursorInvisible)
{
al_destroy_mouse_cursor(g_MouseCursorInvisible);
g_MouseCursorInvisible = NULL;
}
}
#if ALLEGRO_HAS_CLIPBOARD
static const char* ImGui_ImplAllegro5_GetClipboardText(void*)
{
if (g_ClipboardTextData)
al_free(g_ClipboardTextData);
g_ClipboardTextData = al_get_clipboard_text(g_Display);
return g_ClipboardTextData;
}
static void ImGui_ImplAllegro5_SetClipboardText(void*, const char* text)
{
al_set_clipboard_text(g_Display, text);
}
#endif
bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
{
g_Display = display;
// Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendPlatformName = io.BackendRendererName = "imgui_impl_allegro5";
// Create custom vertex declaration.
// Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 floats.
// We still use a custom declaration to use 'ALLEGRO_PRIM_TEX_COORD' instead of 'ALLEGRO_PRIM_TEX_COORD_PIXEL' else we can't do a reliable conversion.
ALLEGRO_VERTEX_ELEMENT elems[] =
{
{ ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, IM_OFFSETOF(ImDrawVertAllegro, pos) },
{ ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_FLOAT_2, IM_OFFSETOF(ImDrawVertAllegro, uv) },
{ ALLEGRO_PRIM_COLOR_ATTR, 0, IM_OFFSETOF(ImDrawVertAllegro, col) },
{ 0, 0, 0 }
};
g_VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro));
io.KeyMap[ImGuiKey_Tab] = ALLEGRO_KEY_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = ALLEGRO_KEY_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = ALLEGRO_KEY_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = ALLEGRO_KEY_UP;
io.KeyMap[ImGuiKey_DownArrow] = ALLEGRO_KEY_DOWN;
io.KeyMap[ImGuiKey_PageUp] = ALLEGRO_KEY_PGUP;
io.KeyMap[ImGuiKey_PageDown] = ALLEGRO_KEY_PGDN;
io.KeyMap[ImGuiKey_Home] = ALLEGRO_KEY_HOME;
io.KeyMap[ImGuiKey_End] = ALLEGRO_KEY_END;
io.KeyMap[ImGuiKey_Insert] = ALLEGRO_KEY_INSERT;
io.KeyMap[ImGuiKey_Delete] = ALLEGRO_KEY_DELETE;
io.KeyMap[ImGuiKey_Backspace] = ALLEGRO_KEY_BACKSPACE;
io.KeyMap[ImGuiKey_Space] = ALLEGRO_KEY_SPACE;
io.KeyMap[ImGuiKey_Enter] = ALLEGRO_KEY_ENTER;
io.KeyMap[ImGuiKey_Escape] = ALLEGRO_KEY_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = ALLEGRO_KEY_PAD_ENTER;
io.KeyMap[ImGuiKey_A] = ALLEGRO_KEY_A;
io.KeyMap[ImGuiKey_C] = ALLEGRO_KEY_C;
io.KeyMap[ImGuiKey_V] = ALLEGRO_KEY_V;
io.KeyMap[ImGuiKey_X] = ALLEGRO_KEY_X;
io.KeyMap[ImGuiKey_Y] = ALLEGRO_KEY_Y;
io.KeyMap[ImGuiKey_Z] = ALLEGRO_KEY_Z;
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
#if ALLEGRO_HAS_CLIPBOARD
io.SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText;
io.ClipboardUserData = NULL;
#endif
return true;
}
void ImGui_ImplAllegro5_Shutdown()
{
ImGui_ImplAllegro5_InvalidateDeviceObjects();
g_Display = NULL;
g_Time = 0.0;
if (g_VertexDecl)
al_destroy_vertex_decl(g_VertexDecl);
g_VertexDecl = NULL;
if (g_ClipboardTextData)
al_free(g_ClipboardTextData);
g_ClipboardTextData = NULL;
}
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* ev)
{
ImGuiIO& io = ImGui::GetIO();
switch (ev->type)
{
case ALLEGRO_EVENT_MOUSE_AXES:
if (ev->mouse.display == g_Display)
{
io.MouseWheel += ev->mouse.dz;
io.MouseWheelH -= ev->mouse.dw;
io.MousePos = ImVec2(ev->mouse.x, ev->mouse.y);
}
return true;
case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
if (ev->mouse.display == g_Display && ev->mouse.button <= 5)
io.MouseDown[ev->mouse.button - 1] = (ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
return true;
case ALLEGRO_EVENT_TOUCH_MOVE:
if (ev->touch.display == g_Display)
io.MousePos = ImVec2(ev->touch.x, ev->touch.y);
return true;
case ALLEGRO_EVENT_TOUCH_BEGIN:
case ALLEGRO_EVENT_TOUCH_END:
case ALLEGRO_EVENT_TOUCH_CANCEL:
if (ev->touch.display == g_Display && ev->touch.primary)
io.MouseDown[0] = (ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
return true;
case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
if (ev->mouse.display == g_Display)
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
return true;
case ALLEGRO_EVENT_KEY_CHAR:
if (ev->keyboard.display == g_Display)
if (ev->keyboard.unichar != 0)
io.AddInputCharacter((unsigned int)ev->keyboard.unichar);
return true;
case ALLEGRO_EVENT_KEY_DOWN:
case ALLEGRO_EVENT_KEY_UP:
if (ev->keyboard.display == g_Display)
io.KeysDown[ev->keyboard.keycode] = (ev->type == ALLEGRO_EVENT_KEY_DOWN);
return true;
}
return false;
}
static void ImGui_ImplAllegro5_UpdateMouseCursor()
{
ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
return;
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
al_set_mouse_cursor(g_Display, g_MouseCursorInvisible);
}
else
{
ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT;
switch (imgui_cursor)
{
case ImGuiMouseCursor_TextInput: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT; break;
case ImGuiMouseCursor_ResizeAll: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_MOVE; break;
case ImGuiMouseCursor_ResizeNS: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N; break;
case ImGuiMouseCursor_ResizeEW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E; break;
case ImGuiMouseCursor_ResizeNESW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE; break;
case ImGuiMouseCursor_ResizeNWSE: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW; break;
case ImGuiMouseCursor_NotAllowed: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE; break;
}
al_set_system_mouse_cursor(g_Display, cursor_id);
}
}
void ImGui_ImplAllegro5_NewFrame()
{
if (!g_Texture)
ImGui_ImplAllegro5_CreateDeviceObjects();
ImGuiIO& io = ImGui::GetIO();
// Setup display size (every frame to accommodate for window resizing)
int w, h;
w = al_get_display_width(g_Display);
h = al_get_display_height(g_Display);
io.DisplaySize = ImVec2((float)w, (float)h);
// Setup time step
double current_time = al_get_time();
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
g_Time = current_time;
// Setup inputs
ALLEGRO_KEYBOARD_STATE keys;
al_get_keyboard_state(&keys);
io.KeyCtrl = al_key_down(&keys, ALLEGRO_KEY_LCTRL) || al_key_down(&keys, ALLEGRO_KEY_RCTRL);
io.KeyShift = al_key_down(&keys, ALLEGRO_KEY_LSHIFT) || al_key_down(&keys, ALLEGRO_KEY_RSHIFT);
io.KeyAlt = al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR);
io.KeySuper = al_key_down(&keys, ALLEGRO_KEY_LWIN) || al_key_down(&keys, ALLEGRO_KEY_RWIN);
ImGui_ImplAllegro5_UpdateMouseCursor();
}

View File

@ -0,0 +1,30 @@
// dear imgui: Renderer + Platform Backend for Allegro 5
// (Info: Allegro 5 is a cross-platform general purpose library for handling windows, inputs, graphics, etc.)
// Implemented features:
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Platform: Clipboard support (from Allegro 5.1.12)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// Issues:
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
// [ ] Platform: Missing gamepad support.
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
struct ALLEGRO_DISPLAY;
union ALLEGRO_EVENT;
IMGUI_IMPL_API bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display);
IMGUI_IMPL_API void ImGui_ImplAllegro5_Shutdown();
IMGUI_IMPL_API void ImGui_ImplAllegro5_NewFrame();
IMGUI_IMPL_API void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data);
IMGUI_IMPL_API bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* event);
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API bool ImGui_ImplAllegro5_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplAllegro5_InvalidateDeviceObjects();

View File

@ -0,0 +1,187 @@
// dear imgui: Platform Binding for Android native app
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
// Implemented features:
// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE).
// Missing features:
// [ ] Platform: Clipboard support.
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
// Important:
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-03-04: Initial version.
#include "imgui.h"
#include "imgui_impl_android.h"
#include <time.h>
#include <map>
#include <queue>
#include <android/native_window.h>
#include <android/input.h>
#include <android/keycodes.h>
#include <android/log.h>
// Android data
static double g_Time = 0.0;
static ANativeWindow* g_Window;
static char g_LogTag[] = "ImGuiExample";
static std::map<int32_t, std::queue<int32_t>> g_KeyEventQueues; // FIXME: Remove dependency on map and queue once we use upcoming input queue.
int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event)
{
ImGuiIO& io = ImGui::GetIO();
int32_t event_type = AInputEvent_getType(input_event);
switch (event_type)
{
case AINPUT_EVENT_TYPE_KEY:
{
int32_t event_key_code = AKeyEvent_getKeyCode(input_event);
int32_t event_action = AKeyEvent_getAction(input_event);
int32_t event_meta_state = AKeyEvent_getMetaState(input_event);
io.KeyCtrl = ((event_meta_state & AMETA_CTRL_ON) != 0);
io.KeyShift = ((event_meta_state & AMETA_SHIFT_ON) != 0);
io.KeyAlt = ((event_meta_state & AMETA_ALT_ON) != 0);
switch (event_action)
{
// FIXME: AKEY_EVENT_ACTION_DOWN and AKEY_EVENT_ACTION_UP occur at once as soon as a touch pointer
// goes up from a key. We use a simple key event queue/ and process one event per key per frame in
// ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787
case AKEY_EVENT_ACTION_DOWN:
case AKEY_EVENT_ACTION_UP:
g_KeyEventQueues[event_key_code].push(event_action);
break;
default:
break;
}
break;
}
case AINPUT_EVENT_TYPE_MOTION:
{
int32_t event_action = AMotionEvent_getAction(input_event);
int32_t event_pointer_index = (event_action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
event_action &= AMOTION_EVENT_ACTION_MASK;
switch (event_action)
{
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_UP:
// Physical mouse buttons (and probably other physical devices) also invoke the actions AMOTION_EVENT_ACTION_DOWN/_UP,
// but we have to process them separately to identify the actual button pressed. This is done below via
// AMOTION_EVENT_ACTION_BUTTON_PRESS/_RELEASE. Here, we only process "FINGER" input (and "UNKNOWN", as a fallback).
if((AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER)
|| (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN))
{
io.MouseDown[0] = (event_action == AMOTION_EVENT_ACTION_DOWN) ? true : false;
io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
}
break;
case AMOTION_EVENT_ACTION_BUTTON_PRESS:
case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
{
int32_t button_state = AMotionEvent_getButtonState(input_event);
io.MouseDown[0] = (button_state & AMOTION_EVENT_BUTTON_PRIMARY) ? true : false;
io.MouseDown[1] = (button_state & AMOTION_EVENT_BUTTON_SECONDARY) ? true : false;
io.MouseDown[2] = (button_state & AMOTION_EVENT_BUTTON_TERTIARY) ? true : false;
}
break;
case AMOTION_EVENT_ACTION_HOVER_MOVE: // Hovering: Tool moves while NOT pressed (such as a physical mouse)
case AMOTION_EVENT_ACTION_MOVE: // Touch pointer moves while DOWN
io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
break;
case AMOTION_EVENT_ACTION_SCROLL:
io.MouseWheel = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index);
io.MouseWheelH = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index);
break;
default:
break;
}
}
return 1;
default:
break;
}
return 0;
}
bool ImGui_ImplAndroid_Init(ANativeWindow* window)
{
g_Window = window;
g_Time = 0.0;
// Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendPlatformName = "imgui_impl_android";
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = AKEYCODE_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = AKEYCODE_DPAD_LEFT; // also covers physical keyboard arrow key
io.KeyMap[ImGuiKey_RightArrow] = AKEYCODE_DPAD_RIGHT; // also covers physical keyboard arrow key
io.KeyMap[ImGuiKey_UpArrow] = AKEYCODE_DPAD_UP; // also covers physical keyboard arrow key
io.KeyMap[ImGuiKey_DownArrow] = AKEYCODE_DPAD_DOWN; // also covers physical keyboard arrow key
io.KeyMap[ImGuiKey_PageUp] = AKEYCODE_PAGE_UP;
io.KeyMap[ImGuiKey_PageDown] = AKEYCODE_PAGE_DOWN;
io.KeyMap[ImGuiKey_Home] = AKEYCODE_MOVE_HOME;
io.KeyMap[ImGuiKey_End] = AKEYCODE_MOVE_END;
io.KeyMap[ImGuiKey_Insert] = AKEYCODE_INSERT;
io.KeyMap[ImGuiKey_Delete] = AKEYCODE_FORWARD_DEL;
io.KeyMap[ImGuiKey_Backspace] = AKEYCODE_DEL;
io.KeyMap[ImGuiKey_Space] = AKEYCODE_SPACE;
io.KeyMap[ImGuiKey_Enter] = AKEYCODE_ENTER;
io.KeyMap[ImGuiKey_Escape] = AKEYCODE_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = AKEYCODE_NUMPAD_ENTER;
io.KeyMap[ImGuiKey_A] = AKEYCODE_A;
io.KeyMap[ImGuiKey_C] = AKEYCODE_C;
io.KeyMap[ImGuiKey_V] = AKEYCODE_V;
io.KeyMap[ImGuiKey_X] = AKEYCODE_X;
io.KeyMap[ImGuiKey_Y] = AKEYCODE_Y;
io.KeyMap[ImGuiKey_Z] = AKEYCODE_Z;
return true;
}
void ImGui_ImplAndroid_Shutdown()
{
}
void ImGui_ImplAndroid_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
// Process queued key events
// FIXME: This is a workaround for multiple key event actions occurring at once (see above) and can be removed once we use upcoming input queue.
for (auto& key_queue : g_KeyEventQueues)
{
if (key_queue.second.empty())
continue;
io.KeysDown[key_queue.first] = (key_queue.second.front() == AKEY_EVENT_ACTION_DOWN);
key_queue.second.pop();
}
// Setup display size (every frame to accommodate for window resizing)
int32_t window_width = ANativeWindow_getWidth(g_Window);
int32_t window_height = ANativeWindow_getHeight(g_Window);
int display_width = window_width;
int display_height = window_height;
io.DisplaySize = ImVec2((float)window_width, (float)window_height);
if (window_width > 0 && window_height > 0)
io.DisplayFramebufferScale = ImVec2((float)display_width / window_width, (float)display_height / window_height);
// Setup time step
struct timespec current_timespec;
clock_gettime(CLOCK_MONOTONIC, &current_timespec);
double current_time = (double)(current_timespec.tv_sec) + (current_timespec.tv_nsec / 1000000000.0);
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
g_Time = current_time;
}

View File

@ -0,0 +1,26 @@
// dear imgui: Platform Binding for Android native app
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
// Implemented features:
// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE).
// Missing features:
// [ ] Platform: Clipboard support.
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
// Important:
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
#pragma once
struct ANativeWindow;
struct AInputEvent;
IMGUI_IMPL_API bool ImGui_ImplAndroid_Init(ANativeWindow* window);
IMGUI_IMPL_API int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event);
IMGUI_IMPL_API void ImGui_ImplAndroid_Shutdown();
IMGUI_IMPL_API void ImGui_ImplAndroid_NewFrame();

View File

@ -0,0 +1,536 @@
// dear imgui: Renderer Backend for DirectX10
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture backend. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-02-18: DirectX10: Change blending equation to preserve alpha in output buffer.
// 2019-07-21: DirectX10: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData().
// 2019-05-29: DirectX10: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX10: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-07-13: DirectX10: Fixed unreleased resources in Init and Shutdown functions.
// 2018-06-08: Misc: Extracted imgui_impl_dx10.cpp/.h away from the old combined DX10+Win32 example.
// 2018-06-08: DirectX10: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-04-09: Misc: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that was left in DX10 example but removed in 1.47 (Nov 2015) on other backends.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX10_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2016-05-07: DirectX10: Disabling depth-write.
#include "imgui.h"
#include "imgui_impl_dx10.h"
// DirectX
#include <stdio.h>
#include <d3d10_1.h>
#include <d3d10.h>
#include <d3dcompiler.h>
#ifdef _MSC_VER
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
#endif
// DirectX data
static ID3D10Device* g_pd3dDevice = NULL;
static IDXGIFactory* g_pFactory = NULL;
static ID3D10Buffer* g_pVB = NULL;
static ID3D10Buffer* g_pIB = NULL;
static ID3D10VertexShader* g_pVertexShader = NULL;
static ID3D10InputLayout* g_pInputLayout = NULL;
static ID3D10Buffer* g_pVertexConstantBuffer = NULL;
static ID3D10PixelShader* g_pPixelShader = NULL;
static ID3D10SamplerState* g_pFontSampler = NULL;
static ID3D10ShaderResourceView*g_pFontTextureView = NULL;
static ID3D10RasterizerState* g_pRasterizerState = NULL;
static ID3D10BlendState* g_pBlendState = NULL;
static ID3D10DepthStencilState* g_pDepthStencilState = NULL;
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
struct VERTEX_CONSTANT_BUFFER
{
float mvp[4][4];
};
static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* ctx)
{
// Setup viewport
D3D10_VIEWPORT vp;
memset(&vp, 0, sizeof(D3D10_VIEWPORT));
vp.Width = (UINT)draw_data->DisplaySize.x;
vp.Height = (UINT)draw_data->DisplaySize.y;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = vp.TopLeftY = 0;
ctx->RSSetViewports(1, &vp);
// Bind shader and vertex buffers
unsigned int stride = sizeof(ImDrawVert);
unsigned int offset = 0;
ctx->IASetInputLayout(g_pInputLayout);
ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
ctx->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ctx->VSSetShader(g_pVertexShader);
ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
ctx->PSSetShader(g_pPixelShader);
ctx->PSSetSamplers(0, 1, &g_pFontSampler);
ctx->GSSetShader(NULL);
// Setup render state
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff);
ctx->OMSetDepthStencilState(g_pDepthStencilState, 0);
ctx->RSSetState(g_pRasterizerState);
}
// Render function
void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
ID3D10Device* ctx = g_pd3dDevice;
// Create and grow vertex/index buffers if needed
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
{
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
D3D10_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
if (ctx->CreateBuffer(&desc, NULL, &g_pVB) < 0)
return;
}
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
{
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
D3D10_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
if (ctx->CreateBuffer(&desc, NULL, &g_pIB) < 0)
return;
}
// Copy and convert all vertices into a single contiguous buffer
ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
g_pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst);
g_pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst);
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
g_pVB->Unmap();
g_pIB->Unmap();
// Setup orthographic projection matrix into our constant buffer
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
{
void* mapped_resource;
if (g_pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
return;
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource;
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
float mvp[4][4] =
{
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.5f, 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
};
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
g_pVertexConstantBuffer->Unmap();
}
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
struct BACKUP_DX10_STATE
{
UINT ScissorRectsCount, ViewportsCount;
D3D10_RECT ScissorRects[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
D3D10_VIEWPORT Viewports[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
ID3D10RasterizerState* RS;
ID3D10BlendState* BlendState;
FLOAT BlendFactor[4];
UINT SampleMask;
UINT StencilRef;
ID3D10DepthStencilState* DepthStencilState;
ID3D10ShaderResourceView* PSShaderResource;
ID3D10SamplerState* PSSampler;
ID3D10PixelShader* PS;
ID3D10VertexShader* VS;
ID3D10GeometryShader* GS;
D3D10_PRIMITIVE_TOPOLOGY PrimitiveTopology;
ID3D10Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
DXGI_FORMAT IndexBufferFormat;
ID3D10InputLayout* InputLayout;
};
BACKUP_DX10_STATE old;
old.ScissorRectsCount = old.ViewportsCount = D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
ctx->RSGetState(&old.RS);
ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
ctx->PSGetSamplers(0, 1, &old.PSSampler);
ctx->PSGetShader(&old.PS);
ctx->VSGetShader(&old.VS);
ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
ctx->GSGetShader(&old.GS);
ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
ctx->IAGetInputLayout(&old.InputLayout);
// Setup desired DX state
ImGui_ImplDX10_SetupRenderState(draw_data, ctx);
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
int global_vtx_offset = 0;
int global_idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplDX10_SetupRenderState(draw_data, ctx);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Apply scissor/clipping rectangle
const D3D10_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y)};
ctx->RSSetScissorRects(1, &r);
// Bind texture, Draw
ID3D10ShaderResourceView* texture_srv = (ID3D10ShaderResourceView*)pcmd->TextureId;
ctx->PSSetShaderResources(0, 1, &texture_srv);
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
}
}
global_idx_offset += cmd_list->IdxBuffer.Size;
global_vtx_offset += cmd_list->VtxBuffer.Size;
}
// Restore modified DX state
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
ctx->PSSetShader(old.PS); if (old.PS) old.PS->Release();
ctx->VSSetShader(old.VS); if (old.VS) old.VS->Release();
ctx->GSSetShader(old.GS); if (old.GS) old.GS->Release();
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
}
static void ImGui_ImplDX10_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// Upload texture to graphics system
{
D3D10_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DEFAULT;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
ID3D10Texture2D* pTexture = NULL;
D3D10_SUBRESOURCE_DATA subResource;
subResource.pSysMem = pixels;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
// Create texture view