FLTK simple animation - c++

I can successfully compiled and run the Hello World code.
Now I want to do something like animation.
I first create a rectangle class to implement draw() from Fl::widget
class myRect: public Fl_Widget {
private:
Fl_Color color;
void draw(){
fl_color(color);
fl_rectf(x(),y(),w(),h(),color);
}
public:
myRect(int X,int Y,int W,int H, Fl_Color c) : Fl_Widget(X,Y,W,H),color(c) {}
};
int main (int argc, char ** argv)
{
Fl_Window *window = new Fl_Window (300, 180, "FLTK Test");
vector<myRect*> allRect;
for(int i=0; i<10; ++i){
allRect.push_back(new myRect ((i*10)%100,100,50,50,i%256));
}
window->end();
window->show();
return Fl::run();
}
The code above can run as I expected.
But Now I want to show the rectangles one by one, with some time interval such as 1 second.
Make it just like animation.
I have read the official document but I still have no idead about that.
Please give me some information. Thanks !!
Thanks to DejanLekic, I revised my code as below:
#include <iostream>
#include <vector>
#include <FL/Fl.H>
#include <FL/Fl_Widget.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
using namespace std;
class myRect: public Fl_Widget {
private:
Fl_Color color;
void draw(){
fl_color(color);
fl_rectf(x(),y(),w(),h(),color);
}
public:
myRect(int X,int Y,int W,int H, Fl_Color c)
:Fl_Widget(X,Y,W,H),color(c) {}
};
vector<myRect*> allRect;
void winUpdate(void *data)
{
static unsigned i = 0;
Fl_Double_Window *o = (Fl_Double_Window*)data;
if(i < allRect.size()){
o->add(allRect[i]);
if(i>=3) o->remove(allRect[i-3]);
o->redraw();
Fl::add_timeout(0.5,winUpdate,data);
++i;
}
}
int main (int argc, char ** argv)
{
for(int i=0; i<8; ++i){
allRect.push_back(new myRect(i*30,i*30,50,50,i));
}
Fl_Double_Window *window = new Fl_Double_Window (400, 400, "FLTK Test");
Fl::add_timeout(2,winUpdate,window);
window->end();
Fl::visual(FL_DOUBLE|FL_INDEX);
window->show();
return Fl::run();
}
It seems to run well, but I'm not sure whether it is correct or not.
If there is any problem, please let me know. Thanks.

Cory, you are on the right path.
Here is a complete example how to do a simple 2D animation using FLTK's drawing capabilities: http://seriss.com/people/erco/fltk/#AnimateDrawing
Similar thing using OpenGL: http://seriss.com/people/erco/fltk/#OpenGlInterp
The key, in both examples is in the Fl::add_timeout(0.25, Timer_CB, (void*)this); line, and in the Timer_CB() static (callback) method. Both examples are nice and easy and I am confident you will understand them instantly.

Related

How can I write a (very) basic custom QAbstractTextDocumentLayout subclass?

I'm trying to create a simple notepad-style Qt application. Since I think I might want a lot of control over exactly how text is rendered, I'm trying to write a custom QAbstractTextDocumentLayout class. The code below compiles and runs, but the text area is blank, no matter how much I type. The debug statements in my draw() function correctly show the entered text, so I know my input is in some form making it all the way to the draw() function, but it's not being rendered.
I just want to tweak this in a minimal way so I can at least see some text being rendered, even if the implementation is incomplete. I also haven't been able to find any documentation whatsoever on writing custom QAbstractTextDocumentLayout, so if anyone had a reference I'd also appreciate that.
main.cpp
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QTextEdit>
#include <QKeyEvent>
#include "./DocumentLayout.cpp"
class MainContent : public QWidget
{
Q_OBJECT
QTextEdit textEdit;
DocumentLayout layout;
public:
MainContent() : textEdit(this), layout(textEdit.document())
{
int innerPadding = 20;
textEdit.document()->setDocumentMargin(innerPadding);
int textColor = 0xD8DEE9;
int backgroundColor = 0x2E3440;
int selectionColor = 0x2E3440;
int selectionBackgroundColor = 0x81A1C1;
QPalette palette = textEdit.palette();
palette.setColor(QPalette::Base, QColor(backgroundColor));
palette.setColor(QPalette::Text, QColor(textColor));
palette.setColor(QPalette::Highlight, QColor(selectionBackgroundColor));
palette.setColor(QPalette::HighlightedText, QColor(selectionColor));
textEdit.setPalette(palette);
textEdit.setFrameStyle(QFrame::NoFrame);
textEdit.document()->setDocumentLayout(&layout);
};
void resizeEvent(QResizeEvent *event)
{
textEdit.setGeometry(0, 0, this->width(), this->height());
}
void keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_W && event->modifiers() == Qt::ControlModifier)
{
qApp->quit();
}
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow window;
window.setWindowTitle("Hello, world!");
window.resize(400, 500);
MainContent content;
window.setCentralWidget(&content);
window.show();
return app.exec();
}
#include "main.moc"
DocumentLayout.cpp
#include <QAbstractTextDocumentLayout>
#include <QPainter>
#include <QTextBlock>
#include <QDebug>
class DocumentLayout : public QAbstractTextDocumentLayout
{
public:
DocumentLayout(QTextDocument *document) : QAbstractTextDocumentLayout(document)
{
}
void draw(QPainter *painter, const PaintContext &context)
{
QTextDocument *document = this->document();
QTextBlock block = document->begin();
QPointF position(20, 20);
painter->setPen(context.palette.color(QPalette::Text));
QTextLayout *layout = block.layout();
layout->draw(painter, position);
position.ry() += layout->boundingRect().height();
qDebug() << "drew" << block.text() << "at" << position;
}
int hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
{
return 0;
}
int pageCount() const
{
return 1;
}
QSizeF documentSize() const
{
return QSizeF(400, 800);
}
QRectF frameBoundingRect(QTextFrame *frame) const
{
return QRectF(0, 0, 400, 800);
}
QRectF blockBoundingRect(const QTextBlock &block) const
{
return QRectF(0, 0, 400, 800);
}
void documentChanged(int from, int charsRemoved, int charsAdded)
{
}
};

Need help refactoring class into separate header and cpp files

Could anyone break the MyWindow class out into separate MyWindow.h and MyWindow.cpp files from this excellent FLTK example?
I have tried all afternoon. I am stuck on the (void*)this part in the Fl::add_timeout method. I am sure I have other things wrong as well.
I would like to see how the recursion is best handled. Do you MyWindow::RenderImage_CB or leave it as RenderImage_CB?
Adding the code here for convenience.
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
#include <stdio.h>
#include <time.h>
#define XSIZE 500
#define YSIZE 500
#define UPDATE_RATE 0.05 // update rate in seconds
// Demonstrate how to display a pixel buffer in FLTK
// WINDOW CLASS TO HANDLE DRAWING IMAGE
class MyWindow : public Fl_Double_Window {
unsigned char pixbuf[YSIZE][XSIZE][3]; // image buffer
// FLTK DRAW METHOD
void draw() {
fl_draw_image((const uchar*)&pixbuf, 0, 0, XSIZE, YSIZE, 3, XSIZE*3);
}
// TIMER CALLBACK: CALLED TO UPDATE THE DRAWING
static void RenderImage_CB(void *userdata) {
MyWindow *win = (MyWindow*)userdata;
win->RenderImage();
Fl::repeat_timeout(UPDATE_RATE, RenderImage_CB, userdata);
}
public:
// CTOR
MyWindow(int w, int h, const char *name=0) : Fl_Double_Window(w,h,name) {
end();
RenderImage(); // show first drawing
// Start timer updating
Fl::add_timeout(UPDATE_RATE, RenderImage_CB, (void*)this);
}
// PLOT A PIXEL AS AN RGB COLOR INTO THE PIXEL BUFFER
void PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b) {
pixbuf[y][x][0] = r;
pixbuf[y][x][1] = g;
pixbuf[y][x][2] = b;
}
// MAKE A NEW PICTURE IN THE PIXEL BUFFER, SCHEDULE FLTK TO DRAW IT
void RenderImage() {
static unsigned char drawcount = 0;
for ( int x=0; x<XSIZE; x++ )
for ( int y=0; y<YSIZE; y++ )
PlotPixel(x, y, x+drawcount, y+drawcount, x+y+drawcount);
++drawcount;
redraw();
}
};
int main(int argc, char**argv) {
Fl::visual(FL_RGB); // prevents dithering on some systems
MyWindow *win = new MyWindow(XSIZE, YSIZE);
win->show();
return(Fl::run());
}
Separated this way gives a compiler error:
main.cpp
#include "MyWindow.h"
int main(int argc, char**argv) {
Fl::visual(FL_RGB); // prevents dithering on some systems
MyWindow *win = new MyWindow(XSIZE, YSIZE);
win->show();
return(Fl::run());
}
MyWindow.h
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
#include <stdio.h>
#include <time.h>
#define XSIZE 500
#define YSIZE 500
#define UPDATE_RATE 0.05 // update rate in seconds
// WINDOW CLASS TO HANDLE DRAWING IMAGE
class MyWindow : public Fl_Double_Window {
unsigned char pixbuf[YSIZE][XSIZE][3]; // image buffer
// FLTK DRAW METHOD
void draw();
// TIMER CALLBACK: CALLED TO UPDATE THE DRAWING
void RenderImage_CB(void *userdata);
public:
// CTOR
MyWindow(int w, int h, const char *name=0) : Fl_Double_Window(w,h,name){};
// PLOT A PIXEL AS AN RGB COLOR INTO THE PIXEL BUFFER
void PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b);
// MAKE A NEW PICTURE IN THE PIXEL BUFFER, SCHEDULE FLTK TO DRAW IT
void RenderImage();
};
MyWindow.cpp
#include "MyWindow.h"
void MyWindow::draw() {
fl_draw_image((const uchar*)&pixbuf, 0, 0, XSIZE, YSIZE, 3, XSIZE*3);
}
void MyWindow::RenderImage_CB(void *userdata) {
MyWindow *win = (MyWindow*)userdata;
win->RenderImage();
Fl::repeat_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, userdata);
}
MyWindow::MyWindow(int w, int h, const char *name) : Fl_Double_Window(w,h,name) {
end();
MyWindow::RenderImage(); // show first drawing
// Start timer updating
Fl::add_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, (void*)this);
}
void MyWindow::PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b) {
pixbuf[y][x][0] = r;
pixbuf[y][x][1] = g;
pixbuf[y][x][2] = b;
}
void MyWindow::RenderImage() {
static unsigned char drawcount = 0;
for ( int x=0; x<XSIZE; x++ )
for ( int y=0; y<YSIZE; y++ )
PlotPixel(x, y, x+drawcount, y+drawcount, x+y+drawcount);
++drawcount;
redraw();
}
Using the above my first error is:
MyWindow.cpp:10:71: error: no matching function for call to 'Fl::repeat_timeout(double, <unresolved overloaded function type>, void*&)'
Fl::repeat_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, userdata);
This compiles and runs:
main.cpp
#include "MyWindow.h"
int main(int argc, char**argv) {
Fl::visual(FL_RGB); // prevents dithering on some systems
MyWindow *win = new MyWindow(XSIZE, YSIZE);
win->show();
return(Fl::run());
}
MyWindow.h
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
#include <stdio.h>
#include <time.h>
#define XSIZE 500
#define YSIZE 500
#define UPDATE_RATE 0.05 // update rate in seconds
// WINDOW CLASS TO HANDLE DRAWING IMAGE
class MyWindow : public Fl_Double_Window {
unsigned char pixbuf[YSIZE][XSIZE][3]; // image buffer
// FLTK DRAW METHOD
void draw();
// TIMER CALLBACK: CALLED TO UPDATE THE DRAWING
static void RenderImage_CB(void *userdata);
public:
// CTOR
MyWindow(int w, int h, const char *name=0);// : Fl_Double_Window(w,h,name){};
// PLOT A PIXEL AS AN RGB COLOR INTO THE PIXEL BUFFER
void PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b);
// MAKE A NEW PICTURE IN THE PIXEL BUFFER, SCHEDULE FLTK TO DRAW IT
void RenderImage();
};
MyWindow.cpp
#include "MyWindow.h"
MyWindow::MyWindow(int w, int h, const char *name) : Fl_Double_Window(w,h,name) {
end();
MyWindow::RenderImage(); // show first drawing
// Start timer updating
Fl::add_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, (void*)this);
}
void MyWindow::draw() {
fl_draw_image((const uchar*)&pixbuf, 0, 0, XSIZE, YSIZE, 3, XSIZE*3);
}
void MyWindow::RenderImage_CB(void *userdata) {
MyWindow *win = (MyWindow*)userdata;
win->RenderImage();
Fl::repeat_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, userdata);
}
void MyWindow::PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b) {
pixbuf[y][x][0] = r;
pixbuf[y][x][1] = g;
pixbuf[y][x][2] = b;
}
void MyWindow::RenderImage() {
static unsigned char drawcount = 0;
for ( int x=0; x<XSIZE; x++ )
for ( int y=0; y<YSIZE; y++ )
PlotPixel(x, y, x+drawcount, y+drawcount, x+y+drawcount);
++drawcount;
redraw();
}

LNK1561 entry point must be defined - SDL

I got a LNK1561 entry point must be defined error i tried somethings my self as stsyem settings to console and it still doesn't work. Here is my code for every class the SDl.h is from the SDL.h donwload page.
main.cpp:
#include <iostream>
#include "MainGame.h"
int main(int argc, char** argv) {
std::cout << "Enter any ket to quit...";
int a;
std::cin >> a;
return 0;
}
MainGame.cpp:
#include "MainGame.h"
MainGame::MainGame()
{
_window = nullptr;
_screenHeight = 1028;
_screenWidth = 768;
}
MainGame::~MainGame()
{
}
void MainGame::run() {
InitSystems();
}
void MainGame::InitSystems() {
SDL_Init(SDL_INIT_EVERYTHING);
_window = SDL_CreateWindow("title", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, 1028, 768, SDL_WINDOW_OPENGL);
}
MainGame.h:
#pragma once
#include <SDL/SDL.h>
class MainGame
{
public:
MainGame();
~MainGame();
void run();
void InitSystems();
private:
SDL_Window* _window;
int _screenWidth;
int _screenHeight;
};
Allt his code is to open an Windowed frame on your computer en open an console with the text Press Any ket to quit... If i remove the SDL.h include and the SDL code it all works if i put the include back and not the SDL code it gives the error again.
Have you tried using MainGame in your main function? Chances that the compiler assumes that it is never used and you do not get the #include <SDL/SDL.h> directive to work. Also, consider changing #include <SDL/SDL.h> to #include "SDL/SDL.h".
Also you might consider using SDL_SetMainReady for the cases that you are not using SDL_Main as the entry point.

C++ SFML 2.2 graphics not rendering

I'm just playing around with C++ SFML stuff and I kinda don't understand why my code isn't working. The thing I want to do is to draw like let's say 5, squares in Window randomly placed around the screen using vector, but I don't understand why it's not working. And it doesn't give any error as well, I can open game like normal, but it's just not rendering.
This is the main game class:
#include "main_game.h"
#include "main_menu.h"
void main_game::Initialize(sf::RenderWindow* window)
{
this->Player = new player();
this->Player->setOrigin(this->Player->getGlobalBounds().width / 2, this->Player->getGlobalBounds().height / 2);
this->TestObject = new testObject();
this->TestObject->Initialize();
this->TestObject->setOrigin(this->TestObject->getGlobalBounds().width / 2, this->TestObject->getGlobalBounds().height / 2);
}
void main_game::Update(sf::RenderWindow* window)
{
this->Player->setPosition(sf::Mouse::getPosition(*window).x, sf::Mouse::getPosition(*window).y);
this->Player->Update();
if (this->Player->CheckCollision(TestObject))
{
this->TestObject->setColor(sf::Color::Red);
}
else
{
this->TestObject->setColor(sf::Color::Cyan);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Escape))
{
coreState.SetState(new main_menu());
}
}
void main_game::Render(sf::RenderWindow* window, std::vector<sf::Sprite> sprites)
{
this->TestObject->Render(*window, sprites);
window->draw(*this->Player);
}
void main_game::Destroy(sf::RenderWindow* window)
{
delete this->Player;
delete this->TestObject;
}
This is the testObject.h class
#pragma once
#include "entity.h"
class testObject : public Entity
{
public:
testObject();
void Initialize();
void Render(sf::RenderWindow &window, std::vector<sf::Sprite> sprites);
void Update();
private:
sf::RenderWindow window;
};
And this is testObject.cpp class
#include "testObject.h"
testObject::testObject()
{
this->Load("testObject.png");
}
void testObject::Initialize()
{
sf::Texture testObjectTexture;
sf::Sprite testObjectSprite;
testObjectTexture.loadFromFile("testObject.png");
testObjectSprite.setTexture(testObjectTexture);
std::vector<sf::Sprite> sprites(5, sf::Sprite(testObjectSprite));
srand(time(0));
for (unsigned int i = 0; i < sprites.size(); i++)
{
sprites[i].setPosition(1 + (rand() % 1024 - 32), rand() % 640 - 32);
}
}
void testObject::Render(sf::RenderWindow &window, std::vector<sf::Sprite> sprites)
{
for (unsigned int i = 0; i < sprites.size(); i++)
{
window.draw(sprites[i]);
}
}
void testObject::Update()
{
Entity::Update();
}
main_game.h:
#pragma once
#include "game_state.h"
#include "player.h"
#include "testObject.h"
class main_game : public tiny_state
{
public:
void Initialize(sf::RenderWindow* window);
void Update(sf::RenderWindow* window);
void Render(sf::RenderWindow* window, std::vector<sf::Sprite> sprites);
void Destroy(sf::RenderWindow* window);
private:
player* Player;
testObject* TestObject;
};
An easy fix to this is simply use an array, or any other data structure that can store by copy rather than store by reference instead of a vector, which stores by reference, to hold the sprites.
The problem is two fold, its not just a scope issue, if you moved the render function into the initialize scope, you will draw your sprite 5 times in the same place, because every element in your vector is pointing to testObjectSprite's memory location (the same place).

how to make parallel events in c++ (specific Qt 4.6)

I have a problem with the execution of multiple functions at once.
Specific , I have two classes (MyRect and space). The Idea is similar to space invaders but I stuck on the beginning. In class MyRect I have defined two rectangles :: body (ship body) and bullet (ship bullet).In the main class space is created ship as MyRect new object with body && bullet rectangles.Also there is definition for keyPress events.
Problem is that when I fire bullet , everythig stops excetp moving of bullet and until loop MyRect::fireBullet(int x, int y) is done , i cant move ship during this event.Obviously, I do some fundamental mistakes so if someone is willing to clarify this.
here is sample code ::
MyRect.h
#include <QWidget>
#include <QRect>
#include <QMainWindow>
#include <QPainter>
#include <QLabel>
#include <ctime>
#include <QtGui/QMainWindow>
class space;
class MyRect : public QObject {
Q_OBJECT
public:
MyRect(int in_x, int in_y, int in_w, int in_h, QWidget* parent)
{
itsx = in_x;
itsy = in_y;
itsw = in_w;
itsh = in_h;
body = new QRect(itsx, itsy, itsw, itsh);
bullet = new QRect(itsx+41, itsy-15, itsw/8, itsh/2);
itsParent = parent;
}
~MyRect() {}
void move(int x ,int y);
public slots:
void fireBullet(int x, int y);
private:
int itsx;
int itsy;
int itsw;
int itsh;
QWidget* itsParent;
QRect* body;
QRect* bullet;
friend class space;
};
MyRect.cpp
#include "MyRect.h"
void wait( float seconds )
{
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
}
void MyRect::move(int x, int y)
{
body->moveTo(x,y);
bullet->moveTo(x+35, y-15);
}
void MyRect::fireBullet(int x, int y)
{
y = y-15;
for(int i=0 ; i<200 ; i++)
{
bullet->moveTo(x+41, y--);
itsParent->repaint();
wait(0.001);
}
}
space.h
#include <QKeyEvent>
#include <QMouseEvent>
#include "MyRect.h"
class space : public QMainWindow
{
Q_OBJECT
public:
space(QWidget *parent = 0);
~space(){}
protected:
void paintEvent(QPaintEvent *event);
void keyPressEvent(QKeyEvent* event);
private:
private:
int x;
int y;
int w;
int h;
MyRect* ship;
signals:
void fireBullet(int x, int y);
};
space.cpp
#include "space.h"
#include <QApplication>
space::space(QWidget *parent)
: QMainWindow(parent)
{
x = 170;
y = 250;
w = 90;
h = 25;
ship = new MyRect(x,y,w,h, this);
connect(this, SIGNAL(fireBullet(int,int)), ship, SLOT(fireBullet(int,int)) );
}
void space::paintEvent(QPaintEvent *event)
{
QPen pen(Qt::black, 2, Qt::SolidLine);
QColor hourColor(0, 255, 0);
QPainter painter(this);
painter.setBrush(hourColor);
painter.setPen(pen);
painter.drawRect( *(ship->body) );
painter.drawRect( *(ship->bullet) );
}
void space::keyPressEvent(QKeyEvent* event)
{
switch(event->key()) {
case Qt::Key_D :
{
x = x+10;
ship->move(x,y);
this->update();
break;
}
case Qt::Key_A :
{
x = x-10;
ship->move(x,y);
this->update();
break;
}
case Qt::Key_M :
{
emit fireBullet(x,y);
break;
}
}
}
main.cpp
#include "space.h"
#include <QDesktopWidget>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
space window;
window.setWindowTitle("Lines");
window.resize(500,500);
window.show();
return app.exec();
}
Thanks for the answers.
You have an architectural problem. What you are doing is moving the bullet in a loop in its fireBullet method. While that loop is running, the rest of the program isn't, since a single thread can only be doing one thing at a time.
The solution is to refactor your code so that everything on the screen gets updated by one frame-worth of animation every time you call some kind of update method. Basically, you just need to retain enough state, where you are, how fast you are moving, how far you can go before disappearing, so that you can move by the desired amount each frame.
Another thing that you would change is to have the keyPressEvent update the state of the spaceship to know which way it should be moving, so that it can move on its regular paintEvent. For that you can use a QTimer