From 53685bb0f1ee2823d0c26f44657a5bb670f1ffe1 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Tue, 16 Mar 2021 00:21:09 +0100 Subject: [PATCH] [DEV] continue rework --- .classpath | 51 +- lib/freetype-jni.jar | Bin 0 -> 18392 bytes lib/libfreetype-jni.so | Bin 0 -> 1030728 bytes resources/data/color.frag | 10 + resources/data/color.prog | 2 + resources/data/color.vert | 18 + resources/data/color3.frag | 10 + resources/data/color3.prog | 2 + resources/data/color3.vert | 18 + resources/data/ewol-gui-file-chooser.xml | 50 + resources/data/fonts/FreeMono.svg | 9874 +++++ resources/data/fonts/FreeMonoBold.svg | 5443 +++ resources/data/fonts/FreeMonoBoldOblique.svg | 5198 +++ resources/data/fonts/FreeMonoOblique.svg | 6389 +++ resources/data/fonts/FreeSans.svg | 15542 +++++++ resources/data/fonts/FreeSansBold.svg | 8052 ++++ resources/data/fonts/FreeSansBoldOblique.svg | 7236 ++++ resources/data/fonts/FreeSansOblique.svg | 9376 +++++ resources/data/fonts/FreeSerif.svg | 34749 ++++++++++++++++ resources/data/icon.svg | 67 + resources/data/simple3D.frag | 10 + resources/data/simple3D.prog | 2 + resources/data/simple3D.vert | 18 + resources/data/text.frag | 41 + resources/data/text.prog | 2 + resources/data/text.vert | 47 + resources/data/textured.frag | 14 + resources/data/textured.prog | 2 + resources/data/textured.vert | 22 + resources/data/textured3D.frag | 15 + resources/data/textured3D.prog | 2 + resources/data/textured3D.vert | 21 + resources/data/textured3D2.frag | 55 + resources/data/textured3D2.prog | 2 + resources/data/textured3D2.vert | 25 + resources/data/texturedDF.frag | 25 + resources/data/texturedDF.vert | 22 + resources/data/texturedNoMaterial.frag | 13 + resources/data/texturedNoMaterial.prog | 2 + resources/data/texturedNoMaterial.vert | 18 + resources/data/theme/color/black/Button.json | 10 + .../data/theme/color/black/CheckBox.json | 10 + .../data/theme/color/black/ContextMenu.json | 7 + resources/data/theme/color/black/Entry.json | 13 + resources/data/theme/color/black/Image.json | 5 + resources/data/theme/color/black/Label.json | 6 + .../theme/color/black/ListFileSystem.json | 8 + resources/data/theme/color/black/PopUp.json | 7 + .../theme/color/black/WidgetScrolled.json | 8 + resources/data/theme/color/black/Windows.json | 5 + resources/data/theme/color/white/Button.json | 10 + .../data/theme/color/white/CheckBox.json | 10 + .../data/theme/color/white/ContextMenu.json | 7 + resources/data/theme/color/white/Entry.json | 13 + resources/data/theme/color/white/Image.json | 5 + resources/data/theme/color/white/Label.json | 6 + .../theme/color/white/ListFileSystem.json | 8 + resources/data/theme/color/white/PopUp.json | 7 + .../theme/color/white/WidgetScrolled.json | 8 + resources/data/theme/color/white/Windows.json | 5 + resources/data/theme/default/Add.svg | 7 + resources/data/theme/default/AtoZ.svg | 11 + resources/data/theme/default/Attache.svg | 7 + .../data/theme/default/CaseSensitive.svg | 13 + resources/data/theme/default/ChevronLeft.svg | 66 + resources/data/theme/default/ChevronLess.svg | 66 + resources/data/theme/default/ChevronMore.svg | 66 + resources/data/theme/default/ChevronRight.svg | 66 + resources/data/theme/default/Close.svg | 9 + resources/data/theme/default/Contact.svg | 14 + resources/data/theme/default/Down.svg | 14 + .../data/theme/default/FavoriteDisable.svg | 7 + .../data/theme/default/FavoriteEnable.svg | 9 + .../data/theme/default/FavoriteMiddle.svg | 9 + resources/data/theme/default/File.svg | 4 + resources/data/theme/default/Folder.svg | 7 + resources/data/theme/default/Forbidden.svg | 60 + resources/data/theme/default/Help.svg | 7 + resources/data/theme/default/Home.svg | 11 + resources/data/theme/default/Info.svg | 7 + resources/data/theme/default/List.svg | 11 + resources/data/theme/default/Load.svg | 7 + resources/data/theme/default/Lock.svg | 7 + resources/data/theme/default/Next.svg | 7 + resources/data/theme/default/OpenMenu.svg | 9 + resources/data/theme/default/Parameter.svg | 61 + resources/data/theme/default/Previous.svg | 7 + resources/data/theme/default/Quit.svg | 9 + resources/data/theme/default/Redo.svg | 12 + resources/data/theme/default/Remove.svg | 7 + resources/data/theme/default/Remove2.svg | 63 + resources/data/theme/default/Replace.svg | 15 + resources/data/theme/default/SDCard.svg | 7 + resources/data/theme/default/Save.svg | 16 + resources/data/theme/default/Search.svg | 49 + resources/data/theme/default/Trash.svg | 9 + resources/data/theme/default/Undo.svg | 12 + resources/data/theme/default/Up.svg | 14 + resources/data/theme/default/Update.svg | 9 + resources/data/theme/default/Validate.svg | 7 + resources/data/theme/default/VolumeMax.svg | 13 + resources/data/theme/default/VolumeMute.svg | 9 + resources/data/theme/default/Warning.svg | 7 + resources/data/theme/default/WhereAmI.svg | 17 + resources/data/theme/default/WrapAround.svg | 13 + resources/data/theme/default/ZoomIn.svg | 9 + resources/data/theme/shape/round/Button.frag | 27 + resources/data/theme/shape/round/Button.json | 23 + resources/data/theme/shape/round/Button.vert | 51 + .../data/theme/shape/round/CheckBox.frag | 70 + .../data/theme/shape/round/CheckBox.json | 11 + .../data/theme/shape/round/CheckBox.vert | 63 + .../data/theme/shape/round/ContextMenu.frag | 26 + .../data/theme/shape/round/ContextMenu.json | 23 + .../data/theme/shape/round/ContextMenu.vert | 17 + resources/data/theme/shape/round/Entry.frag | 28 + resources/data/theme/shape/round/Entry.json | 23 + resources/data/theme/shape/round/Entry.vert | 17 + resources/data/theme/shape/round/PopUp.frag | 26 + resources/data/theme/shape/round/PopUp.json | 23 + resources/data/theme/shape/round/PopUp.vert | 20 + .../theme/shape/round/WidgetScrolled.frag | 60 + .../theme/shape/round/WidgetScrolled.json | 9 + .../theme/shape/round/WidgetScrolled.vert | 50 + resources/data/theme/shape/square/Button.frag | 26 + resources/data/theme/shape/square/Button.json | 23 + resources/data/theme/shape/square/Button.vert | 52 + .../data/theme/shape/square/CheckBox.frag | 28 + .../data/theme/shape/square/CheckBox.json | 25 + .../data/theme/shape/square/CheckBox.vert | 71 + .../data/theme/shape/square/ContextMenu.frag | 27 + .../data/theme/shape/square/ContextMenu.json | 23 + .../data/theme/shape/square/ContextMenu.vert | 28 + resources/data/theme/shape/square/Entry.frag | 27 + resources/data/theme/shape/square/Entry.json | 23 + resources/data/theme/shape/square/Entry.vert | 50 + resources/data/theme/shape/square/PopUp.frag | 27 + resources/data/theme/shape/square/PopUp.json | 23 + resources/data/theme/shape/square/PopUp.vert | 17 + resources/data/theme/shape/square/Select.json | 5 + .../data/theme/shape/square/SelectBt.json | 23 + .../data/theme/shape/square/SelectEntry.json | 23 + resources/data/theme/shape/square/Spin.json | 7 + .../data/theme/shape/square/SpinDown.json | 23 + .../data/theme/shape/square/SpinEntry.json | 23 + resources/data/theme/shape/square/SpinUp.json | 23 + .../theme/shape/square/WidgetScrolled.frag | 25 + .../theme/shape/square/WidgetScrolled.json | 23 + .../theme/shape/square/WidgetScrolled.vert | 50 + resources/data/translate/EN.json | 6 + resources/data/translate/FR.json | 6 + src/module-info.java | 3 + src/org/atriasoft/echrono/Clock.java | 4 +- src/org/atriasoft/echrono/Duration.java | 9 + src/org/atriasoft/echrono/Steady.java | 9 + src/org/atriasoft/echrono/Time.java | 4 + src/org/atriasoft/egami/Image.java | 170 + src/org/atriasoft/egami/ImageFloat.java | 159 + src/org/atriasoft/egami/ImageMono.java | 111 + src/org/atriasoft/ewol/DrawProperty.cpp | 24 - src/org/atriasoft/ewol/DrawProperty.java | 98 +- .../atriasoft/ewol/{ewol.java => Ewol.java} | 8 +- src/org/atriasoft/ewol/Gravity.java | 28 +- src/org/atriasoft/ewol/Padding.cpp | 93 - src/org/atriasoft/ewol/Padding.java | 155 +- src/org/atriasoft/ewol/compositing/Area.cpp | 142 - src/org/atriasoft/ewol/compositing/Area.java | 101 - .../ewol/compositing/Compositing.cpp | 47 - .../ewol/compositing/Compositing.java | 113 +- .../ewol/compositing/CompositingImage.java | 498 + .../atriasoft/ewol/compositing/Drawing.cpp | 4 +- .../atriasoft/ewol/compositing/Drawing.java | 436 +- src/org/atriasoft/ewol/compositing/Image.cpp | 364 - src/org/atriasoft/ewol/compositing/Image.java | 193 - src/org/atriasoft/ewol/compositing/Shaper.cpp | 6 +- .../atriasoft/ewol/compositing/Shaper.java | 2 +- src/org/atriasoft/ewol/compositing/Sprite.cpp | 39 - .../atriasoft/ewol/compositing/Sprite.java | 29 - src/org/atriasoft/ewol/compositing/Text.cpp | 10 +- src/org/atriasoft/ewol/compositing/Text.java | 2 +- .../atriasoft/ewol/compositing/TextBase.java | 4 +- src/org/atriasoft/ewol/compositing/TextDF.cpp | 407 - .../atriasoft/ewol/compositing/TextDF.java | 70 - .../atriasoft/ewol/context/Application.cpp | 49 - src/org/atriasoft/ewol/context/ConfigFont.cpp | 43 - .../atriasoft/ewol/context/ConfigFont.java | 175 +- src/org/atriasoft/ewol/context/Context.cpp | 57 - .../atriasoft/ewol/context/EwolContext.java | 154 +- .../atriasoft/ewol/context/InputManager.cpp | 502 - .../atriasoft/ewol/context/InputManager.java | 569 +- src/org/atriasoft/ewol/event/EntrySystem.java | 4 +- .../event/{Entry.java => EventEntry.java} | 33 +- .../{EvantInput.java => EventInput.java} | 0 src/org/atriasoft/ewol/event/EventTime.java | 23 +- src/org/atriasoft/ewol/event/InputSystem.java | 3 +- src/org/atriasoft/ewol/gravity.cpp | 86 - .../ewol/internal/LoadPackageStream.java | 84 + src/org/atriasoft/ewol/internal/Tools.java | 22 + src/org/atriasoft/ewol/object/EwolObject.java | 19 +- src/org/atriasoft/ewol/object/Manager.cpp | 161 - src/org/atriasoft/ewol/object/Object.cpp | 0 .../atriasoft/ewol/object/ObjectManager.java | 176 +- src/org/atriasoft/ewol/object/Worker.cpp | 29 - src/org/atriasoft/ewol/resource/ColorFile.cpp | 86 - .../atriasoft/ewol/resource/ColorFile.java | 73 - .../ewol/resource/Colored3DObject.cpp | 527 - .../ewol/resource/Colored3DObject.java | 89 - .../atriasoft/ewol/resource/ConfigFile.cpp | 92 - .../atriasoft/ewol/resource/ConfigFile.java | 44 - .../ewol/resource/DistanceFieldFont.cpp | 470 - .../ewol/resource/DistanceFieldFont.java | 96 - .../atriasoft/ewol/resource/FontFreeType.cpp | 384 - .../atriasoft/ewol/resource/FontFreeType.java | 61 - src/org/atriasoft/ewol/resource/ImageDF.cpp | 225 - src/org/atriasoft/ewol/resource/ImageDF.java | 47 - .../resource/RefactorColored3DObject.java | 493 + .../ewol/resource/ResourceColorFile.java | 162 + .../ewol/resource/ResourceConfigFile.java | 132 + .../ewol/resource/ResourceFontFreeType.java | 274 + .../ewol/resource/ResourceTexture2.java | 344 + .../ewol/resource/ResourceTextureFile.java | 102 + .../ewol/resource/ResourceTexturedFont.java | 378 + src/org/atriasoft/ewol/resource/Texture.cpp | 319 - src/org/atriasoft/ewol/resource/Texture.java | 91 - .../atriasoft/ewol/resource/TextureFile.cpp | 119 - .../atriasoft/ewol/resource/TextureFile.java | 47 - .../atriasoft/ewol/resource/TexturedFont.cpp | 369 - .../atriasoft/ewol/resource/TexturedFont.java | 98 - .../ewol/resource/font/FontBase.java | 87 +- .../ewol/resource/font/FontMode.java | 30 + .../ewol/resource/font/GlyphProperty.java | 182 +- .../atriasoft/ewol/resource/font/Kerning.java | 111 +- src/org/atriasoft/ewol/widget/Widget.cpp | 1 - src/org/atriasoft/ewol/widget/Widget.java | 382 +- .../atriasoft/ewol/widget/WidgetManager.java | 20 +- .../atriasoft/ewol/widget/WidgetScrolled.cpp | 14 +- src/org/atriasoft/ewol/widget/Windows.cpp | 4 +- src/org/atriasoft/ewol/widget/Windows.java | 158 +- 238 files changed, 109465 insertions(+), 6920 deletions(-) create mode 100644 lib/freetype-jni.jar create mode 100755 lib/libfreetype-jni.so create mode 100644 resources/data/color.frag create mode 100644 resources/data/color.prog create mode 100644 resources/data/color.vert create mode 100644 resources/data/color3.frag create mode 100644 resources/data/color3.prog create mode 100644 resources/data/color3.vert create mode 100644 resources/data/ewol-gui-file-chooser.xml create mode 100644 resources/data/fonts/FreeMono.svg create mode 100644 resources/data/fonts/FreeMonoBold.svg create mode 100644 resources/data/fonts/FreeMonoBoldOblique.svg create mode 100644 resources/data/fonts/FreeMonoOblique.svg create mode 100644 resources/data/fonts/FreeSans.svg create mode 100644 resources/data/fonts/FreeSansBold.svg create mode 100644 resources/data/fonts/FreeSansBoldOblique.svg create mode 100644 resources/data/fonts/FreeSansOblique.svg create mode 100644 resources/data/fonts/FreeSerif.svg create mode 100644 resources/data/icon.svg create mode 100644 resources/data/simple3D.frag create mode 100644 resources/data/simple3D.prog create mode 100644 resources/data/simple3D.vert create mode 100644 resources/data/text.frag create mode 100644 resources/data/text.prog create mode 100644 resources/data/text.vert create mode 100644 resources/data/textured.frag create mode 100644 resources/data/textured.prog create mode 100644 resources/data/textured.vert create mode 100644 resources/data/textured3D.frag create mode 100644 resources/data/textured3D.prog create mode 100644 resources/data/textured3D.vert create mode 100644 resources/data/textured3D2.frag create mode 100644 resources/data/textured3D2.prog create mode 100644 resources/data/textured3D2.vert create mode 100644 resources/data/texturedDF.frag create mode 100644 resources/data/texturedDF.vert create mode 100644 resources/data/texturedNoMaterial.frag create mode 100644 resources/data/texturedNoMaterial.prog create mode 100644 resources/data/texturedNoMaterial.vert create mode 100644 resources/data/theme/color/black/Button.json create mode 100644 resources/data/theme/color/black/CheckBox.json create mode 100644 resources/data/theme/color/black/ContextMenu.json create mode 100644 resources/data/theme/color/black/Entry.json create mode 100644 resources/data/theme/color/black/Image.json create mode 100644 resources/data/theme/color/black/Label.json create mode 100644 resources/data/theme/color/black/ListFileSystem.json create mode 100644 resources/data/theme/color/black/PopUp.json create mode 100644 resources/data/theme/color/black/WidgetScrolled.json create mode 100644 resources/data/theme/color/black/Windows.json create mode 100644 resources/data/theme/color/white/Button.json create mode 100644 resources/data/theme/color/white/CheckBox.json create mode 100644 resources/data/theme/color/white/ContextMenu.json create mode 100644 resources/data/theme/color/white/Entry.json create mode 100644 resources/data/theme/color/white/Image.json create mode 100644 resources/data/theme/color/white/Label.json create mode 100644 resources/data/theme/color/white/ListFileSystem.json create mode 100644 resources/data/theme/color/white/PopUp.json create mode 100644 resources/data/theme/color/white/WidgetScrolled.json create mode 100644 resources/data/theme/color/white/Windows.json create mode 100644 resources/data/theme/default/Add.svg create mode 100644 resources/data/theme/default/AtoZ.svg create mode 100644 resources/data/theme/default/Attache.svg create mode 100644 resources/data/theme/default/CaseSensitive.svg create mode 100644 resources/data/theme/default/ChevronLeft.svg create mode 100644 resources/data/theme/default/ChevronLess.svg create mode 100644 resources/data/theme/default/ChevronMore.svg create mode 100644 resources/data/theme/default/ChevronRight.svg create mode 100644 resources/data/theme/default/Close.svg create mode 100644 resources/data/theme/default/Contact.svg create mode 100644 resources/data/theme/default/Down.svg create mode 100644 resources/data/theme/default/FavoriteDisable.svg create mode 100644 resources/data/theme/default/FavoriteEnable.svg create mode 100644 resources/data/theme/default/FavoriteMiddle.svg create mode 100644 resources/data/theme/default/File.svg create mode 100644 resources/data/theme/default/Folder.svg create mode 100644 resources/data/theme/default/Forbidden.svg create mode 100644 resources/data/theme/default/Help.svg create mode 100644 resources/data/theme/default/Home.svg create mode 100644 resources/data/theme/default/Info.svg create mode 100644 resources/data/theme/default/List.svg create mode 100644 resources/data/theme/default/Load.svg create mode 100644 resources/data/theme/default/Lock.svg create mode 100644 resources/data/theme/default/Next.svg create mode 100644 resources/data/theme/default/OpenMenu.svg create mode 100644 resources/data/theme/default/Parameter.svg create mode 100644 resources/data/theme/default/Previous.svg create mode 100644 resources/data/theme/default/Quit.svg create mode 100644 resources/data/theme/default/Redo.svg create mode 100644 resources/data/theme/default/Remove.svg create mode 100644 resources/data/theme/default/Remove2.svg create mode 100644 resources/data/theme/default/Replace.svg create mode 100644 resources/data/theme/default/SDCard.svg create mode 100644 resources/data/theme/default/Save.svg create mode 100644 resources/data/theme/default/Search.svg create mode 100644 resources/data/theme/default/Trash.svg create mode 100644 resources/data/theme/default/Undo.svg create mode 100644 resources/data/theme/default/Up.svg create mode 100644 resources/data/theme/default/Update.svg create mode 100644 resources/data/theme/default/Validate.svg create mode 100644 resources/data/theme/default/VolumeMax.svg create mode 100644 resources/data/theme/default/VolumeMute.svg create mode 100644 resources/data/theme/default/Warning.svg create mode 100644 resources/data/theme/default/WhereAmI.svg create mode 100644 resources/data/theme/default/WrapAround.svg create mode 100644 resources/data/theme/default/ZoomIn.svg create mode 100644 resources/data/theme/shape/round/Button.frag create mode 100644 resources/data/theme/shape/round/Button.json create mode 100644 resources/data/theme/shape/round/Button.vert create mode 100644 resources/data/theme/shape/round/CheckBox.frag create mode 100644 resources/data/theme/shape/round/CheckBox.json create mode 100644 resources/data/theme/shape/round/CheckBox.vert create mode 100644 resources/data/theme/shape/round/ContextMenu.frag create mode 100644 resources/data/theme/shape/round/ContextMenu.json create mode 100644 resources/data/theme/shape/round/ContextMenu.vert create mode 100644 resources/data/theme/shape/round/Entry.frag create mode 100644 resources/data/theme/shape/round/Entry.json create mode 100644 resources/data/theme/shape/round/Entry.vert create mode 100644 resources/data/theme/shape/round/PopUp.frag create mode 100644 resources/data/theme/shape/round/PopUp.json create mode 100644 resources/data/theme/shape/round/PopUp.vert create mode 100644 resources/data/theme/shape/round/WidgetScrolled.frag create mode 100644 resources/data/theme/shape/round/WidgetScrolled.json create mode 100644 resources/data/theme/shape/round/WidgetScrolled.vert create mode 100644 resources/data/theme/shape/square/Button.frag create mode 100644 resources/data/theme/shape/square/Button.json create mode 100644 resources/data/theme/shape/square/Button.vert create mode 100644 resources/data/theme/shape/square/CheckBox.frag create mode 100644 resources/data/theme/shape/square/CheckBox.json create mode 100644 resources/data/theme/shape/square/CheckBox.vert create mode 100644 resources/data/theme/shape/square/ContextMenu.frag create mode 100644 resources/data/theme/shape/square/ContextMenu.json create mode 100644 resources/data/theme/shape/square/ContextMenu.vert create mode 100644 resources/data/theme/shape/square/Entry.frag create mode 100644 resources/data/theme/shape/square/Entry.json create mode 100644 resources/data/theme/shape/square/Entry.vert create mode 100644 resources/data/theme/shape/square/PopUp.frag create mode 100644 resources/data/theme/shape/square/PopUp.json create mode 100644 resources/data/theme/shape/square/PopUp.vert create mode 100644 resources/data/theme/shape/square/Select.json create mode 100644 resources/data/theme/shape/square/SelectBt.json create mode 100644 resources/data/theme/shape/square/SelectEntry.json create mode 100644 resources/data/theme/shape/square/Spin.json create mode 100644 resources/data/theme/shape/square/SpinDown.json create mode 100644 resources/data/theme/shape/square/SpinEntry.json create mode 100644 resources/data/theme/shape/square/SpinUp.json create mode 100644 resources/data/theme/shape/square/WidgetScrolled.frag create mode 100644 resources/data/theme/shape/square/WidgetScrolled.json create mode 100644 resources/data/theme/shape/square/WidgetScrolled.vert create mode 100644 resources/data/translate/EN.json create mode 100644 resources/data/translate/FR.json create mode 100644 src/org/atriasoft/egami/Image.java create mode 100644 src/org/atriasoft/egami/ImageFloat.java create mode 100644 src/org/atriasoft/egami/ImageMono.java delete mode 100644 src/org/atriasoft/ewol/DrawProperty.cpp rename src/org/atriasoft/ewol/{ewol.java => Ewol.java} (89%) delete mode 100644 src/org/atriasoft/ewol/Padding.cpp delete mode 100644 src/org/atriasoft/ewol/compositing/Area.cpp delete mode 100644 src/org/atriasoft/ewol/compositing/Area.java delete mode 100644 src/org/atriasoft/ewol/compositing/Compositing.cpp create mode 100644 src/org/atriasoft/ewol/compositing/CompositingImage.java delete mode 100644 src/org/atriasoft/ewol/compositing/Image.cpp delete mode 100644 src/org/atriasoft/ewol/compositing/Image.java delete mode 100644 src/org/atriasoft/ewol/compositing/Sprite.cpp delete mode 100644 src/org/atriasoft/ewol/compositing/Sprite.java delete mode 100644 src/org/atriasoft/ewol/compositing/TextDF.cpp delete mode 100644 src/org/atriasoft/ewol/compositing/TextDF.java delete mode 100644 src/org/atriasoft/ewol/context/Application.cpp delete mode 100644 src/org/atriasoft/ewol/context/ConfigFont.cpp delete mode 100644 src/org/atriasoft/ewol/context/Context.cpp delete mode 100644 src/org/atriasoft/ewol/context/InputManager.cpp rename src/org/atriasoft/ewol/event/{Entry.java => EventEntry.java} (59%) rename src/org/atriasoft/ewol/event/{EvantInput.java => EventInput.java} (100%) delete mode 100644 src/org/atriasoft/ewol/gravity.cpp create mode 100644 src/org/atriasoft/ewol/internal/LoadPackageStream.java create mode 100644 src/org/atriasoft/ewol/internal/Tools.java delete mode 100644 src/org/atriasoft/ewol/object/Manager.cpp delete mode 100644 src/org/atriasoft/ewol/object/Object.cpp delete mode 100644 src/org/atriasoft/ewol/object/Worker.cpp delete mode 100644 src/org/atriasoft/ewol/resource/ColorFile.cpp delete mode 100644 src/org/atriasoft/ewol/resource/ColorFile.java delete mode 100644 src/org/atriasoft/ewol/resource/Colored3DObject.cpp delete mode 100644 src/org/atriasoft/ewol/resource/Colored3DObject.java delete mode 100644 src/org/atriasoft/ewol/resource/ConfigFile.cpp delete mode 100644 src/org/atriasoft/ewol/resource/ConfigFile.java delete mode 100644 src/org/atriasoft/ewol/resource/DistanceFieldFont.cpp delete mode 100644 src/org/atriasoft/ewol/resource/DistanceFieldFont.java delete mode 100644 src/org/atriasoft/ewol/resource/FontFreeType.cpp delete mode 100644 src/org/atriasoft/ewol/resource/FontFreeType.java delete mode 100644 src/org/atriasoft/ewol/resource/ImageDF.cpp delete mode 100644 src/org/atriasoft/ewol/resource/ImageDF.java create mode 100644 src/org/atriasoft/ewol/resource/RefactorColored3DObject.java create mode 100644 src/org/atriasoft/ewol/resource/ResourceColorFile.java create mode 100644 src/org/atriasoft/ewol/resource/ResourceConfigFile.java create mode 100644 src/org/atriasoft/ewol/resource/ResourceFontFreeType.java create mode 100644 src/org/atriasoft/ewol/resource/ResourceTexture2.java create mode 100644 src/org/atriasoft/ewol/resource/ResourceTextureFile.java create mode 100644 src/org/atriasoft/ewol/resource/ResourceTexturedFont.java delete mode 100644 src/org/atriasoft/ewol/resource/Texture.cpp delete mode 100644 src/org/atriasoft/ewol/resource/Texture.java delete mode 100644 src/org/atriasoft/ewol/resource/TextureFile.cpp delete mode 100644 src/org/atriasoft/ewol/resource/TextureFile.java delete mode 100644 src/org/atriasoft/ewol/resource/TexturedFont.cpp delete mode 100644 src/org/atriasoft/ewol/resource/TexturedFont.java create mode 100644 src/org/atriasoft/ewol/resource/font/FontMode.java delete mode 100644 src/org/atriasoft/ewol/widget/Widget.cpp diff --git a/.classpath b/.classpath index bd70087..3de4651 100644 --- a/.classpath +++ b/.classpath @@ -5,28 +5,15 @@ + + - - - - - - - - - - - - - - - - + @@ -36,10 +23,40 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/freetype-jni.jar b/lib/freetype-jni.jar new file mode 100644 index 0000000000000000000000000000000000000000..1156985d1273a47ef00e67712cdcf2ca28eb3a0c GIT binary patch literal 18392 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 literal 0 HcmV?d00001 diff --git a/lib/libfreetype-jni.so b/lib/libfreetype-jni.so new file mode 100755 index 0000000000000000000000000000000000000000..e0db50b686c4df40704bff9c034a554d11584940 GIT binary patch literal 1030728 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

EAHh5*cqa3x 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�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

7Zd|n% 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

k*I7 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

oQ>fQ{KWpMB`VJ?rq3=-2Vw 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/data/fonts/FreeMono.svg b/resources/data/fonts/FreeMono.svg new file mode 100644 index 0000000..88c79e9 --- /dev/null +++ b/resources/data/fonts/FreeMono.svg @@ -0,0 +1,9874 @@ + + + + +Created by FontForge 20191125 at Wed Sep 15 23:00:57 2010 + By convertio +Copyleft 2002, 2003, 2005, 2008, 2009, 2010 Free Software Foundation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/data/fonts/FreeMonoBold.svg b/resources/data/fonts/FreeMonoBold.svg new file mode 100644 index 0000000..e8009c3 --- /dev/null +++ b/resources/data/fonts/FreeMonoBold.svg @@ -0,0 +1,5443 @@ + + + + +Created by FontForge 20191125 at Wed Sep 15 22:59:39 2010 + By convertio +Copyleft 2002, 2003, 2005, 2008, 2009, 2010 Free Software Foundation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/data/fonts/FreeMonoBoldOblique.svg b/resources/data/fonts/FreeMonoBoldOblique.svg new file mode 100644 index 0000000..e1dd340 --- /dev/null +++ b/resources/data/fonts/FreeMonoBoldOblique.svg @@ -0,0 +1,5198 @@ + + + + +Created by FontForge 20200511 at Wed Sep 15 23:00:06 2010 + By convertio +Copyleft 2002, 2003, 2005, 2008, 2009, 2010 Free Software Foundation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/data/fonts/FreeMonoOblique.svg b/resources/data/fonts/FreeMonoOblique.svg new file mode 100644 index 0000000..ba8f4bc --- /dev/null +++ b/resources/data/fonts/FreeMonoOblique.svg @@ -0,0 +1,6389 @@ + + + + +Created by FontForge 20191125 at Wed Sep 15 23:00:34 2010 + By convertio +Copyleft 2002, 2003, 2005, 2008, 2009, 2010 Free Software Foundation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/data/fonts/FreeSans.svg b/resources/data/fonts/FreeSans.svg new file mode 100644 index 0000000..efdc01e --- /dev/null +++ b/resources/data/fonts/FreeSans.svg @@ -0,0 +1,15542 @@ + + + + +Created by FontForge 20200511 at Sun Sep 19 11:36:01 2010 + By convertio +Copyleft 2002, 2003, 2005, 2008, 2009, 2010 Free Software Foundation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/data/fonts/FreeSansBold.svg b/resources/data/fonts/FreeSansBold.svg new file mode 100644 index 0000000..d16c8bd --- /dev/null +++ b/resources/data/fonts/FreeSansBold.svg @@ -0,0 +1,8052 @@ + + + + +Created by FontForge 20191125 at Sun Sep 19 11:41:50 2010 + By convertio +Copyleft 2002, 2003, 2005, 2008, 2009, 2010 Free Software Foundation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/data/fonts/FreeSansBoldOblique.svg b/resources/data/fonts/FreeSansBoldOblique.svg new file mode 100644 index 0000000..842491c --- /dev/null +++ b/resources/data/fonts/FreeSansBoldOblique.svg @@ -0,0 +1,7236 @@ + + + + +Created by FontForge 20191125 at Sun Sep 19 11:42:50 2010 + By convertio +Copyleft 2002, 2003, 2005, 2008, 2009, 2010 Free Software Foundation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/data/fonts/FreeSansOblique.svg b/resources/data/fonts/FreeSansOblique.svg new file mode 100644 index 0000000..8b8c84d --- /dev/null +++ b/resources/data/fonts/FreeSansOblique.svg @@ -0,0 +1,9376 @@ + + + + +Created by FontForge 20200511 at Sun Sep 19 11:41:10 2010 + By convertio +Copyleft 2002, 2003, 2005, 2008, 2009, 2010 Free Software Foundation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/data/fonts/FreeSerif.svg b/resources/data/fonts/FreeSerif.svg new file mode 100644 index 0000000..9f717de --- /dev/null +++ b/resources/data/fonts/FreeSerif.svg @@ -0,0 +1,34749 @@ + + + + +Created by FontForge 20200511 at Sun Sep 19 12:35:57 2010 + By convertio +Copyleft 2002, 2003, 2005, 2008, 2009, 2010 Free Software Foundation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/data/icon.svg b/resources/data/icon.svg new file mode 100644 index 0000000..5553afd --- /dev/null +++ b/resources/data/icon.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/data/simple3D.frag b/resources/data/simple3D.frag new file mode 100644 index 0000000..cb8e54c --- /dev/null +++ b/resources/data/simple3D.frag @@ -0,0 +1,10 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +varying vec4 f_color; + +void main(void) { + gl_FragColor = f_color; +} diff --git a/resources/data/simple3D.prog b/resources/data/simple3D.prog new file mode 100644 index 0000000..9106c32 --- /dev/null +++ b/resources/data/simple3D.prog @@ -0,0 +1,2 @@ +simple3D.vert +simple3D.frag \ No newline at end of file diff --git a/resources/data/simple3D.vert b/resources/data/simple3D.vert new file mode 100644 index 0000000..cdc691a --- /dev/null +++ b/resources/data/simple3D.vert @@ -0,0 +1,18 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input : +attribute vec3 EW_coord3d; +uniform vec4 EW_color; +uniform mat4 EW_MatrixTransformation; + +// output : +varying vec4 f_color; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord3d, 1.0); + //gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(EW_coord2d, 0.0, 1.0); + f_color = EW_color; +} diff --git a/resources/data/text.frag b/resources/data/text.frag new file mode 100644 index 0000000..32a55e5 --- /dev/null +++ b/resources/data/text.frag @@ -0,0 +1,41 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input : +uniform sampler2D EW_texID; + +varying vec2 f_texcoord; +varying vec4 f_color; +/* +void main(void) { + gl_FragColor = f_color; + vec2 tmpCoord = f_texcoord; + tmpCoord = mod(tmpCoord, 1.0); + vec4 map = texture2D(EW_texID, tmpCoord); + if (f_texcoord.x<1.0) { + // normal font : + gl_FragColor.a = gl_FragColor.a*map.a; + } else if (f_texcoord.x<2.0) { + // Italic font : + gl_FragColor.a = gl_FragColor.a*map.r; + } else if (f_texcoord.x<3.0) { + // Bold font : + gl_FragColor.a = gl_FragColor.a*map.g; + } else { + // bold italic font : + gl_FragColor.a = gl_FragColor.a*map.b; + } +} +*/ + +varying vec4 f_patern; + +void main(void) { + gl_FragColor = f_color; + vec4 map = texture2D(EW_texID, f_texcoord); + float alphaCoef = dot(map, f_patern); + gl_FragColor.a = gl_FragColor.a*alphaCoef; +} + diff --git a/resources/data/text.prog b/resources/data/text.prog new file mode 100644 index 0000000..6b0ff18 --- /dev/null +++ b/resources/data/text.prog @@ -0,0 +1,2 @@ +text.vert +text.frag \ No newline at end of file diff --git a/resources/data/text.vert b/resources/data/text.vert new file mode 100644 index 0000000..c06eb71 --- /dev/null +++ b/resources/data/text.vert @@ -0,0 +1,47 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input : +attribute vec3 EW_coord3d; +attribute vec2 EW_texture2d; +attribute vec4 EW_color; +uniform mat4 EW_MatrixTransformation; + +// output : +varying vec4 f_color; +varying vec2 f_texcoord; +/* +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + //gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(EW_coord2d, 0.0, 1.0); + // set texture output coord + f_texcoord = EW_texture2d; + // set output color : + f_color = EW_color; +} +*/ +varying vec4 f_patern; +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord3d, 1.0); + //gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(EW_coord2d, 0.0, 1.0); + // set output color : + f_color = EW_color; + if (EW_texture2d.x<1.0) { + // normal font : + f_patern = vec4 (0.0, 0.0, 0.0, 1.0); + } else if (EW_texture2d.x<2.0) { + // Italic font : + f_patern = vec4 (1.0, 0.0, 0.0, 0.0); + } else if (EW_texture2d.x<3.0) { + // Bold font : + f_patern = vec4 (0.0, 1.0, 0.0, 0.0); + } else { + // bold italic font : + f_patern = vec4 (0.0, 0.0, 1.0, 0.0); + } + // set texture output coord + f_texcoord = mod(EW_texture2d, 1.0); +} + diff --git a/resources/data/textured.frag b/resources/data/textured.frag new file mode 100644 index 0000000..50eea1c --- /dev/null +++ b/resources/data/textured.frag @@ -0,0 +1,14 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input : +uniform sampler2D EW_texID; + +varying vec2 f_texcoord; +varying vec4 f_color; + +void main(void) { + gl_FragColor = texture2D(EW_texID, f_texcoord) * f_color; +} diff --git a/resources/data/textured.prog b/resources/data/textured.prog new file mode 100644 index 0000000..eb053e2 --- /dev/null +++ b/resources/data/textured.prog @@ -0,0 +1,2 @@ +textured.vert +textured.frag \ No newline at end of file diff --git a/resources/data/textured.vert b/resources/data/textured.vert new file mode 100644 index 0000000..d5ec23e --- /dev/null +++ b/resources/data/textured.vert @@ -0,0 +1,22 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input : +attribute vec2 EW_coord2d; +attribute vec2 EW_texture2d; +attribute vec4 EW_color; +uniform mat4 EW_MatrixTransformation; + +// output : +varying vec4 f_color; +varying vec2 f_texcoord; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + // set texture output coord + f_texcoord = EW_texture2d; + // set output color : + f_color = EW_color; +} diff --git a/resources/data/textured3D.frag b/resources/data/textured3D.frag new file mode 100644 index 0000000..ce2a070 --- /dev/null +++ b/resources/data/textured3D.frag @@ -0,0 +1,15 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input : +uniform sampler2D EW_texID; + +varying vec2 f_texcoord; +varying vec4 f_color; + +void main(void) { + gl_FragColor = texture2D(EW_texID, f_texcoord) * f_color; + //gl_FragColor = vec4(1.0,1.0,0.2,0.6); +} diff --git a/resources/data/textured3D.prog b/resources/data/textured3D.prog new file mode 100644 index 0000000..35578b6 --- /dev/null +++ b/resources/data/textured3D.prog @@ -0,0 +1,2 @@ +textured3D.vert +textured3D.frag \ No newline at end of file diff --git a/resources/data/textured3D.vert b/resources/data/textured3D.vert new file mode 100644 index 0000000..65973c9 --- /dev/null +++ b/resources/data/textured3D.vert @@ -0,0 +1,21 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif +// Input : +attribute vec3 EW_coord3d; +attribute vec2 EW_texture2d; +attribute vec4 EW_color; +uniform mat4 EW_MatrixTransformation; + +// output : +varying vec4 f_color; +varying vec2 f_texcoord; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord3d, 1.0); + // set texture output coord + f_texcoord = EW_texture2d; + // set output color : + f_color = EW_color; +} diff --git a/resources/data/textured3D2.frag b/resources/data/textured3D2.frag new file mode 100644 index 0000000..f37bf8e --- /dev/null +++ b/resources/data/textured3D2.frag @@ -0,0 +1,55 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif +struct DirectionalLight { + vec3 direction; + vec3 halfplane; + vec4 ambientColor; + vec4 diffuseColor; + vec4 specularColor; +}; + +struct Material { + vec4 ambientFactor; + vec4 diffuseFactor; + vec4 specularFactor; + float shininess; +}; + +// Light +uniform DirectionalLight EW_directionalLight; +// Material +uniform Material EW_material; + +// Input : +uniform sampler2D EW_texID; + +varying vec2 f_texcoord; +varying vec3 v_ecNormal; + +void main(void) { + vec4 tmpElementColor = texture2D(EW_texID, f_texcoord); + + // Normalize v_ecNormal + vec3 ecNormal = v_ecNormal / length(v_ecNormal); + + float ecNormalDotLightDirection = max(0.0, dot(ecNormal, EW_directionalLight.direction)); + float ecNormalDotLightHalfplane = max(0.0, dot(ecNormal, EW_directionalLight.halfplane)); + + // Calculate ambient light + vec4 ambientLight = EW_directionalLight.ambientColor * EW_material.ambientFactor; + + // Calculate diffuse light + vec4 diffuseLight = ecNormalDotLightDirection * EW_directionalLight.diffuseColor * EW_material.diffuseFactor; + + // Calculate specular light + vec4 specularLight = vec4(0.0); + + if (ecNormalDotLightHalfplane > 0.0) { + specularLight = pow(ecNormalDotLightHalfplane, EW_material.shininess) * EW_directionalLight.specularColor * EW_material.specularFactor; + specularLight = EW_directionalLight.specularColor * EW_material.specularFactor; + } + vec4 light = ambientLight + diffuseLight + specularLight; + gl_FragColor = tmpElementColor;// * light; +} diff --git a/resources/data/textured3D2.prog b/resources/data/textured3D2.prog new file mode 100644 index 0000000..e7330f0 --- /dev/null +++ b/resources/data/textured3D2.prog @@ -0,0 +1,2 @@ +textured3D2.vert +textured3D2.frag \ No newline at end of file diff --git a/resources/data/textured3D2.vert b/resources/data/textured3D2.vert new file mode 100644 index 0000000..69ddada --- /dev/null +++ b/resources/data/textured3D2.vert @@ -0,0 +1,25 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif +// Input : +attribute vec3 EW_coord3d; +attribute vec2 EW_texture2d; +attribute vec3 EW_normal; +uniform mat4 EW_MatrixTransformation; +uniform mat4 EW_MatrixPosition; + +// output : +varying vec2 f_texcoord; +varying vec3 v_ecNormal; + +void main(void) { + gl_Position = EW_MatrixTransformation * EW_MatrixPosition * vec4(EW_coord3d, 1.0); + // set texture output coord + f_texcoord = EW_texture2d; + mat4 MatrixPosition = EW_MatrixPosition; + MatrixPosition[3][0] = 0.0; + MatrixPosition[3][1] = 0.0; + MatrixPosition[3][2] = 0.0; + v_ecNormal = vec3(MatrixPosition * vec4(EW_normal, 1.0) ); +} diff --git a/resources/data/texturedDF.frag b/resources/data/texturedDF.frag new file mode 100644 index 0000000..8a76bc7 --- /dev/null +++ b/resources/data/texturedDF.frag @@ -0,0 +1,25 @@ +#ifdef GL_ES +#extension GL_OES_standard_derivatives : enable +precision mediump float; +precision mediump int; +#endif + +// Input : +uniform sampler2D EW_texID; +uniform float EW_SoftEdgeMin; +uniform float EW_SoftEdgeMax; +uniform int EW_SoftEdge; + +varying vec2 f_texcoord; +varying vec4 f_color; + + +void main(void) { + vec4 color = texture2D(EW_texID, f_texcoord ); + float dist = color.r; + float width = fwidth(dist); + float alpha = smoothstep(0.5-width, 0.5+width, dist); + + // Smooth + gl_FragColor = vec4(f_color[0], f_color[1], f_color[2], f_color[3]*alpha); +} diff --git a/resources/data/texturedDF.vert b/resources/data/texturedDF.vert new file mode 100644 index 0000000..1e8591b --- /dev/null +++ b/resources/data/texturedDF.vert @@ -0,0 +1,22 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input : +attribute vec3 EW_coord3d; +attribute vec2 EW_texture2d; +attribute vec4 EW_color; +uniform mat4 EW_MatrixTransformation; + +// output : +varying vec4 f_color; +varying vec2 f_texcoord; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord3d, 1.0); + // set texture output coord + f_texcoord = EW_texture2d; + // set output color : + f_color = EW_color; +} \ No newline at end of file diff --git a/resources/data/texturedNoMaterial.frag b/resources/data/texturedNoMaterial.frag new file mode 100644 index 0000000..b6c6e2a --- /dev/null +++ b/resources/data/texturedNoMaterial.frag @@ -0,0 +1,13 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input: +uniform sampler2D EW_texID; + +varying vec2 f_texcoord; + +void main(void) { + gl_FragColor = texture2D(EW_texID, f_texcoord); +} diff --git a/resources/data/texturedNoMaterial.prog b/resources/data/texturedNoMaterial.prog new file mode 100644 index 0000000..b9a1a8f --- /dev/null +++ b/resources/data/texturedNoMaterial.prog @@ -0,0 +1,2 @@ +texturedNoMaterial.vert +texturedNoMaterial.frag \ No newline at end of file diff --git a/resources/data/texturedNoMaterial.vert b/resources/data/texturedNoMaterial.vert new file mode 100644 index 0000000..6ce4ff3 --- /dev/null +++ b/resources/data/texturedNoMaterial.vert @@ -0,0 +1,18 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif +// Input: +attribute vec3 EW_coord3d; +attribute vec2 EW_texture2d; +uniform mat4 EW_MatrixTransformation; +uniform mat4 EW_MatrixPosition; + +// output: +varying vec2 f_texcoord; + +void main(void) { + // set texture output coord + f_texcoord = EW_texture2d; + gl_Position = EW_MatrixTransformation * EW_MatrixPosition * vec4(EW_coord3d, 1.0); +} diff --git a/resources/data/theme/color/black/Button.json b/resources/data/theme/color/black/Button.json new file mode 100644 index 0000000..337ef3d --- /dev/null +++ b/resources/data/theme/color/black/Button.json @@ -0,0 +1,10 @@ +{ + "color": [ + { name:"EW_background", color:"#0000" }, + { name:"EW_border", color:"#FFF" }, + { name:"EW_foreground", color:"#000A" }, + { name:"EW_foregroundHover", color:"#0066" }, + { name:"EW_foregroundSelected", color:"#060A" }, + { name:"EW_foregroundPressed", color:"#6006" }, + ] +} diff --git a/resources/data/theme/color/black/CheckBox.json b/resources/data/theme/color/black/CheckBox.json new file mode 100644 index 0000000..095a42a --- /dev/null +++ b/resources/data/theme/color/black/CheckBox.json @@ -0,0 +1,10 @@ +{ + "color": [ + { name:"EW_background", color:"#0000" }, + { name:"EW_border", color:"#FFF" }, + { name:"EW_foreground", color:"#000A" }, + { name:"EW_foregroundHover", color:"#0066" }, + { name:"EW_foregroundSelected", color:"#FFFA" }, + { name:"EW_foregroundPressed", color:"#6006" }, + ] +} diff --git a/resources/data/theme/color/black/ContextMenu.json b/resources/data/theme/color/black/ContextMenu.json new file mode 100644 index 0000000..81ee65a --- /dev/null +++ b/resources/data/theme/color/black/ContextMenu.json @@ -0,0 +1,7 @@ +{ + "color": [ + { name:"EW_background", color:"#0000" }, + { name:"EW_border", color:"#FFFF" }, + { name:"EW_foreground", color:"#000A" }, + ] +} diff --git a/resources/data/theme/color/black/Entry.json b/resources/data/theme/color/black/Entry.json new file mode 100644 index 0000000..0c7a498 --- /dev/null +++ b/resources/data/theme/color/black/Entry.json @@ -0,0 +1,13 @@ +{ + "color": [ + { name:"EW_background", color:"#0000" }, + { name:"EW_foreground", color:"#000A" }, + { name:"EW_foregroundSelected", color:"#FFF3" }, + { name:"EW_foregroundHover", color:"#0082" }, + { name:"EW_border", color:"#FFFF" }, + { name:"text-foreground", color:"#CCCF" }, + { name:"text-background", color:"#0000" }, + { name:"text-cursor", color:"#00AF" }, + { name:"text-selection", color:"#0A0F" }, + ] +} diff --git a/resources/data/theme/color/black/Image.json b/resources/data/theme/color/black/Image.json new file mode 100644 index 0000000..566f0e1 --- /dev/null +++ b/resources/data/theme/color/black/Image.json @@ -0,0 +1,5 @@ +{ + "color": [ + { name:"foreground", color:"#FFFF" }, + ] +} diff --git a/resources/data/theme/color/black/Label.json b/resources/data/theme/color/black/Label.json new file mode 100644 index 0000000..14d16d3 --- /dev/null +++ b/resources/data/theme/color/black/Label.json @@ -0,0 +1,6 @@ +{ + "color": [ + { name:"background", color:"#0000" }, + { name:"foreground", color:"#FFFF" } + ] +} diff --git a/resources/data/theme/color/black/ListFileSystem.json b/resources/data/theme/color/black/ListFileSystem.json new file mode 100644 index 0000000..31c1587 --- /dev/null +++ b/resources/data/theme/color/black/ListFileSystem.json @@ -0,0 +1,8 @@ +{ + "color": [ + { name:"text", color:"#EEEF" }, + { name:"background1", color:"#111F" }, + { name:"background2", color:"#333F" }, + { name:"selected", color:"#338F" }, + ] +} \ No newline at end of file diff --git a/resources/data/theme/color/black/PopUp.json b/resources/data/theme/color/black/PopUp.json new file mode 100644 index 0000000..8071f8e --- /dev/null +++ b/resources/data/theme/color/black/PopUp.json @@ -0,0 +1,7 @@ +{ + "color": [ + { name:"EW_background", color:"#000A" }, + { name:"EW_foreground", color:"#000000F8" }, + { name:"EW_border", color:"#FFFF" }, + ] +} diff --git a/resources/data/theme/color/black/WidgetScrolled.json b/resources/data/theme/color/black/WidgetScrolled.json new file mode 100644 index 0000000..a9b0de5 --- /dev/null +++ b/resources/data/theme/color/black/WidgetScrolled.json @@ -0,0 +1,8 @@ +{ + "color": [ + { name:"EW_background", color:"#0004" }, + { name:"EW_border", color:"#FFF" }, + { name:"EW_foreground", color:"#FFF9" }, + { name:"EW_foregroundPressed", color:"#6006" }, + ] +} diff --git a/resources/data/theme/color/black/Windows.json b/resources/data/theme/color/black/Windows.json new file mode 100644 index 0000000..5d5d5bf --- /dev/null +++ b/resources/data/theme/color/black/Windows.json @@ -0,0 +1,5 @@ +{ + "color": [ + { name:"background", color:"#222F" }, + ] +} diff --git a/resources/data/theme/color/white/Button.json b/resources/data/theme/color/white/Button.json new file mode 100644 index 0000000..a15c714 --- /dev/null +++ b/resources/data/theme/color/white/Button.json @@ -0,0 +1,10 @@ +{ + "color": [ + { name:"EW_background", color:"#0000" }, + { name:"EW_border", color:"#000" }, + { name:"EW_foreground", color:"#8884" }, + { name:"EW_foregroundHover", color:"#00A6" }, + { name:"EW_foregroundSelected", color:"#0A0A" }, + { name:"EW_foregroundPressed", color:"#A006" }, + ] +} diff --git a/resources/data/theme/color/white/CheckBox.json b/resources/data/theme/color/white/CheckBox.json new file mode 100644 index 0000000..016f8d1 --- /dev/null +++ b/resources/data/theme/color/white/CheckBox.json @@ -0,0 +1,10 @@ +{ + "color": [ + { name:"EW_background", color:"#0000" }, + { name:"EW_border", color:"#000" }, + { name:"EW_foreground", color:"#8884" }, + { name:"EW_foregroundHover", color:"#00A6" }, + { name:"EW_foregroundSelected", color:"#000A" }, + { name:"EW_foregroundPressed", color:"#000A" }, + ] +} diff --git a/resources/data/theme/color/white/ContextMenu.json b/resources/data/theme/color/white/ContextMenu.json new file mode 100644 index 0000000..c708fd3 --- /dev/null +++ b/resources/data/theme/color/white/ContextMenu.json @@ -0,0 +1,7 @@ +{ + "color": [ + { name:"EW_background", color:"#0000" }, + { name:"EW_border", color:"#000F" }, + { name:"EW_foreground", color:"#FFFA" }, + ] +} diff --git a/resources/data/theme/color/white/Entry.json b/resources/data/theme/color/white/Entry.json new file mode 100644 index 0000000..4619621 --- /dev/null +++ b/resources/data/theme/color/white/Entry.json @@ -0,0 +1,13 @@ +{ + "color": [ + { name:"EW_background", color:"#0000" }, + { name:"EW_foreground", color:"#FFFA" }, + { name:"EW_foregroundSelected", color:"#0005" }, + { name:"EW_foregroundHover", color:"#55F5" }, + { name:"EW_border", color:"#000F" }, + { name:"text-foreground", color:"#222F" }, + { name:"text-background", color:"#0000" }, + { name:"text-cursor", color:"#00FF" }, + { name:"text-selection", color:"#0A0F" }, + ] +} diff --git a/resources/data/theme/color/white/Image.json b/resources/data/theme/color/white/Image.json new file mode 100644 index 0000000..54f759b --- /dev/null +++ b/resources/data/theme/color/white/Image.json @@ -0,0 +1,5 @@ +{ + "color": [ + { name:"foreground", color:"#000F" }, + ] +} diff --git a/resources/data/theme/color/white/Label.json b/resources/data/theme/color/white/Label.json new file mode 100644 index 0000000..fa813f0 --- /dev/null +++ b/resources/data/theme/color/white/Label.json @@ -0,0 +1,6 @@ +{ + "color": [ + { name:"background", color:"#0000" }, + { name:"foreground", color:"#000F" } + ] +} diff --git a/resources/data/theme/color/white/ListFileSystem.json b/resources/data/theme/color/white/ListFileSystem.json new file mode 100644 index 0000000..c9d7dc1 --- /dev/null +++ b/resources/data/theme/color/white/ListFileSystem.json @@ -0,0 +1,8 @@ +{ + "color": [ + { name:"text", color:"#111F" }, + { name:"background1", color:"#EEEF" }, + { name:"background2", color:"#BBBF" }, + { name:"selected", color:"#88FF" }, + ] +} \ No newline at end of file diff --git a/resources/data/theme/color/white/PopUp.json b/resources/data/theme/color/white/PopUp.json new file mode 100644 index 0000000..00cc22e --- /dev/null +++ b/resources/data/theme/color/white/PopUp.json @@ -0,0 +1,7 @@ +{ + "color": [ + { name:"EW_background", color:"#888A" }, + { name:"EW_foreground", color:"#FFFFFFF0" }, + { name:"EW_border", color:"#000F" }, + ] +} \ No newline at end of file diff --git a/resources/data/theme/color/white/WidgetScrolled.json b/resources/data/theme/color/white/WidgetScrolled.json new file mode 100644 index 0000000..01b6465 --- /dev/null +++ b/resources/data/theme/color/white/WidgetScrolled.json @@ -0,0 +1,8 @@ +{ + "color": [ + { name:"EW_background", color:"#FFF4" }, + { name:"EW_border", color:"#000" }, + { name:"EW_foreground", color:"#4449" }, + { name:"EW_foregroundPressed", color:"#B006" }, + ] +} diff --git a/resources/data/theme/color/white/Windows.json b/resources/data/theme/color/white/Windows.json new file mode 100644 index 0000000..d645bb7 --- /dev/null +++ b/resources/data/theme/color/white/Windows.json @@ -0,0 +1,5 @@ +{ + "color": [ + { name:"background", color:"#888F" }, + ] +} \ No newline at end of file diff --git a/resources/data/theme/default/Add.svg b/resources/data/theme/default/Add.svg new file mode 100644 index 0000000..562f893 --- /dev/null +++ b/resources/data/theme/default/Add.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/AtoZ.svg b/resources/data/theme/default/AtoZ.svg new file mode 100644 index 0000000..781cd3c --- /dev/null +++ b/resources/data/theme/default/AtoZ.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/resources/data/theme/default/Attache.svg b/resources/data/theme/default/Attache.svg new file mode 100644 index 0000000..84be150 --- /dev/null +++ b/resources/data/theme/default/Attache.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/CaseSensitive.svg b/resources/data/theme/default/CaseSensitive.svg new file mode 100644 index 0000000..5ef3f6c --- /dev/null +++ b/resources/data/theme/default/CaseSensitive.svg @@ -0,0 +1,13 @@ + + + + + image/svg+xml + + + + + + + + diff --git a/resources/data/theme/default/ChevronLeft.svg b/resources/data/theme/default/ChevronLeft.svg new file mode 100644 index 0000000..c9c0f37 --- /dev/null +++ b/resources/data/theme/default/ChevronLeft.svg @@ -0,0 +1,66 @@ + + + +image/svg+xml + + + + + + + \ No newline at end of file diff --git a/resources/data/theme/default/ChevronLess.svg b/resources/data/theme/default/ChevronLess.svg new file mode 100644 index 0000000..8546660 --- /dev/null +++ b/resources/data/theme/default/ChevronLess.svg @@ -0,0 +1,66 @@ + + + +image/svg+xml + + + + + + + \ No newline at end of file diff --git a/resources/data/theme/default/ChevronMore.svg b/resources/data/theme/default/ChevronMore.svg new file mode 100644 index 0000000..da17476 --- /dev/null +++ b/resources/data/theme/default/ChevronMore.svg @@ -0,0 +1,66 @@ + + + +image/svg+xml + + + + + + + \ No newline at end of file diff --git a/resources/data/theme/default/ChevronRight.svg b/resources/data/theme/default/ChevronRight.svg new file mode 100644 index 0000000..62d1acc --- /dev/null +++ b/resources/data/theme/default/ChevronRight.svg @@ -0,0 +1,66 @@ + + + +image/svg+xml + + + + + + + \ No newline at end of file diff --git a/resources/data/theme/default/Close.svg b/resources/data/theme/default/Close.svg new file mode 100644 index 0000000..ef041c8 --- /dev/null +++ b/resources/data/theme/default/Close.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/resources/data/theme/default/Contact.svg b/resources/data/theme/default/Contact.svg new file mode 100644 index 0000000..61e6b2d --- /dev/null +++ b/resources/data/theme/default/Contact.svg @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/resources/data/theme/default/Down.svg b/resources/data/theme/default/Down.svg new file mode 100644 index 0000000..1e34f0d --- /dev/null +++ b/resources/data/theme/default/Down.svg @@ -0,0 +1,14 @@ + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/data/theme/default/FavoriteDisable.svg b/resources/data/theme/default/FavoriteDisable.svg new file mode 100644 index 0000000..5d9e376 --- /dev/null +++ b/resources/data/theme/default/FavoriteDisable.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/FavoriteEnable.svg b/resources/data/theme/default/FavoriteEnable.svg new file mode 100644 index 0000000..804bb84 --- /dev/null +++ b/resources/data/theme/default/FavoriteEnable.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/resources/data/theme/default/FavoriteMiddle.svg b/resources/data/theme/default/FavoriteMiddle.svg new file mode 100644 index 0000000..4a3a616 --- /dev/null +++ b/resources/data/theme/default/FavoriteMiddle.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/resources/data/theme/default/File.svg b/resources/data/theme/default/File.svg new file mode 100644 index 0000000..9cdd5b9 --- /dev/null +++ b/resources/data/theme/default/File.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/data/theme/default/Folder.svg b/resources/data/theme/default/Folder.svg new file mode 100644 index 0000000..3f309e2 --- /dev/null +++ b/resources/data/theme/default/Folder.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/Forbidden.svg b/resources/data/theme/default/Forbidden.svg new file mode 100644 index 0000000..fa523d0 --- /dev/null +++ b/resources/data/theme/default/Forbidden.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/resources/data/theme/default/Help.svg b/resources/data/theme/default/Help.svg new file mode 100644 index 0000000..8dd63d7 --- /dev/null +++ b/resources/data/theme/default/Help.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/Home.svg b/resources/data/theme/default/Home.svg new file mode 100644 index 0000000..4aa0a07 --- /dev/null +++ b/resources/data/theme/default/Home.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/resources/data/theme/default/Info.svg b/resources/data/theme/default/Info.svg new file mode 100644 index 0000000..3c957ff --- /dev/null +++ b/resources/data/theme/default/Info.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/List.svg b/resources/data/theme/default/List.svg new file mode 100644 index 0000000..8f2414a --- /dev/null +++ b/resources/data/theme/default/List.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/resources/data/theme/default/Load.svg b/resources/data/theme/default/Load.svg new file mode 100644 index 0000000..926fb25 --- /dev/null +++ b/resources/data/theme/default/Load.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/Lock.svg b/resources/data/theme/default/Lock.svg new file mode 100644 index 0000000..b4d88e6 --- /dev/null +++ b/resources/data/theme/default/Lock.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/Next.svg b/resources/data/theme/default/Next.svg new file mode 100644 index 0000000..8ac2c93 --- /dev/null +++ b/resources/data/theme/default/Next.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/OpenMenu.svg b/resources/data/theme/default/OpenMenu.svg new file mode 100644 index 0000000..7754b5e --- /dev/null +++ b/resources/data/theme/default/OpenMenu.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/resources/data/theme/default/Parameter.svg b/resources/data/theme/default/Parameter.svg new file mode 100644 index 0000000..5eeed26 --- /dev/null +++ b/resources/data/theme/default/Parameter.svg @@ -0,0 +1,61 @@ + + + + + + + + + + image/svg+xml + + + + + + + diff --git a/resources/data/theme/default/Previous.svg b/resources/data/theme/default/Previous.svg new file mode 100644 index 0000000..08c79b5 --- /dev/null +++ b/resources/data/theme/default/Previous.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/Quit.svg b/resources/data/theme/default/Quit.svg new file mode 100644 index 0000000..bc512d1 --- /dev/null +++ b/resources/data/theme/default/Quit.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/resources/data/theme/default/Redo.svg b/resources/data/theme/default/Redo.svg new file mode 100644 index 0000000..a76f98c --- /dev/null +++ b/resources/data/theme/default/Redo.svg @@ -0,0 +1,12 @@ + + + + + + + diff --git a/resources/data/theme/default/Remove.svg b/resources/data/theme/default/Remove.svg new file mode 100644 index 0000000..e4c4d79 --- /dev/null +++ b/resources/data/theme/default/Remove.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/Remove2.svg b/resources/data/theme/default/Remove2.svg new file mode 100644 index 0000000..29be9c9 --- /dev/null +++ b/resources/data/theme/default/Remove2.svg @@ -0,0 +1,63 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/resources/data/theme/default/Replace.svg b/resources/data/theme/default/Replace.svg new file mode 100644 index 0000000..2d59c32 --- /dev/null +++ b/resources/data/theme/default/Replace.svg @@ -0,0 +1,15 @@ + + + + + image/svg+xml + + + + + + + + + + diff --git a/resources/data/theme/default/SDCard.svg b/resources/data/theme/default/SDCard.svg new file mode 100644 index 0000000..1b434d3 --- /dev/null +++ b/resources/data/theme/default/SDCard.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/Save.svg b/resources/data/theme/default/Save.svg new file mode 100644 index 0000000..138c8a4 --- /dev/null +++ b/resources/data/theme/default/Save.svg @@ -0,0 +1,16 @@ + + + + + + + + + \ No newline at end of file diff --git a/resources/data/theme/default/Search.svg b/resources/data/theme/default/Search.svg new file mode 100644 index 0000000..272fb0b --- /dev/null +++ b/resources/data/theme/default/Search.svg @@ -0,0 +1,49 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/resources/data/theme/default/Trash.svg b/resources/data/theme/default/Trash.svg new file mode 100644 index 0000000..c7765e9 --- /dev/null +++ b/resources/data/theme/default/Trash.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/resources/data/theme/default/Undo.svg b/resources/data/theme/default/Undo.svg new file mode 100644 index 0000000..2cdc7f8 --- /dev/null +++ b/resources/data/theme/default/Undo.svg @@ -0,0 +1,12 @@ + + + + + + + diff --git a/resources/data/theme/default/Up.svg b/resources/data/theme/default/Up.svg new file mode 100644 index 0000000..273a0fe --- /dev/null +++ b/resources/data/theme/default/Up.svg @@ -0,0 +1,14 @@ + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/data/theme/default/Update.svg b/resources/data/theme/default/Update.svg new file mode 100644 index 0000000..67286a1 --- /dev/null +++ b/resources/data/theme/default/Update.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/resources/data/theme/default/Validate.svg b/resources/data/theme/default/Validate.svg new file mode 100644 index 0000000..54e9f80 --- /dev/null +++ b/resources/data/theme/default/Validate.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/VolumeMax.svg b/resources/data/theme/default/VolumeMax.svg new file mode 100644 index 0000000..181f34d --- /dev/null +++ b/resources/data/theme/default/VolumeMax.svg @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/resources/data/theme/default/VolumeMute.svg b/resources/data/theme/default/VolumeMute.svg new file mode 100644 index 0000000..a28cefb --- /dev/null +++ b/resources/data/theme/default/VolumeMute.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/resources/data/theme/default/Warning.svg b/resources/data/theme/default/Warning.svg new file mode 100644 index 0000000..2e1cbd7 --- /dev/null +++ b/resources/data/theme/default/Warning.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/data/theme/default/WhereAmI.svg b/resources/data/theme/default/WhereAmI.svg new file mode 100644 index 0000000..80e6032 --- /dev/null +++ b/resources/data/theme/default/WhereAmI.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/resources/data/theme/default/WrapAround.svg b/resources/data/theme/default/WrapAround.svg new file mode 100644 index 0000000..116be27 --- /dev/null +++ b/resources/data/theme/default/WrapAround.svg @@ -0,0 +1,13 @@ + + + + + image/svg+xml + + + + + + + + diff --git a/resources/data/theme/default/ZoomIn.svg b/resources/data/theme/default/ZoomIn.svg new file mode 100644 index 0000000..25578fc --- /dev/null +++ b/resources/data/theme/default/ZoomIn.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/resources/data/theme/shape/round/Button.frag b/resources/data/theme/shape/round/Button.frag new file mode 100644 index 0000000..21e7245 --- /dev/null +++ b/resources/data/theme/shape/round/Button.frag @@ -0,0 +1,27 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// transmit from the vertex shader +varying vec2 v_propPos; +varying vec4 v_colorTansition; + +uniform vec4 EW_border; +uniform vec4 EW_background; + +void main(void) { + // vec2 circleMode = smoothstep(ratioLow, ratio, positionCenter)*(S_roundedRatio+S_sizePadding); + // Calculate the distance of the radius + float tmpDist = sqrt(dot(v_propPos,v_propPos)); + // Generate the internal rampe for the the imput drawing + float tmpVal = smoothstep(0.6, 0.7, tmpDist); + // set Background + gl_FragColor = mix(v_colorTansition, EW_background, tmpVal); + // Generate the internal rampe for the the imput drawing + float tmpValBorder = 0.7 - abs(tmpDist - 0.7); + float tmpBorder = smoothstep(0.5, 0.7, tmpValBorder); + // set Border + gl_FragColor = mix(gl_FragColor, EW_border, tmpBorder); +} + diff --git a/resources/data/theme/shape/round/Button.json b/resources/data/theme/shape/round/Button.json new file mode 100644 index 0000000..8da1a6a --- /dev/null +++ b/resources/data/theme/shape/round/Button.json @@ -0,0 +1,23 @@ +{ + mode:3, + display-outside:false, + + padding-out-left:1, + padding-out-right:1, + padding-out-top:1, + padding-out-buttom:1, + + border-left:12, + border-right:12, + border-top:12, + border-buttom:12, + + padding-in-left:1, + padding-in-right:1, + padding-in-top:1, + padding-in-buttom:1, + + change-time:356, + program:"THEME_GUI:///Button.prog?lib=ewol", + color:"THEME_COLOR:///Button.json?lib=ewol" +} diff --git a/resources/data/theme/shape/round/Button.vert b/resources/data/theme/shape/round/Button.vert new file mode 100644 index 0000000..f421b12 --- /dev/null +++ b/resources/data/theme/shape/round/Button.vert @@ -0,0 +1,51 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct widgetStateProperty { + int stateOld; + int stateNew; + float transition; +}; + +uniform widgetStateProperty EW_status; + +// Input : +attribute vec2 EW_coord2d; +attribute vec2 EW_widgetPropertyPos; +uniform mat4 EW_MatrixTransformation; +uniform vec4 EW_foreground; +uniform vec4 EW_foregroundHover; +uniform vec4 EW_foregroundSelected; +uniform vec4 EW_foregroundPressed; + +// output : +varying vec2 v_propPos; +varying vec4 v_colorTansition; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + v_propPos = EW_widgetPropertyPos; + + vec4 colorOld = EW_foreground; + if(EW_status.stateOld == 1) { + colorOld = EW_foregroundPressed; + } else if(EW_status.stateOld == 2) { + colorOld = EW_foregroundHover; + } else if(EW_status.stateOld == 3) { + colorOld = EW_foregroundSelected; + } + vec4 colorNew = EW_foreground; + if(EW_status.stateNew == 1) { + colorNew = EW_foregroundPressed; + } else if(EW_status.stateNew == 2) { + colorNew = EW_foregroundHover; + } else if(EW_status.stateNew == 3) { + colorNew = EW_foregroundSelected; + } + + // note : int() is needed for the OpenGL ES platform + v_colorTansition = colorOld * (1.0 - EW_status.transition) + + colorNew * EW_status.transition; +} diff --git a/resources/data/theme/shape/round/CheckBox.frag b/resources/data/theme/shape/round/CheckBox.frag new file mode 100644 index 0000000..a9df069 --- /dev/null +++ b/resources/data/theme/shape/round/CheckBox.frag @@ -0,0 +1,70 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct widgetStateProperty { + int activate; + int stateOld; + int stateNew; + float transition; +}; + +uniform widgetStateProperty EW_status; + +// transmit from the vertex shader +varying vec2 v_position; // interpolated position ... +varying vec2 v_propPos; +varying vec4 v_colorTansition; +varying vec4 v_colorBorder; +varying vec4 v_colorBackground; +varying vec4 v_colorInside; + +// internal static define +float S_sizePadding = 3.0; // must not be NULL +float S_sizeBorder = 1.0; //==> this id for 1 px border +float S_roundedRatio = 10.0; + + +void main(void) { + // position form center : + vec2 ratio = EW_widgetProperty.size / 2.0; + + // prevent origin moving ... + vec2 position = v_position - EW_widgetProperty.origin; + + /* generate a central simetry + ____ _____ + \ / + \ / + \ / + - + */ + vec2 positionCenter = abs(position-ratio); + // This is a clip to remove center of the display of the widget + vec2 ratioLow = ratio - (S_roundedRatio+S_sizePadding); + vec2 circleMode = smoothstep(ratioLow, ratio, positionCenter)*(S_roundedRatio+S_sizePadding); + // Calculate the distance of the radius + float tmpDist = float(int(sqrt(dot(circleMode,circleMode)))); + // Generate the internal rampe for the the imput drawing + float tmpVal = smoothstep(S_roundedRatio - S_sizeBorder*1.5, + S_roundedRatio + S_sizeBorder*1.5, + tmpDist); + // set Background + gl_FragColor = v_colorBackground; + // set foreground + gl_FragColor = gl_FragColor*tmpVal + v_colorTansition*(1.0-tmpVal); + // set border + float tmpVal2 = abs(tmpVal-0.5)*2.0; + gl_FragColor = gl_FragColor*tmpVal2 + v_colorBorder*(1.0-tmpVal2); + + // prevent origin moving ... + position = v_position - EW_widgetProperty.insidePos - EW_widgetProperty.insideSize*0.5; + position = position / EW_widgetProperty.insideSize; + + if (sqrt(dot(position, position)) <= 1.0) { + gl_FragColor = v_colorInside; + } + +} + diff --git a/resources/data/theme/shape/round/CheckBox.json b/resources/data/theme/shape/round/CheckBox.json new file mode 100644 index 0000000..cf8c21e --- /dev/null +++ b/resources/data/theme/shape/round/CheckBox.json @@ -0,0 +1,11 @@ + + box-size:20, + box-inside:12, + padding-left:10, + padding-right:10, + padding-top:10, + padding-buttom:10, + change-time:356, + program:"THEME_GUI:///CheckBox.prog?lib=ewol", + color:"THEME_COLOR:///CheckBox.json?lib=ewol" +} diff --git a/resources/data/theme/shape/round/CheckBox.vert b/resources/data/theme/shape/round/CheckBox.vert new file mode 100644 index 0000000..e1c5aae --- /dev/null +++ b/resources/data/theme/shape/round/CheckBox.vert @@ -0,0 +1,63 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct widgetStateProperty { + int activate; + int stateOld; + int stateNew; + float transition; +}; + +uniform widgetStateProperty EW_status; + +// Input : +attribute vec2 EW_coord2d; +attribute vec2 EW_widgetPropertyPos; +uniform mat4 EW_MatrixTransformation; +uniform vec4 EW_border; +uniform vec4 EW_background; +uniform vec4 EW_foreground; +uniform vec4 EW_foregroundHover; +uniform vec4 EW_foregroundSelected; +uniform vec4 EW_foregroundPressed; + +// output : +varying vec2 v_position; // This will be passed into the fragment shader. +varying vec2 v_propPos; +varying vec4 v_colorTansition; +varying vec4 v_colorBorder; +varying vec4 v_colorBackground; +varying vec4 v_colorInside; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + // transmit position of the curent element (intermolated ...) + v_position = EW_coord2d; + v_propPos = EW_widgetPropertyPos; + + vec4 colorOld = EW_foreground; + if(EW_status.stateOld == 1) { + colorOld = EW_foregroundPressed; + } else if(EW_status.stateOld == 2) { + colorOld = EW_foregroundHover; + } + vec4 colorNew = EW_foreground; + if(EW_status.stateNew == 1) { + colorNew = EW_foregroundPressed; + } else if(EW_status.stateNew == 2) { + colorNew = EW_foregroundHover; + } + + v_colorInside = EW_foreground; + if (EW_status.activate == 1) { + v_colorInside = EW_foregroundSelected; + } + + // note : int() is needed for the OpenGL ES platform + v_colorTansition = colorOld * (1.0 - EW_status.transition) + + colorNew * EW_status.transition; + v_colorBorder = EW_border; + v_colorBackground = EW_background; +} diff --git a/resources/data/theme/shape/round/ContextMenu.frag b/resources/data/theme/shape/round/ContextMenu.frag new file mode 100644 index 0000000..2c1052f --- /dev/null +++ b/resources/data/theme/shape/round/ContextMenu.frag @@ -0,0 +1,26 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +uniform vec4 EW_background; +uniform vec4 EW_foreground; +uniform vec4 EW_border; + +varying vec2 v_propPos; + +void main(void) { + // vec2 circleMode = smoothstep(ratioLow, ratio, positionCenter)*(S_roundedRatio+S_sizePadding); + // Calculate the distance of the radius + float tmpDist = sqrt(dot(v_propPos,v_propPos)); + // Generate the internal rampe for the the imput drawing + float tmpVal = smoothstep(0.6, 0.7, tmpDist); + // set Background + gl_FragColor = mix(EW_foreground, EW_background, tmpVal); + // Generate the internal rampe for the the imput drawing + float tmpValBorder = 0.7 - abs(tmpDist - 0.7); + float tmpBorder = smoothstep(0.5, 0.7, tmpValBorder); + // set Border + gl_FragColor = mix(gl_FragColor, EW_border, tmpBorder); +} + diff --git a/resources/data/theme/shape/round/ContextMenu.json b/resources/data/theme/shape/round/ContextMenu.json new file mode 100644 index 0000000..e8923b5 --- /dev/null +++ b/resources/data/theme/shape/round/ContextMenu.json @@ -0,0 +1,23 @@ +{ + mode:3, + display-outside:false, + + padding-out-left:1, + padding-out-right:1, + padding-out-top:1, + padding-out-buttom:1, + + border-left:12, + border-right:12, + border-top:12, + border-buttom:12, + + padding-in-left:1, + padding-in-right:1, + padding-in-top:1, + padding-in-buttom:1, + + change-time:356, + program:"THEME_GUI:///ContextMenu.prog?lib=ewol", + color:"THEME_COLOR:///ContextMenu.json?lib=ewol" +} diff --git a/resources/data/theme/shape/round/ContextMenu.vert b/resources/data/theme/shape/round/ContextMenu.vert new file mode 100644 index 0000000..d4da54e --- /dev/null +++ b/resources/data/theme/shape/round/ContextMenu.vert @@ -0,0 +1,17 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input : +attribute vec2 EW_coord2d; +attribute vec2 EW_widgetPropertyPos; +uniform mat4 EW_MatrixTransformation; + +// output : +varying vec2 v_propPos; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + v_propPos = EW_widgetPropertyPos; +} diff --git a/resources/data/theme/shape/round/Entry.frag b/resources/data/theme/shape/round/Entry.frag new file mode 100644 index 0000000..8544ce8 --- /dev/null +++ b/resources/data/theme/shape/round/Entry.frag @@ -0,0 +1,28 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + + +// transmit from the vertex shader +varying vec2 v_propPos; + +uniform vec4 EW_background; +uniform vec4 EW_foreground; +uniform vec4 EW_border; + +void main(void) { + // vec2 circleMode = smoothstep(ratioLow, ratio, positionCenter)*(S_roundedRatio+S_sizePadding); + // Calculate the distance of the radius + float tmpDist = sqrt(dot(v_propPos,v_propPos)); + // Generate the internal rampe for the the imput drawing + float tmpVal = smoothstep(0.6, 0.7, tmpDist); + // set Background + gl_FragColor = mix(EW_foreground, EW_background, tmpVal); + // Generate the internal rampe for the the imput drawing + float tmpValBorder = 0.7 - abs(tmpDist - 0.7); + float tmpBorder = smoothstep(0.5, 0.7, tmpValBorder); + // set Border + gl_FragColor = mix(gl_FragColor, EW_border, tmpBorder); +} + diff --git a/resources/data/theme/shape/round/Entry.json b/resources/data/theme/shape/round/Entry.json new file mode 100644 index 0000000..d812b70 --- /dev/null +++ b/resources/data/theme/shape/round/Entry.json @@ -0,0 +1,23 @@ +{ + mode:3, + display-outside:false, + + padding-out-left:1, + padding-out-right:1, + padding-out-top:1, + padding-out-buttom:1, + + border-left:12, + border-right:12, + border-top:12, + border-buttom:12, + + padding-in-left:1, + padding-in-right:1, + padding-in-top:1, + padding-in-buttom:1, + + change-time:356, + program:"THEME_GUI:///Entry.prog?lib=ewol", + color:"THEME_COLOR:///Entry.json?lib=ewol" +} diff --git a/resources/data/theme/shape/round/Entry.vert b/resources/data/theme/shape/round/Entry.vert new file mode 100644 index 0000000..d4da54e --- /dev/null +++ b/resources/data/theme/shape/round/Entry.vert @@ -0,0 +1,17 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input : +attribute vec2 EW_coord2d; +attribute vec2 EW_widgetPropertyPos; +uniform mat4 EW_MatrixTransformation; + +// output : +varying vec2 v_propPos; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + v_propPos = EW_widgetPropertyPos; +} diff --git a/resources/data/theme/shape/round/PopUp.frag b/resources/data/theme/shape/round/PopUp.frag new file mode 100644 index 0000000..cdf00b2 --- /dev/null +++ b/resources/data/theme/shape/round/PopUp.frag @@ -0,0 +1,26 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// transmit from the vertex shader +varying vec2 v_propPos; + +uniform vec4 EW_background; +uniform vec4 EW_foreground; +uniform vec4 EW_border; + +void main(void) { + // vec2 circleMode = smoothstep(ratioLow, ratio, positionCenter)*(S_roundedRatio+S_sizePadding); + // Calculate the distance of the radius + float tmpDist = sqrt(dot(v_propPos,v_propPos)); + // Generate the internal rampe for the the imput drawing + float tmpVal = smoothstep(0.6, 0.7, tmpDist); + // set Background + gl_FragColor = mix(EW_foreground, EW_background, tmpVal); + // Generate the internal rampe for the the imput drawing + float tmpValBorder = 0.7 - abs(tmpDist - 0.7); + float tmpBorder = smoothstep(0.5, 0.7, tmpValBorder); + // set Border + gl_FragColor = mix(gl_FragColor, EW_border, tmpBorder); +} \ No newline at end of file diff --git a/resources/data/theme/shape/round/PopUp.json b/resources/data/theme/shape/round/PopUp.json new file mode 100644 index 0000000..1a570f9 --- /dev/null +++ b/resources/data/theme/shape/round/PopUp.json @@ -0,0 +1,23 @@ +{ + mode:3, + display-outside:false, + + padding-out-left:1, + padding-out-right:1, + padding-out-top:1, + padding-out-buttom:1, + + border-left:12, + border-right:12, + border-top:12, + border-buttom:12, + + padding-in-left:1, + padding-in-right:1, + padding-in-top:1, + padding-in-buttom:1, + + change-time:356, + program:"THEME_GUI:///PopUp.prog?lib=ewol, + color:"THEME_COLOR:///PopUp.json?lib=ewol" +} diff --git a/resources/data/theme/shape/round/PopUp.vert b/resources/data/theme/shape/round/PopUp.vert new file mode 100644 index 0000000..399e312 --- /dev/null +++ b/resources/data/theme/shape/round/PopUp.vert @@ -0,0 +1,20 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input : +attribute vec2 EW_coord2d; +attribute vec2 EW_widgetPropertyPos; +uniform mat4 EW_MatrixTransformation; + +// output : +varying vec2 v_position; // This will be passed into the fragment shader. +varying vec2 v_propPos; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + // transmit position of the curent element (intermolated ...) + v_position = EW_coord2d; + v_propPos = EW_widgetPropertyPos; +} diff --git a/resources/data/theme/shape/round/WidgetScrolled.frag b/resources/data/theme/shape/round/WidgetScrolled.frag new file mode 100644 index 0000000..7c788f6 --- /dev/null +++ b/resources/data/theme/shape/round/WidgetScrolled.frag @@ -0,0 +1,60 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct widgetStateProperty { + int stateOld; + int stateNew; + float transition; +}; + +uniform widgetStateProperty EW_status; + +// transmit from the vertex shader +varying vec2 v_position; // interpolated position ... +varying vec2 v_propPos; +varying vec4 v_colorTansition; +varying vec4 v_colorBorder; +varying vec4 v_colorBackground; + +// internal static define +float S_sizePadding = 2.0; // must not be NULL +float S_sizeBorder = 1.3; //==> this id for 1 px border +float S_roundedRatio = 6.0; + + +void main(void) { + // position form center : + vec2 ratio = EW_widgetProperty.insideSize / 2.0; + + // prevent origin moving ... + vec2 position = v_position - EW_widgetProperty.insidePos; + + /* generate a central simetry + ____ _____ + \ / + \ / + \ / + - + */ + vec2 positionCenter = abs(position-ratio); + // This is a clip to remove center of the display of the widget + vec2 ratioLow = ratio - (S_roundedRatio+S_sizePadding); + vec2 circleMode = smoothstep(ratioLow, ratio, positionCenter)*(S_roundedRatio+S_sizePadding); + // Calculate the distance of the radius + float tmpDist = float(int(sqrt(dot(circleMode,circleMode)))); + // Generate the internal rampe for the the imput drawing + float tmpVal = smoothstep(S_roundedRatio - S_sizeBorder*1.5, + S_roundedRatio + S_sizeBorder*1.5, + tmpDist); + // set Background + gl_FragColor = v_colorBackground; + // set foreground + gl_FragColor = gl_FragColor*tmpVal + v_colorTansition*(1.0-tmpVal); + // set border + float tmpVal2 = abs(tmpVal-0.5)*2.0; + gl_FragColor = gl_FragColor*tmpVal2 + v_colorBorder*(1.0-tmpVal2); + +} + diff --git a/resources/data/theme/shape/round/WidgetScrolled.json b/resources/data/theme/shape/round/WidgetScrolled.json new file mode 100644 index 0000000..52bb594 --- /dev/null +++ b/resources/data/theme/shape/round/WidgetScrolled.json @@ -0,0 +1,9 @@ +{ + padding-left:16, + padding-right:16, + padding-top:16, + padding-buttom:16, + change-time:200, + program:"THEME_GUI:///WidgetScrolled.prog?lib=ewol", + color:"THEME_COLOR:///WidgetScrolled.json?lib=ewol" +} diff --git a/resources/data/theme/shape/round/WidgetScrolled.vert b/resources/data/theme/shape/round/WidgetScrolled.vert new file mode 100644 index 0000000..615f188 --- /dev/null +++ b/resources/data/theme/shape/round/WidgetScrolled.vert @@ -0,0 +1,50 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct widgetStateProperty { + int stateOld; + int stateNew; + float transition; +}; + +uniform widgetStateProperty EW_status; + +// Input : +attribute vec2 EW_coord2d; +attribute vec2 EW_widgetPropertyPos; +uniform mat4 EW_MatrixTransformation; +uniform vec4 EW_border; +uniform vec4 EW_background; +uniform vec4 EW_foreground; +uniform vec4 EW_foregroundPressed; + +// output : +varying vec2 v_position; // This will be passed into the fragment shader. +varying vec2 v_propPos; +varying vec4 v_colorTansition; +varying vec4 v_colorBorder; +varying vec4 v_colorBackground; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + // transmit position of the curent element (intermolated ...) + v_position = EW_coord2d; + v_propPos = EW_widgetPropertyPos; + + vec4 colorOld = EW_foreground; + if(EW_status.stateOld == 1) { + colorOld = EW_foregroundPressed; + } + vec4 colorNew = EW_foreground; + if(EW_status.stateNew == 1) { + colorNew = EW_foregroundPressed; + } + + // note : int() is needed for the OpenGL ES platform + v_colorTansition = colorOld * (1.0 - EW_status.transition) + + colorNew * EW_status.transition; + v_colorBorder = EW_border; + v_colorBackground = EW_background; +} diff --git a/resources/data/theme/shape/square/Button.frag b/resources/data/theme/shape/square/Button.frag new file mode 100644 index 0000000..d8e7a96 --- /dev/null +++ b/resources/data/theme/shape/square/Button.frag @@ -0,0 +1,26 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// transmit from the vertex shader +varying vec2 v_propPos; +varying vec4 v_colorTansition; +uniform vec4 EW_border; +uniform vec4 EW_background; + + +void main(void) { + // prevent origin moving ... + gl_FragColor = vec4(v_propPos.y, v_propPos.x, 1.0, 1.0); + if( v_propPos.x == 1.0 + && v_propPos.y == 1.0) { + gl_FragColor = v_colorTansition; + } else if ( v_propPos.x == 0.0 + || v_propPos.y == 0.0) { + gl_FragColor = EW_background; + } else { + gl_FragColor = EW_border; + } +} + diff --git a/resources/data/theme/shape/square/Button.json b/resources/data/theme/shape/square/Button.json new file mode 100644 index 0000000..b2a5ce8 --- /dev/null +++ b/resources/data/theme/shape/square/Button.json @@ -0,0 +1,23 @@ +{ + mode:2, + display-outside:false, + + padding-out-left:1, + padding-out-right:1, + padding-out-top:1, + padding-out-buttom:1, + + border-left:1, + border-right:1, + border-top:1, + border-buttom:1, + + padding-in-left:1, + padding-in-right:1, + padding-in-top:1, + padding-in-buttom:1, + + change-time:356, + program:"THEME_GUI:///Button.prog?lib=ewol", + color:"THEME_COLOR:///Button.json?lib=ewol" +} diff --git a/resources/data/theme/shape/square/Button.vert b/resources/data/theme/shape/square/Button.vert new file mode 100644 index 0000000..7c66c3c --- /dev/null +++ b/resources/data/theme/shape/square/Button.vert @@ -0,0 +1,52 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct widgetStateProperty { + int stateOld; + int stateNew; + float transition; +}; + +uniform widgetStateProperty EW_status; + +// Input : +attribute vec2 EW_coord2d; +attribute vec2 EW_widgetPropertyPos; +uniform mat4 EW_MatrixTransformation; +uniform vec4 EW_foreground; +uniform vec4 EW_foregroundHover; +uniform vec4 EW_foregroundSelected; +uniform vec4 EW_foregroundPressed; + +// output : +varying vec2 v_propPos; +varying vec4 v_colorTansition; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + // transmit position of the curent element (intermolated ...) + v_propPos = EW_widgetPropertyPos; + + vec4 colorOld = EW_foreground; + if(EW_status.stateOld == 1) { + colorOld = EW_foregroundPressed; + } else if(EW_status.stateOld == 2) { + colorOld = EW_foregroundHover; + } else if(EW_status.stateOld == 3) { + colorOld = EW_foregroundSelected; + } + vec4 colorNew = EW_foreground; + if(EW_status.stateNew == 1) { + colorNew = EW_foregroundPressed; + } else if(EW_status.stateNew == 2) { + colorNew = EW_foregroundHover; + } else if(EW_status.stateNew == 3) { + colorNew = EW_foregroundSelected; + } + + // note : int() is needed for the OpenGL ES platform + v_colorTansition = colorOld * (1.0 - EW_status.transition) + + colorNew * EW_status.transition; +} diff --git a/resources/data/theme/shape/square/CheckBox.frag b/resources/data/theme/shape/square/CheckBox.frag new file mode 100644 index 0000000..3c11e09 --- /dev/null +++ b/resources/data/theme/shape/square/CheckBox.frag @@ -0,0 +1,28 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + + +// transmit from the vertex shader +varying vec2 v_position; // interpolated position ... +varying vec2 v_propPos; +varying vec4 v_colorTansition; +varying vec4 v_colorBorder; +varying vec4 v_colorBackground; +varying vec4 v_colorInside; + +void main(void) { + // prevent origin moving ... + gl_FragColor = vec4(v_propPos.y, v_propPos.x, 1.0, 1.0); + if( v_propPos.x == 1.0 + && v_propPos.y == 1.0) { + gl_FragColor = v_colorTansition; + } else if ( v_propPos.x == 0.0 + || v_propPos.y == 0.0) { + gl_FragColor = v_colorBackground; + } else { + gl_FragColor = v_colorBorder; + } +} + diff --git a/resources/data/theme/shape/square/CheckBox.json b/resources/data/theme/shape/square/CheckBox.json new file mode 100644 index 0000000..589e187 --- /dev/null +++ b/resources/data/theme/shape/square/CheckBox.json @@ -0,0 +1,25 @@ +{ + mode:2, + display-outside:false, + + padding-out-left:1, + padding-out-right:1, + padding-out-top:1, + padding-out-buttom:1, + + border-left:1, + border-right:1, + border-top:1, + border-buttom:1, + + padding-in-left:1, + padding-in-right:1, + padding-in-top:1, + padding-in-buttom:1, + + box-size:20, + box-inside:12, + change-time:356, + program:"THEME_GUI:///CheckBox.prog?lib=ewol", + color:"THEME_COLOR:///CheckBox.json?lib=ewol" +} \ No newline at end of file diff --git a/resources/data/theme/shape/square/CheckBox.vert b/resources/data/theme/shape/square/CheckBox.vert new file mode 100644 index 0000000..50900e2 --- /dev/null +++ b/resources/data/theme/shape/square/CheckBox.vert @@ -0,0 +1,71 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct widgetStateProperty { + int activate; + int stateOld; + int stateNew; + float transition; +}; + +uniform widgetStateProperty EW_status; + +// Input : +attribute vec2 EW_coord2d; +attribute vec2 EW_widgetPropertyPos; +uniform mat4 EW_MatrixTransformation; +uniform vec4 EW_border; +uniform vec4 EW_background; +uniform vec4 EW_foreground; +uniform vec4 EW_foregroundHover; +uniform vec4 EW_foregroundSelected; +uniform vec4 EW_foregroundPressed; + +// output : +varying vec2 v_position; // This will be passed into the fragment shader. +varying vec2 v_propPos; +varying vec4 v_colorTansition; +varying vec4 v_colorBorder; +varying vec4 v_colorBackground; +varying vec4 v_colorInside; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + // transmit position of the curent element (intermolated ...) + v_position = EW_coord2d; + v_propPos = EW_widgetPropertyPos; + + vec4 colorOld = EW_foreground; + if(EW_status.stateOld == 1) { + colorOld = EW_foregroundPressed; + } else if(EW_status.stateOld == 2) { + colorOld = EW_foregroundHover; + } else if(EW_status.stateOld == 3) { + colorOld = EW_foregroundSelected; + } + vec4 colorNew = EW_foreground; + if(EW_status.stateNew == 1) { + colorNew = EW_foregroundPressed; + } else if(EW_status.stateNew == 2) { + colorNew = EW_foregroundHover; + } else if(EW_status.stateNew == 3) { + colorNew = EW_foregroundSelected; + } + + v_colorInside = EW_foreground; + if (EW_status.activate == 1) { + v_colorInside = EW_foregroundSelected; + } + + // note : int() is needed for the OpenGL ES platform + v_colorTansition = colorOld * (1.0 - EW_status.transition) + + colorNew * EW_status.transition; + // for test ... TODO : Remove + if (EW_status.activate == 1) { + v_colorTansition = EW_foregroundSelected; + } + v_colorBorder = EW_border; + v_colorBackground = EW_background; +} diff --git a/resources/data/theme/shape/square/ContextMenu.frag b/resources/data/theme/shape/square/ContextMenu.frag new file mode 100644 index 0000000..8363c53 --- /dev/null +++ b/resources/data/theme/shape/square/ContextMenu.frag @@ -0,0 +1,27 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +uniform vec4 EW_background; +uniform vec4 EW_foreground; +uniform vec4 EW_border; + +// transmit from the vertex shader +varying vec2 v_position; // interpolated position ... +varying vec2 v_propPos; + +void main(void) { + // prevent origin moving ... + gl_FragColor = vec4(v_propPos.y, v_propPos.x, 1.0, 1.0); + if( v_propPos.x == 1.0 + && v_propPos.y == 1.0) { + gl_FragColor = EW_foreground; + } else if ( v_propPos.x == 0.0 + || v_propPos.y == 0.0) { + gl_FragColor = EW_background; + } else { + gl_FragColor = EW_border; + } +} + diff --git a/resources/data/theme/shape/square/ContextMenu.json b/resources/data/theme/shape/square/ContextMenu.json new file mode 100644 index 0000000..29495b0 --- /dev/null +++ b/resources/data/theme/shape/square/ContextMenu.json @@ -0,0 +1,23 @@ +{ + mode:2, + display-outside:false, + + padding-out-left:2, + padding-out-right:2, + padding-out-top:2, + padding-out-buttom:2, + + border-left:3, + border-right:3, + border-top:3, + border-buttom:3, + + padding-in-left:2, + padding-in-right:2, + padding-in-top:2, + padding-in-buttom:2, + + change-time:356, + program:"THEME_GUI:///ContextMenu.prog?lib=ewol", + color:"THEME_COLOR:///ContextMenu.json?lib=ewol" +} diff --git a/resources/data/theme/shape/square/ContextMenu.vert b/resources/data/theme/shape/square/ContextMenu.vert new file mode 100644 index 0000000..a75f3e8 --- /dev/null +++ b/resources/data/theme/shape/square/ContextMenu.vert @@ -0,0 +1,28 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct widgetStateProperty { + int stateOld; + int stateNew; + float transition; +}; + +uniform widgetStateProperty EW_status; + +// Input : +attribute vec2 EW_coord2d; +attribute vec2 EW_widgetPropertyPos; +uniform mat4 EW_MatrixTransformation; + +// output : +varying vec2 v_position; // This will be passed into the fragment shader. +varying vec2 v_propPos; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + // transmit position of the curent element (intermolated ...) + v_position = EW_coord2d; + v_propPos = EW_widgetPropertyPos; +} diff --git a/resources/data/theme/shape/square/Entry.frag b/resources/data/theme/shape/square/Entry.frag new file mode 100644 index 0000000..bf5d7f2 --- /dev/null +++ b/resources/data/theme/shape/square/Entry.frag @@ -0,0 +1,27 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +uniform vec4 EW_background; +uniform vec4 EW_border; + + +// transmit from the vertex shader +varying vec2 v_position; // interpolated position ... +varying vec2 v_propPos; +varying vec4 v_colorTansition; + +void main(void) { + // prevent origin moving ... + gl_FragColor = vec4(v_propPos.y, v_propPos.x, 1.0, 1.0); + if( v_propPos.x == 1.0 + && v_propPos.y == 1.0) { + gl_FragColor = v_colorTansition; + } else if ( v_propPos.x == 0.0 + || v_propPos.y == 0.0) { + gl_FragColor = EW_background; + } else { + gl_FragColor = EW_border; + } +} \ No newline at end of file diff --git a/resources/data/theme/shape/square/Entry.json b/resources/data/theme/shape/square/Entry.json new file mode 100644 index 0000000..79eedd2 --- /dev/null +++ b/resources/data/theme/shape/square/Entry.json @@ -0,0 +1,23 @@ +{ + mode:2, + display-outside:false, + + padding-out-left:2, + padding-out-right:2, + padding-out-top:2, + padding-out-buttom:2, + + border-left:1, + border-right:1, + border-top:1, + border-buttom:1, + + padding-in-left:2, + padding-in-right:2, + padding-in-top:2, + padding-in-buttom:2, + + change-time:356, + program:"THEME_GUI:///Entry.prog?lib=ewol", + color:"THEME_COLOR:///Entry.json?lib=ewol" +} diff --git a/resources/data/theme/shape/square/Entry.vert b/resources/data/theme/shape/square/Entry.vert new file mode 100644 index 0000000..d02de34 --- /dev/null +++ b/resources/data/theme/shape/square/Entry.vert @@ -0,0 +1,50 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct widgetStateProperty { + int stateOld; + int stateNew; + float transition; +}; + +// Input : +attribute vec2 EW_coord2d; +attribute vec2 EW_widgetPropertyPos; +uniform mat4 EW_MatrixTransformation; +uniform widgetStateProperty EW_status; +uniform vec4 EW_foreground; +uniform vec4 EW_foregroundSelected; +uniform vec4 EW_foregroundHover; + +// output : +varying vec2 v_position; // This will be passed into the fragment shader. +varying vec2 v_propPos; +varying vec4 v_colorTansition; + +void main(void) { + + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + // transmit position of the curent element (intermolated ...) + v_position = EW_coord2d; + v_propPos = EW_widgetPropertyPos; + + + vec4 colorOld = EW_foreground; + if(EW_status.stateOld==1) { + colorOld = EW_foregroundSelected; + } else if(EW_status.stateOld==2) { + colorOld = EW_foregroundHover; + } + vec4 colorNew = EW_foreground; + if(EW_status.stateNew==1) { + colorNew = EW_foregroundSelected; + } else if(EW_status.stateNew==2) { + colorNew = EW_foregroundHover; + } + + // note : int() is needed for the OpenGL ES platform + v_colorTansition = colorOld*(1.0-EW_status.transition) + + colorNew*EW_status.transition; +} diff --git a/resources/data/theme/shape/square/PopUp.frag b/resources/data/theme/shape/square/PopUp.frag new file mode 100644 index 0000000..02b2f8e --- /dev/null +++ b/resources/data/theme/shape/square/PopUp.frag @@ -0,0 +1,27 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif +uniform vec4 EW_background; +uniform vec4 EW_foreground; +uniform vec4 EW_border; + + +// transmit from the vertex shader +varying vec2 v_position; // interpolated position ... +varying vec2 v_propPos; + +void main(void) { + // prevent origin moving ... + gl_FragColor = vec4(v_propPos.y, v_propPos.x, 1.0, 1.0); + if( v_propPos.x == 1.0 + && v_propPos.y == 1.0) { + gl_FragColor = EW_foreground; + } else if ( v_propPos.x == 0.0 + || v_propPos.y == 0.0) { + gl_FragColor = EW_background; + } else { + gl_FragColor = EW_border; + } +} + diff --git a/resources/data/theme/shape/square/PopUp.json b/resources/data/theme/shape/square/PopUp.json new file mode 100644 index 0000000..b033fb9 --- /dev/null +++ b/resources/data/theme/shape/square/PopUp.json @@ -0,0 +1,23 @@ +{ + mode:2, + display-outside:false, + + padding-out-left:2, + padding-out-right:2, + padding-out-top:2, + padding-out-buttom:2, + + border-left:3, + border-right:3, + border-top:3, + border-buttom:3, + + padding-in-left:2, + padding-in-right:2, + padding-in-top:2, + padding-in-buttom:2, + + change-time:356, + program:"THEME_GUI:///PopUp.prog?lib=ewol", + color:"THEME_COLOR:///PopUp.json?lib=ewol" +} diff --git a/resources/data/theme/shape/square/PopUp.vert b/resources/data/theme/shape/square/PopUp.vert new file mode 100644 index 0000000..d4da54e --- /dev/null +++ b/resources/data/theme/shape/square/PopUp.vert @@ -0,0 +1,17 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input : +attribute vec2 EW_coord2d; +attribute vec2 EW_widgetPropertyPos; +uniform mat4 EW_MatrixTransformation; + +// output : +varying vec2 v_propPos; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + v_propPos = EW_widgetPropertyPos; +} diff --git a/resources/data/theme/shape/square/Select.json b/resources/data/theme/shape/square/Select.json new file mode 100644 index 0000000..655fd31 --- /dev/null +++ b/resources/data/theme/shape/square/Select.json @@ -0,0 +1,5 @@ +{ + entry-shaper:"THEME_GUI:///SelectEntry.json?lib=ewol", + up-shaper:"THEME_GUI:///SelectBt.json?lib=ewol", + up-data:"", +} \ No newline at end of file diff --git a/resources/data/theme/shape/square/SelectBt.json b/resources/data/theme/shape/square/SelectBt.json new file mode 100644 index 0000000..41b4a94 --- /dev/null +++ b/resources/data/theme/shape/square/SelectBt.json @@ -0,0 +1,23 @@ +{ + mode:2, + display-outside:false, + + padding-out-left:0, + padding-out-right:1, + padding-out-top:1, + padding-out-buttom:1, + + border-left:1, + border-right:1, + border-top:1, + border-buttom:1, + + padding-in-left:1, + padding-in-right:1, + padding-in-top:1, + padding-in-buttom:1, + + change-time:356, + program:"THEME_GUI:///Button.prog?lib=ewol", + color:"THEME_COLOR:///Button.json?lib=ewol" +} diff --git a/resources/data/theme/shape/square/SelectEntry.json b/resources/data/theme/shape/square/SelectEntry.json new file mode 100644 index 0000000..2c31f26 --- /dev/null +++ b/resources/data/theme/shape/square/SelectEntry.json @@ -0,0 +1,23 @@ +{ + mode:2, + display-outside:false, + + padding-out-left:0, + padding-out-right:0, + padding-out-top:1, + padding-out-buttom:1, + + border-left:1, + border-right:0, + border-top:1, + border-buttom:1, + + padding-in-left:2, + padding-in-right:2, + padding-in-top:1, + padding-in-buttom:1, + + change-time:356, + program:"THEME_GUI:///Entry.prog?lib=ewol", + color:"THEME_COLOR:///Entry.json?lib=ewol" +} diff --git a/resources/data/theme/shape/square/Spin.json b/resources/data/theme/shape/square/Spin.json new file mode 100644 index 0000000..bc127f2 --- /dev/null +++ b/resources/data/theme/shape/square/Spin.json @@ -0,0 +1,7 @@ +{ + entry-shaper:"THEME_GUI:///SpinEntry.json?lib=ewol", + up-shaper:"THEME_GUI:///SpinUp.json?lib=ewol", + up-data:"", + down-shaper:"THEME_GUI:///SpinDown.json?lib=ewol", + down-data:"", +} \ No newline at end of file diff --git a/resources/data/theme/shape/square/SpinDown.json b/resources/data/theme/shape/square/SpinDown.json new file mode 100644 index 0000000..4b8452c --- /dev/null +++ b/resources/data/theme/shape/square/SpinDown.json @@ -0,0 +1,23 @@ +{ + mode:2, + display-outside:false, + + padding-out-left:0, + padding-out-right:0, + padding-out-top:1, + padding-out-buttom:1, + + border-left:1, + border-right:0, + border-top:1, + border-buttom:1, + + padding-in-left:1, + padding-in-right:1, + padding-in-top:1, + padding-in-buttom:1, + + change-time:356, + program:"THEME_GUI:///Button.prog?lib=ewol", + color:"THEME_COLOR:///Button.json?lib=ewol" +} diff --git a/resources/data/theme/shape/square/SpinEntry.json b/resources/data/theme/shape/square/SpinEntry.json new file mode 100644 index 0000000..2c31f26 --- /dev/null +++ b/resources/data/theme/shape/square/SpinEntry.json @@ -0,0 +1,23 @@ +{ + mode:2, + display-outside:false, + + padding-out-left:0, + padding-out-right:0, + padding-out-top:1, + padding-out-buttom:1, + + border-left:1, + border-right:0, + border-top:1, + border-buttom:1, + + padding-in-left:2, + padding-in-right:2, + padding-in-top:1, + padding-in-buttom:1, + + change-time:356, + program:"THEME_GUI:///Entry.prog?lib=ewol", + color:"THEME_COLOR:///Entry.json?lib=ewol" +} diff --git a/resources/data/theme/shape/square/SpinUp.json b/resources/data/theme/shape/square/SpinUp.json new file mode 100644 index 0000000..0159a01 --- /dev/null +++ b/resources/data/theme/shape/square/SpinUp.json @@ -0,0 +1,23 @@ +{ + mode:2, + display-outside:false, + + padding-out-left:0, + padding-out-right:0, + padding-out-top:1, + padding-out-buttom:1, + + border-left:1, + border-right:1, + border-top:1, + border-buttom:1, + + padding-in-left:1, + padding-in-right:1, + padding-in-top:1, + padding-in-buttom:1, + + change-time:356, + program:"THEME_GUI:///Button.prog?lib=ewol", + color:"THEME_COLOR:///Button.json?lib=ewol" +} diff --git a/resources/data/theme/shape/square/WidgetScrolled.frag b/resources/data/theme/shape/square/WidgetScrolled.frag new file mode 100644 index 0000000..2b6f3ad --- /dev/null +++ b/resources/data/theme/shape/square/WidgetScrolled.frag @@ -0,0 +1,25 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// transmit from the vertex shader +varying vec2 v_position; // interpolated position ... +varying vec2 v_propPos; +varying vec4 v_colorTansition; +varying vec4 v_colorBorder; +varying vec4 v_colorBackground; + +void main(void) { + // prevent origin moving ... + gl_FragColor = vec4(v_propPos.y, v_propPos.x, 1.0, 1.0); + if( v_propPos.x == 1.0 + && v_propPos.y == 1.0) { + gl_FragColor = v_colorTansition; + } else if ( v_propPos.x == 0.0 + || v_propPos.y == 0.0) { + gl_FragColor = v_colorBackground; + } else { + gl_FragColor = v_colorBorder; + } +} diff --git a/resources/data/theme/shape/square/WidgetScrolled.json b/resources/data/theme/shape/square/WidgetScrolled.json new file mode 100644 index 0000000..51b4ce9 --- /dev/null +++ b/resources/data/theme/shape/square/WidgetScrolled.json @@ -0,0 +1,23 @@ +{ + mode:2, + display-outside:true, + + padding-out-left:1, + padding-out-right:1, + padding-out-top:1, + padding-out-buttom:1, + + border-left:1, + border-right:1, + border-top:1, + border-buttom:1, + + padding-in-left:3, + padding-in-right:3, + padding-in-top:3, + padding-in-buttom:3, + + change-time:200, + program:"THEME_GUI:///WidgetScrolled.prog?lib=ewol", + color:"THEME_COLOR:///WidgetScrolled.json?lib=ewol" +} diff --git a/resources/data/theme/shape/square/WidgetScrolled.vert b/resources/data/theme/shape/square/WidgetScrolled.vert new file mode 100644 index 0000000..4606c18 --- /dev/null +++ b/resources/data/theme/shape/square/WidgetScrolled.vert @@ -0,0 +1,50 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct widgetStateProperty { + int stateOld; + int stateNew; + float transition; +}; + +uniform widgetStateProperty EW_status; + +// Input : +attribute vec2 EW_coord2d; +attribute vec2 EW_widgetPropertyPos; +uniform mat4 EW_MatrixTransformation; +uniform vec4 EW_border; +uniform vec4 EW_background; +uniform vec4 EW_foreground; +uniform vec4 EW_foregroundPressed; + +// output : +varying vec2 v_position; // This will be passed into the fragment shader. +varying vec2 v_propPos; +varying vec4 v_colorTansition; +varying vec4 v_colorBorder; +varying vec4 v_colorBackground; + +void main(void) { + gl_Position = EW_MatrixTransformation * vec4(EW_coord2d, 0.0, 1.0); + // transmit position of the curent element (intermolated ...) + v_position = EW_coord2d; + v_propPos = EW_widgetPropertyPos; + + vec4 colorOld = EW_foreground; + if(EW_status.stateOld == 1) { + colorOld = EW_foregroundPressed; + } + vec4 colorNew = EW_foreground; + if(EW_status.stateNew == 1) { + colorNew = EW_foregroundPressed; + } + + // note : int() is needed for the OpenGL ES platform + v_colorTansition = colorOld * (1.0 - EW_status.transition) + + colorNew * EW_status.transition; + v_colorBorder = EW_border; + v_colorBackground = EW_background; +} diff --git a/resources/data/translate/EN.json b/resources/data/translate/EN.json new file mode 100644 index 0000000..5d5d4a1 --- /dev/null +++ b/resources/data/translate/EN.json @@ -0,0 +1,6 @@ +{ + "FileChooser":"File chooser ...", + "Cancel":"Cancel", + "Validate":"Validate", + "ShowHiddenFiles":"Show hiden files" +} \ No newline at end of file diff --git a/resources/data/translate/FR.json b/resources/data/translate/FR.json new file mode 100644 index 0000000..f0ec5f8 --- /dev/null +++ b/resources/data/translate/FR.json @@ -0,0 +1,6 @@ +{ + "FileChooser":"Sélection d'un fichier ...", + "Cancel":"Annuler", + "Validate":"Valider", + "ShowHiddenFiles":"Afficher les fichiers cachés" +} \ No newline at end of file diff --git a/src/module-info.java b/src/module-info.java index 4e3001e..6ee81df 100644 --- a/src/module-info.java +++ b/src/module-info.java @@ -4,9 +4,12 @@ open module org.atriasoft.ewol { exports org.atriasoft.ewol; + exports org.atriasoft.egami; requires transitive org.atriasoft.gale; requires transitive org.atriasoft.etk; requires transitive org.atriasoft.exml; + requires transitive org.atriasoft.ejson; requires transitive io.scenarium.logger; + requires freetype.jni; } diff --git a/src/org/atriasoft/echrono/Clock.java b/src/org/atriasoft/echrono/Clock.java index 0f1f4af..5defcc4 100644 --- a/src/org/atriasoft/echrono/Clock.java +++ b/src/org/atriasoft/echrono/Clock.java @@ -4,8 +4,8 @@ package org.atriasoft.echrono; * @brief Clock is a compleate virtual clock that is used to virtualize the urrent clock used (can be non real-time, ex:for simulation) */ public class Clock { - public static Time now() { - return new Time(System.nanoTime()); + public static Clock now() { + return new Clock(System.nanoTime()); } private final long data; //!< virtual clock diff --git a/src/org/atriasoft/echrono/Duration.java b/src/org/atriasoft/echrono/Duration.java index c75ef1f..f3d3cab 100644 --- a/src/org/atriasoft/echrono/Duration.java +++ b/src/org/atriasoft/echrono/Duration.java @@ -1,6 +1,10 @@ package org.atriasoft.echrono; public class Duration { + public static Duration milliseconds(final long milli) { + return new Duration(milli / 1000.0); + } + private final long data; // stored in ns public Duration() { @@ -27,6 +31,11 @@ public class Duration { return this.data; } + public boolean isGreaterThan(final Duration sepatateTime) { + // TODO Auto-generated method stub + return this.data - sepatateTime.data > 0; + } + public float toSeconds() { // TODO Auto-generated method stub return (float) (this.data / 1000000000.0); diff --git a/src/org/atriasoft/echrono/Steady.java b/src/org/atriasoft/echrono/Steady.java index 80cc55b..e594435 100644 --- a/src/org/atriasoft/echrono/Steady.java +++ b/src/org/atriasoft/echrono/Steady.java @@ -4,6 +4,10 @@ package org.atriasoft.echrono; * @brief Steady is a Program start time clock */ public class Steady { + public static Steady now() { + return new Steady(System.nanoTime()); + } + private final long data; //!< Monotonic clock since computer start (ns) public Steady() { @@ -29,4 +33,9 @@ public class Steady { public long get() { return this.data; } + + public Duration less(final Steady other) { + // TODO Auto-generated method stub + return new Duration(this.data - other.data); + } } diff --git a/src/org/atriasoft/echrono/Time.java b/src/org/atriasoft/echrono/Time.java index 5a887b5..734edb2 100644 --- a/src/org/atriasoft/echrono/Time.java +++ b/src/org/atriasoft/echrono/Time.java @@ -33,4 +33,8 @@ public class Time { public long get() { return this.data; } + + public Clock toClock() { + return new Clock(this.data); + } } diff --git a/src/org/atriasoft/egami/Image.java b/src/org/atriasoft/egami/Image.java new file mode 100644 index 0000000..661a5ee --- /dev/null +++ b/src/org/atriasoft/egami/Image.java @@ -0,0 +1,170 @@ +package org.atriasoft.egami; + +import org.atriasoft.etk.math.Vector2i; + +public class Image { + private int width; + private int height; + private byte[] buffer; + + public Image(final int width, final int height) { + this.width = width; + this.height = height; + this.buffer = new byte[width * height * 4]; + } + + public Image(final int width, final int height, final byte[] buffer) { + this.buffer = buffer; + this.width = width; + this.height = height; + } + + public void clear() { + for (int xxx = 0; xxx < this.buffer.length; ++xxx) { + this.buffer[xxx] = 0; + } + + } + + public byte getA(final int x, final int y) { + return this.buffer[(y * this.width + x) * 4 + 3]; + } + + public byte getB(final int x, final int y) { + return this.buffer[(y * this.width + x) * 4 + 2]; + } + + public byte[] getBuffer() { + return this.buffer; + } + + public byte getG(final int x, final int y) { + return this.buffer[(y * this.width + x) * 4 + 1]; + } + + public Vector2i getGPUSize() { + /* + if (false) { + // Some GPU does not support not pow2 dimention.... + #if defined(__TARGET_OS__Android) \ + || defined(__TARGET_OS__IOs) + return ivec2(nextP2(m_data->getSize().x()), + nextP2(m_data->getSize().y())); + } + */ + return getSize(); + } + + public int getHeight() { + return this.height; + } + + public byte getR(final int x, final int y) { + return this.buffer[(y * this.width + x) * 4]; + } + + public byte[] GetRaw() { + // TODO Auto-generated method stub + return this.buffer; + } + + public Vector2i getSize() { + return new Vector2i(this.width, this.height); + } + + public int getWidth() { + return this.width; + } + + public void resize(final int width, final int height) { + if (width == this.width && height == this.height) { + // same size == > nothing to do ... + return; + } + final int oldWidth = this.width; + final int oldHeight = this.height; + final byte[] oldBuffer = this.buffer; + this.width = width; + this.height = height; + this.buffer = new byte[this.width * this.height * 4]; + if (this.width <= oldWidth) { + if (this.height < oldHeight) { + // Just remove lines .... + for (int yyy = 0; yyy < this.height; ++yyy) { + for (int xxx = 0; xxx < this.width; ++xxx) { + this.buffer[(yyy * this.width + xxx) * 4] = oldBuffer[(yyy * oldWidth + xxx) * 4]; + this.buffer[(yyy * this.width + xxx) * 4 + 1] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 1]; + this.buffer[(yyy * this.width + xxx) * 4 + 2] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 2]; + this.buffer[(yyy * this.width + xxx) * 4 + 3] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 3]; + } + } + } else { + // just add lines + for (int yyy = 0; yyy < oldHeight; ++yyy) { + for (int xxx = 0; xxx < this.width; ++xxx) { + this.buffer[(yyy * this.width + xxx) * 4] = oldBuffer[(yyy * oldWidth + xxx) * 4]; + this.buffer[(yyy * this.width + xxx) * 4 + 1] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 1]; + this.buffer[(yyy * this.width + xxx) * 4 + 2] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 2]; + this.buffer[(yyy * this.width + xxx) * 4 + 3] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 3]; + } + } + } + } else if (this.height <= oldHeight) { + for (int yyy = 0; yyy < this.height; ++yyy) { + for (int xxx = 0; xxx < oldWidth; ++xxx) { + this.buffer[(yyy * this.width + xxx) * 4] = oldBuffer[(yyy * oldWidth + xxx) * 4]; + this.buffer[(yyy * this.width + xxx) * 4 + 1] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 1]; + this.buffer[(yyy * this.width + xxx) * 4 + 2] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 2]; + this.buffer[(yyy * this.width + xxx) * 4 + 3] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 3]; + } + } + } else { + for (int yyy = 0; yyy < oldHeight; ++yyy) { + for (int xxx = 0; xxx < oldWidth; ++xxx) { + this.buffer[(yyy * this.width + xxx) * 4] = oldBuffer[(yyy * oldWidth + xxx) * 4]; + this.buffer[(yyy * this.width + xxx) * 4 + 1] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 1]; + this.buffer[(yyy * this.width + xxx) * 4 + 2] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 2]; + this.buffer[(yyy * this.width + xxx) * 4 + 3] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 3]; + } + } + } + } + + public void setA(final int x, final int y, final byte value) { + this.buffer[(y * this.width + x) * 4 + 3] = value; + } + + public void setA(final int x, final int y, final float value) { + this.buffer[(y * this.width + x) * 4 + 3] = (byte) (value * 256.0f); + } + + public void setB(final int x, final int y, final byte value) { + this.buffer[(y * this.width + x) * 4 + 2] = value; + } + + public void setB(final int x, final int y, final float value) { + this.buffer[(y * this.width + x) * 4 + 2] = (byte) (value * 256.0f); + } + + public void setG(final int x, final int y, final byte value) { + this.buffer[(y * this.width + x) * 4 + 1] = value; + } + + public void setG(final int x, final int y, final float value) { + this.buffer[(y * this.width + x) * 4 + 1] = (byte) (value * 256.0f); + } + + public void setR(final int x, final int y, final byte value) { + this.buffer[(y * this.width + x) * 4] = value; + } + + public void setR(final int x, final int y, final float value) { + this.buffer[(y * this.width + x) * 4] = (byte) (value * 256.0f); + } + + public void setSize(final int width, final int height) { + this.width = width; + this.height = height; + this.buffer = new byte[width * height * 4]; + } +} diff --git a/src/org/atriasoft/egami/ImageFloat.java b/src/org/atriasoft/egami/ImageFloat.java new file mode 100644 index 0000000..96cc071 --- /dev/null +++ b/src/org/atriasoft/egami/ImageFloat.java @@ -0,0 +1,159 @@ +package org.atriasoft.egami; + +import org.atriasoft.etk.math.Vector2i; + +public class ImageFloat { + private int width; + private int height; + private float[] buffer; + + public ImageFloat(final int width, final int height) { + this.width = width; + this.height = height; + this.buffer = new float[width * height * 4]; + } + + public ImageFloat(final int width, final int height, final float[] buffer) { + this.buffer = buffer; + this.width = width; + this.height = height; + } + + public float getA(final int x, final int y) { + return this.buffer[(y * this.width + x) * 4 + 3]; + } + + public float getB(final int x, final int y) { + return this.buffer[(y * this.width + x) * 4 + 2]; + } + + public float[] getBuffer() { + return this.buffer; + } + + public float getG(final int x, final int y) { + return this.buffer[(y * this.width + x) * 4 + 1]; + } + + public Vector2i getGPUSize() { + /* + if (false) { + // Some GPU does not support not pow2 dimention.... + /* + #if defined(__TARGET_OS__Android) \ + || defined(__TARGET_OS__IOs) + return ivec2(nextP2(m_data->getSize().x()), + nextP2(m_data->getSize().y())); + } + */ + return getSize(); + } + + public int getHeight() { + return this.height; + } + + public float getR(final int x, final int y) { + return this.buffer[(y * this.width + x) * 4]; + } + + public Vector2i getSize() { + return new Vector2i(this.width, this.height); + } + + public int getWidth() { + return this.width; + } + + public void resize(final int width, final int height) { + if (width == this.width && height == this.height) { + // same size == > nothing to do ... + return; + } + final int oldWidth = this.width; + final int oldHeight = this.height; + final float[] oldBuffer = this.buffer; + this.width = width; + this.height = height; + this.buffer = new float[this.width * this.height * 4]; + if (this.width <= oldWidth) { + if (this.height < oldHeight) { + // Just remove lines .... + for (int yyy = 0; yyy < this.height; ++yyy) { + for (int xxx = 0; xxx < this.width; ++xxx) { + this.buffer[(yyy * this.width + xxx) * 4] = oldBuffer[(yyy * oldWidth + xxx) * 4]; + this.buffer[(yyy * this.width + xxx) * 4 + 1] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 1]; + this.buffer[(yyy * this.width + xxx) * 4 + 2] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 2]; + this.buffer[(yyy * this.width + xxx) * 4 + 3] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 3]; + } + } + } else { + // just add lines + for (int yyy = 0; yyy < oldHeight; ++yyy) { + for (int xxx = 0; xxx < this.width; ++xxx) { + this.buffer[(yyy * this.width + xxx) * 4] = oldBuffer[(yyy * oldWidth + xxx) * 4]; + this.buffer[(yyy * this.width + xxx) * 4 + 1] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 1]; + this.buffer[(yyy * this.width + xxx) * 4 + 2] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 2]; + this.buffer[(yyy * this.width + xxx) * 4 + 3] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 3]; + } + } + } + } else if (this.height <= oldHeight) { + for (int yyy = 0; yyy < this.height; ++yyy) { + for (int xxx = 0; xxx < oldWidth; ++xxx) { + this.buffer[(yyy * this.width + xxx) * 4] = oldBuffer[(yyy * oldWidth + xxx) * 4]; + this.buffer[(yyy * this.width + xxx) * 4 + 1] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 1]; + this.buffer[(yyy * this.width + xxx) * 4 + 2] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 2]; + this.buffer[(yyy * this.width + xxx) * 4 + 3] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 3]; + } + } + } else { + for (int yyy = 0; yyy < oldHeight; ++yyy) { + for (int xxx = 0; xxx < oldWidth; ++xxx) { + this.buffer[(yyy * this.width + xxx) * 4] = oldBuffer[(yyy * oldWidth + xxx) * 4]; + this.buffer[(yyy * this.width + xxx) * 4 + 1] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 1]; + this.buffer[(yyy * this.width + xxx) * 4 + 2] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 2]; + this.buffer[(yyy * this.width + xxx) * 4 + 3] = oldBuffer[(yyy * oldWidth + xxx) * 4 + 3]; + } + } + } + } + + public void setA(final int x, final int y, final byte value) { + this.buffer[(y * this.width + x) * 4 + 3] = value / 256.0f; + } + + public void setA(final int x, final int y, final float value) { + this.buffer[(y * this.width + x) * 4 + 3] = value; + } + + public void setB(final int x, final int y, final byte value) { + this.buffer[(y * this.width + x) * 4 + 2] = value / 256.0f; + } + + public void setB(final int x, final int y, final float value) { + this.buffer[(y * this.width + x) * 4 + 2] = value; + } + + public void setG(final int x, final int y, final byte value) { + this.buffer[(y * this.width + x) * 4 + 1] = value / 256.0f; + } + + public void setG(final int x, final int y, final float value) { + this.buffer[(y * this.width + x) * 4 + 1] = value; + } + + public void setR(final int x, final int y, final byte value) { + this.buffer[(y * this.width + x) * 4] = value / 256.0f; + } + + public void setR(final int x, final int y, final float value) { + this.buffer[(y * this.width + x) * 4] = value; + } + + public void setSize(final int width, final int height) { + this.width = width; + this.height = height; + this.buffer = new float[width * height * 4]; + } +} diff --git a/src/org/atriasoft/egami/ImageMono.java b/src/org/atriasoft/egami/ImageMono.java new file mode 100644 index 0000000..73d9c61 --- /dev/null +++ b/src/org/atriasoft/egami/ImageMono.java @@ -0,0 +1,111 @@ +package org.atriasoft.egami; + +import org.atriasoft.etk.math.Vector2i; + +public class ImageMono { + private int width; + private int height; + private byte[] buffer; + + public ImageMono(final int width, final int height) { + this.width = width; + this.height = height; + this.buffer = new byte[width * height]; + } + + public ImageMono(final int width, final int height, final byte[] buffer) { + this.buffer = buffer; + this.width = width; + this.height = height; + } + + public byte get(final int x, final int y) { + return this.buffer[(y * this.width + x)]; + } + + public byte[] getBuffer() { + return this.buffer; + } + + public Vector2i getGPUSize() { + /* + if (false) { + // Some GPU does not support not pow2 dimention.... + #if defined(__TARGET_OS__Android) \ + || defined(__TARGET_OS__IOs) + return ivec2(nextP2(m_data->getSize().x()), + nextP2(m_data->getSize().y())); + } + */ + return getSize(); + } + + public int getHeight() { + return this.height; + } + + public Vector2i getSize() { + return new Vector2i(this.width, this.height); + } + + public int getWidth() { + return this.width; + } + + public void resize(final int width, final int height) { + if (width == this.width && height == this.height) { + // same size == > nothing to do ... + return; + } + final int oldWidth = this.width; + final int oldHeight = this.height; + final byte[] oldBuffer = this.buffer; + this.width = width; + this.height = height; + this.buffer = new byte[this.width * this.height * 4]; + if (this.width <= oldWidth) { + if (this.height < oldHeight) { + // Just remove lines .... + for (int yyy = 0; yyy < this.height; ++yyy) { + for (int xxx = 0; xxx < this.width; ++xxx) { + this.buffer[yyy * this.width + xxx] = oldBuffer[yyy * oldWidth + xxx]; + } + } + } else { + // just add lines + for (int yyy = 0; yyy < oldHeight; ++yyy) { + for (int xxx = 0; xxx < this.width; ++xxx) { + this.buffer[yyy * this.width + xxx] = oldBuffer[yyy * oldWidth + xxx]; + } + } + } + } else if (this.height <= oldHeight) { + for (int yyy = 0; yyy < this.height; ++yyy) { + for (int xxx = 0; xxx < oldWidth; ++xxx) { + this.buffer[yyy * this.width + xxx] = oldBuffer[yyy * oldWidth + xxx]; + } + } + } else { + for (int yyy = 0; yyy < oldHeight; ++yyy) { + for (int xxx = 0; xxx < oldWidth; ++xxx) { + this.buffer[yyy * this.width + xxx] = oldBuffer[yyy * oldWidth + xxx]; + } + } + } + } + + public void set(final int x, final int y, final byte value) { + this.buffer[(y * this.width + x)] = value; + } + + public void set(final int x, final int y, final float value) { + this.buffer[(y * this.width + x)] = (byte) (value * 256.0f); + } + + public void setSize(final int width, final int height) { + this.width = width; + this.height = height; + this.buffer = new byte[width * height]; + } + +} diff --git a/src/org/atriasoft/ewol/DrawProperty.cpp b/src/org/atriasoft/ewol/DrawProperty.cpp deleted file mode 100644 index 43076be..0000000 --- a/src/org/atriasoft/ewol/DrawProperty.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include - -#include -ETK_DECLARE_TYPE(ewol::DrawProperty); - -etk::Stream ewol::operator +(etk::Stream _os, ewol::DrawProperty _obj) { - _os + "{ windowsSize=" + _obj.this.windowsSize + " start=" + _obj.this.origin + " stop=" + (_obj.this.origin+_obj.this.size) + "}"; - return _os; -} - -void ewol::DrawProperty::limit( Vector2f _origin, Vector2f _size) { - this.size += this.origin; - this.origin.setMax(_origin); - this.size.setMin(_origin+_size); - this.size -= this.origin; -} - diff --git a/src/org/atriasoft/ewol/DrawProperty.java b/src/org/atriasoft/ewol/DrawProperty.java index 8a5d8ec..57a074b 100644 --- a/src/org/atriasoft/ewol/DrawProperty.java +++ b/src/org/atriasoft/ewol/DrawProperty.java @@ -1,48 +1,68 @@ +package org.atriasoft.ewol; + +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector2i; + /** @file * @author Edouard DUPIN * @copyright 2011, Edouard DUPIN, all right reserved * @license MPL v2.0 (see license file) */ -#pragma once -#include -#include - -namespace ewol { - /** - * @not_in_doc +public class DrawProperty { + /* + /-. windowsSize + *--------------------------------------------------* + | | + | | + | size | + | / | + | o-------------------o | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | o-------------------o | + | / | + | origin | + | | + *--------------------------------------------------* + / + (0,0) */ - class DrawProperty{ - /* - /-. this.windowsSize - *--------------------------------------------------* - | g | - | | - | this.size | - | / | - | o-------------------o | - | | | | - | | | | - | | | | - | | | | - | | | | - | | | | - | | | | - | | | | - | o-------------------o | - | / | - | this.origin | - | | - *--------------------------------------------------* - / - (0,0) - */ - public : - Vector2i this.windowsSize; //!< Windows compleate size - Vector2i this.origin; //!< Windows clipping upper widget (can not be <0) - Vector2i this.size; //!< Windows clipping upper widget (can not be <0 and >this.windowsSize) - void limit( Vector2f _origin, Vector2f _size); - }; - etk::Stream operator +(etk::Stream _os, ewol::DrawProperty _obj); + public Vector2i windowsSize = new Vector2i(0, 0); //!< Windows complete size + public Vector2i origin = new Vector2i(0, 0); //!< Windows clipping upper widget (can not be <0) + public Vector2i size = new Vector2i(0, 0); //!< Windows clipping upper widget (can not be <0 and >this.windowsSize) + public DrawProperty() { + + } + + public DrawProperty(final Vector2i windowsSize, final Vector2i origin, final Vector2i size) { + super(); + this.windowsSize = windowsSize; + this.origin = origin; + this.size = size; + } + + @Override + public DrawProperty clone() { + return new DrawProperty(this.windowsSize, this.origin, this.size); + } + + public void limit(final Vector2f _origin, final Vector2f _size) { + this.size.add(this.origin); + this.origin.setMax((int) _origin.x, (int) _origin.y); + this.size.setMin((int) (_origin.x + _size.x), (int) (_origin.y + _size.y)); + this.size.less(this.origin); + } + + @Override + public String toString() { + return "DrawProperty [windowsSize=" + this.windowsSize + ", start=" + this.origin + ", stop=" + this.origin.addNew(this.size) + "]"; + } } diff --git a/src/org/atriasoft/ewol/ewol.java b/src/org/atriasoft/ewol/Ewol.java similarity index 89% rename from src/org/atriasoft/ewol/ewol.java rename to src/org/atriasoft/ewol/Ewol.java index a14a0a6..2882e6f 100644 --- a/src/org/atriasoft/ewol/ewol.java +++ b/src/org/atriasoft/ewol/Ewol.java @@ -1,4 +1,6 @@ +package org.atriasoft.ewol; +import org.atriasoft.etk.Uri; /** @file * @author Edouard DUPIN * @copyright 2011, Edouard DUPIN, all right reserved @@ -7,7 +9,11 @@ import org.atriasoft.ewol.context.EwolApplication; import org.atriasoft.ewol.context.EwolContext; -class Ewol { +public class Ewol { + static { + Uri.addLibrary("ewol", Ewol.class); + } + public static EwolContext getContext() { // TODO Auto-generated method stub return EwolContext.getContext(); diff --git a/src/org/atriasoft/ewol/Gravity.java b/src/org/atriasoft/ewol/Gravity.java index 23ddee8..1420a1e 100644 --- a/src/org/atriasoft/ewol/Gravity.java +++ b/src/org/atriasoft/ewol/Gravity.java @@ -5,6 +5,8 @@ */ package org.atriasoft.ewol; +import org.atriasoft.etk.math.Vector2f; + /** * @brief Gravity of the widget property */ @@ -17,5 +19,29 @@ public enum Gravity { topRight, //!< gravity is in top-right topLeft, //!< gravity is in top-left buttomRight, //!< gravity is in buttom-right - buttomLeft, //!< gravity is in buttom-left + buttomLeft; //!< gravity is in buttom-left + + Vector2f gravityGenerateDelta(final Gravity _gravity, final Vector2f _deltas) { + final Vector2f out = new Vector2f(0.0f, 0.0f); + if (_deltas.x > 0.0001f) { + if (_gravity == left || _gravity == buttomLeft || _gravity == topLeft) { + // nothing to do + } else if (_gravity == right || _gravity == buttomRight || _gravity == topRight) { + out.x = (int) (_deltas.x); + } else { + out.x = (int) (_deltas.x * 0.5f); + } + } + if (_deltas.y > 0.0001f) { + if (_gravity == buttom || _gravity == buttomLeft || _gravity == buttomRight) { + // nothing to do + } else if (_gravity == top || _gravity == topRight || _gravity == topLeft) { + out.y = (int) (_deltas.y); + } else { + out.y = (int) (_deltas.y * 0.5f); + } + } + return out; + } + } diff --git a/src/org/atriasoft/ewol/Padding.cpp b/src/org/atriasoft/ewol/Padding.cpp deleted file mode 100644 index 66e1af5..0000000 --- a/src/org/atriasoft/ewol/Padding.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include -ETK_DECLARE_TYPE(ewol::Padding); - -ewol::Padding::Padding() { - // nothing to do... -} - -ewol::Padding::Padding(float _xl, float _yt, float _xr, float _yb) { - setValue(_xl, _yt, _xr, _yb); -} - -void ewol::Padding::setValue(float _xl, float _yt, float _xr, float _yb) { - this.value[0] = _xl; - this.value[1] = _yt; - this.value[2] = _xr; - this.value[3] = _yb; -} - -float ewol::Padding::x() { - return this.value[0] + this.value[2]; -} - -float ewol::Padding::y() { - return this.value[1] + this.value[3]; -} - -float ewol::Padding::xLeft() { - return this.value[0]; -} - -void ewol::Padding::setXLeft(float _val) { - this.value[0] = _val; -} - -float ewol::Padding::xRight() { - return this.value[2]; -} - -void ewol::Padding::setXRight(float _val) { - this.value[2] = _val; -} - -float ewol::Padding::yTop() { - return this.value[1]; -} - -void ewol::Padding::setYTop(float _val) { - this.value[1] = _val; -} - -float ewol::Padding::yButtom() { - return this.value[3]; -} - -void ewol::Padding::setYButtom(float _val) { - this.value[3] = _val; -} - -ewol::Padding ewol::Padding::operator+=( Padding _v) { - this.value[0] += _v.this.value[0]; - this.value[1] += _v.this.value[1]; - this.value[2] += _v.this.value[2]; - this.value[3] += _v.this.value[3]; - return *this; -} - -ewol::Padding ewol::Padding::operator+( Padding _v) { - return Padding(this.value[0] + _v.this.value[0], - this.value[1] + _v.this.value[1], - this.value[2] + _v.this.value[2], - this.value[3] + _v.this.value[3]); -} - -etk::Stream ewol::operator +(etk::Stream _os, ewol::Padding _obj) { - _os + "{"; - _os + _obj.xLeft(); - _os + ","; - _os + _obj.yTop(); - _os + ","; - _os + _obj.xRight(); - _os + ","; - _os + _obj.yButtom(); - _os + "}"; - return _os; -} - diff --git a/src/org/atriasoft/ewol/Padding.java b/src/org/atriasoft/ewol/Padding.java index a43057c..94239f8 100644 --- a/src/org/atriasoft/ewol/Padding.java +++ b/src/org/atriasoft/ewol/Padding.java @@ -3,41 +3,130 @@ * @copyright 2011, Edouard DUPIN, all right reserved * @license MPL v2.0 (see license file) */ -#pragma once -#include -#include - -namespace ewol { +/** + * @breif Simple class to abstarct the padding porperty. + */ +public class Padding { + private float xLeft; + private float yTop; + private float xRight; + private float yBottom; //!< this represent the 4 padding value Left top right buttom (like css) + + public Padding() { + setValue(); + } + + public Padding(final float _xLeft) { + setValue(_xLeft); + } + + public Padding(final float _xLeft, final float _yt) { + setValue(_xLeft, _yt); + } + + public Padding(final float _xLeft, final float _yt, final float _xr) { + setValue(_xLeft, _yt, _xr); + } + + public Padding(final float _xLeft, final float _yt, final float _xr, final float _yb) { + setValue(_xLeft, _yt, _xr, _yb); + } + /** - * @breif Simple class to abstarct the padding porperty. - */ - class Padding { - private: - float this.value[4]; //!< this represent the 4 padding value Left top right buttom (like css) - public: - Padding(); - Padding(float _xl, float _yt=0.0f, float _xr=0.0f, float _yb=0.0f); - void setValue(float _xl, float _yt=0.0f, float _xr=0.0f, float _yb=0.0f); - float x() ; - float y() ; - float xLeft() ; - void setXLeft(float _val); - float xRight() ; - void setXRight(float _val); - float yTop() ; - void setYTop(float _val); - float yButtom() ; - void setYButtom(float _val); - /** * @brief Add a vector to this one * @param _v The vector to add to this one */ - Padding operator+=( Padding _v); - //! @previous - Padding operator+( Padding _v); - - }; - etk::Stream operator +(etk::Stream _os, ewol::Padding _obj); -}; - + public Padding add(final Padding _v) { + this.xLeft += _v.xLeft; + this.yTop += _v.yTop; + this.xRight += _v.xRight; + this.yBottom += _v.yBottom; + return this; + } + + //! @previous + public Padding addNew(final Padding _v) { + return new Padding(this.xLeft + _v.xLeft, this.yTop + _v.yTop, this.xRight + _v.xRight, this.yBottom + _v.yBottom); + } + + public void setValue() { + this.xLeft = 0; + this.yTop = 0; + this.xRight = 0; + this.yBottom = 0; + } + + public void setValue(final float _xLeft) { + this.xLeft = _xLeft; + this.yTop = 0; + this.xRight = 0; + this.yBottom = 0; + } + + public void setValue(final float _xLeft, final float _yt) { + this.xLeft = _xLeft; + this.yTop = _yt; + this.xRight = 0; + this.yBottom = 0; + } + + public void setValue(final float _xLeft, final float _yt, final float _xr) { + this.xLeft = _xLeft; + this.yTop = _yt; + this.xRight = _xr; + this.yBottom = 0; + } + + public void setValue(final float _xLeft, final float _yt, final float _xr, final float _yb) { + this.xLeft = _xLeft; + this.yTop = _yt; + this.xRight = _xr; + this.yBottom = _yb; + } + + public void setXLeft(final float _val) { + this.xLeft = _val; + } + + public void setXRight(final float _val) { + this.xRight = _val; + } + + public void setYButtom(final float _val) { + this.yBottom = _val; + } + + public void setYTop(final float _val) { + this.yTop = _val; + } + + @Override + public String toString() { + return "{" + xLeft() + "," + yTop() + "," + xRight() + "," + yButtom() + "}"; + } + + public float x() { + return this.xLeft + this.xRight; + } + + public float xLeft() { + return this.xLeft; + } + + public float xRight() { + return this.xRight; + } + + public float y() { + return this.yTop + this.yBottom; + } + + public float yButtom() { + return this.yBottom; + } + + public float yTop() { + return this.yTop; + } +} diff --git a/src/org/atriasoft/ewol/compositing/Area.cpp b/src/org/atriasoft/ewol/compositing/Area.cpp deleted file mode 100644 index 276c065..0000000 --- a/src/org/atriasoft/ewol/compositing/Area.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include -#include -ETK_DECLARE_TYPE(ewol::compositing::Area); - -// VBO table property: - int ewol::compositing::Area::this.vboIdCoord(0); - int ewol::compositing::Area::this.vboIdCoordText(1); - int ewol::compositing::Area::this.vboIdColor(2); -#define NB_VBO (3) - -ewol::compositing::Area::Area( Vector2i _size) : - this.position(0.0, 0.0, 0.0), - this.color(etk::color::white), - this.GLprogram(null), - this.GLPosition(-1), - this.GLMatrix(-1), - this.GLColor(-1), - this.GLtexture(-1), - this.GLtexID(-1), - this.resource(null) { - this.resource = ewol::resource::Texture::create(); - this.resource.setImageSize(_size); - this.resource.flush(); - // Create the VBO: - this.VBO = gale::resource::VirtualBufferObject::create(NB_VBO); - if (this.VBO == null) { - Log.error("can not instanciate VBO ..."); - return; - } - // TO facilitate some debugs we add a name of the VBO: - this.VBO.setName("[VBO] of ewol::compositing::Area"); - loadProgram(); -} - -ewol::compositing::Area::~Area() { - -} - -void ewol::compositing::Area::loadProgram() { - // get the shader resource : - this.GLPosition = 0; - this.GLprogram = gale::resource::Program::create(String("DATA:///textured3D.prog?lib=ewol")); - if (this.GLprogram != null) { - this.GLPosition = this.GLprogram.getAttribute("EW_coord3d"); - this.GLColor = this.GLprogram.getAttribute("EW_color"); - this.GLtexture = this.GLprogram.getAttribute("EW_texture2d"); - this.GLMatrix = this.GLprogram.getUniform("EW_MatrixTransformation"); - this.GLtexID = this.GLprogram.getUniform("EW_texID"); - } -} - -void ewol::compositing::Area::draw(boolean _disableDepthTest) { - if (this.VBO.bufferSize(this.vboIdCoord) <= 0) { - //Log.warning("Nothink to draw..."); - return; - } - if (this.resource == null) { - // this is a normale case ... the user can choice to have no image ... - return; - } - if (this.GLprogram == null) { - Log.error("No shader ..."); - return; - } - // set Matrix : translation/positionMatrix - mat4 tmpMatrix = gale::openGL::getMatrix()*this.matrixApply; - this.GLprogram.use(); - this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); - // TextureID - this.GLprogram.setTexture0(this.GLtexID, this.resource.getRendererId()); - // position: - this.GLprogram.sendAttributePointer(this.GLPosition, this.VBO, this.vboIdCoord); - // Texture: - this.GLprogram.sendAttributePointer(this.GLtexture, this.VBO, this.vboIdColor); - // color: - this.GLprogram.sendAttributePointer(this.GLColor, this.VBO, this.vboIdCoordText); - // Request the draw od the elements : - gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, this.VBO.bufferSize(this.vboIdCoord)); - this.GLprogram.unUse(); -} - -void ewol::compositing::Area::clear() { - // call upper class - ewol::Compositing::clear(); - // reset all VBOs: - this.VBO.clear(); - // reset temporal variables : - this.position = Vector3f(0.0, 0.0, 0.0); -} - -void ewol::compositing::Area::print( Vector2i _size) { - Vector3f point(0,0,0); - Vector2f tex(0,1); - point.setX(this.position.x()); - point.setY(this.position.y()); - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - this.VBO.pushOnBuffer(this.vboIdCoordText, tex); - - tex.setValue(1,1); - point.setX(this.position.x() + _size.x()); - point.setY(this.position.y()); - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - this.VBO.pushOnBuffer(this.vboIdCoordText, tex); - - tex.setValue(1,0); - point.setX(this.position.x() + _size.x()); - point.setY(this.position.y() + _size.y()); - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - this.VBO.pushOnBuffer(this.vboIdCoordText, tex); - - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - this.VBO.pushOnBuffer(this.vboIdCoordText, tex); - - tex.setValue(0,0); - point.setX(this.position.x()); - point.setY(this.position.y() + _size.y()); - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - this.VBO.pushOnBuffer(this.vboIdCoordText, tex); - - tex.setValue(0,1); - point.setX(this.position.x()); - point.setY(this.position.y()); - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - this.VBO.pushOnBuffer(this.vboIdCoordText, tex); - - this.VBO.flush(); -} - - diff --git a/src/org/atriasoft/ewol/compositing/Area.java b/src/org/atriasoft/ewol/compositing/Area.java deleted file mode 100644 index ec97617..0000000 --- a/src/org/atriasoft/ewol/compositing/Area.java +++ /dev/null @@ -1,101 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace ewol { - namespace compositing { - class Area : public ewol::Compositing { - private: - Vector3f this.position; //!< The current position to draw - etk::Color this.color; //!< The text foreground color - private: - ememory::Ptr this.GLprogram; //!< pointer on the opengl display program - int this.GLPosition; //!< openGL id on the element (vertex buffer) - int this.GLMatrix; //!< openGL id on the element (transformation matrix) - int this.GLColor; //!< openGL id on the element (color buffer) - int this.GLtexture; //!< openGL id on the element (Texture position) - int this.GLtexID; //!< openGL id on the element (texture ID) - private: - ememory::Ptr this.resource; //!< texture resources - protected: - static int this.vboIdCoord; - static int this.vboIdCoordText; - static int this.vboIdColor; - ememory::Ptr this.VBO; - private: - /** - * @brief load the openGL program and get all the ID needed - */ - void loadProgram(); - public: - /** - * @brief generic ructor - * @param[in] _size Basic size of the area. - */ - Area( Vector2i _size); - /** - * @brief generic destructor - */ - ~Area(); - public: - /** - * @brief draw All the refistered text in the current element on openGL - */ - void draw(boolean _disableDepthTest=true); - /** - * @brief clear alll the registered element in the current element - */ - void clear(); - /** - * @brief get the current display position (sometime needed in the gui control) - * @return the current position. - */ - Vector3f getPos() { - return this.position; - }; - /** - * @brief set position for the next text writen - * @param[in] _pos Position of the text (in 3D) - */ - void setPos( Vector3f _pos) { - this.position = _pos; - }; - void setPos( Vector2f _pos) { - setPos(Vector3f(_pos.x(),_pos.y(),0)); - }; - /** - * @brief set relative position for the next text writen - * @param[in] _pos ofset apply of the text (in 3D) - */ - void setRelPos( Vector3f _pos) { - this.position += _pos; - }; - void setRelPos( Vector2f _pos) { - setRelPos(Vector3f(_pos.x(),_pos.y(),0)); - }; - /** - * @brief add a compleate of the image to display with the requested size - * @param[in] _size size of the output image - */ - void print( Vector2i _size); - - egami::Image get() { - return this.resource.get(); - }; - void flush() { - this.resource.flush(); - }; - }; - }; -}; diff --git a/src/org/atriasoft/ewol/compositing/Compositing.cpp b/src/org/atriasoft/ewol/compositing/Compositing.cpp deleted file mode 100644 index 26f620f..0000000 --- a/src/org/atriasoft/ewol/compositing/Compositing.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include - -#include -#include -#include -ETK_DECLARE_TYPE(ewol::Compositing); - -ewol::Compositing::Compositing() { - // nothing to do -} - - -void ewol::Compositing::resetMatrix() { - this.matrixApply.identity(); -} - - -void ewol::Compositing::translate( Vector3f _vect) { - this.matrixApply *= etk::matTranslate(_vect); -} - - -void ewol::Compositing::rotate( Vector3f _vect, float _angle) { - this.matrixApply *= etk::matRotate(_vect, _angle); -} - - -void ewol::Compositing::scale( Vector3f _vect) { - this.matrixApply *= etk::matScale(_vect); -} - - -void ewol::Compositing::clear() { - this.matrixApply.identity(); -} - - -void ewol::Compositing::setMatrix( mat4 _mat) { - this.matrixApply = _mat; -} diff --git a/src/org/atriasoft/ewol/compositing/Compositing.java b/src/org/atriasoft/ewol/compositing/Compositing.java index c2a3dfa..f999a25 100644 --- a/src/org/atriasoft/ewol/compositing/Compositing.java +++ b/src/org/atriasoft/ewol/compositing/Compositing.java @@ -1,58 +1,67 @@ +import org.atriasoft.etk.math.Matrix4f; +import org.atriasoft.etk.math.Vector3f; + /** @file * @author Edouard DUPIN * @copyright 2011, Edouard DUPIN, all right reserved * @license MPL v2.0 (see license file) */ -#pragma once -#include -#include -#include - -namespace ewol { - class Compositing { - protected: - mat4 this.matrixApply; - public: - /** - * @brief generic ructor - */ - Compositing(); - /** - * @brief Generic destructor - */ - ~Compositing() = default; - /** - * @brief Virtal pure function that request the draw of all openGl elements - */ - void draw(boolean _disableDepthTest = true) = 0; - /** - * @brief clear alll tre registered element in the current element - */ - void clear(); - /** - * @brief reset to the eye matrix the openGL mouving system - */ - void resetMatrix(); - /** - * @brief translate the current display of this element - * @param[in] _vect The translation vector to apply at the transformation matrix - */ - void translate( Vector3f _vect); - /** - * @brief rotate the curent display of this element - * @param[in] _vect The rotation vector to apply at the transformation matrix - */ - void rotate( Vector3f _vect, float _angle); - /** - * @brief scale the current diaplsy of this element - * @param[in] _vect The scaling vector to apply at the transformation matrix - */ - void scale( Vector3f _vect); - /** - * @brief set the transformation matrix - * @param[in] _mat The new matrix. - */ - void setMatrix( mat4 _mat); - }; -}; +public abstract class Compositing { + protected Matrix4f matrixApply = Matrix4f.identity(); + + /** + * @brief clear alll tre registered element in the current element + */ + public void clear() { + this.matrixApply.setIdentity(); + } + + /** + * @brief Virtal pure function that request the draw of all openGl elements + */ + public void draw() { + draw(true); + } + + public abstract void draw(final boolean _disableDepthTest); + + /** + * @brief reset to the eye matrix the openGL mouving system + */ + public void resetMatrix() { + this.matrixApply.setIdentity(); + } + + /** + * @brief rotate the curent display of this element + * @param[in] _vect The rotation vector to apply at the transformation matrix + */ + public void rotate(final Vector3f _vect, final float _angle) { + this.matrixApply.multiply(Matrix4f.createMatrixRotate(_vect, _angle)); + } + + /** + * @brief scale the current diaplsy of this element + * @param[in] _vect The scaling vector to apply at the transformation matrix + */ + public void scale(final Vector3f _vect) { + this.matrixApply.multiply(Matrix4f.createMatrixScale(_vect)); + } + + /** + * @brief set the transformation matrix + * @param[in] _mat The new matrix. + */ + public void setMatrix(final Matrix4f _mat) { + this.matrixApply = _mat; + } + + /** + * @brief translate the current display of this element + * @param[in] _vect The translation vector to apply at the transformation matrix + */ + public void translate(final Vector3f _vect) { + this.matrixApply.multiply(Matrix4f.createMatrixTranslate(_vect)); + } +} diff --git a/src/org/atriasoft/ewol/compositing/CompositingImage.java b/src/org/atriasoft/ewol/compositing/CompositingImage.java new file mode 100644 index 0000000..c63ad00 --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/CompositingImage.java @@ -0,0 +1,498 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package org.atriasoft.ewol.compositing; + +import org.atriasoft.egami.Image; +import org.atriasoft.etk.Color; +import org.atriasoft.etk.Uri; +import org.atriasoft.etk.math.Matrix4f; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector2i; +import org.atriasoft.etk.math.Vector3f; +import org.atriasoft.ewol.internal.Log; +import org.atriasoft.ewol.resource.ResourceTexture2; +import org.atriasoft.ewol.resource.ResourceTextureFile; +import org.atriasoft.gale.backend3d.OpenGL; +import org.atriasoft.gale.backend3d.OpenGL.RenderMode; +import org.atriasoft.gale.resource.ResourceProgram; +import org.atriasoft.gale.resource.ResourceVirtualBufferObject; + +class CompositingImage extends Compositing { + public static final int sizeAuto = 0; + // VBO table property: + public static final int vboIdCoord = 0; + public static final int vboIdCoordTex = 1; + public static final int vboIdColor = 2; + public static final int NB_VBO = 3; + private Uri filename; + private Vector2i requestSize = new Vector2i(2, 2); + private Vector3f position = new Vector3f(0, 0, 0); //!< The current position to draw + private Vector3f clippingPosStart = new Vector3f(0, 0, 0); //!< Clipping start position + private Vector3f clippingPosStop = new Vector3f(0, 0, 0); //!< Clipping stop position + private boolean clippingEnable = true; //!< true if the clipping must be activated + + private Color color = new Color(1, 1, 1); //!< The text foreground color + private float angle = 0; //!< Angle to set at the axes + private ResourceProgram GLprogram = null; //!< pointer on the opengl display program + private int GLPosition = -1; //!< openGL id on the element (vertex buffer) + private int GLMatrix = -1; //!< openGL id on the element (transformation matrix) + private int GLColor = -1; //!< openGL id on the element (color buffer) + private int GLtexture = -1; //!< openGL id on the element (Texture position) + private int GLtexID = -1; //!< openGL id on the element (texture ID) + + private ResourceTextureFile resource = null; //!< texture resources + private ResourceTexture2 resourceImage = null; //!< texture resources + private ResourceVirtualBufferObject VBO = null; + + /** + * @brief generic ructor + * @param[in] _uri URI of the file that might be loaded + * @param[in] _df enable distance field mode + * @param[in] _size for the image when Verctorial image loading is requested + */ + public CompositingImage() { + this(new Uri(""), sizeAuto); + } + + public CompositingImage(final Uri _uri, final int _size) { + this.filename = _uri; + // Create the VBO: + this.VBO = ResourceVirtualBufferObject.create(NB_VBO); + if (this.VBO == null) { + Log.error("can not instanciate VBO ..."); + return; + } + // TO facilitate some debugs we add a name of the VBO: + this.VBO.setName("[VBO] of ewol::compositing::Image"); + setSource(_uri, _size); + loadProgram(); + } + + /** + * @brief clear alll tre registered element in the current element + */ + @Override + public void clear() { + // call upper class + super.clear(); + // reset Buffer : + this.VBO.clear(); + // reset temporal variables : + this.position = new Vector3f(0, 0, 0); + this.clippingPosStart = new Vector3f(0, 0, 0); + this.clippingPosStop = new Vector3f(0, 0, 0); + this.clippingEnable = false; + this.color = Color.WHITE; + this.angle = 0; + } + + /** + * @brief draw All the refistered text in the current element on openGL + * @param[in] _disableDepthTest disable the Depth test for display + */ + @Override + public void draw(final boolean _disableDepthTest) { + /* + if (this.VBO.bufferSize(this.vboIdCoord) <= 0) { + //Log.warning("Nothink to draw..."); + return; + } + */ + if (this.resource == null && this.resourceImage == null) { + // this is a normale case ... the user can choice to have no image ... + return; + } + if (this.GLprogram == null) { + Log.error("No shader ..."); + return; + } + //Log.warning("Display image : " + this.VBO.bufferSize(this.vboIdCoord)); + if (_disableDepthTest == true) { + OpenGL.disable(OpenGL.Flag.flag_depthTest); + } else { + OpenGL.enable(OpenGL.Flag.flag_depthTest); + } + // set Matrix : translation/positionMatrix + final Matrix4f tmpMatrix = OpenGL.getMatrix().multiplyNew(this.matrixApply); + this.GLprogram.use(); + this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); + // TextureID + if (this.resourceImage != null) { + this.resourceImage.bindForRendering(0); + } else if (this.resource != null) { + this.resource.bindForRendering(0); + } else { + Log.error("FONT type error Request normal and display distance field ..."); + } + // position: + this.GLprogram.sendAttributePointer(this.GLPosition, this.VBO, CompositingImage.vboIdCoord); + // Texture: + this.GLprogram.sendAttributePointer(this.GLtexture, this.VBO, CompositingImage.vboIdCoordTex); + // color: + this.GLprogram.sendAttributePointer(this.GLColor, this.VBO, CompositingImage.vboIdColor); + // Request the draw of the elements: + OpenGL.drawArrays(RenderMode.triangle, 0, this.VBO.bufferSize(CompositingImage.vboIdCoord)); + + this.GLprogram.unUse(); + } + + /** + * @brief get the current display position (sometime needed in the gui control) + * @return the current position. + */ + public Vector3f getPos() { + return this.position; + } + + /** + * @brief get the source image registered size in the file (<0 when multiple size image) + * @return tre image registered size + */ + public Vector2i getRealSize() { + if (this.resource == null && this.resourceImage == null) { + return new Vector2i(0, 0); + } + if (this.resource != null) { + return this.resource.getRealSize(); + } + if (this.resourceImage != null) { + return this.resourceImage.getUsableSize(); + } + return new Vector2i(0, 0); + }; + + /** + * @brief Sometimes the user declare an image but not allocate the ressources all the time, this is to know it .. + * @return the validity od the resources. + */ + public boolean hasSources() { + return this.resource != null; + }; + + /** + * @brief load the openGL program and get all the ID needed + */ + private void loadProgram() { + // get the shader resource: + this.GLPosition = 0; + this.GLprogram = ResourceProgram.create(new Uri("DATA", "textured3D.vert", "ewol"), new Uri("DATA", "textured3D.frag", "ewol")); + if (this.GLprogram != null) { + this.GLPosition = this.GLprogram.getAttribute("EW_coord3d"); + this.GLColor = this.GLprogram.getAttribute("EW_color"); + this.GLtexture = this.GLprogram.getAttribute("EW_texture2d"); + this.GLMatrix = this.GLprogram.getUniform("EW_MatrixTransformation"); + this.GLtexID = this.GLprogram.getUniform("EW_texID"); + } + }; + + public void print(final Vector2f _size) { + printPart(_size, new Vector2f(0, 0), new Vector2f(1, 1)); + } + + /** + * @brief add a compleate of the image to display with the requested size + * @param[in] _size size of the output image + */ + public void print(final Vector2i _size) { + print(new Vector2f(_size.x, _size.y)); + }; + + /** + * @brief add a part of the image to display with the requested size + * @param[in] _size size of the output image + * @param[in] _sourcePosStart Start position in the image [0..1] (can be bigger but this repeate the image). + * @param[in] _sourcePosStop Stop position in the image [0..1] (can be bigger but this repeate the image). + */ + public void printPart(final Vector2f _size, final Vector2f _sourcePosStart, final Vector2f _sourcePosStop) { + if (this.resource == null) { + return; + } + final Vector2f openGLSize = new Vector2f(this.resource.getOpenGlSize().x, this.resource.getOpenGlSize().y); + final Vector2i usefullSize = this.resource.getUsableSize(); + final Vector2f ratio = new Vector2f(usefullSize.x / openGLSize.x, usefullSize.y / openGLSize.y); + final Vector2f sourcePosStart = _sourcePosStart.multiplyNew(ratio); + final Vector2f sourcePosStop = _sourcePosStop.multiplyNew(ratio); + Log.verbose(" openGLSize=" + openGLSize + " usableSize=" + usefullSize + " start=" + sourcePosStart + " stop=" + sourcePosStop); + + if (this.angle == 0.0f) { + Vector3f point = this.position.clone(); + + final Vector3f[] coords = new Vector3f[6]; + final Vector2f[] coordsTex = new Vector2f[6]; + final Color[] colors = new Color[6]; + int indexElem = 0; + + Vector2f tex = new Vector2f(sourcePosStart.x, sourcePosStop.y); + coords[indexElem] = point; + coordsTex[indexElem] = tex; + colors[indexElem] = this.color; + indexElem++; + + tex = new Vector2f(sourcePosStop.x, sourcePosStop.y); + point = point.clone(); + point.setX(this.position.x + _size.x); + point.setY(this.position.y); + coords[indexElem] = point; + coordsTex[indexElem] = tex; + colors[indexElem] = this.color; + indexElem++; + + tex = new Vector2f(sourcePosStop.x, sourcePosStart.y); + point = point.clone(); + point.setX(this.position.x + _size.x); + point.setY(this.position.y + _size.y); + coords[indexElem] = point; + coordsTex[indexElem] = tex; + colors[indexElem] = this.color; + indexElem++; + + coords[indexElem] = point; + coordsTex[indexElem] = tex; + colors[indexElem] = this.color; + indexElem++; + + tex = new Vector2f(sourcePosStart.x, sourcePosStart.y); + point = point.clone(); + point.setX(this.position.x); + point.setY(this.position.y + _size.y); + coords[indexElem] = point; + coordsTex[indexElem] = tex; + colors[indexElem] = this.color; + indexElem++; + + tex = new Vector2f(sourcePosStart.x, sourcePosStop.y); + point = point.clone(); + point.setX(this.position.x); + point.setY(this.position.y); + coords[indexElem] = point; + coordsTex[indexElem] = tex; + colors[indexElem] = this.color; + indexElem++; + + this.VBO.setVboData(CompositingImage.vboIdCoord, coords); + this.VBO.setVboData(CompositingImage.vboIdCoordTex, coordsTex); + this.VBO.setVboData(CompositingImage.vboIdColor, colors); + + this.VBO.flush(); + return; + } + + final Vector3f center = this.position.addNew(new Vector3f(_size.x, _size.y, 0)).divide(2.0f); + + final Vector3f limitedSize = new Vector3f(_size.x * 0.5f, _size.y * 0.5f, 0.0f); + + Vector3f point = new Vector3f(0, 0, 0); + + Vector2f tex = new Vector2f(_sourcePosStart.x, sourcePosStop.y); + + final Vector3f[] coords = new Vector3f[6]; + final Vector2f[] coordsTex = new Vector2f[6]; + final Color[] colors = new Color[6]; + int indexElem = 0; + + point = new Vector3f(-limitedSize.x, -limitedSize.y, 0); + point = point.rotateNew(new Vector3f(0, 0, 1), this.angle).add(center); + coords[indexElem] = point; + coordsTex[indexElem] = tex; + colors[indexElem] = this.color; + indexElem++; + + tex = new Vector2f(sourcePosStop.x, sourcePosStop.y); + point = new Vector3f(limitedSize.x, -limitedSize.y, 0); + point = point.rotateNew(new Vector3f(0, 0, 1), this.angle).add(center); + coords[indexElem] = point; + coordsTex[indexElem] = tex; + colors[indexElem] = this.color; + indexElem++; + + tex = new Vector2f(sourcePosStop.x, sourcePosStart.y); + point = new Vector3f(limitedSize.x, limitedSize.y, 0); + point = point.rotateNew(new Vector3f(0, 0, 1), this.angle).add(center); + coords[indexElem] = point; + coordsTex[indexElem] = tex; + colors[indexElem] = this.color; + indexElem++; + + coords[indexElem] = point; + coordsTex[indexElem] = tex; + colors[indexElem] = this.color; + indexElem++; + + tex = new Vector2f(sourcePosStart.x, sourcePosStart.y); + point = new Vector3f(-limitedSize.x, limitedSize.y, 0); + point = point.rotateNew(new Vector3f(0, 0, 1), this.angle).add(center); + coords[indexElem] = point; + coordsTex[indexElem] = tex; + colors[indexElem] = this.color; + indexElem++; + + tex = new Vector2f(sourcePosStart.x, sourcePosStop.y); + point = new Vector3f(-limitedSize.x, -limitedSize.y, 0); + point = point.rotateNew(new Vector3f(0, 0, 1), this.angle).add(center); + coords[indexElem] = point; + coordsTex[indexElem] = tex; + colors[indexElem] = this.color; + indexElem++; + + this.VBO.setVboData(CompositingImage.vboIdCoord, coords); + this.VBO.setVboData(CompositingImage.vboIdCoordTex, coordsTex); + this.VBO.setVboData(CompositingImage.vboIdColor, colors); + + this.VBO.flush(); + }; + + /** + * @brief set a unique rotation of this element (not set in the rotate Generic system) + * @param[in] _angle Angle to set in radiant. + */ + public void setAngle(final float _angleRad) { + this.angle = _angleRad; + }; + + void setClipping(final Vector2f _pos, final Vector2f _posEnd) { + setClipping(new Vector3f(_pos.x, _pos.y, 0), new Vector3f(_posEnd.x, _posEnd.y, 0)); + }; + + /** + * @brief Request a clipping area for the text (next draw only) + * @param[in] _pos Start position of the clipping + * @param[in] _posEnd End position of the clipping + */ + public void setClipping(final Vector3f _pos, final Vector3f _posEnd) { + // note the internal system all time request to have a bounding all time in the same order + if (_pos.x <= _posEnd.x) { + this.clippingPosStart.setX(_pos.x); + this.clippingPosStop.setX(_posEnd.x); + } else { + this.clippingPosStart.setX(_posEnd.x); + this.clippingPosStop.setX(_pos.x); + } + if (_pos.y <= _posEnd.y) { + this.clippingPosStart.setY(_pos.y); + this.clippingPosStop.setY(_posEnd.y); + } else { + this.clippingPosStart.setY(_posEnd.y); + this.clippingPosStop.setY(_pos.y); + } + if (_pos.z <= _posEnd.z) { + this.clippingPosStart.setZ(_pos.z); + this.clippingPosStop.setZ(_posEnd.z); + } else { + this.clippingPosStart.setZ(_posEnd.z); + this.clippingPosStop.setZ(_pos.z); + } + this.clippingEnable = true; + } + + /** + * @brief enable/Disable the clipping (without lose the current clipping position) + * @brief _newMode The new status of the clipping + */ + public void setClippingMode(final boolean _newMode) { + this.clippingEnable = _newMode; + }; + + public void setClippingWidth(final Vector2f _pos, final Vector2f _width) { + setClippingWidth(new Vector3f(_pos.x, _pos.y, 0), new Vector3f(_width.x, _width.y, 0)); + }; + + /** + * @brief Request a clipping area for the text (next draw only) + * @param[in] _pos Start position of the clipping + * @param[in] _width Width size of the clipping + */ + public void setClippingWidth(final Vector3f _pos, final Vector3f _width) { + setClipping(_pos, _pos.addNew(_width)); + } + + /** + * @brief set the Color of the current foreground font + * @param[in] _color Color to set on foreground (for next print) + */ + public void setColor(final Color _color) { + this.color = _color; + }; + + public void setPos(final Vector2f _pos) { + setPos(new Vector3f(_pos.x, _pos.y, 0)); + } + + /** + * @brief set position for the next text writen + * @param[in] _pos Position of the text (in 3D) + */ + public void setPos(final Vector3f _pos) { + this.position = _pos; + } + + public void setRelPos(final Vector2f _pos) { + setRelPos(new Vector3f(_pos.x, _pos.y, 0)); + } + + /** + * @brief set relative position for the next text writen + * @param[in] _pos ofset apply of the text (in 3D) + */ + public void setRelPos(final Vector3f _pos) { + this.position.add(_pos); + } + + public void setSource(final Image _image) { + clear(); + this.filename = null; + this.requestSize = _image.getSize(); + this.resourceImage = new ResourceTexture2(); + this.resourceImage.set(_image); + } + + /** + * @brief change the image Source == > can not be done to display 2 images at the same time ... + * @param[in] _uri New file of the Image + * @param[in] _size for the image when Verctorial image loading is requested + */ + public void setSource(final Uri _uri) { + setSource(_uri, 32); + } + + public void setSource(final Uri _uri, final int _size) { + setSource(_uri, new Vector2i(_size, _size)); + } + + public void setSource(final Uri _uri, final Vector2i _size) { + clear(); + if (this.filename == _uri && this.requestSize.x == _size.x && this.requestSize.y == _size.y) { + // Nothing to do ... + return; + } + final ResourceTextureFile resource = this.resource; + final ResourceTexture2 resourceTex = this.resourceImage; + this.filename = _uri; + this.requestSize = _size; + this.resource = null; + this.resourceImage = null; + + final Vector2i tmpSize = new Vector2i(_size.x, _size.y); + // note that no image can be loaded... + if (_uri.isEmpty() == false) { + // link to new one + this.resource = ResourceTextureFile.create(this.filename, tmpSize); + if (this.resource == null) { + Log.error("Can not get Image resource"); + } + } + if (this.resource == null && this.resourceImage == null) { + if (resource != null) { + Log.warning("Retrive previous resource"); + this.resource = resource; + } + if (resourceTex != null) { + Log.warning("Retrive previous resource (image)"); + this.resourceImage = resourceTex; + } + } + } + +} diff --git a/src/org/atriasoft/ewol/compositing/Drawing.cpp b/src/org/atriasoft/ewol/compositing/Drawing.cpp index 9c37acc..9d6ae1c 100644 --- a/src/org/atriasoft/ewol/compositing/Drawing.cpp +++ b/src/org/atriasoft/ewol/compositing/Drawing.cpp @@ -320,10 +320,10 @@ void ewol::compositing::Drawing::draw(boolean _disableDepthTest) { return; } // set Matrix : translation/positionMatrix - mat4 tmpMatrix = gale::openGL::getMatrix()*this.matrixApply; + Matrix4f tmpMatrix = gale::openGL::getMatrix()*this.matrixApply; this.GLprogram.use(); this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); - mat4 tmpMatrix2; + Matrix4f tmpMatrix2; this.GLprogram.uniformMatrix(this.GLMatrixPosition, tmpMatrix2); // position: this.GLprogram.sendAttributePointer(this.GLPosition, this.VBO, this.vboIdCoord); diff --git a/src/org/atriasoft/ewol/compositing/Drawing.java b/src/org/atriasoft/ewol/compositing/Drawing.java index aa22d2f..c53283d 100644 --- a/src/org/atriasoft/ewol/compositing/Drawing.java +++ b/src/org/atriasoft/ewol/compositing/Drawing.java @@ -1,229 +1,275 @@ + /** @file * @author Edouard DUPIN * @copyright 2011, Edouard DUPIN, all right reserved * @license MPL v2.0 (see license file) */ -#pragma once +package org.atriasoft.ewol.compositing; -#include +import org.atriasoft.etk.Color; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector3f; +import org.atriasoft.ewol.internal.Log; +import org.atriasoft.gale.resource.ResourceProgram; +import org.atriasoft.gale.resource.ResourceVirtualBufferObject; -#include -#include -#include - - -namespace ewol { - namespace compositing { - class Drawing : public ewol::Compositing { - private: - Vector3f this.position; //!< The current position to draw - Vector3f this.clippingPosStart; //!< Clipping start position - Vector3f this.clippingPosStop; //!< Clipping stop position - boolean this.clippingEnable; //!< true if the clipping must be activated - private: - etk::Color<> this.color; //!< The text foreground color - etk::Color<> this.colorBg; //!< The text background color - private: - ememory::Ptr this.GLprogram; //!< pointer on the opengl display program - int this.GLPosition; //!< openGL id on the element (vertex buffer) - int this.GLMatrix; //!< openGL id on the element (transformation matrix) - int this.GLMatrixPosition; //!< position matrix - int this.GLColor; //!< openGL id on the element (color buffer) - protected: - static int this.vboIdCoord; - static int this.vboIdColor; - ememory::Ptr this.VBO; - public: - /** - * @brief Basic ructor - */ - Drawing(); - /** - * @brief Basic destructor - */ - ~Drawing(); - private: - /** +class Drawing extends Compositing { + + private Vector3f position = new Vector3f(0, 0, 0); //!< The current position to draw + private final Vector3f clippingPosStart = new Vector3f(0, 0, 0); //!< Clipping start position + private final Vector3f clippingPosStop = new Vector3f(0, 0, 0); //!< Clipping stop position + private boolean clippingEnable = false; //!< true if the clipping must be activated + private Color color = Color.BLACK.clone(); //!< The text foreground color + private Color colorBg = Color.NONE.clone(); //!< The text background color + private ResourceProgram GLprogram; //!< pointer on the opengl display program + private final int GLPosition = -1; //!< openGL id on the element (vertex buffer) + private final int GLMatrix = -1; //!< openGL id on the element (transformation matrix) + private final int GLMatrixPosition = -1; //!< position matrix + private final int GLColor = -1; //!< openGL id on the element (color buffer) + protected static int vboIdCoord = 0; + protected static int vboIdColor = 1; + protected ResourceVirtualBufferObject VBO; + + /** + * @brief Basic ructor + */ + public Drawing() { + loadProgram(); + for (int iii = 0; iii < 3; iii++) { + this.triangle[iii] = this.position; + this.tricolor[iii] = this.color; + } + // Create the VBO: + this.VBO = ResourceVirtualBufferObject.create(4); + if (this.VBO == null) { + Log.error("can not instanciate VBO ..."); + return; + } + // TO facilitate some debugs we add a name of the VBO: + this.VBO.setName("[VBO] of ewol::compositing::Area"); + } + + /** * @brief load the openGL program and get all the ID needed */ - void loadProgram(); - /** + private void loadProgram(); + + /** * @brief Un-Load the openGL program and get all the ID needed */ - void unLoadProgram(); - float this.thickness; //!< when drawing line and other things - int this.triElement; //!< special counter of the single dot generated - Vector3f this.triangle[3]; //!< Register every system with a combinaison of tiangle - etk::Color this.tricolor[3]; //!< Register every the associated color foreground - // internal API for the generation abstraction of triangles - /** + private void unLoadProgram(); + + private final float thickness = 0; //!< when drawing line and other things + private final int triElement = 0; //!< special counter of the single dot generated + private final Vector3f[] triangle = new Vector3f[3]; //!< Register every system with a combinaison of tiangle + private final Color[] tricolor = new Color[3]; //!< Register every the associated color foreground + // internal API for the generation abstraction of triangles + + /** * @brief Lunch the generation of triangle */ - void generateTriangle(); - /** + private void generateTriangle() { + this.triElement = 0; + + this.VBO.pushOnBuffer(this.vboIdCoord, this.triangle[0]); + this.VBO.pushOnBuffer(this.vboIdColor, this.tricolor[0]); + this.VBO.pushOnBuffer(this.vboIdCoord, this.triangle[1]); + this.VBO.pushOnBuffer(this.vboIdColor, this.tricolor[1]); + this.VBO.pushOnBuffer(this.vboIdCoord, this.triangle[2]); + this.VBO.pushOnBuffer(this.vboIdColor, this.tricolor[2]); + }; + + /** * @brief in case of some error the count can be reset */ - void resetCount(); - /** + private void resetCount(); + + /** * @brief set the Color of the current triangle drawing * @param[in] _color Color to current dots generated */ - void internalSetColor( etk::Color<> _color); - /** + private void internalSetColor(Color _color); + + /** * @brief internal add of the specific point * @param[in] _point The requeste dpoint to add */ - void setPoint( Vector3f point); - - public: - /** + private void setPoint(Vector3f point); + + /** * @brief draw All the refistered text in the current element on openGL */ - void draw(boolean _disableDepthTest=true); - /** - * @brief clear alll tre registered element in the current element - */ - void clear(); - /** - * @brief get the current display position (sometime needed in the gui control) - * @return the current position. - */ - Vector3f getPos() { - return this.position; - }; - /** - * @brief set position for the next text writen - * @param[in] _pos Position of the text (in 3D) - */ - void setPos( Vector3f _pos) { - this.position = _pos; - }; - void setPos( Vector2f _pos) { - setPos(Vector3f(_pos.x(), _pos.y(), 0)); - }; - /** - * @brief set relative position for the next text writen - * @param[in] _pos ofset apply of the text (in 3D) - */ - void setRelPos( Vector3f _pos) { - this.position += _pos; - }; - void setRelPos( Vector2f _pos) { - setRelPos(Vector3f(_pos.x(), _pos.y(), 0)); - }; - /** + @Override + public void draw(final boolean _disableDepthTest=true); + + /** + * @brief clear alll tre registered element in the current element + */ + @Override + public void clear(); + + /** + * @brief get the current display position (sometime needed in the gui control) + * @return the current position. + */ + public Vector3f getPos() { + return this.position; + }; + + /** + * @brief set position for the next text writen + * @param[in] _pos Position of the text (in 3D) + */ + public void setPos(final Vector3f _pos) { + this.position = _pos; + }; + + public void setPos(final Vector2f _pos) { + setPos(Vector3f(_pos.x(), _pos.y(), 0)); + }; + + /** + * @brief set relative position for the next text writen + * @param[in] _pos ofset apply of the text (in 3D) + */ + public void setRelPos(final Vector3f _pos) { + this.position += _pos; + }; + + public void setRelPos(final Vector2f _pos) { + setRelPos(Vector3f(_pos.x(), _pos.y(), 0)); + }; + + /** * @brief set the Color of the current foreground font * @param[in] _color Color to set on foreground (for next print) */ - void setColor( etk::Color<> _color) { - this.color = _color; - }; - /** - * @brief Get the foreground color of the font. - * @return Foreground color. - */ - etk::Color<> getColor() { - return this.color; - }; - /** + public void setColor(final Color _color) { + this.color = _color; + }; + + /** + * @brief Get the foreground color of the font. + * @return Foreground color. + */ + public Color getColor() { + return this.color; + }; + + /** * @brief set the background color of the font (for selected Text (not the global BG)) * @param[in] _color Color to set on background (for next print) */ - void setColorBg( etk::Color<> _color) { - this.colorBg = _color; - }; - /** - * @brief Get the background color of the font. - * @return Background color. - */ - etk::Color<> getColorBg() { - return this.colorBg; - }; - /** - * @brief Request a clipping area for the text (next draw only) - * @param[in]_ pos Start position of the clipping - * @param[in] _width Width size of the clipping - */ - void setClippingWidth( Vector3f _pos, Vector3f _width) { - setClipping(_pos, _pos+_width); - }; - void setClippingWidth( Vector2f _pos, Vector2f _width) { - setClippingWidth(Vector3f(_pos.x(),_pos.y(),-1), Vector3f(_width.x(),_width.y(), 2)); - }; - /** - * @brief Request a clipping area for the text (next draw only) - * @param[in] _pos Start position of the clipping - * @param[in] _posEnd End position of the clipping - */ - void setClipping( Vector3f _pos, Vector3f _posEnd); - void setClipping( Vector2f _pos, Vector2f _posEnd) { - setClipping(Vector3f(_pos.x(),_pos.y(),-1), Vector3f(_posEnd.x(),_posEnd.y(), 1)); - }; - /** - * @brief enable/Disable the clipping (without lose the current clipping position) - * @brief _newMode The new status of the clipping - */ - void setClippingMode(boolean _newMode) { - this.clippingEnable = _newMode; - }; - /** - * @brief Specify the line thickness for the next elements - * @param[in] _thickness The thickness disired for the next print - */ - void setThickness(float _thickness); - /** - * @brief add a point reference at the current position (this is a vertex reference at the current position - */ - void addVertex(); - /** - * @brief draw a line to a specific position - * @param[in] _dest Position of the end of the line. - */ - void lineTo( Vector3f _dest); - void lineTo( Vector2f _dest) { - lineTo(Vector3f(_dest.x(), _dest.y(), 0)); - }; - /** - * @brief Relative drawing a line (spacial vector) - * @param[in] _vect Vector of the curent line. - */ - void lineRel( Vector3f _vect) { - lineTo(this.position+_vect); - }; - void lineRel( Vector2f _vect) { - lineRel(Vector3f(_vect.x(), _vect.y(), 0)); - }; - /** - * @brief draw a 2D rectangle to the position requested. - * @param[in] _dest Position the the end of the rectangle - */ - void rectangle( Vector3f _dest); - void rectangle( Vector2f _dest) { - rectangle(Vector3f(_dest.x(), _dest.y(), 0)); - }; - /** - * @brief draw a 2D rectangle to the requested size. - * @param[in] _size size of the rectangle - */ - void rectangleWidth( Vector3f _size) { - rectangle(this.position+_size); - }; - void rectangleWidth( Vector2f _size) { - rectangleWidth(Vector3f(_size.x(), _size.y(), 0)); - }; - /** - * @brief draw a 3D rectangle to the position requested. - * @param[in] _dest Position the the end of the rectangle - */ - void cube( Vector3f _dest); - /** + public void setColorBg(final Color _color) { + this.colorBg = _color; + }; + + /** + * @brief Get the background color of the font. + * @return Background color. + */ + public Color getColorBg() { + return this.colorBg; + }; + + /** + * @brief Request a clipping area for the text (next draw only) + * @param[in]_ pos Start position of the clipping + * @param[in] _width Width size of the clipping + */ + public void setClippingWidth(final Vector3f _pos, final Vector3f _width) { + setClipping(_pos, _pos + _width); + }; + + public void setClippingWidth(final Vector2f _pos, final Vector2f _width) { + setClippingWidth(Vector3f(_pos.x(), _pos.y(), -1), Vector3f(_width.x(), _width.y(), 2)); + }; + + /** + * @brief Request a clipping area for the text (next draw only) + * @param[in] _pos Start position of the clipping + * @param[in] _posEnd End position of the clipping + */ + public void setClipping(Vector3f _pos, Vector3f _posEnd); + + public void setClipping(final Vector2f _pos, final Vector2f _posEnd) { + setClipping(Vector3f(_pos.x(), _pos.y(), -1), Vector3f(_posEnd.x(), _posEnd.y(), 1)); + }; + + /** + * @brief enable/Disable the clipping (without lose the current clipping position) + * @brief _newMode The new status of the clipping + */ + public void setClippingMode(final boolean _newMode) { + this.clippingEnable = _newMode; + }; + + /** + * @brief Specify the line thickness for the next elements + * @param[in] _thickness The thickness disired for the next print + */ + public void setThickness(float _thickness); + + /** + * @brief add a point reference at the current position (this is a vertex reference at the current position + */ + public void addVertex(); + + /** + * @brief draw a line to a specific position + * @param[in] _dest Position of the end of the line. + */ + public void lineTo(Vector3f _dest); + + public void lineTo(final Vector2f _dest) { + lineTo(new Vector3f(_dest.x, _dest.y, 0)); + }; + + /** + * @brief Relative drawing a line (spacial vector) + * @param[in] _vect Vector of the curent line. + */ + public void lineRel(final Vector3f _vect) { + lineTo(this.position.addNew(_vect)); + }; + + public void lineRel(final Vector2f _vect) { + lineRel(new Vector3f(_vect.x, _vect.y, 0)); + }; + + /** + * @brief draw a 2D rectangle to the position requested. + * @param[in] _dest Position the the end of the rectangle + */ + public void rectangle(Vector3f _dest); + + public void rectangle(final Vector2f _dest) { + rectangle(Vector3f(_dest.x(), _dest.y(), 0)); + }; + + /** + * @brief draw a 2D rectangle to the requested size. + * @param[in] _size size of the rectangle + */ + public void rectangleWidth(final Vector3f _size) { + rectangle(this.position + _size); + }; + + public void rectangleWidth(final Vector2f _size) { + rectangleWidth(Vector3f(_size.x(), _size.y(), 0)); + }; + + /** + * @brief draw a 3D rectangle to the position requested. + * @param[in] _dest Position the the end of the rectangle + */ + public void cube(Vector3f _dest); + + /** * @brief draw a 2D circle with the specify rafdius parameter. * @param[in] _radius Distence to the dorder * @param[in] _angleStart start angle of this circle ([0..2PI] otherwithe == > disable) * @param[in] _angleStop stop angle of this circle ([0..2PI] otherwithe == > disable) */ - void circle(float _radius, float _angleStart = 0, float _angleStop = 2*M_PI); - }; - }; -}; - + public void circle(final float _radius, final float _angleStart = 0, float _angleStop = 2*M_PI); + } diff --git a/src/org/atriasoft/ewol/compositing/Image.cpp b/src/org/atriasoft/ewol/compositing/Image.cpp deleted file mode 100644 index 37b13fc..0000000 --- a/src/org/atriasoft/ewol/compositing/Image.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include -#include -ETK_DECLARE_TYPE(ewol::compositing::Image); - - int ewol::compositing::Image::sizeAuto(0); - -// VBO table property: - int ewol::compositing::Image::this.vboIdCoord(0); - int ewol::compositing::Image::this.vboIdCoordTex(1); - int ewol::compositing::Image::this.vboIdColor(2); -#define NB_VBO (3) - -ewol::compositing::Image::Image( etk::Uri _imageName, - boolean _df, - int _size) : - this.filename(_imageName), - this.requestSize(2,2), - this.position(0.0, 0.0, 0.0), - this.clippingPosStart(0.0, 0.0, 0.0), - this.clippingPosStop(0.0, 0.0, 0.0), - this.clippingEnable(false), - this.color(etk::color::white), - this.angle(0.0), - this.GLprogram(null), - this.GLPosition(-1), - this.GLMatrix(-1), - this.GLColor(-1), - this.GLtexture(-1), - this.GLtexID(-1), - this.distanceFieldMode(_df), - this.resource(null), - this.resourceDF(null) { - // Create the VBO: - this.VBO = gale::resource::VirtualBufferObject::create(NB_VBO); - if (this.VBO == null) { - Log.error("can not instanciate VBO ..."); - return; - } - // TO facilitate some debugs we add a name of the VBO: - this.VBO.setName("[VBO] of ewol::compositing::Image"); - setSource(_imageName, _size); - loadProgram(); -} - -ewol::compositing::Image::~Image() { - -} - -void ewol::compositing::Image::loadProgram() { - // get the shader resource: - this.GLPosition = 0; - this.GLprogram.reset(); - if (this.distanceFieldMode == true) { - this.GLprogram = gale::resource::Program::create("DATA:///texturedDF.prog?lib=ewol"); - } else { - this.GLprogram = gale::resource::Program::create("DATA:///textured3D.prog?lib=ewol"); - } - if (this.GLprogram != null) { - this.GLPosition = this.GLprogram.getAttribute("EW_coord3d"); - this.GLColor = this.GLprogram.getAttribute("EW_color"); - this.GLtexture = this.GLprogram.getAttribute("EW_texture2d"); - this.GLMatrix = this.GLprogram.getUniform("EW_MatrixTransformation"); - this.GLtexID = this.GLprogram.getUniform("EW_texID"); - } -} - -void ewol::compositing::Image::draw(boolean _disableDepthTest) { - if (this.VBO.bufferSize(this.vboIdCoord) <= 0) { - //Log.warning("Nothink to draw..."); - return; - } - if ( this.resource == null - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM this.resourceDF == null - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM this.resourceImage == null) { - // this is a normale case ... the user can choice to have no image ... - return; - } - if (this.GLprogram == null) { - Log.error("No shader ..."); - return; - } - //Log.warning("Display image : " + this.VBO.bufferSize(this.vboIdCoord)); - if (_disableDepthTest == true) { - gale::openGL::disable(gale::openGL::flag_depthTest); - } else { - gale::openGL::enable(gale::openGL::flag_depthTest); - } - // set Matrix : translation/positionMatrix - mat4 tmpMatrix = gale::openGL::getMatrix()*this.matrixApply; - this.GLprogram.use(); - this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); - // TextureID - if (this.resourceImage != null) { - this.GLprogram.setTexture0(this.GLtexID, this.resourceImage.getRendererId()); - } else if (this.resource != null) { - if (this.distanceFieldMode == true) { - Log.error("FONT type error Request distance field and display normal ..."); - } - this.GLprogram.setTexture0(this.GLtexID, this.resource.getRendererId()); - } else { - if (this.distanceFieldMode == false) { - Log.error("FONT type error Request normal and display distance field ..."); - } - this.GLprogram.setTexture0(this.GLtexID, this.resourceDF.getRendererId()); - } - // position: - this.GLprogram.sendAttributePointer(this.GLPosition, this.VBO, this.vboIdCoord); - // Texture: - this.GLprogram.sendAttributePointer(this.GLtexture, this.VBO, this.vboIdCoordTex); - // color: - this.GLprogram.sendAttributePointer(this.GLColor, this.VBO, this.vboIdColor); - // Request the draw of the elements: - gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, this.VBO.bufferSize(this.vboIdCoord)); - this.GLprogram.unUse(); -} - -void ewol::compositing::Image::clear() { - // call upper class - ewol::Compositing::clear(); - // reset Buffer : - this.VBO.clear(); - // reset temporal variables : - this.position = Vector3f(0.0, 0.0, 0.0); - this.clippingPosStart = Vector3f(0.0, 0.0, 0.0); - this.clippingPosStop = Vector3f(0.0, 0.0, 0.0); - this.clippingEnable = false; - this.color = etk::color::white; - this.angle = 0.0; -} - -void ewol::compositing::Image::setClipping( Vector3f _pos, Vector3f _posEnd) { - // note the internal system all time request to have a bounding all time in the same order - if (_pos.x() <= _posEnd.x()) { - this.clippingPosStart.setX(_pos.x()); - this.clippingPosStop.setX(_posEnd.x()); - } else { - this.clippingPosStart.setX(_posEnd.x()); - this.clippingPosStop.setX(_pos.x()); - } - if (_pos.y() <= _posEnd.y()) { - this.clippingPosStart.setY(_pos.y()); - this.clippingPosStop.setY(_posEnd.y()); - } else { - this.clippingPosStart.setY(_posEnd.y()); - this.clippingPosStop.setY(_pos.y()); - } - if (_pos.z() <= _posEnd.z()) { - this.clippingPosStart.setZ(_pos.z()); - this.clippingPosStop.setZ(_posEnd.z()); - } else { - this.clippingPosStart.setZ(_posEnd.z()); - this.clippingPosStop.setZ(_pos.z()); - } - this.clippingEnable = true; -} - -void ewol::compositing::Image::setAngle(float _angle) { - this.angle = _angle; -} - -void ewol::compositing::Image::print( Vector2f _size) { - printPart(_size, Vector2f(0,0), Vector2f(1.0,1.0)); -} - -void ewol::compositing::Image::printPart( Vector2f _size, - Vector2f _sourcePosStart, - Vector2f _sourcePosStop) { - if (this.resource == null) { - return; - } - Vector2f openGLSize = Vector2f(this.resource.getOpenGlSize().x(), this.resource.getOpenGlSize().y()); - Vector2f usefullSize = this.resource.getUsableSize(); - Vector2f ratio = usefullSize/openGLSize; - _sourcePosStart *= ratio; - _sourcePosStop *= ratio; - Log.verbose(" openGLSize=" + openGLSize + " usableSize=" + usefullSize + " start=" + _sourcePosStart + " stop=" + _sourcePosStop); - - //Log.error("Debug image " + this.filename + " ==> " + this.position + " " + _size + " " + _sourcePosStart + " " << _sourcePosStop); - if (this.angle == 0.0f) { - Vector3f point = this.position; - Vector2f tex(_sourcePosStart.x(),_sourcePosStop.y()); - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdCoordTex, tex); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - - tex.setValue(_sourcePosStop.x(),_sourcePosStop.y()); - point.setX(this.position.x() + _size.x()); - point.setY(this.position.y()); - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdCoordTex, tex); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - - tex.setValue(_sourcePosStop.x(),_sourcePosStart.y()); - point.setX(this.position.x() + _size.x()); - point.setY(this.position.y() + _size.y()); - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdCoordTex, tex); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdCoordTex, tex); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - - tex.setValue(_sourcePosStart.x(),_sourcePosStart.y()); - point.setX(this.position.x()); - point.setY(this.position.y() + _size.y()); - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdCoordTex, tex); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - - tex.setValue(_sourcePosStart.x(),_sourcePosStop.y()); - point.setX(this.position.x()); - point.setY(this.position.y()); - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdCoordTex, tex); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - this.VBO.flush(); - return; - } - Vector3f center = this.position + Vector3f(_size.x(),_size.y(),0)/2.0f; - Vector3f limitedSize(_size.x()*0.5f, _size.y()*0.5f, 0.0f); - - Vector3f point(0,0,0); - Vector2f tex(_sourcePosStart.x(),_sourcePosStop.y()); - - point.setValue(-limitedSize.x(), -limitedSize.y(), 0); - point = point.rotate(Vector3f(0,0,1), this.angle) + center; - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdCoordTex, tex); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - - tex.setValue(_sourcePosStop.x(),_sourcePosStop.y()); - point.setValue(limitedSize.x(), -limitedSize.y(), 0); - point = point.rotate(Vector3f(0,0,1), this.angle) + center; - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdCoordTex, tex); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - - tex.setValue(_sourcePosStop.x(),_sourcePosStart.y()); - point.setValue(limitedSize.x(), limitedSize.y(), 0); - point = point.rotate(Vector3f(0,0,1), this.angle) + center; - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdCoordTex, tex); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdCoordTex, tex); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - - tex.setValue(_sourcePosStart.x(),_sourcePosStart.y()); - point.setValue(-limitedSize.x(), limitedSize.y(), 0); - point = point.rotate(Vector3f(0,0,1), this.angle) + center; - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdCoordTex, tex); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - - tex.setValue(_sourcePosStart.x(),_sourcePosStop.y()); - point.setValue(-limitedSize.x(), -limitedSize.y(), 0); - point = point.rotate(Vector3f(0,0,1), this.angle) + center; - this.VBO.pushOnBuffer(this.vboIdCoord, point); - this.VBO.pushOnBuffer(this.vboIdCoordTex, tex); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - - this.VBO.flush(); -} - -void ewol::compositing::Image::setSource( etk::Uri _uri, Vector2f _size) { - clear(); - if ( this.filename == _uri - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM this.requestSize == _size) { - // Nothing to do ... - return; - } - ememory::Ptr resource = this.resource; - ememory::Ptr resourceDF = this.resourceDF; - ememory::Ptr resourceTex = this.resourceImage; - this.filename = _uri; - this.requestSize = _size; - this.resource.reset(); - this.resourceDF.reset(); - this.resourceImage.reset(); - Vector2i tmpSize(_size.x(),_size.y()); - // note that no image can be loaded... - if (_uri.isEmpty() == false) { - // link to new one - if (this.distanceFieldMode == false) { - this.resource = ewol::resource::TextureFile::create(this.filename, tmpSize); - if (this.resource == null) { - Log.error("Can not get Image resource"); - } - } else { - this.resourceDF = ewol::resource::ImageDF::create(this.filename, tmpSize); - if (this.resourceDF == null) { - Log.error("Can not get Image resource DF"); - } - } - } - if ( this.resource == null - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM this.resourceDF == null - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM this.resourceImage == null) { - if (resource != null) { - Log.warning("Retrive previous resource"); - this.resource = resource; - } - if (resourceDF != null) { - Log.warning("Retrive previous resource (DF)"); - this.resourceDF = resourceDF; - } - if (resourceTex != null) { - Log.warning("Retrive previous resource (image)"); - this.resourceImage = resourceTex; - } - } -} -void ewol::compositing::Image::setSource(egami::Image _image) { - clear(); - this.filename = "direct image BUFFER"; - this.requestSize = _image.getSize(); - this.resourceImage = ewol::resource::Texture::create(); - this.resourceImage.set(etk::move(_image)); -} - -boolean ewol::compositing::Image::hasSources() { - return this.resource != null - || this.resourceDF != null; -} - - -Vector2f ewol::compositing::Image::getRealSize() { - if ( this.resource == null - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM this.resourceDF == null - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM this.resourceImage == null) { - return Vector2f(0,0); - } - if (this.resource != null) { - return this.resource.getRealSize(); - } - if (this.resourceDF != null) { - return this.resourceDF.getRealSize(); - } - if (this.resourceImage != null) { - return this.resourceImage.getUsableSize(); - } - return Vector2f(0,0); -} - - - -void ewol::compositing::Image::setDistanceFieldMode(boolean _mode) { - if (this.distanceFieldMode == _mode) { - return; - } - this.distanceFieldMode = _mode; - // Force reload input - setSource(this.filename, this.requestSize); - loadProgram(); -} diff --git a/src/org/atriasoft/ewol/compositing/Image.java b/src/org/atriasoft/ewol/compositing/Image.java deleted file mode 100644 index 18d2c60..0000000 --- a/src/org/atriasoft/ewol/compositing/Image.java +++ /dev/null @@ -1,193 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ -#pragma once - -#include -#include -#include -#include -#include - -namespace ewol { - namespace compositing { - class Image : public ewol::Compositing { - public: - static int sizeAuto; - private: - etk::Uri this.filename; - Vector2i this.requestSize; - Vector3f this.position; //!< The current position to draw - Vector3f this.clippingPosStart; //!< Clipping start position - Vector3f this.clippingPosStop; //!< Clipping stop position - boolean this.clippingEnable; //!< true if the clipping must be activated - private: - etk::Color this.color; //!< The text foreground color - float this.angle; //!< Angle to set at the axes - private: - ememory::Ptr this.GLprogram; //!< pointer on the opengl display program - int this.GLPosition; //!< openGL id on the element (vertex buffer) - int this.GLMatrix; //!< openGL id on the element (transformation matrix) - int this.GLColor; //!< openGL id on the element (color buffer) - int this.GLtexture; //!< openGL id on the element (Texture position) - int this.GLtexID; //!< openGL id on the element (texture ID) - private: - boolean this.distanceFieldMode; //!< select distance field mode - ememory::Ptr this.resource; //!< texture resources - ememory::Ptr this.resourceImage; //!< texture resources - ememory::Ptr this.resourceDF; //!< texture resources - static int this.vboIdCoord; - static int this.vboIdCoordTex; - static int this.vboIdColor; - ememory::Ptr this.VBO; - private: - /** - * @brief load the openGL program and get all the ID needed - */ - void loadProgram(); - public: - /** - * @brief generic ructor - * @param[in] _uri URI of the file that might be loaded - * @param[in] _df enable distance field mode - * @param[in] _size for the image when Verctorial image loading is requested - */ - Image( etk::Uri _uri="", - boolean _df=false, - int _size=ewol::compositing::Image::sizeAuto); - /** - * @brief generic destructor - */ - ~Image(); - public: - /** - * @brief draw All the refistered text in the current element on openGL - * @param[in] _disableDepthTest disable the Depth test for display - */ - void draw(boolean _disableDepthTest=true); - /** - * @brief clear alll tre registered element in the current element - */ - void clear(); - /** - * @brief get the current display position (sometime needed in the gui control) - * @return the current position. - */ - Vector3f getPos() { - return this.position; - }; - /** - * @brief set position for the next text writen - * @param[in] _pos Position of the text (in 3D) - */ - void setPos( Vector3f _pos) { - this.position = _pos; - }; - void setPos( Vector2f _pos) { - setPos(Vector3f(_pos.x(),_pos.y(),0)); - }; - /** - * @brief set relative position for the next text writen - * @param[in] _pos ofset apply of the text (in 3D) - */ - void setRelPos( Vector3f _pos) { - this.position += _pos; - }; - void setRelPos( Vector2f _pos) { - setRelPos(Vector3f(_pos.x(),_pos.y(),0)); - }; - /** - * @brief set the Color of the current foreground font - * @param[in] _color Color to set on foreground (for next print) - */ - void setColor( etk::Color<> _color) { - this.color = _color; - }; - /** - * @brief Request a clipping area for the text (next draw only) - * @param[in] _pos Start position of the clipping - * @param[in] _width Width size of the clipping - */ - void setClippingWidth( Vector3f _pos, Vector3f _width) { - setClipping(_pos, _pos+_width); - }; - void setClippingWidth( Vector2f _pos, Vector2f _width) { - setClippingWidth(Vector3f(_pos.x(),_pos.y(),0), Vector3f(_width.x(),_width.y(),0)); - }; - /** - * @brief Request a clipping area for the text (next draw only) - * @param[in] _pos Start position of the clipping - * @param[in] _posEnd End position of the clipping - */ - void setClipping( Vector3f _pos, Vector3f _posEnd); - void setClipping( Vector2f _pos, Vector2f _posEnd) { - setClipping(Vector3f(_pos.x(),_pos.y(),0), Vector3f(_posEnd.x(),_posEnd.y(),0)); - }; - /** - * @brief enable/Disable the clipping (without lose the current clipping position) - * @brief _newMode The new status of the clipping - */ - void setClippingMode(boolean _newMode) { - this.clippingEnable = _newMode; - }; - /** - * @brief set a unique rotation of this element (not set in the rotate Generic system) - * @param[in] _angle Angle to set in radiant. - */ - void setAngle(float _angleRad); - /** - * @brief add a compleate of the image to display with the requested size - * @param[in] _size size of the output image - */ - void print( Vector2i _size) { - print(Vector2f(_size.x(),_size.y())); - }; - void print( Vector2f _size); - /** - * @brief add a part of the image to display with the requested size - * @param[in] _size size of the output image - * @param[in] _sourcePosStart Start position in the image [0..1] (can be bigger but this repeate the image). - * @param[in] _sourcePosStop Stop position in the image [0..1] (can be bigger but this repeate the image). - */ - void printPart( Vector2f _size, - Vector2f _sourcePosStart, - Vector2f _sourcePosStop); - /** - * @brief change the image Source == > can not be done to display 2 images at the same time ... - * @param[in] _uri New file of the Image - * @param[in] _size for the image when Verctorial image loading is requested - */ - void setSource( etk::Uri _uri, int _size=32) { - setSource(_uri, Vector2f(_size,_size)); - }; - void setSource( etk::Uri _uri, Vector2f _size); - void setSource(egami::Image _image); - /** - * @brief Sometimes the user declare an image but not allocate the ressources all the time, this is to know it .. - * @return the validity od the resources. - */ - boolean hasSources(); - /** - * @brief get the source image registered size in the file (<0 when multiple size image) - * @return tre image registered size - */ - Vector2f getRealSize(); - public: - /** - * @brief Set render mode of the image - * @param[in] _mode Activation of distance field mode - */ - void setDistanceFieldMode(boolean _mode); - /** - * @brief Get the render methode. - * @return The render mode of the image. - */ - boolean getDistanceFieldMode() { - return this.distanceFieldMode; - } - }; - }; -}; - diff --git a/src/org/atriasoft/ewol/compositing/Shaper.cpp b/src/org/atriasoft/ewol/compositing/Shaper.cpp index a87ec62..a463fbd 100644 --- a/src/org/atriasoft/ewol/compositing/Shaper.cpp +++ b/src/org/atriasoft/ewol/compositing/Shaper.cpp @@ -192,7 +192,7 @@ void ewol::compositing::Shaper::draw(boolean _disableDepthTest) { //glScalef(this.scaling.x, this.scaling.y, 1.0); this.GLprogram.use(); // set Matrix : translation/positionMatrix - mat4 tmpMatrix = gale::openGL::getMatrix(); + Matrix4f tmpMatrix = gale::openGL::getMatrix(); this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); // position: this.GLprogram.sendAttributePointer(this.GLPosition, this.VBO, this.vboIdCoord); @@ -641,8 +641,8 @@ boolean ewol::compositing::Shaper::hasSources() { } - etk::Color ewol::compositing::Shaper::getColor(int _id) { - static etk::Color errorValue(0,0,0,0); + Color ewol::compositing::Shaper::getColor(int _id) { + static Color errorValue(0,0,0,0); if (this.colorProperty == null) { Log.warning("null of this.colorProperty ==> return #0000 for id " + _id); return errorValue; diff --git a/src/org/atriasoft/ewol/compositing/Shaper.java b/src/org/atriasoft/ewol/compositing/Shaper.java index 33690c0..c134ad4 100644 --- a/src/org/atriasoft/ewol/compositing/Shaper.java +++ b/src/org/atriasoft/ewol/compositing/Shaper.java @@ -242,7 +242,7 @@ namespace ewol { * @param[in] _id Id of the color * @return the reference on the color */ - etk::Color getColor(int _id); + Color getColor(int _id); public: /** * @brief Get an ID on the configuration instance element diff --git a/src/org/atriasoft/ewol/compositing/Sprite.cpp b/src/org/atriasoft/ewol/compositing/Sprite.cpp deleted file mode 100644 index 21114f9..0000000 --- a/src/org/atriasoft/ewol/compositing/Sprite.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include - -#include -ETK_DECLARE_TYPE(ewol::compositing::Sprite); - -ewol::compositing::Sprite::Sprite( String _imageName, Vector2i _nbSprite, int _size) : - ewol::compositing::Image(_imageName, false, _size), - this.nbSprite(_nbSprite), - this.unitarySpriteSize(0,0) { - /* - Vector2f imageSize = getRealSize(); - this.unitarySpriteSize.setValue(imageSize.x()/(float)this.nbSprite.x(), - imageSize.y()/(float)this.nbSprite.y()); - */ - this.unitarySpriteSize.setValue(1.0/(float)this.nbSprite.x(), - 1.0/(float)this.nbSprite.y()); -} - - -void ewol::compositing::Sprite::printSprite( Vector2i _spriteID, Vector3f _size) { - if( _spriteID.x()<0 - || _spriteID.y()<0 - || _spriteID.x() >= this.nbSprite.x() - || _spriteID.y() >= this.nbSprite.y()) { - return; - } - printPart(Vector2f(_size.x(),_size.y()), - Vector2f((float)(_spriteID.x() )*this.unitarySpriteSize.x(), (float)(_spriteID.y() )*this.unitarySpriteSize.y()), - Vector2f((float)(_spriteID.x()+1)*this.unitarySpriteSize.x(), (float)(_spriteID.y()+1)*this.unitarySpriteSize.y())); -} - - diff --git a/src/org/atriasoft/ewol/compositing/Sprite.java b/src/org/atriasoft/ewol/compositing/Sprite.java deleted file mode 100644 index b834eed..0000000 --- a/src/org/atriasoft/ewol/compositing/Sprite.java +++ /dev/null @@ -1,29 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ -#pragma once - -#include -#include - -namespace ewol { - namespace compositing { - class Sprite : public ewol::compositing::Image { - protected: - Vector2i this.nbSprite; //!< number of sprite in vertical and horizontal - Vector2f this.unitarySpriteSize; //!< size of a unique sprite - public: - Sprite( String _imageName, - Vector2i _nbSprite, - int _size=ewol::compositing::Image::sizeAuto); - ~Sprite() {}; - void printSprite( Vector2i _spriteID, Vector2f _size) { - printSprite(_spriteID, Vector3f(_size.x(), _size.y(),0)); - }; - void printSprite( Vector2i _spriteID, Vector3f _size); - }; - } -} - diff --git a/src/org/atriasoft/ewol/compositing/Text.cpp b/src/org/atriasoft/ewol/compositing/Text.cpp index 01ae569..611a2ae 100644 --- a/src/org/atriasoft/ewol/compositing/Text.cpp +++ b/src/org/atriasoft/ewol/compositing/Text.cpp @@ -21,7 +21,7 @@ ewol::compositing::Text::~Text() { } -void ewol::compositing::Text::drawMT( mat4 _transformationMatrix, boolean _enableDepthTest) { +void ewol::compositing::Text::drawMT( Matrix4f _transformationMatrix, boolean _enableDepthTest) { // draw BG in any case: this.vectorialDraw.draw(); @@ -44,9 +44,9 @@ void ewol::compositing::Text::drawMT( mat4 _transformationMatrix, boolean _enabl gale::openGL::enable(gale::openGL::flag_depthTest); } // set Matrix : translation/positionMatrix - mat4 projMatrix = gale::openGL::getMatrix(); - mat4 camMatrix = gale::openGL::getCameraMatrix(); - mat4 tmpMatrix = projMatrix * camMatrix * _transformationMatrix; + Matrix4f projMatrix = gale::openGL::getMatrix(); + Matrix4f camMatrix = gale::openGL::getCameraMatrix(); + Matrix4f tmpMatrix = projMatrix * camMatrix * _transformationMatrix; this.GLprogram.use(); this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); // Texture: @@ -85,7 +85,7 @@ void ewol::compositing::Text::drawD(boolean _disableDepthTest) { return; } // set Matrix : translation/positionMatrix - mat4 tmpMatrix = gale::openGL::getMatrix()*this.matrixApply; + Matrix4f tmpMatrix = gale::openGL::getMatrix()*this.matrixApply; this.GLprogram.use(); this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); // Texture : diff --git a/src/org/atriasoft/ewol/compositing/Text.java b/src/org/atriasoft/ewol/compositing/Text.java index 80f89e3..a56dd20 100644 --- a/src/org/atriasoft/ewol/compositing/Text.java +++ b/src/org/atriasoft/ewol/compositing/Text.java @@ -35,7 +35,7 @@ namespace ewol { ~Text(); public: void drawD(boolean _disableDepthTest); - void drawMT( mat4 _transformationMatrix, boolean _enableDepthTest); + void drawMT( Matrix4f _transformationMatrix, boolean _enableDepthTest); protected: float this.size; public: diff --git a/src/org/atriasoft/ewol/compositing/TextBase.java b/src/org/atriasoft/ewol/compositing/TextBase.java index 15a8643..184a215 100644 --- a/src/org/atriasoft/ewol/compositing/TextBase.java +++ b/src/org/atriasoft/ewol/compositing/TextBase.java @@ -116,7 +116,7 @@ namespace ewol { drawD(_disableDepthTest); } //! @previous - void draw( mat4 _transformationMatrix, boolean _enableDepthTest=false) { + void draw( Matrix4f _transformationMatrix, boolean _enableDepthTest=false) { drawMT(_transformationMatrix, _enableDepthTest); } /** @@ -124,7 +124,7 @@ namespace ewol { */ void drawD(boolean _disableDepthTest) = 0; //! @previous - void drawMT( mat4 _transformationMatrix, boolean _enableDepthTest) = 0; + void drawMT( Matrix4f _transformationMatrix, boolean _enableDepthTest) = 0; /** * @brief clear all the registered element in the current element */ diff --git a/src/org/atriasoft/ewol/compositing/TextDF.cpp b/src/org/atriasoft/ewol/compositing/TextDF.cpp deleted file mode 100644 index 0f97e22..0000000 --- a/src/org/atriasoft/ewol/compositing/TextDF.cpp +++ /dev/null @@ -1,407 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include -#include -#include -#include -ETK_DECLARE_TYPE(ewol::compositing::TextDF); - -ewol::compositing::TextDF::TextDF( String _fontName, int _fontSize) : - ewol::compositing::TextBase("", false), - this.fontDF(null), - this.GLglyphLevel(-1), - this.size(12.0) { - setFont(_fontName, _fontSize); - loadProgram("DATA:///fontDistanceField/font1.prog?lib=ewol"); -} - -ewol::compositing::TextDF::~TextDF() { - -} - -void ewol::compositing::TextDF::updateSizeToRender( Vector2f _size) { - float minSize = etk::min(_size.x(), _size.y()); - if (this.fontDF != null) { - setFontSize(this.fontDF.getSize(minSize)); - } -} - -void ewol::compositing::TextDF::drawMT( mat4 _transformationMatrix, boolean _enableDepthTest) { - // draw BG in any case: - this.vectorialDraw.draw(); - if ( this.VBO.bufferSize(this.vboIdCoord) <= 0 - || this.fontDF == null) { - //Log.warning("Nothink to draw..."); - return; - } - if (this.fontDF == null) { - Log.warning("no font..."); - return; - } - if (this.GLprogram == null) { - Log.error("No shader ..."); - return; - } - if (_enableDepthTest == true) { - gale::openGL::enable(gale::openGL::flag_depthTest); - } - // set Matrix: translation/positionMatrix - mat4 projMatrix = gale::openGL::getMatrix(); - mat4 camMatrix = gale::openGL::getCameraMatrix(); - mat4 tmpMatrix = projMatrix * camMatrix * _transformationMatrix; - this.GLprogram.use(); - this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); - // Texture: - this.GLprogram.setTexture0(this.GLtexID, this.fontDF.getRendererId()); - this.GLprogram.uniform1i(this.GLtextWidth, this.fontDF.getOpenGlSize().x()); - this.GLprogram.uniform1i(this.GLtextHeight, this.fontDF.getOpenGlSize().x()); - this.GLprogram.sendAttributePointer(this.GLPosition, this.VBO, this.vboIdCoord); - this.GLprogram.sendAttributePointer(this.GLtexture, this.VBO, this.vboIdCoordText); - this.GLprogram.sendAttributePointer(this.GLColor, this.VBO, this.vboIdColor); - this.GLprogram.sendAttributePointer(this.GLglyphLevel, this.VBO, this.vboIdGlyphLevel); - // Request the draw od the elements: - gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, this.VBO.bufferSize(this.vboIdCoord)); - this.GLprogram.unUse(); - if (_enableDepthTest == true) { - gale::openGL::disable(gale::openGL::flag_depthTest); - } -} - - -void ewol::compositing::TextDF::drawD(boolean _disableDepthTest) { - // draw BG in any case: - this.vectorialDraw.draw(); - - if ( this.VBO.bufferSize(this.vboIdCoord) <= 0 - || this.fontDF == null) { - // TODO : Set it back - //Log.warning("Nothink to draw..."); - return; - } - if (this.fontDF == null) { - Log.warning("no font..."); - return; - } - if (this.GLprogram == null) { - Log.error("No shader ..."); - return; - } - // set Matrix: translation/positionMatrix - mat4 tmpMatrix = gale::openGL::getMatrix()*this.matrixApply; - this.GLprogram.use(); - this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); - // Texture: - this.GLprogram.setTexture0(this.GLtexID, this.fontDF.getRendererId()); - this.GLprogram.uniform1i(this.GLtextWidth, this.fontDF.getOpenGlSize().x()); - this.GLprogram.uniform1i(this.GLtextHeight, this.fontDF.getOpenGlSize().x()); - this.GLprogram.sendAttributePointer(this.GLPosition, this.VBO, this.vboIdCoord); - this.GLprogram.sendAttributePointer(this.GLtexture, this.VBO, this.vboIdCoordText); - this.GLprogram.sendAttributePointer(this.GLColor, this.VBO, this.vboIdColor); - this.GLprogram.sendAttributePointer(this.GLglyphLevel, this.VBO, this.vboIdGlyphLevel); - // Request the draw od the elements: - gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, this.VBO.bufferSize(this.vboIdCoord)); - this.GLprogram.unUse(); -} - -void ewol::compositing::TextDF::loadProgram( String _shaderName) { - ewol::compositing::TextBase::loadProgram(_shaderName); - if (this.GLprogram != null) { - this.GLglyphLevel = this.GLprogram.getAttribute("EW_glyphLevel"); - } -} - - -float ewol::compositing::TextDF::getHeight() { - if (this.fontDF == null) { - Log.warning("no font..."); - return 1; - } - return this.fontDF.getHeight(this.size); -} - -ewol::GlyphProperty * ewol::compositing::TextDF::getGlyphPointer(Character _charcode) { - if (this.fontDF == null) { - Log.warning("no font..."); - return null; - } - return this.fontDF.getGlyphPointer(_charcode); -} - -void ewol::compositing::TextDF::setFontSize(int _fontSize) { - clear(); - Log.verbose("Set font Size: " + _fontSize); - if (_fontSize <= 1) { - this.size = ewol::getContext().getFontDefault().getSize(); - } else { - this.size = _fontSize; - } -} - -void ewol::compositing::TextDF::setFontName( String _fontName) { - clear(); - // remove old one - ememory::Ptr previousFont = this.fontDF; - String fontName; - if (_fontName == "") { - fontName = ewol::getContext().getFontDefault().getName(); - } else { - fontName = _fontName; - } - Log.verbose("Set font name: '" + fontName + "'"); - // link to new one - this.fontDF = ewol::resource::DistanceFieldFont::create(fontName); - if (this.fontDF == null) { - Log.error("Can not get find resource"); - this.fontDF = previousFont; - } -} - -void ewol::compositing::TextDF::setFont(String _fontName, int _fontSize) { - setFontSize(_fontSize); - setFontName(_fontName); -} - -void ewol::compositing::TextDF::setFontMode(enum ewol::font::mode _mode) { - this.mode = _mode; -} - -//#define ANGLE_OF_ITALIC (tan(0.4)) -#define ANGLE_OF_ITALIC (0.00698143f) - - -void ewol::compositing::TextDF::printChar( Character _charcode) { - // get a pointer on the glyph property : - ewol::GlyphProperty* myGlyph = getGlyphPointer(_charcode); - if (null == myGlyph) { - Log.error(" font does not really existed ..."); - return; - } - float fontSize = getSize(); - float fontHeigh = getHeight(); - - float factorDisplay = this.fontDF.getDisplayRatio(fontSize); - - // get the kerning ofset : - float kerningOffset = 0; - if (true == this.kerning) { - kerningOffset = myGlyph.kerningGet(this.previousCharcode); - if (kerningOffset != 0) { - //Log.debug("Kerning between : '" + this.previousCharcode + "''" + myGlyph.this.UVal + "' value : " + kerningOffset); - } - } - // 0x01 == 0x20 == ' '; - if ( _charcode != 0x01 - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM _charcode != 0x20) { - float glyphLevel = 0.5f; - if ( this.mode == ewol::font::BoldItalic - || this.mode == ewol::font::Bold) { - glyphLevel = 0.41f; - } - float italicMove = 0.0f; - if ( this.mode == ewol::font::BoldItalic - || this.mode == ewol::font::Italic) { - // This is a simple version of Italic mode, in theory we need to move the up and the down... - italicMove = (float)myGlyph.this.sizeTexture.y() * factorDisplay * ANGLE_OF_ITALIC; - // TODO : pb on the clipper... - } - - /* Bitmap position - * xA xB - * yC *------* - * | | - * | | - * yD *------* - */ - #if 0 - float dxA = this.position.x() + (myGlyph.this.bearing.x() + kerningOffset) * factorDisplay; - float dxB = dxA + myGlyph.this.sizeTexture.x() * factorDisplay; - float dyC = this.position.y() + (myGlyph.this.bearing.y() + fontHeigh - fontSize) * factorDisplay; - float dyD = dyC - myGlyph.this.sizeTexture.y() * factorDisplay; - #else - //Log.debug(" plop : fontHeigh" + fontHeigh + " fontSize=" + fontSize); - float dxA = this.position.x() + ((float)myGlyph.this.bearing.x() + kerningOffset - (float)this.fontDF.getPixelBorderSize()*0.5f) * factorDisplay; - float dxB = dxA + ((float)myGlyph.this.sizeTexture.x() + (float)this.fontDF.getPixelBorderSize()) * factorDisplay; - float dyC = this.position.y() + (fontHeigh - fontSize + ((float)myGlyph.this.bearing.y() + (float)this.fontDF.getPixelBorderSize()*0.5f) * factorDisplay); - float dyD = dyC - ((float)myGlyph.this.sizeTexture.y() + (float)this.fontDF.getPixelBorderSize()) * factorDisplay; - #endif - - float tuA = myGlyph.this.texturePosStart.x(); - float tuB = tuA + myGlyph.this.texturePosSize.x(); - float tvC = myGlyph.this.texturePosStart.y(); - float tvD = tvC + myGlyph.this.texturePosSize.y(); - /* - Vector3f drawingPos = this.vectorialDraw.getPos(); - etk::Color<> backColor = this.vectorialDraw.getColor(); - - this.vectorialDraw.setPos(Vector2f(dxA, dyC)); - - this.vectorialDraw.setColor(etk::Color<>(0.0,1.0,0.0,1.0)); - this.vectorialDraw.rectangle(Vector2f(dxB, dyD)); - - this.vectorialDraw.setPos(drawingPos); - this.vectorialDraw.setColor(backColor); - */ - // Clipping and drawing area - if( this.clippingEnable == true - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM ( dxB < this.clippingPosStart.x() - || dxA > this.clippingPosStop.x() - || dyC < this.clippingPosStart.y() - || dyD > this.clippingPosStop.y() ) ) { - // Nothing to diplay ... - } else { - if (this.clippingEnable == true) { - // generata positions... - float TexSizeX = tuB - tuA; - if (dxA < this.clippingPosStart.x()) { - // clip display - float drawSize = this.clippingPosStart.x() - dxA; - // update element start display - dxA = this.clippingPosStart.x(); - float addElement = TexSizeX * drawSize / ((float)myGlyph.this.sizeTexture.x() * factorDisplay); - // update texture start X Pos - tuA += addElement; - } - if (dxB > this.clippingPosStop.x()) { - // clip display - float drawSize = dxB - this.clippingPosStop.x(); - // update element start display - dxB = this.clippingPosStop.x(); - float addElement = TexSizeX * drawSize / ((float)myGlyph.this.sizeTexture.x() * factorDisplay); - // update texture start X Pos - tuB -= addElement; - } - float TexSizeY = tvC - tvD; - if (dyC > this.clippingPosStop.y()) { - // clip display - float drawSize = dyC - this.clippingPosStop.y(); - // update element start display - dyC = this.clippingPosStop.y(); - float addElement = TexSizeY * drawSize / ((float)myGlyph.this.sizeTexture.y() * factorDisplay); - // update texture start X Pos - tvC -= addElement; - } - if (dyD < this.clippingPosStart.y()) { - // clip display - float drawSize = this.clippingPosStart.y() - dyD; - // update element start display - dyD = this.clippingPosStart.y(); - float addElement = TexSizeY * drawSize / ((float)myGlyph.this.sizeTexture.y() * factorDisplay); - // update texture start X Pos - tvD += addElement; - } - } - if( dxB <= dxA - || dyD >= dyC) { - // nothing to do ... - } else { - /* Bitmap position - * 0------1 - * | | - * | | - * 3------2 - */ - if (this.needDisplay == true) { - Vector3f bitmapDrawPos[4]; - bitmapDrawPos[0].setValue(dxA+italicMove, dyC, 0); - bitmapDrawPos[1].setValue(dxB+italicMove, dyC, 0); - bitmapDrawPos[2].setValue(dxB, dyD, 0); - bitmapDrawPos[3].setValue(dxA, dyD, 0); - /* texture Position : - * 0------1 - * | | - * | | - * 3------2 - */ - Vector2f texturePos[4]; - texturePos[0].setValue(tuA+this.mode, tvC); - texturePos[1].setValue(tuB+this.mode, tvC); - texturePos[2].setValue(tuB+this.mode, tvD); - texturePos[3].setValue(tuA+this.mode, tvD); - - // NOTE : Android does not support the Quads elements ... - /* Step 1 : - * ******** - * ****** - * **** - * ** - * - */ - // set texture coordonates : - this.VBO.pushOnBuffer(this.vboIdCoordText, texturePos[0]); - this.VBO.pushOnBuffer(this.vboIdCoordText, texturePos[1]); - this.VBO.pushOnBuffer(this.vboIdCoordText, texturePos[2]); - // set display positions : - this.VBO.pushOnBuffer(this.vboIdCoord, bitmapDrawPos[0]); - this.VBO.pushOnBuffer(this.vboIdCoord, bitmapDrawPos[1]); - this.VBO.pushOnBuffer(this.vboIdCoord, bitmapDrawPos[2]); - // set the color - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - // set the bliph level - this.VBO.pushOnBuffer(this.vboIdGlyphLevel, glyphLevel); - this.VBO.pushOnBuffer(this.vboIdGlyphLevel, glyphLevel); - this.VBO.pushOnBuffer(this.vboIdGlyphLevel, glyphLevel); - /* Step 2 : - * - * ** - * **** - * ****** - * ******** - */ - // set texture coordonates : - this.VBO.pushOnBuffer(this.vboIdCoordText, texturePos[0]); - this.VBO.pushOnBuffer(this.vboIdCoordText, texturePos[2]); - this.VBO.pushOnBuffer(this.vboIdCoordText, texturePos[3]); - // set display positions : - this.VBO.pushOnBuffer(this.vboIdCoord, bitmapDrawPos[0]); - this.VBO.pushOnBuffer(this.vboIdCoord, bitmapDrawPos[2]); - this.VBO.pushOnBuffer(this.vboIdCoord, bitmapDrawPos[3]); - // set the color - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - this.VBO.pushOnBuffer(this.vboIdColor, this.color); - // set the bliph level - this.VBO.pushOnBuffer(this.vboIdGlyphLevel, glyphLevel); - this.VBO.pushOnBuffer(this.vboIdGlyphLevel, glyphLevel); - this.VBO.pushOnBuffer(this.vboIdGlyphLevel, glyphLevel); - } - } - } - } - // move the position : - //Log.debug(" 5 pos=" + this.position + " advance=" + myGlyph.this.advance.x() + " kerningOffset=" + kerningOffset); - this.position.setX(this.position.x() + (myGlyph.this.advance.x() + kerningOffset) * factorDisplay); - //Log.debug(" 6 print '" + charcode + "' : start=" + this.sizeDisplayStart + " stop=" + this.sizeDisplayStop + " pos=" + this.position); - // Register the previous character - this.previousCharcode = _charcode; - this.VBO.flush(); - return; -} - - -Vector3f ewol::compositing::TextDF::calculateSizeChar( Character _charcode) { - // get a pointer on the glyph property : - ewol::GlyphProperty * myGlyph = getGlyphPointer(_charcode); - int fontHeigh = getHeight(); - - // get the kerning ofset : - float kerningOffset = 0.0; - if (true == this.kerning) { - kerningOffset = myGlyph.kerningGet(this.previousCharcode); - } - - Vector3f outputSize((float)(myGlyph.this.advance.x() + kerningOffset)*this.fontDF.getDisplayRatio(getSize()), - (float)(fontHeigh), - (float)(0.0)); - // Register the previous character - this.previousCharcode = _charcode; - return outputSize; -} - - diff --git a/src/org/atriasoft/ewol/compositing/TextDF.java b/src/org/atriasoft/ewol/compositing/TextDF.java deleted file mode 100644 index 636e598..0000000 --- a/src/org/atriasoft/ewol/compositing/TextDF.java +++ /dev/null @@ -1,70 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ -#pragma once - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace ewol { - namespace compositing { - class TextDF : public ewol::compositing::TextBase { - protected: - ememory::Ptr this.fontDF; //!< Font resources - protected: - int this.GLglyphLevel; //!< openGL Id on the glyph level display - public: - /** - * @brief generic ructor - * @param[in] _fontName Name of the font that might be loaded - * @param[in] _fontSize size of the font that might be loaded - */ - TextDF( String _fontName="", int _fontSize=-1); - /** - * @brief generic destructor - */ - ~TextDF(); - public: - /** - * @brief Calculate size to be at the best size for a render in this special size. - * @note special for Distance field mode. - * @param[in] _size request dimention. - */ - void updateSizeToRender( Vector2f _size); - public: - void drawD(boolean _disableDepthTest); - void drawMT( mat4 _transformationMatrix, boolean _enableDepthTest); - protected: - float this.size; - public: - float getHeight(); - float getSize() { - return this.size; - } - void setSize(float _size) { - this.size = _size; - } - ewol::GlyphProperty * getGlyphPointer(Character _charcode); - - public: - void loadProgram( String _shaderName); - void setFontSize(int _fontSize); - void setFontName( String _fontName); - void setFont(String _fontName, int _fontSize); - void setFontMode(enum ewol::font::mode _mode); - void printChar( Character _charcode); - Vector3f calculateSizeChar( Character _charcode); - }; - } -} - - diff --git a/src/org/atriasoft/ewol/context/Application.cpp b/src/org/atriasoft/ewol/context/Application.cpp deleted file mode 100644 index ff6843c..0000000 --- a/src/org/atriasoft/ewol/context/Application.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include -#include - -#include -ETK_DECLARE_TYPE(EwolApplication); - -EwolApplication::Application() { - -} - -EwolApplication::~Application() { - -} - -void EwolApplication::onCreate(EwolContext _context) { - -} - -void EwolApplication::onStart(EwolContext _context) { - -} - -void EwolApplication::onResume(EwolContext _context) { - -} - -void EwolApplication::onPause(EwolContext _context) { - -} - -void EwolApplication::onStop(EwolContext _context) { - -} - -void EwolApplication::onDestroy(EwolContext _context) { - -} - -void EwolApplication::onKillDemand(EwolContext _context) { - _context.exit(0); -} - diff --git a/src/org/atriasoft/ewol/context/ConfigFont.cpp b/src/org/atriasoft/ewol/context/ConfigFont.cpp deleted file mode 100644 index c0aa5be..0000000 --- a/src/org/atriasoft/ewol/context/ConfigFont.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include -#include -ETK_DECLARE_TYPE(ConfigFont); - -ConfigFont::ConfigFont() : - this.folder("DATA:///fonts?lib=ewol"), - this.name("Arial;Helvetica"), - this.size(10), - this.useExternal(false) { - #ifdef __TARGET_OS__Android - this.name = "Roboto;DroidSans"; - #endif - ewol::resource::freeTypeInit(); -} - -ConfigFont::~ConfigFont() { - // UnInit FreeTypes - ewol::resource::freeTypeUnInit(); -} - -void ConfigFont::set( String _fontName, int _size) { - this.name = _fontName; - this.size = _size; - Log.debug("Set default Font : '" + this.name + "' size=" + this.size); -} - -void ConfigFont::setSize(int _size) { - this.size = _size; - Log.debug("Set default Font : '" + this.name + "' size=" + this.size + " (change size only)"); -} - -void ConfigFont::setName( String _fontName) { - this.name = _fontName; - Log.debug("Set default Font : '" + this.name + "' size=" + this.size + " (change name only)"); -} - diff --git a/src/org/atriasoft/ewol/context/ConfigFont.java b/src/org/atriasoft/ewol/context/ConfigFont.java index e3f2232..7d40638 100644 --- a/src/org/atriasoft/ewol/context/ConfigFont.java +++ b/src/org/atriasoft/ewol/context/ConfigFont.java @@ -1,92 +1,99 @@ +package org.atriasoft.ewol.context; + +import org.atriasoft.etk.Uri; +import org.atriasoft.ewol.internal.Log; + /** @file * @author Edouard DUPIN * @copyright 2011, Edouard DUPIN, all right reserved * @license MPL v2.0 (see license file) */ -#pragma once -#include -#include - -namespace ewol { - namespace context { - class ConfigFont { - public: - /** - * Constructor / destructor - */ - ConfigFont(); - ~ConfigFont(); - private: - etk::Uri this.folder; - public: - /** - * @brief Specify the default font folder for the Ewol search system (only needed when embended font) - * @param[in] _folder basic folder of the font (ex: DATA:fonts) - */ - void setFolder( etk::Uri _folder) { - this.folder = _folder; - }; - /** - * @brief get the default font folder. - * @return The default font folder. - */ - etk::Uri getFolder() { - return this.folder; - }; - private: - String this.name; - int this.size; - public: - /** - * @brief set the defaut font for all the widgets and basics display. - * @param[in] _fontName The font name requested (not case sensitive) ex "Arial" or multiple separate by ';' ex : "Arial;Helvetica". - * @param[in] _size The default size of the font default=10. - */ - void set( String _fontName, int _size); - /** - * @brief get the current default font name - * @raturn a reference on the font name string - */ - String getName() { - return this.name; - }; - /** - * @brief Set the current default font name - * @param[in] _fontName The font name requested (not case sensitive) ex "Arial" or multiple separate by ';' ex : "Arial;Helvetica". - */ - void setName( String _fontName); - /** - * @brief get the default font size. - * @return the font size. - */ - int getSize() { - return this.size; - }; - /** - * @brief Set the default font size. - * @param[in] _size new font size. - */ - void setSize(int _size); - private: - boolean this.useExternal; - public: - /** - * @brief set use of internal/external Font - * @param[in] _val true to enable search of internal data. - */ - void setUseExternal(boolean _val) { - this.useExternal=_val; - }; - /** - * @brief get the use of internal/external Font - * @return true to enable search of internal data. - */ - boolean getUseExternal() { - return this.useExternal; - }; - }; +public class ConfigFont { + private Uri folder = new Uri("DATA:///fonts?lib=ewol"); + private String name = "Arial;Helvetica"; + private int size = 10; + private boolean useExternal = false; + + /** + * Constructor + */ + public ConfigFont() {} + + /** + * @brief get the default font folder. + * @return The default font folder. + */ + public Uri getFolder() { + return this.folder; + } + + /** + * @brief get the current default font name + * @return a reference on the font name string + */ + public String getName() { + return this.name; + } + + /** + * @brief get the default font size. + * @return the font size. + */ + public int getSize() { + return this.size; + }; + + /** + * @brief get the use of internal/external Font + * @return true to enable search of internal data. + */ + public boolean getUseExternal() { + return this.useExternal; + } + + /** + * @brief set the defaut font for all the widgets and basics display. + * @param[in] _fontName The font name requested (not case sensitive) ex "Arial" or multiple separate by ';' ex : "Arial;Helvetica". + * @param[in] _size The default size of the font default=10. + */ + public void set(final String _fontName, final int _size) { + this.name = _fontName; + this.size = _size; + Log.debug("Set default Font : '" + this.name + "' size=" + this.size); + }; + + /** + * @brief Specify the default font folder for the Ewol search system (only needed when embended font) + * @param[in] _folder basic folder of the font (ex: DATA:fonts) + */ + public void setFolder(final Uri _folder) { + this.folder = _folder; + } + + /** + * @brief Set the current default font name + * @param[in] _fontName The font name requested (not case sensitive) ex "Arial" or multiple separate by ';' ex : "Arial;Helvetica". + */ + public void setName(final String _fontName) { + this.name = _fontName; + Log.debug("Set default Font : '" + this.name + "' size=" + this.size + " (change name only)"); + } + + /** + * @brief Set the default font size. + * @param[in] _size new font size. + */ + public void setSize(final int _size) { + this.size = _size; + Log.debug("Set default Font : '" + this.name + "' size=" + this.size + " (change size only)"); + }; + + /** + * @brief set use of internal/external Font + * @param[in] _val true to enable search of internal data. + */ + public void setUseExternal(final boolean _val) { + this.useExternal = _val; }; }; - - diff --git a/src/org/atriasoft/ewol/context/Context.cpp b/src/org/atriasoft/ewol/context/Context.cpp deleted file mode 100644 index eafca84..0000000 --- a/src/org/atriasoft/ewol/context/Context.cpp +++ /dev/null @@ -1,57 +0,0 @@ - - - -void EwolContext::onClipboardEvent(enum gale::context::clipBoard::clipboardListe _clipboardId) - -EwolContext::Context(EwolApplication* _application) : -EwolContext::~Context() { - // nothing to do ... -} - -void EwolContext::requestUpdateSize() { - Context context = gale::getContext(); - context.requestUpdateSize(); -} - -void EwolContext::onPeriod( echrono::Clock _time) { - this.objectManager.timeCall(_time); -} - -void EwolContext::resetIOEvent() { - this.input.newLayerSet(); -} - -void EwolContext::setWindows( ewol::widget::WindowsShared _windows) { - Log.info("set New windows"); - // remove current focus : - this.widgetManager.focusSetDefault(null); - this.widgetManager.focusRelease(); - // set the new pointer as windows system - this.windowsCurrent = _windows; - // set the new default focus: - this.widgetManager.focusSetDefault(_windows); - // display the title of the Windows: - if (this.windowsCurrent != null) { - setTitle(this.windowsCurrent.propertyTitle.get()); - } - // request all the widget redrawing - forceRedrawAll(); -} - -ewol::widget::WindowsShared EwolContext::getWindows() { - return this.windowsCurrent; -}; -void EwolContext::onResize( Vector2i _size) { - Log.verbose("Resize: " + _size); - forceRedrawAll(); -} - -void EwolContext::forceRedrawAll() { - if (this.windowsCurrent == null) { - return; - } - Vector2i size = getSize(); - this.windowsCurrent.setSize(Vector2f(size.x(), size.y())); - this.windowsCurrent.onChangeSize(); -} - diff --git a/src/org/atriasoft/ewol/context/EwolContext.java b/src/org/atriasoft/ewol/context/EwolContext.java index b8bc932..3249f9c 100644 --- a/src/org/atriasoft/ewol/context/EwolContext.java +++ b/src/org/atriasoft/ewol/context/EwolContext.java @@ -5,14 +5,21 @@ */ package org.atriasoft.ewol.context; +import org.atriasoft.echrono.Clock; +import org.atriasoft.etk.Uri; import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector2i; +import org.atriasoft.ewol.event.EntrySystem; import org.atriasoft.ewol.internal.Log; import org.atriasoft.ewol.object.ObjectManager; +import org.atriasoft.ewol.widget.Widget; import org.atriasoft.ewol.widget.WidgetManager; +import org.atriasoft.ewol.widget.Windows; import org.atriasoft.gale.Application; import org.atriasoft.gale.Gale; import org.atriasoft.gale.context.ClipboardList; import org.atriasoft.gale.context.CommandLine; +import org.atriasoft.gale.context.Context; import org.atriasoft.gale.key.KeyKeyboard; import org.atriasoft.gale.key.KeySpecial; import org.atriasoft.gale.key.KeyStatus; @@ -27,11 +34,11 @@ public abstract class EwolContext extends Application { * @brief From everyware in the program, we can get the context inteface. * @return current reference on the instance. */ - static EwolContext getContext() { + public static EwolContext getContext() { return curentInterface; } - private final EwolApplication application; //!< Application handle + private EwolApplication application; //!< Application handle public EwolApplication getApplication() { return this.application; @@ -74,11 +81,12 @@ public abstract class EwolContext extends Application { private final InputManager input; + @Override public void onCreate(final Context _context) { Log.info(" == > Ewol system create (BEGIN)"); // Add basic ewol translation: - etranslate::addPath("ewol", "DATA:///translate/ewol/?lib=ewol"); - etranslate::autoDetectLanguage(); + //etranslate::addPath("ewol", "DATA:///translate/ewol/?lib=ewol"); + //etranslate::autoDetectLanguage(); // By default we set 2 themes (1 color and 1 shape ...) : etk::theme::setNameDefault("GUI", "shape/square/"); etk::theme::setNameDefault("COLOR", "color/black/"); @@ -87,10 +95,10 @@ public abstract class EwolContext extends Application { if ( _context.getCmd().get(iii) == "-h" || _context.getCmd().get(iii) == "--help") { Log.print("ewol - help : "); - Log.print(" " + etk::getApplicationName() + " [options]"); + Log.print(" xxxxxxxxxxxxx [options]"); Log.print(" -h/--help: Display this help"); Log.print(" example:"); - Log.print(" " + etk::getApplicationName() + " --help"); + Log.print(" xxxxxxxxxxxxx --help"); // this is a global help system does not remove it continue; } else { @@ -100,10 +108,13 @@ public abstract class EwolContext extends Application { --iii; } - Log.info("EWOL v:" + ewol::getVersion()); + //Log.info("EWOL v:" + ewol::getVersion()); // force a recalculation /* - requestUpdateSize(); + requestUpdateSize(){ + Context context = gale::getContext(); + context.requestUpdateSize(); + } #if defined(__EWOL_ANDROID_ORIENTATION_LANDSCAPE__) forceOrientation(ewol::screenLandscape); #elif defined(__EWOL_ANDROID_ORIENTATION_PORTRAIT__) @@ -112,40 +123,43 @@ public abstract class EwolContext extends Application { forceOrientation(ewol::screenAuto); #endif */ - EwolApplication appl = this.application; + final EwolApplication appl = this.application; if (appl == null) { Log.error(" == > Create without application"); return; } - appl.onCreate(*this); + appl.onCreate(this); Log.info(" == > Ewol system create (END)"); } - public abstract void onStart(final Context _context) { + @Override + public void onStart(final Context _context) { Log.info(" == > Ewol system start (BEGIN)"); - EwolApplication appl = this.application; + final EwolApplication appl = this.application; if (appl == null) { // TODO : Request exit of the application .... with error ... return; } - appl.onStart(*this); + appl.onStart(this); Log.info(" == > Ewol system start (END)"); } - public abstract void onResume(final Context _context){ + @Override + public void onResume(final Context _context) { Log.info(" == > Ewol system resume (BEGIN)"); - EwolApplication appl = this.application; + final EwolApplication appl = this.application; if (appl == null) { return; } - appl.onResume(*this); + appl.onResume(this); Log.info(" == > Ewol system resume (END)"); } - public abstract void onRegenerateDisplay(final Context _context) { + @Override + public void onRegenerateDisplay(final Context _context) { //Log.info("REGENERATE_DISPLAY"); // check if the user selected a windows - ewol::widget::WindowsShared window = this.windowsCurrent; + final Windows window = this.windowsCurrent; if (window == null) { Log.debug("No windows ..."); return; @@ -158,49 +172,53 @@ public abstract class EwolContext extends Application { //markDrawingIsNeeded(); } - public abstract void onDraw(final Context _context) { + @Override + public void onDraw(final Context _context) { //Log.info("DRAW"); // clean internal data... this.objectManager.cleanInternalRemoved(); // real draw... - ewol::widget::WindowsShared window = this.windowsCurrent; + final Windows window = this.windowsCurrent; if (window == null) { return; } window.sysDraw(); } - public abstract void onPause(final Context _context){ + @Override + public void onPause(final Context _context) { Log.info(" == > Ewol system pause (BEGIN)"); - EwolApplication appl = this.application; + final EwolApplication appl = this.application; if (appl == null) { return; } - appl.onPause(*this); + appl.onPause(this); Log.info(" == > Ewol system pause (END)"); } - public abstract void onStop(final Context _context){ + @Override + public void onStop(final Context _context) { Log.info(" == > Ewol system stop (BEGIN)"); - EwolApplication appl = this.application; + final EwolApplication appl = this.application; if (appl == null) { return; } - appl.onStop(*this); + appl.onStop(this); Log.info(" == > Ewol system stop (END)"); } - public abstract void onDestroy(final Context _context){ + @Override + public void onDestroy(final Context _context) { Log.info(" == > Ewol system destroy (BEGIN)"); // Remove current windows - this.windowsCurrent.reset(); + this.windowsCurrent = null; // clean all widget and sub widget with their resources: this.objectManager.cleanInternalRemoved(); - EwolApplication appl = this.application; + final EwolApplication appl = this.application; if (appl != null) { // call application to uninit - appl.onDestroy(*this); - this.application.reset(); + appl.onDestroy(this); + this.application = null; } // internal clean elements this.objectManager.cleanInternalRemoved(); @@ -211,29 +229,30 @@ public abstract class EwolContext extends Application { Log.info(" == > Ewol system destroy (END)"); } - public abstract void onKillDemand(final Context _context){ + @Override + public void onKillDemand(final Context _context) { Log.info(" == > User demand a destroy (BEGIN)"); - EwolApplication appl = this.application; + final EwolApplication appl = this.application; if (appl == null) { exit(0); return; } - appl.onKillDemand(*this); + appl.onKillDemand(this); Log.info(" == > User demand a destroy (END)"); } - public abstract void onPointer(final KeyType _type, final int _pointerID, final Vector2f _pos, final KeyStatus _state) { + public void onPointer(final KeyType _type, final int _pointerID, final Vector2f _pos, final KeyStatus _state) { switch (_state) { - case KeyStatus::move: + case move: //Log.debug("Receive MSG : THREAD_INPUT_MOTION"); this.input.motion(_type, _pointerID, _pos); break; - case KeyStatus::down: - case KeyStatus::downRepeate: + case down: + case downRepeate: //Log.debug("Receive MSG : THREAD_INPUT_STATE"); this.input.state(_type, _pointerID, true, _pos); break; - case KeyStatus::up: + case up: //Log.debug("Receive MSG : THREAD_INPUT_STATE"); this.input.state(_type, _pointerID, false, _pos); break; @@ -244,7 +263,7 @@ public abstract class EwolContext extends Application { } @Override - public abstract void onKeyboard(final KeySpecial _special, final KeyKeyboard _type, final Character _value, final KeyStatus _state) { + public void onKeyboard(final KeySpecial _special, final KeyKeyboard _type, final Character _value, final KeyStatus _state) { Log.verbose("event {" + _special + "} " + _type + " " + _value + " " + _state); // store the keyboard special key status for mouse event... this.input.setLastKeyboardSpecial(_special); @@ -252,49 +271,38 @@ public abstract class EwolContext extends Application { // No windows ... return; } - boolean repeate = (_state == KeyStatus::downRepeate); - boolean isDown = (_state == KeyStatus::downRepeate) - || (_state == KeyStatus::down); - if (this.windowsCurrent.onEventShortCut(_special, - _value, - _type, - isDown) == true) { + final boolean repeate = (_state == KeyStatus.downRepeate); + final boolean isDown = (_state == KeyStatus.downRepeate) || (_state == KeyStatus.down); + if (this.windowsCurrent.onEventShortCut(_special, _value, _type, isDown) == true) { // Keep a shortcut ... return; } // get the current focused Widget : - Widget tmpWidget = this.widgetManager.focusGet(); + final Widget tmpWidget = this.widgetManager.focusGet(); if (tmpWidget == null) { // no Widget ... return; } // check if the widget allow repeating key events. //Log.info("repeating test :" + repeate + " widget=" + tmpWidget.getKeyboardRepeate() + " state=" + isDown); - if( repeate == false - || ( repeate == true - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM tmpWidget.getKeyboardRepeat() == true) ) { + if (repeate == false || (repeate == true && tmpWidget.getKeyboardRepeat() == true)) { // check Widget shortcut - if (tmpWidget.onEventShortCut(_special, - _value, - _type, - isDown) == false) { + if (tmpWidget.onEventShortCut(_special, _value, _type, isDown) == false) { // generate the direct event ... - if (_type == KeyKeyboard::character) { - ewol::event::EntrySystem tmpEntryEvent(KeyKeyboard::character, - KeyStatus::up, - _special, - _value); - if(isDown == true) { - tmpEntryEvent.this.event.setStatus(KeyStatus::down); + if (_type == KeyKeyboard.character) { + final EntrySystem tmpEntryEvent; + if (isDown == true) { + tmpEntryEvent = new EntrySystem(KeyKeyboard.character, KeyStatus.down, _special, _value); + } else { + tmpEntryEvent = new EntrySystem(KeyKeyboard.character, KeyStatus.up, _special, _value); } tmpWidget.systemEventEntry(tmpEntryEvent); } else { // THREAD_KEYBORAD_MOVE - ewol::event::EntrySystem tmpEntryEvent(_type, - KeyStatus::up, - _special, - 0); - if(isDown == true) { - tmpEntryEvent.this.event.setStatus(KeyStatus::down); + final EntrySystem tmpEntryEvent; + if (isDown == true) { + tmpEntryEvent = new EntrySystem(KeyKeyboard.character, KeyStatus.down, _special, null); + } else { + tmpEntryEvent = new EntrySystem(KeyKeyboard.character, KeyStatus.up, _special, null); } tmpWidget.systemEventEntry(tmpEntryEvent); } @@ -319,7 +327,7 @@ public abstract class EwolContext extends Application { this.input.newLayerSet(); } - private final Windows windowsCurrent = null; //!< current displayed windows + private Windows windowsCurrent = null; //!< current displayed windows /** * @brief set the current windows to display : @@ -336,7 +344,7 @@ public abstract class EwolContext extends Application { this.widgetManager.focusSetDefault(_windows); // display the title of the Windows: if (this.windowsCurrent != null) { - setTitle(this.windowsCurrent.propertyTitle.get()); + setTitle(this.windowsCurrent.propertyTitle); } // request all the widget redrawing forceRedrawAll(); @@ -357,8 +365,8 @@ public abstract class EwolContext extends Application { if (this.windowsCurrent == null) { return; } - final Vector2i size = getSize(); - this.windowsCurrent.setSize(Vector2f(size.x(), size.y())); + final Vector2f size = getSize(); + this.windowsCurrent.setSize(new Vector2f((int) size.x, (int) size.y)); this.windowsCurrent.onChangeSize(); } @@ -420,7 +428,7 @@ public abstract class EwolContext extends Application { * @brief Request a display after call a resize */ public void requestUpdateSize() { - final Context context = gale::getContext(); + final Context context = Gale.getContext(); context.requestUpdateSize(); } diff --git a/src/org/atriasoft/ewol/context/InputManager.cpp b/src/org/atriasoft/ewol/context/InputManager.cpp deleted file mode 100644 index 40810b2..0000000 --- a/src/org/atriasoft/ewol/context/InputManager.cpp +++ /dev/null @@ -1,502 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -ETK_DECLARE_TYPE(ewol::context::InputManager); - -#define EVENT_DEBUG EWOL_VERBOSE -//#define EVENT_DEBUG EWOL_DEBUG - -void ewol::context::InputManager::calculateLimit() { - this.eventInputLimit.sepatateTime = echrono::Duration(echrono::milliseconds(300)); - this.eventInputLimit.DpiOffset = this.dpi*100; - this.eventMouseLimit.sepatateTime = echrono::Duration(echrono::milliseconds(300)); - this.eventMouseLimit.DpiOffset = float(this.dpi)*0.1f; -} - -void ewol::context::InputManager::setDpi(int newDPI) { - this.dpi = newDPI; - // recalculate the DPI system ... - calculateLimit(); -} - -boolean ewol::context::InputManager::localEventInput(KeyType _type, - Widget _destWidget, - int _IdInput, - KeyStatus _status, - Vector2f _pos) { - if (_destWidget != null) { - if ( _type == KeyType::mouse - || _type == KeyType::finger) { - // create the system Event : - ewol::event::InputSystem tmpEventSystem(_type, _status, _IdInput, _pos, _destWidget, 0, this.specialKey); // TODO : set the real ID ... - // generate the event : - return _destWidget.systemEventInput(tmpEventSystem); - } else { - return false; - } - } - return false; -} - -void ewol::context::InputManager::abortElement(InputPoperty *_eventTable, - int _idInput, - KeyType _type) { - if (_eventTable == null) { - return; - } - if (_eventTable[_idInput].isUsed == true) { - localEventInput(_type, - _eventTable[_idInput].curentWidgetEvent.lock(), - _eventTable[_idInput].destinationInputId, - KeyStatus::abort, - _eventTable[_idInput].posEvent); - } -} - -void ewol::context::InputManager::cleanElement(InputPoperty *_eventTable, - int _idInput) { - if (_eventTable == null) { - return; - } - //Log.info("CleanElement[" + idInput + "] = @" + (long)eventTable); - _eventTable[_idInput].isUsed = false; - _eventTable[_idInput].destinationInputId = 0; - _eventTable[_idInput].lastTimeEvent.reset(); - _eventTable[_idInput].curentWidgetEvent.reset(); - _eventTable[_idInput].origin.setValue(0,0); - _eventTable[_idInput].size.setValue(99999999,99999999); - _eventTable[_idInput].downStart.setValue(0,0); - _eventTable[_idInput].isDown = false; - _eventTable[_idInput].isInside = false; - _eventTable[_idInput].nbClickEvent = 0; - _eventTable[_idInput].posEvent.setValue(0,0); -} - -void ewol::context::InputManager::transfertEvent(Widget _source, Widget _destination) { - if( _source == null - || _destination == null) { - // prevent errors ... - return; - } - for(int iii=0; iii" + this.eventInputSaved[iii].destinationInputId + " [EVENT_INPUT_TYPE_ABORT] " + this.eventInputSaved[iii].posEvent); - localEventInput(KeyType::finger, tmpWidget, this.eventInputSaved[iii].destinationInputId, KeyStatus::abort, this.eventInputSaved[iii].posEvent); - // set the new widget ... - this.eventInputSaved[iii].curentWidgetEvent = _destination; - // inform the widget that he receive the event property now... - EVENT_DEBUG("GUI : Input ID=" + iii + " == >" + this.eventInputSaved[iii].destinationInputId + " [EVENT_INPUT_TYPE_TRANSFERT] " + this.eventInputSaved[iii].posEvent); - localEventInput(KeyType::finger, _destination, this.eventInputSaved[iii].destinationInputId, KeyStatus::transfert, this.eventInputSaved[iii].posEvent); - } - tmpWidget = this.eventMouseSaved[iii].curentWidgetEvent.lock(); - if (tmpWidget == _source) { - // inform the widget that it does not receive the event now - EVENT_DEBUG("GUI : Input ID=" + iii + " == >" + this.eventMouseSaved[iii].destinationInputId + " [EVENT_INPUT_TYPE_ABORT] " + this.eventMouseSaved[iii].posEvent); - localEventInput(KeyType::mouse, tmpWidget, this.eventMouseSaved[iii].destinationInputId, KeyStatus::abort, this.eventMouseSaved[iii].posEvent); - // set the new widget ... - this.eventMouseSaved[iii].curentWidgetEvent = _destination; - // inform the widget that he receive the event property now... - EVENT_DEBUG("GUI : Input ID=" + iii + " == >" + this.eventMouseSaved[iii].destinationInputId + " [EVENT_INPUT_TYPE_TRANSFERT] " + this.eventMouseSaved[iii].posEvent); - localEventInput(KeyType::mouse, _destination, this.eventMouseSaved[iii].destinationInputId, KeyStatus::transfert, this.eventMouseSaved[iii].posEvent); - } - } -} - -void ewol::context::InputManager::grabPointer(Widget _widget) { - if(_widget == null) { - return; - } - this.grabWidget = _widget; - /* TODO : - this.context.grabPointerEvents(true, _widget.getOrigin() - + Vector2i(_widget.getSize().x()/2.0f, - _widget.getSize().y()/2.0f) ); - */ -} - -void ewol::context::InputManager::unGrabPointer() { - this.grabWidget.reset(); - // TODO: this.context.grabPointerEvents(false, Vector2f(0,0)); -} - -void ewol::context::InputManager::newLayerSet() { - for(int iii=0; iii the it was finger event ... -void ewol::context::InputManager::motion(KeyType _type, - int _pointerID, - Vector2f _pos) { - EVENT_DEBUG("motion event : " + _type + " " + _pointerID + " " + _pos); - if (MAX_MANAGE_INPUT <= _pointerID) { - // reject pointer == > out of IDs... - return; - } - InputPoperty *eventTable = null; - if (_type == KeyType::mouse) { - eventTable = this.eventMouseSaved; - } else if (_type == KeyType::finger) { - eventTable = this.eventInputSaved; - } else { - Log.error("Unknown type of event"); - return; - } - if( _pointerID > MAX_MANAGE_INPUT - || _pointerID < 0) { - // not manage input - return; - } - ewol::widget::Windows tmpWindows = this.context.getWindows(); - // special case for the mouse event 0 that represent the hover event of the system : - if ( _type == KeyType::mouse - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM _pointerID == 0) { - // this event is all time on the good widget ... and manage the enter and leave ... - // NOTE : the "layer widget" force us to get the widget at the specific position all the time : - Widget tmpWidget; - if (this.grabWidget.lock() != null) { - // grab all events ... - tmpWidget = this.grabWidget.lock(); - } else { - if (tmpWindows != null) { - tmpWidget = tmpWindows.getWidgetAtPos(_pos); - } - } - if( tmpWidget != eventTable[_pointerID].curentWidgetEvent.lock() - || ( eventTable[_pointerID].isInside == true - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM ( eventTable[_pointerID].origin.x() > _pos.x() - || eventTable[_pointerID].origin.y() > _pos.y() - || (eventTable[_pointerID].origin.x() + eventTable[_pointerID].size.x()) < _pos.x() - || (eventTable[_pointerID].origin.y() + eventTable[_pointerID].size.y()) < _pos.y()) ) ) { - eventTable[_pointerID].isInside = false; - EVENT_DEBUG("GUI : Input ID=" + _pointerID + " == >" + eventTable[_pointerID].destinationInputId + " [LEAVE] " + _pos); - eventTable[_pointerID].posEvent = _pos; - localEventInput(_type, - eventTable[_pointerID].curentWidgetEvent.lock(), - eventTable[_pointerID].destinationInputId, - KeyStatus::leave, - _pos); - } - if (eventTable[_pointerID].isInside == false) { - // set the element inside ... - eventTable[_pointerID].isInside = true; - // get destination widget : - eventTable[_pointerID].curentWidgetEvent = tmpWidget; - if (tmpWidget == null) { - eventTable[_pointerID].isInside = false; - } else { - eventTable[_pointerID].origin = tmpWidget.getOrigin(); - eventTable[_pointerID].size = tmpWidget.getSize(); - } - eventTable[_pointerID].destinationInputId = 0; - EVENT_DEBUG("GUI : Input ID=" + _pointerID - + " == >" + eventTable[_pointerID].destinationInputId - + " [ENTER] " + _pos); - eventTable[_pointerID].posEvent = _pos; - localEventInput(_type, - tmpWidget, - eventTable[_pointerID].destinationInputId, - KeyStatus::enter, - _pos); - } - EVENT_DEBUG("GUI : Input ID=" + _pointerID - + " == >" + eventTable[_pointerID].destinationInputId - + " [MOVE] " + _pos); - eventTable[_pointerID].posEvent = _pos; - localEventInput(_type, - tmpWidget, - eventTable[_pointerID].destinationInputId, - KeyStatus::move, - _pos); - } else if (eventTable[_pointerID].isUsed == true) { - if (eventTable[_pointerID].isInside == true) { - if( eventTable[_pointerID].origin.x() > _pos.x() - || eventTable[_pointerID].origin.y() > _pos.y() - || (eventTable[_pointerID].origin.x() + eventTable[_pointerID].size.x()) < _pos.x() - || (eventTable[_pointerID].origin.y() + eventTable[_pointerID].size.y()) < _pos.y()) { - eventTable[_pointerID].isInside = false; - EVENT_DEBUG("GUI : Input ID=" + _pointerID - + " == >" + eventTable[_pointerID].destinationInputId - + " [LEAVE] " + _pos); - eventTable[_pointerID].posEvent = _pos; - localEventInput(_type, - eventTable[_pointerID].curentWidgetEvent.lock(), - eventTable[_pointerID].destinationInputId, - KeyStatus::leave, - _pos); - } - } else { - if( ( eventTable[_pointerID].origin.x() <= _pos.x() - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM (eventTable[_pointerID].origin.x() + eventTable[_pointerID].size.x()) >= _pos.x() ) - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM ( eventTable[_pointerID].origin.y() <= _pos.y() - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM (eventTable[_pointerID].origin.y() + eventTable[_pointerID].size.y()) >= _pos.y() ) ) { - eventTable[_pointerID].isInside = true; - EVENT_DEBUG("GUI : Input ID=" + _pointerID - + " == >" + eventTable[_pointerID].destinationInputId - + " [ENTER] " + _pos); - eventTable[_pointerID].posEvent = _pos; - localEventInput(_type, - eventTable[_pointerID].curentWidgetEvent.lock(), - eventTable[_pointerID].destinationInputId, - KeyStatus::enter, - _pos); - } - } - EVENT_DEBUG("GUI : Input ID=" + _pointerID - + " == >" + eventTable[_pointerID].destinationInputId - + " [MOVE] " + _pos); - eventTable[_pointerID].posEvent = _pos; - localEventInput(_type, - eventTable[_pointerID].curentWidgetEvent.lock(), - eventTable[_pointerID].destinationInputId, - KeyStatus::move, - _pos); - } -} - -void ewol::context::InputManager::state(KeyType _type, - int _pointerID, - boolean _isDown, - Vector2f _pos) { - if (_pointerID >= MAX_MANAGE_INPUT) { - // reject pointer == > out of IDs... - return; - } - EVENT_DEBUG("event pointerId=" + _pointerID); - // convert position in open-GL coordonates ... - InputPoperty *eventTable = null; - InputLimit localLimit; - if (_type == KeyType::mouse) { - eventTable = this.eventMouseSaved; - localLimit = this.eventMouseLimit; - } else if (_type == KeyType::finger) { - eventTable = this.eventInputSaved; - localLimit = this.eventInputLimit; - } else { - Log.error("Unknown type of event"); - return; - } - if( _pointerID > MAX_MANAGE_INPUT - || _pointerID <= 0) { - // not manage input - return; - } - // get the curent time ... - echrono::Clock currentTime = echrono::Clock::now(); - ewol::widget::Windows tmpWindows = this.context.getWindows(); - - if (_isDown == true) { - EVENT_DEBUG("GUI : Input ID=" + _pointerID - + " == >" + eventTable[_pointerID].destinationInputId - + " [DOWN] " + _pos); - if(eventTable[_pointerID].isUsed == true) { - // we have an event previously ... check delay between click and offset position - if (currentTime - eventTable[_pointerID].lastTimeEvent > localLimit.sepatateTime) { - cleanElement(eventTable, _pointerID); - } else if( etk::abs(eventTable[_pointerID].downStart.x() - _pos.x()) >= localLimit.DpiOffset - || etk::abs(eventTable[_pointerID].downStart.y() - _pos.y()) >= localLimit.DpiOffset ){ - cleanElement(eventTable, _pointerID); - } - } - if(eventTable[_pointerID].isUsed == true) { - // save start time - eventTable[_pointerID].lastTimeEvent = currentTime; - // generate DOWN Event - EVENT_DEBUG("GUI : Input ID=" + _pointerID - + " == >" + eventTable[_pointerID].destinationInputId - + " [DOWN] " + _pos); - eventTable[_pointerID].posEvent = _pos; - localEventInput(_type, - eventTable[_pointerID].curentWidgetEvent.lock(), - eventTable[_pointerID].destinationInputId, - KeyStatus::down, - _pos); - } else { - // Mark it used : - eventTable[_pointerID].isUsed = true; - // Save current position : - eventTable[_pointerID].downStart = _pos; - // save start time - eventTable[_pointerID].lastTimeEvent = currentTime; - // set the element inside ... - eventTable[_pointerID].isInside = true; - Widget tmpWidget = this.grabWidget.lock(); - // get destination widget : - if(tmpWindows != null) { - if ( tmpWidget != null - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM _type == KeyType::mouse) { - eventTable[_pointerID].curentWidgetEvent = tmpWidget; - } else { - tmpWidget = tmpWindows.getWidgetAtPos(_pos); - eventTable[_pointerID].curentWidgetEvent = tmpWidget; - if (tmpWidget != null) { - EVENT_DEBUG("Get widget at pos=" + _pos + " type: " + tmpWidget.getObjectType()); - } else { - EVENT_DEBUG("Get widget at pos=" + _pos + " NO WIDGET"); - } - } - } else { - eventTable[_pointerID].curentWidgetEvent.reset(); - } - tmpWidget = eventTable[_pointerID].curentWidgetEvent.lock(); - if (tmpWidget != null) { - eventTable[_pointerID].origin = tmpWidget.getOrigin(); - eventTable[_pointerID].size = tmpWidget.getSize(); - eventTable[_pointerID].destinationInputId = localGetDestinationId(_type, tmpWidget, _pointerID); - } else { - eventTable[_pointerID].destinationInputId = -1; - } - // generate DOWN Event - EVENT_DEBUG("GUI : Input ID=" + _pointerID - + " == >" + eventTable[_pointerID].destinationInputId - + " [DOWN] " + _pos); - eventTable[_pointerID].posEvent = _pos; - localEventInput(_type, - tmpWidget, - eventTable[_pointerID].destinationInputId, - KeyStatus::down, - _pos); - } - } else { - EVENT_DEBUG("GUI : Input ID=" + _pointerID - + " == >" + eventTable[_pointerID].destinationInputId - + " [UP] " + _pos); - Widget tmpWidget = eventTable[_pointerID].curentWidgetEvent.lock(); - if(eventTable[_pointerID].isUsed == false) { - // bad case ... ??? - Log.debug("Up event without previous down ... "); - // Mark it un-used : - eventTable[_pointerID].isUsed = false; - // revove the widget ... - eventTable[_pointerID].curentWidgetEvent.reset(); - } else if (tmpWidget == null) { - // The widget has been removed: - EVENT_DEBUG(" Object Removed ..."); - // Mark it un-used : - eventTable[_pointerID].isUsed = false; - // revove the widget ... - eventTable[_pointerID].curentWidgetEvent.reset(); - } else { - // generate UP Event - EVENT_DEBUG("GUI : Input ID=" + _pointerID - + " == >" + eventTable[_pointerID].destinationInputId - + " [UP] " + _pos); - eventTable[_pointerID].posEvent = _pos; - // send up event after the single event to prevent multiple widget getting elements - localEventInput(_type, - tmpWidget, - _pointerID, - KeyStatus::up, - _pos); - // generate event (single) - if( etk::abs(eventTable[_pointerID].downStart.x() - _pos.x()) < localLimit.DpiOffset - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM etk::abs(eventTable[_pointerID].downStart.y() - _pos.y()) < localLimit.DpiOffset ){ - // Save current position : - eventTable[_pointerID].downStart = _pos; - // save start time - eventTable[_pointerID].lastTimeEvent = currentTime; - int nbClickMax = 0; - if(tmpWidget != null) { - nbClickMax = tmpWidget.getMouseLimit(); - if (nbClickMax>5) { - nbClickMax = 5; - } - } - // in grab mode the single to quinte event are not generated .... - if( ( this.grabWidget.lock() == null - || _type != KeyType::mouse ) - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM eventTable[_pointerID].nbClickEvent < nbClickMax) { - // generate event SINGLE : - eventTable[_pointerID].nbClickEvent++; - EVENT_DEBUG("GUI : Input ID=" + _pointerID - + " == >" + eventTable[_pointerID].destinationInputId - + " [" + eventTable[_pointerID].nbClickEvent + "] " + _pos); - eventTable[_pointerID].posEvent = _pos; - localEventInput(_type, - tmpWidget, - eventTable[_pointerID].destinationInputId, - (KeyStatus)(uint(KeyStatus::pressSingle) + eventTable[_pointerID].nbClickEvent-1), - _pos); - if( eventTable[_pointerID].nbClickEvent >= nbClickMax) { - eventTable[_pointerID].nbClickEvent = 0; - } - } else { - eventTable[_pointerID].nbClickEvent = 0; - } - } - // send up event after the single event to prevent multiple widget getting elements - localEventInput(_type, - tmpWidget, - _pointerID, - KeyStatus::upAfter, - _pos); - // specific for tuch event - if (_type == KeyType::finger) { - cleanElement(eventTable, _pointerID); - } - } - } -} - - diff --git a/src/org/atriasoft/ewol/context/InputManager.java b/src/org/atriasoft/ewol/context/InputManager.java index c6dd671..4e2ea31 100644 --- a/src/org/atriasoft/ewol/context/InputManager.java +++ b/src/org/atriasoft/ewol/context/InputManager.java @@ -3,118 +3,465 @@ * @copyright 2011, Edouard DUPIN, all right reserved * @license MPL v2.0 (see license file) */ -#pragma once -#include +package org.atriasoft.ewol.context; -#define MAX_MANAGE_INPUT (15) +import java.lang.ref.WeakReference; -namespace ewol { - namespace context { - /** - * @brief internal structure - * @not_in_doc - */ - class InputPoperty { - public: - boolean isUsed; - int destinationInputId; - echrono::Clock lastTimeEvent; - WeakReference curentWidgetEvent; - Vector2f origin; - Vector2f size; - Vector2f downStart; - Vector2f posEvent; - boolean isDown; - boolean isInside; - int nbClickEvent; // 0 .. 1 .. 2 .. 3 - }; - - /** - * @brief internal structure - * @not_in_doc - */ - class InputLimit { - public: - echrono::Duration sepatateTime; - int DpiOffset; - }; - class Context; - class InputManager{ - // special grab pointer mode : - private: - WeakReference this.grabWidget; //!< widget that grab the curent pointer. - private: - int this.dpi; - InputLimit this.eventInputLimit; - InputLimit this.eventMouseLimit; - void calculateLimit(); - InputPoperty this.eventInputSaved[MAX_MANAGE_INPUT]; - InputPoperty this.eventMouseSaved[MAX_MANAGE_INPUT]; - void abortElement(InputPoperty* _eventTable, int _idInput, KeyType _type); - void cleanElement(InputPoperty* _eventTable, int _idInput); - /** - * @brief generate the event on the destinated widget. - * @param[in] _type Type of the event that might be sended. - * @param[in] _destWidget Pointer on the requested widget that element might be sended - * @param[in] _IdInput Id of the event (PC : [0..9] and touch : [1..9]) - * @param[in] _typeEvent type of the eventg generated - * @param[in] _pos position of the event - * @return true if event has been greped - */ - boolean localEventInput(KeyType _type, - Widget _destWidget, - int _IdInput, - KeyStatus _typeEvent, - Vector2f _pos); - /** - * @brief convert the system event id in the correct EWOL id depending of the system management mode - * This function find the next input id unused on the specifiic widget - * == > on PC, the ID does not change (GUI is not the same) - * @param[in] _type Type of the kay event. - * @param[in] _destWidget Pointer of the widget destination - * @param[in] _realInputId system Id - * @return the ewol input id - */ - int localGetDestinationId(KeyType _type, - Widget _destWidget, - int _realInputId); - private: - EwolContext this.context; - public: - InputManager(EwolContext _context); - ~InputManager(); - void setDpi(int _newDPI); - - // note if id<0 == > the it was finger event ... - void motion(KeyType _type, int _pointerID, Vector2f _pos ); - void state(KeyType _type, int _pointerID, boolean _isDown, Vector2f _pos); - public: - /** - * @brief a new layer on the windows is set == > might remove all the property of the current element ... - */ - void newLayerSet(); - /** - * @brief This is to transfert the event from one widget to another one - * @param _source the widget where the event came from - * @param _destination the widget where the event mitgh be generated now - */ - void transfertEvent(Widget _source, Widget _destination); - /** - * @brief This fonction lock the pointer properties to move in relative instead of absolute - * @param[in] _widget The widget that lock the pointer events - */ - void grabPointer(Widget _widget); - /** - * @brief This fonction un-lock the pointer properties to move in relative instead of absolute - */ - void unGrabPointer(); - private: - KeySpecial this.specialKey; - public: - void setLastKeyboardSpecial( KeySpecial _specialKey) { - this.specialKey = _specialKey; - } - }; - }; +import org.atriasoft.echrono.Clock; +import org.atriasoft.echrono.Duration; +import org.atriasoft.etk.math.FMath; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.ewol.event.InputSystem; +import org.atriasoft.ewol.internal.Log; +import org.atriasoft.ewol.widget.Widget; +import org.atriasoft.ewol.widget.Windows; +import org.atriasoft.gale.key.KeySpecial; +import org.atriasoft.gale.key.KeyStatus; +import org.atriasoft.gale.key.KeyType; + +/** + * @brief internal structure + */ +class InputLimit { + public Duration sepatateTime; + public int DpiOffset; }; +class InputManager { + private final static int MAX_MANAGE_INPUT = 15; + + // special grab pointer mode : + private WeakReference grabWidget = null; //!< widget that grab the curent pointer. + private int dpi; + private InputLimit eventInputLimit; + private InputLimit eventMouseLimit; + private final InputPoperty[] eventInputSaved = new InputPoperty[MAX_MANAGE_INPUT]; + private final InputPoperty[] eventMouseSaved = new InputPoperty[MAX_MANAGE_INPUT]; + + private final EwolContext context; + private KeySpecial specialKey; + + public InputManager(final EwolContext _context) { + this.context = _context; + setDpi(200); + Log.info("Init (start)"); + for (int iii = 0; iii < MAX_MANAGE_INPUT; iii++) { + // remove the property of this input ... + cleanElement(this.eventInputSaved, iii); + cleanElement(this.eventMouseSaved, iii); + } + Log.info("Init (end)"); + } + + public void abortElement(final InputPoperty[] _eventTable, final int _idInput, final KeyType _type) { + if (_eventTable == null) { + return; + } + if (_eventTable[_idInput].isUsed == true) { + localEventInput(_type, _eventTable[_idInput].curentWidgetEvent.get(), _eventTable[_idInput].destinationInputId, KeyStatus.abort, _eventTable[_idInput].posEvent); + } + } + + private void calculateLimit() { + this.eventInputLimit.sepatateTime = Duration.milliseconds(300); + this.eventInputLimit.DpiOffset = this.dpi * 100; + this.eventMouseLimit.sepatateTime = Duration.milliseconds(300); + this.eventMouseLimit.DpiOffset = (int) (this.dpi * 0.1f); + } + + public void cleanElement(final InputPoperty[] eventMouseSaved2, final int _idInput) { + if (eventMouseSaved2 == null) { + return; + } + //Log.info("CleanElement[" + idInput + "] = @" + (long)eventTable); + eventMouseSaved2[_idInput].isUsed = false; + eventMouseSaved2[_idInput].destinationInputId = 0; + eventMouseSaved2[_idInput].lastTimeEvent = new Clock(); + eventMouseSaved2[_idInput].curentWidgetEvent = null; + eventMouseSaved2[_idInput].origin.setValue(0, 0); + eventMouseSaved2[_idInput].size.setValue(99999999, 99999999); + eventMouseSaved2[_idInput].downStart.setValue(0, 0); + eventMouseSaved2[_idInput].isDown = false; + eventMouseSaved2[_idInput].isInside = false; + eventMouseSaved2[_idInput].nbClickEvent = 0; + eventMouseSaved2[_idInput].posEvent.setValue(0, 0); + } + + /** + * @brief This fonction lock the pointer properties to move in relative instead of absolute + * @param[in] _widget The widget that lock the pointer events + */ + public void grabPointer(final Widget _widget) { + if (_widget == null) { + return; + } + this.grabWidget = new WeakReference<>(_widget); + /* TODO : + this.context.grabPointerEvents(true, _widget.getOrigin() + + Vector2i(_widget.getSize().x/2.0f, + _widget.getSize().y/2.0f) ); + */ + } + + /** + * @brief generate the event on the destinated widget. + * @param[in] _type Type of the event that might be sended. + * @param[in] _destWidget Pointer on the requested widget that element might be sended + * @param[in] _IdInput Id of the event (PC : [0..9] and touch : [1..9]) + * @param[in] _typeEvent type of the eventg generated + * @param[in] _pos position of the event + * @return true if event has been greped + */ + public boolean localEventInput(final KeyType _type, final Widget _destWidget, final int _IdInput, final KeyStatus _status, final Vector2f _pos) { + if (_destWidget != null) { + if (_type == KeyType.mouse || _type == KeyType.finger) { + // create the system Event : + // TODO : set the real ID ... + final InputSystem tmpEventSystem = new InputSystem(_type, _status, _IdInput, _pos, _destWidget, 0, this.specialKey); + // generate the event : + return _destWidget.systemEventInput(tmpEventSystem); + } else { + return false; + } + } + return false; + } + + /** + * @brief convert the system event id in the correct EWOL id depending of the system management mode + * This function find the next input id unused on the specifiic widget + * == > on PC, the ID does not change (GUI is not the same) + * @param[in] _type Type of the kay event. + * @param[in] _destWidget Pointer of the widget destination + * @param[in] _realInputId system Id + * @return the ewol input id + */ + public int localGetDestinationId(final KeyType _type, final Widget _destWidget, final int _realInputId) { + if (_type == KeyType.finger) { + int lastMinimum = 0; + for (int iii = 0; iii < MAX_MANAGE_INPUT; iii++) { + if (true == this.eventInputSaved[iii].isUsed) { + final Widget tmpWidget = this.eventInputSaved[iii].curentWidgetEvent.get(); + if (tmpWidget == _destWidget) { + if (iii != _realInputId) { + lastMinimum = FMath.max(lastMinimum, this.eventInputSaved[iii].destinationInputId); + } + } + } + } + return lastMinimum + 1; + } + return _realInputId; + } + + // note if id<0 == > the it was finger event ... + public void motion(final KeyType _type, final int _pointerID, final Vector2f _pos) { + //Log.debug("motion event : " + _type + " " + _pointerID + " " + _pos); + if (MAX_MANAGE_INPUT <= _pointerID) { + // reject pointer == > out of IDs... + return; + } + InputPoperty[] eventTable = null; + if (_type == KeyType.mouse) { + eventTable = this.eventMouseSaved; + } else if (_type == KeyType.finger) { + eventTable = this.eventInputSaved; + } else { + Log.error("Unknown type of event"); + return; + } + if (_pointerID > MAX_MANAGE_INPUT || _pointerID < 0) { + // not manage input + return; + } + final Windows tmpWindows = this.context.getWindows(); + // special case for the mouse event 0 that represent the hover event of the system : + if (_type == KeyType.mouse && _pointerID == 0) { + // this event is all time on the good widget ... and manage the enter and leave ... + // NOTE : the "layer widget" force us to get the widget at the specific position all the time : + Widget tmpWidget = null; + if (this.grabWidget.get() != null) { + // grab all events ... + tmpWidget = this.grabWidget.get(); + } else if (tmpWindows != null) { + tmpWidget = tmpWindows.getWidgetAtPos(_pos); + } + if (tmpWidget != eventTable[_pointerID].curentWidgetEvent.get() + || (eventTable[_pointerID].isInside == true && (eventTable[_pointerID].origin.x > _pos.x || eventTable[_pointerID].origin.y > _pos.y + || (eventTable[_pointerID].origin.x + eventTable[_pointerID].size.x) < _pos.x || (eventTable[_pointerID].origin.y + eventTable[_pointerID].size.y) < _pos.y))) { + eventTable[_pointerID].isInside = false; + //Log.debug("GUI : Input ID=" + _pointerID + " == >" + eventTable[_pointerID].destinationInputId + " [LEAVE] " + _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, eventTable[_pointerID].curentWidgetEvent.get(), eventTable[_pointerID].destinationInputId, KeyStatus.leave, _pos); + } + if (eventTable[_pointerID].isInside == false) { + // set the element inside ... + eventTable[_pointerID].isInside = true; + // get destination widget : + eventTable[_pointerID].curentWidgetEvent = new WeakReference<>(tmpWidget); + if (tmpWidget == null) { + eventTable[_pointerID].isInside = false; + } else { + eventTable[_pointerID].origin = tmpWidget.getOrigin(); + eventTable[_pointerID].size = tmpWidget.getSize(); + } + eventTable[_pointerID].destinationInputId = 0; + //Log.debug("GUI : Input ID=" + _pointerID + " == >" + eventTable[_pointerID].destinationInputId + " [ENTER] " + _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, tmpWidget, eventTable[_pointerID].destinationInputId, KeyStatus.enter, _pos); + } + //Log.debug("GUI : Input ID=" + _pointerID + " == >" + eventTable[_pointerID].destinationInputId + " [MOVE] " + _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, tmpWidget, eventTable[_pointerID].destinationInputId, KeyStatus.move, _pos); + } else if (eventTable[_pointerID].isUsed == true) { + if (eventTable[_pointerID].isInside == true) { + if (eventTable[_pointerID].origin.x > _pos.x || eventTable[_pointerID].origin.y > _pos.y || (eventTable[_pointerID].origin.x + eventTable[_pointerID].size.x) < _pos.x + || (eventTable[_pointerID].origin.y + eventTable[_pointerID].size.y) < _pos.y) { + eventTable[_pointerID].isInside = false; + //Log.debug("GUI : Input ID=" + _pointerID + " == >" + eventTable[_pointerID].destinationInputId + " [LEAVE] " + _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, eventTable[_pointerID].curentWidgetEvent.get(), eventTable[_pointerID].destinationInputId, KeyStatus.leave, _pos); + } + } else if ((eventTable[_pointerID].origin.x <= _pos.x && (eventTable[_pointerID].origin.x + eventTable[_pointerID].size.x) >= _pos.x) + && (eventTable[_pointerID].origin.y <= _pos.y && (eventTable[_pointerID].origin.y + eventTable[_pointerID].size.y) >= _pos.y)) { + eventTable[_pointerID].isInside = true; + //Log.debug("GUI : Input ID=" + _pointerID + " == >" + eventTable[_pointerID].destinationInputId + " [ENTER] " + _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, eventTable[_pointerID].curentWidgetEvent.get(), eventTable[_pointerID].destinationInputId, KeyStatus.enter, _pos); + } + //Log.debug("GUI : Input ID=" + _pointerID + " == >" + eventTable[_pointerID].destinationInputId + " [MOVE] " + _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, eventTable[_pointerID].curentWidgetEvent.get(), eventTable[_pointerID].destinationInputId, KeyStatus.move, _pos); + } + } + + /** + * @brief a new layer on the windows is set == > might remove all the property of the current element ... + */ + public void newLayerSet() { + for (int iii = 0; iii < MAX_MANAGE_INPUT; iii++) { + // remove the property of this input ... + abortElement(this.eventInputSaved, iii, KeyType.finger); + cleanElement(this.eventInputSaved, iii); + abortElement(this.eventMouseSaved, iii, KeyType.mouse); + cleanElement(this.eventMouseSaved, iii); + } + } + + public void setDpi(final int newDPI) { + this.dpi = newDPI; + // recalculate the DPI system ... + calculateLimit(); + } + + public void setLastKeyboardSpecial(final KeySpecial _specialKey) { + this.specialKey = _specialKey; + } + + public void state(final KeyType _type, final int _pointerID, final boolean _isDown, final Vector2f _pos) { + if (_pointerID >= MAX_MANAGE_INPUT) { + // reject pointer == > out of IDs... + return; + } + //Log.debug("event pointerId=" + _pointerID); + // convert position in open-GL coordonates ... + InputPoperty[] eventTable = null; + InputLimit localLimit; + if (_type == KeyType.mouse) { + eventTable = this.eventMouseSaved; + localLimit = this.eventMouseLimit; + } else if (_type == KeyType.finger) { + eventTable = this.eventInputSaved; + localLimit = this.eventInputLimit; + } else { + Log.error("Unknown type of event"); + return; + } + if (_pointerID > MAX_MANAGE_INPUT || _pointerID <= 0) { + // not manage input + return; + } + // get the curent time ... + final Clock currentTime = Clock.now(); + final Windows tmpWindows = this.context.getWindows(); + + if (_isDown == true) { + //Log.debug("GUI : Input ID=" + _pointerID + " == >" + eventTable[_pointerID].destinationInputId + " [DOWN] " + _pos); + if (eventTable[_pointerID].isUsed == true) { + // we have an event previously ... check delay between click and offset position + if (currentTime.less(eventTable[_pointerID].lastTimeEvent).isGreaterThan(localLimit.sepatateTime)) { + cleanElement(eventTable, _pointerID); + } else if (FMath.abs(eventTable[_pointerID].downStart.x - _pos.x) >= localLimit.DpiOffset || FMath.abs(eventTable[_pointerID].downStart.y - _pos.y) >= localLimit.DpiOffset) { + cleanElement(eventTable, _pointerID); + } + } + if (eventTable[_pointerID].isUsed == true) { + // save start time + eventTable[_pointerID].lastTimeEvent = currentTime; + // generate DOWN Event + //Log.debug("GUI : Input ID=" + _pointerID + " == >" + eventTable[_pointerID].destinationInputId + " [DOWN] " + _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, eventTable[_pointerID].curentWidgetEvent.get(), eventTable[_pointerID].destinationInputId, KeyStatus.down, _pos); + } else { + // Mark it used : + eventTable[_pointerID].isUsed = true; + // Save current position : + eventTable[_pointerID].downStart = _pos; + // save start time + eventTable[_pointerID].lastTimeEvent = currentTime; + // set the element inside ... + eventTable[_pointerID].isInside = true; + Widget tmpWidget = this.grabWidget.get(); + // get destination widget : + if (tmpWindows != null) { + if (tmpWidget != null && _type == KeyType.mouse) { + eventTable[_pointerID].curentWidgetEvent = new WeakReference<>(tmpWidget); + } else { + tmpWidget = tmpWindows.getWidgetAtPos(_pos); + eventTable[_pointerID].curentWidgetEvent = new WeakReference<>(tmpWidget); + /* + if (tmpWidget != null) { + Log.debug("Get widget at pos=" + _pos + " type: " + tmpWidget.getObjectType()); + } else { + Log.debug("Get widget at pos=" + _pos + " NO WIDGET"); + } + */ + } + } else { + eventTable[_pointerID].curentWidgetEvent = null; + } + tmpWidget = eventTable[_pointerID].curentWidgetEvent.get(); + if (tmpWidget != null) { + eventTable[_pointerID].origin = tmpWidget.getOrigin(); + eventTable[_pointerID].size = tmpWidget.getSize(); + eventTable[_pointerID].destinationInputId = localGetDestinationId(_type, tmpWidget, _pointerID); + } else { + eventTable[_pointerID].destinationInputId = -1; + } + // generate DOWN Event + //Log.debug("GUI : Input ID=" + _pointerID + " == >" + eventTable[_pointerID].destinationInputId + " [DOWN] " + _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, tmpWidget, eventTable[_pointerID].destinationInputId, KeyStatus.down, _pos); + } + } else { + //Log.debug("GUI : Input ID=" + _pointerID + " == >" + eventTable[_pointerID].destinationInputId + " [UP] " + _pos); + final Widget tmpWidget = eventTable[_pointerID].curentWidgetEvent.get(); + if (eventTable[_pointerID].isUsed == false) { + // bad case ... ??? + Log.debug("Up event without previous down ... "); + // Mark it un-used : + eventTable[_pointerID].isUsed = false; + // revove the widget ... + eventTable[_pointerID].curentWidgetEvent = null; + } else if (tmpWidget == null) { + // The widget has been removed: + //Log.debug(" Object Removed ..."); + // Mark it un-used : + eventTable[_pointerID].isUsed = false; + // revove the widget ... + eventTable[_pointerID].curentWidgetEvent = null; + } else { + // generate UP Event + //Log.debug("GUI : Input ID=" + _pointerID + " == >" + eventTable[_pointerID].destinationInputId + " [UP] " + _pos); + eventTable[_pointerID].posEvent = _pos; + // send up event after the single event to prevent multiple widget getting elements + localEventInput(_type, tmpWidget, _pointerID, KeyStatus.up, _pos); + // generate event (single) + if (FMath.abs(eventTable[_pointerID].downStart.x - _pos.x) < localLimit.DpiOffset && FMath.abs(eventTable[_pointerID].downStart.y - _pos.y) < localLimit.DpiOffset) { + // Save current position : + eventTable[_pointerID].downStart = _pos; + // save start time + eventTable[_pointerID].lastTimeEvent = currentTime; + int nbClickMax = 0; + if (tmpWidget != null) { + nbClickMax = tmpWidget.getMouseLimit(); + if (nbClickMax > 5) { + nbClickMax = 5; + } + } + // in grab mode the single to quinte event are not generated .... + if ((this.grabWidget.get() == null || _type != KeyType.mouse) && eventTable[_pointerID].nbClickEvent < nbClickMax) { + // generate event SINGLE : + eventTable[_pointerID].nbClickEvent++; + //Log.debug("GUI : Input ID=" + _pointerID + " == >" + eventTable[_pointerID].destinationInputId + " [" + eventTable[_pointerID].nbClickEvent + "] " + _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, tmpWidget, eventTable[_pointerID].destinationInputId, KeyStatus.pressCount(eventTable[_pointerID].nbClickEvent), _pos); + if (eventTable[_pointerID].nbClickEvent >= nbClickMax) { + eventTable[_pointerID].nbClickEvent = 0; + } + } else { + eventTable[_pointerID].nbClickEvent = 0; + } + } + // send up event after the single event to prevent multiple widget getting elements + localEventInput(_type, tmpWidget, _pointerID, KeyStatus.upAfter, _pos); + // specific for tuch event + if (_type == KeyType.finger) { + cleanElement(eventTable, _pointerID); + } + } + } + } + + /** + * @brief This is to transfert the event from one widget to another one + * @param _source the widget where the event came from + * @param _destination the widget where the event mitgh be generated now + */ + public void transfertEvent(final Widget _source, final Widget _destination) { + if (_source == null || _destination == null) { + // prevent errors ... + return; + } + for (int iii = 0; iii < MAX_MANAGE_INPUT; iii++) { + Widget tmpWidget = this.eventInputSaved[iii].curentWidgetEvent.get(); + if (tmpWidget == _source) { + // inform the widget that it does not receive the event now + //Log.debug("GUI : Input ID=" + iii + " == >" + this.eventInputSaved[iii].destinationInputId + " [EVENT_INPUT_TYPE_ABORT] " + this.eventInputSaved[iii].posEvent); + localEventInput(KeyType.finger, tmpWidget, this.eventInputSaved[iii].destinationInputId, KeyStatus.abort, this.eventInputSaved[iii].posEvent); + // set the new widget ... + this.eventInputSaved[iii].curentWidgetEvent = new WeakReference<>(_destination); + // inform the widget that he receive the event property now... + //Log.debug("GUI : Input ID=" + iii + " == >" + this.eventInputSaved[iii].destinationInputId + " [EVENT_INPUT_TYPE_TRANSFERT] " + this.eventInputSaved[iii].posEvent); + localEventInput(KeyType.finger, _destination, this.eventInputSaved[iii].destinationInputId, KeyStatus.transfert, this.eventInputSaved[iii].posEvent); + } + tmpWidget = this.eventMouseSaved[iii].curentWidgetEvent.get(); + if (tmpWidget == _source) { + // inform the widget that it does not receive the event now + //Log.debug("GUI : Input ID=" + iii + " == >" + this.eventMouseSaved[iii].destinationInputId + " [EVENT_INPUT_TYPE_ABORT] " + this.eventMouseSaved[iii].posEvent); + localEventInput(KeyType.mouse, tmpWidget, this.eventMouseSaved[iii].destinationInputId, KeyStatus.abort, this.eventMouseSaved[iii].posEvent); + // set the new widget ... + this.eventMouseSaved[iii].curentWidgetEvent = new WeakReference<>(_destination); + // inform the widget that he receive the event property now... + //Log.debug("GUI : Input ID=" + iii + " == >" + this.eventMouseSaved[iii].destinationInputId + " [EVENT_INPUT_TYPE_TRANSFERT] " + this.eventMouseSaved[iii].posEvent); + localEventInput(KeyType.mouse, _destination, this.eventMouseSaved[iii].destinationInputId, KeyStatus.transfert, this.eventMouseSaved[iii].posEvent); + } + } + } + + /** + * @brief This function un-lock the pointer properties to move in relative instead of absolute + */ + public void unGrabPointer() { + this.grabWidget = null; + // TODO: this.context.grabPointerEvents(false, Vector2f(0,0)); + } + +}; + +/** + * @brief internal structure + */ +class InputPoperty { + public boolean isUsed; + public int destinationInputId; + public Clock lastTimeEvent; + public WeakReference curentWidgetEvent; + public Vector2f origin; + public Vector2f size; + public Vector2f downStart; + public Vector2f posEvent; + public boolean isDown; + public boolean isInside; + public int nbClickEvent; // 0 .. 1 .. 2 .. 3 +} diff --git a/src/org/atriasoft/ewol/event/EntrySystem.java b/src/org/atriasoft/ewol/event/EntrySystem.java index c08f5f6..7830843 100644 --- a/src/org/atriasoft/ewol/event/EntrySystem.java +++ b/src/org/atriasoft/ewol/event/EntrySystem.java @@ -5,9 +5,9 @@ import org.atriasoft.gale.key.KeySpecial; import org.atriasoft.gale.key.KeyStatus; public class EntrySystem { - public final Entry event; + public final EventEntry event; public EntrySystem(final KeyKeyboard _type, final KeyStatus _status, final KeySpecial _specialKey, final Character _char) { - this.event = new Entry(_type, _status, _specialKey, _char); + this.event = new EventEntry(_specialKey, _type, _status, _char); } } \ No newline at end of file diff --git a/src/org/atriasoft/ewol/event/Entry.java b/src/org/atriasoft/ewol/event/EventEntry.java similarity index 59% rename from src/org/atriasoft/ewol/event/Entry.java rename to src/org/atriasoft/ewol/event/EventEntry.java index a071fb0..8a5bbab 100644 --- a/src/org/atriasoft/ewol/event/Entry.java +++ b/src/org/atriasoft/ewol/event/EventEntry.java @@ -4,40 +4,37 @@ import org.atriasoft.gale.key.KeyKeyboard; import org.atriasoft.gale.key.KeySpecial; import org.atriasoft.gale.key.KeyStatus; -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -public class Entry { +public class EventEntry { + private final KeySpecial specialKey; //!< input key status (prevent change in time..) private final KeyKeyboard type; //!< type of hardware event private final KeyStatus status; //!< status of hardware event - private final KeySpecial specialKey; //!< input key status (prevent change in time..) private final Character unicodeData; //!< Unicode data (in some case) - public Entry(final KeyKeyboard _type, final KeyStatus _status, final KeySpecial _specialKey, final Character _char) { - this.type = _type; - this.status = _status; - this.specialKey = _specialKey; - this.unicodeData = _char; - + public EventEntry(final KeySpecial specialKey, final KeyKeyboard type, final KeyStatus status, final Character charValue) { + this.type = type; + this.status = status; + this.specialKey = specialKey; + this.unicodeData = charValue; } public Character getChar() { return this.unicodeData; - }; + } public KeySpecial getSpecialKey() { return this.specialKey; - }; + } public KeyStatus getStatus() { return this.status; - }; + } public KeyKeyboard getType() { return this.type; }; -}; \ No newline at end of file + @Override + public String toString() { + return "EventEntry [type=" + this.type + ", status=" + this.status + ", unicodeData=" + this.unicodeData + ", specialKey=" + this.specialKey + "]"; + } +} diff --git a/src/org/atriasoft/ewol/event/EvantInput.java b/src/org/atriasoft/ewol/event/EventInput.java similarity index 100% rename from src/org/atriasoft/ewol/event/EvantInput.java rename to src/org/atriasoft/ewol/event/EventInput.java diff --git a/src/org/atriasoft/ewol/event/EventTime.java b/src/org/atriasoft/ewol/event/EventTime.java index b953297..7321c74 100644 --- a/src/org/atriasoft/ewol/event/EventTime.java +++ b/src/org/atriasoft/ewol/event/EventTime.java @@ -9,10 +9,10 @@ import org.atriasoft.echrono.Duration; * @license MPL v2.0 (see license file) */ public class EventTime { - private Clock timeSystem; //!< Current system time (micro-second) - private Clock timeUpAppl; //!< Current application wake up-time (micro-second) - private Duration timeDelta; //!< Time from the last cycle call of the system (main appl tick) (second) - private Duration timeDeltaCall; //!< Time from the last call (when we can manage periodic call with specifying periode) (second) + private final Clock timeSystem; //!< Current system time (micro-second) + private final Clock timeUpAppl; //!< Current application wake up-time (micro-second) + private final Duration timeDelta; //!< Time from the last cycle call of the system (main appl tick) (second) + private final Duration timeDeltaCall; //!< Time from the last call (when we can manage periodic call with specifying periode) (second) public EventTime(final Clock _timeSystem, final Clock _timeUpAppl, final Duration _timeDelta, final Duration _timeDeltaCall) { this.timeSystem = _timeSystem; @@ -50,19 +50,4 @@ public class EventTime { return this.timeSystem; }; - public void setApplWakeUpTime(final Clock _timeUpAppl) { - this.timeUpAppl = _timeUpAppl; - }; - - public void setDelta(final Duration _timeDelta) { - this.timeDelta = _timeDelta; - }; - - public void setDeltaCall(final Duration _timeDeltaCall) { - this.timeDeltaCall = _timeDeltaCall; - }; - - public void setTime(final Clock _timeSystem) { - this.timeSystem = _timeSystem; - }; } diff --git a/src/org/atriasoft/ewol/event/InputSystem.java b/src/org/atriasoft/ewol/event/InputSystem.java index 465f5eb..3ee16a4 100644 --- a/src/org/atriasoft/ewol/event/InputSystem.java +++ b/src/org/atriasoft/ewol/event/InputSystem.java @@ -1,12 +1,11 @@ package org.atriasoft.ewol.event; import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.ewol.widget.Widget; import org.atriasoft.gale.key.KeySpecial; import org.atriasoft.gale.key.KeyStatus; import org.atriasoft.gale.key.KeyType; -import jdk.internal.org.jline.reader.Widget; - public class InputSystem { public EventInput event; diff --git a/src/org/atriasoft/ewol/gravity.cpp b/src/org/atriasoft/ewol/gravity.cpp deleted file mode 100644 index dfb7371..0000000 --- a/src/org/atriasoft/ewol/gravity.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include - -#include -ETK_DECLARE_TYPE(enum ewol::gravity); - -String ewol::gravityToString( enum ewol::gravity _obj) { - switch(_obj) { - case ewol::gravity_center: - return "center"; - case ewol::gravity_topLeft: - return "top-left"; - case ewol::gravity_top: - return "top"; - case ewol::gravity_topRight: - return "top-right"; - case ewol::gravity_right: - return "right"; - case ewol::gravity_buttomRight: - return "buttom-right"; - case ewol::gravity_buttom: - return "buttom"; - case ewol::gravity_buttomLeft: - return "buttom-left"; - case ewol::gravity_left: - return "left"; - } - return "unknow"; -} - -enum ewol::gravity ewol::stringToGravity( String _obj) { - if (_obj == "center") { - return ewol::gravity_center; - } else if (_obj == "top-left") { - return ewol::gravity_topLeft; - } else if (_obj == "top") { - return ewol::gravity_top; - } else if (_obj == "top-right") { - return ewol::gravity_topRight; - } else if (_obj == "right") { - return ewol::gravity_right; - } else if (_obj == "buttom-right") { - return ewol::gravity_buttomRight; - } else if (_obj == "buttom") { - return ewol::gravity_buttom; - } else if (_obj == "buttom-left") { - return ewol::gravity_buttomLeft; - } else if (_obj == "left") { - return ewol::gravity_left; - } - return ewol::gravity_center; -} -Vector2f ewol::gravityGenerateDelta( enum ewol::gravity _gravity, Vector2f _deltas) { - Vector2f out(0.0f,0.0f); - if (_deltas.x() > 0.0001f) { - if ((uint(_gravity) uint(ewol::gravity_left)) != 0) { - // nothing to do - } else if ((uint(_gravity) uint(ewol::gravity_right)) != 0) { - out = Vector2f(int(_deltas.x()), 0.0f); - } else { - out = Vector2f(int(_deltas.x()*0.5f), 0.0f); - } - } - if (_deltas.y() > 0.0001f) { - if ((uint(_gravity) uint(ewol::gravity_buttom)) != 0) { - // nothing to do - } else if ((uint(_gravity) uint(ewol::gravity_top)) != 0) { - out += Vector2f(0.0f, int(_deltas.y())); - } else { - out += Vector2f(0.0f, int(_deltas.y()*0.5f)); - } - } - return out; -} - -etk::Stream ewol::operator +(etk::Stream _os, enum ewol::gravity _obj) { - _os + ewol::gravityToString(_obj); - return _os; -} - diff --git a/src/org/atriasoft/ewol/internal/LoadPackageStream.java b/src/org/atriasoft/ewol/internal/LoadPackageStream.java new file mode 100644 index 0000000..2e37bf0 --- /dev/null +++ b/src/org/atriasoft/ewol/internal/LoadPackageStream.java @@ -0,0 +1,84 @@ +package org.atriasoft.ewol.internal; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.stream.Stream; + +public class LoadPackageStream { + public static byte[] getAllData(final String resourceName) { + Log.verbose("Load resource: '/resources" + resourceName + "'"); + final InputStream out = LoadPackageStream.class.getResourceAsStream("/resources" + resourceName); + if (out == null) { + Log.error("Can not load resource: '" + resourceName + "'"); + for (final Path elem : LoadPackageStream.getResources(LoadPackageStream.class.getResource("/resources")).toArray(Path[]::new)) { + Log.warning(" - '" + elem + "'"); + } + return null; + } + byte[] data = null; + try { + data = out.readAllBytes(); + } catch (final IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return data; + } + + public static Stream getResources(final URL element) { + try { + final URI uri = element.toURI(); + FileSystem fs; + Path path; + if (uri.getScheme().contentEquals("jar")) { + try { + fs = FileSystems.getFileSystem(uri); + } catch (final FileSystemNotFoundException e) { + fs = FileSystems.newFileSystem(uri, Collections. emptyMap()); + } + String pathInJar = "/"; + final String tmpPath = element.getPath(); + final int idSeparate = tmpPath.indexOf('!'); + if (idSeparate != -1) { + pathInJar = tmpPath.substring(idSeparate + 1); + while (pathInJar.startsWith("/")) { + pathInJar = pathInJar.substring(1); + } + } + path = fs.getPath(pathInJar); + } else { + fs = FileSystems.getDefault(); + path = Paths.get(uri); + } + return Files.walk(path, 1); + } catch (URISyntaxException | IOException e) { + e.printStackTrace(); + return Stream.of(); + } + } + + public static InputStream getStream(final String resourceName) { + Log.verbose("Load resource: '/resources" + resourceName + "'"); + final InputStream out = LoadPackageStream.class.getResourceAsStream("/resources" + resourceName); + if (out == null) { + Log.error("Can not load resource: '" + resourceName + "'"); + for (final Path elem : LoadPackageStream.getResources(LoadPackageStream.class.getResource("/resources")).toArray(Path[]::new)) { + Log.warning(" - '" + elem + "'"); + } + } + return out; + } + + private LoadPackageStream() {} + +} diff --git a/src/org/atriasoft/ewol/internal/Tools.java b/src/org/atriasoft/ewol/internal/Tools.java new file mode 100644 index 0000000..8170e7f --- /dev/null +++ b/src/org/atriasoft/ewol/internal/Tools.java @@ -0,0 +1,22 @@ +package org.atriasoft.ewol.internal; + +public class Tools { + /** + * @brief get the next power 2 if the input + * @param[in] value Value that we want the next power of 2 + * @return result value + */ + public static int nextP2(final int _value) { + int val = 1; + for (int iii = 1; iii < 31; iii++) { + if (_value <= val) { + return val; + } + val *= 2; + } + Log.critical("impossible CASE...."); + return val; + } + + private Tools() {} +} diff --git a/src/org/atriasoft/ewol/object/EwolObject.java b/src/org/atriasoft/ewol/object/EwolObject.java index 92b9813..37ffeec 100644 --- a/src/org/atriasoft/ewol/object/EwolObject.java +++ b/src/org/atriasoft/ewol/object/EwolObject.java @@ -2,6 +2,7 @@ package org.atriasoft.ewol.object; import java.lang.ref.WeakReference; +import org.atriasoft.ewol.Ewol; import org.atriasoft.ewol.context.EwolContext; import org.atriasoft.ewol.internal.Log; @@ -13,7 +14,7 @@ import org.atriasoft.ewol.internal.Log; /** * @brief Basic message classes for ewol system - * this class mermit at every Object to communicate between them. + * this class permit at every Object to communicate between them. */ public class EwolObject { private static Integer valUID = 0; //!< Static used for the unique ID definition @@ -34,18 +35,18 @@ public class EwolObject { return Ewol.getContext().getEObjectManager(); } - /** - * @brief Retrive an object with his name (in the global list) - * @param[in] _name Name of the object - * @return the requested object or null - */ + /** + * @brief Retrive an object with his name (in the global list) + * @param[in] _name Name of the object + * @return the requested object or null + */ public static EwolObject getObjectNamed(final String _objectName) { return getObjectManager().getObjectNamed(_objectName); } //@EwolPropertyDescription("Object name, might be a unique reference in all the program") //@JacksonXmlProperty(isAttribute = true, localName = "name") - private String name = ""; //!< name of the element ... + protected String name = ""; //!< name of the element ... protected WeakReference parent = null; //!< Reference on the current parent. @@ -180,8 +181,8 @@ public class EwolObject { * @return the requested object or null */ public EwolObject getSubObjectNamed(final String _objectName) { - Log.verbose("check if name : " + _objectName + " ?= " + this.propertyName); - if (_objectName == this.propertyName) { + Log.verbose("check if name : " + _objectName + " ?= " + this.name); + if (_objectName == this.name) { return this; } return null; diff --git a/src/org/atriasoft/ewol/object/Manager.cpp b/src/org/atriasoft/ewol/object/Manager.cpp deleted file mode 100644 index daa2fee..0000000 --- a/src/org/atriasoft/ewol/object/Manager.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include -#include -#include - -#include -ETK_DECLARE_TYPE(ObjectManager); - -ObjectManager::Manager(EwolContext _context) : - this.context(_context), - periodicCall(this, "periodic", "Call every time system render"), - this.applWakeUpTime(0), - this.lastPeriodicCallTime(0) { - Log.debug(" == > init Object-Manager"); - periodicCall.setPeriodic(true); - // set the basic time properties : - this.applWakeUpTime = echrono::Clock::now(); - this.lastPeriodicCallTime = this.applWakeUpTime; -} - -ObjectManager::~Manager() { - ethread::RecursiveLock lock(this.mutex); - this.workerList.clear(); - boolean hasError = false; - if (this.eObjectList.size()!=0) { - Log.error("Must not have anymore eObject !!!"); - hasError = true; - } - if (hasError == true) { - Log.error("Check if the function UnInit has been called !!!"); - } - displayListObject(); -} - -void ObjectManager::displayListObject() { - ethread::RecursiveLock lock(this.mutex); - Log.info("List loaded object : "); - for (auto it : this.eObjectList) { - EwolObject element = it.lock(); - if (element != null) { - Log.info(" [" + element.getId() + "] ref=" + element.useCount()-1 + " name='" + element.propertyName.get() + "' type=" + element.getObjectType()); - } - } -} - -void ObjectManager::unInit() { - ethread::RecursiveLock lock(this.mutex); - Log.debug(" == > Un-Init Object-Manager"); - if (this.workerList.size() > 0) { - Log.debug(" == > Remove all workers"); - this.workerList.clear(); - } - for (auto it : this.eObjectList) { - EwolObject element = it.lock(); - if (element != null) { - //it.removeObject(); - } - } - if (this.eObjectList.size() != 0) { - Log.error("Have " + this.eObjectList.size() + " active Object"); - } - this.eObjectList.clear(); -} - -void ObjectManager::add( EwolObject _object) { - ethread::RecursiveLock lock(this.mutex); - if (_object == null) { - Log.error("try to add an inexistant Object in manager"); - } - this.eObjectList.pushBack(_object); -} - -int ObjectManager::getNumberObject() { - ethread::RecursiveLock lock(this.mutex); - return this.eObjectList.size(); -} - -// clean all Object that request an autoRemove ... -void ObjectManager::cleanInternalRemoved() { - ethread::RecursiveLock lock(this.mutex); - int nbObject = this.eObjectList.size(); - Log.verbose("Clean Object List (if needed) : " + this.eObjectList.size() + " elements"); - auto it(this.eObjectList.begin()); - while (it != this.eObjectList.end()) { - if (it.expired() == true) { - it = this.eObjectList.erase(it); - } else { - ++it; - } - } - if (this.eObjectList.size() != nbObject) { - Log.verbose(" remove " + nbObject - this.eObjectList.size() + " deprecated objects"); - } -} - -EwolObject ObjectManager::get( String _name) { - ethread::RecursiveLock lock(this.mutex); - if (_name == "") { - return null; - } - for (auto it : this.eObjectList) { - EwolObject element = it.lock(); - if ( element != null - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM element.propertyName.get() == _name) { - return element; - } - } - return null; -} - - -EwolObject ObjectManager::getObjectNamed( String _name) { - ethread::RecursiveLock lock(this.mutex); - return ObjectManager::get(_name); -} - - -void ObjectManager::workerAdd( EwolObject _worker) { - ethread::RecursiveLock lock(this.mutex); - this.workerList.pushBack(_worker); -} - -void ObjectManager::workerRemove( EwolObject _worker) { - ethread::RecursiveLock lock(this.mutex); - auto it(this.workerList.begin()); - while (it != this.workerList.end()) { - if (*it == _worker) { - it = this.workerList.erase(it); - } else { - ++it; - } - } -} - -void ObjectManager::timeCall( echrono::Clock _localTime) { - ethread::RecursiveLock lock(this.mutex); - echrono::Clock previousTime = this.lastPeriodicCallTime; - this.lastPeriodicCallTime = _localTime; - if (periodicCall.size() <= 0) { - return; - } - echrono::Duration deltaTime = _localTime - previousTime; - ewol::event::Time myTime(_localTime, this.applWakeUpTime, deltaTime, deltaTime); - periodicCall.emit(myTime); -} - -void ObjectManager::timeCallResume( echrono::Clock _localTime) { - ethread::RecursiveLock lock(this.mutex); - this.lastPeriodicCallTime = _localTime; -} - -boolean ObjectManager::timeCallHave() { - ethread::RecursiveLock lock(this.mutex); - return periodicCall.size() > 0; -} diff --git a/src/org/atriasoft/ewol/object/Object.cpp b/src/org/atriasoft/ewol/object/Object.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/org/atriasoft/ewol/object/ObjectManager.java b/src/org/atriasoft/ewol/object/ObjectManager.java index bd0ea9a..c3e4d43 100644 --- a/src/org/atriasoft/ewol/object/ObjectManager.java +++ b/src/org/atriasoft/ewol/object/ObjectManager.java @@ -6,12 +6,12 @@ import java.util.Iterator; import java.util.List; import org.atriasoft.echrono.Clock; -import org.atriasoft.echrono.Steady; +import org.atriasoft.echrono.Duration; import org.atriasoft.echrono.Time; import org.atriasoft.esignal.Signal; import org.atriasoft.ewol.context.EwolContext; +import org.atriasoft.ewol.event.EventTime; import org.atriasoft.ewol.internal.Log; -import org.atriasoft.gale.event.EventTime; /** @file * @author Edouard DUPIN @@ -21,68 +21,33 @@ import org.atriasoft.gale.event.EventTime; public class ObjectManager { private final List> eObjectList = new ArrayList<>(); // all widget allocated == > all time increment ... never removed ... - private final EwolContext context; + private EwolContext context = null; + + private final List workerList = new ArrayList<>(); + + public final Signal periodicCall = new Signal<>(); + + private final Time applWakeUpTime; //!< Time of the application initialize + + private Clock lastPeriodicCallTime; //!< last call time ... public ObjectManager(final EwolContext _context) { this.context = _context; //periodicCall(this, "periodic", "Call every time system render"); Log.debug(" == > init Object-Manager"); - this.periodicCall.setPeriodic(true); + Log.todo("set this back ..."); + //this.periodicCall.setPeriodic(true); // set the basic time properties : this.applWakeUpTime = Clock.now(); this.lastPeriodicCallTime = new Clock(this.applWakeUpTime.get()); } - /** - * @brief remove all resources (un-init) out of the destructor (due to the system implementation) - */ - synchronized void unInit() { - Log.debug(" == > Un-Init Object-Manager"); - if (this.workerList.size() > 0) { - Log.debug(" == > Remove all workers"); - this.workerList.clear(); - } - for (final WeakReference it : this.eObjectList) { - final EwolObject element = it.get(); - if (element != null) { - //it.removeObject(); - } - } - if (this.eObjectList.size() != 0) { - Log.error("Have " + this.eObjectList.size() + " active Object"); - } - this.eObjectList.clear(); - } - - /** - * @brief Get the number of loaded object in the system - * @return number of Object - */ - synchronized - - int getNumberObject() { - return this.eObjectList.size(); - } - - /** - * @brief Display all object Open. - */ - synchronized void displayListObject() { - Log.info("List loaded object : "); - for (final WeakReference it : this.eObjectList) { - final EwolObject element = it.get(); - if (element != null) { - Log.info(" [" + element.getId() + "] name='" + element.getName() + "' type=" + element.getClass().getCanonicalName()); - } - } - } - /** * @brief Internal API that used only with Object toi reference itself in the manager. * @note The manager remove the object when the refecence Low down 1 (last keeper) * @param[in] _object Reference shared pointer on the object */ - private synchronized void add(final EwolObject _object) { + public synchronized void add(final EwolObject _object) { if (_object == null) { Log.error("try to add an inexistant Object in manager"); } @@ -107,6 +72,19 @@ public class ObjectManager { } } + /** + * @brief Display all object Open. + */ + public synchronized void displayListObject() { + Log.info("List loaded object : "); + for (final WeakReference it : this.eObjectList) { + final EwolObject element = it.get(); + if (element != null) { + Log.info(" [" + element.getId() + "] name='" + element.getName() + "' type=" + element.getClass().getCanonicalName()); + } + } + } + /** * @brief Retrive an Object with his name * @param[in] _name Name of the Object @@ -125,16 +103,75 @@ public class ObjectManager { return null; } + /** + * @brief Get the number of loaded object in the system + * @return number of Object + */ + public synchronized int getNumberObject() { + return this.eObjectList.size(); + } + /** * @brief retrive an object with his name * @param[in] _name Name of the object * @return the requested object or null */ public synchronized EwolObject getObjectNamed(final String _name) { - return ObjectManager.get(_name); + return get(_name); } - private final List workerList = new ArrayList<>(); + /** + * @brief Call every time we can with the current time + * @param[in] _localTime Current system Time. + */ + public synchronized void timeCall(final Clock _localTime) { + final Clock previousTime = this.lastPeriodicCallTime; + this.lastPeriodicCallTime = _localTime; + if (this.periodicCall.size() <= 0) { + return; + } + final Duration deltaTime = new Duration(_localTime.get() - previousTime.get()); + + final EventTime myTime = new EventTime(_localTime, this.applWakeUpTime.toClock(), deltaTime, deltaTime); + this.periodicCall.emit(myTime); + } + + /** + * @breif check if the Interface have some user that request a periodic call + * @return true, have some periodic event... + */ + public synchronized boolean timeCallHave() { + return this.periodicCall.size() > 0; + } + + /** + * @brief If the application is suspended The Ewol Object manager does not know it, just call this to update delta call + * @param[in] _localTime Current system Time. + */ + public synchronized void timeCallResume(final Clock _localTime) { + this.lastPeriodicCallTime = _localTime; + } + + /** + * @brief remove all resources (un-init) out of the destructor (due to the system implementation) + */ + public synchronized void unInit() { + Log.debug(" == > Un-Init Object-Manager"); + if (this.workerList.size() > 0) { + Log.debug(" == > Remove all workers"); + this.workerList.clear(); + } + for (final WeakReference it : this.eObjectList) { + final EwolObject element = it.get(); + if (element != null) { + //it.removeObject(); + } + } + if (this.eObjectList.size() != 0) { + Log.error("Have " + this.eObjectList.size() + " active Object"); + } + this.eObjectList.clear(); + } /** * @brief Add a worker on the system list. @@ -159,41 +196,4 @@ public class ObjectManager { } } - public final Signal periodicCall = new Signal<>(); - - private final Time applWakeUpTime; //!< Time of the application initialize - private Clock lastPeriodicCallTime; //!< last call time ... - - /** - * @brief Call every time we can with the current time - * @param[in] _localTime Current system Time. - */ - public synchronized void timeCall( final Clock _localTime){ - final Clock previousTime = this.lastPeriodicCallTime; - this.lastPeriodicCallTime = _localTime; - if (this.periodicCall.size() <= 0) { - return; - } - final Duration deltaTime = new Duration(_localTime.get() - previousTime.get()); - - final EventTime myTime(final _localTime, this.applWakeUpTime, deltaTime, deltaTime); - this.periodicCall.emit(myTime); - } - - /** - * @brief If the application is suspended The Ewol Object manager does not know it, just call this to update delta call - * @param[in] _localTime Current system Time. - */ - public synchronized void timeCallResume(final Clock _localTime) { - this.lastPeriodicCallTime = _localTime; - } - - /** - * @breif check if the Interface have some user that request a periodic call - * @return true, have some periodic event... - */ - public synchronized boolean timeCallHave() { - return this.periodicCall.size() > 0; - } - } diff --git a/src/org/atriasoft/ewol/object/Worker.cpp b/src/org/atriasoft/ewol/object/Worker.cpp deleted file mode 100644 index e9d87c8..0000000 --- a/src/org/atriasoft/ewol/object/Worker.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include -#include -#include -ETK_DECLARE_TYPE(ewol::object::Worker); - -ewol::object::Worker::Worker() { - addObjectType("ewol::Worker"); -} - -void ewol::object::Worker::init() { - EwolObject::init(); - getObjectManager().workerAdd(sharedFromThis()); -} - -ewol::object::Worker::~Worker() { - // nothing to do ... -} - -void ewol::object::Worker::destroy() { - EwolObject::destroy(); - getObjectManager().workerRemove(sharedFromThis()); -} diff --git a/src/org/atriasoft/ewol/resource/ColorFile.cpp b/src/org/atriasoft/ewol/resource/ColorFile.cpp deleted file mode 100644 index e497e58..0000000 --- a/src/org/atriasoft/ewol/resource/ColorFile.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include -#include -#include -#include -ETK_DECLARE_TYPE(ewol::resource::ColorFile); - -ewol::resource::ColorFile::ColorFile() : - gale::Resource(), - // Set the list unodered - this.list(0, false), - this.errorColor(etk::color::orange) { - addResourceType("ewol::ColorFile"); -} - -void ewol::resource::ColorFile::init( etk::Uri _uri) { - ethread::RecursiveLock lock(this.mutex); - gale::Resource::init(_uri.get()); - Log.debug("CF : load \"" + _uri + "\""); - reload(); - Log.debug("List of all color : " + this.list.getKeys()); -} - -ewol::resource::ColorFile::~ColorFile() { - // remove all element - this.list.clear(); -} - - -void ewol::resource::ColorFile::reload() { - ethread::RecursiveLock lock(this.mutex); - // remove all previous set of value : - for (int iii = 0; iii < this.list.size() ; ++iii) { - this.list.getValue(iii) = this.errorColor; - } - // open and read all json elements: - ejson::Document doc; - if (doc.load(etk::Uri(this.name)) == false) { - Log.error("Can not load file : '" + this.name + "'"); - return; - } - ejson::Array baseArray = doc["color"].toArray(); - if (baseArray.exist() == false) { - Log.error("Can not get basic array : 'color' in file:" + this.name); - doc.display(); - return; - } - boolean findError = false; - for ( auto it : baseArray) { - ejson::Object tmpObj = it.toObject(); - if (tmpObj.exist() == false) { - Log.error(" can not get object in 'color' : " + it); - findError = true; - continue; - } - String name = tmpObj["name"].toString().get(); - String color = tmpObj["color"].toString().get(this.errorColor.getHexString()); - Log.debug("find new color : '" + name + "' color='" + color + "'"); - if (name.size() == 0) { - Log.error("Drop an empty name"); - findError = true; - continue; - } - this.list.add(name, etk::Color(color)); - } - if (findError == true) { - Log.error("pb in parsing file:" + this.name); - doc.display(); - } -} - - -int ewol::resource::ColorFile::request( String _paramName) { - ethread::RecursiveLock lock(this.mutex); - // check if the parameters existed : - if (this.list.exist(_paramName) == false) { - this.list.add(_paramName, this.errorColor); - } - return this.list.getId(_paramName); -} diff --git a/src/org/atriasoft/ewol/resource/ColorFile.java b/src/org/atriasoft/ewol/resource/ColorFile.java deleted file mode 100644 index f49e51b..0000000 --- a/src/org/atriasoft/ewol/resource/ColorFile.java +++ /dev/null @@ -1,73 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ -#pragma once - -#include -#include -#include -#include -#include - -namespace ewol { - namespace resource { - /** - * @brief ColorFile is a Resource designed to be specific with the theme (for example black, or white or orange ...) - */ - class ColorFile : public gale::Resource { - private: - etk::Map > this.list; //!< List of all color in the file - etk::Color this.errorColor; //!< Error returned color - protected: - /** - * @brief Constructor of the color property file - * @param[in] _uri Name of the file needed - */ - ColorFile(); - void init( etk::Uri _uri); - public: - DECLARE_RESOURCE_URI_FACTORY(ColorFile); - /** - * @brief Simple Destructor of this class (nothing specific ...) - */ - ~ColorFile(); - public: - /** - * @brief Set the error color. - * @param[in] _errorColor Color that might be set when not finding a color - */ - void setErrorColor( etk::Color _errorColor) { - this.errorColor = _errorColor; - } - /** - * @brief Request the presence of a specific color. - * @param[in] _paramName Name of the color. - * @return A unique ID of the color (or -1 if an error occured). - */ - int request( String _paramName); - /** - * @brief Get the associated color of the ID. - * @param[in] _Id Id of the color. - * @return The requested color. - */ - etk::Color get(int _id) { - if (_id < 0) { - return this.errorColor; - } - return this.list.getValue(_id); - }; - /** - * @brief Get All color name - * @return list of all color existing - */ - List getColors() { - return this.list.getKeys(); - } - public: // herited function: - void reload(); - }; - }; -}; - diff --git a/src/org/atriasoft/ewol/resource/Colored3DObject.cpp b/src/org/atriasoft/ewol/resource/Colored3DObject.cpp deleted file mode 100644 index 522066f..0000000 --- a/src/org/atriasoft/ewol/resource/Colored3DObject.cpp +++ /dev/null @@ -1,527 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#ifndef __TARGET_OS__Web - -#include -#include -#include -#include -#include - -#include -ETK_DECLARE_TYPE(ewol::resource::Colored3DObject); - -ewol::resource::Colored3DObject::Colored3DObject() : - this.GLprogram(null) { - addResourceType("ewol::Colored3DObject"); -} - -void ewol::resource::Colored3DObject::init() { - gale::Resource::init(); - // get the shader resource : - this.GLPosition = 0; - this.GLprogram = gale::resource::Program::create("DATA:///simple3D.prog?lib=ewol"); - if (this.GLprogram != null) { - this.GLPosition = this.GLprogram.getAttribute("EW_coord3d"); - this.GLColor = this.GLprogram.getUniform("EW_color"); - this.GLMatrix = this.GLprogram.getUniform("EW_MatrixTransformation"); - } -} - -ewol::resource::Colored3DObject::~Colored3DObject() { - -} - - -void ewol::resource::Colored3DObject::draw( List _vertices, - etk::Color _color, - boolean _updateDepthBuffer, - boolean _depthtest) { - if (_vertices.size() <= 0) { - return; - } - if (this.GLprogram == null) { - Log.error("No shader ..."); - return; - } - if (true == _depthtest) { - gale::openGL::enable(gale::openGL::flag_depthTest); - if (false == _updateDepthBuffer) { - glDepthMask(GL_FALSE); - } - } - //Log.debug(" display " + this.coord.size() + " elements" ); - this.GLprogram.use(); - // set Matrix: translation/positionMatrix - mat4 projMatrix = gale::openGL::getMatrix(); - mat4 camMatrix = gale::openGL::getCameraMatrix(); - mat4 tmpMatrix = projMatrix * camMatrix; - this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); - // position : - this.GLprogram.sendAttribute(this.GLPosition, 3/*x,y,z,unused*/, _vertices[0], 4*sizeof(float)); - // color : - this.GLprogram.uniform4fv(this.GLColor, 1/*r,g,b,a*/, (float*)_color); - // Request the draw od the elements: - gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, _vertices.size()); - this.GLprogram.unUse(); - // Request the draw od the elements: - //glDrawArrays(GL_LINES, 0, vertices.size()); - //this.GLprogram.UnUse(); - if (true == _depthtest) { - if (false == _updateDepthBuffer) { - glDepthMask(GL_TRUE); - } - gale::openGL::disable(gale::openGL::flag_depthTest); - } -} - -void ewol::resource::Colored3DObject::draw( List _vertices, - etk::Color _color, - mat4 _transformationMatrix, - boolean _updateDepthBuffer, - boolean _depthtest) { - if (_vertices.size() <= 0) { - return; - } - if (this.GLprogram == null) { - Log.error("No shader ..."); - return; - } - if (true == _depthtest) { - gale::openGL::enable(gale::openGL::flag_depthTest); - if (false == _updateDepthBuffer) { - glDepthMask(GL_FALSE); - } - } - //Log.debug(" display " + this.coord.size() + " elements" ); - this.GLprogram.use(); - // set Matrix: translation/positionMatrix - mat4 projMatrix = gale::openGL::getMatrix(); - mat4 camMatrix = gale::openGL::getCameraMatrix(); - mat4 tmpMatrix = projMatrix * camMatrix * _transformationMatrix; - this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); - // position : - this.GLprogram.sendAttribute(this.GLPosition, 3/*x,y,z*/, _vertices[0], 4*sizeof(float)); - // color : - this.GLprogram.uniform4fv(this.GLColor, 1/*r,g,b,a*/, (float*)_color); - // Request the draw od the elements: - gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, _vertices.size()); - this.GLprogram.unUse(); - if (true == _depthtest) { - if (false == _updateDepthBuffer) { - glDepthMask(GL_TRUE); - } - gale::openGL::disable(gale::openGL::flag_depthTest); - } -} - -void ewol::resource::Colored3DObject::drawLine(List _vertices, - etk::Color _color, - mat4 _transformationMatrix, - boolean _updateDepthBuffer, - boolean _depthtest) { - if (_vertices.size() <= 0) { - return; - } - if (this.GLprogram == null) { - Log.error("No shader ..."); - return; - } - if (true == _depthtest) { - gale::openGL::enable(gale::openGL::flag_depthTest); - if (false == _updateDepthBuffer) { - glDepthMask(GL_FALSE); - } - } - //Log.debug(" display " + this.coord.size() + " elements" ); - this.GLprogram.use(); - // set Matrix: translation/positionMatrix - mat4 projMatrix = gale::openGL::getMatrix(); - mat4 camMatrix = gale::openGL::getCameraMatrix(); - mat4 tmpMatrix = projMatrix * camMatrix * _transformationMatrix; - this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); - // position : - this.GLprogram.sendAttribute(this.GLPosition, 3/*x,y,z*/, _vertices[0], 4*sizeof(float)); - // color : - this.GLprogram.uniform4fv(this.GLColor, 1/*r,g,b,a*/, (float*)_color); - // Request the draw od the elements: - gale::openGL::drawArrays(gale::openGL::renderMode::line, 0, _vertices.size()); - this.GLprogram.unUse(); - if (true == _depthtest) { - if (false == _updateDepthBuffer) { - glDepthMask(GL_TRUE); - } - gale::openGL::disable(gale::openGL::flag_depthTest); - } -} - - -void ewol::resource::Colored3DObject::drawCubeLine( Vector3f _min, - Vector3f _max, - etk::Color _color, - mat4 _transformationMatrix, - boolean _updateDepthBuffer, - boolean _depthtest) { - List vertices; - vertices.pushBack(Vector3f(_min.x(), _min.y(),_min.z())); - vertices.pushBack(Vector3f(_max.x(), _min.y(),_min.z())); - - vertices.pushBack(Vector3f(_max.x(), _min.y(),_min.z())); - vertices.pushBack(Vector3f(_max.x(), _min.y(),_max.z())); - - vertices.pushBack(Vector3f(_max.x(), _min.y(),_max.z())); - vertices.pushBack(Vector3f(_min.x(), _min.y(),_max.z())); - - vertices.pushBack(Vector3f(_min.x(), _min.y(),_max.z())); - vertices.pushBack(Vector3f(_min.x(), _min.y(),_min.z())); - - - vertices.pushBack(Vector3f(_min.x(), _max.y(),_min.z())); - vertices.pushBack(Vector3f(_max.x(), _max.y(),_min.z())); - - vertices.pushBack(Vector3f(_max.x(), _max.y(),_min.z())); - vertices.pushBack(Vector3f(_max.x(), _max.y(),_max.z())); - - vertices.pushBack(Vector3f(_max.x(), _max.y(),_max.z())); - vertices.pushBack(Vector3f(_min.x(), _max.y(),_max.z())); - - vertices.pushBack(Vector3f(_min.x(), _max.y(),_max.z())); - vertices.pushBack(Vector3f(_min.x(), _max.y(),_min.z())); - - - vertices.pushBack(Vector3f(_min.x(), _min.y(),_min.z())); - vertices.pushBack(Vector3f(_min.x(), _max.y(),_min.z())); - - vertices.pushBack(Vector3f(_max.x(), _min.y(),_min.z())); - vertices.pushBack(Vector3f(_max.x(), _max.y(),_min.z())); - - vertices.pushBack(Vector3f(_max.x(), _min.y(),_max.z())); - vertices.pushBack(Vector3f(_max.x(), _max.y(),_max.z())); - - vertices.pushBack(Vector3f(_min.x(), _min.y(),_max.z())); - vertices.pushBack(Vector3f(_min.x(), _max.y(),_max.z())); - - drawLine(vertices, _color, _transformationMatrix, _updateDepthBuffer, _depthtest); -} - -void ewol::resource::Colored3DObject::drawSquare( Vector3f _size, - mat4 _transformationMatrix, - etk::Color _tmpColor) { - List tmpVertices; - static int indices[36] = { 0,1,2, 3,2,1, 4,0,6, - 6,0,2, 5,1,4, 4,1,0, - 7,3,1, 7,1,5, 5,4,7, - 7,4,6, 7,2,3, 7,6,2}; - Vector3f vertices[8]={ Vector3f(_size[0],_size[1],_size[2]), - Vector3f(-_size[0],_size[1],_size[2]), - Vector3f(_size[0],-_size[1],_size[2]), - Vector3f(-_size[0],-_size[1],_size[2]), - Vector3f(_size[0],_size[1],-_size[2]), - Vector3f(-_size[0],_size[1],-_size[2]), - Vector3f(_size[0],-_size[1],-_size[2]), - Vector3f(-_size[0],-_size[1],-_size[2])}; - tmpVertices.clear(); - for (int iii=0 ; iii<36 ; iii+=3) { - // normal calculation : - //btVector3 normal = (vertices[indices[iii+2]]-vertices[indices[iii]]).cross(vertices[indices[iii+1]]-vertices[indices[iii]]); - //normal.normalize (); - tmpVertices.pushBack(vertices[indices[iii]]); - tmpVertices.pushBack(vertices[indices[iii+1]]); - tmpVertices.pushBack(vertices[indices[iii+2]]); - } - draw(tmpVertices, _tmpColor, _transformationMatrix); -} - -void ewol::resource::Colored3DObject::drawSphere(float _radius, - int _lats, - int _longs, - mat4 _transformationMatrix, - etk::Color _tmpColor) { - List tmpVertices; - for(int iii=0; iii<=_lats; ++iii) { - float lat0 = M_PI * (-0.5f + float(iii - 1) / _lats); - float z0 = _radius*sin(lat0); - float zr0 = _radius*cos(lat0); - - float lat1 = M_PI * (-0.5f + float(iii) / _lats); - float z1 = _radius*sin(lat1); - float zr1 = _radius*cos(lat1); - - for(int jjj=0; jjj<_longs; ++jjj) { - float lng = 2.0f * M_PI * float(jjj - 1) / _longs; - float x = cos(lng); - float y = sin(lng); - Vector3f v1 = Vector3f(x * zr1, y * zr1, z1); - Vector3f v4 = Vector3f(x * zr0, y * zr0, z0); - - lng = 2 * M_PI * float(jjj) / _longs; - x = cos(lng); - y = sin(lng); - Vector3f v2 = Vector3f(x * zr1, y * zr1, z1); - Vector3f v3 = Vector3f(x * zr0, y * zr0, z0); - - tmpVertices.pushBack(v1); - tmpVertices.pushBack(v2); - tmpVertices.pushBack(v3); - - tmpVertices.pushBack(v1); - tmpVertices.pushBack(v3); - tmpVertices.pushBack(v4); - } - } - draw(tmpVertices, _tmpColor, _transformationMatrix); -} -void ewol::resource::Colored3DObject::drawCylinder(float _radius, - float _size, - int _lats, - int _longs, - mat4 _transformationMatrix, - etk::Color _tmpColor) { - List tmpVertices; - // center to border (TOP) - - // center to border (TOP) - for(int jjj=0; jjj<_longs; ++jjj) { - float lng = 2.0f * M_PI * float(jjj - 1) / _longs; - - float z = _size*0.5f; - Vector3f v1 = Vector3f(0.0f, 0.0f, z); - - float x = cos(lng)*_radius; - float y = sin(lng)*_radius; - Vector3f v2 = Vector3f(x, y, z); - - lng = 2.0f * M_PI * float(jjj) / _longs; - x = cos(lng)*_radius; - y = sin(lng)*_radius; - Vector3f v3 = Vector3f(x, y, z); - tmpVertices.pushBack(v1); - tmpVertices.pushBack(v3); - tmpVertices.pushBack(v2); - } - // Cylinder - for(int jjj=0; jjj<_longs; ++jjj) { - float lng = 2.0f * M_PI * float(jjj - 1) / _longs; - - float z = _size*0.5f; - - float x = cos(lng)*_radius; - float y = sin(lng)*_radius; - Vector3f v2 = Vector3f(x, y, z); - Vector3f v2b = Vector3f(x, y, -z); - - lng = 2.0f * M_PI * float(jjj) / _longs; - x = cos(lng)*_radius; - y = sin(lng)*_radius; - Vector3f v3 = Vector3f(x, y, z); - Vector3f v3b = Vector3f(x, y, -z); - - tmpVertices.pushBack(v2); - tmpVertices.pushBack(v3); - tmpVertices.pushBack(v3b); - - tmpVertices.pushBack(v2); - tmpVertices.pushBack(v3b); - tmpVertices.pushBack(v2b); - } - // center to border (BUTTOM) - for(int jjj=0; jjj<_longs; ++jjj) { - float lng = 2.0f * M_PI * float(jjj - 1) / _longs; - - float z = _size*-0.5f; - Vector3f v1 = Vector3f(0.0f, 0.0f, z); - - float x = cos(lng)*_radius; - float y = sin(lng)*_radius; - Vector3f v2 = Vector3f(x, y, z); - - lng = 2.0f * M_PI * float(jjj) / _longs; - x = cos(lng)*_radius; - y = sin(lng)*_radius; - Vector3f v3 = Vector3f(x, y, z); - tmpVertices.pushBack(v1); - tmpVertices.pushBack(v2); - tmpVertices.pushBack(v3); - } - draw(tmpVertices, _tmpColor, _transformationMatrix); -} -void ewol::resource::Colored3DObject::drawCapsule(float _radius, - float _size, - int _lats, - int _longs, - mat4 _transformationMatrix, - etk::Color _tmpColor) { - List tmpVertices; - _lats = int(_lats / 2)*2; - - // center to border (TOP) - float offset = _size*0.5f; - for(int iii=_lats/2+1; iii<=_lats; ++iii) { - float lat0 = M_PI * (-0.5f + float(iii - 1) / _lats); - float z0 = _radius*sin(lat0); - float zr0 = _radius*cos(lat0); - - float lat1 = M_PI * (-0.5f + float(iii) / _lats); - float z1 = _radius*sin(lat1); - float zr1 = _radius*cos(lat1); - - for(int jjj=0; jjj<_longs; ++jjj) { - float lng = 2.0f * M_PI * float(jjj - 1) / _longs; - float x = cos(lng); - float y = sin(lng); - Vector3f v1 = Vector3f(x * zr1, y * zr1, z1+offset); - Vector3f v4 = Vector3f(x * zr0, y * zr0, z0+offset); - - lng = 2 * M_PI * float(jjj) / _longs; - x = cos(lng); - y = sin(lng); - Vector3f v2 = Vector3f(x * zr1, y * zr1, z1+offset); - Vector3f v3 = Vector3f(x * zr0, y * zr0, z0+offset); - tmpVertices.pushBack(v1); - tmpVertices.pushBack(v2); - tmpVertices.pushBack(v3); - - tmpVertices.pushBack(v1); - tmpVertices.pushBack(v3); - tmpVertices.pushBack(v4); - } - } - // Cylinder - for(int jjj=0; jjj<_longs; ++jjj) { - float lng = 2.0f * M_PI * float(jjj - 1) / _longs; - - float z = _size*0.5f; - - float x = cos(lng)*_radius; - float y = sin(lng)*_radius; - Vector3f v2 = Vector3f(x, y, z); - Vector3f v2b = Vector3f(x, y, -z); - - lng = 2.0f * M_PI * float(jjj) / _longs; - x = cos(lng)*_radius; - y = sin(lng)*_radius; - Vector3f v3 = Vector3f(x, y, z); - Vector3f v3b = Vector3f(x, y, -z); - - tmpVertices.pushBack(v2); - tmpVertices.pushBack(v3); - tmpVertices.pushBack(v3b); - - tmpVertices.pushBack(v2); - tmpVertices.pushBack(v3b); - tmpVertices.pushBack(v2b); - } - // center to border (BUTTOM) - offset = -_size*0.5f; - for(int iii=0; iii<=_lats/2; ++iii) { - float lat0 = M_PI * (-0.5f + float(iii - 1) / _lats); - float z0 = _radius*sin(lat0); - float zr0 = _radius*cos(lat0); - - float lat1 = M_PI * (-0.5f + float(iii) / _lats); - float z1 = _radius*sin(lat1); - float zr1 = _radius*cos(lat1); - - for(int jjj=0; jjj<_longs; ++jjj) { - float lng = 2.0f * M_PI * float(jjj - 1) / _longs; - float x = cos(lng); - float y = sin(lng); - Vector3f v1 = Vector3f(x * zr1, y * zr1, z1+offset); - Vector3f v4 = Vector3f(x * zr0, y * zr0, z0+offset); - - lng = 2 * M_PI * float(jjj) / _longs; - x = cos(lng); - y = sin(lng); - Vector3f v2 = Vector3f(x * zr1, y * zr1, z1+offset); - Vector3f v3 = Vector3f(x * zr0, y * zr0, z0+offset); - tmpVertices.pushBack(v1); - tmpVertices.pushBack(v2); - tmpVertices.pushBack(v3); - - tmpVertices.pushBack(v1); - tmpVertices.pushBack(v3); - tmpVertices.pushBack(v4); - } - } - draw(tmpVertices, _tmpColor, _transformationMatrix); -} - -void ewol::resource::Colored3DObject::drawCone(float _radius, - float _size, - int _lats, - int _longs, - mat4 _transformationMatrix, - etk::Color _tmpColor) { - List tmpVertices; - // center to border (TOP) - for(int jjj=0; jjj<_longs; ++jjj) { - float lng = 2.0f * M_PI * float(jjj - 1) / _longs; - Vector3f v1 = Vector3f(0.0f, 0.0f, -_size/2); - - float x = cos(lng)*_radius; - float y = sin(lng)*_radius; - Vector3f v2 = Vector3f(x, y, _size/2); - - lng = 2.0f * M_PI * float(jjj) / _longs; - x = cos(lng)*_radius; - y = sin(lng)*_radius; - Vector3f v3 = Vector3f(x, y, _size/2); - tmpVertices.pushBack(v1); - tmpVertices.pushBack(v3); - tmpVertices.pushBack(v2); - } - // center to border (BUTTOM) - for(int jjj=0; jjj<_longs; ++jjj) { - float lng = 2.0f * M_PI * float(jjj - 1) / _longs; - - Vector3f v1 = Vector3f(0.0f, 0.0f, _size/2); - - float x = cos(lng)*_radius; - float y = sin(lng)*_radius; - Vector3f v2 = Vector3f(x, y, _size/2); - - lng = 2.0f * M_PI * float(jjj) / _longs; - x = cos(lng)*_radius; - y = sin(lng)*_radius; - Vector3f v3 = Vector3f(x, y, _size/2); - tmpVertices.pushBack(v1); - tmpVertices.pushBack(v2); - tmpVertices.pushBack(v3); - } - draw(tmpVertices, _tmpColor, _transformationMatrix); -} - -void ewol::resource::Colored3DObject::drawTriangles( List _vertex, - List _indice, - mat4 _transformationMatrix, - etk::Color _tmpColor, - Vector3f _offset) { - List tmpVertices; - for (int iii=0; iii<_indice.size()/3; ++iii) { - tmpVertices.pushBack(_vertex[_indice[iii*3 + 0]]+_offset); - tmpVertices.pushBack(_vertex[_indice[iii*3 + 1]]+_offset); - tmpVertices.pushBack(_vertex[_indice[iii*3 + 2]]+_offset); - //Log.info(" indices " + _indice[iii*3 + 0] + " " + _indice[iii*3 + 1] + " " + _indice[iii*3 + 2]); - //Log.info(" triangle " + _vertex[_indice[iii*3 + 0]] + " " + _vertex[_indice[iii*3 + 1]] + " " + _vertex[_indice[iii*3 + 2]]); - } - //Log.info("display " + tmpVertices.size() + " vertices form " + _indice.size()); - draw(tmpVertices, _tmpColor, _transformationMatrix); -} - -namespace etk { - template<> String toString(ewol::resource::Colored3DObject ) { - return "!!ewol::resource::Colored3DObject!ERROR!CAN_NOT_BE_CONVERT!!"; - } -} -#include - -// declare for signal event -ESIGNAL_DECLARE_SIGNAL(ewol::resource::Colored3DObject); -ESIGNAL_DECLARE_SIGNAL(ememory::Ptr); - -#endif - diff --git a/src/org/atriasoft/ewol/resource/Colored3DObject.java b/src/org/atriasoft/ewol/resource/Colored3DObject.java deleted file mode 100644 index 28caea8..0000000 --- a/src/org/atriasoft/ewol/resource/Colored3DObject.java +++ /dev/null @@ -1,89 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ -#pragma once - -#ifndef __TARGET_OS__Web - -#include -#include -#include -#include - -namespace ewol { - namespace resource { - /** - * @brief simple display of Colored3DObject ==> for DEBUG only Not availlable on ALL platform (like webGL) - */ - class Colored3DObject : public gale::Resource { - protected: - ememory::Ptr this.GLprogram; - int this.GLPosition; - int this.GLMatrix; - int this.GLColor; - protected: - Colored3DObject(); - void init(); - public: - DECLARE_RESOURCE_FACTORY(Colored3DObject); - ~Colored3DObject(); - public: - void draw( List _vertices, - etk::Color _color, - boolean _updateDepthBuffer=true, - boolean _depthtest=true); - void draw( List _vertices, - etk::Color _color, - mat4 _transformationMatrix, - boolean _updateDepthBuffer=true, - boolean _depthtest=true); - void drawLine(List _vertices, - etk::Color _color, - mat4 _transformationMatrix, - boolean _updateDepthBuffer=true, - boolean _depthtest=true); - void drawCubeLine( Vector3f _min, - Vector3f _max, - etk::Color _color, - mat4 _transformationMatrix, - boolean _updateDepthBuffer=true, - boolean _depthtest=true); - public: - void drawSquare( Vector3f _size, - mat4 _transformationMatrix, - etk::Color _tmpColor); - void drawSphere(float _radius, - int _lats, - int _longs, - mat4 _transformationMatrix, - etk::Color _tmpColor); - void drawCylinder(float _radius, - float _size, - int _lats, - int _longs, - mat4 _transformationMatrix, - etk::Color _tmpColor); - void drawCapsule(float _radius, - float _size, - int _lats, - int _longs, - mat4 _transformationMatrix, - etk::Color _tmpColor); - void drawCone(float _radius, - float _size, - int _lats, - int _longs, - mat4 _transformationMatrix, - etk::Color _tmpColor); - void drawTriangles( List _vertex, - List _indice, - mat4 _transformationMatrix, - etk::Color _tmpColor, - Vector3f _offset=Vector3f(0,0,0.1)); - }; - }; -}; - -#endif diff --git a/src/org/atriasoft/ewol/resource/ConfigFile.cpp b/src/org/atriasoft/ewol/resource/ConfigFile.cpp deleted file mode 100644 index 9ae4b63..0000000 --- a/src/org/atriasoft/ewol/resource/ConfigFile.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -ETK_DECLARE_TYPE(ewol::resource::ConfigFile); - -ewol::resource::ConfigFile::ConfigFile() : - gale::Resource(), - // set map unorderred - this.list(0, false) { - addResourceType("ewol::ConfigFile"); -} - -void ewol::resource::ConfigFile::init( etk::Uri _uri) { - ethread::RecursiveLock lock(this.mutex); - gale::Resource::init(_uri.get()); - Log.debug("SFP : load \"" + _uri + "\""); - reload(); -} - - -ewol::resource::ConfigFile::~ConfigFile() { - this.list.clear(); -} - -void ewol::resource::ConfigFile::reload() { - ethread::RecursiveLock lock(this.mutex); - // reset all parameters - for (int iii=0; iii -#include -#include -#include -#include - -namespace ewol { - namespace resource { - class ConfigFile : public gale::Resource { - private: - ejson::Document this.doc; - etk::Map this.list; - protected: - ConfigFile(); - void init( etk::Uri _filename); - public: - ~ConfigFile(); - DECLARE_RESOURCE_URI_FACTORY(ConfigFile); - public: - void reload(); - - int request( String _paramName); - - double getNumber(int _id); - String getString(int _id); - boolean getBoolean(int _id); - public: - /** - * @brief keep the resource pointer. - * @note Never free this pointer by your own... - * @param[in] _filename Name of the configuration file. - * @return pointer on the resource or null if an error occured. - */ - static ememory::Ptr keep( String _filename); - }; - }; -}; diff --git a/src/org/atriasoft/ewol/resource/DistanceFieldFont.cpp b/src/org/atriasoft/ewol/resource/DistanceFieldFont.cpp deleted file mode 100644 index 3f8ff71..0000000 --- a/src/org/atriasoft/ewol/resource/DistanceFieldFont.cpp +++ /dev/null @@ -1,470 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#define SIZE_GENERATION (30) - -#include -ETK_DECLARE_TYPE(ewol::resource::DistanceFieldFont); - -ewol::resource::DistanceFieldFont::DistanceFieldFont() : - ewol::resource::Texture(), - this.borderSize(10), - this.textureBorderSize(0,0) { - addResourceType("ewol::resource::DistanceFieldFont"); - this.font = null; - this.lastGlyphPos.setValue(1,1); - this.lastRawHeigh = 0; - this.sizeRatio = 1.0f; -} - -/** - * @brief Get all the Path contain in the specidy path: - * @param[in] _path Generic path to parse ... - * @return The list of path found - * @example[start] - * auto out = explodeMultiplePath("DATA:///font?lib=ewol"); - * // out contain: {"DATA:///font", "DATA:///font?lib=ewol"} - * @example[stop] - */ -static List explodeMultiplePath( etk::Uri _uri) { - List out; - out.pushBack(_uri); - if (_uri.getQuery().exist("lib") == true) { - etk::Uri tmp = _uri; - tmp.getQuery().erase("lib"); - out.pushBack(tmp); - } - return out; -} - -void ewol::resource::DistanceFieldFont::init( String _fontName) { - ethread::RecursiveLock lock(this.mutex); - ewol::resource::Texture::init(_fontName); - String localName = _fontName; - List folderList; - if (ewol::getContext().getFontDefault().getUseExternal() == true) { - #if defined(__TARGET_OS__Android) - folderList.pushBack(etk::Path("/system/fonts")); - #elif defined(__TARGET_OS__Linux) - folderList.pushBack(etk::Path("/usr/share/fonts")); - #endif - } - etk::Uri applicationBaseFont = ewol::getContext().getFontDefault().getFolder(); - for (auto it : explodeMultiplePath(applicationBaseFont)) { - folderList.pushBack(it); - } - for (int folderID = 0; folderID < folderList.size() ; folderID++) { - List output = etk::uri::listRecursive(folderList[folderID]); - - List split = etk::split(localName, ';'); - Log.info("try to find font named : " + split + " in: " + output); - //Log.critical("parse string : " + split); - boolean hasFindAFont = false; - for (int jjj=0; jjj maybe estimate it with the dpi ??? - setImageSize(Vector2i(512,32)); - // now we can acces directly on the image - this.data.clear(etk::Color<>(0x00000000)); - // add error glyph - addGlyph(0); - // by default we set only the first AINSI char availlable - for (int iii=0x20; iii<0x7F; iii++) { - addGlyph(iii); - } - flush(); - if (true) { - Log.error("Save in cache the loaded data ..... "); - egami::store(this.data, "CACHE:///fileFont.bmp"); // ==> for debug test only ... - egami::store(this.data, "CACHE:///fileFont.png"); - } - exportOnFile(); -} - -ewol::resource::DistanceFieldFont::~DistanceFieldFont() { - -} - - -float ewol::resource::DistanceFieldFont::getDisplayRatio(float _size) { - ethread::RecursiveLock lock(this.mutex); - return _size / (float)SIZE_GENERATION; -} - - -void ewol::resource::DistanceFieldFont::generateDistanceField( egami::ImageMono _input, egami::Image _output) { - Log.info("Generate Distance field font [START]"); - Log.info(" _input.getSize()=" + _input.getSize()); - ethread::RecursiveLock lock(this.mutex); - int size = _input.getSize().x() * _input.getSize().y(); - List xdist; - List ydist; - List gx; - List gy; - List data; - List outside; - List inside; - xdist.resize(size, 0); - ydist.resize(size, 0); - gx.resize(size, 0.0); - gy.resize(size, 0.0); - data.resize(size, 0.0); - outside.resize(size, 0.0); - inside.resize(size, 0.0); - Log.info(" size=" + size); - // Convert img into double (data) - double img_min = 255, img_max = -255; - for (int yyy = 0; yyy < _input.getSize().y(); ++yyy) { - for (int xxx = 0; xxx < _input.getSize().x(); ++xxx) { - int iii = yyy * _input.getSize().x() + xxx; - double v = _input.get(Vector2i(xxx, yyy)); - data[iii] = v; - if (v > img_max) { - img_max = v; - } - if (v < img_min) { - img_min = v; - } - } - } - // Rescale image levels between 0 and 1 - for (int yyy = 0; yyy < _input.getSize().y(); ++yyy) { - for (int xxx = 0; xxx < _input.getSize().x(); ++xxx) { - int iii = yyy * _input.getSize().x() + xxx; - data[iii] = (_input.get(Vector2i(xxx, yyy))-img_min)/img_max; - } - } - // Compute outside = edtaa3(bitmap); % Transform background (0's) - computegradient(data[0], _input.getSize().x(), _input.getSize().y(), gx[0], gy[0]); - edtaa3(data[0], gx[0], gy[0], _input.getSize().x(), _input.getSize().y(), xdist[0], &ydist[0], &outside[0]); - for(int iii = 0; iii < outside.size(); ++iii) { - if( outside[iii] < 0 ) { - outside[iii] = 0.0; - } - } - // Compute inside = edtaa3(1-bitmap); % Transform foreground (1's) - for(int iii = 0; iii < gx.size(); ++iii) { - gx[iii] = 0; - } - for(int iii = 0; iii < gy.size(); ++iii) { - gy[iii] = 0; - } - for(int iii = 0; iii < data.size(); ++iii) { - data[iii] = 1 - data[iii]; - } - computegradient( data[0], _input.getSize().x(), _input.getSize().y(), gx[0], gy[0]); - edtaa3(data[0], gx[0], gy[0], _input.getSize().x(), _input.getSize().y(), xdist[0], &ydist[0], &inside[0]); - for(int iii = 0; iii < inside.size(); ++iii) { - if( inside[iii] < 0 ) { - inside[iii] = 0.0; - } - } - Log.info(" _output=" + _output); - _output.resize(_input.getSize(), etk::Color<>(0)); - _output.clear(etk::Color<>(0)); - for (int xxx = 0; xxx < _output.getSize().x(); ++xxx) { - for (int yyy = 0; yyy < _output.getSize().y(); ++yyy) { - int iii = yyy * _output.getSize().x() + xxx; - outside[iii] -= inside[iii]; - outside[iii] = 128+outside[iii]*16; - if( outside[iii] < 0 ) { - outside[iii] = 0; - } - if( outside[iii] > 255 ) { - outside[iii] = 255; - } - int val = 255 - (unsigned char) outside[iii]; - // TODO : Remove multiple size of the map ... - _output.set(Vector2i(xxx, yyy), etk::Color<>((int)val,(int)val,(int)val,255)); - } - } - Log.info(" _output=" + _output); -} - -boolean ewol::resource::DistanceFieldFont::addGlyph( Character _val) { - ethread::RecursiveLock lock(this.mutex); - boolean hasChange = false; - if (this.font == null) { - return false; - } - // add the curent "char" - GlyphProperty tmpchar; - tmpchar.this.UVal = _val; - egami::ImageMono imageGlyphRaw; - egami::Image imageGlyphDistanceField(Vector2i(32,32), egami::colorType::RGBA8); - Log.debug("Generate Glyph : " + _val); - - if (this.font.getGlyphProperty(SIZE_GENERATION, tmpchar) == true) { - //Log.debug("load char: '" + _val + "'=" + _val); - hasChange = true; - // change line if needed ... - if (this.lastGlyphPos.x() + tmpchar.this.sizeTexture.x()+this.borderSize*2.0 > this.data.getSize().x()) { - this.lastGlyphPos.setX(1); - this.lastGlyphPos += Vector2i(0, this.lastRawHeigh); - this.lastRawHeigh = 0; - } - while(this.lastGlyphPos.y()+tmpchar.this.sizeTexture.y()+this.borderSize*2.0 > this.data.getSize().y()) { - Vector2i size = this.data.getSize(); - size.setY(size.y()*2); - Log.verbose("resize " + this.data.getSize() + " => " + size); - this.data.resize(size, etk::Color<>(0)); - // change the coordonate on the element in the texture - for (int jjj = 0; jjj < this.listElement.size(); ++jjj) { - this.listElement[jjj].this.texturePosStart *= Vector2f(1.0f, 0.5f); - this.listElement[jjj].this.texturePosSize *= Vector2f(1.0f, 0.5f); - } - } - this.textureBorderSize = Vector2f(this.borderSize/(float)this.data.getSize().x(), - this.borderSize/(float)this.data.getSize().y() ); - // draw the glyph - this.font.drawGlyph(imageGlyphRaw, SIZE_GENERATION, tmpchar, this.borderSize); - - generateDistanceField(imageGlyphRaw, imageGlyphDistanceField); - - if (_val == 100) { - Log.debug("print char: " + _val + " size=" + imageGlyphDistanceField.getSize()); - for (int yyy = 0; yyy < imageGlyphDistanceField.getSize().y(); ++yyy) { - for (int xxx = 0; xxx < imageGlyphDistanceField.getSize().x(); ++xxx) { - Log.print((int)(imageGlyphDistanceField.get(Vector2i(xxx, yyy)).r()) + " "); - } - } - } - - this.data.insert(this.lastGlyphPos, imageGlyphDistanceField); - - // set image position - tmpchar.this.texturePosStart.setValue( ((float)this.lastGlyphPos.x()+(this.borderSize*0.5f)) / (float)this.data.getSize().x(), - ((float)this.lastGlyphPos.y()+(this.borderSize*0.5f)) / (float)this.data.getSize().y() ); - tmpchar.this.texturePosSize.setValue( ((float)imageGlyphRaw.getSize().x()-this.borderSize) / (float)this.data.getSize().x(), - ((float)imageGlyphRaw.getSize().y()-this.borderSize) / (float)this.data.getSize().y() ); - - // update the maximum of the line hight : - if (this.lastRawHeigh < imageGlyphRaw.getSize().y()) { - // note : +1 is for the overlapping of the glyph (Part 2) - this.lastRawHeigh = imageGlyphRaw.getSize().y()+1; - } - // note : +1 is for the overlapping of the glyph (Part 3) - // update the Bitmap position drawing : - this.lastGlyphPos += Vector2i(imageGlyphRaw.getSize().x()+1, 0); - } else { - Log.warning("Did not find char : '" + _val + "'=" + _val); - tmpchar.setNotExist(); - } - this.listElement.pushBack(tmpchar); - //this.font[iii].display(); - // generate the kerning for all the characters : - if (tmpchar.exist() == true) { - // TODO : set the kerning back ... - //this.font[iii].generateKerning(this.size, this.listElement[iii]); - } - if (hasChange == true) { - flush(); - //Log.error("Save in cache the loaded data ..... "); - //egami::store(this.data, "CACHE:///fileFont.bmp"); // ==> for debug test only ... - //egami::store(this.data, "CACHE:///fileFont.png"); - } - return hasChange; -} - -int ewol::resource::DistanceFieldFont::getIndex(Character _charcode) { - ethread::RecursiveLock lock(this.mutex); - if (_charcode < 0x20) { - return 0; - } else if (_charcode < 0x80) { - return _charcode - 0x1F; - } else { - for (int iii=0x80-0x20; iii < this.listElement.size(); iii++) { - //Log.debug("search : '" + charcode + "' =?= '" + (this.listElement[displayMode])[iii].this.UVal + "'"); - if (_charcode == (this.listElement)[iii].this.UVal) { - //Log.debug("search : '" + charcode + "'"); - if ((this.listElement)[iii].exist()) { - //Log.debug("return " + iii); - return iii; - } else { - return 0; - } - } - } - } - if (addGlyph(_charcode) == true) { - // TODO : This does not work due to the fact that the update of open GL is not done in the context main cycle !!! - ewol::getContext().forceRedrawAll(); - } - return 0; -} - -ewol::GlyphProperty* ewol::resource::DistanceFieldFont::getGlyphPointer( Character _charcode) { - ethread::RecursiveLock lock(this.mutex); - Log.verbose("getGlyphPointer : " + uint(_charcode)); - int index = getIndex(_charcode); - if( index < 0 - || (int)index >= this.listElement.size() ) { - Log.error(" Try to get glyph index inexistant ... == > return the index 0 ... id=" + index); - if (this.listElement.size() > 0) { - return ((this.listElement)[0]); - } - return null; - } - //Log.error(" index=" + index); - //Log.error(" this.UVal=" + this.listElement[_displayMode][index].this.UVal); - //Log.error(" this.glyphIndex=" + this.listElement[_displayMode][index].this.glyphIndex); - //Log.error(" this.advance=" + this.listElement[_displayMode][index].this.advance); - //Log.error(" this.bearing=" + this.listElement[_displayMode][index].this.bearing); - return ((this.listElement)[index]); -} - -void ewol::resource::DistanceFieldFont::exportOnFile() { - ethread::RecursiveLock lock(this.mutex); - Log.debug("EXPORT: DistanceFieldFont : file : '" + this.fileName + ".json'"); - ejson::Document doc; - ejson::Array tmpList; - for (int iii=0; iii -#include -#include - -namespace ewol { - namespace resource { - class DistanceFieldFont : public ewol::resource::Texture { - private: - etk::Uri this.fileName; - float this.sizeRatio; - // specific element to have the the know if the specify element is known... - // == > otherwise I can just generate italic ... - // == > Bold is a little more complicated (maybe with the bordersize) - ememory::Ptr this.font; - public: - List this.listElement; - private: - // for the texture generation : - Vector2i this.lastGlyphPos; - int this.lastRawHeigh; - protected: - DistanceFieldFont(); - void init( String _fontName); - public: - DECLARE_RESOURCE_NAMED_FACTORY(DistanceFieldFont); - ~DistanceFieldFont(); - public: - float getDisplayRatio(float _size); - /** - * @brief get the display height of this font - * @param[in] _size Request font size - * @return Dimention of the font need between 2 lines - */ - float getHeight(float _size) { - return ((float)this.font.getHeight(_size)); - }; - /** - * @brief get the font size with a specific display size - * @param[in] _fontHeight Request font height - * @return Dimention of the font for this compleate line size. - */ - float getSize(float _fontHeight) { - return this.font.getSizeWithHeight(_fontHeight); - } - /** - * @brief get the ID of a unicode charcode - * @param[in] _charcode The unicodeValue - * @return The ID in the table (if it does not exist : return 0) - */ - int getIndex(Character _charcode); - /** - * @brief get the pointer on the coresponding glyph - * @param[in] _charcode The unicodeValue - * @return The pointer on the glyph == > never null - */ - ewol::GlyphProperty* getGlyphPointer( Character _charcode); - public: - /** - * @brief keep the resource pointer. - * @note Never free this pointer by your own... - * @param[in] _filename Name of the texture font. - * @return pointer on the resource or null if an error occured. - */ - static ememory::Ptr keep( String _filename); - private: - /** - * @brief add a glyph in a texture font. - * @param[in] _val Char value to add. - * @return true if the image size have change, false otherwise - */ - boolean addGlyph( Character _val); - - void generateDistanceField( egami::ImageMono _input, egami::Image _output); - private: - float this.borderSize; //!< number of pixel added on the border of a glyph - Vector2f this.textureBorderSize; //!< Transformed the border size in the texture dimention - public: - float getPixelBorderSize() { - return this.borderSize; - } - Vector2f getTextureBorderSize() { - return this.textureBorderSize; - } - public: - void exportOnFile(); - boolean importFromFile(); - }; - }; -}; diff --git a/src/org/atriasoft/ewol/resource/FontFreeType.cpp b/src/org/atriasoft/ewol/resource/FontFreeType.cpp deleted file mode 100644 index 319ec63..0000000 --- a/src/org/atriasoft/ewol/resource/FontFreeType.cpp +++ /dev/null @@ -1,384 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include - - -#include - -#include -#include -#include -#include - -#include -ETK_DECLARE_TYPE(ewol::resource::FontFreeType); - -// free Font hnadle of librairies ... entry for acces ... -static int l_countLoaded=0; -static FT_Library library; - -void ewol::resource::freeTypeInit() { - Log.debug(" == > init Font-Manager"); - l_countLoaded++; - if (l_countLoaded>1) { - // already loaded ... - return; - } - int error = FT_Init_FreeType( library ); - if(0 != error) { - Log.critical(" when loading FreeType Librairy ..."); - } -} - -void ewol::resource::freeTypeUnInit() { - Log.debug(" == > Un-Init Font-Manager"); - l_countLoaded--; - if (l_countLoaded>0) { - // already needed ... - return; - } - int error = FT_Done_FreeType( library ); - library = null; - if(0 != error) { - Log.critical(" when Un-loading FreeType Librairy ..."); - } -} - -ewol::resource::FontFreeType::FontFreeType() { - addResourceType("ewol::FontFreeType"); - this.init = false; - this.FileSize = 0; -} - -void ewol::resource::FontFreeType::init( etk::Uri _uri) { - ethread::RecursiveLock lock(this.mutex); - ewol::resource::FontBase::init(_uri); - auto fileIO = etk::uri::get(_uri); - if (fileIO == null) { - Log.error("File Does not exist : " + _uri); - return; - } - if (fileIO.open(etk::io::OpenMode::Read) == false) { - Log.error("Can not open the file : " + _uri); - return; - } - this.FileBuffer = fileIO.readAll(); - // close the file: - fileIO.close(); - // load Face ... - int error = FT_New_Memory_Face(library, this.FileBuffer[0], this.FileBuffer.size(), 0, this.fftFace ); - if( FT_Err_Unknown_File_Format == error) { - Log.error("... the font file could be opened and read, but it appears ... that its font format is unsupported"); - } else if (0 != error) { - Log.error("... another error code means that the font file could not ... be opened or read, or simply that it is broken..."); - } else { - // all OK - Log.debug("load font : \"" + _uri + "\" glyph count = " + (int)this.fftFace.nuthis.glyphs); - this.init = true; - //display(); - } -} - -ewol::resource::FontFreeType::~FontFreeType() { - ethread::RecursiveLock lock(this.mutex); - // clean the tmp memory - this.FileBuffer.clear(); - // must be deleted fftFace - FT_Done_Face(this.fftFace); -} - -Vector2f ewol::resource::FontFreeType::getSize(int _fontSize, String _unicodeString) { - ethread::RecursiveLock lock(this.mutex); - if (this.init == false) { - return Vector2f(0,0); - } - // TODO : ... - Vector2f outputSize(0,0); - return outputSize; -} - -int ewol::resource::FontFreeType::getHeight(int _fontSize) { - ethread::RecursiveLock lock(this.mutex); - return _fontSize*1.43f; // this is a really "magic" number ... -} -float ewol::resource::FontFreeType::getSizeWithHeight(float _fontHeight) { - ethread::RecursiveLock lock(this.mutex); - return _fontHeight*0.6993f; // this is a really "magic" number ... -} - -boolean ewol::resource::FontFreeType::getGlyphProperty(int _fontSize, ewol::GlyphProperty _property) { - ethread::RecursiveLock lock(this.mutex); - if(false == this.init) { - return false; - } - // 300dpi (hight quality) 96 dpi (normal quality) - int fontQuality = 96; - // Select size ... - // note tha +6 == *64 corespond with the 1/64th of points calculation of freetype - int error = FT_Set_Char_Size(this.fftFace, _fontSize+6, _fontSize+6, fontQuality, fontQuality); - if (0!=error ) { - Log.error("FT_Set_Char_Size == > error in settings ..."); - return false; - } - // a small shortcut - FT_GlyphSlot slot = this.fftFace.glyph; - // retrieve glyph index from character code - int glyph_index = FT_Get_Char_Index(this.fftFace, _property.this.UVal); - // load glyph image into the slot (erase previous one) - error = FT_Load_Glyph(this.fftFace, // handle to face object - glyph_index, // glyph index - FT_LOAD_DEFAULT ); - if (0!=error ) { - Log.error("FT_Load_Glyph specify Glyph"); - return false; - } - // convert to an anti-aliased bitmap - error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL ); - if (0!=error) { - Log.error("FT_Render_Glyph"); - return false; - } - // set properties : - _property.this.glyphIndex = glyph_index; - _property.this.sizeTexture.setValue(slot.bitmap.width, slot.bitmap.rows); - _property.this.bearing.setValue( slot.metrics.horiBearingX>>6 , slot.metrics.horiBearingY>>6 ); - _property.this.advance.setValue( slot.metrics.horiAdvance>>6 , slot.metrics.vertAdvance>>6 ); - - return true; -} - -boolean ewol::resource::FontFreeType::drawGlyph(egami::Image _imageOut, - int _fontSize, - Vector2i _glyphPosition, - ewol::GlyphProperty _property, - int8_t _posInImage) { - ethread::RecursiveLock lock(this.mutex); - if(this.init == false) { - return false; - } - // 300dpi (hight quality) 96 dpi (normal quality) - int fontQuality = 96; - // Select size ... - // note tha +6 == *64 corespond with the 1/64th of points calculation of freetype - int error = FT_Set_Char_Size(this.fftFace, _fontSize+6, _fontSize+6, fontQuality, fontQuality); - if (0!=error ) { - Log.error("FT_Set_Char_Size == > error in settings ..."); - return false; - } - // a small shortcut - FT_GlyphSlot slot = this.fftFace.glyph; - // load glyph image into the slot (erase previous one) - error = FT_Load_Glyph(this.fftFace, // handle to face object - _property.this.glyphIndex, // glyph index - FT_LOAD_DEFAULT ); - if (0!=error ) { - Log.error("FT_Load_Glyph specify Glyph"); - return false; - } - // convert to an anti-aliased bitmap - error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL ); - if (0!=error) { - Log.error("FT_Render_Glyph"); - return false; - } - // draw it on the output Image : - etk::Color<> tlpppp(0xFF, 0xFF, 0xFF, 0x00); - for(int jjj=0; jjj < slot.bitmap.rows;jjj++) { - for(int iii=0; iii < slot.bitmap.width; iii++){ - tlpppp = _imageOut.get(Vector2i(_glyphPosition.x()+iii, _glyphPosition.y()+jjj)); - int valueColor = slot.bitmap.buffer[iii + slot.bitmap.width*jjj]; - // set only alpha : - switch(_posInImage) { - default: - case 0: - tlpppp.setA(valueColor); - break; - case 1: - tlpppp.setR(valueColor); - break; - case 2: - tlpppp.setG(valueColor); - break; - case 3: - tlpppp.setB(valueColor); - break; - } - // real set of color - _imageOut.set(Vector2i(_glyphPosition.x()+iii, _glyphPosition.y()+jjj), tlpppp ); - } - } - return true; -} - -boolean ewol::resource::FontFreeType::drawGlyph(egami::ImageMono _imageOut, - int _fontSize, - ewol::GlyphProperty _property, - int _borderSize) { - ethread::RecursiveLock lock(this.mutex); - if(false == this.init) { - return false; - } - // 300dpi (hight quality) 96 dpi (normal quality) - int fontQuality = 96; - // Select size ... - // note tha +6 == *64 corespond with the 1/64th of points calculation of freetype - int error = FT_Set_Char_Size(this.fftFace, _fontSize+6, _fontSize+6, fontQuality, fontQuality); - if (0!=error ) { - Log.error("FT_Set_Char_Size == > error in settings ..."); - return false; - } - // a small shortcut - FT_GlyphSlot slot = this.fftFace.glyph; - // load glyph image into the slot (erase previous one) - error = FT_Load_Glyph(this.fftFace, // handle to face object - _property.this.glyphIndex, // glyph index - FT_LOAD_DEFAULT ); - if (0!=error ) { - Log.error("FT_Load_Glyph specify Glyph"); - return false; - } - // convert to an anti-aliased bitmap - error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL ); // TODO : set FT_RENDER_MODE_MONO ==> 1 bit value ==> faster generation ... - if (0!=error) { - Log.error("FT_Render_Glyph"); - return false; - } - // resize output image : - _imageOut.resize(Vector2i(slot.bitmap.width+2*_borderSize, slot.bitmap.rows+2*_borderSize), 0); - - for(int jjj=0; jjj < slot.bitmap.rows;jjj++) { - for(int iii=0; iii < slot.bitmap.width; iii++){ - int valueColor = slot.bitmap.buffer[iii + slot.bitmap.width*jjj]; - // real set of color - _imageOut.set(Vector2i(_borderSize+iii, _borderSize+jjj), valueColor ); - } - } - return true; -} - - -void ewol::resource::FontFreeType::generateKerning(int fontSize, List listGlyph) { - ethread::RecursiveLock lock(this.mutex); - if(this.init == false) { - return; - } - if ((FT_FACE_FLAG_KERNING this.fftFace.face_flags) == 0) { - Log.info("No kerning generation (disable) in the font"); - } - // 300dpi (hight quality) 96 dpi (normal quality) - int fontQuality = 96; - // Select size ... - // note tha +6 == *64 corespond with the 1/64th of points calculation of freetype - int error = FT_Set_Char_Size(this.fftFace, fontSize+6, fontSize+6, fontQuality, fontQuality); - if (0!=error ) { - Log.error("FT_Set_Char_Size == > error in settings ..."); - return; - } - // For all the kerning element we get the kerning value : - for(int iii=0; iii " + (kerning.x/64.0f)); - } - } - } -} - - -void ewol::resource::FontFreeType::display() { - ethread::RecursiveLock lock(this.mutex); - if(this.init == false) { - return; - } - Log.info(" number of glyph = " + (int)this.fftFace.nuthis.glyphs); - if ((FT_FACE_FLAG_SCALABLE this.fftFace.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_SCALABLE (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_SCALABLE (disable)"); - } - if ((FT_FACE_FLAG_FIXED_SIZES this.fftFace.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_FIXED_SIZES (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_FIXED_SIZES (disable)"); - } - if ((FT_FACE_FLAG_FIXED_WIDTH this.fftFace.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_FIXED_WIDTH (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_FIXED_WIDTH (disable)"); - } - if ((FT_FACE_FLAG_SFNT this.fftFace.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_SFNT (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_SFNT (disable)"); - } - if ((FT_FACE_FLAG_HORIZONTAL this.fftFace.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_HORIZONTAL (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_HORIZONTAL (disable)"); - } - if ((FT_FACE_FLAG_VERTICAL this.fftFace.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_VERTICAL (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_VERTICAL (disable)"); - } - if ((FT_FACE_FLAG_KERNING this.fftFace.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_KERNING (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_KERNING (disable)"); - } - /* Deprecated flag - if ((FT_FACE_FLAG_FAST_GLYPHS face.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_FAST_GLYPHS (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_FAST_GLYPHS (disable)"); - } - */ - if ((FT_FACE_FLAG_MULTIPLE_MASTERS this.fftFace.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_MULTIPLE_MASTERS (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_MULTIPLE_MASTERS (disable)"); - } - if ((FT_FACE_FLAG_GLYPH_NAMES this.fftFace.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_GLYPH_NAMES (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_GLYPH_NAMES (disable)"); - } - if ((FT_FACE_FLAG_EXTERNAL_STREAM this.fftFace.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_EXTERNAL_STREAM (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_EXTERNAL_STREAM (disable)"); - } - if ((FT_FACE_FLAG_HINTER this.fftFace.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_HINTER (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_HINTER (disable)"); - } - if ((FT_FACE_FLAG_CID_KEYED this.fftFace.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_CID_KEYED (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_CID_KEYED (disable)"); - } - /* - if ((FT_FACE_FLAG_TRICKY this.fftFace.face_flags) != 0) { - Log.info(" flags = FT_FACE_FLAG_TRICKY (enable)"); - } else { - Log.debug(" flags = FT_FACE_FLAG_TRICKY (disable)"); - } - */ - Log.info(" unit per EM = " + this.fftFace.units_per_EM); - Log.info(" num of fixed sizes = " + this.fftFace.nuthis.fixed_sizes); - //Log.info(" Availlable sizes = " + (int)this.fftFace.available_sizes); - - //Log.info(" Current size = " + (int)this.fftFace.size); -} diff --git a/src/org/atriasoft/ewol/resource/FontFreeType.java b/src/org/atriasoft/ewol/resource/FontFreeType.java deleted file mode 100644 index 9279162..0000000 --- a/src/org/atriasoft/ewol/resource/FontFreeType.java +++ /dev/null @@ -1,61 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ -#pragma once - -#include -#include -#include -#include - -extern "C" { - #include -} -#include FT_FREETYPE_H - -namespace ewol { - namespace resource { - // show : http://www.freetype.org/freetype2/docs/tutorial/step2.html - class FontFreeType : public ewol::resource::FontBase { - private: - List this.FileBuffer; - int this.FileSize; - FT_Face this.fftFace; - boolean this.init; - void display(); - protected: - FontFreeType(); - void init( etk::Uri _uri); - public: - DECLARE_RESOURCE_URI_FACTORY(FontFreeType); - ~FontFreeType(); - public: - - boolean getGlyphProperty(int _fontSize, - ewol::GlyphProperty _property); - - boolean drawGlyph(egami::Image _imageOut, - int _fontSize, - Vector2i _glyphPosition, - ewol::GlyphProperty _property, - int8_t _posInImage); - - boolean drawGlyph(egami::ImageMono _imageOut, - int _fontSize, - ewol::GlyphProperty _property, - int _borderSize = 0); - - Vector2f getSize(int _fontSize, String _unicodeString); - - int getHeight(int _fontSize); - float getSizeWithHeight(float _fontHeight); - - void generateKerning(int _fontSize, List _listGlyph); - }; - void freeTypeInit(); - void freeTypeUnInit(); - }; -}; - diff --git a/src/org/atriasoft/ewol/resource/ImageDF.cpp b/src/org/atriasoft/ewol/resource/ImageDF.cpp deleted file mode 100644 index de6aaa3..0000000 --- a/src/org/atriasoft/ewol/resource/ImageDF.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - - -#include -#include -#include -#include -#include -#include - -#include -ETK_DECLARE_TYPE(ewol::resource::ImageDF); - -ewol::resource::ImageDF::ImageDF() { - addResourceType("ewol::resource::ImageDF"); -} - - -void ewol::resource::ImageDF::init() { - ethread::RecursiveLock lock(this.mutex); - ewol::resource::Texture::init(); -} - -void ewol::resource::ImageDF::init(String _genName, etk::Uri _uri, Vector2i _size) { - ethread::RecursiveLock lock(this.mutex); - ewol::resource::Texture::init(_genName); - Log.debug("create a new resource::Image : _genName=" + _genName + " _uri=" + _uri + " size=" + _size); - this.data = egami::load(_uri, _size); - if (this.data.exist() == false) { - Log.error("ERROR when loading the image : " + _uri); - } - Vector2i tmp = this.data.getSize(); - this.realImageSize = Vector2f(tmp.x(), tmp.y()); - // distance field Generation - // TODO : if it is not a .edf ==> generate dynamicly ... - /* - egami::ImageMono input; - input.resize(tmp); - for (int yyy = 0; yyy < tmp.y(); ++yyy) { - for (int xxx = 0; xxx < tmp.x(); ++xxx) { - input.set(Vector2i(xxx, yyy), this.data.get(Vector2i(xxx, yyy)).a() ); - } - } - generateDistanceField(input, this.data); - */ - flush(); -} - - -void ewol::resource::ImageDF::generateDistanceField( egami::ImageMono _input, egami::Image _output) { - ethread::RecursiveLock lock(this.mutex); - int size = _input.getSize().x() * _input.getSize().y(); - List xdist; - List ydist; - List gx; - List gy; - List data; - List outside; - List inside; - xdist.resize(size, 0); - ydist.resize(size, 0); - gx.resize(size, 0.0); - gy.resize(size, 0.0); - data.resize(size, 0.0); - outside.resize(size, 0.0); - inside.resize(size, 0.0); - // Convert img into double (data) - double img_min = 255, img_max = -255; - for (int yyy = 0; yyy < _input.getSize().y(); ++yyy) { - for (int xxx = 0; xxx < _input.getSize().x(); ++xxx) { - int iii = yyy * _input.getSize().x() + xxx; - double v = _input.get(Vector2i(xxx, yyy)); - data[iii] = v; - if (v > img_max) { - img_max = v; - } - if (v < img_min) { - img_min = v; - } - } - } - // Rescale image levels between 0 and 1 - for (int yyy = 0; yyy < _input.getSize().y(); ++yyy) { - for (int xxx = 0; xxx < _input.getSize().x(); ++xxx) { - int iii = yyy * _input.getSize().x() + xxx; - data[iii] = (_input.get(Vector2i(xxx, yyy))-img_min)/img_max; - } - } - - // Compute outside = edtaa3(bitmap); % Transform background (0's) - computegradient(data[0], _input.getSize().x(), _input.getSize().y(), gx[0], gy[0]); - edtaa3(data[0], gx[0], gy[0], _input.getSize().x(), _input.getSize().y(), xdist[0], &ydist[0], &outside[0]); - for(int iii = 0; iii < outside.size(); ++iii) { - if( outside[iii] < 0 ) { - outside[iii] = 0.0; - } - } - - // Compute inside = edtaa3(1-bitmap); % Transform foreground (1's) - for(int iii = 0; iii < gx.size(); ++iii) { - gx[iii] = 0; - } - for(int iii = 0; iii < gy.size(); ++iii) { - gy[iii] = 0; - } - for(int iii = 0; iii < data.size(); ++iii) { - data[iii] = 1 - data[iii]; - } - computegradient( data[0], _input.getSize().x(), _input.getSize().y(), gx[0], gy[0]); - edtaa3(data[0], gx[0], gy[0], _input.getSize().x(), _input.getSize().y(), xdist[0], &ydist[0], &inside[0]); - for(int iii = 0; iii < inside.size(); ++iii) { - if( inside[iii] < 0 ) { - inside[iii] = 0.0; - } - } - - _output.resize(_input.getSize(), etk::Color<>(0)); - _output.clear(etk::Color<>(0)); - for (int xxx = 0; xxx < _output.getSize().x(); ++xxx) { - for (int yyy = 0; yyy < _output.getSize().y(); ++yyy) { - int iii = yyy * _output.getSize().x() + xxx; - outside[iii] -= inside[iii]; - outside[iii] = 128+outside[iii]*16; - if( outside[iii] < 0 ) { - outside[iii] = 0; - } - if( outside[iii] > 255 ) { - outside[iii] = 255; - } - int val = 255 - (unsigned char) outside[iii]; - // TODO : Remove multiple size of the map ... - _output.set(Vector2i(xxx, yyy), etk::Color<>((int)val,(int)val,(int)val,255)); - } - } -} - - -#ifdef __TARGET_OS__Android -/** - * @brief get the next power 2 if the input - * @param[in] _value Value that we want the next power of 2 - * @return result value - */ -static int nextP2(int _value) { - int val=1; - for (int iii=1; iii<31; iii++) { - if (_value <= val) { - return val; - } - val *=2; - } - Log.critical("impossible CASE.... request P2 of " + _value); - return val; -} -#endif - - - -ememory::Ptr ewol::resource::ImageDF::create( etk::Uri _uri, Vector2i _size) { - Log.verbose("KEEP: TextureFile: '" + _uri + "' size=" + _size); - if (_uri.isEmpty() == true) { - ememory::Ptr object(ETK_NEW(ewol::resource::ImageDF)); - if (object == null) { - Log.error("allocation error of a resource : ??TEX??"); - return null; - } - object.init(); - getManager().localAdd(object); - return object; - } - if (_size.x() == 0) { - _size.setX(-1); - //Log.error("Error Request the image size.x() =0 ???"); - } - if (_size.y() == 0) { - _size.setY(-1); - //Log.error("Error Request the image size.y() =0 ???"); - } - etk::Uri tmpFilename = _uri; - if (etk::toLower(_uri.getPath().getExtention()) != "svg") { - _size = Vector2i(-1,-1); - } - #ifdef __TARGET_OS__MacOs - Log.error("TODO : remove this strange hack"); - _size = Vector2i(64,64); - #endif - if ( _size.x() > 0 - LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM _size.y() > 0) { - Log.verbose(" == > specific size : " + _size); - #ifdef __TARGET_OS__Android - _size.setValue(nextP2(_size.x()), nextP2(_size.y())); - #endif - tmpFilename.getQuery().set("x", etk::toString(_size.x())); - tmpFilename.getQuery().set("y", etk::toString(_size.y())); - } - - Log.verbose("KEEP: TextureFile: '" + tmpFilename + "' new size=" + _size); - ememory::Ptr object = null; - ememory::Ptr object2 = getManager().localKeep("DF__" + tmpFilename.getString()); - if (object2 != null) { - object = ememory::dynamicPointerCast(object2); - if (object == null) { - Log.critical("Request resource file : '" + tmpFilename + "' With the wrong type (dynamic cast error)"); - return null; - } - } - if (object != null) { - return object; - } - Log.info("CREATE: ImageDF: '" + tmpFilename + "' size=" + _size); - // need to crate a new one ... - object = ememory::Ptr(ETK_NEW(ewol::resource::ImageDF)); - if (object == null) { - Log.error("allocation error of a resource : " + _uri); - return null; - } - object.init("DF__" + tmpFilename.getString(), _uri, _size); - getManager().localAdd(object); - return object; -} - diff --git a/src/org/atriasoft/ewol/resource/ImageDF.java b/src/org/atriasoft/ewol/resource/ImageDF.java deleted file mode 100644 index 90110dd..0000000 --- a/src/org/atriasoft/ewol/resource/ImageDF.java +++ /dev/null @@ -1,47 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ -#pragma once - -#include -#include -#include -#include - -namespace ewol { - namespace resource { - class ImageDF : public ewol::resource::Texture { - protected: - Vector2f this.realImageSize; - protected: - ImageDF(); - void init(); - void init(String _genName, etk::Uri _uri, Vector2i _size); - public: - ~ImageDF() { }; - protected: - /** - * @brief Generate distance field of this Image input. - * @param[in] _input Input image to change in distance field mode. - * @param[out] _output New image generate with this image _input. - */ - void generateDistanceField( egami::ImageMono _input, egami::Image _output); - public: - Vector2f getRealSize() { - return this.realImageSize; - }; - public: - /** - * @brief keep the resource pointer. - * @note Never free this pointer by your own... - * @param[in] _filename Name of the image file. - * @param[in] _requested size of the image (usefull when loading .svg to automatic rescale) - * @return pointer on the resource or null if an error occured. - */ - static ememory::Ptr create( etk::Uri _uri, Vector2i _size=Vector2i(-1,-1)); - }; - }; -}; - diff --git a/src/org/atriasoft/ewol/resource/RefactorColored3DObject.java b/src/org/atriasoft/ewol/resource/RefactorColored3DObject.java new file mode 100644 index 0000000..62a52e6 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/RefactorColored3DObject.java @@ -0,0 +1,493 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package org.atriasoft.ewol.resource; + +import java.util.ArrayList; +import java.util.List; + +import org.atriasoft.etk.Color; +import org.atriasoft.etk.Uri; +import org.atriasoft.etk.math.Matrix4f; +import org.atriasoft.etk.math.Vector3f; +import org.atriasoft.ewol.internal.Log; +import org.atriasoft.gale.backend3d.OpenGL; +import org.atriasoft.gale.resource.Resource; +import org.atriasoft.gale.resource.ResourceProgram; + +/** + * @brief simple display of Colored3DObject ==> for DEBUG only Not availlable on ALL platform (like webGL) + */ +public class RefactorColored3DObject extends Resource { + protected ResourceProgram GLprogram; + protected int GLPosition; + protected int GLMatrix; + protected int GLColor; + + public RefactorColored3DObject() { + super(); + // get the shader resource : + this.GLPosition = 0; + this.GLprogram = ResourceProgram.create(new Uri("DATA:///simple3D.vert?lib=ewol"), new Uri("DATA:///simple3D.frag?lib=ewol")); + if (this.GLprogram != null) { + this.GLPosition = this.GLprogram.getAttribute("EW_coord3d"); + this.GLColor = this.GLprogram.getUniform("EW_color"); + this.GLMatrix = this.GLprogram.getUniform("EW_MatrixTransformation"); + } + } + + @Override + public void cleanUp() { + // TODO Auto-generated method stub + + } + + public void draw(final List _vertices, final Color _color) { + draw(_vertices, _color, true, true); + } + + public void draw(final List _vertices, final Color _color, final boolean _updateDepthBuffer, final boolean _depthtest) { + if (_vertices.size() <= 0) { + return; + } + if (this.GLprogram == null) { + Log.error("No shader ..."); + return; + } + if (true == _depthtest) { + OpenGL.enable(OpenGL.Flag.flag_depthTest); + if (false == _updateDepthBuffer) { + OpenGL.setDeathMask(false); + } + } + + //Log.debug(" display " + this.coord.size() + " elements" ); + this.GLprogram.use(); + // set Matrix: translation/positionMatrix + final Matrix4f projMatrix = OpenGL.getMatrix(); + final Matrix4f camMatrix = OpenGL.getCameraMatrix(); + final Matrix4f tmpMatrix = projMatrix.multiplyNew(camMatrix); + this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); + // position : + this.GLprogram.sendAttribute(this.GLPosition, 3/*x,y,z,unused*/, ResourceProgram.storeDataInFloatBufferVector3f(_vertices), 3); + // color : + this.GLprogram.uniformColor(this.GLColor, _color); + // Request the draw od the elements: + OpenGL.drawArrays(OpenGL.RenderMode.triangle, 0, _vertices.size()); + this.GLprogram.unUse(); + // Request the draw od the elements: + //glDrawArrays(GL_LINES, 0, vertices.size()); + //this.GLprogram.UnUse(); + if (true == _depthtest) { + if (false == _updateDepthBuffer) { + OpenGL.setDeathMask(true); + ; + } + OpenGL.disable(OpenGL.Flag.flag_depthTest); + } + } + + public void draw(final List _vertices, final Color _color, final Matrix4f _transformationMatrix) { + draw(_vertices, _color, _transformationMatrix, true, true); + } + + public void draw(final List _vertices, final Color _color, final Matrix4f _transformationMatrix, final boolean _updateDepthBuffer, final boolean _depthtest) { + if (_vertices.size() <= 0) { + return; + } + if (this.GLprogram == null) { + Log.error("No shader ..."); + return; + } + if (true == _depthtest) { + OpenGL.enable(OpenGL.Flag.flag_depthTest); + if (false == _updateDepthBuffer) { + OpenGL.setDeathMask(false); + } + } + //Log.debug(" display " + this.coord.size() + " elements" ); + this.GLprogram.use(); + // set Matrix: translation/positionMatrix + final Matrix4f projMatrix = OpenGL.getMatrix(); + final Matrix4f camMatrix = OpenGL.getCameraMatrix(); + final Matrix4f tmpMatrix = projMatrix.multiplyNew(camMatrix).multiply(_transformationMatrix); + this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); + // position : + this.GLprogram.sendAttribute(this.GLPosition, 3/*x,y,z*/, ResourceProgram.storeDataInFloatBufferVector3f(_vertices), 3); // TODO : check 4->3 + // color : + this.GLprogram.uniformColor(this.GLColor, _color); + // Request the draw od the elements: + OpenGL.drawArrays(OpenGL.RenderMode.triangle, 0, _vertices.size()); + this.GLprogram.unUse(); + if (true == _depthtest) { + if (false == _updateDepthBuffer) { + OpenGL.setDeathMask(true); + } + OpenGL.disable(OpenGL.Flag.flag_depthTest); + } + } + + public void drawCapsule(final float _radius, final float _size, int _lats, final int _longs, final Matrix4f _transformationMatrix, final Color _tmpColor) { + final List tmpVertices = new ArrayList<>(); + _lats = _lats / 2 * 2; + + // center to border (TOP) + float offset = _size * 0.5f; + for (int iii = _lats / 2 + 1; iii <= _lats; ++iii) { + final float lat0 = (float) (Math.PI) * (-0.5f + (float) (iii - 1) / _lats); + final float z0 = (float) (_radius * Math.sin(lat0)); + final float zr0 = (float) (_radius * Math.cos(lat0)); + + final float lat1 = (float) (Math.PI) * (-0.5f + (float) (iii) / _lats); + final float z1 = (float) (_radius * Math.sin(lat1)); + final float zr1 = (float) (_radius * Math.cos(lat1)); + + for (int jjj = 0; jjj < _longs; ++jjj) { + float lng = 2.0f * (float) (Math.PI) * (jjj - 1) / _longs; + float x = (float) Math.cos(lng); + float y = (float) Math.sin(lng); + final Vector3f v1 = new Vector3f(x * zr1, y * zr1, z1 + offset); + final Vector3f v4 = new Vector3f(x * zr0, y * zr0, z0 + offset); + + lng = 2 * (float) (Math.PI) * (jjj) / _longs; + x = (float) Math.cos(lng); + y = (float) Math.sin(lng); + final Vector3f v2 = new Vector3f(x * zr1, y * zr1, z1 + offset); + final Vector3f v3 = new Vector3f(x * zr0, y * zr0, z0 + offset); + tmpVertices.add(v1); + tmpVertices.add(v2); + tmpVertices.add(v3); + + tmpVertices.add(v1); + tmpVertices.add(v3); + tmpVertices.add(v4); + } + } + // Cylinder + for (int jjj = 0; jjj < _longs; ++jjj) { + float lng = 2.0f * (float) (Math.PI) * (jjj - 1) / _longs; + + final float z = _size * 0.5f; + + float x = (float) (Math.cos(lng) * _radius); + float y = (float) (Math.sin(lng) * _radius); + final Vector3f v2 = new Vector3f(x, y, z); + final Vector3f v2b = new Vector3f(x, y, -z); + + lng = 2.0f * (float) (Math.PI) * (jjj) / _longs; + x = (float) (Math.cos(lng) * _radius); + y = (float) (Math.sin(lng) * _radius); + final Vector3f v3 = new Vector3f(x, y, z); + final Vector3f v3b = new Vector3f(x, y, -z); + + tmpVertices.add(v2); + tmpVertices.add(v3); + tmpVertices.add(v3b); + + tmpVertices.add(v2); + tmpVertices.add(v3b); + tmpVertices.add(v2b); + } + // center to border (BUTTOM) + offset = -_size * 0.5f; + for (int iii = 0; iii <= _lats / 2; ++iii) { + final float lat0 = (float) (Math.PI) * (-0.5f + (float) (iii - 1) / _lats); + final float z0 = (float) (_radius * Math.sin(lat0)); + final float zr0 = (float) (_radius * Math.cos(lat0)); + + final float lat1 = (float) (Math.PI) * (-0.5f + (float) (iii) / _lats); + final float z1 = (float) (_radius * Math.sin(lat1)); + final float zr1 = (float) (_radius * Math.cos(lat1)); + + for (int jjj = 0; jjj < _longs; ++jjj) { + float lng = 2.0f * (float) (Math.PI) * (jjj - 1) / _longs; + float x = (float) Math.cos(lng); + float y = (float) Math.sin(lng); + final Vector3f v1 = new Vector3f(x * zr1, y * zr1, z1 + offset); + final Vector3f v4 = new Vector3f(x * zr0, y * zr0, z0 + offset); + + lng = 2 * (float) (Math.PI) * (jjj) / _longs; + x = (float) Math.cos(lng); + y = (float) Math.sin(lng); + final Vector3f v2 = new Vector3f(x * zr1, y * zr1, z1 + offset); + final Vector3f v3 = new Vector3f(x * zr0, y * zr0, z0 + offset); + tmpVertices.add(v1); + tmpVertices.add(v2); + tmpVertices.add(v3); + + tmpVertices.add(v1); + tmpVertices.add(v3); + tmpVertices.add(v4); + } + } + draw(tmpVertices, _tmpColor, _transformationMatrix); + } + + public void drawCone(final float _radius, final float _size, final int _lats, final int _longs, final Matrix4f _transformationMatrix, final Color _tmpColor) { + final List tmpVertices = new ArrayList<>(); + // center to border (TOP) + for (int jjj = 0; jjj < _longs; ++jjj) { + float lng = 2.0f * (float) (Math.PI) * (jjj - 1) / _longs; + final Vector3f v1 = new Vector3f(0.0f, 0.0f, -_size / 2); + + float x = (float) (Math.cos(lng) * _radius); + float y = (float) (Math.sin(lng) * _radius); + final Vector3f v2 = new Vector3f(x, y, _size / 2); + + lng = 2.0f * (float) (Math.PI) * (jjj) / _longs; + x = (float) (Math.cos(lng) * _radius); + y = (float) (Math.sin(lng) * _radius); + final Vector3f v3 = new Vector3f(x, y, _size / 2); + tmpVertices.add(v1); + tmpVertices.add(v3); + tmpVertices.add(v2); + } + // center to border (BUTTOM) + for (int jjj = 0; jjj < _longs; ++jjj) { + float lng = 2.0f * (float) (Math.PI) * (jjj - 1) / _longs; + + final Vector3f v1 = new Vector3f(0.0f, 0.0f, _size / 2); + + float x = (float) (Math.cos(lng) * _radius); + float y = (float) (Math.sin(lng) * _radius); + final Vector3f v2 = new Vector3f(x, y, _size / 2); + + lng = 2.0f * (float) (Math.PI) * (jjj) / _longs; + x = (float) (Math.cos(lng) * _radius); + y = (float) (Math.sin(lng) * _radius); + final Vector3f v3 = new Vector3f(x, y, _size / 2); + tmpVertices.add(v1); + tmpVertices.add(v2); + tmpVertices.add(v3); + } + draw(tmpVertices, _tmpColor, _transformationMatrix); + } + + public void drawCubeLine(final Vector3f _min, final Vector3f _max, final Color _color, final Matrix4f _transformationMatrix) { + drawCubeLine(_min, _max, _color, _transformationMatrix, true, true); + } + + public void drawCubeLine(final Vector3f _min, final Vector3f _max, final Color _color, final Matrix4f _transformationMatrix, final boolean _updateDepthBuffer, final boolean _depthtest) { + final List vertices = new ArrayList<>(); + vertices.add(new Vector3f(_min.x, _min.y, _min.z)); + vertices.add(new Vector3f(_max.x, _min.y, _min.z)); + + vertices.add(new Vector3f(_max.x, _min.y, _min.z)); + vertices.add(new Vector3f(_max.x, _min.y, _max.z)); + + vertices.add(new Vector3f(_max.x, _min.y, _max.z)); + vertices.add(new Vector3f(_min.x, _min.y, _max.z)); + + vertices.add(new Vector3f(_min.x, _min.y, _max.z)); + vertices.add(new Vector3f(_min.x, _min.y, _min.z)); + + vertices.add(new Vector3f(_min.x, _max.y, _min.z)); + vertices.add(new Vector3f(_max.x, _max.y, _min.z)); + + vertices.add(new Vector3f(_max.x, _max.y, _min.z)); + vertices.add(new Vector3f(_max.x, _max.y, _max.z)); + + vertices.add(new Vector3f(_max.x, _max.y, _max.z)); + vertices.add(new Vector3f(_min.x, _max.y, _max.z)); + + vertices.add(new Vector3f(_min.x, _max.y, _max.z)); + vertices.add(new Vector3f(_min.x, _max.y, _min.z)); + + vertices.add(new Vector3f(_min.x, _min.y, _min.z)); + vertices.add(new Vector3f(_min.x, _max.y, _min.z)); + + vertices.add(new Vector3f(_max.x, _min.y, _min.z)); + vertices.add(new Vector3f(_max.x, _max.y, _min.z)); + + vertices.add(new Vector3f(_max.x, _min.y, _max.z)); + vertices.add(new Vector3f(_max.x, _max.y, _max.z)); + + vertices.add(new Vector3f(_min.x, _min.y, _max.z)); + vertices.add(new Vector3f(_min.x, _max.y, _max.z)); + + drawLine(vertices, _color, _transformationMatrix, _updateDepthBuffer, _depthtest); + } + + public void drawCylinder(final float _radius, final float _size, final int _lats, final int _longs, final Matrix4f _transformationMatrix, final Color _tmpColor) { + final List tmpVertices = new ArrayList<>(); + // center to border (TOP) + + // center to border (TOP) + for (int jjj = 0; jjj < _longs; ++jjj) { + float lng = 2.0f * (float) (Math.PI) * (jjj - 1) / _longs; + + final float z = _size * 0.5f; + final Vector3f v1 = new Vector3f(0.0f, 0.0f, z); + + float x = (float) (Math.cos(lng) * _radius); + float y = (float) (Math.sin(lng) * _radius); + final Vector3f v2 = new Vector3f(x, y, z); + + lng = 2.0f * (float) (Math.PI) * (jjj) / _longs; + x = (float) (Math.cos(lng) * _radius); + y = (float) (Math.sin(lng) * _radius); + final Vector3f v3 = new Vector3f(x, y, z); + tmpVertices.add(v1); + tmpVertices.add(v3); + tmpVertices.add(v2); + } + // Cylinder + for (int jjj = 0; jjj < _longs; ++jjj) { + float lng = 2.0f * (float) (Math.PI) * (jjj - 1) / _longs; + + final float z = _size * 0.5f; + + float x = (float) (Math.cos(lng) * _radius); + float y = (float) (Math.sin(lng) * _radius); + final Vector3f v2 = new Vector3f(x, y, z); + final Vector3f v2b = new Vector3f(x, y, -z); + + lng = 2.0f * (float) (Math.PI) * (jjj) / _longs; + x = (float) (Math.cos(lng) * _radius); + y = (float) (Math.sin(lng) * _radius); + final Vector3f v3 = new Vector3f(x, y, z); + final Vector3f v3b = new Vector3f(x, y, -z); + + tmpVertices.add(v2); + tmpVertices.add(v3); + tmpVertices.add(v3b); + + tmpVertices.add(v2); + tmpVertices.add(v3b); + tmpVertices.add(v2b); + } + // center to border (BUTTOM) + for (int jjj = 0; jjj < _longs; ++jjj) { + float lng = 2.0f * (float) (Math.PI) * (jjj - 1) / _longs; + + final float z = _size * -0.5f; + final Vector3f v1 = new Vector3f(0.0f, 0.0f, z); + + float x = (float) (Math.cos(lng) * _radius); + float y = (float) (Math.sin(lng) * _radius); + final Vector3f v2 = new Vector3f(x, y, z); + + lng = 2.0f * (float) (Math.PI) * (jjj) / _longs; + x = (float) (Math.cos(lng) * _radius); + y = (float) (Math.sin(lng) * _radius); + final Vector3f v3 = new Vector3f(x, y, z); + tmpVertices.add(v1); + tmpVertices.add(v2); + tmpVertices.add(v3); + } + draw(tmpVertices, _tmpColor, _transformationMatrix); + } + + public void drawLine(final List _vertices, final Color _color, final Matrix4f _transformationMatrix) { + drawLine(_vertices, _color, _transformationMatrix, true, true); + } + + public void drawLine(final List _vertices, final Color _color, final Matrix4f _transformationMatrix, final boolean _updateDepthBuffer, final boolean _depthtest) { + if (_vertices.size() <= 0) { + return; + } + if (this.GLprogram == null) { + Log.error("No shader ..."); + return; + } + if (true == _depthtest) { + OpenGL.enable(OpenGL.Flag.flag_depthTest); + if (false == _updateDepthBuffer) { + OpenGL.setDeathMask(false); + } + } + //Log.debug(" display " + this.coord.size() + " elements" ); + this.GLprogram.use(); + // set Matrix: translation/positionMatrix + final Matrix4f projMatrix = OpenGL.getMatrix(); + final Matrix4f camMatrix = OpenGL.getCameraMatrix(); + final Matrix4f tmpMatrix = projMatrix.multiplyNew(camMatrix).multiply(_transformationMatrix); + this.GLprogram.uniformMatrix(this.GLMatrix, tmpMatrix); + // position : + this.GLprogram.sendAttribute(this.GLPosition, 3/*x,y,z*/, ResourceProgram.storeDataInFloatBufferVector3f(_vertices), 3);// TODO : check 4->3 + // color : + this.GLprogram.uniformColor(this.GLColor, _color); + // Request the draw od the elements: + OpenGL.drawArrays(OpenGL.RenderMode.line, 0, _vertices.size()); + this.GLprogram.unUse(); + if (true == _depthtest) { + if (false == _updateDepthBuffer) { + OpenGL.setDeathMask(true); + } + OpenGL.disable(OpenGL.Flag.flag_depthTest); + } + } + + public void drawSphere(final float _radius, final int _lats, final int _longs, final Matrix4f _transformationMatrix, final Color _tmpColor) { + final List tmpVertices = new ArrayList<>(); + for (int iii = 0; iii <= _lats; ++iii) { + final float lat0 = (float) (Math.PI) * (-0.5f + (float) (iii - 1) / _lats); + final float z0 = (float) (_radius * Math.sin(lat0)); + final float zr0 = (float) (_radius * Math.cos(lat0)); + + final float lat1 = (float) (Math.PI) * (-0.5f + (float) (iii) / _lats); + final float z1 = (float) (_radius * Math.sin(lat1)); + final float zr1 = (float) (_radius * Math.cos(lat1)); + + for (int jjj = 0; jjj < _longs; ++jjj) { + float lng = 2.0f * (float) (Math.PI) * (jjj - 1) / _longs; + float x = (float) Math.cos(lng); + float y = (float) Math.sin(lng); + final Vector3f v1 = new Vector3f(x * zr1, y * zr1, z1); + final Vector3f v4 = new Vector3f(x * zr0, y * zr0, z0); + + lng = 2 * (float) (Math.PI) * (jjj) / _longs; + x = (float) Math.cos(lng); + y = (float) Math.sin(lng); + final Vector3f v2 = new Vector3f(x * zr1, y * zr1, z1); + final Vector3f v3 = new Vector3f(x * zr0, y * zr0, z0); + + tmpVertices.add(v1); + tmpVertices.add(v2); + tmpVertices.add(v3); + + tmpVertices.add(v1); + tmpVertices.add(v3); + tmpVertices.add(v4); + } + } + draw(tmpVertices, _tmpColor, _transformationMatrix); + } + + public void drawSquare(final Vector3f _size, final Matrix4f _transformationMatrix, final Color _tmpColor) { + final List tmpVertices = new ArrayList<>(); + final int[] indices = { 0, 1, 2, 3, 2, 1, 4, 0, 6, 6, 0, 2, 5, 1, 4, 4, 1, 0, 7, 3, 1, 7, 1, 5, 5, 4, 7, 7, 4, 6, 7, 2, 3, 7, 6, 2 }; + final Vector3f[] vertices = { new Vector3f(_size.x, _size.y, _size.z), new Vector3f(-_size.x, _size.y, _size.z), new Vector3f(_size.x, -_size.y, _size.z), + new Vector3f(-_size.x, -_size.y, _size.z), new Vector3f(_size.x, _size.y, -_size.z), new Vector3f(-_size.x, _size.y, -_size.z), new Vector3f(_size.x, -_size.y, -_size.z), + new Vector3f(-_size.x, -_size.y, -_size.z) }; + tmpVertices.clear(); + for (int iii = 0; iii < 36; iii += 3) { + // normal calculation : + //btVector3 normal = (vertices[indices[iii+2]]-vertices[indices[iii]]).cross(vertices[indices[iii+1]]-vertices[indices[iii]]); + //normal.normalize (); + tmpVertices.add(vertices[indices[iii]]); + tmpVertices.add(vertices[indices[iii + 1]]); + tmpVertices.add(vertices[indices[iii + 2]]); + } + draw(tmpVertices, _tmpColor, _transformationMatrix); + } + + public void drawTriangles(final List _vertex, final List _indice, final Matrix4f _transformationMatrix, final Color _tmpColor) { + drawTriangles(_vertex, _indice, _transformationMatrix, _tmpColor, new Vector3f(0.0f, 0.0f, 0.1f)); + } + + public void drawTriangles(final List _vertex, final List _indice, final Matrix4f _transformationMatrix, final Color _tmpColor, final Vector3f _offset) { + final List tmpVertices = new ArrayList<>(); + for (int iii = 0; iii < _indice.size() / 3; ++iii) { + tmpVertices.add(_vertex.get(_indice.get(iii * 3 + 0)).addNew(_offset)); + tmpVertices.add(_vertex.get(_indice.get(iii * 3 + 1)).addNew(_offset)); + tmpVertices.add(_vertex.get(_indice.get(iii * 3 + 2)).addNew(_offset)); + //Log.info(" indices " + _indice[iii*3 + 0] + " " + _indice[iii*3 + 1] + " " + _indice[iii*3 + 2]); + //Log.info(" triangle " + _vertex[_indice[iii*3 + 0]] + " " + _vertex[_indice[iii*3 + 1]] + " " + _vertex[_indice[iii*3 + 2]]); + } + //Log.info("display " + tmpVertices.size() + " vertices form " + _indice.size()); + draw(tmpVertices, _tmpColor, _transformationMatrix); + } +} diff --git a/src/org/atriasoft/ewol/resource/ResourceColorFile.java b/src/org/atriasoft/ewol/resource/ResourceColorFile.java new file mode 100644 index 0000000..2553cee --- /dev/null +++ b/src/org/atriasoft/ewol/resource/ResourceColorFile.java @@ -0,0 +1,162 @@ +package org.atriasoft.ewol.resource; + +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +import java.util.ArrayList; +import java.util.List; + +import org.atriasoft.ejson.Ejson; +import org.atriasoft.ejson.model.JsonArray; +import org.atriasoft.ejson.model.JsonNode; +import org.atriasoft.ejson.model.JsonObject; +import org.atriasoft.etk.Color; +import org.atriasoft.etk.Uri; +import org.atriasoft.ewol.internal.Log; +import org.atriasoft.gale.resource.Resource; + +/** + * @brief ColorFile is a Resource designed to be specific with the theme (for example black, or white or orange ...) + */ +public class ResourceColorFile extends Resource { + private final List list = new ArrayList<>(); //!< List of all color in the file + private Color errorColor = Color.ORANGE; + + /** + * @brief Constructor of the color property file + * @param[in] _uri Name of the file needed + */ + public ResourceColorFile(final Uri _uri) { + super(_uri.get()); + Log.debug("CF : load \"" + _uri + "\""); + reload(); + //Log.debug("List of all color : " + this.list.keySet()); + } + + @Override + public void cleanUp() { + + } + + /** + * @brief Get the associated color of the ID. + * @param[in] _Id Id of the color. + * @return The requested color. + */ + Color get(final int _id) { + if (_id < 0) { + return this.errorColor; + } + return this.list.get(_id).color; + } + + /** + * @brief Get All color name + * @return list of all color existing + */ + List getColors() { + final List out = new ArrayList<>(this.list.size()); + for (int iii = 0; iii < this.list.size(); iii++) { + out.add(this.list.get(iii).name); + } + return out; + }; + + public synchronized void put(final String name, final Color color) { + for (int iii = 0; iii < this.list.size(); iii++) { + final ListElement elem = this.list.get(iii); + if (elem.name.contentEquals(name)) { + elem.color = color; + return; + } + } + this.list.add(new ListElement(name, color)); + } + + @Override + public synchronized void reload() { + // remove all previous set of value : + for (int iii = 0; iii < this.list.size(); ++iii) { + this.list.get(iii).color = this.errorColor; + } + Log.todo("Mut be implemented ..."); + // open and read all json elements: + try { + final JsonObject out = Ejson.parse(new Uri(this.name)).toJsonObject(); + + final JsonArray baseArray = out.get("color").toJsonArray(); + if (baseArray == null) { + Log.error("Can not get basic array : 'color' in file:" + this.name); + Ejson.display(out); + return; + } + boolean findError = false; + for (final JsonNode it : baseArray.getNodes()) { + final JsonObject tmpObj = it.toJsonObject(); + if (tmpObj == null) { + Log.error(" can not get object in 'color' : " + it); + findError = true; + continue; + } + final String name = tmpObj.get("name").toJsonString().getValue(); + final String color = tmpObj.get("color").toJsonString().getValue(); + Log.debug("find new color : '" + name + "' color='" + color + "'"); + if (name.length() == 0) { + Log.error("Drop an empty name"); + findError = true; + continue; + } + if (color.length() == 0) { + put(name, this.errorColor.clone()); + } else {} + put(name, Color.valueOf(color)); + } + if (findError == true) { + Log.error("pb in parsing file:" + this.name); + Ejson.display(out); + } + } catch (final Exception e) { + Log.error("chach exception in parsing config file... " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * @brief Request the presence of a specific color. + * @param[in] _paramName Name of the color. + * @return A unique ID of the color (or -1 if an error occured). + */ + public synchronized int request(final String _paramName) { + for (int iii = 0; iii < this.list.size(); iii++) { + final ListElement elem = this.list.get(iii); + if (elem.name.contentEquals(_paramName)) { + return iii; + } + } + this.list.add(new ListElement(_paramName, this.errorColor.clone())); + return this.list.size() - 1; + } + + /** + * @brief Set the error color. + * @param[in] _errorColor Color that might be set when not finding a color + */ + public void setErrorColor(final Color _errorColor) { + this.errorColor = _errorColor; + } + +} + +class ListElement { + public String name; + public Color color; + + public ListElement(final String name, final Color color) { + super(); + this.name = name; + this.color = color; + } + +}; diff --git a/src/org/atriasoft/ewol/resource/ResourceConfigFile.java b/src/org/atriasoft/ewol/resource/ResourceConfigFile.java new file mode 100644 index 0000000..8d3605d --- /dev/null +++ b/src/org/atriasoft/ewol/resource/ResourceConfigFile.java @@ -0,0 +1,132 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package org.atriasoft.ewol.resource; + +import java.util.ArrayList; +import java.util.List; + +import org.atriasoft.ejson.Ejson; +import org.atriasoft.ejson.model.JsonNode; +import org.atriasoft.ejson.model.JsonObject; +import org.atriasoft.etk.Uri; +import org.atriasoft.ewol.internal.Log; +import org.atriasoft.gale.resource.Resource; + +public class ResourceConfigFile extends Resource { + /** + * @brief keep the resource pointer. + * @note Never free this pointer by your own... + * @param[in] _filename Name of the configuration file. + * @return pointer on the resource or null if an error occured. + */ + public static ResourceConfigFile keep(final String name) { + Resource resource2 = null; + if (name.isEmpty() == false && name != "---") { + resource2 = getManager().localKeep(name); + } + if (resource2 != null) { + if (resource2 instanceof ResourceConfigFile) { + resource2.keep(); + return (ResourceConfigFile) resource2; + } + Log.critical("Request resource file : '" + name + "' With the wrong type (dynamic cast error)"); + return null; + } + final ResourceConfigFile resource = new ResourceConfigFile(new Uri(name)); + getManager().localAdd(resource); + return resource; + + } + + // List of all color in the file + private final List list = new ArrayList<>(); + + protected ResourceConfigFile(final Uri _uri) { + super(_uri.get()); + Log.debug("SFP : load '" + _uri + "'"); + reload(); + + } + + @Override + public void cleanUp() { + // TODO Auto-generated method stub + + } + + boolean getBoolean(final int _id) { + if (_id < 0 || this.list.get(_id).node == null || this.list.get(_id).node.isJsonBoolean() == false) { + return false; + } + return this.list.get(_id).node.toJsonBoolean().getValue(); + } + + public synchronized double getNumber(final int _id) { + if (_id < 0 || this.list.get(_id).node == null || this.list.get(_id).node.isJsonNumber() == false) { + return 0.0; + } + return this.list.get(_id).node.toJsonNumber().getValue(); + } + + String getString(final int _id) { + if (_id < 0 || this.list.get(_id).node == null || this.list.get(_id).node.isJsonString() == false) { + return ""; + } + return this.list.get(_id).node.toJsonString().getValue(); + } + + public synchronized void put(final String name, final JsonNode node) { + for (int iii = 0; iii < this.list.size(); iii++) { + final ListElementConfig elem = this.list.get(iii); + if (elem.name.contentEquals(name)) { + elem.node = node; + return; + } + } + this.list.add(new ListElementConfig(name, node)); + } + + @Override + public synchronized void reload() { + // reset all parameters + for (int iii = 0; iii < this.list.size(); ++iii) { + this.list.get(iii).node = null; + } + JsonObject out; + try { + out = Ejson.parse(new Uri(this.name)).toJsonObject(); + } catch (final Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return; + } + out.getNodes().forEach((key, value) -> { + put(key, value); + }); + } + + public synchronized int request(final String _paramName) { + for (int iii = 0; iii < this.list.size(); iii++) { + final ListElementConfig elem = this.list.get(iii); + if (elem.name.contentEquals(_paramName)) { + return iii; + } + } + this.list.add(new ListElementConfig(_paramName, null)); + return this.list.size() - 1; + } +} + +class ListElementConfig { + public final String name; + public JsonNode node; + + public ListElementConfig(final String name, final JsonNode node) { + super(); + this.name = name; + this.node = node; + } +} \ No newline at end of file diff --git a/src/org/atriasoft/ewol/resource/ResourceFontFreeType.java b/src/org/atriasoft/ewol/resource/ResourceFontFreeType.java new file mode 100644 index 0000000..4484bd0 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/ResourceFontFreeType.java @@ -0,0 +1,274 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package org.atriasoft.ewol.resource; + +import java.util.List; + +import org.atriasoft.egami.Image; +import org.atriasoft.egami.ImageMono; +import org.atriasoft.etk.Uri; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector2i; +import org.atriasoft.ewol.internal.LoadPackageStream; +import org.atriasoft.ewol.internal.Log; +import org.atriasoft.ewol.resource.font.FontBase; +import org.atriasoft.ewol.resource.font.GlyphProperty; +import org.atriasoft.gale.resource.Resource; + +import com.mlomb.freetypejni.Bitmap; +import com.mlomb.freetypejni.Face; +import com.mlomb.freetypejni.FreeType; +import com.mlomb.freetypejni.FreeTypeConstants; +import com.mlomb.freetypejni.FreeTypeConstants.FT_Kerning_Mode; +import com.mlomb.freetypejni.FreeTypeConstants.FT_Render_Mode; +import com.mlomb.freetypejni.GlyphSlot; +import com.mlomb.freetypejni.Kerning; +import com.mlomb.freetypejni.Library; + +// show : http://www.freetype.org/freetype2/docs/tutorial/step2.html +public class ResourceFontFreeType extends FontBase { + private static final Library library; + static { + library = FreeType.newLibrary(); + } + + public static ResourceFontFreeType create(final Uri uri) { + Log.verbose("KEEP: FontFreeType: " + uri); + ResourceFontFreeType object = null; + final Resource object2 = getManager().localKeep(uri); + if (object2 != null) { + object = (ResourceFontFreeType) object2; + if (object == null) { + Log.critical("Request resource file : '" + uri + "' With the wrong type (dynamic cast error)"); + return null; + } + } + if (object != null) { + return object; + } + Log.debug("CREATE: FontFreeType: " + uri); + // need to crate a new one ... + return new ResourceFontFreeType(uri); + } + + private final byte[] FileBuffer; + private final Face fftFace; + + private boolean init; + + private ResourceFontFreeType(final Uri _uri) { + super(_uri); + this.FileBuffer = LoadPackageStream.getAllData(_uri.getPath()); + // load Face ... + this.fftFace = library.newFace(this.FileBuffer, 0); + if (this.fftFace == null) { + Log.error("... the font file could be opened and read, but it appears ... that its font format is unsupported"); + } else { + // all OK + Log.debug("load font : \"" + _uri + "\" glyph count = " + this.fftFace.getNumGlyphs()); + this.init = true; + // display(); + } + } + + @Override + public synchronized void display() { + if (this.init == false) { + return; + } + Log.info(" number of glyph = " + this.fftFace.getNumGlyphs()); + } + + @Override + public synchronized boolean drawGlyph(final Image _imageOut, final int _fontSize, final Vector2i _glyphPosition, final GlyphProperty _property, final int _posInImage) { + if (this.init == false) { + return false; + } + // 300dpi (hight quality) 96 dpi (normal quality) + final int fontQuality = 96; + // Select size ... + // note tha +6 == *64 corespond with the 1/64th of points calculation of freetype + boolean error = this.fftFace.setCharSize(_fontSize + 6, _fontSize + 6, fontQuality, fontQuality); + if (error == false) { + Log.error("FT_Set_Char_Size == > error in settings ..."); + return false; + } + // a small shortcut + final GlyphSlot slot = this.fftFace.getGlyphSlot(); + // load glyph image into the slot (erase previous one) + error = this.fftFace.loadGlyph(_property.glyphIndex, FreeTypeConstants.FT_LOAD_DEFAULT); + if (error == false) { + Log.error("FT_Load_Glyph specify Glyph"); + return false; + } + // convert to an anti-aliased bitmap + error = slot.renderGlyph(FT_Render_Mode.FT_RENDER_MODE_NORMAL); + if (error == false) { + Log.error("FT_Render_Glyph"); + return false; + } + // draw it on the output Image : + final Bitmap bitmap = slot.getBitmap(); + for (int jjj = 0; jjj < bitmap.getRows(); jjj++) { + for (int iii = 0; iii < bitmap.getWidth(); iii++) { + final int valueColor = bitmap.getBuffer().get(iii + bitmap.getWidth() * jjj); + // set only alpha : + switch (_posInImage) { + default: + case 0: + _imageOut.setA(_glyphPosition.x + iii, _glyphPosition.y + jjj, valueColor); + break; + case 1: + _imageOut.setR(_glyphPosition.x + iii, _glyphPosition.y + jjj, valueColor); + break; + case 2: + _imageOut.setG(_glyphPosition.x + iii, _glyphPosition.y + jjj, valueColor); + break; + case 3: + _imageOut.setB(_glyphPosition.x + iii, _glyphPosition.y + jjj, valueColor); + break; + } + // real set of color + + } + } + return true; + } + + @Override + public synchronized boolean drawGlyph(final ImageMono _imageOut, final int _fontSize, final GlyphProperty _property, final int _borderSize) { + if (false == this.init) { + return false; + } + // 300dpi (hight quality) 96 dpi (normal quality) + final int fontQuality = 96; + // Select size ... + // note tha +6 == *64 corespond with the 1/64th of points calculation of freetype + boolean error = this.fftFace.setCharSize(_fontSize + 6, _fontSize + 6, fontQuality, fontQuality); + if (error == false) { + Log.error("FT_Set_Char_Size == > error in settings ..."); + return false; + } + // a small shortcut + final GlyphSlot slot = this.fftFace.getGlyphSlot(); + // load glyph image into the slot (erase previous one) + error = this.fftFace.loadGlyph(_property.glyphIndex, // glyph index + FreeTypeConstants.FT_LOAD_DEFAULT); + if (error == false) { + Log.error("FT_Load_Glyph specify Glyph"); + return false; + } + // convert to an anti-aliased bitmap + error = slot.renderGlyph(FT_Render_Mode.FT_RENDER_MODE_NORMAL); // TODO : set FT_RENDER_MODE_MONO ==> 1 bit value ==> faster generation ... + if (error == false) { + Log.error("FT_Render_Glyph"); + return false; + } + // resize output image : + final Bitmap bitmap = slot.getBitmap(); + _imageOut.resize(bitmap.getWidth() + 2 * _borderSize, bitmap.getRows() + 2 * _borderSize); + + for (int jjj = 0; jjj < bitmap.getRows(); jjj++) { + for (int iii = 0; iii < bitmap.getWidth(); iii++) { + final int valueColor = bitmap.getBuffer().get(iii + bitmap.getWidth() * jjj); + // real set of color + _imageOut.set(_borderSize + iii, _borderSize + jjj, valueColor); + } + } + return true; + } + + @Override + public synchronized void generateKerning(final int fontSize, final List listGlyph) { + if (this.init == false) { + return; + } + if (this.fftFace.hasKerning() == false) { + Log.info("No kerning generation (disable) in the font"); + } + // 300dpi (hight quality) 96 dpi (normal quality) + final int fontQuality = 96; + // Select size ... + // note tha +6 == *64 corespond with the 1/64th of points calculation of freetype + final boolean error = this.fftFace.setCharSize(fontSize + 6, fontSize + 6, fontQuality, fontQuality); + if (error == false) { + Log.error("FT_Set_Char_Size == > error in settings ..."); + return; + } + // For all the kerning element we get the kerning value : + for (int iii = 0; iii < listGlyph.size(); iii++) { + listGlyph.get(iii).kerningClear(); + for (int kkk = 0; kkk < listGlyph.size(); kkk++) { + final Kerning kerning = this.fftFace.getKerning(listGlyph.get(kkk).glyphIndex, listGlyph.get(iii).glyphIndex, FT_Kerning_Mode.FT_KERNING_UNFITTED); + // add the kerning only if != 0 ... + if (kerning.x != 0) { + listGlyph.get(iii).kerningAdd(listGlyph.get(kkk).UVal, kerning.x / 32.0f); + //Log.debug("Kerning between : '" + (char)listGlyph[iii].this.UVal + "''" + (char)listGlyph[kkk].this.UVal + "' value : " + kerning.x + " => " + (kerning.x/64.0f)); + } + } + } + } + + @Override + public synchronized boolean getGlyphProperty(final int _fontSize, final GlyphProperty _property) { + if (false == this.init) { + return false; + } + // 300dpi (hight quality) 96 dpi (normal quality) + final int fontQuality = 96; + // Select size ... + // note tha +6 == *64 corespond with the 1/64th of points calculation of freetype + boolean error = this.fftFace.setCharSize(_fontSize + 6, _fontSize + 6, fontQuality, fontQuality); + if (error == false) { + Log.error("FT_Set_Char_Size == > error in settings ..."); + return false; + } + // a small shortcut + final GlyphSlot slot = this.fftFace.getGlyphSlot(); + // retrieve glyph index from character code + final int glyph_index = this.fftFace.getCharIndex(_property.UVal); + // load glyph image into the slot (erase previous one) + error = this.fftFace.loadGlyph(glyph_index, // glyph index + FreeTypeConstants.FT_LOAD_DEFAULT); + if (error == false) { + Log.error("FT_Load_Glyph specify Glyph"); + return false; + } + // convert to an anti-aliased bitmap + error = slot.renderGlyph(FT_Render_Mode.FT_RENDER_MODE_NORMAL); + if (error == false) { + Log.error("FT_Render_Glyph"); + return false; + } + // set properties : + _property.glyphIndex = glyph_index; + final Bitmap bitmap = slot.getBitmap(); + _property.sizeTexture.setValue(bitmap.getWidth(), bitmap.getRows()); + _property.bearing.setValue(slot.getMetrics().getHoriBearingX() >> 6, slot.getMetrics().getHoriBearingY() >> 6); + _property.advance.setValue(slot.getMetrics().getHoriAdvance() >> 6, slot.getMetrics().getVertAdvance() >> 6); + return true; + } + + @Override + public synchronized int getHeight(final int _fontSize) { + return (int) (_fontSize * 1.43f); // this is a really "magic" number ... + } + + @Override + public synchronized Vector2f getSize(final int _fontSize, final String _unicodeString) { + if (this.init == false) { + return new Vector2f(0, 0); + } + // TODO ... + return new Vector2f(0, 0); + } + + @Override + public synchronized float getSizeWithHeight(final float _fontHeight) { + return _fontHeight * 0.6993f; // this is a really "magic" number ... + } + +} diff --git a/src/org/atriasoft/ewol/resource/ResourceTexture2.java b/src/org/atriasoft/ewol/resource/ResourceTexture2.java new file mode 100644 index 0000000..12acb2f --- /dev/null +++ b/src/org/atriasoft/ewol/resource/ResourceTexture2.java @@ -0,0 +1,344 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package org.atriasoft.ewol.resource; + +import org.atriasoft.echrono.Steady; +import org.atriasoft.egami.Image; +import org.atriasoft.etk.Uri; +import org.atriasoft.etk.math.Vector2i; +import org.atriasoft.ewol.internal.Log; +import org.atriasoft.ewol.internal.Tools; +import org.atriasoft.gale.backend3d.OpenGL; +import org.atriasoft.gale.resource.Resource; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; + +public class ResourceTexture2 extends Resource { + public enum TextureColorMode { + rgb, //!< red/green/blue data + rgba //!< red/green/blue/alpha data + } + + private static int[] textureIdBinding = { GL13.GL_TEXTURE0, GL13.GL_TEXTURE1, GL13.GL_TEXTURE2, GL13.GL_TEXTURE3, GL13.GL_TEXTURE4, GL13.GL_TEXTURE5, GL13.GL_TEXTURE6, GL13.GL_TEXTURE7, + GL13.GL_TEXTURE8, GL13.GL_TEXTURE9, GL13.GL_TEXTURE10, GL13.GL_TEXTURE11, GL13.GL_TEXTURE12, GL13.GL_TEXTURE13, GL13.GL_TEXTURE14, GL13.GL_TEXTURE15, GL13.GL_TEXTURE16, GL13.GL_TEXTURE17, + GL13.GL_TEXTURE18, GL13.GL_TEXTURE19, GL13.GL_TEXTURE20, GL13.GL_TEXTURE21, GL13.GL_TEXTURE22, GL13.GL_TEXTURE23, GL13.GL_TEXTURE24, GL13.GL_TEXTURE25, GL13.GL_TEXTURE26, + GL13.GL_TEXTURE27, GL13.GL_TEXTURE28, GL13.GL_TEXTURE29, GL13.GL_TEXTURE30, GL13.GL_TEXTURE31 };; + + /* + public static ResourceTexture2 createFromPng(final Uri uriTexture) { + return createFromPng(uriTexture, 1); + } + + public static ResourceTexture2 createFromPng(final Uri uriTexture, final int textureUnit) { + ResourceTexture2 resource; + Resource resource2; + final String name = uriTexture.getValue(); + if (name.isEmpty() == false && name != "---") { + resource2 = getManager().localKeep(name); + } else { + Log.error("Can not create a shader without a filaname"); + return null; + } + if (resource2 != null) { + if (resource2 instanceof ResourceTexture2) { + resource2.keep(); + return (ResourceTexture2) resource2; + } + Log.critical("Request resource file : '" + name + "' With the wrong type (dynamic cast error)"); + return null; + } + resource = new ResourceTexture2(uriTexture, textureUnit); + final ImageRawData decodedData = ImageLoader.decodePngFile(uriTexture); + resource.setTexture(decodedData.getBuffer(), new Vector2i(decodedData.getWidth(), decodedData.getHeight()), (decodedData.isHasAlpha() == true ? TextureColorMode.rgba : TextureColorMode.rgb), + textureUnit); + resource.flush(); + return resource; + } + */ + + /** + * @brief get the next power 2 if the input + * @param value Value that we want the next power of 2 + * @return result value + */ + private static int nextP2(final int value) { + int val = 1; + for (int iii = 1; iii < 31; iii++) { + if (value <= val) { + return val; + } + val *= 2; + } + Log.critical("impossible CASE...."); + return val; + } + + protected int texId = -1; //!< openGl textureID. + // openGl Context properties : + protected Image data = new Image(32, 32); + //! Last loaded size in the system openGL + protected Vector2i lastSize = new Vector2i(1, 1); + //! some image are not square == > we need to sqared it to prevent some openGl api error the the displayable size is not all the time 0.0 . 1.0 + protected Vector2i realImageSize = new Vector2i(1, 1); + // internal state of the openGl system. + protected boolean loaded = false; + protected int lastTypeObject = 0; + protected int lastSizeObject = 0; + // repeat mode of the image (repeat the image if out of range [0..1]) + protected boolean repeat = false; + + // Filter apply at the image when rendering it + protected TextureFilter filter = TextureFilter.linear; + + //!< Color space of the image. + private final TextureColorMode dataColorSpace = TextureColorMode.rgba; + + public ResourceTexture2() { + super(); + } + + public ResourceTexture2(final String filename) { + super(filename); + } + + /* + public void bindForRendering(final int idTexture) { + if (this.loaded == false) { + return; + } + GL13.glActiveTexture(textureIdBinding[idTexture]); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.texId); + if (this.dataColorSpace == TextureColorMode.rgb) { + OpenGL.enable(OpenGL.Flag.flag_cullFace); + OpenGL.enable(OpenGL.Flag.flag_back); + } + } + */ + + public ResourceTexture2(final Uri filename) { + super(filename); + } + + public void bindForRendering(final int idTexture) { + if (this.loaded == false) { + return; + } + GL13.glActiveTexture(textureIdBinding[idTexture]); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.texId); + if (this.dataColorSpace == TextureColorMode.rgb) { + OpenGL.enable(OpenGL.Flag.flag_cullFace); + OpenGL.enable(OpenGL.Flag.flag_back); + } + } + + @Override + public void cleanUp() { + removeContext(); + } + + // Flush the data to send it at the openGl system + public synchronized void flush() { + // request to the manager to be call at the next update ... + Log.verbose("Request UPDATE of Element"); + getManager().update(this); + }; + + // Get the reference on this image to draw something on it ... + public Image get() { + return this.data; + } + + public Vector2i getOpenGlSize() { + return this.data.getSize(); + } + + public int getRendererId() { + return this.texId; + } + + public Vector2i getUsableSize() { + return this.realImageSize; + } + + @Override + public synchronized void removeContext() { + if (this.loaded == true) { + // Request remove texture ... + Log.info("TEXTURE: Rm [" + getId() + "] texId=" + this.texId); + // TODO Check if we are in the correct thread + OpenGL.glDeleteTextures(this.texId); + this.loaded = false; + } + } + + @Override + public synchronized void removeContextToLate() { + this.loaded = false; + this.texId = -1; + }; + + /** + * @brief Set the image in the texture system + * @note It will resize in square2 if needed by the system. + * @param[in] _image Image to set. + */ + public synchronized void set(final Image _image) { + Log.debug("Set a new image in a texture:"); + Log.debug(" size=" + _image.getSize()); + this.data = _image; + this.realImageSize = this.data.getSize().clone(); + final Vector2i compatibilityHWSize = new Vector2i(Tools.nextP2(this.realImageSize.x), Tools.nextP2(this.realImageSize.y)); + if (this.realImageSize != compatibilityHWSize) { + Log.verbose("RESIZE Image for HArwareCompatibility:" + this.realImageSize + " => " + compatibilityHWSize); + this.data.resize(compatibilityHWSize.x, compatibilityHWSize.y); + } + flush(); + }; + + /** + * @brief Set the Filter mode to apply at the image when display with a scale (not 1:1 ratio) + * @param[in] _value Value of the new filter mode + */ + public void setFilterMode(final TextureFilter _filter) { + this.filter = _filter; + } + + // You must set the size here, because it will be set in multiple of pow(2) + public synchronized void setImageSize(final Vector2i _newSize) { + _newSize.setValue(Tools.nextP2(_newSize.x), Tools.nextP2(_newSize.y)); + this.data.resize(_newSize.x, _newSize.y); + }; + + /** + * @brief Set the repeate mode of the images if UV range is out of [0..1] + * @param[in] _value Value of the new repeate mode + */ + public void setRepeat(final boolean _value) { + this.repeat = _value; + } + + public void unBindForRendering() { + if (this.loaded == false) { + return; + } + if (this.dataColorSpace == TextureColorMode.rgb) { + OpenGL.disable(OpenGL.Flag.flag_cullFace); + OpenGL.disable(OpenGL.Flag.flag_back); + } + } + + @Override + public synchronized boolean updateContext() { + Log.verbose("updateContext [START]"); + final Steady tic = Steady.now(); + /* TODO : use unlockable synchronized ... + if (lock.tryLock() == false) { + //Lock error ==> try later ... + return false; + } + */ + final int typeObject = OpenGL.GL_RGBA; + final int sizeObject = OpenGL.GL_UNSIGNED_BYTE; + if (this.loaded == true) { + if (this.lastTypeObject != typeObject || this.lastSizeObject != sizeObject || this.lastSize.equals(this.data.getSize()) == false) { + Log.warning("TEXTURE: Rm [" + getId() + "] texId=" + this.texId); + OpenGL.glDeleteTextures(this.texId); + this.loaded = false; + } + } + if (this.loaded == false) { + // Request a new texture at openGl : + this.texId = OpenGL.glGenTextures(); + this.lastSize = this.data.getSize(); + this.lastTypeObject = typeObject; + this.lastSizeObject = sizeObject; + Log.debug("TEXTURE: add [" + getId() + "]=" + this.data.getSize() + "=>" + this.data.getGPUSize() + " OGl_Id=" + this.texId + " type=" + this.data.getClass().getCanonicalName()); + } else { + Log.debug("TEXTURE: update [" + getId() + "]=" + this.data.getSize() + "=>" + this.data.getGPUSize() + " OGl_Id=" + this.texId + " type=" + this.data.getClass().getCanonicalName()); + } + // in all case we set the texture properties : + // TODO : check error ??? + OpenGL.bindTexture2D(this.texId); + + if (this.loaded == false) { + if (this.repeat == false) { + OpenGL.setTexture2DWrapClampToEdge(); + } else { + OpenGL.setTexture2DWrapRepeat(); + } + if (this.filter == TextureFilter.linear) { + OpenGL.setTexture2DFilterLinear(); + } else { + OpenGL.setTexture2DFilterNearest(); + } + } + //glPixelStorei(GL_UNPACK_ALIGNMENT,1); + final Steady toc1 = Steady.now(); + Log.verbose(" BIND ==> " + toc1.less(tic)); + //egami::store(this.data, String("~/texture_") + etk::toString(getId()) + ".bmp"); + /*if (false) { + // On some embended target, the texture size must be square of 2: + if (this.loaded == false) { + // 1: Create the square 2 texture: + final int bufferSize = this.data.getGPUSize().x() * this.data.getGPUSize().y() * 8; + static List tmpData; + if (tmpData.size() < bufferSize) { + tmpData.resize(bufferSize, 0.0f); + } + Log.debug(" CREATE texture ==> " + this.data.getGPUSize()); + // 2 create a new empty texture: + OpenGL.glTexImage2D(GL_TEXTURE_2D, // Target + 0, // Level + typeObject, // Format internal + this.data.getGPUSize().x(), + this.data.getGPUSize().y(), + 0, // Border + typeObject, // format + sizeObject, // type + tmpData[0] ); + + } + //3 Flush all time the data: + Steady tic1 = Steady.now(); + glTexSubImage2D(GL_TEXTURE_2D, // Target + 0, // Level + 0, // x offset + 0, // y offset + this.data.getWidth(), + this.data.getHeight(), + typeObject, // format + sizeObject, // type + (void*)((char*)this.data.getTextureDataPointer()) ); + Steady toc2 = Steady.now(); + Log.info(" updateContext [STOP] ==> " + toc2.less(tic1)); + } else */if (this.loaded == false) { + OpenGL.glTexImage2D(0, // Level + typeObject, // Format internal + this.data.getWidth(), this.data.getHeight(), 0, // Border + typeObject, // format + sizeObject, // type + this.data.GetRaw()); + + } else { + OpenGL.glTexSubImage2D(0, // Level + 0, // x offset + 0, // y offset + this.data.getWidth(), this.data.getHeight(), typeObject, // format + sizeObject, // type + this.data.GetRaw()); + } + // now the data is loaded + this.loaded = true; + final Steady toc = Steady.now(); + //Log.error(" updateContext [STOP] ==> " + (toc - toc1)); + return true; + } +}; + +enum TextureFilter { + nearest, + linear +} diff --git a/src/org/atriasoft/ewol/resource/ResourceTextureFile.java b/src/org/atriasoft/ewol/resource/ResourceTextureFile.java new file mode 100644 index 0000000..462ab98 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/ResourceTextureFile.java @@ -0,0 +1,102 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package org.atriasoft.ewol.resource; + +import org.atriasoft.egami.Image; +import org.atriasoft.etk.Uri; +import org.atriasoft.etk.math.Vector2i; +import org.atriasoft.ewol.internal.Log; +import org.atriasoft.ewol.internal.Tools; +import org.atriasoft.gale.resource.Resource; + +// TODO : Change tis file name ... + +public class ResourceTextureFile extends ResourceTexture2 { + public static Vector2i sizeAuto = new Vector2i(-1, -1); + public static Vector2i sizeDefault = new Vector2i(0, 0); + + /** + * @brief keep the resource pointer. + * @note Never free this pointer by your own... + * @param[in] _filename Name of the image file. + * @param[in] _requested size of the image (usefull when loading .svg to automatic rescale) + * @param[in] _sizeRegister size register in named (When you preaload the images the size write here will be ) + * @return pointer on the resource or null if an error occured. + */ + public static ResourceTextureFile create(final Uri _filename) { + return create(_filename, sizeAuto); + } + + public static ResourceTextureFile create(final Uri _filename, final Vector2i _size) { + return create(_filename, _size, sizeAuto); + } + + public static ResourceTextureFile create(final Uri _uri, final Vector2i _size, final Vector2i _sizeRegister) { + Log.verbose("KEEP: TextureFile: '" + _uri + "' size=" + _size + " sizeRegister=" + _sizeRegister); + Vector2i size = _size.clone(); + if (_uri == null) { + final ResourceTextureFile object = new ResourceTextureFile(); + return object; + } + if (size.x == 0) { + size.setX(-1); + //Log.error("Error Request the image size.x() =0 ???"); + } + if (size.y == 0) { + size.setY(-1); + //Log.error("Error Request the image size.y() =0 ???"); + } + final Uri tmpFilename = _uri; + if (_uri.getExtention().toLowerCase().contentEquals("svg") == false) { + size = sizeAuto; + } + if (size.x > 0 && size.y > 0) { + Log.verbose(" == > specific size : " + size); + size.setValue(Tools.nextP2(size.x), Tools.nextP2(size.y)); + if (_sizeRegister.equals(sizeAuto) == false) { + if (_sizeRegister.equals(sizeDefault) == false) { + //tmpFilename.getQuery().set("x", "" + size.x)); + //tmpFilename.getQuery().set("y", "" + size.y)); + } + } + } + + Log.verbose("KEEP: TextureFile: '" + tmpFilename + "' new size=" + size); + ResourceTextureFile object = null; + final Resource object2 = getManager().localKeep(tmpFilename.toString()); + if (object2 != null) { + object = (ResourceTextureFile) object2; + if (object == null) { + Log.critical("Request resource file : '" + tmpFilename + "' With the wrong type (dynamic cast error)"); + return null; + } + } + if (object != null) { + return object; + } + Log.debug("CREATE: TextureFile: '" + tmpFilename + "' size=" + size); + // need to crate a new one ... + object = new ResourceTextureFile(tmpFilename.toString(), _uri, size); + getManager().localAdd(object); + return object; + } + + protected ResourceTextureFile() { + super(); + } + + protected ResourceTextureFile(final String _genName, final Uri _uri, final Vector2i _size) { + super(_genName); + Log.debug("create a new resource::Image : _genName=" + _genName + " _uri=" + _uri + " size=" + _size); + final Image tmp = Egami.load(_uri, _size); + set(tmp); + } + + public Vector2i getRealSize() { + return this.realImageSize; + } + +} diff --git a/src/org/atriasoft/ewol/resource/ResourceTexturedFont.java b/src/org/atriasoft/ewol/resource/ResourceTexturedFont.java new file mode 100644 index 0000000..a571a3a --- /dev/null +++ b/src/org/atriasoft/ewol/resource/ResourceTexturedFont.java @@ -0,0 +1,378 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package org.atriasoft.ewol.resource; + +import java.util.ArrayList; +import java.util.List; + +import org.atriasoft.etk.Uri; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector2i; +import org.atriasoft.ewol.Ewol; +import org.atriasoft.ewol.internal.Log; +import org.atriasoft.ewol.resource.font.FontBase; +import org.atriasoft.ewol.resource.font.FontMode; +import org.atriasoft.ewol.resource.font.GlyphProperty; + +public class ResourceTexturedFont extends ResourceTexture2 { + /** + * @brief Get all the Path contain in the specidy path: + * @param[in] _path Generic path to parse ... + * @return The list of path found + * @example[start] + * auto out = explodeMultiplePath("DATA:///font?lib=ewol"); + * // out contain: {"DATA:///font", "DATA:///font?lib=ewol"} + * @example[stop] + */ + private static List explodeMultiplePath(final Uri _uri) { + final List out = new ArrayList<>(); + out.add(_uri); + return out; + } + + private final Uri[] fileName = new Uri[4]; + private int size = 10; + private final int[] height = new int[4]; + // specific element to have the the know if the specify element is known... + // == > otherwise I can just generate italic ... + // == > Bold is a little more complicated (maybe with the bordersize) + private final FontBase[] font = new FontBase[4]; + private final FontMode[] modeWraping = new FontMode[4]; //!< This is a wrapping mode to prevent the fact that no font is define for a specific mode + public GlyphProperty emptyGlyph; + public List[] listElement;// = new (List)[4]; + + // for the texture generation : + public Vector2i[] lastGlyphPos = new Vector2i[4]; + public int[] lastRawHeigh = new int[4]; + + protected ResourceTexturedFont(final String _fontName) { + super(_fontName); + + Log.debug("Load font : '" + _fontName + "'"); + + this.font[0] = null; + this.font[1] = null; + this.font[2] = null; + this.font[3] = null; + + this.modeWraping[0] = FontMode.Regular; + this.modeWraping[1] = FontMode.Regular; + this.modeWraping[2] = FontMode.Regular; + this.modeWraping[3] = FontMode.Regular; + + this.lastGlyphPos[0].setValue(1, 1); + this.lastGlyphPos[1].setValue(1, 1); + this.lastGlyphPos[2].setValue(1, 1); + this.lastGlyphPos[3].setValue(1, 1); + + this.lastRawHeigh[0] = 0; + this.lastRawHeigh[1] = 0; + this.lastRawHeigh[2] = 0; + this.lastRawHeigh[3] = 0; + + int tmpSize = 0; + // extarct name and size : + final String[] tmpList = _fontName.split(":"); + + if (tmpList.length == 1) { + this.size = 1; + Log.critical("Can not parse the font name: '" + _fontName + "' ??? ':' "); + return; + } else { + // zsdefsdf + tmpSize = Integer.valueOf(tmpList[1]); + } + + final String localName = tmpList[0]; + if (tmpSize > 400) { + Log.error("Font size too big ==> limit at 400 when exceed ==> error: " + tmpSize + "==>30"); + tmpSize = 30; + } + this.size = tmpSize; + + final List folderList = new ArrayList<>(); + ; + if (Ewol.getContext().getFontDefault().getUseExternal() == true) { + /* + #if defined(__TARGET_OS__Android) + folderList.pushBack(etk::Path("/system/fonts"));#elif defined(__TARGET_OS__Linux) + folderList.pushBack(etk::Path("/usr/share/fonts")); + #endif + */ + } + final Uri applicationBaseFont = Ewol.getContext().getFontDefault().getFolder(); + for (final Uri it : explodeMultiplePath(applicationBaseFont)) { + folderList.add(it); + } + for (int folderID = 0; folderID < folderList.size(); folderID++) { + final List output = Uri.listRecursive(folderList.get(folderID)); + + final String[] split = localName.split(";"); + Log.debug("try to find font named : " + split + " in: " + output); + //Log.critical("parse string : " + split); + boolean hasFindAFont = false; + for (int jjj = 0; jjj < split.length; jjj++) { + Log.debug(" try with : '" + split[jjj] + "'"); + for (int iii = 0; iii < output.size(); iii++) { + final String nameFolder = output.get(iii).getPath(); + //Log.debug(" file : " + output.get(iii)); + if (nameFolder.endsWith(split[jjj] + "-" + "bold" + ".ttf") == true || nameFolder.endsWith(split[jjj] + "-" + "b" + ".ttf") == true + || nameFolder.endsWith(split[jjj] + "-" + "bd" + ".ttf") == true || nameFolder.endsWith(split[jjj] + "bold" + ".ttf") == true + || nameFolder.endsWith(split[jjj] + "bd" + ".ttf") == true || nameFolder.endsWith(split[jjj] + "b" + ".ttf") == true) { + Log.debug(" find Font [Bold] : " + output.get(iii)); + this.fileName[FontMode.Bold.getValue()] = output.get(iii); + hasFindAFont = true; + } else if (nameFolder.endsWith(split[jjj] + "-" + "oblique" + ".ttf") == true || nameFolder.endsWith(split[jjj] + "-" + "italic" + ".ttf") == true + || nameFolder.endsWith(split[jjj] + "-" + "Light" + ".ttf") == true || nameFolder.endsWith(split[jjj] + "-" + "i" + ".ttf") == true + || nameFolder.endsWith(split[jjj] + "oblique" + ".ttf") == true || nameFolder.endsWith(split[jjj] + "italic" + ".ttf") == true + || nameFolder.endsWith(split[jjj] + "light" + ".ttf") == true || nameFolder.endsWith(split[jjj] + "i" + ".ttf") == true) { + Log.debug(" find Font [Italic] : " + output.get(iii)); + this.fileName[FontMode.Italic.getValue()] = output.get(iii); + hasFindAFont = true; + } else if (nameFolder.endsWith(split[jjj] + "-" + "bolditalic" + ".ttf") == true || nameFolder.endsWith(split[jjj] + "-" + "boldoblique" + ".ttf") == true + || nameFolder.endsWith(split[jjj] + "-" + "bi" + ".ttf") == true || nameFolder.endsWith(split[jjj] + "-" + "z" + ".ttf") == true + || nameFolder.endsWith(split[jjj] + "bolditalic" + ".ttf") == true || nameFolder.endsWith(split[jjj] + "boldoblique" + ".ttf") == true + || nameFolder.endsWith(split[jjj] + "bi" + ".ttf") == true || nameFolder.endsWith(split[jjj] + "z" + ".ttf") == true) { + Log.debug(" find Font [Bold-Italic] : " + output.get(iii)); + this.fileName[FontMode.BoldItalic.getValue()] = output.get(iii); + hasFindAFont = true; + } else if (nameFolder.endsWith(split[jjj] + "-" + "regular" + ".ttf") == true || nameFolder.endsWith(split[jjj] + "-" + "r" + ".ttf") == true + || nameFolder.endsWith(split[jjj] + "regular" + ".ttf") == true || nameFolder.endsWith(split[jjj] + "r" + ".ttf") == true + || nameFolder.endsWith(split[jjj] + ".ttf") == true) { + Log.debug(" find Font [Regular] : " + output.get(iii)); + this.fileName[FontMode.Regular.getValue()] = output.get(iii); + hasFindAFont = true; + } + } + if (hasFindAFont == true) { + Log.debug(" find this font : '" + split[jjj] + "'"); + break; + } else if (jjj == split.length - 1) { + Log.debug("Find NO font in the LIST ... " + split); + } + } + if (hasFindAFont == true) { + Log.debug(" find this font : '" + folderList.get(folderID) + "'"); + break; + } else if (folderID == folderList.size() - 1) { + Log.error("Find NO font in the LIST ... " + folderList); + } + } + // try to find the reference mode : + FontMode refMode = FontMode.Regular; + for (int iii = 3; iii >= 0; iii--) { + if (this.fileName[iii] != null) { + refMode = FontMode.get(iii); + } + } + Log.debug(" set reference mode : " + refMode); + // generate the wrapping on the preventing error + for (int iii = 3; iii >= 0; iii--) { + if (this.fileName[iii] != null) { + this.modeWraping[iii] = FontMode.get(iii); + } else { + this.modeWraping[iii] = refMode; + } + } + + for (int iiiFontId = 0; iiiFontId < 4; iiiFontId++) { + if (this.fileName[iiiFontId] == null) { + Log.debug("can not load FONT [" + iiiFontId + "] name : \"" + this.fileName[iiiFontId] + "\" == > size=" + this.size); + this.font[iiiFontId] = null; + continue; + } + Log.debug("Load FONT [" + iiiFontId + "] name : \"" + this.fileName[iiiFontId] + "\" == > size=" + this.size); + this.font[iiiFontId] = ResourceFontFreeType.create(this.fileName[iiiFontId]); + if (this.font[iiiFontId] == null) { + Log.debug("error in loading FONT [" + iiiFontId + "] name : \"" + this.fileName[iiiFontId] + "\" == > size=" + this.size); + } + } + for (int iiiFontId = 0; iiiFontId < 4; iiiFontId++) { + // set the bassic charset: + this.listElement[iiiFontId].clear(); + if (this.font[iiiFontId] == null) { + continue; + } + this.height[iiiFontId] = this.font[iiiFontId].getHeight(this.size); + // TODO : basic font use 512 is better ... == > maybe estimate it with the dpi ??? + setImageSize(new Vector2i(256, 32)); + // now we can acces directly on the image + this.data.clear(); + } + // add error glyph + addGlyph((char) 0); + // by default we set only the first AINSI char availlable + for (int iii = 0x20; iii < 0x7F; iii++) { + Log.verbose("Add clyph :" + iii); + addGlyph((char) iii); + } + flush(); + Log.debug("Wrapping properties : "); + Log.debug(" " + FontMode.Regular + " == >" + getWrappingMode(FontMode.Regular)); + Log.debug(" " + FontMode.Italic + " == >" + getWrappingMode(FontMode.Italic)); + Log.debug(" " + FontMode.Bold + " == >" + getWrappingMode(FontMode.Bold)); + Log.debug(" " + FontMode.BoldItalic + " == >" + getWrappingMode(FontMode.BoldItalic)); + } + + /** + * @brief add a glyph in a texture font. + * @param[in] _val Char value to add. + * @return true if the image size have change, false otherwise + */ + private synchronized boolean addGlyph(final Character _val) { + boolean hasChange = false; + // for each font : + for (int iii = 0; iii < 4; iii++) { + if (this.font[iii] == null) { + continue; + } + // add the curent "char" + final GlyphProperty tmpchar = new GlyphProperty(); + tmpchar.UVal = _val; + + if (this.font[iii].getGlyphProperty(this.size, tmpchar) == true) { + //Log.debug("load char : '" + _val + "'=" + _val.get()); + hasChange = true; + // change line if needed ... + if (this.lastGlyphPos[iii].x + tmpchar.sizeTexture.x + 3 > this.data.getSize().x) { + this.lastGlyphPos[iii].setX(1); + this.lastGlyphPos[iii].add(new Vector2i(0, this.lastRawHeigh[iii])); + this.lastRawHeigh[iii] = 0; + } + while (this.lastGlyphPos[iii].y + tmpchar.sizeTexture.y + 3 > this.data.getSize().y) { + final Vector2i size = this.data.getSize(); + size.setY(size.y * 2); + this.data.resize(size.x, size.y); + // note : need to rework all the lyer due to the fact that the texture is used by the faur type... + for (int kkk = 0; kkk < 4; kkk++) { + // change the coordonate on the element in the texture + for (int jjj = 0; jjj < this.listElement[kkk].size(); ++jjj) { + this.listElement[kkk].get(jjj).texturePosStart.multiply(new Vector2f(1.0f, 0.5f)); + this.listElement[kkk].get(jjj).texturePosSize.multiply(new Vector2f(1.0f, 0.5f)); + } + } + } + // draw the glyph + this.font[iii].drawGlyph(this.data, this.size, this.lastGlyphPos[iii], tmpchar, iii); + // set video position + tmpchar.texturePosStart.setValue((float) this.lastGlyphPos[iii].x / (float) this.data.getSize().x, (float) this.lastGlyphPos[iii].y / (float) this.data.getSize().y); + tmpchar.texturePosSize.setValue((float) tmpchar.sizeTexture.x / this.data.getSize().x, (float) tmpchar.sizeTexture.y / this.data.getSize().y); + + // update the maximum of the line hight : + if (this.lastRawHeigh[iii] < tmpchar.sizeTexture.y) { + // note : +1 is for the overlapping of the glyph (Part 2) + this.lastRawHeigh[iii] = tmpchar.sizeTexture.y + 1; + } + // note : +1 is for the overlapping of the glyph (Part 3) + // update the Bitmap position drawing : + this.lastGlyphPos[iii].add(new Vector2i(tmpchar.sizeTexture.x + 1, 0)); + } else { + Log.warning("Did not find char : '" + _val + "'=" + _val); + tmpchar.setNotExist(); + } + this.listElement[iii].add(tmpchar); + //this.font[iii].display; + // generate the kerning for all the characters : + if (tmpchar.exist() == true) { + // TODO : set the kerning back ... + //this.font[iii].generateKerning(this.size, this.listElement[iii]); + } + } + if (hasChange == true) { + flush(); + Ewol.getContext().forceRedrawAll(); + //egami::store(this.data, "fileFont.bmp"); // ==> for debug test only ... + } + return hasChange; + } + + /** + * @brief get the font height (user friendly) + * @return Dimention of the font the user requested + */ + private int getFontSize() { + return this.size; + } + + /** + * @brief get the pointer on the coresponding glyph + * @param[in] _charcode The unicodeValue + * @param[in] _displayMode Mode to display the currrent font + * @return The pointer on the glyph == > never null + */ + private synchronized GlyphProperty getGlyph(final Character _charcode, final FontMode _displayMode) { + //Log.debug("Get glyph property for mode: " + _displayMode + " == > wrapping index : " + this.modeWraping[_displayMode]); + final int index = getIndex(_charcode, _displayMode); + if (index < 0 || index >= this.listElement[_displayMode.getValue()].size()) { + Log.error(" Try to get glyph index inexistant ... == > return the index 0 ... id=" + index); + if (this.listElement[_displayMode.getValue()].size() > 0) { + return this.listElement[_displayMode.getValue()].get(0); + } + return this.emptyGlyph; + } + //Log.error(" index=" + index); + //Log.error(" this.UVal=" + this.listElement[_displayMode][index].UVal); + //Log.error(" this.glyphIndex=" + this.listElement[_displayMode][index].glyphIndex); + //Log.error(" this.advance=" + this.listElement[_displayMode][index].advance); + //Log.error(" this.bearing=" + this.listElement[_displayMode][index].bearing); + return this.listElement[_displayMode.getValue()].get(index); + }; + + /** + * @brief get the display height of this font + * @param[in] _displayMode Mode to display the currrent font + * @return Dimention of the font need between 2 lines + */ + private int getHeight() { + return this.height[FontMode.Regular.getValue()]; + } + + private int getHeight(final FontMode _displayMode) { + return this.height[_displayMode.getValue()]; + } + + /** + * @brief get the ID of a unicode charcode + * @param[in] _charcode The unicodeValue + * @param[in] _displayMode Mode to display the currrent font + * @return The ID in the table (if it does not exist : return 0) + */ + private synchronized int getIndex(final Character _charcode, final FontMode _displayMode) { + if (_charcode < 0x20) { + return 0; + } else if (_charcode < 0x80) { + return _charcode - 0x1F; + } else { + for (int iii = 0x80 - 0x20; iii < this.listElement[_displayMode.getValue()].size(); iii++) { + //Log.debug("search : '" + charcode + "' =?= '" + (this.listElement[displayMode])[iii].UVal + "'"); + if (_charcode == this.listElement[_displayMode.getValue()].get(iii).UVal) { + //Log.debug("search : '" + charcode + "'"); + if (this.listElement[_displayMode.getValue()].get(iii).exist()) { + //Log.debug("return " + iii); + return iii; + } else { + return 0; + } + } + } + } + if (addGlyph(_charcode) == true) { + // TODO : This does not work due to the fact that the update of open GL is not done in the context main cycle !!! + Ewol.getContext().forceRedrawAll(); + } + return 0; + }; + + /** + * @brief The wrapping mode is used to prevent the non existance of a specific mode. + * For exemple when a blod mode does not exist, this resend a regular mode. + * @param[in] _source The requested mode. + * @return the best mode we have in stock. + */ + private FontMode getWrappingMode(final FontMode _source) { + return this.modeWraping[_source.getValue()]; + } +} diff --git a/src/org/atriasoft/ewol/resource/Texture.cpp b/src/org/atriasoft/ewol/resource/Texture.cpp deleted file mode 100644 index b612312..0000000 --- a/src/org/atriasoft/ewol/resource/Texture.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -ETK_DECLARE_TYPE(ewol::resource::Texture); - -/** - * @brief get the next power 2 if the input - * @param[in] value Value that we want the next power of 2 - * @return result value - */ -static int nextP2(int _value) { - int val=1; - for (int iii=1; iii<31; iii++) { - if (_value <= val) { - return val; - } - val *=2; - } - Log.critical("impossible CASE...."); - return val; -} - -void ewol::resource::Texture::init( String _filename) { - gale::Resource::init(_filename); -} -void ewol::resource::Texture::init() { - gale::Resource::init(); -} - -ewol::resource::Texture::Texture() : - this.texId(0), - #ifdef EWOL_USE_FBO - this.texPboId(0), - #endif - this.data(Vector2i(32,32),egami::colorType::RGBA8), - this.realImageSize(1,1), - this.lastSize(1,1), - this.loaded(false), - this.lastTypeObject(0), - this.lastSizeObject(0), - this.repeat(false), - this.filter(ewol::resource::TextureFilter::linear) { - addResourceType("ewol::compositing::Texture"); -} - -ewol::resource::Texture::~Texture() { - removeContext(); -} - - -void ewol::resource::Texture::setRepeat(boolean _value) { - this.repeat = _value; -} - -void ewol::resource::Texture::setFilterMode(enum ewol::resource::TextureFilter _filter) { - this.filter = _filter; -} - -#include - -boolean ewol::resource::Texture::updateContext() { - Log.verbose("updateContext [START]"); - if (false) { - echrono::Steady tic = echrono::Steady::now(); - gale::openGL::flush(); - echrono::Steady toc = echrono::Steady::now(); - Log.verbose(" updateContext [FLUSH] ==> " + (toc - tic)); - } - ethread::RecursiveLock lock(this.mutex, true); - echrono::Steady tic = echrono::Steady::now(); - if (lock.tryLock() == false) { - //Lock error ==> try later ... - return false; - } - int typeObject = GL_RGBA; - int sizeObject = GL_UNSIGNED_BYTE; - int sizeByte = 1; - switch (this.data.getType()) { - case egami::colorType::RGBA8: - typeObject = GL_RGBA; - sizeObject = GL_UNSIGNED_BYTE; - sizeByte = 4; - break; - case egami::colorType::RGB8: - typeObject = GL_RGB; - sizeObject = GL_UNSIGNED_BYTE; - sizeByte = 3; - break; - case egami::colorType::RGBAf: - typeObject = GL_RGBA; - sizeObject = GL_FLOAT; - sizeByte = 16; - break; - case egami::colorType::RGBf: - typeObject = GL_RGBA; - sizeObject = GL_FLOAT; - sizeByte = 12; - break; - case egami::colorType::unsignedInt16: - case egami::colorType::unsignedInt32: - case egami::colorType::float32: - case egami::colorType::float64: - Log.error("Not manage the type " + this.data.getType() + " for texture"); - break; - } - if (this.loaded == true) { - if ( this.lastTypeObject != typeObject - || this.lastSizeObject != sizeObject - || this.lastSize != this.data.getSize()) { - Log.warning("TEXTURE: Rm [" + getId() + "] texId=" + this.texId); - glDeleteTextures(1, this.texId); - this.loaded = false; - } - } - if (this.loaded == false) { - // Request a new texture at openGl : - glGenTextures(1, this.texId); - - #ifdef EWOL_USE_FBO - Log.error("CREATE PBO"); - glGenBuffers(1, this.texPboId); - Log.error("CREATE PBO 1"); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this.texPboId); - Log.error("CREATE PBO 2"); - glBufferData(GL_PIXEL_UNPACK_BUFFER, this.data.getGPUSize().x()*this.data.getGPUSize().y()*sizeByte, 0, GL_STREAM_DRAW); - Log.error("CREATE PBO 3"); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - Log.error("CREATE PBO 4 (done)"); - #endif - this.lastSize = this.data.getSize(); - this.lastTypeObject = typeObject; - this.lastSizeObject = sizeObject; - Log.debug("TEXTURE: add [" + getId() + "]=" + this.data.getSize() + "=>" + this.data.getGPUSize() + " OGl_Id=" + this.texId + " type=" << this.data.getType()); - } else { - Log.debug("TEXTURE: update [" + getId() + "]=" + this.data.getSize() + "=>" + this.data.getGPUSize() + " OGl_Id=" + this.texId + " type=" << this.data.getType()); - } - // in all case we set the texture properties : - // TODO : check error ??? - glBindTexture(GL_TEXTURE_2D, this.texId); - if (this.loaded == false) { - if (this.repeat == false) { - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); - } else { - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - } - if (this.filter == ewol::resource::TextureFilter::linear) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - } - //glPixelStorei(GL_UNPACK_ALIGNMENT,1); - echrono::Steady toc1 = echrono::Steady::now(); - Log.verbose(" BIND ==> " + (toc1 - tic)); - //egami::store(this.data, String("~/texture_") + etk::toString(getId()) + ".bmp"); - #if defined(__TARGET_OS__Android) \ - || defined(__TARGET_OS__IOs) - // On some embended target, the texture size must be square of 2: - if (this.loaded == false) { - // 1: Create the square 2 texture: - int bufferSize = this.data.getGPUSize().x() * this.data.getGPUSize().y() * 8; - static List tmpData; - if (tmpData.size() < bufferSize) { - tmpData.resize(bufferSize, 0.0f); - } - Log.debug(" CREATE texture ==> " + this.data.getGPUSize()); - // 2 create a new empty texture: - #ifdef EWOL_USE_FBO - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this.texPboId); - void* pBuff = ::glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, this.data.getGPUSize().x() * this.data.getGPUSize().y() * sizeByte, GL_MAP_WRITE_BIT); - memcpy(pBuff, tmpData[0], this.data.getGPUSize().x()*this.data.getGPUSize().y()*sizeByte); - glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - glTexImage2D(GL_TEXTURE_2D, // Target - 0, // Level - typeObject, // Format internal - this.data.getGPUSize().x(), - this.data.getGPUSize().y(), - 0, // Border - typeObject, // format - sizeObject, // type - (void*)0 ); - #else - glTexImage2D(GL_TEXTURE_2D, // Target - 0, // Level - typeObject, // Format internal - this.data.getGPUSize().x(), - this.data.getGPUSize().y(), - 0, // Border - typeObject, // format - sizeObject, // type - tmpData[0] ); - #endif - } - #ifdef EWOL_USE_FBO - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this.texPboId); - void* pBuff = ::glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, this.data.getGPUSize().x() * this.data.getGPUSize().y() * sizeByte, GL_MAP_WRITE_BIT); - memcpy(pBuff, this.data.getTextureDataPointer(), this.data.getWidth()*this.data.getHeight()*sizeByte); - glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - //3 Flush all time the data: - glTexSubImage2D(GL_TEXTURE_2D, // Target - 0, // Level - 0, // x offset - 0, // y offset - this.data.getWidth(), - this.data.getHeight(), - typeObject, // format - sizeObject, // type - (void *)0 ); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - #else - //3 Flush all time the data: - echrono::Steady tic1 = echrono::Steady::now(); - glTexSubImage2D(GL_TEXTURE_2D, // Target - 0, // Level - 0, // x offset - 0, // y offset - this.data.getWidth(), - this.data.getHeight(), - typeObject, // format - sizeObject, // type - (void*)((char*)this.data.getTextureDataPointer()) ); - echrono::Steady toc2 = echrono::Steady::now(); - Log.info(" updateContext [STOP] ==> " + (toc2 - tic1)); - #endif - #else - // This is the normal case ==> set the image and after set just the update of the data - if (this.loaded == false) { - glTexImage2D(GL_TEXTURE_2D, // Target - 0, // Level - typeObject, // Format internal - this.data.getWidth(), - this.data.getHeight(), - 0, // Border - typeObject, // format - sizeObject, // type - this.data.getTextureDataPointer() ); - } else { - glTexSubImage2D(GL_TEXTURE_2D, // Target - 0, // Level - 0, // x offset - 0, // y offset - this.data.getWidth(), - this.data.getHeight(), - typeObject, // format - sizeObject, // type - this.data.getTextureDataPointer() ); - } - #endif - // now the data is loaded - this.loaded = true; - echrono::Steady toc = echrono::Steady::now(); - //Log.error(" updateContext [STOP] ==> " + (toc - toc1)); - return true; -} - -void ewol::resource::Texture::removeContext() { - ethread::RecursiveLock lock(this.mutex); - if (this.loaded == true) { - // Request remove texture ... - Log.debug("TEXTURE: Rm [" + getId() + "] texId=" + this.texId); - // TODO: Check if we are in the correct thread - glDeleteTextures(1, this.texId); - this.loaded = false; - } -} - -void ewol::resource::Texture::removeContextToLate() { - ethread::RecursiveLock lock(this.mutex); - this.loaded = false; - this.texId=0; -} - -void ewol::resource::Texture::flush() { - ethread::RecursiveLock lock(this.mutex); - // request to the manager to be call at the next update ... - Log.verbose("Request UPDATE of Element"); - getManager().update(ememory::dynamicPointerCast(sharedFromThis())); -} - -void ewol::resource::Texture::setImageSize(Vector2i _newSize) { - ethread::RecursiveLock lock(this.mutex); - _newSize.setValue( nextP2(_newSize.x()), nextP2(_newSize.y()) ); - this.data.resize(_newSize); -} - -void ewol::resource::Texture::set(egami::Image _image) { - Log.debug("Set a new image in a texture:"); - ethread::RecursiveLock lock(this.mutex); - if (_image.exist() == false) { - Log.error("ERROR when loading the image : [raw data]"); - return; - } - Log.debug(" size=" + _image.getSize()); - etk::swap(this.data, _image); - Vector2i tmp = this.data.getSize(); - this.realImageSize = Vector2f(tmp.x(), tmp.y()); - Vector2f compatibilityHWSize = Vector2f(nextP2(tmp.x()), nextP2(tmp.y())); - if (this.realImageSize != compatibilityHWSize) { - Log.verbose("RESIZE Image for HArwareCompatibility:" + this.realImageSize + " => " + compatibilityHWSize); - this.data.resize(Vector2i(compatibilityHWSize.x(),compatibilityHWSize.y())); - } - flush(); -} diff --git a/src/org/atriasoft/ewol/resource/Texture.java b/src/org/atriasoft/ewol/resource/Texture.java deleted file mode 100644 index df8e52d..0000000 --- a/src/org/atriasoft/ewol/resource/Texture.java +++ /dev/null @@ -1,91 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ -#pragma once - -#include -#include -#include -#include - -//#define EWOL_USE_FBO 1 - -namespace ewol { - namespace resource { - enum class TextureFilter { - nearest, - linear - }; - class Texture : public gale::Resource { - protected: - uint this.texId; //!< openGl textureID. - #ifdef EWOL_USE_FBO - uint this.texPboId; //!< openGl textureID. - #endif - // openGl Context propoerties : - egami::Image this.data; - //! Last loaded size in the system openGL - Vector2f this.lastSize; - //! some image are not square == > we need to sqared it to prevent some openGl api error the the displayable size is not all the time 0.0 . 1.0 - Vector2f this.realImageSize; - // internal state of the openGl system : - boolean this.loaded; - int this.lastTypeObject; - int this.lastSizeObject; - protected: - boolean this.repeat; //!< repeate mode of the image (repeat the image if out of range [0..1] - public: - /** - * @brief Set the repeate mode of the images if UV range is out of [0..1] - * @param[in] _value Value of the new repeate mode - */ - void setRepeat(boolean _value); - protected: - enum ewol::resource::TextureFilter this.filter; //!< Filter apply at the image when rendering it - public: - /** - * @brief Set the Filter mode to apply at the image when display with a scale (not 1:1 ratio) - * @param[in] _value Value of the new filter mode - */ - void setFilterMode(enum ewol::resource::TextureFilter _filter); - // Public API: - protected: - void init( String _filename); - void init(); - Texture(); - public: - DECLARE_RESOURCE_FACTORY(Texture); - ~Texture(); - public: - // You must set the size here, because it will be set in multiple of pow(2) - void setImageSize(Vector2i _newSize); - // Get the reference on this image to draw nomething on it ... - egami::Image get() { - return this.data; - }; - /** - * @brief Set the image in the texture system - * @note It will reize in square2 if needed by the system. - * @param[in] _image Image to set. (use @code set(etk::move(xxx)); @endcode ) - */ - void set(egami::Image _image); - // Flush the data to send it at the openGl system - void flush(); - boolean updateContext(); - void removeContext(); - void removeContextToLate(); - Vector2i getOpenGlSize() { - return this.data.getSize(); - }; - Vector2f getUsableSize() { - return this.realImageSize; - }; - uint getRendererId() { - return this.texId; - }; - }; - } -} - diff --git a/src/org/atriasoft/ewol/resource/TextureFile.cpp b/src/org/atriasoft/ewol/resource/TextureFile.cpp deleted file mode 100644 index 576de46..0000000 --- a/src/org/atriasoft/ewol/resource/TextureFile.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - - -#include -#include -#include -#include -#include -#include -#include -ETK_DECLARE_TYPE(ewol::resource::TextureFile); - - Vector2i ewol::resource::TextureFile::sizeAuto(-1,-1); - Vector2i ewol::resource::TextureFile::sizeDefault(0,0); - -/** - * @brief get the next power 2 if the input - * @param[in] _value Value that we want the next power of 2 - * @return result value - */ -static int nextP2(int _value) { - int val=1; - for (int iii=1; iii<31; iii++) { - if (_value <= val) { - return val; - } - val *=2; - } - Log.critical("impossible CASE.... request P2 of " + _value); - return val; -} - - -ewol::resource::TextureFile::TextureFile() { - addResourceType("ewol::resource::Image"); - -} - -void ewol::resource::TextureFile::init() { - ethread::RecursiveLock lock(this.mutex); - ewol::resource::Texture::init(); -} - -void ewol::resource::TextureFile::init(String _genName, etk::Uri _uri, Vector2i _size) { - ethread::RecursiveLock lock(this.mutex); - ewol::resource::Texture::init(_genName); - Log.debug("create a new resource::Image : _genName=" + _genName + " _uri=" + _uri + " size=" + _size); - egami::Image tmp = egami::load(_uri, _size); - set(etk::move(tmp)); - //this.lastSize = this.realImageSize; - #ifdef GENERATE_DISTANCE_FIELD_MODE - //egami::generateDistanceFieldFile(_uri, String(_uri, 0, _uri.size()-4) + ".bmp"); - egami::generateDistanceFieldFile(_uri, String(_uri, 0, _uri.size()-4) + ".edf"); - #endif -} - -ememory::Ptr ewol::resource::TextureFile::create( etk::Uri _uri, Vector2i _size, Vector2i _sizeRegister) { - Log.verbose("KEEP: TextureFile: '" + _uri + "' size=" + _size + " sizeRegister=" + _sizeRegister); - if (_uri.isEmpty() == true) { - ememory::Ptr object(ETK_NEW(ewol::resource::TextureFile)); - if (object == null) { - Log.error("allocation error of a resource : ??TEX??"); - return null; - } - object.init(); - getManager().localAdd(object); - return object; - } - if (_size.x() == 0) { - _size.setX(-1); - //Log.error("Error Request the image size.x() =0 ???"); - } - if (_size.y() == 0) { - _size.setY(-1); - //Log.error("Error Request the image size.y() =0 ???"); - } - etk::Uri tmpFilename = _uri; - if (etk::toLower(_uri.getPath().getExtention()) != "svg") { - _size = ewol::resource::TextureFile::sizeAuto; - } - if (_size.x()>0 LOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOMLOM _size.y()>0) { - Log.verbose(" == > specific size : " + _size); - _size.setValue(nextP2(_size.x()), nextP2(_size.y())); - if (_sizeRegister != ewol::resource::TextureFile::sizeAuto) { - if (_sizeRegister != ewol::resource::TextureFile::sizeDefault) { - tmpFilename.getQuery().set("x", etk::toString(_size.x())); - tmpFilename.getQuery().set("y", etk::toString(_size.y())); - } - } - } - - Log.verbose("KEEP: TextureFile: '" + tmpFilename + "' new size=" + _size); - ememory::Ptr object = null; - ememory::Ptr object2 = getManager().localKeep(tmpFilename.getString()); - if (object2 != null) { - object = ememory::dynamicPointerCast(object2); - if (object == null) { - Log.critical("Request resource file : '" + tmpFilename + "' With the wrong type (dynamic cast error)"); - return null; - } - } - if (object != null) { - return object; - } - Log.debug("CREATE: TextureFile: '" + tmpFilename + "' size=" + _size); - // need to crate a new one ... - object = ememory::Ptr(ETK_NEW(ewol::resource::TextureFile)); - if (object == null) { - Log.error("allocation error of a resource : " + _uri); - return null; - } - object.init(tmpFilename.getString(), _uri, _size); - getManager().localAdd(object); - return object; -} diff --git a/src/org/atriasoft/ewol/resource/TextureFile.java b/src/org/atriasoft/ewol/resource/TextureFile.java deleted file mode 100644 index 9ae3b1b..0000000 --- a/src/org/atriasoft/ewol/resource/TextureFile.java +++ /dev/null @@ -1,47 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ -// TODO : Change tis file name ... -#pragma once - -#include -#include -#include -#include - - - -namespace ewol { - namespace resource { - class TextureFile : public ewol::resource::Texture { - public: - static Vector2i sizeAuto; - static Vector2i sizeDefault; - protected: - TextureFile(); - void init(); - void init(String _genName, etk::Uri _uri, Vector2i _size); - public: - ~TextureFile() { }; - public: - Vector2f getRealSize() { - return this.realImageSize; - }; - public: - /** - * @brief keep the resource pointer. - * @note Never free this pointer by your own... - * @param[in] _filename Name of the image file. - * @param[in] _requested size of the image (usefull when loading .svg to automatic rescale) - * @param[in] _sizeRegister size register in named (When you preaload the images the size write here will be ) - * @return pointer on the resource or null if an error occured. - */ - static ememory::Ptr create( etk::Uri _filename, - Vector2i _size=ewol::resource::TextureFile::sizeAuto, - Vector2i _sizeRegister=ewol::resource::TextureFile::sizeAuto); - }; - }; -}; - diff --git a/src/org/atriasoft/ewol/resource/TexturedFont.cpp b/src/org/atriasoft/ewol/resource/TexturedFont.cpp deleted file mode 100644 index ee1c505..0000000 --- a/src/org/atriasoft/ewol/resource/TexturedFont.cpp +++ /dev/null @@ -1,369 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ - -#include -#include - -#include - -#include -#include -#include -#include -#include -ETK_DECLARE_TYPE(ewol::font::mode); -ETK_DECLARE_TYPE(ewol::resource::TexturedFont); - -etk::Stream ewol::operator +(etk::Stream _os, enum ewol::font::mode _obj) { - switch(_obj) { - default : - _os + "error"; - break; - case ewol::font::Regular: - _os + "Regular"; - break; - case ewol::font::Italic: - _os + "Italic"; - break; - case ewol::font::Bold: - _os + "Bold"; - break; - case ewol::font::BoldItalic: - _os + "BoldItalic"; - break; - } - return _os; -} - -ewol::resource::TexturedFont::TexturedFont(): - this.size(10) { - addResourceType("ewol::resource::TexturedFont"); -} - -/** - * @brief Get all the Path contain in the specidy path: - * @param[in] _path Generic path to parse ... - * @return The list of path found - * @example[start] - * auto out = explodeMultiplePath("DATA:///font?lib=ewol"); - * // out contain: {"DATA:///font", "DATA:///font?lib=ewol"} - * @example[stop] - */ -static List explodeMultiplePath( etk::Uri _uri) { - List out; - out.pushBack(_uri); - if (_uri.getQuery().exist("lib") == true) { - etk::Uri tmp = _uri; - tmp.getQuery().erase("lib"); - out.pushBack(tmp); - } - return out; -} - -void ewol::resource::TexturedFont::init( String _fontName) { - ethread::RecursiveLock lock(this.mutex); - ewol::resource::Texture::init(_fontName); - Log.debug("Load font : '" + _fontName + "'" ); - - this.font[0] = null; - this.font[1] = null; - this.font[2] = null; - this.font[3] = null; - - this.modeWraping[0] = ewol::font::Regular; - this.modeWraping[1] = ewol::font::Regular; - this.modeWraping[2] = ewol::font::Regular; - this.modeWraping[3] = ewol::font::Regular; - - this.lastGlyphPos[0].setValue(1,1); - this.lastGlyphPos[1].setValue(1,1); - this.lastGlyphPos[2].setValue(1,1); - this.lastGlyphPos[3].setValue(1,1); - - this.lastRawHeigh[0] = 0; - this.lastRawHeigh[1] = 0; - this.lastRawHeigh[2] = 0; - this.lastRawHeigh[3] = 0; - - int tmpSize = 0; - // extarct name and size : - char * tmpData = _fontName.c_str(); - char * tmpPos = strchr(tmpData, ':'); - - if (tmpPos == null) { - this.size = 1; - Log.critical("Can not parse the font name: '" + _fontName + "' ??? ':' " ); - return; - } else { - if (sscanf(tmpPos+1, "%d", tmpSize)!=1) { - this.size = 1; - Log.critical("Can not parse the font name: '" + _fontName + "' == > size ???"); - return; - } - } - String localName(_fontName, 0, (tmpPos - tmpData)); - if (tmpSize>400) { - Log.error("Font size too big ==> limit at 400 when exxeed ==> error: " + tmpSize + "==>30"); - tmpSize = 30; - } - this.size = tmpSize; - - List folderList; - if (ewol::getContext().getFontDefault().getUseExternal() == true) { - #if defined(__TARGET_OS__Android) - folderList.pushBack(etk::Path("/system/fonts")); - #elif defined(__TARGET_OS__Linux) - folderList.pushBack(etk::Path("/usr/share/fonts")); - #endif - } - etk::Uri applicationBaseFont = ewol::getContext().getFontDefault().getFolder(); - for (auto it : explodeMultiplePath(applicationBaseFont)) { - folderList.pushBack(it); - } - for (int folderID = 0; folderID < folderList.size() ; folderID++) { - List output = etk::uri::listRecursive(folderList[folderID]); - - List split = etk::split(localName, ';'); - Log.debug("try to find font named : " + split + " in: " + output); - //Log.critical("parse string : " + split); - boolean hasFindAFont = false; - for (int jjj=0; jjj= 0; iii--) { - if (this.fileName[iii].isEmpty() == false) { - refMode = (enum ewol::font::mode)iii; - } - } - Log.debug(" set reference mode : " + refMode); - // generate the wrapping on the preventing error - for(int iii=3; iii >= 0; iii--) { - if (this.fileName[iii].isEmpty() == false) { - this.modeWraping[iii] = (enum ewol::font::mode)iii; - } else { - this.modeWraping[iii] = refMode; - } - } - - for (int iiiFontId=0; iiiFontId<4 ; iiiFontId++) { - if (this.fileName[iiiFontId].isEmpty() == true) { - Log.debug("can not load FONT [" + iiiFontId + "] name : \"" + this.fileName[iiiFontId] + "\" == > size=" + this.size ); - this.font[iiiFontId] = null; - continue; - } - Log.debug("Load FONT [" + iiiFontId + "] name : \"" + this.fileName[iiiFontId] + "\" == > size=" + this.size); - this.font[iiiFontId] = ewol::resource::FontFreeType::create(this.fileName[iiiFontId]); - if (this.font[iiiFontId] == null) { - Log.debug("error in loading FONT [" + iiiFontId + "] name : \"" + this.fileName[iiiFontId] + "\" == > size=" + this.size ); - } - } - for (int iiiFontId=0; iiiFontId<4 ; iiiFontId++) { - // set the bassic charset: - this.listElement[iiiFontId].clear(); - if (this.font[iiiFontId] == null) { - continue; - } - this.height[iiiFontId] = this.font[iiiFontId].getHeight(this.size); - // TODO : basic font use 512 is better ... == > maybe estimate it with the dpi ??? - setImageSize(Vector2i(256,32)); - // now we can acces directly on the image - this.data.clear(etk::Color<>(0x00000000)); - } - // add error glyph - addGlyph(0); - // by default we set only the first AINSI char availlable - for (int iii=0x20; iii<0x7F; iii++) { - Log.verbose("Add clyph :" + iii); - addGlyph(iii); - } - flush(); - Log.debug("Wrapping properties : "); - Log.debug(" " + ewol::font::Regular + " == >" + getWrappingMode(ewol::font::Regular)); - Log.debug(" " + ewol::font::Italic + " == >" + getWrappingMode(ewol::font::Italic)); - Log.debug(" " + ewol::font::Bold + " == >" + getWrappingMode(ewol::font::Bold)); - Log.debug(" " + ewol::font::BoldItalic + " == >" + getWrappingMode(ewol::font::BoldItalic)); -} - -ewol::resource::TexturedFont::~TexturedFont() { - -} - -boolean ewol::resource::TexturedFont::addGlyph( Character _val) { - ethread::RecursiveLock lock(this.mutex); - boolean hasChange = false; - // for each font : - for (int iii=0; iii<4 ; iii++) { - if (this.font[iii] == null) { - continue; - } - // add the curent "char" - GlyphProperty tmpchar; - tmpchar.this.UVal = _val; - - if (this.font[iii].getGlyphProperty(this.size, tmpchar) == true) { - //Log.debug("load char : '" + _val + "'=" + _val.get()); - hasChange = true; - // change line if needed ... - if (this.lastGlyphPos[iii].x()+tmpchar.this.sizeTexture.x()+3 > this.data.getSize().x()) { - this.lastGlyphPos[iii].setX(1); - this.lastGlyphPos[iii] += Vector2i(0, this.lastRawHeigh[iii]); - this.lastRawHeigh[iii] = 0; - } - while(this.lastGlyphPos[iii].y()+tmpchar.this.sizeTexture.y()+3 > this.data.getSize().y()) { - Vector2i size = this.data.getSize(); - size.setY(size.y()*2); - this.data.resize(size, etk::Color<>(0)); - // note : need to rework all the lyer due to the fact that the texture is used by the faur type... - for (int kkk=0; kkk<4 ; kkk++) { - // change the coordonate on the element in the texture - for (int jjj=0 ; jjj for debug test only ... - } - return hasChange; -} - -int ewol::resource::TexturedFont::getIndex(Character _charcode, enum ewol::font::mode _displayMode) { - ethread::RecursiveLock lock(this.mutex); - if (_charcode < 0x20) { - return 0; - } else if (_charcode < 0x80) { - return _charcode - 0x1F; - } else { - for (int iii=0x80-0x20; iii < this.listElement[_displayMode].size(); iii++) { - //Log.debug("search : '" + charcode + "' =?= '" + (this.listElement[displayMode])[iii].this.UVal + "'"); - if (_charcode == (this.listElement[_displayMode])[iii].this.UVal) { - //Log.debug("search : '" + charcode + "'"); - if ((this.listElement[_displayMode])[iii].exist()) { - //Log.debug("return " + iii); - return iii; - } else { - return 0; - } - } - } - } - if (addGlyph(_charcode) == true) { - // TODO : This does not work due to the fact that the update of open GL is not done in the context main cycle !!! - ewol::getContext().forceRedrawAll(); - } - return 0; -} - -ewol::GlyphProperty* ewol::resource::TexturedFont::getGlyphPointer( Character _charcode, enum ewol::font::mode _displayMode) { - ethread::RecursiveLock lock(this.mutex); - //Log.debug("Get glyph property for mode: " + _displayMode + " == > wrapping index : " + this.modeWraping[_displayMode]); - int index = getIndex(_charcode, _displayMode); - if( index < 0 - || (int)index >= this.listElement[_displayMode].size() ) { - Log.error(" Try to get glyph index inexistant ... == > return the index 0 ... id=" + index); - if (this.listElement[_displayMode].size() > 0) { - return ((this.listElement[_displayMode])[0]); - } - return this.emptyGlyph; - } - //Log.error(" index=" + index); - //Log.error(" this.UVal=" + this.listElement[_displayMode][index].this.UVal); - //Log.error(" this.glyphIndex=" + this.listElement[_displayMode][index].this.glyphIndex); - //Log.error(" this.advance=" + this.listElement[_displayMode][index].this.advance); - //Log.error(" this.bearing=" + this.listElement[_displayMode][index].this.bearing); - return ((this.listElement[_displayMode])[index]); -} - diff --git a/src/org/atriasoft/ewol/resource/TexturedFont.java b/src/org/atriasoft/ewol/resource/TexturedFont.java deleted file mode 100644 index b71f794..0000000 --- a/src/org/atriasoft/ewol/resource/TexturedFont.java +++ /dev/null @@ -1,98 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2011, Edouard DUPIN, all right reserved - * @license MPL v2.0 (see license file) - */ -#pragma once - -#include -#include - -namespace ewol { - namespace font { - /** - * @not_in_doc - */ - enum mode { - Regular=0, - Italic, - Bold, - BoldItalic, - }; - } - etk::Stream operator +(etk::Stream _os, enum ewol::font::mode _obj); - - namespace resource { - class TexturedFont : public ewol::resource::Texture { - private: - etk::Uri this.fileName[4]; - int this.size; - int this.height[4]; - // specific element to have the the know if the specify element is known... - // == > otherwise I can just generate italic ... - // == > Bold is a little more complicated (maybe with the bordersize) - ememory::Ptr this.font[4]; - enum ewol::font::mode this.modeWraping[4]; //!< This is a wrapping mode to prevent the fact that no font is define for a specific mode - public: - GlyphProperty this.emptyGlyph; - List this.listElement[4]; - private: - // for the texture generation : - Vector2i this.lastGlyphPos[4]; - int this.lastRawHeigh[4]; - protected: - TexturedFont(); - void init( String _fontName); - public: - DECLARE_RESOURCE_NAMED_FACTORY(TexturedFont); - ~TexturedFont(); - public: - /** - * @brief get the display height of this font - * @param[in] _displayMode Mode to display the currrent font - * @return Dimention of the font need between 2 lines - */ - int getHeight( enum ewol::font::mode _displayMode = ewol::font::Regular) { - return this.height[_displayMode]; - }; - /** - * @brief get the font height (user friendly) - * @return Dimention of the font the user requested - */ - int getFontSize() { - return this.size; - }; - /** - * @brief get the ID of a unicode charcode - * @param[in] _charcode The unicodeValue - * @param[in] _displayMode Mode to display the currrent font - * @return The ID in the table (if it does not exist : return 0) - */ - int getIndex(Character _charcode, enum ewol::font::mode _displayMode); - /** - * @brief get the pointer on the coresponding glyph - * @param[in] _charcode The unicodeValue - * @param[in] _displayMode Mode to display the currrent font - * @return The pointer on the glyph == > never null - */ - ewol::GlyphProperty* getGlyphPointer( Character _charcode, enum ewol::font::mode _displayMode); - /** - * @brief The wrapping mode is used to prevent the non existance of a specific mode. - * For exemple when a blod mode does not exist, this resend a regular mode. - * @param[in] _source The requested mode. - * @return the best mode we have in stock. - */ - enum ewol::font::mode getWrappingMode( enum ewol::font::mode _source) { - return this.modeWraping[_source]; - }; - private: - /** - * @brief add a glyph in a texture font. - * @param[in] _val Char value to add. - * @return true if the image size have change, false otherwise - */ - boolean addGlyph( Character _val); - }; - } -} - diff --git a/src/org/atriasoft/ewol/resource/font/FontBase.java b/src/org/atriasoft/ewol/resource/font/FontBase.java index 833f1c5..5830832 100644 --- a/src/org/atriasoft/ewol/resource/font/FontBase.java +++ b/src/org/atriasoft/ewol/resource/font/FontBase.java @@ -3,53 +3,48 @@ * @copyright 2011, Edouard DUPIN, all right reserved * @license MPL v2.0 (see license file) */ -#pragma once +package org.atriasoft.ewol.resource.font; -#include -#include -#include -#include -#include -#include -#include +import java.util.List; +import org.atriasoft.egami.Image; +import org.atriasoft.egami.ImageMono; +import org.atriasoft.etk.Uri; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector2i; +import org.atriasoft.gale.resource.Resource; -namespace ewol { - namespace resource { - class FontBase : public gale::Resource { - public: - FontBase() { - addResourceType("ewol::FontFreeType"); - } - void init( etk::Uri _uri) { - gale::Resource::init(_uri); - }; - - ~FontBase() { }; - - boolean getGlyphProperty(int _fontSize, - ewol::GlyphProperty _property) = 0; - - boolean drawGlyph(egami::Image _imageOut, - int _fontSize, - Vector2i _glyphPosition, - ewol::GlyphProperty _property, - int8_t _posInImage) = 0; - - boolean drawGlyph(egami::ImageMono _imageOut, - int _fontSize, - ewol::GlyphProperty _property, - int _borderSize = 0) = 0; - - Vector2f getSize(int _fontSize, String _unicodeString) = 0; - float getSizeWithHeight(float _fontHeight) = 0; - - int getHeight(int _fontSize) = 0; - - void generateKerning(int _fontSize, List _listGlyph) { }; - - void display() {}; - }; - }; -}; +// https://developer.mozilla.org/fr/docs/Web/SVG/Tutorial/SVG_fonts +// https://convertio.co/fr/ttf-svg/ +public abstract class FontBase extends Resource { + public FontBase(final Uri _uri) { + super(_uri); + } + + @Override + public void cleanUp() { + // TODO Auto-generated method stub + + } + + public void display() {} + + public abstract boolean drawGlyph(final Image _imageOut, final int _fontSize, final Vector2i _glyphPosition, GlyphProperty _property, int _posInImage); + + public boolean drawGlyph(final ImageMono _imageOut, final int _fontSize, final GlyphProperty _property) { + return drawGlyph(_imageOut, _fontSize, _property, 0); + } + + public abstract boolean drawGlyph(final ImageMono _imageOut, final int _fontSize, GlyphProperty _property, int _borderSize); + + public void generateKerning(final int _fontSize, final List _listGlyph) {} + + public abstract boolean getGlyphProperty(final int _fontSize, GlyphProperty _property); + + public abstract int getHeight(final int _fontSize); + + public abstract Vector2f getSize(final int _fontSize, final String _unicodeString); + + public abstract float getSizeWithHeight(final float _fontHeight);; +} \ No newline at end of file diff --git a/src/org/atriasoft/ewol/resource/font/FontMode.java b/src/org/atriasoft/ewol/resource/font/FontMode.java new file mode 100644 index 0000000..194de03 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/font/FontMode.java @@ -0,0 +1,30 @@ +package org.atriasoft.ewol.resource.font; + +public enum FontMode { + Regular(0), + Italic(1), + Bold(2), + BoldItalic(3); + + public static FontMode get(final int newValue) { + switch (newValue) { + case 1: + return Italic; + case 2: + return Bold; + case 3: + return BoldItalic; + } + return Regular; + } + + private final int value; + + FontMode(final int newValue) { + this.value = newValue; + } + + public int getValue() { + return this.value; + } +} diff --git a/src/org/atriasoft/ewol/resource/font/GlyphProperty.java b/src/org/atriasoft/ewol/resource/font/GlyphProperty.java index 12f9d2e..4283b7b 100644 --- a/src/org/atriasoft/ewol/resource/font/GlyphProperty.java +++ b/src/org/atriasoft/ewol/resource/font/GlyphProperty.java @@ -3,101 +3,95 @@ * @copyright 2011, Edouard DUPIN, all right reserved * @license MPL v2.0 (see license file) */ -#pragma once +package org.atriasoft.ewol.resource.font; -#include +import java.util.ArrayList; +import java.util.List; -namespace ewol { - /* - | | | | - | | | | - | | | | - Y | | | | - ^ |------------| |------------| - | - this.advance.y:/. | - | | - | | - this.sizeTex.x/. | | |------------| |------------| - | | | | | | | - | | | | | | | - | | | | | | | - | | | | | | | - | | | | A | | G | - | | | | | | | - | | | | | | | - | | | | | | | - | | | | | | | - \. | | |------------| |------------| - /-. | | - \-. \. | - this.bearing.y | - |____*________________________*____________>> X - - - <-----------------------. : this.advance.x - - <-----------. : this.sizeTexture.x - - <--. : this.bearing.x - - */ +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector2i; + +/* + | | | | + | | | | + | | | | + Y | | | | + ^ |------------| |------------| + | + advance.y:/. | + | | + | | + sizeTex.x/. | | |------------| |------------| + | | | | | | | + | | | | | | | + | | | | | | | + | | | | | | | + | | | | A | | G | + | | | | | | | + | | | | | | | + | | | | | | | + | | | | | | | + \. | | |------------| |------------| + /-. | | + \-. \. | + bearing.y | + |____*________________________*____________>> X + + + <-----------------------. : advance.x + + <-----------. : sizeTexture.x + + <--. : bearing.x + +*/ +/** + * @not_in_doc + */ +public class GlyphProperty { + public Character UVal = 0; //!< Unicode value + public boolean exist = true; + public int glyphIndex = 0; //!< Glyph index in the system + public Vector2i sizeTexture = new Vector2i(10, 10); //!< size of the element to display + public Vector2i bearing = new Vector2i(2, 2); //!< offset to display the data (can be negatif id the texture sise is bigger than the theoric places in the string) + public Vector2i advance = new Vector2i(10, 10); //!< space use in the display for this specific char + public Vector2f texturePosStart = new Vector2f(0, 0); //!< Texture normalized position (START) + public Vector2f texturePosSize = new Vector2f(0, 0); //!< Texture normalized position (SIZE) + private final List kerning = new ArrayList<>(); //!< kerning values of link of all elements + + public GlyphProperty() { + + } + /** - * @not_in_doc + * @brief get the status of the char, if it exist or not in the FONT + * @return true if the char is availlable, false otherwise */ - class GlyphProperty { - public: - Character this.UVal; //!< Unicode value - public: - boolean this.exist; - public: - int this.glyphIndex; //!< Glyph index in the system - Vector2i this.sizeTexture; //!< size of the element to display - Vector2i this.bearing; //!< offset to display the data (can be negatif id the texture sise is bigger than the theoric places in the string) - Vector2i this.advance; //!< space use in the display for this specific char - Vector2f this.texturePosStart; //!< Texture normalized position (START) - Vector2f this.texturePosSize; //!< Texture normalized position (SIZE) - private: - List this.kerning; //!< kerning values of link of all elements - public: - GlyphProperty() : - this.UVal(0), - this.exist(true), - this.glyphIndex(0), - this.sizeTexture(10,10), - this.bearing(2,2), - this.advance(10,10), - this.texturePosStart(0,0), - this.texturePosSize(0,0) { - - }; - float kerningGet( Character _charcode) { - for(int iii=0; iii iterator = this.localShortcut.iterator(); + while (iterator.hasNext()) { + if (iterator.next().message.contentEquals(_message) == true) { + iterator.remove(); } } + } /** * @brief Event on a short-cut of this Widget (in case of return false, the event on the keyevent will arrive in the function @ref onEventKb). @@ -653,35 +657,33 @@ class Widget extends EwolObject { * @note To prevent some error when you get an event get it if it is down and Up ... ==> like this it could not generate some mistake in the error. */ public boolean onEventShortCut(final KeySpecial _special, Character _unicodeValue, final KeyKeyboard _kbMove, final boolean _isDown) { - if (_unicodeValue >= 'A' && _unicodeValue <= 'Z') { - _unicodeValue += 'a' - 'A'; - } - Log.verbose("check shortcut...." + _special + " " + _unicodeValue + " " + _kbMove + " " + (_isDown ? "DOWN" : "UP") + " nb shortcut:" << this.localShortcut.size()); + _unicodeValue = Character.toLowerCase(_unicodeValue); + Log.verbose("check shortcut...." + _special + " " + _unicodeValue + " " + _kbMove + " " + (_isDown ? "DOWN" : "UP") + " nb shortcut:" + this.localShortcut.size()); // Remove the up event of the shortcut... if (_isDown == false) { for (int iii = this.localShortcut.size() - 1; iii >= 0; iii--) { - if (this.localShortcut[iii].isActive == false) { + if (this.localShortcut.get(iii).isActive == false) { continue; } - if ((this.localShortcut[iii].keyboardMoveValue == KeyKeyboard::unknow && this.localShortcut[iii].unicodeValue == _unicodeValue) - || (this.localShortcut[iii].keyboardMoveValue == _kbMove && this.localShortcut[iii].unicodeValue == 0)) { + if ((this.localShortcut.get(iii).keyboardMoveValue == KeyKeyboard.unknow && this.localShortcut.get(iii).unicodeValue == _unicodeValue) + || (this.localShortcut.get(iii).keyboardMoveValue == _kbMove && this.localShortcut.get(iii).unicodeValue == 0)) { // In this case we grap the event in case of an error can occured ... - this.localShortcut[iii].isActive = false; + this.localShortcut.get(iii).isActive = false; Log.verbose("detect up of a shortcut"); return true; } } } - //Log.info("Try to find generic shortcut ..."); + //Log.info("Try to indexOf generic shortcut ..."); for (int iii = this.localShortcut.size() - 1; iii >= 0; iii--) { - if (this.localShortcut[iii].specialKey.getShift() == _special.getShift() && this.localShortcut[iii].specialKey.getCtrl() == _special.getCtrl() - && this.localShortcut[iii].specialKey.getAlt() == _special.getAlt() && this.localShortcut[iii].specialKey.getMeta() == _special.getMeta() - && ((this.localShortcut[iii].keyboardMoveValue == KeyKeyboard::unknow && this.localShortcut[iii].unicodeValue == _unicodeValue) - || (this.localShortcut[iii].keyboardMoveValue == _kbMove && this.localShortcut[iii].unicodeValue == 0))) { + if (this.localShortcut.get(iii).specialKey.getShift() == _special.getShift() && this.localShortcut.get(iii).specialKey.getCtrl() == _special.getCtrl() + && this.localShortcut.get(iii).specialKey.getAlt() == _special.getAlt() && this.localShortcut.get(iii).specialKey.getMeta() == _special.getMeta() + && ((this.localShortcut.get(iii).keyboardMoveValue == KeyKeyboard.unknow && this.localShortcut.get(iii).unicodeValue == _unicodeValue) + || (this.localShortcut.get(iii).keyboardMoveValue == _kbMove && this.localShortcut.get(iii).unicodeValue == 0))) { if (_isDown == true) { - this.localShortcut[iii].isActive = true; - Log.verbose("Generate shortCut: " + this.localShortcut[iii].message); - this.signalShortcut.emit(this.localShortcut[iii].message); + this.localShortcut.get(iii).isActive = true; + Log.verbose("Generate shortCut: " + this.localShortcut.get(iii).message); + this.signalShortcut.emit(this.localShortcut.get(iii).message); } return true; } @@ -748,52 +750,52 @@ class Widget extends EwolObject { / (0,0) */ - public void systemDraw( final DrawProperty _displayProp){ + public void systemDraw( final DrawProperty _displayProp){ //Log.info("[" + getId() + "] Draw : [" + propertyName + "] t=" + getObjectType() + " o=" + this.origin + " s=" << this.size << " hide=" << propertyHide); if (this.propertyHide == true){ // widget is hidden ... return; } - final Vector2f displayOrigin = this.origin + this.offset; + final Vector2f displayOrigin = this.origin.addNew(this.offset); // check if the element is displayable in the windows : - if( _displayProp.this.windowsSize.x() < this.origin.x() - || _displayProp.this.windowsSize.y() < this.origin.y() ) { + if( _displayProp.windowsSize.x < this.origin.x + || _displayProp.windowsSize.y < this.origin.y ) { // out of the windows == > nothing to display ... return; } final DrawProperty tmpSize = _displayProp.clone(); tmpSize.limit(this.origin, this.size); - if (tmpSize.this.size.x() <= 0 || tmpSize.this.size.y() <= 0) { + if (tmpSize.size.x <= 0 || tmpSize.size.y <= 0) { return; } - glViewport( (int)tmpSize.this.origin.x(), - (int)tmpSize.this.origin.y(), - (int)tmpSize.this.size.x(), - (int)tmpSize.this.size.y()); + OpenGL.glViewport( (int)tmpSize.origin.x, + (int)tmpSize.origin.y, + (int)tmpSize.size.x, + (int)tmpSize.size.y); // special case, when origin < display origin, we need to cut the display : - final Vector2i downOffset = this.origin - tmpSize.this.origin; - downOffset.setMin(Vector2i(0,0)); + final Vector2i downOffset = new Vector2i((int)(this.origin.x - tmpSize.origin.x), (int)(this.origin.y - tmpSize.origin.y)); + downOffset.setMin(new Vector2i(0,0)); - final mat4 tmpTranslate = etk::matTranslate(Vector3fClipInt32(Vector3f(-tmpSize.this.size.x()/2+this.offset.x() + downOffset.x(), - -tmpSize.this.size.y()/2+this.offset.y() + downOffset.y(), + final Matrix4f tmpTranslate = etk::matTranslate(Vector3fClipInt32(new Vector3f(-tmpSize.size.x/2+this.offset.x + downOffset.x, + -tmpSize.size.y/2+this.offset.y + downOffset.y, -1.0f))); - final mat4 tmpScale = etk::matScale(Vector3f(this.zoom, this.zoom, 1.0f)); - final mat4 tmpProjection = etk::matOrtho((int)(-tmpSize.this.size.x())>>1, - (int)( tmpSize.this.size.x())>>1, - (int)(-tmpSize.this.size.y())>>1, - (int)( tmpSize.this.size.y())>>1, + final Matrix4f tmpScale = etk::matScale(Vector3f(this.zoom, this.zoom, 1.0f)); + final Matrix4f tmpProjection = etk::matOrtho((int)(-tmpSize.this.size.x)>>1, + (int)( tmpSize.this.size.x)>>1, + (int)(-tmpSize.this.size.y)>>1, + (int)( tmpSize.this.size.y)>>1, (int)(-1), (int)( 1)); - mat4 tmpMat = tmpProjection * tmpScale * tmpTranslate; + Matrix4f tmpMat = tmpProjection * tmpScale * tmpTranslate; - gale::openGL::push(); + OpenGL.push(); // set internal matrix system : - gale::openGL::setMatrix(tmpMat); + OpenGL.setMatrix(tmpMat); //long ___startTime = ewol::getTime(); onDraw(); - gale::openGL::pop(); + OpenGL.pop(); return; } @@ -815,12 +817,12 @@ class Widget extends EwolObject { * @note : the generation of the offset is due to the fact the cursor position is forced at the center of the widget. * @note This done nothing in "Finger" or "Stylet" mode. */ -public void grabCursor() -if (this.grabCursor == false) { - getContext().inputEventGrabPointer(ememory::dynamicPointerCast(sharedFromThis())); - this.grabCursor = true; -} -} + public void grabCursor() { + if (this.grabCursor == false) { + getContext().inputEventGrabPointer(this); + this.grabCursor = true; + } + } /** * @brief Un-Grab the cursor (default mode cursor offset) @@ -840,17 +842,17 @@ if (this.grabCursor == false) { return this.grabCursor; } - private final Cursor cursorDisplay = Cursor.arrow; + private Cursor cursorDisplay = Cursor.arrow; /** - * @brief set the cursor display type. - * @param[in] _newCursor selected new cursor. - */ - public void setCursor(enum gale::context::cursor _newCursor) { - Log.debug("Change Cursor in " + _newCursor); - this.cursorDisplay = _newCursor; - getContext().setCursor(this.cursorDisplay); - } + * @brief set the cursor display type. + * @param[in] _newCursor selected new cursor. + */ + public void setCursor(final Cursor _newCursor) { + Log.debug("Change Cursor in " + _newCursor); + this.cursorDisplay = _newCursor; + getContext().setCursor(this.cursorDisplay); + } /** * @brief get the current cursor. @@ -915,47 +917,47 @@ if (this.grabCursor == false) { markToRedraw(); } - protected void onChangePropertyMaxSize() { - final Vector2f pixelMin = this.propertyMinSize.getPixel(); - final Vector2f pixelMax = this.propertyMaxSize.getPixel(); - // check minimum maximum compatibility : - boolean error=false; - if (pixelMin.x()>pixelMax.x()) { - error=true; - } - if (pixelMin.y()>pixelMax.y()) { - error=true; - } - if (error == true) { - Log.error("Can not set a 'min size' > 'max size' reset to maximum ..."); - this.propertyMaxSize.setDirect(gale::Dimension(Vector2f(ULTIMATE_MAX_SIZE,ULTIMATE_MAX_SIZE),gale::distance::pixel)); - } - requestUpdateSize(); - } + protected void onChangePropertyMaxSize() { + final Vector2f pixelMin = this.propertyMinSize.getPixel(); + final Vector2f pixelMax = this.propertyMaxSize.getPixel(); + // check minimum maximum compatibility : + boolean error = false; + if (pixelMin.x > pixelMax.x) { + error = true; + } + if (pixelMin.y > pixelMax.y) { + error = true; + } + if (error == true) { + Log.error("Can not set a 'min size' > 'max size' reset to maximum ..."); + this.propertyMaxSize = new Dimension(new Vector2f(999999, 999999), Distance.PIXEL); + } + requestUpdateSize(); + } - protected void onChangePropertyMinSize() { - final Vector2f pixelMin = this.propertyMinSize.getPixel(); - final Vector2f pixelMax = this.propertyMaxSize.getPixel(); - // check minimum maximum compatibility : - boolean error=false; - if (pixelMin.x()>pixelMax.x()) { - error=true; - } - if (pixelMin.y()>pixelMax.y()) { - error=true; - } - if (error == true) { - Log.error("Can not set a 'min size' > 'max size' set nothing ..."); - this.propertyMinSize.setDirect(gale::Dimension(Vector2f(0,0),gale::distance::pixel)); - } - requestUpdateSize(); - } + protected void onChangePropertyMinSize() { + final Vector2f pixelMin = this.propertyMinSize.getPixel(); + final Vector2f pixelMax = this.propertyMaxSize.getPixel(); + // check minimum maximum compatibility : + boolean error = false; + if (pixelMin.x > pixelMax.x) { + error = true; + } + if (pixelMin.y > pixelMax.y) { + error = true; + } + if (error == true) { + Log.error("Can not set a 'min size' > 'max size' set nothing ..."); + this.propertyMinSize = new Dimension(new Vector2f(0, 0), Distance.PIXEL); + } + requestUpdateSize(); + } public void drawWidgetTree(final int _level) { - String space; + String space = ""; for (int iii = 0; iii < _level; ++iii) { space += " "; } - Log.print(space + "[" + getId() + "] name='" + propertyName + "' type=" + getObjectType() + " o=" + this.origin << " s=" << this.size << " hide=" << this.propertyHide); + Log.print(space + "[" + getId() + "] name='" + this.name + "' type=" + getClass().getCanonicalName() + " o=" + this.origin + " s=" + this.size + " hide=" + this.propertyHide); } -};}; \ No newline at end of file +} diff --git a/src/org/atriasoft/ewol/widget/WidgetManager.java b/src/org/atriasoft/ewol/widget/WidgetManager.java index fc914d5..5f91a05 100644 --- a/src/org/atriasoft/ewol/widget/WidgetManager.java +++ b/src/org/atriasoft/ewol/widget/WidgetManager.java @@ -135,7 +135,7 @@ public class WidgetManager { * @brief Get the current Focused widget. * @return The pointer on the current focused element. */ - public public Widget focusGet() { + public Widget focusGet() { return this.focusWidgetCurrent.get(); } @@ -160,11 +160,11 @@ public class WidgetManager { focusWidgetCurrent.rmFocus(); focusWidgetCurrent = null; } - if (_newWidget.propertyCanFocus.get() == false) { + if (_newWidget.propertyCanFocus == false) { Log.debug("Widget can not have focus, id=" + _newWidget.getId()); return; } - this.focusWidgetCurrent = _newWidget; + this.focusWidgetCurrent = new WeakReference<>(_newWidget); if (_newWidget != null) { Log.debug("Set focus on WidgetID=" + _newWidget.getId()); _newWidget.setFocus(); @@ -176,7 +176,7 @@ public class WidgetManager { */ public void focusRelease() { final Widget focusWidgetDefault = this.focusWidgetDefault.get(); - final Widget focusWidgetCurrent = this.focusWidgetCurrent.get(); + Widget focusWidgetCurrent = this.focusWidgetCurrent.get(); if (focusWidgetDefault == focusWidgetCurrent) { // nothink to do ... return; @@ -198,24 +198,24 @@ public class WidgetManager { * @param[in] _newWidget Widget that might get the focus (when nothing else). */ public void focusSetDefault(final Widget _newWidget) { - if (_newWidget != null && _newWidget.propertyCanFocus.get() == false) { + if (_newWidget != null && _newWidget.propertyCanFocus == false) { Log.verbose("Widget can not have focus, id=" + _newWidget.getId()); return; } - final EwolWidget focusWidgetDefault = this.focusWidgetDefault.lock(); - final EwolWidget focusWidgetCurrent = this.focusWidgetCurrent.lock(); + final Widget focusWidgetDefault = this.focusWidgetDefault.get(); + final Widget focusWidgetCurrent = this.focusWidgetCurrent.get(); if (focusWidgetDefault == focusWidgetCurrent) { if (focusWidgetCurrent != null) { Log.debug("Rm focus on WidgetID=" + focusWidgetCurrent.getId()); focusWidgetCurrent.rmFocus(); } - this.focusWidgetCurrent = _newWidget; + this.focusWidgetCurrent = new WeakReference<>(_newWidget); if (_newWidget != null) { Log.debug("Set focus on WidgetID=" + _newWidget.getId()); _newWidget.setFocus(); } } - this.focusWidgetDefault = _newWidget; + this.focusWidgetDefault = new WeakReference<>(_newWidget); } /** @@ -253,7 +253,7 @@ public class WidgetManager { * @brief Set a callback when we need redraw the display (need by MacOs) * @param[in] _func function to call */ - private void setCallbackonRedrawNeeded(final Runnable _func) { + public void setCallbackonRedrawNeeded(final Runnable _func) { this.funcRedrawNeeded = _func; } diff --git a/src/org/atriasoft/ewol/widget/WidgetScrolled.cpp b/src/org/atriasoft/ewol/widget/WidgetScrolled.cpp index 70a27f1..f40a965 100644 --- a/src/org/atriasoft/ewol/widget/WidgetScrolled.cpp +++ b/src/org/atriasoft/ewol/widget/WidgetScrolled.cpp @@ -426,10 +426,10 @@ void ewol::widget::WidgetScrolled::systemDraw( ewol::DrawProperty _displayProp) if (this.scroollingMode == scroolModeCenter) { // here we invert the reference of the standard openGl view because the reference in the common display is Top left and not buttom left gale::openGL::setViewPort(this.origin, this.size); - mat4 tmpProjection = etk::matOrtho(-this.size.x()/2, this.size.x()/2, -this.size.y()/2, this.size.y()/2, -1, 1); - mat4 tmpScale = etk::matScale(Vector3f(this.zoom, this.zoom, 1.0) ); - mat4 tmpTranslate = etk::matTranslate(Vector3f(-this.maxSize.x()/2, -this.maxSize.y()/2, -1.0) ); - mat4 tmpMat = tmpProjection * tmpScale * tmpTranslate; + Matrix4f tmpProjection = etk::matOrtho(-this.size.x()/2, this.size.x()/2, -this.size.y()/2, this.size.y()/2, -1, 1); + Matrix4f tmpScale = etk::matScale(Vector3f(this.zoom, this.zoom, 1.0) ); + Matrix4f tmpTranslate = etk::matTranslate(Vector3f(-this.maxSize.x()/2, -this.maxSize.y()/2, -1.0) ); + Matrix4f tmpMat = tmpProjection * tmpScale * tmpTranslate; // set internal matrix system : gale::openGL::setMatrix(tmpMat); // Call the widget drawing methode @@ -437,9 +437,9 @@ void ewol::widget::WidgetScrolled::systemDraw( ewol::DrawProperty _displayProp) } if (this.scroollingMode == scroolModeGame) { // here we invert the reference of the standard openGl view because the reference in the common display is Top left and not buttom left gale::openGL::setViewPort(this.origin, this.size); - mat4 tmpProjection = etk::matOrtho(-this.size.x()/2, this.size.x()/2, -this.size.y()/2, this.size.y()/2, -1, 1); - mat4 tmpTranslate = etk::matTranslate(Vector3f( -this.maxSize.x()/2, -this.maxSize.y()/2, -1.0) ); - mat4 tmpMat = tmpProjection * tmpTranslate; + Matrix4f tmpProjection = etk::matOrtho(-this.size.x()/2, this.size.x()/2, -this.size.y()/2, this.size.y()/2, -1, 1); + Matrix4f tmpTranslate = etk::matTranslate(Vector3f( -this.maxSize.x()/2, -this.maxSize.y()/2, -1.0) ); + Matrix4f tmpMat = tmpProjection * tmpTranslate; // set internal matrix system : gale::openGL::setMatrix(tmpMat); // Call the widget drawing methode diff --git a/src/org/atriasoft/ewol/widget/Windows.cpp b/src/org/atriasoft/ewol/widget/Windows.cpp index c8df178..3e0190c 100644 --- a/src/org/atriasoft/ewol/widget/Windows.cpp +++ b/src/org/atriasoft/ewol/widget/Windows.cpp @@ -96,7 +96,7 @@ void ewol::widget::Windows::sysDraw() { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // clear the matrix system : - mat4 newOne; + Matrix4f newOne; gale::openGL::setBasicMatrix(newOne); ewol::DrawProperty displayProp; @@ -127,7 +127,7 @@ void ewol::widget::Windows::systemDraw( ewol::DrawProperty _displayProp) { long ___startTime0 = ewol::getTime(); #endif // clear the screen with transparency ... - etk::Color colorBg(0.5, 0.5, 0.5, 0.5); + Color colorBg(0.5, 0.5, 0.5, 0.5); if (this.resourceColor != null) { colorBg = this.resourceColor.get(this.colorBg); } diff --git a/src/org/atriasoft/ewol/widget/Windows.java b/src/org/atriasoft/ewol/widget/Windows.java index 6605089..666e3fe 100644 --- a/src/org/atriasoft/ewol/widget/Windows.java +++ b/src/org/atriasoft/ewol/widget/Windows.java @@ -1,85 +1,89 @@ +package org.atriasoft.ewol.widget; + +import java.util.ArrayList; +import java.util.List; + +import org.atriasoft.etk.Uri; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.ewol.DrawProperty; +import org.atriasoft.ewol.object.EwolObject; +import org.atriasoft.ewol.resource.ResourceColorFile; + /** @file * @author Edouard DUPIN * @copyright 2011, Edouard DUPIN, all right reserved * @license MPL v2.0 (see license file) */ -#pragma once -#include -#include -#include -#include -#include - -namespace ewol { - namespace widget { - class Windows; - using Windows = ememory::Ptr; - using WindowsWeak = ememory::WeakPtr; - /** - * @brief Windows basic interface - */ - class Windows : public Widget { - public: - eproperty::Value propertyColorConfiguration; //!< Configuration file of the windows theme - eproperty::Value propertyTitle; //!< Current title of the windows - protected: - ememory::Ptr this.resourceColor; //!< theme color property (name of file in @ref propertyColorConfiguration) - int this.colorBg; //!< Default background color of the windows - protected: - Windows(); - void init() ; - public: - ~Windows(); - // internal event at ewol system: - public: - void sysDraw(); - protected: - Widget this.subWidget; //!< main sub-widget of the Windows. - public: - /** - * @brief Set the main widget of the application. - * @param[in] _widget Widget to set in the windows. - */ - void setSubWidget(Widget _widget); - protected: - List this.popUpWidgetList; //!< List of pop-up displayed - public: - /** - * @brief Add a pop-up on the Windows. - * @param[in] _widget Widget to set on top of the pop-up. - */ - void popUpWidgetPush(Widget _widget); - /** - * @brief Remove the pop-up on top. - */ - void popUpWidgetPop(); - /** - * @brief Get the number of pop-up - * @return Count of pop-up - */ - int popUpCount() { - return this.popUpWidgetList.size(); - } - protected: - void systemDraw( ewol::DrawProperty _displayProp) ; - public: - void onRegenerateDisplay() ; - void onChangeSize() ; - Widget getWidgetAtPos( Vector2f _pos) ; - void requestDestroyFromChild( EwolObject _child) ; - EwolObject getSubObjectNamed( String _objectName) ; - void drawWidgetTree(int _level=0) ; - protected: - /** - * @brief Called when property change: Title - */ - void onChangePropertyTitle(); - /** - * @brief Called when property change: Color configuration file - */ - void onChangePropertyColor(); - }; +/** + * @brief Windows basic interface + */ +public class Windows extends Widget { + + public Uri propertyColorConfiguration; //!< Configuration file of the windows theme + public String propertyTitle; //!< Current title of the windows + protected ResourceColorFile resourceColor; //!< theme color property (name of file in @ref propertyColorConfiguration) + protected int colorBg; //!< Default background color of the windows + protected List popUpWidgetList = new ArrayList(); + + // internal event at ewol system: + + protected Widget subWidget; + + protected Windows(); + + @Override + public void drawWidgetTree(int _level); //!< List of pop-up displayed + + @Override + public EwolObject getSubObjectNamed(String _objectName); + + public Widget getWidgetAtPos(Vector2f _pos); + + /** + * @brief Called when property change: Color configuration file + */ + protected void onChangePropertyColor(); + + /** + * @brief Called when property change: Title + */ + protected void onChangePropertyTitle(); + + @Override + public void onChangeSize(); + + @Override + public void onRegenerateDisplay(); + + /** + * @brief Get the number of pop-up + * @return Count of pop-up + */ + public int popUpCount() { + return this.popUpWidgetList.size(); } + + /** + * @brief Remove the pop-up on top. + */ + public void popUpWidgetPop(); + + /** + * @brief Add a pop-up on the Windows. + * @param[in] _widget Widget to set on top of the pop-up. + */ + public void popUpWidgetPush(Widget _widget); + + public void requestDestroyFromChild(EwolObject _child); //!< main sub-widget of the Windows. + + /** + * @brief Set the main widget of the application. + * @param[in] _widget Widget to set in the windows. + */ + public void setSubWidget(Widget _widget); + + public void sysDraw(); + + protected void systemDraw(DrawProperty _displayProp); } -