1 /*
2  Copyright (C) 2010-2014 Kristian Duske
3 
4  This file is part of TrenchBroom.
5 
6  TrenchBroom is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  TrenchBroom is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "UVView.h"
21 #include "PreferenceManager.h"
22 #include "Preferences.h"
23 #include "Assets/Texture.h"
24 #include "Model/BrushFace.h"
25 #include "Model/BrushGeometry.h"
26 #include "Renderer/Camera.h"
27 #include "Renderer/EdgeRenderer.h"
28 #include "Renderer/Renderable.h"
29 #include "Renderer/RenderBatch.h"
30 #include "Renderer/RenderContext.h"
31 #include "Renderer/Shaders.h"
32 #include "Renderer/ShaderManager.h"
33 #include "Renderer/Vbo.h"
34 #include "Renderer/VertexArray.h"
35 #include "Renderer/VertexSpec.h"
36 #include "View/GLAttribs.h"
37 #include "View/Grid.h"
38 #include "View/MapDocument.h"
39 #include "View/UVCameraTool.h"
40 #include "View/UVOffsetTool.h"
41 #include "View/UVRotateTool.h"
42 #include "View/UVScaleTool.h"
43 #include "View/UVShearTool.h"
44 #include "View/UVOriginTool.h"
45 
46 #include <cassert>
47 #include <iostream>
48 
49 namespace TrenchBroom {
50     namespace View {
51         const Model::Hit::HitType UVView::FaceHit = Model::Hit::freeHitType();
52 
UVView(wxWindow * parent,MapDocumentWPtr document,GLContextManager & contextManager)53         UVView::UVView(wxWindow* parent, MapDocumentWPtr document, GLContextManager& contextManager) :
54         RenderView(parent, contextManager, buildAttribs()),
55         ToolBoxConnector(this),
56         m_document(document),
57         m_helper(m_camera) {
58             setToolBox(m_toolBox);
59             m_toolBox.setClickToActivate(false);
60             createTools();
61             m_toolBox.disable();
62             bindObservers();
63         }
64 
~UVView()65         UVView::~UVView() {
66             unbindObservers();
67         }
68 
setSubDivisions(const Vec2i & subDivisions)69         void UVView::setSubDivisions(const Vec2i& subDivisions) {
70             m_helper.setSubDivisions(subDivisions);
71             Refresh();
72         }
73 
createTools()74         void UVView::createTools() {
75             addTool(new UVRotateTool(m_document, m_helper));
76             addTool(new UVOriginTool(m_helper));
77             addTool(new UVScaleTool(m_document, m_helper));
78             addTool(new UVShearTool(m_document, m_helper));
79             addTool(new UVOffsetTool(m_document, m_helper));
80             addTool(new UVCameraTool(m_camera));
81         }
82 
bindObservers()83         void UVView::bindObservers() {
84             MapDocumentSPtr document = lock(m_document);
85             document->nodesDidChangeNotifier.addObserver(this, &UVView::nodesDidChange);
86             document->brushFacesDidChangeNotifier.addObserver(this, &UVView::brushFacesDidChange);
87             document->selectionDidChangeNotifier.addObserver(this, &UVView::selectionDidChange);
88             document->grid().gridDidChangeNotifier.addObserver(this, &UVView::gridDidChange);
89 
90             PreferenceManager& prefs = PreferenceManager::instance();
91             prefs.preferenceDidChangeNotifier.addObserver(this, &UVView::preferenceDidChange);
92 
93             m_camera.cameraDidChangeNotifier.addObserver(this, &UVView::cameraDidChange);
94         }
95 
unbindObservers()96         void UVView::unbindObservers() {
97             if (!expired(m_document)) {
98                 MapDocumentSPtr document = lock(m_document);
99                 document->nodesDidChangeNotifier.removeObserver(this, &UVView::nodesDidChange);
100                 document->brushFacesDidChangeNotifier.removeObserver(this, &UVView::brushFacesDidChange);
101                 document->selectionDidChangeNotifier.removeObserver(this, &UVView::selectionDidChange);
102                 document->grid().gridDidChangeNotifier.removeObserver(this, &UVView::gridDidChange);
103             }
104 
105             PreferenceManager& prefs = PreferenceManager::instance();
106             prefs.preferenceDidChangeNotifier.removeObserver(this, &UVView::preferenceDidChange);
107 
108             m_camera.cameraDidChangeNotifier.removeObserver(this, &UVView::cameraDidChange);
109         }
110 
selectionDidChange(const Selection & selection)111         void UVView::selectionDidChange(const Selection& selection) {
112             MapDocumentSPtr document = lock(m_document);
113             const Model::BrushFaceList& faces = document->selectedBrushFaces();
114             if (faces.size() != 1)
115                 m_helper.setFace(NULL);
116             else
117                 m_helper.setFace(faces.back());
118 
119             if (m_helper.valid())
120                 m_toolBox.enable();
121             else
122                 m_toolBox.disable();
123             Refresh();
124         }
125 
nodesDidChange(const Model::NodeList & nodes)126         void UVView::nodesDidChange(const Model::NodeList& nodes) {
127             Refresh();
128         }
129 
brushFacesDidChange(const Model::BrushFaceList & faces)130         void UVView::brushFacesDidChange(const Model::BrushFaceList& faces) {
131             Refresh();
132         }
133 
gridDidChange()134         void UVView::gridDidChange() {
135             Refresh();
136         }
137 
preferenceDidChange(const IO::Path & path)138         void UVView::preferenceDidChange(const IO::Path& path) {
139             Refresh();
140         }
141 
cameraDidChange(const Renderer::Camera * camera)142         void UVView::cameraDidChange(const Renderer::Camera* camera) {
143             Refresh();
144         }
145 
doUpdateViewport(int x,int y,int width,int height)146         void UVView::doUpdateViewport(int x, int y, int width, int height) {
147             m_camera.setViewport(Renderer::Camera::Viewport(x, y, width, height));
148             m_helper.cameraViewportChanged();
149         }
150 
doRender()151         void UVView::doRender() {
152             if (m_helper.valid()) {
153                 MapDocumentSPtr document = lock(m_document);
154                 document->commitPendingAssets();
155 
156                 Renderer::RenderContext renderContext(Renderer::RenderContext::RenderMode_2D, m_camera, fontManager(), shaderManager());
157                 Renderer::RenderBatch renderBatch(vertexVbo(), indexVbo());
158 
159                 setupGL(renderContext);
160                 renderTexture(renderContext, renderBatch);
161                 renderFace(renderContext, renderBatch);
162                 renderToolBox(renderContext, renderBatch);
163                 renderTextureAxes(renderContext, renderBatch);
164 
165                 renderBatch.render(renderContext);
166             }
167         }
168 
doShouldRenderFocusIndicator() const169         bool UVView::doShouldRenderFocusIndicator() const {
170             return false;
171         }
172 
setupGL(Renderer::RenderContext & renderContext)173         void UVView::setupGL(Renderer::RenderContext& renderContext) {
174             const Renderer::Camera::Viewport& viewport = renderContext.camera().unzoomedViewport();
175             glAssert(glViewport(viewport.x, viewport.y, viewport.width, viewport.height));
176 
177             glAssert(glEnable(GL_MULTISAMPLE));
178             glAssert(glEnable(GL_BLEND));
179             glAssert(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
180             glAssert(glShadeModel(GL_SMOOTH));
181             glAssert(glDisable(GL_DEPTH_TEST));
182         }
183 
184         class UVView::RenderTexture : public Renderer::DirectRenderable {
185         private:
186             typedef Renderer::VertexSpecs::P3NT2::Vertex Vertex;
187 
188             const UVViewHelper& m_helper;
189             Renderer::VertexArray m_vertexArray;
190         public:
RenderTexture(const UVViewHelper & helper)191             RenderTexture(const UVViewHelper& helper) :
192             m_helper(helper) {
193                 Vertex::List vertices = getVertices();
194                 m_vertexArray = Renderer::VertexArray::swap(vertices);
195             }
196         private:
getVertices()197             Vertex::List getVertices() {
198                 const Model::BrushFace* face = m_helper.face();
199                 const Vec3& normal = face->boundary().normal;
200 
201                 Vertex::List vertices;
202                 vertices.reserve(4);
203 
204                 const Renderer::Camera& camera = m_helper.camera();
205                 const Renderer::Camera::Viewport& v = camera.zoomedViewport();
206                 const float w2 = static_cast<float>(v.width) / 2.0f;
207                 const float h2 = static_cast<float>(v.height) / 2.0f;
208 
209                 const Vec3f& p = camera.position();
210                 const Vec3f& r = camera.right();
211                 const Vec3f& u = camera.up();
212 
213                 const Vec3f pos1 = -w2 * r +h2 * u + p;
214                 const Vec3f pos2 = +w2 * r +h2 * u + p;
215                 const Vec3f pos3 = +w2 * r -h2 * u + p;
216                 const Vec3f pos4 = -w2 * r -h2 * u + p;
217 
218                 vertices.push_back(Vertex(pos1, normal, face->textureCoords(pos1)));
219                 vertices.push_back(Vertex(pos2, normal, face->textureCoords(pos2)));
220                 vertices.push_back(Vertex(pos3, normal, face->textureCoords(pos3)));
221                 vertices.push_back(Vertex(pos4, normal, face->textureCoords(pos4)));
222 
223                 return vertices;
224             }
225         private:
doPrepareVertices(Renderer::Vbo & vertexVbo)226             void doPrepareVertices(Renderer::Vbo& vertexVbo) {
227                 m_vertexArray.prepare(vertexVbo);
228             }
229 
doRender(Renderer::RenderContext & renderContext)230             void doRender(Renderer::RenderContext& renderContext) {
231                 const Model::BrushFace* face = m_helper.face();
232                 const Vec2f& offset = face->offset();
233                 const Vec2f& scale = face->scale();
234                 const Mat4x4 toTex = face->toTexCoordSystemMatrix(offset, scale, true);
235 
236                 const Assets::Texture* texture = face->texture();
237                 assert(texture != NULL);
238 
239                 texture->activate();
240 
241                 Renderer::ActiveShader shader(renderContext.shaderManager(), Renderer::Shaders::UVViewShader);
242                 shader.set("ApplyTexture", true);
243                 shader.set("Color", texture->averageColor());
244                 shader.set("Brightness", pref(Preferences::Brightness));
245                 shader.set("RenderGrid", true);
246                 shader.set("GridSizes", Vec2f(texture->width(), texture->height()));
247                 shader.set("GridColor", Color(0.6f, 0.6f, 0.6f, 1.0f)); // TODO: make this a preference
248                 shader.set("GridScales", scale);
249                 shader.set("GridMatrix", toTex);
250                 shader.set("GridDivider", Vec2f(m_helper.subDivisions()));
251                 shader.set("CameraZoom", m_helper.cameraZoom());
252                 shader.set("Texture", 0);
253 
254                 m_vertexArray.render(GL_QUADS);
255 
256                 texture->deactivate();
257             }
258         };
259 
renderTexture(Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)260         void UVView::renderTexture(Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) {
261             const Model::BrushFace* face = m_helper.face();
262             const Assets::Texture* texture = face->texture();
263             if (texture == NULL)
264                 return;
265 
266             renderBatch.addOneShot(new RenderTexture(m_helper));
267         }
268 
renderFace(Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)269         void UVView::renderFace(Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) {
270             assert(m_helper.valid());
271 
272             const Model::BrushFace* face = m_helper.face();
273             const Model::BrushFace::VertexList faceVertices = face->vertices();
274 
275             typedef Renderer::VertexSpecs::P3::Vertex Vertex;
276             Vertex::List edgeVertices;
277             edgeVertices.reserve(faceVertices.size());
278 
279             Model::BrushFace::VertexList::const_iterator it, end;
280             for (it = faceVertices.begin(), end = faceVertices.end(); it != end; ++it)
281                 edgeVertices.push_back(Vertex((*it)->position()));
282 
283             const Color edgeColor(1.0f, 1.0f, 1.0f, 1.0f); // TODO: make this a preference
284 
285             Renderer::DirectEdgeRenderer edgeRenderer(Renderer::VertexArray::swap(edgeVertices), GL_LINE_LOOP);
286             edgeRenderer.renderOnTop(renderBatch, edgeColor, 2.5f);
287         }
288 
renderTextureAxes(Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)289         void UVView::renderTextureAxes(Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) {
290             assert(m_helper.valid());
291 
292             const Model::BrushFace* face = m_helper.face();
293             const Vec3& normal = face->boundary().normal;
294 
295             const Vec3 xAxis = face->textureXAxis() - face->textureXAxis().dot(normal) * normal;
296             const Vec3 yAxis = face->textureYAxis() - face->textureYAxis().dot(normal) * normal;
297             const Vec3 center = face->boundsCenter();
298 
299             typedef Renderer::VertexSpecs::P3C4::Vertex Vertex;
300             Vertex::List vertices;
301             vertices.reserve(4);
302 
303             const FloatType length = 32.0 / FloatType(m_helper.cameraZoom());
304 
305             vertices.push_back(Vertex(center, pref(Preferences::XAxisColor)));
306             vertices.push_back(Vertex(center + length * xAxis, pref(Preferences::XAxisColor)));
307             vertices.push_back(Vertex(center, pref(Preferences::YAxisColor)));
308             vertices.push_back(Vertex(center + length * yAxis, pref(Preferences::YAxisColor)));
309 
310             Renderer::DirectEdgeRenderer edgeRenderer(Renderer::VertexArray::swap(vertices), GL_LINES);
311             edgeRenderer.renderOnTop(renderBatch, 2.0f);
312         }
313 
renderToolBox(Renderer::RenderContext & renderContext,Renderer::RenderBatch & renderBatch)314         void UVView::renderToolBox(Renderer::RenderContext& renderContext, Renderer::RenderBatch& renderBatch) {
315             renderTools(renderContext, renderBatch);
316         }
317 
doGetPickRequest(const int x,const int y) const318         PickRequest UVView::doGetPickRequest(const int x, const int y) const {
319             return PickRequest(Ray3(m_camera.pickRay(x, y)), m_camera);
320         }
321 
doPick(const Ray3 & pickRay) const322         Model::PickResult UVView::doPick(const Ray3& pickRay) const {
323             Model::PickResult pickResult = Model::PickResult::byDistance(lock(m_document)->editorContext());
324             if (!m_helper.valid())
325                 return pickResult;
326 
327             Model::BrushFace* face = m_helper.face();
328             const FloatType distance = face->intersectWithRay(pickRay);
329             if (!Math::isnan(distance)) {
330                 const Vec3 hitPoint = pickRay.pointAtDistance(distance);
331                 pickResult.addHit(Model::Hit(UVView::FaceHit, distance, hitPoint, face));
332             }
333             return pickResult;
334         }
335     }
336 }
337