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