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