1 /****************************************************************************
2 * MeshLab o o *
3 * A versatile mesh processing toolbox o o *
4 * _ O _ *
5 * Copyright(C) 2005 \/)\/ *
6 * Visual Computing Lab /\/| *
7 * ISTI - Italian National Research Council | *
8 * \ *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
20 * for more details. *
21 * *
22 ****************************************************************************/
23
24 #ifndef PAINTBOX_H_
25 #define PAINTBOX_H_
26
27 #include <vector>
28
29 #include <vcg/math/base.h>
30 #include <GL/glew.h>
31 #include "ui_paintbox.h"
32
33 /**
34 * The types of tools MUST be defined in the same order as
35 * the buttons inside the tabs.
36 */
37 typedef enum {COLOR_PAINT, COLOR_FILL, COLOR_GRADIENT, COLOR_SMOOTH, COLOR_CLONE, COLOR_PICK, COLOR_NOISE,
38 MESH_SELECT, MESH_SMOOTH, MESH_PUSH, MESH_PULL} ToolType;
39
40
41 /**
42 * Mnemonics to address the tabs numbers. These MUST be declared
43 * in the same order as the actual tabs
44 */
45 enum {COLOR_TAB, MESH_TAB, PREFERENCES_TAB};
46
47 //TODO add mnemonics for all settings
48
49 typedef enum {CIRCLE, SQUARE, PIXMAP} Brush;
50
51 /**
52 * This class manages the user interface and is concerned
53 * with emitting appropriate signals. It should not be
54 * concerned with the application logic in any way.
55 */
56 class Paintbox : public QWidget, private Ui::Paintbox
57 {
58 Q_OBJECT
59
60 private:
61 ToolType active; //the active tool for each page
62 // QUndoStack * stack;
63
64 QHash<QWidget *, QUndoStack *> stack_association;
65
66 QUndoGroup * stacks;
67
68 ToolType previous_type;
69
70 QGraphicsPixmapItem * item;
71 bool pixmap_available;
72 QPoint item_delta;
73
74 public:
75 Paintbox(QWidget * parent = 0, Qt::WindowFlags flags = 0);
76
pushCommand(QUndoCommand * c)77 inline void pushCommand(QUndoCommand* c) {stacks->activeStack()->push(c);}
78
getForegroundColor()79 inline QColor getForegroundColor() {return foreground_frame->getColor();}
getBackgroundColor()80 inline QColor getBackgroundColor() {return background_frame->getColor();}
81
getCurrentType()82 inline ToolType getCurrentType() {return active;}
getSize()83 inline int getSize() {return size_slider->value();}
getRadius()84 inline double getRadius() {return (double)getSize() / 100.0;}
getSizeUnit()85 inline int getSizeUnit() {return pen_unit->currentIndex();}
getBrush()86 inline Brush getBrush() {return (Brush)brush_box->currentIndex();}
getSearchMode()87 inline int getSearchMode() { return search_mode->currentIndex() + 1; }
getOpacity()88 inline int getOpacity() {return opacity_slider->value();}
getSmoothPercentual()89 inline int getSmoothPercentual() {return percentual_slider->value();}
getHardness()90 inline int getHardness() {return hardness_slider->value();}
getPaintBackFace()91 inline bool getPaintBackFace() {return backface_culling->isChecked();}
getPaintInvisible()92 inline bool getPaintInvisible() {return invisible_painting->isChecked(); }
getGradientType()93 inline int getGradientType() { return gradient_type->currentIndex(); }
getGradientForm()94 inline int getGradientForm() { return gradient_form->currentIndex(); }
getPickMode()95 inline int getPickMode() { return pick_mode->currentIndex(); }
getNoiseSize()96 inline float getNoiseSize() {return noise_slider->value();}
getDisplacement()97 inline int getDisplacement() {return mesh_displacement_slider->value();}
getDirection()98 inline int getDirection() {return mesh_displacement_direction->currentIndex();}
99
100 // pressure
getPressureFrameEnabled()101 inline bool getPressureFrameEnabled() {return pressure_frame->isEnabled();}
enablePressureFrame()102 inline void enablePressureFrame() {pressure_frame->setEnabled(true);}
getPressureDisplacement()103 inline bool getPressureDisplacement() {return displacement_box->isChecked();}
getPressureHardness()104 inline bool getPressureHardness() {return hardness_box->isChecked();}
getPressureSize()105 inline bool getPressureSize() {return size_box->isChecked(); }
getPressureOpacity()106 inline bool getPressureOpacity() {return opacity_box->isChecked();}
107
getUndoStack()108 inline QUndoStack * getUndoStack() {return stacks->activeStack();}
109
110 void setUndoStack(QWidget * parent);
111
112 void setForegroundColor(QColor & c);
113 void setBackgroundColor(QColor & c);
114
115 //Brush preview
116 void refreshBrushPreview();
117
118 //Cloning
getCloneScene()119 inline QGraphicsScene * getCloneScene() {return clone_source_view->scene();}
getClonePixmap()120 inline QGraphicsPixmapItem * getClonePixmap() {return item;}
121 void getPixmapBuffer(GLubyte * & cbuffer, GLfloat* & zbuffer, int & w, int & h);
isNewPixmapAvailable()122 inline bool isNewPixmapAvailable(){return pixmap_available;}
123
124 void setClonePixmap(QImage & image);
125 // void setPixmapCenter(qreal x, qreal y);
126 QPoint getPixmapDelta();
127 void setPixmapOffset(qreal x, qreal y);
128 void loadClonePixmap();
129 void restorePreviousType();
130
131 signals:
132 void undo();
133 void redo();
134 void typeChange(ToolType t);
135 void brushSettingsChange(int size, int opacity, int hardness);
136
137 public slots:
on_pen_button_toggled(bool checked)138 void on_pen_button_toggled(bool checked) {if(checked) {active = COLOR_PAINT; emit typeChange(active);}}
on_fill_button_toggled(bool checked)139 void on_fill_button_toggled(bool checked) {if(checked) {active = COLOR_FILL;emit typeChange(active);}}
on_gradient_button_toggled(bool checked)140 void on_gradient_button_toggled(bool checked) {if(checked) {active = COLOR_GRADIENT; emit typeChange(active);}}
on_smooth_button_toggled(bool checked)141 void on_smooth_button_toggled(bool checked){if(checked) {active = COLOR_SMOOTH;emit typeChange(active);}}
on_clone_button_toggled(bool checked)142 void on_clone_button_toggled(bool checked){if(checked) {active = COLOR_CLONE; emit typeChange(active);} clone_source_frame->setVisible(checked);}
on_pick_button_toggled(bool checked)143 void on_pick_button_toggled(bool checked){if(checked) {previous_type = active; active = COLOR_PICK; emit typeChange(active);}}
on_mesh_pick_button_toggled(bool checked)144 void on_mesh_pick_button_toggled(bool checked){if(checked) {active = MESH_SELECT; emit typeChange(active);}}
on_mesh_smooth_button_toggled(bool checked)145 void on_mesh_smooth_button_toggled(bool checked){if(checked) {active = MESH_SMOOTH; emit typeChange(active);}}
on_mesh_sculpt_button_toggled(bool checked)146 void on_mesh_sculpt_button_toggled(bool checked){if(checked) {active = MESH_PUSH; emit typeChange(active);}}
on_mesh_add_button_toggled(bool checked)147 void on_mesh_add_button_toggled(bool checked){if(checked) {active = MESH_PULL; emit typeChange(active);}}
on_perlin_button_toggled(bool checked)148 void on_perlin_button_toggled(bool checked){if(checked) {active = COLOR_NOISE; emit typeChange(active);}}
on_undo_button_clicked()149 void on_undo_button_clicked(){emit undo();}
on_redo_button_clicked()150 void on_redo_button_clicked(){emit redo();}
151 void on_default_colors_clicked();
152 void on_switch_colors_clicked();
on_brush_box_currentIndexChanged(int)153 void on_brush_box_currentIndexChanged(int){refreshBrushPreview();}
on_hardness_slider_valueChanged(int)154 void on_hardness_slider_valueChanged(int){refreshBrushPreview();}
on_size_slider_valueChanged(int)155 void on_size_slider_valueChanged(int){refreshBrushPreview();}
on_clone_source_load_button_clicked()156 void on_clone_source_load_button_clicked(){loadClonePixmap();}
on_mesh_displacement_slider_valueChanged(int val)157 void on_mesh_displacement_slider_valueChanged(int val){displacement_spin_box->setValue((double)val);}
on_displacement_spin_box_valueChanged(double val)158 void on_displacement_spin_box_valueChanged(double val){mesh_displacement_slider->setValue((int)val);}
on_noise_slider_valueChanged(int val)159 void on_noise_slider_valueChanged(int val){noise_box->setValue((double)val);}
on_noise_box_valueChanged(double val)160 void on_noise_box_valueChanged(double val){noise_slider->setValue((int)val);}
161
162 void setPixmapDelta(double x, double y);
163 void movePixmapDelta(double x, double y);
164 void resetPixmapDelta();
165 };
166
167 /******Brush Shapes******/
168
169 /**
170 * Returns the "value" of the brush at the given distance from the center
171 */
brush(Brush b,float distance,float dx,float dy,float hardness)172 inline float brush(Brush b, float distance, float dx, float dy, float hardness)
173 {
174 float op = 0.0; /*< 0 means totally colored, 1 totally blank, but right before returning, its meaning will be the opposite*/
175
176 switch (b)
177 {
178 case CIRCLE : //circle
179 if (distance >= 1.0) op = 1.0;
180 else if (distance * 100.0 > hardness) //if after the treshold of total color
181 {
182 op = (distance * 100.0 - hardness)/ (float) (100 - hardness);
183 }
184 op = 1 - op;
185 break;
186
187 case SQUARE :
188 dx = vcg::math::Abs(dx * 141.4213562); dy = vcg::math::Abs(dy * 141.4213562); //multiply by sqrt(2) and by 100
189 if (dx >= 100 || dy >= 100 ) op = 1.0;
190 else if (dx > hardness || dy > hardness)
191 {
192 op = (std::max<float>(dx, dy) - hardness)/ (float) (100 - hardness);
193 }
194 op = 1 - op;
195 break;
196
197 case PIXMAP :
198
199 default:
200 break;
201 }
202
203 return op;
204 }
205
206 /**
207 * Rasterizes a given brush at the given hardness as a w x h image
208 */
raster(Brush b,int w,int h,float hardness)209 inline QImage raster(Brush b, int w, int h, float hardness)
210 {
211 float cx = w/2.0;
212 float cy = h/2.0;
213 QImage image(w, h, QImage::Format_RGB32);
214 for (float x = 0; x < w; x++){
215 for (float y = 0; y < h; y++){
216 float _x = ((x - cx) * 1.4142 * 2)/w;
217 float _y = ((y - cy) * 1.4142 * 2)/h;
218 int op = 255 * (1 - brush(b, sqrt(_x * _x + _y * _y), _x, _y, hardness));
219 image.setPixel(x, y, qRgb(op, op, op));
220 }
221 }
222 return image;
223 }
224
225 #endif /*PAINTBOX_H_*/
226