[Scummvm-git-logs] scummvm master -> 9fd225639a2a8921cd1f365395e556f900c550db

aquadran noreply at scummvm.org
Sat Oct 26 15:37:50 UTC 2024


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
9fd225639a WINTERMUTE: Restore original code for 3ds loader


Commit: 9fd225639a2a8921cd1f365395e556f900c550db
    https://github.com/scummvm/scummvm/commit/9fd225639a2a8921cd1f365395e556f900c550db
Author: Paweł Kołodziejski (aquadran at gmail.com)
Date: 2024-10-26T17:37:45+02:00

Commit Message:
WINTERMUTE: Restore original code for 3ds loader

Changed paths:
  A engines/wintermute/base/gfx/3dface.cpp
  A engines/wintermute/base/gfx/3dface.h
  A engines/wintermute/base/gfx/3dvertex.cpp
  A engines/wintermute/base/gfx/3dvertex.h
    engines/wintermute/ad/ad_scene_geometry.cpp
    engines/wintermute/ad/ad_waypoint_group3d.cpp
    engines/wintermute/base/gfx/3dcamera.cpp
    engines/wintermute/base/gfx/3dcamera.h
    engines/wintermute/base/gfx/3dlight.cpp
    engines/wintermute/base/gfx/3dlight.h
    engines/wintermute/base/gfx/3dloader_3ds.cpp
    engines/wintermute/base/gfx/3dloader_3ds.h
    engines/wintermute/base/gfx/3dmesh.cpp
    engines/wintermute/base/gfx/3dmesh.h
    engines/wintermute/base/gfx/opengl/base_render_opengl3d.cpp
    engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
    engines/wintermute/base/gfx/opengl/mesh3ds_opengl.cpp
    engines/wintermute/base/gfx/opengl/mesh3ds_opengl.h
    engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.cpp
    engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h
    engines/wintermute/base/gfx/opengl/shaders/wme_geometry.vertex
    engines/wintermute/module.mk


diff --git a/engines/wintermute/ad/ad_scene_geometry.cpp b/engines/wintermute/ad/ad_scene_geometry.cpp
index e708c415135..5d4fb9dcbc6 100644
--- a/engines/wintermute/ad/ad_scene_geometry.cpp
+++ b/engines/wintermute/ad/ad_scene_geometry.cpp
@@ -182,78 +182,125 @@ bool AdSceneGeometry::loadFile(const char *filename) {
 	filenameTmp.replace(filenameTmp.size() - 3, 3, "geometry", 0, 8);
 	AdGeomExt *geomExt = getGeometryExtension(filenameTmp.begin());
 
-	// Light3D, AdBlock, AdGeneric and AdWalkplane all inherit from BaseScriptable
-	// the latter one is overriding the new operator such that instances are registered
-	// in the system class registry
-	// for the most part, the subclasses of BaseScriptable override the new operator themselves,
-	// but here this is not the case. So these instances are not supposed to be registered
-	// and doing so would create faulty savegames. The persistence of them will be handled by AdSceneGeometry
-	SystemClassRegistry::getInstance()->_disabled = true;
-
-	BaseArray<Mesh3DS *> meshes;
-	BaseArray<Common::String> meshNames;
-
-	if (!load3DSFile(filename, meshes, meshNames, _lights, _cameras, _gameRef)) {
+	Loader3DS *loader = new Loader3DS(_gameRef);
+	if (!loader->parseFile(filename)) {
+		delete loader;
 		delete geomExt;
 		return false;
 	}
 
 	uint i;
 
-	// load meshes
-	for (i = 0; i < meshes.size(); i++) {
-		AdGeomExtNode *ExtNode = geomExt->matchName(meshNames[i].c_str());
+	SystemClassRegistry::getInstance()->_disabled = true;
 
-		if (!ExtNode) {
+	// load meshes
+	for (i = 0; i < loader->getNumMeshes(); i++) {
+		AdGeomExtNode *extNode = geomExt->matchName(loader->getMeshName(i).c_str());
+		if (!extNode) {
 			continue;
 		}
 
-		switch (ExtNode->_type) {
+		switch (extNode->_type) {
 		case GEOM_WALKPLANE: {
 				AdWalkplane *plane = new AdWalkplane(_gameRef);
-				plane->setName(meshNames[i].c_str());
-				plane->_mesh = meshes[i];
-				plane->_mesh->computeNormals();
-				plane->_mesh->fillVertexBuffer(0xFF0000FF); // original 0x700000FF
-				plane->_receiveShadows = ExtNode->_receiveShadows;
-				_planes.add(plane);
+				plane->setName(loader->getMeshName(i).c_str());
+				plane->_mesh = _gameRef->_renderer3D->createMesh3DS();
+				if (!loader->loadMesh(i, plane->_mesh)) {
+					delete plane->_mesh;
+					delete plane;
+					delete loader;
+					delete geomExt;
+					return false;
+				} else {
+					plane->_mesh->computeNormals();
+					plane->_mesh->fillVertexBuffer(0xD00000FF); // original 0x700000FF
+					plane->_receiveShadows = extNode->_receiveShadows;
+					_planes.add(plane);
+				}
 			}
 			break;
 
 		case GEOM_BLOCKED: {
 				AdBlock *block = new AdBlock(_gameRef);
-				block->setName(meshNames[i].c_str());
-				block->_mesh = meshes[i];
-				block->_mesh->computeNormals();
-				block->_mesh->fillVertexBuffer(0xFFFF0000); // original 0x70FF0000
-				block->_receiveShadows = ExtNode->_receiveShadows;
-				_blocks.add(block);
+				block->setName(loader->getMeshName(i).c_str());
+				block->_mesh = _gameRef->_renderer3D->createMesh3DS();
+				if (!loader->loadMesh(i, block->_mesh)) {
+					delete block->_mesh;
+					delete block;
+					delete loader;
+					delete geomExt;
+					return false;
+				} else {
+					block->_mesh->computeNormals();
+					block->_mesh->fillVertexBuffer(0xD0FF0000); // original 0x70FF0000
+					block->_receiveShadows = extNode->_receiveShadows;
+					_blocks.add(block);
+				}
 			}
 			break;
 
 		case GEOM_WAYPOINT: {
-				Mesh3DS *mesh = meshes[i];
-				if (_waypointGroups.size() == 0) {
-					_waypointGroups.add(new AdWaypointGroup3D(_gameRef));
+				Mesh3DS *mesh = _gameRef->_renderer3D->createMesh3DS();
+				if (!loader->loadMesh(i, mesh)) {
+					delete mesh;
+					delete loader;
+					delete geomExt;
+					return false;
+				} else {
+					if (_waypointGroups.size() == 0) {
+						_waypointGroups.add(new AdWaypointGroup3D(_gameRef));
+					}
+					_waypointGroups[0]->addFromMesh(mesh);
+					delete mesh;
 				}
-				_waypointGroups[0]->addFromMesh(mesh);
-				delete mesh;
 			}
 			break;
 
 		case GEOM_GENERIC: {
 				AdGeneric *generic = new AdGeneric(_gameRef);
-				generic->setName(meshNames[i].c_str());
-				generic->_mesh = meshes[i];
-				generic->_mesh->computeNormals();
-				generic->_mesh->fillVertexBuffer(0xFF00FF00); // original 0x7000FF00
-				generic->_receiveShadows = ExtNode->_receiveShadows;
-				_generics.add(generic);
+				generic->setName(loader->getMeshName(i).c_str());
+				generic->_mesh = _gameRef->_renderer3D->createMesh3DS();
+				if (!loader->loadMesh(i, generic->_mesh)) {
+					delete generic->_mesh;
+					delete generic;
+					delete loader;
+					delete geomExt;
+					return false;
+				} else {
+					generic->_mesh->computeNormals();
+					generic->_mesh->fillVertexBuffer(0xD000FF00); // original 0x7000FF00
+					generic->_receiveShadows = extNode->_receiveShadows;
+					_generics.add(generic);
+				}
 			}
 			break;
 		}
 	}
 
+	// load cameras
+	for (i = 0; i < loader->getNumCameras(); i++) {
+		Camera3D *camera = new Camera3D(_gameRef);
+		if (!loader->loadCamera(i, camera)) {
+			delete camera;
+			delete loader;
+			delete geomExt;
+			return false;
+		} else
+			_cameras.add(camera);
+	}
+
+	// load lights
+	for (i = 0; i < loader->getNumLights(); i++) {
+		Light3D *light = new Light3D(_gameRef);
+		if (!loader->loadLight(i, light)) {
+			delete light;
+			delete loader;
+			delete geomExt;
+			return false;
+		} else
+			_lights.add(light);
+	}
+
 	SystemClassRegistry::getInstance()->_disabled = false;
 
 	if (_cameras.size() > 0) {
@@ -265,6 +312,7 @@ bool AdSceneGeometry::loadFile(const char *filename) {
 		setActiveLight(0);
 	}
 
+	delete loader;
 	delete geomExt;
 
 	// drop waypoints to the ground
@@ -426,16 +474,12 @@ float AdSceneGeometry::getHeightAt(DXVector3 pos, float tolerance, bool *intFoun
 	bool intFoundTmp = false;
 
 	for (uint32 i = 0; i < _planes.size(); i++) {
-		for (int j = 0; j < _planes[i]->_mesh->faceCount(); j++) {
-			uint16 *triangle = _planes[i]->_mesh->getFace(j);
-			float *vp0 = _planes[i]->_mesh->getVertexPosition(triangle[0]);
-			float *vp1 = _planes[i]->_mesh->getVertexPosition(triangle[1]);
-			float *vp2 = _planes[i]->_mesh->getVertexPosition(triangle[2]);
-			DXVector3 v0(vp0[0], vp0[1], vp0[2]);
-			DXVector3 v1(vp1[0], vp1[1], vp1[2]);
-			DXVector3 v2(vp2[0], vp2[1], vp2[2]);
-
-			if (intersectTriangle(pos, dir, v0, v1, v2, &intersection._x, &intersection._y, &intersection._z)) {
+		for (int j = 0; j < _planes[i]->_mesh->_numFaces; j++) {
+			if (intersectTriangle(pos, dir,
+								  _planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[0]]._pos,
+								  _planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[1]]._pos,
+								  _planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[2]]._pos,
+								  &intersection._x, &intersection._y, &intersection._z)) {
 				if (intersection._y > pos._y + tolerance) {
 					continue; // only fall down
 				}
@@ -458,16 +502,14 @@ float AdSceneGeometry::getHeightAt(DXVector3 pos, float tolerance, bool *intFoun
 
 //////////////////////////////////////////////////////////////////////////
 bool AdSceneGeometry::directPathExists(DXVector3 *p1, DXVector3 *p2) {
+	DXVector3 v0, v1, v2;
+
 	// test walkplanes
 	for (uint i = 0; i < _planes.size(); i++) {
-		for (int j = 0; j < _planes[i]->_mesh->faceCount(); j++) {
-			uint16 *triangle = _planes[i]->_mesh->getFace(j);
-			float *vp0 = _planes[i]->_mesh->getVertexPosition(triangle[0]);
-			float *vp1 = _planes[i]->_mesh->getVertexPosition(triangle[1]);
-			float *vp2 = _planes[i]->_mesh->getVertexPosition(triangle[2]);
-			DXVector3 v0(vp0[0], vp0[1], vp0[2]);
-			DXVector3 v1(vp1[0], vp1[1], vp1[2]);
-			DXVector3 v2(vp2[0], vp2[1], vp2[2]);
+		for (int j = 0; j < _planes[i]->_mesh->_numFaces; j++) {
+			v0 = _planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[0]]._pos;
+			v1 = _planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[1]]._pos;
+			v2 = _planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[2]]._pos;
 			DXVector3 intersection;
 			float dist;
 
@@ -489,14 +531,10 @@ bool AdSceneGeometry::directPathExists(DXVector3 *p1, DXVector3 *p2) {
 			continue;
 		}
 
-		for (int j = 0; j < _blocks[i]->_mesh->faceCount(); j++) {
-			uint16 *triangle = _blocks[i]->_mesh->getFace(j);
-			float *vp0 = _blocks[i]->_mesh->getVertexPosition(triangle[0]);
-			float *vp1 = _blocks[i]->_mesh->getVertexPosition(triangle[1]);
-			float *vp2 = _blocks[i]->_mesh->getVertexPosition(triangle[2]);
-			DXVector3 v0(vp0[0], vp0[1], vp0[2]);
-			DXVector3 v1(vp1[0], vp1[1], vp1[2]);
-			DXVector3 v2(vp2[0], vp2[1], vp2[2]);
+		for (int j = 0; j < _blocks[i]->_mesh->_numFaces; j++) {
+			v0 = _blocks[i]->_mesh->_vertices[_blocks[i]->_mesh->_faces[j]._vertices[0]]._pos;
+			v1 = _blocks[i]->_mesh->_vertices[_blocks[i]->_mesh->_faces[j]._vertices[1]]._pos;
+			v2 = _blocks[i]->_mesh->_vertices[_blocks[i]->_mesh->_faces[j]._vertices[2]]._pos;
 			DXVector3 intersection;
 			float dist;
 
@@ -519,20 +557,18 @@ bool AdSceneGeometry::directPathExists(DXVector3 *p1, DXVector3 *p2) {
 
 //////////////////////////////////////////////////////////////////////////
 DXVector3 AdSceneGeometry::getBlockIntersection(DXVector3 *p1, DXVector3 *p2) {
+	DXVector3 v0, v1, v2;
+
 	// test blocks
 	for (uint i = 0; i < _blocks.size(); i++) {
 		if (!_blocks[i]->_active) {
 			continue;
 		}
 
-		for (int j = 0; j < _blocks[i]->_mesh->faceCount(); j++) {
-			uint16 *triangle = _blocks[i]->_mesh->getFace(j);
-			float *vp0 = _blocks[i]->_mesh->getVertexPosition(triangle[0]);
-			float *vp1 = _blocks[i]->_mesh->getVertexPosition(triangle[1]);
-			float *vp2 = _blocks[i]->_mesh->getVertexPosition(triangle[2]);
-			DXVector3 v0(vp0[0], vp0[1], vp0[2]);
-			DXVector3 v1(vp1[0], vp1[1], vp1[2]);
-			DXVector3 v2(vp2[0], vp2[1], vp2[2]);
+		for (int j = 0; j < _blocks[i]->_mesh->_numFaces; j++) {
+			v0 = _blocks[i]->_mesh->_vertices[_blocks[i]->_mesh->_faces[j]._vertices[0]]._pos;
+			v1 = _blocks[i]->_mesh->_vertices[_blocks[i]->_mesh->_faces[j]._vertices[1]]._pos;
+			v2 = _blocks[i]->_mesh->_vertices[_blocks[i]->_mesh->_faces[j]._vertices[2]]._pos;
 			DXVector3 intersection;
 			float dist;
 
@@ -684,16 +720,12 @@ bool AdSceneGeometry::convert2Dto3D(int x, int y, DXVector3 *pos) {
 	float minDist = FLT_MAX;
 	DXVector3 intersection, ray;
 	for (uint32 i = 0; i < _planes.size(); i++) {
-		for (int j = 0; j < _planes[i]->_mesh->faceCount(); j++) {
-			uint16 *triangle = _planes[i]->_mesh->getFace(j);
-			float *vp0 = _planes[i]->_mesh->getVertexPosition(triangle[0]);
-			float *vp1 = _planes[i]->_mesh->getVertexPosition(triangle[1]);
-			float *vp2 = _planes[i]->_mesh->getVertexPosition(triangle[2]);
-			DXVector3 v0(vp0[0], vp0[1], vp0[2]);
-			DXVector3 v1(vp1[0], vp1[1], vp1[2]);
-			DXVector3 v2(vp2[0], vp2[1], vp2[2]);
-
-			if (intersectTriangle(vPickRayOrig, vPickRayDir, v0, v1, v2, &intersection._x, &intersection._y, &intersection._z)) {
+		for (int j = 0; j < _planes[i]->_mesh->_numFaces; j++) {
+			if (intersectTriangle(vPickRayOrig, vPickRayDir,
+								  _planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[0]]._pos,
+								  _planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[1]]._pos,
+								  _planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[2]]._pos,
+								  &intersection._x, &intersection._y, &intersection._z)) {
 				ray = intersection - vPickRayOrig;
 				float dist = DXVec3Length(&ray);
 
@@ -904,10 +936,10 @@ bool AdSceneGeometry::enableLights(DXVector3 point, BaseArray<char *> &ignoreLig
 			DXVector3 dif;
 
 			if (_lights[i]->_isSpotlight) {
-				DXVector3 dir = _lights[i]->_target - _lights[i]->_position;
-				dif = (_lights[i]->_position + dir * 0.75f) - point;
+				DXVector3 dir = _lights[i]->_target - _lights[i]->_pos;
+				dif = (_lights[i]->_pos + dir * 0.75f) - point;
 			} else {
-				dif = _lights[i]->_position - point;
+				dif = _lights[i]->_pos - point;
 			}
 
 			_lights[i]->_distance = fabs(DXVec3Length(&dif));
@@ -1178,7 +1210,7 @@ uint32 AdSceneGeometry::getLightColor(const char *lightName) {
 DXVector3 AdSceneGeometry::getLightPos(const char *lightName) {
 	for (uint i = 0; i < _lights.size(); i++) {
 		if (scumm_stricmp(lightName, _lights[i]->getName()) == 0) {
-			return _lights[i]->_position;
+			return _lights[i]->_pos;
 		}
 	}
 	return DXVector3(0, 0, 0);
diff --git a/engines/wintermute/ad/ad_waypoint_group3d.cpp b/engines/wintermute/ad/ad_waypoint_group3d.cpp
index d32fda0b60d..c19fda41510 100644
--- a/engines/wintermute/ad/ad_waypoint_group3d.cpp
+++ b/engines/wintermute/ad/ad_waypoint_group3d.cpp
@@ -50,18 +50,18 @@ bool AdWaypointGroup3D::addFromMesh(Mesh3DS *mesh) {
 	DXVector3 min = DXVector3(0, 0, 0);
 	DXVector3 max = DXVector3(0, 0, 0);
 
-	if (mesh->vertexCount() > 0) {
-		min = max = mesh->getVertexPosition(0);
+	if (mesh->_numVertices > 0) {
+		min = max = mesh->_vertices[0]._pos;
 	}
 
-	for (int i = 0; i < mesh->vertexCount(); i++) {
-		min._x = MIN(min._x, mesh->getVertexPosition(i)[0]);
-		min._y = MIN(min._y, mesh->getVertexPosition(i)[1]);
-		min._z = MIN(min._z, mesh->getVertexPosition(i)[2]);
+	for (int i = 0; i < mesh->_numVertices; i++) {
+		min._x = MIN(min._x, mesh->_vertices[i]._pos._x);
+		min._y = MIN(min._y, mesh->_vertices[i]._pos._y);
+		min._z = MIN(min._z, mesh->_vertices[i]._pos._z);
 
-		max._x = MAX(max._x, mesh->getVertexPosition(i)[0]);
-		max._y = MAX(max._y, mesh->getVertexPosition(i)[1]);
-		max._z = MAX(max._z, mesh->getVertexPosition(i)[2]);
+		max._x = MAX(max._x, mesh->_vertices[i]._pos._x);
+		max._y = MAX(max._y, mesh->_vertices[i]._pos._y);
+		max._z = MAX(max._z, mesh->_vertices[i]._pos._z);
 	}
 
 	DXVector3 *vect = new DXVector3;
diff --git a/engines/wintermute/base/gfx/3dcamera.cpp b/engines/wintermute/base/gfx/3dcamera.cpp
index 6dd3a27ac9b..3e6540333f2 100644
--- a/engines/wintermute/base/gfx/3dcamera.cpp
+++ b/engines/wintermute/base/gfx/3dcamera.cpp
@@ -41,7 +41,7 @@ namespace Wintermute {
 
 //////////////////////////////////////////////////////////////////////////
 Camera3D::Camera3D(BaseGame *inGame) : BaseNamedObject(inGame) {
-	_position = DXVector3(0.0f, 0.0f, 0.0f);
+	_pos = DXVector3(0.0f, 0.0f, 0.0f);
 	_target = DXVector3(0.0f, 0.0f, 0.0f);
 	_bank = 0.0f;
 	_fov = _origFov = degToRad(45.0f);
@@ -62,14 +62,14 @@ bool Camera3D::getViewMatrix(DXMatrix *viewMatrix) {
 		DXVec3TransformCoord(&up, &up, &rot);
 	}
 
-	DXMatrixLookAtLH(viewMatrix, &_position, &_target, &up);
+	DXMatrixLookAtLH(viewMatrix, &_pos, &_target, &up);
 
 	return true;
 }
 
 //////////////////////////////////////////////////////////////////////////
 void Camera3D::setupPos(DXVector3 pos, DXVector3 target, float bank) {
-	_position = pos;
+	_pos = pos;
 	_target = target;
 	_bank = bank;
 }
@@ -79,23 +79,23 @@ void Camera3D::rotateView(float x, float y, float z) {
 	DXVector3 vVector; // Vector for the position/view.
 
 	// Get our view vector (The direciton we are facing)
-	vVector = _target - _position; // This gets the direction of the view
+	vVector = _target - _pos; // This gets the direction of the view
 
 	// Rotate the view along the desired axis
 	if (x) {
 		// Rotate the view vector up or down, then add it to our position
-		_target._z = (float)(_position._z + sin(x) * vVector._y + cos(x) * vVector._z);
-		_target._y = (float)(_position._y + cos(x) * vVector._y - sin(x) * vVector._z);
+		_target._z = (float)(_pos._z + sin(x) * vVector._y + cos(x) * vVector._z);
+		_target._y = (float)(_pos._y + cos(x) * vVector._y - sin(x) * vVector._z);
 	}
 	if (y) {
 		// Rotate the view vector right or left, then add it to our position
-		_target._z = (float)(_position._z + sin(y) * vVector._x + cos(y) * vVector._z);
-		_target._x = (float)(_position._x + cos(y) * vVector._x - sin(y) * vVector._z);
+		_target._z = (float)(_pos._z + sin(y) * vVector._x + cos(y) * vVector._z);
+		_target._x = (float)(_pos._x + cos(y) * vVector._x - sin(y) * vVector._z);
 	}
 	if (z) {
 		// Rotate the view vector diagnally right or diagnally down, then add it to our position
-		_target._x = (float)(_position._x + sin(z) * vVector._y + cos(z) * vVector._x);
-		_target._y = (float)(_position._y + cos(z) * vVector._y - sin(z) * vVector._x);
+		_target._x = (float)(_pos._x + sin(z) * vVector._y + cos(z) * vVector._x);
+		_target._y = (float)(_pos._y + cos(z) * vVector._y - sin(z) * vVector._x);
 	}
 }
 
@@ -104,47 +104,12 @@ void Camera3D::move(float speed) {
 	DXVector3 vector; // Init a vector for our view
 
 	// Get our view vector (The direciton we are facing)
-	vector = _target - _position; // This gets the direction of the view
+	vector = _target - _pos; // This gets the direction of the view
 
-	_position._x += vector._x * speed; // Add our acceleration to our position's X
-	_position._z += vector._z * speed; // Add our acceleration to our position's Z
+	_pos._x += vector._x * speed; // Add our acceleration to our position's X
+	_pos._z += vector._z * speed; // Add our acceleration to our position's Z
 	_target._x += vector._x * speed;   // Add our acceleration to our view's X
 	_target._z += vector._z * speed;   // Add our acceleration to our view's Z
 }
 
-bool Camera3D::loadFrom3DS(Common::MemoryReadStream &fileStream) {
-	uint32 wholeChunkSize = fileStream.readUint32LE();
-	int32 end = fileStream.pos() + wholeChunkSize - 6;
-
-	_position._x = fileStream.readFloatLE();
-	_position._z = fileStream.readFloatLE();
-	_position._y = fileStream.readFloatLE();
-
-	_target._x = fileStream.readFloatLE();
-	_target._z = fileStream.readFloatLE();
-	_target._y = fileStream.readFloatLE();
-
-	_bank = fileStream.readFloatLE();
-
-	float lens = fileStream.readFloatLE();
-
-	if (lens > 0.0f) {
-		_fov = degToRad(1900.0f / lens);
-	} else {
-		_fov = degToRad(45.0f);
-	}
-
-	_origFov = _fov;
-
-	// discard all subchunks
-	while (fileStream.pos() < end) {
-		fileStream.readUint16LE(); // chunk id
-		uint32 chunkSize = fileStream.readUint32LE();
-
-		fileStream.seek(chunkSize - 6, SEEK_CUR);
-	}
-
-	return true;
-}
-
 } // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/3dcamera.h b/engines/wintermute/base/gfx/3dcamera.h
index f95b226be2b..ccc11e2e906 100644
--- a/engines/wintermute/base/gfx/3dcamera.h
+++ b/engines/wintermute/base/gfx/3dcamera.h
@@ -33,9 +33,6 @@
 #include "engines/wintermute/base/base_named_object.h"
 #include "engines/wintermute/base/gfx/xmath.h"
 
-#include "math/matrix4.h"
-#include "math/vector3d.h"
-
 namespace Wintermute {
 
 class Camera3D : public BaseNamedObject {
@@ -47,15 +44,13 @@ public:
 	Camera3D(BaseGame *inGame);
 	virtual ~Camera3D();
 
-	DXVector3 _position;
+	DXVector3 _pos;
 	DXVector3 _target;
 	float _bank;
 	float _fov;
 	float _origFov;
 	float _nearClipPlane;
 	float _farClipPlane;
-
-	bool loadFrom3DS(Common::MemoryReadStream &fileStream);
 };
 
 } // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/3dface.cpp b/engines/wintermute/base/gfx/3dface.cpp
new file mode 100644
index 00000000000..45c3d2fd89f
--- /dev/null
+++ b/engines/wintermute/base/gfx/3dface.cpp
@@ -0,0 +1,49 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * This file is based on WME.
+ * http://dead-code.org/redir.php?target=wme
+ * Copyright (c) 2003-2013 Jan Nedoma and contributors
+ */
+
+#include "engines/wintermute/base/gfx/3dface.h"
+#include "engines/wintermute/dcgf.h"
+
+namespace Wintermute {
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////
+Face3D::Face3D() {
+	for (int i = 0; i < 3; i++) {
+		_normals[i] = DXVector3(0, 0, 0);
+		_vertices[i] = 0;
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////
+Face3D::~Face3D() {
+}
+
+} // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/3dface.h b/engines/wintermute/base/gfx/3dface.h
new file mode 100644
index 00000000000..397416f72e0
--- /dev/null
+++ b/engines/wintermute/base/gfx/3dface.h
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * This file is based on WME.
+ * http://dead-code.org/redir.php?target=wme
+ * Copyright (c) 2003-2013 Jan Nedoma and contributors
+ */
+
+#ifndef WINTERMUTE_3D_FACE_H
+#define WINTERMUTE_3D_FACE_H
+
+#include "engines/wintermute/base/gfx/xmath.h"
+
+namespace Wintermute {
+
+class Face3D {
+public:
+	Face3D();
+	virtual ~Face3D();
+
+	uint16 _vertices[3];
+	DXVector3 _normals[3];
+};
+
+} // namespace Wintermute
+
+#endif
diff --git a/engines/wintermute/base/gfx/3dlight.cpp b/engines/wintermute/base/gfx/3dlight.cpp
index 758132d098f..7dbb5dd23aa 100644
--- a/engines/wintermute/base/gfx/3dlight.cpp
+++ b/engines/wintermute/base/gfx/3dlight.cpp
@@ -41,7 +41,7 @@ namespace Wintermute {
 //////////////////////////////////////////////////////////////////////////
 Light3D::Light3D(BaseGame *inGame) : BaseScriptable(inGame, false, false) {
 	_diffuseColor = BYTETORGBA(255, 255, 255, 255);
-	_position = DXVector3(0, 0, 0);
+	_pos = DXVector3(0, 0, 0);
 	_target = DXVector3(0, 0, 0);
 	_isSpotlight = false;
 	_falloff = 0;
@@ -63,7 +63,7 @@ bool Light3D::setLight(int index) {
 	diffuse._z = RGBCOLGetB(_diffuseColor) / 256.0f;
 	diffuse._w = 1.0f;
 
-	_gameRef->_renderer3D->setLightParameters(index, _position, _target - _position, diffuse, _isSpotlight);
+	_gameRef->_renderer3D->setLightParameters(index, _pos, _target - _pos, diffuse, _isSpotlight);
 
 	if (_active) {
 		_gameRef->_renderer3D->lightEnable(index, true);
@@ -75,7 +75,7 @@ bool Light3D::setLight(int index) {
 //////////////////////////////////////////////////////////////////////////
 bool Light3D::getViewMatrix(DXMatrix *viewMatrix) {
 	DXVector3 up = DXVector3(0.0f, 1.0f, 0.0f);
-	DXMatrixLookAtLH(viewMatrix, &_position, &_target, &up);
+	DXMatrixLookAtLH(viewMatrix, &_pos, &_target, &up);
 	return true;
 }
 
@@ -86,73 +86,4 @@ bool Light3D::persist(BasePersistenceManager *persistMgr) {
 	return true;
 }
 
-bool Light3D::loadFrom3DS(Common::MemoryReadStream &fileStream) {
-	uint32 wholeChunkSize = fileStream.readUint32LE();
-	int32 end = fileStream.pos() + wholeChunkSize - 6;
-
-	_position._x = fileStream.readFloatLE();
-	_position._z = fileStream.readFloatLE();
-	_position._y = fileStream.readFloatLE();
-
-	while (fileStream.pos() < end) {
-		uint16 chunkId = fileStream.readUint16LE();
-		uint32 chunkSize = fileStream.readUint32LE();
-
-		switch (chunkId) {
-		case SPOTLIGHT:
-			_target._x = fileStream.readFloatLE();
-			_target._z = fileStream.readFloatLE();
-			_target._y = fileStream.readFloatLE();
-
-			// this is appearently not used
-			fileStream.readFloatLE();
-
-			_falloff = fileStream.readFloatLE();
-			_isSpotlight = true;
-			break;
-
-		case LIGHT_IS_OFF:
-			_active = false;
-			break;
-
-		case RGB_BYTE: {
-			byte r = fileStream.readByte();
-			byte g = fileStream.readByte();
-			byte b = fileStream.readByte();
-
-			_diffuseColor = r << 16;
-			_diffuseColor |= g << 8;
-			_diffuseColor |= b;
-			_diffuseColor |= 255 << 24;
-			break;
-		}
-
-		case RGB_FLOAT: {
-			float r = fileStream.readFloatLE();
-			float g = fileStream.readFloatLE();
-			float b = fileStream.readFloatLE();
-
-			_diffuseColor = static_cast<int32>(r * 255) << 16;
-			_diffuseColor |= static_cast<int32>(g * 255) << 8;
-			_diffuseColor |= static_cast<int32>(b * 255);
-			_diffuseColor |= 255 << 24;
-			break;
-		}
-
-		case RANGE_END:
-		case 0x4659:
-		case MULTIPLIER:
-		case ROLL:
-		case SPOT_SHADOW_MAP:
-		case SPOT_RAY_TRACE_BIAS:
-		case SPOT_RAY_TRACE:
-		default:
-			fileStream.seek(chunkSize - 6, SEEK_CUR);
-			break;
-		}
-	}
-
-	return true;
-}
-
 } // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/3dlight.h b/engines/wintermute/base/gfx/3dlight.h
index d18921e7408..e8427f8d39e 100644
--- a/engines/wintermute/base/gfx/3dlight.h
+++ b/engines/wintermute/base/gfx/3dlight.h
@@ -45,7 +45,7 @@ public:
 	Light3D(BaseGame *inGame);
 	virtual ~Light3D();
 	uint32 _diffuseColor;
-	DXVector3 _position;
+	DXVector3 _pos;
 	DXVector3 _target;
 	bool _isSpotlight;
 	bool _active;
@@ -55,7 +55,6 @@ public:
 	bool _isAvailable;
 
 	bool setLight(int index = 0);
-	bool loadFrom3DS(Common::MemoryReadStream &fileStream);
 };
 
 } // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/3dloader_3ds.cpp b/engines/wintermute/base/gfx/3dloader_3ds.cpp
index 8771e0d14eb..6b4d3ac5903 100644
--- a/engines/wintermute/base/gfx/3dloader_3ds.cpp
+++ b/engines/wintermute/base/gfx/3dloader_3ds.cpp
@@ -19,109 +19,406 @@
  *
  */
 
-#include "common/memstream.h"
-
+#include "engines/wintermute/dcgf.h"
+#include "engines/wintermute/math/math_util.h"
 #include "engines/wintermute/base/base_file_manager.h"
-#include "engines/wintermute/base/base_game.h"
-#include "engines/wintermute/base/gfx/base_renderer3d.h"
-#include "engines/wintermute/base/gfx/3dcamera.h"
-#include "engines/wintermute/base/gfx/3dlight.h"
 #include "engines/wintermute/base/gfx/3dloader_3ds.h"
-#include "engines/wintermute/base/gfx/3dmesh.h"
+#include "engines/wintermute/base/gfx/3dface.h"
+#include "engines/wintermute/base/gfx/3dvertex.h"
 
 namespace Wintermute {
 
-bool load3DSObject(Common::MemoryReadStream &fileStream, BaseArray<Wintermute::Mesh3DS *> &meshes, BaseArray<Common::String> &meshNames,
-	           BaseArray<Wintermute::Light3D *> &lights, BaseArray<Wintermute::Camera3D *> &cameras, BaseGame *gameRef) {
-	uint32 wholeChunkSize = fileStream.readUint32LE();
-	int32 end = fileStream.pos() + wholeChunkSize - 6;
+#define MAIN3DS               0x4D4D // level 1
+#define EDIT3DS               0x3D3D // level 1
+#define NAMED_OBJECT          0x4000 // level 2
+#define TRIANGLE_MESH         0x4100 // level 3
+#define TRIANGLE_VERTEXLIST   0x4110 // level 4
+#define TRIANGLE_FACELIST     0x4120 // level 4
+#define CHUNK_CAMERA          0x4700 // level 3
+#define CHUNK_LIGHT           0x4600
+#define LIGHT_SPOTLIGHT       0x4610
+#define LIGHT_IS_OFF          0x4620
+#define RGB_FLOAT             0x0010
+#define RGB_BYTE              0x0011
+
+
+//////////////////////////////////////////////////////////////////////////
+Loader3DS::Loader3DS(BaseGame *inGame) : BaseNamedObject(inGame) {
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+Loader3DS::~Loader3DS() {
+	for (size_t i = 0; i < _objects.size(); i++)
+		delete _objects[i];
+	_objects.clear();
+}
 
-	Common::String name;
-	for (int8 current = fileStream.readByte(); current != 0; current = fileStream.readByte()) {
-		name.insertChar(current, name.size());
-	}
 
-	while (fileStream.pos() < end) {
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+Loader3DS::FileObject3DS::FileObject3DS() {
+	_type = OBJ_3DS_NONE;
+
+	_numVertices = 0;
+	_vertices = nullptr;
+
+	_numFaces = 0;
+	_faces = nullptr;
+
+	_lightOff = false;
+	_lightSpotlight = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+Loader3DS::FileObject3DS::~FileObject3DS() {
+	if (_vertices != NULL)
+		delete[] _vertices;
+	if (_faces != NULL)
+		delete[] _faces;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool Loader3DS::parseFile(const Common::String &filename) {
+	_filename = filename;
+
+	uint32 fileSize;
+	byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename, &fileSize);
+	if (!buffer)
+		return false;
+
+	FileObject3DS *obj = nullptr;
+	uint16 i;
+
+	Common::MemoryReadStream fileStream(buffer, fileSize);
+
+	while (fileStream.pos() < fileStream.size()) {
 		uint16 chunkId = fileStream.readUint16LE();
+		uint32 chunkLength = fileStream.readUint32LE();
 
-		Mesh3DS *mesh;
-		Light3D *light;
-		Camera3D *camera;
+		bool handled = true;
 
 		switch (chunkId) {
-		case MESH:
-			mesh = gameRef->_renderer3D->createMesh3DS();
-			if (mesh->loadFrom3DS(fileStream)) {
-				meshNames.add(name);
-				meshes.add(mesh);
-			} else {
-				delete mesh;
-			}
+			case MAIN3DS:
 			break;
 
-		case LIGHT:
-			light = new Light3D(gameRef);
-			if (light->loadFrom3DS(fileStream)) {
-				light->setName(name.c_str());
-				lights.add(light);
-			} else {
-				delete light;
-			}
+			case EDIT3DS:
 			break;
 
-		case CAMERA:
-			camera = new Camera3D(gameRef);
-			if (camera->loadFrom3DS(fileStream)) {
-				camera->setName(name.c_str());
-				cameras.add(camera);
-			} else {
-				delete camera;
+			//////////////////////////////////////////////////////////////////////
+			// object ////////////////////////////////////////////////////////////
+			case NAMED_OBJECT: {
+				Common::String name;
+				for (int8 current = fileStream.readByte(); current != 0; current = fileStream.readByte()) {
+					name.insertChar(current, name.size());
+				}
+				obj = new FileObject3DS;
+				obj->_name = name;
+				_objects.add(obj);
 			}
 			break;
 
-		default:
+
+			// mesh //////////////////////////////////////////////////////////////
+			case TRIANGLE_MESH:
+				if (obj == nullptr)
+					break;
+				obj->_type = OBJ_3DS_MESH;
+			break;
+
+
+			case TRIANGLE_VERTEXLIST:
+				if (obj == nullptr || obj->_type != OBJ_3DS_MESH)
+					break;
+
+				obj->_numVertices = fileStream.readUint16LE();
+				obj->_vertices = new DXVector3[obj->_numVertices];
+				for (i = 0; i < obj->_numVertices; i++) {
+					obj->_vertices[i]._x = fileStream.readFloatLE();
+					obj->_vertices[i]._z = fileStream.readFloatLE();
+					obj->_vertices[i]._y = fileStream.readFloatLE();
+				}
+			break;
+
+
+			case TRIANGLE_FACELIST:
+				if (obj == nullptr || obj->_type != OBJ_3DS_MESH)
+					break;
+
+				obj->_numFaces = fileStream.readUint16LE();
+
+				obj->_faces = new SFace[obj->_numFaces];
+				for (i = 0; i < obj->_numFaces; i++) {
+					obj->_faces[i]._a = fileStream.readUint16LE();
+					obj->_faces[i]._c = fileStream.readUint16LE();
+					obj->_faces[i]._b = fileStream.readUint16LE();
+					fileStream.readUint16LE(); // skip
+				}
+			break;
+
+
+			// camera //////////////////////////////////////////////////////////////
+			case CHUNK_CAMERA:
+				if (obj == nullptr)
+					break;
+				obj->_type = OBJ_3DS_CAMERA;
+
+				obj->_cameraPos._x = fileStream.readFloatLE();
+				obj->_cameraPos._z = fileStream.readFloatLE();
+				obj->_cameraPos._y = fileStream.readFloatLE();
+
+				obj->_cameraTarget._x = fileStream.readFloatLE();
+				obj->_cameraTarget._z = fileStream.readFloatLE();
+				obj->_cameraTarget._y = fileStream.readFloatLE();
+				
+				obj->_cameraBank = fileStream.readFloatLE();
+				obj->_cameraLens = fileStream.readFloatLE();
+				if (obj->_cameraLens > 0)
+					obj->_cameraFOV = 1900.0f / obj->_cameraLens;
+				else
+					obj->_cameraFOV = 45.0f;
+			break;
+
+
+			// light //////////////////////////////////////////////////////////////
+			case CHUNK_LIGHT:
+				if (obj == nullptr)
+					break;
+				obj->_type = OBJ_3DS_LIGHT;
+
+				obj->_lightPos._x = fileStream.readFloatLE();
+				obj->_lightPos._z = fileStream.readFloatLE();
+				obj->_lightPos._y = fileStream.readFloatLE();
+			break;
+
+			case LIGHT_SPOTLIGHT:
+				if (obj == nullptr || obj->_type != OBJ_3DS_LIGHT)
+					break;
+
+				obj->_lightTarget._x = fileStream.readFloatLE();
+				obj->_lightTarget._z = fileStream.readFloatLE();
+				obj->_lightTarget._y = fileStream.readFloatLE();
+
+				obj->_lightHotspot = fileStream.readFloatLE();
+				obj->_lightFalloff = fileStream.readFloatLE();
+				obj->_lightSpotlight = true;
+			break;
+
+			case LIGHT_IS_OFF:
+				if (obj == nullptr || obj->_type != OBJ_3DS_LIGHT)
+					break;
+
+				obj->_lightOff = true;
+			break;
+
+
+			// colors ////////////////////////////////////////////////////////////////////////
+			case RGB_FLOAT:
+				if (obj && obj->_type == OBJ_3DS_LIGHT) {
+					float r, g, b;
+					r = fileStream.readFloatLE();
+					g = fileStream.readFloatLE();
+					b = fileStream.readFloatLE();
+
+					obj->_lightColor = BYTETORGBA((int)(r * 255), (int)(g * 255), (int)(b * 255), 255);
+				} else
+					handled = false;
+			break;
+
+			case RGB_BYTE:
+				if (obj && obj->_type == OBJ_3DS_LIGHT) {
+					byte r, g, b;
+					r = fileStream.readByte();
+					g = fileStream.readByte();
+					b = fileStream.readByte();
+
+					obj->_lightColor = BYTETORGBA(r, g, b, 255);
+				} else
+					handled = false;
 			break;
+
+			default:
+				handled = false;
 		}
+
+		if (!handled)
+			fileStream.seek(chunkLength - 6, SEEK_CUR);
 	}
 
+	delete[] buffer;
+
 	return true;
 }
 
-bool load3DSFile(const char *filename, BaseArray<Wintermute::Mesh3DS *> &meshes, BaseArray<Common::String> &meshNames,
-	         BaseArray<Wintermute::Light3D *> &lights, BaseArray<Wintermute::Camera3D *> &cameras, BaseGame *gameRef) {
-	uint32 fileSize = 0;
-	byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename, &fileSize);
 
-	if (buffer == nullptr) {
-		return false;
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+uint Loader3DS::getNumMeshes() {
+	int ret = 0;
+
+	for (size_t i = 0; i < _objects.size(); i++)
+		if (_objects[i]->_type == OBJ_3DS_MESH)
+			ret++;
+
+	return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+Common::String Loader3DS::getMeshName(int index) {
+	int pos = -1;
+
+	for (size_t i = 0; i < _objects.size(); i++) {
+		if (_objects[i]->_type == OBJ_3DS_MESH)
+			pos++;
+		if (pos == index)
+			return _objects[i]->_name;
 	}
+	return Common::String();
+}
 
-	Common::MemoryReadStream fileStream(buffer, fileSize);
 
-	while (fileStream.pos() < fileStream.size()) {
-		uint16 chunkId = fileStream.readUint16LE();
-		uint32 chunkSize = 0;
+//////////////////////////////////////////////////////////////////////////
+bool Loader3DS::loadMesh(int index, Mesh3DS *mesh) {
+	if (!mesh)
+		return false;
 
-		switch (chunkId) {
-		case MAIN:
-		case EDITOR:
-			chunkSize = fileStream.readUint32LE();
-			break;
+	int pos = -1;
+	for (size_t i = 0; i < _objects.size(); i++) {
+		if (_objects[i]->_type == OBJ_3DS_MESH)
+			pos++;
+		if (pos == index){
+			FileObject3DS *obj = _objects[i];
+			mesh->cleanup();
 
-		case OBJECT:
-			load3DSObject(fileStream, meshes, meshNames, lights, cameras, gameRef);
-			break;
+			mesh->_numVertices = obj->_numVertices;
+			mesh->_numFaces = obj->_numFaces;
 
-		default:
-			chunkSize = fileStream.readUint32LE();
-			fileStream.seek(chunkSize - 6, SEEK_CUR);
-			break;
+			int j;
+
+			mesh->_vertices = new Vertex3D[mesh->_numVertices];
+			for (j = 0; j < mesh->_numVertices; j++) {
+				mesh->_vertices[j]._pos._x = obj->_vertices[j]._x;
+				mesh->_vertices[j]._pos._y = obj->_vertices[j]._y;
+				mesh->_vertices[j]._pos._z = obj->_vertices[j]._z;
+			}
+
+			mesh->_faces = new Face3D[mesh->_numFaces];
+			for (j = 0; j < mesh->_numFaces; j++) {
+				mesh->_faces[j]._vertices[0] = obj->_faces[j]._a;
+				mesh->_faces[j]._vertices[1] = obj->_faces[j]._b;
+				mesh->_faces[j]._vertices[2] = obj->_faces[j]._c;
+			}
+
+			mesh->setName(obj->_name.c_str());
+
+			return true;
 		}
 	}
+	return false;
+}
 
-	delete[] buffer;
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+uint Loader3DS::getNumLights() {
+	int ret = 0;
+
+	for (size_t i = 0; i < _objects.size(); i++)
+		if (_objects[i]->_type == OBJ_3DS_LIGHT)
+			ret++;
+
+	return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+Common::String Loader3DS::getLightName(int index) {
+	int pos = -1;
+
+	for (size_t i = 0; i < _objects.size(); i++) {
+		if (_objects[i]->_type == OBJ_3DS_LIGHT)
+			pos++;
+		if (pos == index)
+			return _objects[i]->_name;
+	}
+	return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool Loader3DS::loadLight(int index, Light3D *light) {
+	if (!light)
+		return false;
+
+	int pos = -1;
+	for (size_t i = 0; i < _objects.size(); i++) {
+		if (_objects[i]->_type == OBJ_3DS_LIGHT) {
+			pos++;
+			if (pos == index) {
+				light->setName(_objects[i]->_name.c_str());
+				light->_pos = _objects[i]->_lightPos;
+				light->_target = _objects[i]->_lightTarget;
+				light->_isSpotlight = _objects[i]->_lightSpotlight;
+				light->_active = !_objects[i]->_lightOff;
+				light->_diffuseColor = _objects[i]->_lightColor;
+				light->_falloff = _objects[i]->_lightFalloff;
+			}
+		}
+	}
 
 	return true;
 }
 
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+uint Loader3DS::getNumCameras() {
+	int ret = 0;
+
+	for (size_t i = 0; i < _objects.size(); i++)
+		if (_objects[i]->_type == OBJ_3DS_CAMERA)
+			ret++;
+
+	return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+Common::String Loader3DS::getCameraName(int index) {
+	int pos = -1;
+	for (size_t i = 0; i < _objects.size(); i++) {
+		if (_objects[i]->_type == OBJ_3DS_CAMERA)
+			pos++;
+		if (pos == index)
+			return _objects[i]->_name;
+	}
+	return Common::String();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool Loader3DS::loadCamera(int index, Camera3D *camera) {
+	if (!camera) return
+		false;
+
+	int pos = -1;
+	for (size_t i = 0; i < _objects.size(); i++) {
+		if (_objects[i]->_type == OBJ_3DS_CAMERA)
+			pos++;
+		if (pos == index) {
+			camera->setupPos(_objects[i]->_cameraPos, _objects[i]->_cameraTarget, _objects[i]->_cameraBank);
+			camera->setName(_objects[i]->_name.c_str());
+			camera->_fov = camera->_origFov = degToRad(_objects[i]->_cameraFOV);
+
+			return true;
+		}
+	}
+	return false;
+}
+
 } // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/3dloader_3ds.h b/engines/wintermute/base/gfx/3dloader_3ds.h
index 519252abe8a..7d5b383f395 100644
--- a/engines/wintermute/base/gfx/3dloader_3ds.h
+++ b/engines/wintermute/base/gfx/3dloader_3ds.h
@@ -23,51 +23,70 @@
 #define WINTERMUTE_3D_LOADER_3DS_H
 
 #include "engines/wintermute/coll_templ.h"
+#include "engines/wintermute/base/base_named_object.h"
+#include "engines/wintermute/base/gfx/3dcamera.h"
+#include "engines/wintermute/base/gfx/3dlight.h"
+#include "engines/wintermute/base/gfx/3dmesh.h"
+
+#include "common/str.h"
 
 namespace Wintermute {
 
-class BaseGame;
-class Light3D;
-class Camera3D;
-class Mesh3DS;
+class Loader3DS : public BaseNamedObject {
+public:
+	enum E3DSFileObjectType{
+		OBJ_3DS_NONE, OBJ_3DS_MESH, OBJ_3DS_CAMERA, OBJ_3DS_LIGHT
+	};
+
+	struct SFace{
+		uint16 _a;
+		uint16 _b;
+		uint16 _c;
+	};
 
-bool load3DSFile(const char *filename, BaseArray<Mesh3DS *> &meshes, BaseArray<Common::String> &meshNames,
-                 BaseArray<Light3D *> &lights, BaseArray<Camera3D *> &cameras, BaseGame *gameRef);
+	class FileObject3DS {
+	public:
+		DXVector3 _cameraTarget;
+		float _cameraBank;
+		float _cameraLens;
+		float _cameraFOV;
+		DXVector3 _cameraPos;
+		DXVector3 _lightTarget;
+		DXVector3 _lightPos;
+		uint32 _lightColor;
+		float _lightHotspot;
+		float _lightFalloff;
+		bool _lightOff;
+		bool _lightSpotlight;
+		bool _hidden;
+		uint16 _numCoordinates;
+		uint16 _numFaces;
+		SFace *_faces;
+		DXVector3 *_vertices;
+		uint16 _numVertices;
+		Common::String _name;
+		E3DSFileObjectType _type;
+		virtual ~FileObject3DS();
+		FileObject3DS();
+	};
 
-enum Chunks3DS {
-	RGB_FLOAT = 0x0010,
-	RGB_BYTE = 0x0011,
-	EDITOR = 0x3D3D,
-	OBJECT = 0x4000,
-	MESH = 0x4100,
-	VERTICES = 0x4110,
-	FACES = 0x4120,
-	FACES_MATERIAL = 0x4130,
-	MAPPING_COORDS = 0x4140,
-	SMOOTHING_GROUPS = 0x4150,
-	LOCAL_COORDS = 0x4160,
-	LIGHT = 0x4600,
-	SPOTLIGHT = 0x4610,
-	LIGHT_IS_OFF = 0x4620,
-	SPOT_RAY_TRACE = 0x4627,
-	SPOT_SHADOW_MAP = 0x4641,
-	ROLL = 0x4656,
-	SPOT_RAY_TRACE_BIAS = 0x4658,
-	RANGE_END = 0x465A,
-	MULTIPLIER = 0x465B,
-	CAMERA = 0x4700,
-	MAIN = 0x4D4D,
-	KEYFRAMER = 0xB000,
-	AMBIENT_INFO = 0xB001,
-	MESH_INFO = 0xB002,
-	CAMERA_INFO = 0xB003,
-	CAMERA_TARGET_INFO = 0xB004,
-	OMNI_LIGHT_INFO = 0xB005,
-	SPOTLIGHT_TARGET_INFO = 0xB006,
-	SPOTLIGHT_INFO = 0xB007,
-	NODE_HEADER = 0xB010,
-	ROLL_TRACK = 0xB024
+public:
+	Common::String getCameraName(int index);
+	Common::String getLightName(int index);
+	Common::String getMeshName(int index);
+	bool loadCamera(int index, Camera3D *camera);
+	uint getNumCameras();
+	bool loadLight(int index, Light3D *light);
+	uint getNumLights();
+	bool loadMesh(int index, Mesh3DS *mesh);
+	uint getNumMeshes();
+	bool parseFile(const Common::String &filename);
+	Common::String _filename;
+	Loader3DS(BaseGame *inGame);
+	virtual ~Loader3DS();
+	BaseArray<FileObject3DS *> _objects;
 };
 
 } // namespace Wintermute
+
 #endif
diff --git a/engines/wintermute/base/gfx/3dmesh.cpp b/engines/wintermute/base/gfx/3dmesh.cpp
index 7680f489386..fd734e6ccf8 100644
--- a/engines/wintermute/base/gfx/3dmesh.cpp
+++ b/engines/wintermute/base/gfx/3dmesh.cpp
@@ -19,86 +19,131 @@
  *
  */
 
+/*
+ * This file is based on WME.
+ * http://dead-code.org/redir.php?target=wme
+ * Copyright (c) 2003-2013 Jan Nedoma and contributors
+ */
+
 #include "common/file.h"
 
+#include "engines/wintermute/base/base_game.h"
 #include "engines/wintermute/base/gfx/3dloader_3ds.h"
 #include "engines/wintermute/base/gfx/3dmesh.h"
 
 namespace Wintermute {
 
-Mesh3DS::Mesh3DS() : _vertexData(nullptr), _vertexCount(0), _indexData(nullptr), _indexCount(0) {
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////
+Mesh3DS::Mesh3DS(BaseGame *inGame) : BaseNamedObject(inGame) {
+	_vertices = nullptr;
+	_faces = nullptr;
+	_numFaces = _numVertices = 0;
+	_visible = true;
 }
 
+//////////////////////////////////////////////////////////////////////////
 Mesh3DS::~Mesh3DS() {
-	delete[] _vertexData;
-	delete[] _indexData;
+	cleanup();
 }
 
-bool Mesh3DS::loadFrom3DS(Common::MemoryReadStream &fileStream) {
-	uint32 wholeChunkSize = fileStream.readUint32LE();
-	int32 end = fileStream.pos() + wholeChunkSize - 6;
-
-	while (fileStream.pos() < end) {
-		uint16 chunkId = fileStream.readUint16LE();
-		uint32 chunkSize = fileStream.readUint32LE();
-
-		switch (chunkId) {
-		case VERTICES:
-			_vertexCount = fileStream.readUint16LE();
-			_vertexData = new GeometryVertex[_vertexCount]();
-
-			for (int i = 0; i < _vertexCount; ++i) {
-				_vertexData[i].x = fileStream.readFloatLE();
-				_vertexData[i].z = fileStream.readFloatLE();
-				_vertexData[i].y = fileStream.readFloatLE();
-			}
-			break;
-
-		case FACES: {
-			uint16 faceCount = fileStream.readUint16LE();
-			_indexCount = 3 * faceCount;
-			_indexData = new uint16[_indexCount];
-
-			for (int i = 0; i < faceCount; ++i) {
-				_indexData[i * 3 + 0] = fileStream.readUint16LE();
-				_indexData[i * 3 + 2] = fileStream.readUint16LE();
-				_indexData[i * 3 + 1] = fileStream.readUint16LE();
-				fileStream.readUint16LE(); // not used
-			}
-			break;
-		}
-		case FACES_MATERIAL:
-		case MAPPING_COORDS:
-		case LOCAL_COORDS:
-		case SMOOTHING_GROUPS:
-		default:
-			fileStream.seek(chunkSize - 6, SEEK_CUR);
-			break;
+//////////////////////////////////////////////////////////////////////////
+void Mesh3DS::cleanup() {
+	delete[] _vertices;
+	_vertices = nullptr;
+	_numVertices = 0;
+
+	delete[] _faces;
+	_faces = nullptr;
+	_numFaces = 0;
+
+	_vb.free();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool Mesh3DS::createVertexBuffer() {
+	_vb.free();
+
+	if (_numFaces == 0)
+		return true;
+
+	int vbSize = _numFaces * sizeof(Mesh3DSVertex) * 3;
+	_vb = DXBuffer(vbSize);
+	if (_vb.ptr() == nullptr) {
+		_gameRef->LOG(0, "Error creating vertex buffer.");
+		return false;
+	} else
+		return true;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool Mesh3DS::fillVertexBuffer(uint32 color) {
+	_vb.free();
+
+	if (_numFaces == 0)
+		return true;
+
+	int vbSize = _numFaces * sizeof(Mesh3DSVertex) * 3;
+	_vb = DXBuffer(vbSize);
+	if (_vb.ptr() == nullptr) {
+		_gameRef->LOG(0, "Error creating vertex buffer.");
+		return false;
+	}
+
+	Mesh3DSVertex *verts = (Mesh3DSVertex *)_vb.ptr();
+
+	for (int i = 0; i < _numFaces; i++) {
+		for (int j = 0; j < 3; j++) {
+			int iOutVert = i * 3 + j;
+			int iVertex = _faces[i]._vertices[j];
+
+			verts[iOutVert]._x  = _vertices[iVertex]._pos._x;
+			verts[iOutVert]._y  = _vertices[iVertex]._pos._y;
+			verts[iOutVert]._z  = _vertices[iVertex]._pos._z;
+
+			verts[iOutVert]._nx = _faces[i]._normals[j]._x;
+			verts[iOutVert]._ny = _faces[i]._normals[j]._y;
+			verts[iOutVert]._nz = _faces[i]._normals[j]._z;
+
+			verts[iOutVert]._r = RGBCOLGetR(color) / 255.0f;
+			verts[iOutVert]._g = RGBCOLGetG(color) / 255.0f;
+			verts[iOutVert]._b = RGBCOLGetB(color) / 255.0f;
+			verts[iOutVert]._a = RGBCOLGetA(color) / 255.0f;
 		}
 	}
 
+	fillVertexBuffer();
+
 	return true;
 }
 
+
+//////////////////////////////////////////////////////////////////////////
 void Mesh3DS::computeNormals() {
-	DXVector3 *normals = new DXVector3[_vertexCount];
-	for (int i = 0; i < _vertexCount; ++i) {
+	DXVector3 *normals = new DXVector3[_numVertices];
+	for (int i = 0; i < _numVertices; ++i) {
 		normals[i]._x = 0.0f;
 		normals[i]._y = 0.0f;
 		normals[i]._z = 0.0f;
 	}
 
-	for (int i = 0; i < faceCount(); ++i) {
-		uint16 a = _indexData[3 * i + 0];
-		uint16 b = _indexData[3 * i + 1];
-		uint16 c = _indexData[3 * i + 2];
+	for (int i = 0; i < _numFaces; ++i) {
+		uint16 a = _faces[i]._vertices[0];
+		uint16 b = _faces[i]._vertices[1];
+		uint16 c = _faces[i]._vertices[2];
 
-		DXVector3 v1(getVertexPosition(a));
-		DXVector3 v2(getVertexPosition(b));
-		DXVector3 v3(getVertexPosition(c));
+		DXVector3 *v1 = &_vertices[a]._pos;
+		DXVector3 *v2 = &_vertices[b]._pos;
+		DXVector3 *v3 = &_vertices[c]._pos;
 
-		DXVector3 edge1 = v2 - v1;
-		DXVector3 edge2 = v3 - v2;
+		DXVector3 edge1 = *v2 - *v1;
+		DXVector3 edge2 = *v3 - *v2;
 		DXVector3 normal;
 		DXVec3Cross(&normal, &edge1, &edge2);
 		DXVec3Normalize(&normal, &normal);
@@ -109,50 +154,20 @@ void Mesh3DS::computeNormals() {
 	}
 
 	// Assign the newly computed normals back to the vertices
-	for (int i = 0; i < faceCount(); ++i) {
+	for (int i = 0; i < _numFaces; ++i) {
 		for (int j = 0; j < 3; j++) {
-			DXVector3 normal;
-			DXVec3Normalize(&normal, &normals[_indexData[3 * i + j]]);
-			//_vertexData[_indexData[3 * i + j]].nx = normal._x;
-			//_vertexData[_indexData[3 * i + j]].ny = normal._y;
-			//_vertexData[_indexData[3 * i + j]].nz = normal._z;
+			DXVec3Normalize(&_faces[i]._normals[j], &normals[_faces[i]._vertices[j]]);
+			//_faces[i]._normals[j] = normals[_faces[i]._vertices[j]];
 		}
 	}
 
 	delete[] normals;
 }
 
-void Mesh3DS::dumpVertexCoordinates(const char *filename) {
-	Common::DumpFile dump;
-	dump.open(filename);
-
-	for (uint16 *index = _indexData; index < _indexData + _indexCount; ++index) {
-		float x = _vertexData[*index].x;
-		float y = _vertexData[*index].y;
-		float z = _vertexData[*index].z;
-
-		dump.writeString(Common::String::format("%u ", *index));
-		dump.writeString(Common::String::format("%g ", x));
-		dump.writeString(Common::String::format("%g ", y));
-		dump.writeString(Common::String::format("%g\n", z));
-	}
-}
-
-int Mesh3DS::faceCount() {
-	// .3ds files have only triangles anyways
-	return _indexCount / 3;
-}
-
-uint16 *Mesh3DS::getFace(int index) {
-	return _indexData + 3 * index;
-}
-
-float *Mesh3DS::getVertexPosition(int index) {
-	return reinterpret_cast<float *>(&((_vertexData + index)->x));
-}
-
-int Wintermute::Mesh3DS::vertexCount() {
-	return _vertexCount;
+//////////////////////////////////////////////////////////////////////////
+bool Mesh3DS::persist(BasePersistenceManager *persistMgr) {
+	persistMgr->transferBool(TMEMBER(_visible));
+	return true;
 }
 
 } // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/3dmesh.h b/engines/wintermute/base/gfx/3dmesh.h
index f889e1a992a..e9810d3903a 100644
--- a/engines/wintermute/base/gfx/3dmesh.h
+++ b/engines/wintermute/base/gfx/3dmesh.h
@@ -19,47 +19,57 @@
  *
  */
 
+/*
+ * This file is based on WME.
+ * http://dead-code.org/redir.php?target=wme
+ * Copyright (c) 2003-2013 Jan Nedoma and contributors
+ */
+
 #ifndef WINTERMUTE_3D_MESH_H
 #define WINTERMUTE_3D_MESH_H
 
 #include "common/memstream.h"
 
-#include "math/vector4d.h"
-
+#include "engines/wintermute/base/base_named_object.h"
 #include "engines/wintermute/base/gfx/xmath.h"
+#include "engines/wintermute/base/gfx/xbuffer.h"
+#include "engines/wintermute/base/gfx/3dface.h"
+#include "engines/wintermute/base/gfx/3dvertex.h"
 
 namespace Wintermute {
 
-struct GeometryVertex {
-	float x;
-	float y;
-	float z;
-	float nx;
-	float ny;
-	float nz;
+#if defined(SCUMMVM_USE_PRAGMA_PACK)
+#pragma pack(4)
+#endif
+
+struct Mesh3DSVertex {
+	float _x, _y, _z;
+	float _nx, _ny, _nz;
+	float _r, _g, _b, _a;
 };
 
-class Mesh3DS {
+#if defined(SCUMMVM_USE_PRAGMA_PACK)
+#pragma pack()
+#endif
+
+class Mesh3DS : public BaseNamedObject {
 public:
-	Mesh3DS();
-	virtual ~Mesh3DS();
+	bool persist(BasePersistenceManager *persistMgr);
+	bool createVertexBuffer();
 	void computeNormals();
-	virtual void fillVertexBuffer(uint32 color) = 0;
-	virtual bool loadFrom3DS(Common::MemoryReadStream &fileStream);
+	void cleanup();
+	Mesh3DS(BaseGame *inGame);
+	virtual ~Mesh3DS();
+	bool fillVertexBuffer(uint32 color);
+	virtual void fillVertexBuffer() = 0;
 	virtual void render() = 0;
-	virtual void dumpVertexCoordinates(const char *filename);
-	virtual int faceCount();
-	virtual uint16 *getFace(int index);
-
-	virtual int vertexCount();
-	virtual float *getVertexPosition(int index);
 
-protected:
-	GeometryVertex *_vertexData;
-	uint16 _vertexCount;
-	uint16 *_indexData;
-	uint16 _indexCount;
-	DXVector4 _color;
+	Face3D *_faces;
+	uint16 _numFaces;
+	uint16 _numVertices;
+	Vertex3D *_vertices;
+	DXBuffer _vb;
+	bool _visible;
 };
 
 } // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/3dvertex.cpp b/engines/wintermute/base/gfx/3dvertex.cpp
new file mode 100644
index 00000000000..04ac27a4fb6
--- /dev/null
+++ b/engines/wintermute/base/gfx/3dvertex.cpp
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * This file is based on WME.
+ * http://dead-code.org/redir.php?target=wme
+ * Copyright (c) 2003-2013 Jan Nedoma and contributors
+ */
+
+#include "engines/wintermute/base/gfx/3dvertex.h"
+#include "engines/wintermute/dcgf.h"
+
+namespace Wintermute {
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////
+Vertex3D::Vertex3D() {
+	_pos = DXVector3(0, 0, 0);
+}
+
+//////////////////////////////////////////////////////////////////////////
+Vertex3D::~Vertex3D() {
+}
+
+} // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/3dvertex.h b/engines/wintermute/base/gfx/3dvertex.h
new file mode 100644
index 00000000000..80590412945
--- /dev/null
+++ b/engines/wintermute/base/gfx/3dvertex.h
@@ -0,0 +1,45 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * This file is based on WME.
+ * http://dead-code.org/redir.php?target=wme
+ * Copyright (c) 2003-2013 Jan Nedoma and contributors
+ */
+
+#ifndef WINTERMUTE_3D_VERTEX_H
+#define WINTERMUTE_3D_VERTEX_H
+
+#include "engines/wintermute/base/gfx/xmath.h"
+
+namespace Wintermute {
+
+class Vertex3D {
+public:
+	Vertex3D();
+	virtual ~Vertex3D();
+
+	DXVector3 _pos;
+};
+
+} // namespace Wintermute
+
+#endif
diff --git a/engines/wintermute/base/gfx/opengl/base_render_opengl3d.cpp b/engines/wintermute/base/gfx/opengl/base_render_opengl3d.cpp
index fa4c071d91c..10ba76fc9df 100644
--- a/engines/wintermute/base/gfx/opengl/base_render_opengl3d.cpp
+++ b/engines/wintermute/base/gfx/opengl/base_render_opengl3d.cpp
@@ -770,24 +770,24 @@ void BaseRenderOpenGL3D::renderSceneGeometry(const BaseArray<AdWalkplane *> &pla
 		if (lights[i]->_active) {
 			glBegin(GL_LINES);
 			glColor3f(1.0f, 1.0f, 0.0f);
-			DXVector3 right = lights[i]->_position + DXVector3(1000.0f, 0.0f, 0.0f);
-			DXVector3 up = lights[i]->_position + DXVector3(0.0f, 1000.0f, 0.0f);
-			DXVector3 backward = lights[i]->_position + DXVector3(0.0f, 0.0f, 1000.0f);
-			DXVector3 left = lights[i]->_position + DXVector3(-1000.0f, 0.0f, 0.0f);
-			DXVector3 down = lights[i]->_position + DXVector3(0.0f, -1000.0f, 0.0f);
-			DXVector3 forward = lights[i]->_position + DXVector3(0.0f, 0.0f, -1000.0f);
-
-			glVertex3fv(lights[i]->_position);
+			DXVector3 right = lights[i]->_pos + DXVector3(1000.0f, 0.0f, 0.0f);
+			DXVector3 up = lights[i]->_pos + DXVector3(0.0f, 1000.0f, 0.0f);
+			DXVector3 backward = lights[i]->_pos + DXVector3(0.0f, 0.0f, 1000.0f);
+			DXVector3 left = lights[i]->_pos + DXVector3(-1000.0f, 0.0f, 0.0f);
+			DXVector3 down = lights[i]->_pos + DXVector3(0.0f, -1000.0f, 0.0f);
+			DXVector3 forward = lights[i]->_pos + DXVector3(0.0f, 0.0f, -1000.0f);
+
+			glVertex3fv(lights[i]->_pos);
 			glVertex3fv(right);
-			glVertex3fv(lights[i]->_position);
+			glVertex3fv(lights[i]->_pos);
 			glVertex3fv(up);
-			glVertex3fv(lights[i]->_position);
+			glVertex3fv(lights[i]->_pos);
 			glVertex3fv(backward);
-			glVertex3fv(lights[i]->_position);
+			glVertex3fv(lights[i]->_pos);
 			glVertex3fv(left);
-			glVertex3fv(lights[i]->_position);
+			glVertex3fv(lights[i]->_pos);
 			glVertex3fv(down);
-			glVertex3fv(lights[i]->_position);
+			glVertex3fv(lights[i]->_pos);
 			glVertex3fv(forward);
 			glEnd();
 		}
@@ -840,7 +840,7 @@ void BaseRenderOpenGL3D::renderShadowGeometry(const BaseArray<AdWalkplane *> &pl
 }
 
 Mesh3DS *BaseRenderOpenGL3D::createMesh3DS() {
-	return new Mesh3DSOpenGL();
+	return new Mesh3DSOpenGL(_gameRef);
 }
 
 XMesh *BaseRenderOpenGL3D::createXMesh() {
diff --git a/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp b/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
index ba35b1f217f..f9908a8870b 100644
--- a/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
+++ b/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
@@ -564,7 +564,7 @@ bool BaseRenderOpenGL3DShader::initRenderer(int width, int height, bool windowed
 	_spriteShader->enableVertexAttribute("texcoord", _spriteVBO, 2, GL_FLOAT, false, sizeof(SpriteVertexShader), 8);
 	_spriteShader->enableVertexAttribute("color", _spriteVBO, 4, GL_FLOAT, false, sizeof(SpriteVertexShader), 16);
 
-	static const char *geometryAttributes[] = { "position", nullptr };
+	static const char *geometryAttributes[] = { "position", "color", nullptr };
 	_geometryShader = OpenGL::Shader::fromFiles("wme_geometry", geometryAttributes);
 
 	static const char *shadowVolumeAttributes[] = { "position", nullptr };
@@ -917,7 +917,7 @@ void BaseRenderOpenGL3DShader::renderShadowGeometry(const BaseArray<AdWalkplane
 }
 
 Mesh3DS *BaseRenderOpenGL3DShader::createMesh3DS() {
-	return new Mesh3DSOpenGLShader(_geometryShader);
+	return new Mesh3DSOpenGLShader(_gameRef, _geometryShader);
 }
 
 XMesh *BaseRenderOpenGL3DShader::createXMesh() {
diff --git a/engines/wintermute/base/gfx/opengl/mesh3ds_opengl.cpp b/engines/wintermute/base/gfx/opengl/mesh3ds_opengl.cpp
index 73b3cbe795c..2933791e556 100644
--- a/engines/wintermute/base/gfx/opengl/mesh3ds_opengl.cpp
+++ b/engines/wintermute/base/gfx/opengl/mesh3ds_opengl.cpp
@@ -29,24 +29,27 @@
 
 namespace Wintermute {
 
-Mesh3DSOpenGL::Mesh3DSOpenGL() {
+Mesh3DSOpenGL::Mesh3DSOpenGL(BaseGame *inGame) : Mesh3DS(inGame) {
 }
 
 Mesh3DSOpenGL::~Mesh3DSOpenGL() {
 }
 
-void Mesh3DSOpenGL::fillVertexBuffer(uint32 color) {
-	_color._x = RGBCOLGetR(color) / 255.0f;
-	_color._y = RGBCOLGetG(color) / 255.0f;
-	_color._z = RGBCOLGetB(color) / 255.0f;
-	_color._w = RGBCOLGetA(color) / 255.0f;
+void Mesh3DSOpenGL::fillVertexBuffer() {
+	_vertexCount = _numFaces * 3;
+	_vertexData = (Mesh3DSVertex *)_vb.ptr();
 }
 
 void Mesh3DSOpenGL::render() {
-	glColor4f(_color._x, _color._y, _color._z, _color._w);
+	if (_vertexCount == 0)
+		return;
+
 	glEnableClientState(GL_VERTEX_ARRAY);
-	glVertexPointer(3, GL_FLOAT, sizeof(GeometryVertex), reinterpret_cast<byte *>(_vertexData));
-	glDrawElements(GL_TRIANGLES, _indexCount, GL_UNSIGNED_SHORT, _indexData);
+	glEnableClientState(GL_COLOR_ARRAY);
+	glVertexPointer(3, GL_FLOAT, sizeof(Mesh3DSVertex), &_vertexData[0]._x);
+	glColorPointer(4, GL_FLOAT, sizeof(Mesh3DSVertex), &_vertexData[0]._r);
+	glDrawArrays(GL_TRIANGLES, 0, _vertexCount);
+	glDisableClientState(GL_COLOR_ARRAY);
 	glDisableClientState(GL_VERTEX_ARRAY);
 }
 
diff --git a/engines/wintermute/base/gfx/opengl/mesh3ds_opengl.h b/engines/wintermute/base/gfx/opengl/mesh3ds_opengl.h
index f6e458016de..352f4a945f1 100644
--- a/engines/wintermute/base/gfx/opengl/mesh3ds_opengl.h
+++ b/engines/wintermute/base/gfx/opengl/mesh3ds_opengl.h
@@ -30,10 +30,14 @@ namespace Wintermute {
 
 class Mesh3DSOpenGL : public Mesh3DS {
 public:
-	Mesh3DSOpenGL();
+	Mesh3DSOpenGL(BaseGame *inGame);
 	~Mesh3DSOpenGL();
-	void fillVertexBuffer(uint32 color) override;
+	void fillVertexBuffer() override;
 	void render() override;
+
+private:
+	Mesh3DSVertex *_vertexData;
+	uint16 _vertexCount;
 };
 
 } // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.cpp b/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.cpp
index 9be3c3f9a73..301d717970f 100644
--- a/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.cpp
+++ b/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.cpp
@@ -29,7 +29,7 @@
 
 namespace Wintermute {
 
-Mesh3DSOpenGLShader::Mesh3DSOpenGLShader(OpenGL::Shader *shader) : _shader(shader) {
+Mesh3DSOpenGLShader::Mesh3DSOpenGLShader(BaseGame *inGame, OpenGL::Shader *shader) : Mesh3DS(inGame), _shader(shader) {
 	glGenBuffers(1, &_vertexBuffer);
 	glGenBuffers(1, &_indexBuffer);
 }
@@ -39,34 +39,25 @@ Mesh3DSOpenGLShader::~Mesh3DSOpenGLShader() {
 	glDeleteBuffers(1, &_indexBuffer);
 }
 
-void Mesh3DSOpenGLShader::fillVertexBuffer(uint32 color) {
-	_color._x = RGBCOLGetR(color) / 255.0f;
-	_color._y = RGBCOLGetG(color) / 255.0f;
-	_color._z = RGBCOLGetB(color) / 255.0f;
-	_color._w = RGBCOLGetA(color) / 255.0f;
+void Mesh3DSOpenGLShader::fillVertexBuffer() {
+	_vertexCount = _numFaces * 3;
+	_vertexData = (Mesh3DSVertex *)_vb.ptr();
 
 	glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(GeometryVertex) * _vertexCount, _vertexData, GL_STATIC_DRAW);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(Mesh3DSVertex) * _vertexCount, _vertexData, GL_STATIC_DRAW);
 	glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
-	glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * _indexCount, _indexData, GL_STATIC_DRAW);
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 }
 
 void Mesh3DSOpenGLShader::render() {
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
+	if (_vertexCount == 0)
+		return;
 
-	_shader->enableVertexAttribute("position", _vertexBuffer, 3, GL_FLOAT, false, sizeof(GeometryVertex), 0);
+	_shader->enableVertexAttribute("position", _vertexBuffer, 3, GL_FLOAT, false, sizeof(Mesh3DSVertex), 0);
+	_shader->enableVertexAttribute("color", _vertexBuffer, 4, GL_FLOAT, false, sizeof(Mesh3DSVertex), 24);
 
 	_shader->use(true);
-	Math::Vector4d color = Math::Vector4d(_color._x, _color._y, _color._z, 1.0f);
-	_shader->setUniform("color", color);
-
-	glDrawElements(GL_TRIANGLES, _indexCount, GL_UNSIGNED_SHORT, 0);
 
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+	glDrawArrays(GL_TRIANGLES, 0, _vertexCount);
 }
 
 } // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h b/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h
index 54f65815fee..420619f9836 100644
--- a/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h
+++ b/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h
@@ -32,12 +32,14 @@ namespace Wintermute {
 
 class Mesh3DSOpenGLShader : public Mesh3DS {
 public:
-	Mesh3DSOpenGLShader(OpenGL::Shader *shader);
+	Mesh3DSOpenGLShader(BaseGame *inGame, OpenGL::Shader *shader);
 	~Mesh3DSOpenGLShader();
-	void fillVertexBuffer(uint32 color) override;
+	void fillVertexBuffer() override;
 	void render() override;
 
 private:
+	Mesh3DSVertex *_vertexData;
+	uint16 _vertexCount;
 	GLuint _vertexBuffer;
 	GLuint _indexBuffer;
 	OpenGL::Shader *_shader;
diff --git a/engines/wintermute/base/gfx/opengl/shaders/wme_geometry.vertex b/engines/wintermute/base/gfx/opengl/shaders/wme_geometry.vertex
index a3c25bd53a6..69fe6c6826e 100644
--- a/engines/wintermute/base/gfx/opengl/shaders/wme_geometry.vertex
+++ b/engines/wintermute/base/gfx/opengl/shaders/wme_geometry.vertex
@@ -1,10 +1,9 @@
 in vec3 position;
+in vec4 color;
 
 uniform highp mat4 viewMatrix;
 uniform highp mat4 projMatrix;
 
-uniform vec4 color;
-
 out vec4 Color;
 
 void main() {
diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk
index 9710e382b73..f79c2254ad9 100644
--- a/engines/wintermute/module.mk
+++ b/engines/wintermute/module.mk
@@ -161,9 +161,11 @@ MODULE_OBJS += \
 	ad/ad_waypoint_group3d.o \
 	base/gfx/3dcamera.o \
 	base/gfx/3dlight.o \
+	base/gfx/3dface.o \
 	base/gfx/3dloader_3ds.o \
 	base/gfx/3dmesh.o \
 	base/gfx/3dshadow_volume.o \
+	base/gfx/3dvertex.o \
 	base/gfx/base_renderer3d.o \
 	base/gfx/skin_mesh_helper.o \
 	base/gfx/xactive_animation.o \




More information about the Scummvm-git-logs mailing list