Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from stissing/master
Added a lens effect
- Loading branch information
Showing
7 changed files
with
195 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
#include <gui/common/Lens.hpp> | ||
#include <touchgfx/hal/HAL.hpp> | ||
#include <math.h> | ||
#include <BitmapDatabase.hpp> | ||
|
||
Lens::Lens() | ||
{ | ||
// calculate the distortion of the lens | ||
// derivations of the formula can be found online, for instance in the demo effects collection at | ||
// http://demo-effects.cvs.sourceforge.net/viewvc/demo-effects/demo-effects/LENS/lens.c?view=markup | ||
for (int y = 0; y < lensRadius; y++) { | ||
for (int x = 0; x < lensRadius; x++) { | ||
int ix, iy, offset; | ||
if ((x * x + y * y) < (lensRadius * lensRadius)) | ||
{ | ||
float shift = lensZoom/sqrt((float)lensZoom*lensZoom - (x*x + y*y - lensRadius*lensRadius)); | ||
ix = (int)(x * shift - x); | ||
iy = (int)(y * shift - y); | ||
} | ||
else | ||
{ | ||
ix = 0; | ||
iy = 0; | ||
} | ||
offset = (iy * touchgfx::HAL::DISPLAY_WIDTH + ix); | ||
lens[lensRadius - y][lensRadius - x] = -offset; | ||
lens[lensRadius + y][lensRadius + x] = offset; | ||
offset = (-iy * touchgfx::HAL::DISPLAY_WIDTH + ix); | ||
lens[lensRadius + y][lensRadius - x] = -offset; | ||
lens[lensRadius - y][lensRadius + x] = offset; | ||
} | ||
} | ||
setWidth(lensWidth); | ||
setHeight(lensWidth); | ||
|
||
lensImage.setBitmap(touchgfx::Bitmap(BITMAP_LENS_IMAGE_ID)); | ||
} | ||
|
||
touchgfx::Rect Lens::getSolidRect() const | ||
{ | ||
return touchgfx::Rect(); | ||
} | ||
|
||
void Lens::draw(const touchgfx::Rect& invalidatedArea) const | ||
{ | ||
uint16_t *fb = touchgfx::HAL::getInstance()->lockFrameBuffer(); | ||
|
||
touchgfx::Rect abs(0,0,getWidth(),getHeight()); | ||
translateRectToAbsolute(abs); | ||
|
||
// since we both read and write the frame buffer, we split the loops in to four sections/quadrants | ||
// and run through them left to right or right to left, top to bottom or bottom to top, | ||
int16_t middleX = getWidth()/2; | ||
int16_t middleY = getHeight()/2; | ||
|
||
for(int y = invalidatedArea.y; y < invalidatedArea.bottom() && y <= middleY; y++) | ||
{ | ||
for(int x = invalidatedArea.x; x < invalidatedArea.right() && x <= middleX; x++) | ||
{ | ||
apply(fb, abs.x, abs.y, x, y); | ||
} | ||
|
||
for(int x = invalidatedArea.right()-1; x > middleX && x >= invalidatedArea.x; x--) | ||
{ | ||
apply(fb, abs.x, abs.y, x, y); | ||
} | ||
} | ||
|
||
for(int y = invalidatedArea.bottom()-1; y > middleY && y >= invalidatedArea.y; y--) | ||
{ | ||
for(int x = invalidatedArea.x; x < invalidatedArea.right() && x <= middleX; x++) | ||
{ | ||
apply(fb, abs.x, abs.y, x, y); | ||
} | ||
|
||
for(int x = invalidatedArea.right()-1; x > middleX && x >= invalidatedArea.x; x--) | ||
{ | ||
apply(fb, abs.x, abs.y, x, y); | ||
} | ||
} | ||
|
||
touchgfx::HAL::getInstance()->unlockFrameBuffer(); | ||
|
||
touchgfx::Rect dirtyBitmapArea = touchgfx::Bitmap(lensImage.getBitmap()).getRect() & invalidatedArea; | ||
touchgfx::HAL::lcd().drawPartialBitmap(touchgfx::Bitmap(lensImage.getBitmap()), abs.x, abs.y, dirtyBitmapArea, 255); | ||
} | ||
|
||
void Lens::apply(uint16_t* fb, int absx, int absy, int x, int y) const | ||
{ | ||
int16_t lensOffset = lens[y][x]; | ||
uint32_t fbOffset = x+absx + (y+absy) * touchgfx::HAL::DISPLAY_WIDTH; | ||
if((int32_t)fbOffset + lensOffset < 0) | ||
{ | ||
fb[fbOffset] = fb[fbOffset + lensOffset + touchgfx::HAL::DISPLAY_HEIGHT*touchgfx::HAL::DISPLAY_WIDTH]; | ||
} | ||
else if((int32_t)fbOffset + lensOffset > touchgfx::HAL::DISPLAY_HEIGHT*touchgfx::HAL::DISPLAY_WIDTH) | ||
{ | ||
fb[fbOffset] = fb[fbOffset + lensOffset - touchgfx::HAL::DISPLAY_HEIGHT*touchgfx::HAL::DISPLAY_WIDTH]; | ||
} | ||
else | ||
{ | ||
fb[fbOffset] = fb[fbOffset + lensOffset]; | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#ifndef LENS_HPP | ||
#define LENS_HPP | ||
|
||
#include <touchgfx/widgets/Widget.hpp> | ||
#include <touchgfx/hal/Types.hpp> | ||
#include <touchgfx/widgets/Image.hpp> | ||
|
||
/** | ||
* @class Lens | ||
* | ||
* Lens shows a lens like effect on top of the frame buffer | ||
* | ||
* This widget is part of the TouchGFX Open Widget Repository. | ||
* https://github.com/draupnergraphics/touchgfx-open-repository | ||
* | ||
* @note This version of a lens, will not draw it self correctly if solid | ||
* widgets are placed on top of it. This is due to the fact that | ||
* the lens uses data from the frame buffer and the data | ||
* below the lens (and the solid widgets) will not be updated in this case | ||
* | ||
* @sa touchgfx::Widget | ||
*/ | ||
class Lens : public touchgfx::Widget | ||
{ | ||
public: | ||
/** | ||
* @fn Lens::Lens(); | ||
* | ||
* @brief initializes the lens data | ||
*/ | ||
Lens(); | ||
|
||
/** | ||
* @fn virtual touchgfx::Rect Lens::getSolidRect() const; | ||
* | ||
* @brief Report the solid dimensions of this widget. | ||
* As we would like the frame buffer below to be drawn, | ||
* the widget is reported as transparent | ||
* | ||
* @return an empty rectangle. | ||
*/ | ||
virtual touchgfx::Rect getSolidRect() const; | ||
|
||
/** | ||
* @fn virtual void Lens::draw(const touchgfx::Rect& invalidatedArea) const; | ||
* | ||
* @brief read, distort and write the frame buffer contents. | ||
* | ||
* @param invalidatedArea The part of the widget that should be drawn. | ||
*/ | ||
virtual void draw(const touchgfx::Rect& invalidatedArea) const; | ||
private: | ||
void apply(uint16_t* fb, int absx, int absy, int x, int y) const; | ||
|
||
static const uint8_t lensRadius = 100; | ||
static const uint8_t lensWidth = 2*lensRadius; | ||
static const uint8_t lensZoom = 40; | ||
int16_t lens[lensWidth][lensWidth]; //note: move the lens data to flash | ||
touchgfx::Image lensImage; | ||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
Purpose | ||
======== | ||
|
||
![example](screenshots/lens-effect.png "Resulting lens effect") | ||
|
||
The purpose of the Lens is to provide an effect on top of already existing graphics. The lens will distort the contents below it. | ||
|
||
The lens has a radius of 100. This number can be adjusted. | ||
|
||
The lens adds an image of a semi transparent glass on top of the distorted graphics. If the radius of the lens is adjusted, additional image data may be needed for the glass. | ||
|
||
![glass](assets/lens_image.png "Glass") | ||
|
||
Note that the lens is more dependent on the contents of the framebuffer and therefore the order of drawing than more regular widgets. | ||
|
||
TouchGFX Version | ||
================= | ||
|
||
This widget was created and tested using TouchGFX version 4.2.0 | ||
|
||
Functional description | ||
====================== | ||
|
||
Add the lens to a view. | ||
|
||
|
||
|
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.