1 // This file belongs to the "MiniCore" game engine.
2 // Copyright (C) 2013 Jussi Lind <jussi.lind@iki.fi>
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 // MA  02110-1301, USA.
18 //
19 
20 #include "mcmesh.hh"
21 
22 #include "mcassetmanager.hh"
23 #include "mcbbox.hh"
24 #include "mccamera.hh"
25 #include "mcglshaderprogram.hh"
26 #include "mcgltexcoord.hh"
27 #include "mcglvertex.hh"
28 #include "mctrigonom.hh"
29 
30 #include <algorithm>
31 
MCMesh(std::string handle,const FaceVector & faces,MCGLMaterialPtr material)32 MCMesh::MCMesh(std::string handle, const FaceVector & faces, MCGLMaterialPtr material)
33   : MCGLObjectBase(handle)
34 {
35     setWidth(1.0f);
36 
37     setHeight(1.0f);
38 
39     init(faces);
40 
41     setMaterial(material);
42 }
43 
init(const FaceVector & faces)44 void MCMesh::init(const FaceVector & faces)
45 {
46     float minX = std::numeric_limits<float>::max();
47     float maxX = std::numeric_limits<float>::min();
48     float minY = std::numeric_limits<float>::max();
49     float maxY = std::numeric_limits<float>::min();
50     float minZ = std::numeric_limits<float>::max();
51     float maxZ = std::numeric_limits<float>::min();
52 
53     size_t vertexIndex = 0;
54     for (auto && face : faces)
55     {
56         if (face.vertices.size() != 3)
57         {
58             throw std::runtime_error("Only triangular faces supported!");
59         }
60 
61         for (size_t faceVertexIndex = 0; faceVertexIndex < face.vertices.size(); faceVertexIndex++)
62         {
63             MCGLVertex vertex = { face.vertices.at(faceVertexIndex).x, face.vertices.at(faceVertexIndex).y, face.vertices.at(faceVertexIndex).z };
64 
65             addVertex(vertex);
66 
67             addNormal({ face.vertices.at(faceVertexIndex).i, face.vertices.at(faceVertexIndex).j, face.vertices.at(faceVertexIndex).k });
68 
69             addTexCoord({ face.vertices.at(faceVertexIndex).u, face.vertices.at(faceVertexIndex).v });
70 
71             if (!vertexIndex)
72             {
73                 minX = vertex.x();
74                 maxX = vertex.x();
75                 minY = vertex.y();
76                 maxY = vertex.y();
77             }
78             else
79             {
80                 minX = std::min(minX, vertex.x());
81                 maxX = std::max(maxX, vertex.x());
82                 minY = std::min(minY, vertex.y());
83                 maxY = std::max(maxY, vertex.y());
84                 minZ = std::min(minZ, vertex.z());
85                 maxZ = std::max(maxZ, vertex.z());
86             }
87 
88             vertexIndex++;
89         }
90     }
91 
92     setWidth(maxX - minX);
93 
94     setHeight(maxY - minY);
95 
96     setMinZ(minZ);
97 
98     setMaxZ(maxZ);
99 
100     setColors(ColorVector(vertexCount(), color()));
101 
102     initVBOs();
103 }
104 
initVBOs()105 void MCMesh::initVBOs()
106 {
107     static const auto vertexDataSize = sizeof(MCGLVertex) * vertexCount();
108 
109     static const auto normalDataSize = sizeof(MCGLVertex) * vertexCount();
110 
111     static const auto texCoordDataSize = sizeof(MCGLTexCoord) * vertexCount();
112 
113     static const auto numColorComponents = 4;
114 
115     static const auto colorDataSize = sizeof(GLfloat) * vertexCount() * numColorComponents;
116 
117     static const auto totalDataSize = vertexDataSize + normalDataSize + texCoordDataSize + colorDataSize;
118 
119     initBufferData(totalDataSize, GL_STATIC_DRAW);
120 
121     addBufferSubData(
122       MCGLShaderProgram::VAL_Vertex, vertexDataSize, verticesAsGlArray());
123     addBufferSubData(
124       MCGLShaderProgram::VAL_Normal, normalDataSize, normalsAsGlArray());
125     addBufferSubData(
126       MCGLShaderProgram::VAL_TexCoords, texCoordDataSize, texCoordsAsGlArray());
127     addBufferSubData(
128       MCGLShaderProgram::VAL_Color, colorDataSize, colorsAsGlArray());
129 
130     finishBufferData();
131 }
132 
render(MCCamera * camera,MCVector3dFR pos,float angle)133 void MCMesh::render(MCCamera * camera, MCVector3dFR pos, float angle)
134 {
135     bind();
136 
137     float x = pos.i();
138     float y = pos.j();
139     float z = pos.k();
140 
141     if (camera)
142     {
143         camera->mapToCamera(x, y);
144     }
145 
146     shaderProgram()->bind();
147     shaderProgram()->setScale(scale().i(), scale().j(), scale().k());
148     shaderProgram()->setColor(color());
149     shaderProgram()->setTransform(angle, MCVector3dF(x, y, z));
150 
151     MCGLObjectBase::render();
152 
153     release();
154 }
155 
renderShadow(MCCamera * camera,MCVector3dFR pos,float angle)156 void MCMesh::renderShadow(MCCamera * camera, MCVector3dFR pos, float angle)
157 {
158     float x = pos.i();
159     float y = pos.j();
160 
161     if (camera)
162     {
163         camera->mapToCamera(x, y);
164     }
165 
166     bindShadow();
167 
168     shadowShaderProgram()->setScale(scale().i(), scale().j(), scale().k());
169     shadowShaderProgram()->setTransform(angle, MCVector3dF(x, y, pos.k()));
170 
171     MCGLObjectBase::render();
172 
173     releaseShadow();
174 }
175