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 COPYRIGHT
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 // Matrix calculations taken from the glm library
24 // Which is covered by the MIT license
25 // And has this additional copyright note:
26 /* Copyright (c) 2005 - 2012 G-Truc Creation
27  *
28  * Permission is hereby granted, free of charge, to any person obtaining a copy
29  * of this software and associated documentation files (the "Software"), to deal
30  * in the Software without restriction, including without limitation the rights
31  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32  * copies of the Software, and to permit persons to whom the Software is
33  * furnished to do so, subject to the following conditions:
34  *
35  * The above copyright notice and this permission notice shall be included in
36  * all copies or substantial portions of the Software.
37  */
38 
39 #include "engines/grim/gfx_base.h"
40 #include "engines/grim/savegame.h"
41 #include "engines/grim/bitmap.h"
42 #include "engines/grim/grim.h"
43 
44 #include "engines/grim/model.h"
45 
46 namespace Grim {
47 
GfxBase()48 GfxBase::GfxBase() :
49 		_renderBitmaps(true), _renderZBitmaps(true), _shadowModeActive(false),
50 		_currentPos(0, 0, 0), _dimLevel(0.0f),
51 		_screenWidth(0), _screenHeight(0),
52 		_scaleW(1.0f), _scaleH(1.0f), _currentShadowArray(nullptr),
53 		_shadowColorR(255), _shadowColorG(255), _shadowColorB(255) {
54 			for (unsigned int i = 0; i < _numSpecialtyTextures; i++) {
55 				_specialtyTextures[i]._isShared = true;
56 			}
57 }
58 
setShadowMode()59 void GfxBase::setShadowMode() {
60 	_shadowModeActive = true;
61 }
62 
clearShadowMode()63 void GfxBase::clearShadowMode() {
64 	_shadowModeActive = false;
65 }
66 
isShadowModeActive()67 bool GfxBase::isShadowModeActive() {
68 	return _shadowModeActive;
69 }
70 
saveState(SaveGame * state)71 void GfxBase::saveState(SaveGame *state) {
72 	state->beginSection('DRVR');
73 
74 	byte r, g, b;
75 	getShadowColor(&r, &g, &b);
76 	state->writeByte(r);
77 	state->writeByte(g);
78 	state->writeByte(b);
79 	state->writeBool(_renderBitmaps);
80 	state->writeBool(_renderZBitmaps);
81 
82 	state->endSection();
83 }
84 
restoreState(SaveGame * state)85 void GfxBase::restoreState(SaveGame *state) {
86 	state->beginSection('DRVR');
87 
88 	byte r, g, b;
89 	r = state->readByte();
90 	g = state->readByte();
91 	b = state->readByte();
92 	setShadowColor(r, g , b);
93 	_renderBitmaps = state->readBool();
94 	_renderZBitmaps = state->readBool();
95 
96 	state->endSection();
97 }
98 
renderBitmaps(bool render)99 void GfxBase::renderBitmaps(bool render) {
100 	_renderBitmaps = render;
101 }
102 
renderZBitmaps(bool render)103 void GfxBase::renderZBitmaps(bool render) {
104 	_renderZBitmaps = render;
105 }
106 
drawMesh(const Mesh * mesh)107 void GfxBase::drawMesh(const Mesh *mesh) {
108 	for (int i = 0; i < mesh->_numFaces; i++)
109 		mesh->_faces[i].draw(mesh);
110 }
111 
112 #ifndef USE_OPENGL
113 // Allow CreateGfxOpenGL to be called even if OpenGL isn't included
CreateGfxOpenGL()114 GfxBase *CreateGfxOpenGL() {
115 	return CreateGfxTinyGL();
116 }
117 #endif // USE_OPENGL
118 
makeLookMatrix(const Math::Vector3d & pos,const Math::Vector3d & interest,const Math::Vector3d & up)119 Math::Matrix4 GfxBase::makeLookMatrix(const Math::Vector3d& pos, const Math::Vector3d& interest, const Math::Vector3d& up) {
120 	Math::Vector3d f = (interest - pos).getNormalized();
121 	Math::Vector3d u = up.getNormalized();
122 	Math::Vector3d s = Math::Vector3d::crossProduct(f, u).getNormalized();
123 	u = Math::Vector3d::crossProduct(s, f);
124 
125 	Math::Matrix4 look;
126 	look(0,0) = s.x();
127 	look(1,0) = s.y();
128 	look(2,0) = s.z();
129 	look(0,1) = u.x();
130 	look(1,1) = u.y();
131 	look(2,1) = u.z();
132 	look(0,2) = -f.x();
133 	look(1,2) = -f.y();
134 	look(2,2) = -f.z();
135 	look(3,0) = -Math::Vector3d::dotProduct(s, pos);
136 	look(3,1) = -Math::Vector3d::dotProduct(u, pos);
137 	look(3,2) =  Math::Vector3d::dotProduct(f, pos);
138 
139 	look.transpose();
140 
141 	return look;
142 }
143 
makeProjMatrix(float fov,float nclip,float fclip)144 Math::Matrix4 GfxBase::makeProjMatrix(float fov, float nclip, float fclip) {
145 	float right = nclip * tan(fov / 2 * (LOCAL_PI / 180));
146 	float left = -right;
147 	float top = right * 0.75;
148 	float bottom = -right * 0.75;
149 
150 	Math::Matrix4 proj;
151 	proj(0,0) = (2.0f * nclip) / (right - left);
152 	proj(1,1) = (2.0f * nclip) / (top - bottom);
153 	proj(2,0) = (right + left) / (right - left);
154 	proj(2,1) = (top + bottom) / (top - bottom);
155 	proj(2,2) = -(fclip + nclip) / (fclip - nclip);
156 	proj(2,3) = -1.0f;
157 	proj(3,2) = -(2.0f * fclip * nclip) / (fclip - nclip);
158 	proj(3,3) = 0.0f;
159 
160 	return proj;
161 }
162 
163 
createSpecialtyTexture(uint id,const uint8 * data,int width,int height)164 void GfxBase::createSpecialtyTexture(uint id, const uint8 *data, int width, int height) {
165 	if (id >= _numSpecialtyTextures)
166 		return;
167 	if (_specialtyTextures[id]._texture) {
168 		destroyTexture(&_specialtyTextures[id]);
169 	}
170 	delete[] _specialtyTextures[id]._data;
171 	_specialtyTextures[id]._width = width;
172 	_specialtyTextures[id]._height = height;
173 	_specialtyTextures[id]._bpp = 4;
174 	_specialtyTextures[id]._colorFormat = BM_RGBA;
175 	createTexture(&_specialtyTextures[id], data, nullptr, true);
176 }
177 
createScreenshotBitmap(const Graphics::PixelBuffer src,int w,int h,bool flipOrientation)178 Bitmap *GfxBase::createScreenshotBitmap(const Graphics::PixelBuffer src, int w, int h, bool flipOrientation) {
179         Graphics::PixelBuffer buffer = Graphics::PixelBuffer::createBuffer<565>(w * h, DisposeAfterUse::YES);
180 
181         int i1 = (_screenWidth * w - 1) / _screenWidth + 1;
182         int j1 = (_screenHeight * h - 1) / _screenHeight + 1;
183 
184         for (int j = 0; j < j1; j++) {
185                 for (int i = 0; i < i1; i++) {
186                         int x0 = i * _screenWidth / w;
187                         int x1 = ((i + 1) * _screenWidth - 1) / w + 1;
188                         int y0 = j * _screenHeight / h;
189                         int y1 = ((j + 1) * _screenHeight - 1) / h + 1;
190                         uint16 sr = 0, sg = 0, sb = 0;
191                         for (int y = y0; y < y1; y++) {
192                                 for (int x = x0; x < x1; x++) {
193                                         uint8 r, g, b;
194                                         src.getRGBAt(y * _screenWidth + x, r, g, b);
195                                         sr += r;
196                                         sg += g;
197                                         sb += b;
198                                 }
199                         }
200                         sr /= (x1 - x0) * (y1 - y0);
201                         sg /= (x1 - x0) * (y1 - y0);
202                         sb /= (x1 - x0) * (y1 - y0);
203                         if (g_grim->getGameType() == GType_MONKEY4) {
204                                 buffer.setPixelAt( (flipOrientation ? j : (h - j - 1) ) * w + i, sr, sg, sb);
205                         } else {
206                                 uint32 color = (sr + sg + sb) / 3;
207                                 buffer.setPixelAt( (flipOrientation ? j : (h - j - 1) ) * w + i, color, color, color);
208                         }
209                 }
210         }
211 
212         Bitmap *screenshot = new Bitmap(buffer, w, h, "screenshot");
213         return screenshot;
214 }
215 
makeScreenTextures()216 void GfxBase::makeScreenTextures() {
217 	//make a buffer big enough to hold any of the textures
218 	uint8 *buffer = new uint8[256 * 256 * 4];
219 
220 	// TODO: Handle screen resolutions other than 640 x 480
221 	createSpecialtyTextureFromScreen(0, buffer, 0, 0, 256, 256);
222 	createSpecialtyTextureFromScreen(1, buffer, 256, 0, 256, 256);
223 	createSpecialtyTextureFromScreen(2, buffer, 512, 0, 128, 128);
224 	createSpecialtyTextureFromScreen(3, buffer, 512, 128, 128, 128);
225 	createSpecialtyTextureFromScreen(4, buffer, 0, 256, 256, 256);
226 	createSpecialtyTextureFromScreen(5, buffer, 256, 256, 256, 256);
227 	createSpecialtyTextureFromScreen(6, buffer, 512, 256, 128, 128);
228 	createSpecialtyTextureFromScreen(7, buffer, 512, 384, 128, 128);
229 
230 	delete[] buffer;
231 }
232 
getSpecialtyTexturePtr(Common::String name)233 Texture *GfxBase::getSpecialtyTexturePtr(Common::String name) {
234 	assert(name.hasPrefix("specialty"));
235 	name.erase(0, 9);
236 	unsigned int id;
237 	sscanf(name.c_str(), "%u", &id);
238 	if (id >= _numSpecialtyTextures) {
239 		return nullptr;
240 	}
241 	return &_specialtyTextures[id];
242 }
243 
244 }
245