1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "engines/stark/gfx/openglsprop.h"
24 
25 #include "engines/stark/gfx/driver.h"
26 #include "engines/stark/gfx/texture.h"
27 #include "engines/stark/formats/biffmesh.h"
28 #include "engines/stark/scene.h"
29 #include "engines/stark/services/services.h"
30 
31 #include "graphics/opengl/shader.h"
32 
33 namespace Stark {
34 namespace Gfx {
35 
OpenGLSPropRenderer(Driver * gfx)36 OpenGLSPropRenderer::OpenGLSPropRenderer(Driver *gfx) :
37 		VisualProp(),
38 		_gfx(gfx),
39 		_faceVBO(-1) {
40 	static const char* attributes[] = { "position", "normal", "texcoord", nullptr };
41 	_shader = OpenGL::Shader::fromFiles("stark_prop", attributes);
42 }
43 
~OpenGLSPropRenderer()44 OpenGLSPropRenderer::~OpenGLSPropRenderer() {
45 	clearVertices();
46 
47 	delete _shader;
48 }
49 
render(const Math::Vector3d position,float direction)50 void OpenGLSPropRenderer::render(const Math::Vector3d position, float direction) {
51 	if (_faceVBO == -1) {
52 		// Update the OpenGL Buffer Objects if required
53 		clearVertices();
54 		uploadVertices();
55 	}
56 
57 	_gfx->set3DMode();
58 
59 	Math::Matrix4 model = getModelMatrix(position, direction);
60 	Math::Matrix4 view = StarkScene->getViewMatrix();
61 	Math::Matrix4 projection = StarkScene->getProjectionMatrix();
62 
63 	Math::Matrix4 mvp = projection * view * model;
64 	mvp.transpose();
65 
66 	_shader->enableVertexAttribute("position", _faceVBO, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 0);
67 	_shader->enableVertexAttribute("normal", _faceVBO, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 12);
68 	_shader->enableVertexAttribute("texcoord", _faceVBO, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 24);
69 	_shader->use(true);
70 	_shader->setUniform("mvp", mvp);
71 
72 	const Common::Array<Face> &faces = _model->getFaces();
73 	const Common::Array<Material> &materials = _model->getMaterials();
74 
75 	for (Common::Array<Face>::const_iterator face = faces.begin(); face != faces.end(); ++face) {
76 		const Material &material = materials[face->materialId];
77 
78 		// For each face draw its vertices from the VBO, indexed by the EBO
79 		const Gfx::Texture *tex = _texture->getTexture(material.texture);
80 		if (tex) {
81 			tex->bind();
82 		} else {
83 			glBindTexture(GL_TEXTURE_2D, 0);
84 		}
85 
86 		_shader->setUniform("textured", tex != nullptr);
87 		_shader->setUniform("color", Math::Vector3d(material.r, material.g, material.b));
88 
89 		GLuint ebo = _faceEBO[face];
90 		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
91 		glDrawElements(GL_TRIANGLES, face->vertexIndices.size(), GL_UNSIGNED_INT, 0);
92 	}
93 
94 	_shader->unbind();
95 }
96 
clearVertices()97 void OpenGLSPropRenderer::clearVertices() {
98 	OpenGL::Shader::freeBuffer(_faceVBO);
99 	_faceVBO = -1;
100 
101 	for (FaceBufferMap::iterator it = _faceEBO.begin(); it != _faceEBO.end(); ++it) {
102 		OpenGL::Shader::freeBuffer(it->_value);
103 	}
104 
105 	_faceEBO.clear();
106 }
107 
uploadVertices()108 void OpenGLSPropRenderer::uploadVertices() {
109 	_faceVBO = createFaceVBO();
110 
111 	const Common::Array<Face> &faces = _model->getFaces();
112 	for (Common::Array<Face>::const_iterator face = faces.begin(); face != faces.end(); ++face) {
113 		_faceEBO[face] = createFaceEBO(face);
114 	}
115 }
116 
createFaceVBO()117 uint32 OpenGLSPropRenderer::createFaceVBO() {
118 	const Common::Array<Formats::BiffMesh::Vertex> &vertices = _model->getVertices();
119 
120 	return OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(float) * 9 * vertices.size(), &vertices.front());
121 }
122 
createFaceEBO(const Face * face)123 uint32 OpenGLSPropRenderer::createFaceEBO(const Face *face) {
124 	return OpenGL::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32) * face->vertexIndices.size(), &face->vertexIndices.front());
125 }
126 
127 } // End of namespace Gfx
128 } // End of namespace Stark
129