From 2dbf4675a5f160809d8808c800eee157cfd763a1 Mon Sep 17 00:00:00 2001 From: Benau Date: Mon, 2 Jan 2017 16:14:59 +0800 Subject: [PATCH] First version of new texture format Todo: IBL, texture compression, GLES, premul alpha .... --- lib/irrlicht/CMakeLists.txt | 2 - lib/irrlicht/include/ITexture.h | 3 + .../source/Irrlicht/CB3DMeshFileLoader.cpp | 1105 ---------------- .../source/Irrlicht/CB3DMeshFileLoader.h | 140 --- lib/irrlicht/source/Irrlicht/CNullDriver.h | 1 + lib/irrlicht/source/Irrlicht/COGLES2Texture.h | 2 +- lib/irrlicht/source/Irrlicht/COpenGLTexture.h | 2 +- .../source/Irrlicht/CSceneManager.cpp | 16 - sources.cmake | 2 +- src/graphics/2dutils.cpp | 56 +- src/graphics/irr_driver.cpp | 11 + src/graphics/material.cpp | 9 +- src/graphics/material.hpp | 7 +- src/graphics/material_manager.cpp | 20 +- src/graphics/material_manager.hpp | 1 + src/graphics/skybox.cpp | 1 + src/graphics/spherical_harmonics.cpp | 1 + src/graphics/stk_mesh_loader.cpp | 1109 +++++++++++++++++ src/graphics/stk_mesh_loader.hpp | 139 +++ src/graphics/stk_tex_manager.cpp | 126 ++ src/graphics/stk_tex_manager.hpp | 61 + src/graphics/stk_texture.cpp | 214 ++++ src/graphics/stk_texture.hpp | 115 ++ src/graphics/texture_manager.cpp | 19 +- src/graphics/texture_manager.hpp | 2 +- 25 files changed, 1818 insertions(+), 1346 deletions(-) delete mode 100644 lib/irrlicht/source/Irrlicht/CB3DMeshFileLoader.cpp delete mode 100644 lib/irrlicht/source/Irrlicht/CB3DMeshFileLoader.h create mode 100644 src/graphics/stk_mesh_loader.cpp create mode 100644 src/graphics/stk_mesh_loader.hpp create mode 100644 src/graphics/stk_tex_manager.cpp create mode 100644 src/graphics/stk_tex_manager.hpp create mode 100644 src/graphics/stk_texture.cpp create mode 100644 src/graphics/stk_texture.hpp diff --git a/lib/irrlicht/CMakeLists.txt b/lib/irrlicht/CMakeLists.txt index d85a415b6..02e865f97 100644 --- a/lib/irrlicht/CMakeLists.txt +++ b/lib/irrlicht/CMakeLists.txt @@ -64,7 +64,6 @@ endif() set(IRRLICHT_SOURCES source/Irrlicht/CAnimatedMeshSceneNode.cpp source/Irrlicht/CAttributes.cpp -source/Irrlicht/CB3DMeshFileLoader.cpp source/Irrlicht/CBillboardSceneNode.cpp source/Irrlicht/CBoneSceneNode.cpp source/Irrlicht/CCameraSceneNode.cpp @@ -196,7 +195,6 @@ source/Irrlicht/BuiltInFont.h source/Irrlicht/CAnimatedMeshSceneNode.h source/Irrlicht/CAttributeImpl.h source/Irrlicht/CAttributes.h -source/Irrlicht/CB3DMeshFileLoader.h source/Irrlicht/CBillboardSceneNode.h source/Irrlicht/CBlit.h source/Irrlicht/CBoneSceneNode.h diff --git a/lib/irrlicht/include/ITexture.h b/lib/irrlicht/include/ITexture.h index 2f544375b..ae6566cb7 100644 --- a/lib/irrlicht/include/ITexture.h +++ b/lib/irrlicht/include/ITexture.h @@ -190,6 +190,9 @@ public: //! Get name of texture (in most cases this is the filename) const io::SNamedPath& getName() const { return NamedPath; } + //! return open gl texture name + virtual u32 getOpenGLTextureName() const = 0; + protected: //! Helper function, helps to get the desired texture creation format from the flags. diff --git a/lib/irrlicht/source/Irrlicht/CB3DMeshFileLoader.cpp b/lib/irrlicht/source/Irrlicht/CB3DMeshFileLoader.cpp deleted file mode 100644 index 3d8769e10..000000000 --- a/lib/irrlicht/source/Irrlicht/CB3DMeshFileLoader.cpp +++ /dev/null @@ -1,1105 +0,0 @@ -// Copyright (C) 2006-2012 Luke Hoschke -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -// B3D Mesh loader -// File format designed by Mark Sibly for the Blitz3D engine and has been -// declared public domain - -#include "IrrCompileConfig.h" -#ifdef _IRR_COMPILE_WITH_B3D_LOADER_ - -#include "CB3DMeshFileLoader.h" - -#include "IVideoDriver.h" -#include "IFileSystem.h" -#include "os.h" - -#ifdef _DEBUG -#define _B3D_READER_DEBUG -#endif - -namespace irr -{ -namespace scene -{ - -//! Constructor -CB3DMeshFileLoader::CB3DMeshFileLoader(scene::ISceneManager* smgr) -: SceneManager(smgr), AnimatedMesh(0), B3DFile(0), NormalsInFile(false), - HasVertexColors(false), ShowWarning(true) -{ - #ifdef _DEBUG - setDebugName("CB3DMeshFileLoader"); - #endif -} - - -//! returns true if the file maybe is able to be loaded by this class -//! based on the file extension (e.g. ".bsp") -bool CB3DMeshFileLoader::isALoadableFileExtension(const io::path& filename) const -{ - return core::hasFileExtension ( filename, "b3d" ); -} - - -//! creates/loads an animated mesh from the file. -//! \return Pointer to the created mesh. Returns 0 if loading failed. -//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). -//! See IReferenceCounted::drop() for more information. -IAnimatedMesh* CB3DMeshFileLoader::createMesh(io::IReadFile* f) -{ - if (!f) - return 0; - - B3DFile = f; - AnimatedMesh = new scene::CSkinnedMesh(); - ShowWarning = true; // If true a warning is issued if too many textures are used - VerticesStart=0; - - if ( load() ) - { - AnimatedMesh->finalize(); - } - else - { - AnimatedMesh->drop(); - AnimatedMesh = 0; - } - - return AnimatedMesh; -} - - -bool CB3DMeshFileLoader::load() -{ - B3dStack.clear(); - - NormalsInFile=false; - HasVertexColors=false; - - //------ Get header ------ - - SB3dChunkHeader header; - B3DFile->read(&header, sizeof(header)); -#ifdef __BIG_ENDIAN__ - header.size = os::Byteswap::byteswap(header.size); -#endif - - if ( strncmp( header.name, "BB3D", 4 ) != 0 ) - { - os::Printer::log("File is not a b3d file. Loading failed (No header found)", B3DFile->getFileName(), ELL_ERROR); - return false; - } - - // Add main chunk... - B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8)); - - // Get file version, but ignore it, as it's not important with b3d files... - s32 fileVersion; - B3DFile->read(&fileVersion, sizeof(fileVersion)); -#ifdef __BIG_ENDIAN__ - fileVersion = os::Byteswap::byteswap(fileVersion); -#endif - - //------ Read main chunk ------ - - while ( (B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos() ) - { - B3DFile->read(&header, sizeof(header)); -#ifdef __BIG_ENDIAN__ - header.size = os::Byteswap::byteswap(header.size); -#endif - B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8)); - - if ( strncmp( B3dStack.getLast().name, "TEXS", 4 ) == 0 ) - { - if (!readChunkTEXS()) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "BRUS", 4 ) == 0 ) - { - if (!readChunkBRUS()) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 ) - { - if (!readChunkNODE((CSkinnedMesh::SJoint*)0) ) - return false; - } - else - { - os::Printer::log("Unknown chunk found in mesh base - skipping"); - B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length); - B3dStack.erase(B3dStack.size()-1); - } - } - - B3dStack.clear(); - - BaseVertices.clear(); - AnimatedVertices_VertexID.clear(); - AnimatedVertices_BufferID.clear(); - - Materials.clear(); - Textures.clear(); - - return true; -} - - -bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *inJoint) -{ - CSkinnedMesh::SJoint *joint = AnimatedMesh->addJoint(inJoint); - readString(joint->Name); - -#ifdef _B3D_READER_DEBUG - core::stringc logStr; - for ( u32 i=1; i < B3dStack.size(); ++i ) - logStr += "-"; - logStr += "read ChunkNODE"; - os::Printer::log(logStr.c_str(), joint->Name.c_str()); -#endif - - f32 position[3], scale[3], rotation[4]; - - readFloats(position, 3); - readFloats(scale, 3); - readFloats(rotation, 4); - - joint->Animatedposition = core::vector3df(position[0],position[1],position[2]) ; - joint->Animatedscale = core::vector3df(scale[0],scale[1],scale[2]); - joint->Animatedrotation = core::quaternion(rotation[1], rotation[2], rotation[3], rotation[0]); - - //Build LocalMatrix: - - core::matrix4 positionMatrix; - positionMatrix.setTranslation( joint->Animatedposition ); - core::matrix4 scaleMatrix; - scaleMatrix.setScale( joint->Animatedscale ); - core::matrix4 rotationMatrix; - joint->Animatedrotation.getMatrix_transposed(rotationMatrix); - - joint->LocalMatrix = positionMatrix * rotationMatrix * scaleMatrix; - - if (inJoint) - joint->GlobalMatrix = inJoint->GlobalMatrix * joint->LocalMatrix; - else - joint->GlobalMatrix = joint->LocalMatrix; - - while(B3dStack.getLast().startposition + B3dStack.getLast().length > B3DFile->getPos()) // this chunk repeats - { - SB3dChunkHeader header; - B3DFile->read(&header, sizeof(header)); -#ifdef __BIG_ENDIAN__ - header.size = os::Byteswap::byteswap(header.size); -#endif - - B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8)); - - if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 ) - { - if (!readChunkNODE(joint)) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "MESH", 4 ) == 0 ) - { - VerticesStart=BaseVertices.size(); - if (!readChunkMESH(joint)) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "BONE", 4 ) == 0 ) - { - if (!readChunkBONE(joint)) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "KEYS", 4 ) == 0 ) - { - if(!readChunkKEYS(joint)) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "ANIM", 4 ) == 0 ) - { - if (!readChunkANIM()) - return false; - } - else - { - os::Printer::log("Unknown chunk found in node chunk - skipping"); - B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length); - B3dStack.erase(B3dStack.size()-1); - } - } - - B3dStack.erase(B3dStack.size()-1); - - return true; -} - - -bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *inJoint) -{ -#ifdef _B3D_READER_DEBUG - core::stringc logStr; - for ( u32 i=1; i < B3dStack.size(); ++i ) - logStr += "-"; - logStr += "read ChunkMESH"; - os::Printer::log(logStr.c_str()); -#endif - - s32 brushID; - B3DFile->read(&brushID, sizeof(brushID)); -#ifdef __BIG_ENDIAN__ - brushID = os::Byteswap::byteswap(brushID); -#endif - - NormalsInFile=false; - HasVertexColors=false; - - while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats - { - SB3dChunkHeader header; - B3DFile->read(&header, sizeof(header)); -#ifdef __BIG_ENDIAN__ - header.size = os::Byteswap::byteswap(header.size); -#endif - - B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8)); - - if ( strncmp( B3dStack.getLast().name, "VRTS", 4 ) == 0 ) - { - if (!readChunkVRTS(inJoint)) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "TRIS", 4 ) == 0 ) - { - scene::SSkinMeshBuffer *meshBuffer = AnimatedMesh->addMeshBuffer(); - - if (brushID!=-1) - { - loadTextures(Materials[brushID]); - meshBuffer->Material=Materials[brushID].Material; - } - - if(readChunkTRIS(meshBuffer,AnimatedMesh->getMeshBuffers().size()-1, VerticesStart)==false) - return false; - - if (!NormalsInFile) - { - s32 i; - - for ( i=0; i<(s32)meshBuffer->Indices.size(); i+=3) - { - core::plane3df p(meshBuffer->getVertex(meshBuffer->Indices[i+0])->Pos, - meshBuffer->getVertex(meshBuffer->Indices[i+1])->Pos, - meshBuffer->getVertex(meshBuffer->Indices[i+2])->Pos); - - meshBuffer->getVertex(meshBuffer->Indices[i+0])->Normal += p.Normal; - meshBuffer->getVertex(meshBuffer->Indices[i+1])->Normal += p.Normal; - meshBuffer->getVertex(meshBuffer->Indices[i+2])->Normal += p.Normal; - } - - for ( i = 0; i<(s32)meshBuffer->getVertexCount(); ++i ) - { - meshBuffer->getVertex(i)->Normal.normalize(); - BaseVertices[VerticesStart+i].Normal=meshBuffer->getVertex(i)->Normal; - } - } - } - else - { - os::Printer::log("Unknown chunk found in mesh - skipping"); - B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length); - B3dStack.erase(B3dStack.size()-1); - } - } - - B3dStack.erase(B3dStack.size()-1); - - return true; -} - - -/* -VRTS: - int flags ;1=normal values present, 2=rgba values present - int tex_coord_sets ;texture coords per vertex (eg: 1 for simple U/V) max=8 - but we only support 3 - int tex_coord_set_size ;components per set (eg: 2 for simple U/V) max=4 - { - float x,y,z ;always present - float nx,ny,nz ;vertex normal: present if (flags&1) - float red,green,blue,alpha ;vertex color: present if (flags&2) - float tex_coords[tex_coord_sets][tex_coord_set_size] ;tex coords - } -*/ -bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *inJoint) -{ -#ifdef _B3D_READER_DEBUG - core::stringc logStr; - for ( u32 i=1; i < B3dStack.size(); ++i ) - logStr += "-"; - logStr += "ChunkVRTS"; - os::Printer::log(logStr.c_str()); -#endif - - const s32 max_tex_coords = 3; - s32 flags, tex_coord_sets, tex_coord_set_size; - - B3DFile->read(&flags, sizeof(flags)); - B3DFile->read(&tex_coord_sets, sizeof(tex_coord_sets)); - B3DFile->read(&tex_coord_set_size, sizeof(tex_coord_set_size)); -#ifdef __BIG_ENDIAN__ - flags = os::Byteswap::byteswap(flags); - tex_coord_sets = os::Byteswap::byteswap(tex_coord_sets); - tex_coord_set_size = os::Byteswap::byteswap(tex_coord_set_size); -#endif - - if (tex_coord_sets >= max_tex_coords || tex_coord_set_size >= 4) // Something is wrong - { - os::Printer::log("tex_coord_sets or tex_coord_set_size too big", B3DFile->getFileName(), ELL_ERROR); - return false; - } - - //------ Allocate Memory, for speed -----------// - - s32 numberOfReads = 3; - - if (flags & 1) - { - NormalsInFile = true; - numberOfReads += 3; - } - if (flags & 2) - { - numberOfReads += 4; - HasVertexColors=true; - } - - numberOfReads += tex_coord_sets*tex_coord_set_size; - - const s32 memoryNeeded = (B3dStack.getLast().length / sizeof(f32)) / numberOfReads; - - BaseVertices.reallocate(memoryNeeded + BaseVertices.size() + 1); - AnimatedVertices_VertexID.reallocate(memoryNeeded + AnimatedVertices_VertexID.size() + 1); - - //--------------------------------------------// - - while( (B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats - { - f32 position[3]; - f32 normal[3]={0.f, 0.f, 0.f}; - f32 color[4]={1.0f, 1.0f, 1.0f, 1.0f}; - f32 tex_coords[max_tex_coords][4]; - - readFloats(position, 3); - - if (flags & 1) - readFloats(normal, 3); - if (flags & 2) - readFloats(color, 4); - - for (s32 i=0; i= 1 && tex_coord_set_size >= 2) - { - tu=tex_coords[0][0]; - tv=tex_coords[0][1]; - } - - f32 tu2=0.0f, tv2=0.0f; - if (tex_coord_sets>1 && tex_coord_set_size>1) - { - tu2=tex_coords[1][0]; - tv2=tex_coords[1][1]; - } - - // Create Vertex... - video::S3DVertex2TCoords Vertex(position[0], position[1], position[2], - normal[0], normal[1], normal[2], - video::SColorf(color[0], color[1], color[2], color[3]).toSColor(), - tu, tv, tu2, tv2); - - // Transform the Vertex position by nested node... - inJoint->GlobalMatrix.transformVect(Vertex.Pos); - inJoint->GlobalMatrix.rotateVect(Vertex.Normal); - - //Add it... - BaseVertices.push_back(Vertex); - - AnimatedVertices_VertexID.push_back(-1); - AnimatedVertices_BufferID.push_back(-1); - } - - B3dStack.erase(B3dStack.size()-1); - - return true; -} - - -bool CB3DMeshFileLoader::readChunkTRIS(scene::SSkinMeshBuffer *meshBuffer, u32 meshBufferID, s32 vertices_Start) -{ -#ifdef _B3D_READER_DEBUG - core::stringc logStr; - for ( u32 i=1; i < B3dStack.size(); ++i ) - logStr += "-"; - logStr += "ChunkTRIS"; - os::Printer::log(logStr.c_str()); -#endif - - bool showVertexWarning=false; - - s32 triangle_brush_id; // Note: Irrlicht can't have different brushes for each triangle (using a workaround) - B3DFile->read(&triangle_brush_id, sizeof(triangle_brush_id)); -#ifdef __BIG_ENDIAN__ - triangle_brush_id = os::Byteswap::byteswap(triangle_brush_id); -#endif - - SB3dMaterial *B3dMaterial; - - if (triangle_brush_id != -1) - { - loadTextures(Materials[triangle_brush_id]); - B3dMaterial = &Materials[triangle_brush_id]; - meshBuffer->Material = B3dMaterial->Material; - } - else - B3dMaterial = 0; - - const s32 memoryNeeded = B3dStack.getLast().length / sizeof(s32); - meshBuffer->Indices.reallocate(memoryNeeded + meshBuffer->Indices.size() + 1); - - while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats - { - s32 vertex_id[3]; - - B3DFile->read(vertex_id, 3*sizeof(s32)); -#ifdef __BIG_ENDIAN__ - vertex_id[0] = os::Byteswap::byteswap(vertex_id[0]); - vertex_id[1] = os::Byteswap::byteswap(vertex_id[1]); - vertex_id[2] = os::Byteswap::byteswap(vertex_id[2]); -#endif - - //Make Ids global: - vertex_id[0] += vertices_Start; - vertex_id[1] += vertices_Start; - vertex_id[2] += vertices_Start; - - for(s32 i=0; i<3; ++i) - { - if ((u32)vertex_id[i] >= AnimatedVertices_VertexID.size()) - { - os::Printer::log("Illegal vertex index found", B3DFile->getFileName(), ELL_ERROR); - return false; - } - - if (AnimatedVertices_VertexID[ vertex_id[i] ] != -1) - { - if ( AnimatedVertices_BufferID[ vertex_id[i] ] != (s32)meshBufferID ) //If this vertex is linked in a different meshbuffer - { - AnimatedVertices_VertexID[ vertex_id[i] ] = -1; - AnimatedVertices_BufferID[ vertex_id[i] ] = -1; - showVertexWarning=true; - } - } - if (AnimatedVertices_VertexID[ vertex_id[i] ] == -1) //If this vertex is not in the meshbuffer - { - //Check for lightmapping: - if (BaseVertices[ vertex_id[i] ].TCoords2 != core::vector2df(0.f,0.f)) - meshBuffer->convertTo2TCoords(); //Will only affect the meshbuffer the first time this is called - - //Add the vertex to the meshbuffer: - if (meshBuffer->VertexType == video::EVT_STANDARD) - meshBuffer->Vertices_Standard.push_back( BaseVertices[ vertex_id[i] ] ); - else - meshBuffer->Vertices_2TCoords.push_back(BaseVertices[ vertex_id[i] ] ); - - //create vertex id to meshbuffer index link: - AnimatedVertices_VertexID[ vertex_id[i] ] = meshBuffer->getVertexCount()-1; - AnimatedVertices_BufferID[ vertex_id[i] ] = meshBufferID; - - if (B3dMaterial) - { - // Apply Material/Color/etc... - video::S3DVertex *Vertex=meshBuffer->getVertex(meshBuffer->getVertexCount()-1); - - if (!HasVertexColors) - Vertex->Color=B3dMaterial->Material.DiffuseColor; - else if (Vertex->Color.getAlpha() == 255) - Vertex->Color.setAlpha( (s32)(B3dMaterial->alpha * 255.0f) ); - - // Use texture's scale - if (B3dMaterial->Textures[0]) - { - Vertex->TCoords.X *= B3dMaterial->Textures[0]->Xscale; - Vertex->TCoords.Y *= B3dMaterial->Textures[0]->Yscale; - } - /* - if (B3dMaterial->Textures[1]) - { - Vertex->TCoords2.X *=B3dMaterial->Textures[1]->Xscale; - Vertex->TCoords2.Y *=B3dMaterial->Textures[1]->Yscale; - } - */ - } - } - } - - meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[0] ] ); - meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[1] ] ); - meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[2] ] ); - } - - B3dStack.erase(B3dStack.size()-1); - - if (showVertexWarning) - os::Printer::log("B3dMeshLoader: Warning, different meshbuffers linking to the same vertex, this will cause problems with animated meshes"); - - return true; -} - - -bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *inJoint) -{ -#ifdef _B3D_READER_DEBUG - core::stringc logStr; - for ( u32 i=1; i < B3dStack.size(); ++i ) - logStr += "-"; - logStr += "read ChunkBONE"; - os::Printer::log(logStr.c_str()); -#endif - - if (B3dStack.getLast().length > 8) - { - while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats - { - u32 globalVertexID; - f32 strength; - B3DFile->read(&globalVertexID, sizeof(globalVertexID)); - B3DFile->read(&strength, sizeof(strength)); -#ifdef __BIG_ENDIAN__ - globalVertexID = os::Byteswap::byteswap(globalVertexID); - strength = os::Byteswap::byteswap(strength); -#endif - globalVertexID += VerticesStart; - - if (AnimatedVertices_VertexID[globalVertexID]==-1) - { - os::Printer::log("B3dMeshLoader: Weight has bad vertex id (no link to meshbuffer index found)"); - } - else if (strength >0) - { - CSkinnedMesh::SWeight *weight=AnimatedMesh->addWeight(inJoint); - weight->strength=strength; - //Find the meshbuffer and Vertex index from the Global Vertex ID: - weight->vertex_id = AnimatedVertices_VertexID[globalVertexID]; - weight->buffer_id = AnimatedVertices_BufferID[globalVertexID]; - } - } - } - - B3dStack.erase(B3dStack.size()-1); - return true; -} - - -bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *inJoint) -{ -#ifdef _B3D_READER_DEBUG - // Only print first, that's just too much output otherwise - if ( !inJoint || (inJoint->PositionKeys.empty() && inJoint->ScaleKeys.empty() && inJoint->RotationKeys.empty()) ) - { - core::stringc logStr; - for ( u32 i=1; i < B3dStack.size(); ++i ) - logStr += "-"; - logStr += "read ChunkKEYS"; - os::Printer::log(logStr.c_str()); - } -#endif - - s32 flags; - B3DFile->read(&flags, sizeof(flags)); -#ifdef __BIG_ENDIAN__ - flags = os::Byteswap::byteswap(flags); -#endif - - CSkinnedMesh::SPositionKey *oldPosKey=0; - core::vector3df oldPos[2]; - CSkinnedMesh::SScaleKey *oldScaleKey=0; - core::vector3df oldScale[2]; - CSkinnedMesh::SRotationKey *oldRotKey=0; - core::quaternion oldRot[2]; - bool isFirst[3]={true,true,true}; - while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats - { - s32 frame; - - B3DFile->read(&frame, sizeof(frame)); - #ifdef __BIG_ENDIAN__ - frame = os::Byteswap::byteswap(frame); - #endif - - // Add key frames, frames in Irrlicht are zero-based - f32 data[4]; - if (flags & 1) - { - readFloats(data, 3); - if ((oldPosKey!=0) && (oldPos[0]==oldPos[1])) - { - const core::vector3df pos(data[0], data[1], data[2]); - if (oldPos[1]==pos) - oldPosKey->frame = (f32)frame-1; - else - { - oldPos[0]=oldPos[1]; - oldPosKey=AnimatedMesh->addPositionKey(inJoint); - oldPosKey->frame = (f32)frame-1; - oldPos[1].set(oldPosKey->position.set(pos)); - } - } - else if (oldPosKey==0 && isFirst[0]) - { - oldPosKey=AnimatedMesh->addPositionKey(inJoint); - oldPosKey->frame = (f32)frame-1; - oldPos[0].set(oldPosKey->position.set(data[0], data[1], data[2])); - oldPosKey=0; - isFirst[0]=false; - } - else - { - if (oldPosKey!=0) - oldPos[0]=oldPos[1]; - oldPosKey=AnimatedMesh->addPositionKey(inJoint); - oldPosKey->frame = (f32)frame-1; - oldPos[1].set(oldPosKey->position.set(data[0], data[1], data[2])); - } - } - if (flags & 2) - { - readFloats(data, 3); - if ((oldScaleKey!=0) && (oldScale[0]==oldScale[1])) - { - const core::vector3df scale(data[0], data[1], data[2]); - if (oldScale[1]==scale) - oldScaleKey->frame = (f32)frame-1; - else - { - oldScale[0]=oldScale[1]; - oldScaleKey=AnimatedMesh->addScaleKey(inJoint); - oldScaleKey->frame = (f32)frame-1; - oldScale[1].set(oldScaleKey->scale.set(scale)); - } - } - else if (oldScaleKey==0 && isFirst[1]) - { - oldScaleKey=AnimatedMesh->addScaleKey(inJoint); - oldScaleKey->frame = (f32)frame-1; - oldScale[0].set(oldScaleKey->scale.set(data[0], data[1], data[2])); - oldScaleKey=0; - isFirst[1]=false; - } - else - { - if (oldScaleKey!=0) - oldScale[0]=oldScale[1]; - oldScaleKey=AnimatedMesh->addScaleKey(inJoint); - oldScaleKey->frame = (f32)frame-1; - oldScale[1].set(oldScaleKey->scale.set(data[0], data[1], data[2])); - } - } - if (flags & 4) - { - readFloats(data, 4); - if ((oldRotKey!=0) && (oldRot[0]==oldRot[1])) - { - // meant to be in this order since b3d stores W first - const core::quaternion rot(data[1], data[2], data[3], data[0]); - if (oldRot[1]==rot) - oldRotKey->frame = (f32)frame-1; - else - { - oldRot[0]=oldRot[1]; - oldRotKey=AnimatedMesh->addRotationKey(inJoint); - oldRotKey->frame = (f32)frame-1; - oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); - } - } - else if (oldRotKey==0 && isFirst[2]) - { - oldRotKey=AnimatedMesh->addRotationKey(inJoint); - oldRotKey->frame = (f32)frame-1; - // meant to be in this order since b3d stores W first - oldRot[0].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); - oldRotKey=0; - isFirst[2]=false; - } - else - { - if (oldRotKey!=0) - oldRot[0]=oldRot[1]; - oldRotKey=AnimatedMesh->addRotationKey(inJoint); - oldRotKey->frame = (f32)frame-1; - // meant to be in this order since b3d stores W first - oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); - } - } - } - - B3dStack.erase(B3dStack.size()-1); - return true; -} - - -bool CB3DMeshFileLoader::readChunkANIM() -{ -#ifdef _B3D_READER_DEBUG - core::stringc logStr; - for ( u32 i=1; i < B3dStack.size(); ++i ) - logStr += "-"; - logStr += "read ChunkANIM"; - os::Printer::log(logStr.c_str()); -#endif - - s32 animFlags; //not stored\used - s32 animFrames;//not stored\used - f32 animFPS; //not stored\used - - B3DFile->read(&animFlags, sizeof(s32)); - B3DFile->read(&animFrames, sizeof(s32)); - readFloats(&animFPS, 1); - if (animFPS>0.f) - AnimatedMesh->setAnimationSpeed(animFPS); - os::Printer::log("FPS", io::path((double)animFPS), ELL_DEBUG); - - #ifdef __BIG_ENDIAN__ - animFlags = os::Byteswap::byteswap(animFlags); - animFrames = os::Byteswap::byteswap(animFrames); - #endif - - B3dStack.erase(B3dStack.size()-1); - return true; -} - - -bool CB3DMeshFileLoader::readChunkTEXS() -{ -#ifdef _B3D_READER_DEBUG - core::stringc logStr; - for ( u32 i=1; i < B3dStack.size(); ++i ) - logStr += "-"; - logStr += "read ChunkTEXS"; - os::Printer::log(logStr.c_str()); -#endif - - while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats - { - Textures.push_back(SB3dTexture()); - SB3dTexture& B3dTexture = Textures.getLast(); - - readString(B3dTexture.TextureName); - B3dTexture.TextureName.replace('\\','/'); -#ifdef _B3D_READER_DEBUG - os::Printer::log("read Texture", B3dTexture.TextureName.c_str()); -#endif - - B3DFile->read(&B3dTexture.Flags, sizeof(s32)); - B3DFile->read(&B3dTexture.Blend, sizeof(s32)); -#ifdef __BIG_ENDIAN__ - B3dTexture.Flags = os::Byteswap::byteswap(B3dTexture.Flags); - B3dTexture.Blend = os::Byteswap::byteswap(B3dTexture.Blend); -#endif -#ifdef _B3D_READER_DEBUG - os::Printer::log("Flags", core::stringc(B3dTexture.Flags).c_str()); - os::Printer::log("Blend", core::stringc(B3dTexture.Blend).c_str()); -#endif - readFloats(&B3dTexture.Xpos, 1); - readFloats(&B3dTexture.Ypos, 1); - readFloats(&B3dTexture.Xscale, 1); - readFloats(&B3dTexture.Yscale, 1); - readFloats(&B3dTexture.Angle, 1); - } - - B3dStack.erase(B3dStack.size()-1); - - return true; -} - - -bool CB3DMeshFileLoader::readChunkBRUS() -{ -#ifdef _B3D_READER_DEBUG - core::stringc logStr; - for ( u32 i=1; i < B3dStack.size(); ++i ) - logStr += "-"; - logStr += "read ChunkBRUS"; - os::Printer::log(logStr.c_str()); -#endif - - u32 n_texs; - B3DFile->read(&n_texs, sizeof(u32)); -#ifdef __BIG_ENDIAN__ - n_texs = os::Byteswap::byteswap(n_texs); -#endif - - // number of texture ids read for Irrlicht - const u32 num_textures = core::min_(n_texs, video::MATERIAL_MAX_TEXTURES); - // number of bytes to skip (for ignored texture ids) - const u32 n_texs_offset = (num_textures B3DFile->getPos()) //this chunk repeats - { - // This is what blitz basic calls a brush, like a Irrlicht Material - - core::stringc name; - readString(name); -#ifdef _B3D_READER_DEBUG - os::Printer::log("read Material", name); -#endif - Materials.push_back(SB3dMaterial()); - SB3dMaterial& B3dMaterial=Materials.getLast(); - - readFloats(&B3dMaterial.red, 1); - readFloats(&B3dMaterial.green, 1); - readFloats(&B3dMaterial.blue, 1); - readFloats(&B3dMaterial.alpha, 1); - readFloats(&B3dMaterial.shininess, 1); - - B3DFile->read(&B3dMaterial.blend, sizeof(B3dMaterial.blend)); - B3DFile->read(&B3dMaterial.fx, sizeof(B3dMaterial.fx)); -#ifdef __BIG_ENDIAN__ - B3dMaterial.blend = os::Byteswap::byteswap(B3dMaterial.blend); - B3dMaterial.fx = os::Byteswap::byteswap(B3dMaterial.fx); -#endif -#ifdef _B3D_READER_DEBUG - os::Printer::log("Blend", core::stringc(B3dMaterial.blend).c_str()); - os::Printer::log("FX", core::stringc(B3dMaterial.fx).c_str()); -#endif - - u32 i; - for (i=0; iread(&texture_id, sizeof(s32)); -#ifdef __BIG_ENDIAN__ - texture_id = os::Byteswap::byteswap(texture_id); -#endif - //--- Get pointers to the texture, based on the IDs --- - if ((u32)texture_id < Textures.size()) - { - B3dMaterial.Textures[i]=&Textures[texture_id]; -#ifdef _B3D_READER_DEBUG - os::Printer::log("Layer", core::stringc(i).c_str()); - os::Printer::log("using texture", Textures[texture_id].TextureName.c_str()); -#endif - } - else - B3dMaterial.Textures[i]=0; - } - // skip other texture ids - for (i=0; iread(&texture_id, sizeof(s32)); -#ifdef __BIG_ENDIAN__ - texture_id = os::Byteswap::byteswap(texture_id); -#endif - if (ShowWarning && (texture_id != -1) && (n_texs>video::MATERIAL_MAX_TEXTURES)) - { - os::Printer::log("Too many textures used in one material", B3DFile->getFileName(), ELL_WARNING); - ShowWarning = false; - } - } - - //Fixes problems when the lightmap is on the first texture: - if (B3dMaterial.Textures[0] != 0) - { - if (B3dMaterial.Textures[0]->Flags & 65536) // 65536 = secondary UV - { - SB3dTexture *TmpTexture; - TmpTexture = B3dMaterial.Textures[1]; - B3dMaterial.Textures[1] = B3dMaterial.Textures[0]; - B3dMaterial.Textures[0] = TmpTexture; - } - } - - //If a preceeding texture slot is empty move the others down: - for (i=num_textures; i>0; --i) - { - for (u32 j=i-1; jBlend == 5) //(Multiply 2) - B3dMaterial.Material.MaterialType = video::EMT_LIGHTMAP_M2; - else - B3dMaterial.Material.MaterialType = video::EMT_LIGHTMAP; - B3dMaterial.Material.Lighting = false; - } - else - { - B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; - B3dMaterial.Material.ZWriteEnable = false; - } - } - else if (B3dMaterial.Textures[0]) //One texture: - { - // Flags & 0x1 is usual SOLID, 0x8 is mipmap (handled before) - if (B3dMaterial.Textures[0]->Flags & 0x2) //(Alpha mapped) - { - B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - B3dMaterial.Material.ZWriteEnable = false; - } - else if (B3dMaterial.Textures[0]->Flags & 0x4) //(Masked) - B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; // TODO: create color key texture - else if (B3dMaterial.Textures[0]->Flags & 0x40) - B3dMaterial.Material.MaterialType = video::EMT_SPHERE_MAP; - else if (B3dMaterial.Textures[0]->Flags & 0x80) - B3dMaterial.Material.MaterialType = video::EMT_SPHERE_MAP; // TODO: Should be cube map - else if (B3dMaterial.alpha == 1.f) - B3dMaterial.Material.MaterialType = video::EMT_SOLID; - else - { - B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; - B3dMaterial.Material.ZWriteEnable = false; - } - } - else //No texture: - { - if (B3dMaterial.alpha == 1.f) - B3dMaterial.Material.MaterialType = video::EMT_SOLID; - else - { - B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; - B3dMaterial.Material.ZWriteEnable = false; - } - } - - B3dMaterial.Material.DiffuseColor = video::SColorf(B3dMaterial.red, B3dMaterial.green, B3dMaterial.blue, B3dMaterial.alpha).toSColor(); - B3dMaterial.Material.ColorMaterial=video::ECM_NONE; - - //------ Material fx ------ - - if (B3dMaterial.fx & 1) //full-bright - { - B3dMaterial.Material.AmbientColor = video::SColor(255, 255, 255, 255); - B3dMaterial.Material.Lighting = false; - } - else - B3dMaterial.Material.AmbientColor = B3dMaterial.Material.DiffuseColor; - - if (B3dMaterial.fx & 2) //use vertex colors instead of brush color - B3dMaterial.Material.ColorMaterial=video::ECM_DIFFUSE_AND_AMBIENT; - - if (B3dMaterial.fx & 4) //flatshaded - B3dMaterial.Material.GouraudShading = false; - - if (B3dMaterial.fx & 16) //disable backface culling - B3dMaterial.Material.BackfaceCulling = false; - - if (B3dMaterial.fx & 32) //force vertex alpha-blending - { - B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; - B3dMaterial.Material.ZWriteEnable = false; - } - - B3dMaterial.Material.Shininess = B3dMaterial.shininess; - } - - B3dStack.erase(B3dStack.size()-1); - - return true; -} - - -void CB3DMeshFileLoader::loadTextures(SB3dMaterial& material) const -{ - const bool previous32BitTextureFlag = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_ALWAYS_32_BIT); - SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true); - - // read texture from disk - // note that mipmaps might be disabled by Flags & 0x8 - const bool doMipMaps = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); - - for (u32 i=0; iTextureName.size() && !material.Material.getTexture(i)) - { - if (!SceneManager->getParameters()->getAttributeAsBool(B3D_LOADER_IGNORE_MIPMAP_FLAG)) - SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, (B3dTexture->Flags & 0x8) ? true:false); - { - video::ITexture* tex = 0; - io::IFileSystem* fs = SceneManager->getFileSystem(); - io::path texnameWithUserPath( SceneManager->getParameters()->getAttributeAsString(B3D_TEXTURE_PATH) ); - if ( texnameWithUserPath.size() ) - { - texnameWithUserPath += '/'; - texnameWithUserPath += B3dTexture->TextureName; - } - if (fs->existFile(texnameWithUserPath)) - tex = SceneManager->getVideoDriver()->getTexture(texnameWithUserPath); - else if (fs->existFile(B3dTexture->TextureName)) - tex = SceneManager->getVideoDriver()->getTexture(B3dTexture->TextureName); - else if (fs->existFile(fs->getFileDir(B3DFile->getFileName()) +"/"+ fs->getFileBasename(B3dTexture->TextureName))) - tex = SceneManager->getVideoDriver()->getTexture(fs->getFileDir(B3DFile->getFileName()) +"/"+ fs->getFileBasename(B3dTexture->TextureName)); - else - tex = SceneManager->getVideoDriver()->getTexture(fs->getFileBasename(B3dTexture->TextureName)); - - material.Material.setTexture(i, tex); - } - if (material.Textures[i]->Flags & 0x10) // Clamp U - material.Material.TextureLayer[i].TextureWrapU=video::ETC_CLAMP; - if (material.Textures[i]->Flags & 0x20) // Clamp V - material.Material.TextureLayer[i].TextureWrapV=video::ETC_CLAMP; - } - } - - SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, doMipMaps); - SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, previous32BitTextureFlag); -} - - -void CB3DMeshFileLoader::readString(core::stringc& newstring) -{ - newstring=""; - while (B3DFile->getPos() <= B3DFile->getSize()) - { - c8 character; - B3DFile->read(&character, sizeof(character)); - if (character==0) - return; - newstring.append(character); - } -} - - -void CB3DMeshFileLoader::readFloats(f32* vec, u32 count) -{ - B3DFile->read(vec, count*sizeof(f32)); - #ifdef __BIG_ENDIAN__ - for (u32 n=0; n B3dStack; - - core::array Materials; - core::array Textures; - - core::array AnimatedVertices_VertexID; - - core::array AnimatedVertices_BufferID; - - core::array BaseVertices; - - ISceneManager* SceneManager; - CSkinnedMesh* AnimatedMesh; - io::IReadFile* B3DFile; - - //B3Ds have Vertex ID's local within the mesh I don't want this - // Variable needs to be class member due to recursion in calls - u32 VerticesStart; - - bool NormalsInFile; - bool HasVertexColors; - bool ShowWarning; -}; - - -} // end namespace scene -} // end namespace irr - -#endif // __C_B3D_MESH_LOADER_H_INCLUDED__ - diff --git a/lib/irrlicht/source/Irrlicht/CNullDriver.h b/lib/irrlicht/source/Irrlicht/CNullDriver.h index 96b429c79..cd3b18049 100644 --- a/lib/irrlicht/source/Irrlicht/CNullDriver.h +++ b/lib/irrlicht/source/Irrlicht/CNullDriver.h @@ -744,6 +744,7 @@ namespace video virtual E_DRIVER_TYPE getDriverType() const { return video::EDT_NULL; } virtual ECOLOR_FORMAT getColorFormat() const { return video::ECF_A1R5G5B5; }; virtual u32 getPitch() const { return 0; } + virtual u32 getOpenGLTextureName() const { return 0; } virtual void regenerateMipMapLevels(void* mipmapData=0) {}; core::dimension2d size; }; diff --git a/lib/irrlicht/source/Irrlicht/COGLES2Texture.h b/lib/irrlicht/source/Irrlicht/COGLES2Texture.h index 7782b361c..3f6bb74e4 100644 --- a/lib/irrlicht/source/Irrlicht/COGLES2Texture.h +++ b/lib/irrlicht/source/Irrlicht/COGLES2Texture.h @@ -81,7 +81,7 @@ public: virtual u32 getPitch() const; //! return open gl texture name - GLuint getOpenGLTextureName() const; + virtual u32 getOpenGLTextureName() const; //! return whether this texture has mipmaps virtual bool hasMipMaps() const; diff --git a/lib/irrlicht/source/Irrlicht/COpenGLTexture.h b/lib/irrlicht/source/Irrlicht/COpenGLTexture.h index 8ec232ef7..823dc2c4b 100644 --- a/lib/irrlicht/source/Irrlicht/COpenGLTexture.h +++ b/lib/irrlicht/source/Irrlicht/COpenGLTexture.h @@ -78,7 +78,7 @@ public: virtual u32 getPitch() const; //! return open gl texture name - GLuint getOpenGLTextureName() const; + virtual u32 getOpenGLTextureName() const; //! return whether this texture has mipmaps virtual bool hasMipMaps() const; diff --git a/lib/irrlicht/source/Irrlicht/CSceneManager.cpp b/lib/irrlicht/source/Irrlicht/CSceneManager.cpp index eabb96ea8..ebd48ee14 100644 --- a/lib/irrlicht/source/Irrlicht/CSceneManager.cpp +++ b/lib/irrlicht/source/Irrlicht/CSceneManager.cpp @@ -24,10 +24,6 @@ #include "CSkinnedMesh.h" #endif -#ifdef _IRR_COMPILE_WITH_B3D_LOADER_ -#include "CB3DMeshFileLoader.h" -#endif - #include "CCubeSceneNode.h" #include "CSphereSceneNode.h" #include "CAnimatedMeshSceneNode.h" @@ -121,13 +117,6 @@ CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs, // create geometry creator GeometryCreator = new CGeometryCreator(); - // add file format loaders. add the least commonly used ones first, - // as these are checked last - #ifdef _IRR_COMPILE_WITH_B3D_LOADER_ - MeshLoaderList.push_back(new CB3DMeshFileLoader(this)); - #endif - - // factories ISceneNodeFactory* factory = new CDefaultSceneNodeFactory(this); registerSceneNodeFactory(factory); @@ -1427,11 +1416,6 @@ void CSceneManager::drawAll(u32 flags) void CSceneManager::setLightManager(ILightManager* lightManager) { - if (lightManager) - lightManager->grab(); - if (LightManager) - LightManager->drop(); - LightManager = lightManager; } diff --git a/sources.cmake b/sources.cmake index d4f28ae4d..ba4868d71 100644 --- a/sources.cmake +++ b/sources.cmake @@ -1,5 +1,5 @@ # Modify this file to change the last-modified date when you add/remove a file. -# This will then trigger a new cmake run automatically. +# This will then trigger a new cmake run automatically. file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp") file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp") file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*") diff --git a/src/graphics/2dutils.cpp b/src/graphics/2dutils.cpp index 87bf3a16e..2237b43e7 100644 --- a/src/graphics/2dutils.cpp +++ b/src/graphics/2dutils.cpp @@ -28,14 +28,6 @@ #include "graphics/texture_shader.hpp" #include "utils/cpp2011.hpp" -#if defined(USE_GLES2) -# define _IRR_COMPILE_WITH_OGLES2_ -# include "../../lib/irrlicht/source/Irrlicht/COGLES2Texture.h" -#else -# include "../../lib/irrlicht/source/Irrlicht/COpenGLTexture.h" -#endif - - // ============================================================================ class Primitive2DList : public TextureShader { @@ -186,16 +178,8 @@ static void drawTexColoredQuad(const video::ITexture *texture, ColoredTextureRectShader::getInstance()->use(); glBindVertexArray(ColoredTextureRectShader::getInstance()->m_vao); - -#if !defined(USE_GLES2) - const irr::video::COpenGLTexture *t = - static_cast(texture); -#else - const irr::video::COGLES2Texture *t = - static_cast(texture); -#endif ColoredTextureRectShader::getInstance() - ->setTextureUnits(t->getOpenGLTextureName()); + ->setTextureUnits(texture->getOpenGLTextureName()); ColoredTextureRectShader::getInstance() ->setUniforms(core::vector2df(center_pos_x, center_pos_y), core::vector2df(width, height), @@ -367,16 +351,8 @@ void draw2DImage(const video::ITexture* texture, UniformColoredTextureRectShader::getInstance()->use(); glBindVertexArray(SharedGPUObjects::getUI_VAO()); - -#if !defined(USE_GLES2) - const video::COpenGLTexture *c_texture = - static_cast(texture); -#else - const video::COGLES2Texture *c_texture = - static_cast(texture); -#endif UniformColoredTextureRectShader::getInstance() - ->setTextureUnits(c_texture->getOpenGLTextureName()); + ->setTextureUnits(texture->getOpenGLTextureName()); UniformColoredTextureRectShader::getInstance() ->setUniforms(core::vector2df(center_pos_x, center_pos_y), @@ -450,16 +426,8 @@ void draw2DImage(const video::ITexture* texture, UniformColoredTextureRectShader::getInstance()->use(); glBindVertexArray(SharedGPUObjects::getUI_VAO()); - -#if !defined(USE_GLES2) - const video::COpenGLTexture *c_texture = - static_cast(texture); -#else - const video::COGLES2Texture *c_texture = - static_cast(texture); -#endif UniformColoredTextureRectShader::getInstance() - ->setTextureUnits(c_texture->getOpenGLTextureName()); + ->setTextureUnits(texture->getOpenGLTextureName()); UniformColoredTextureRectShader::getInstance() ->setUniforms(core::vector2df(center_pos_x, center_pos_y), @@ -574,14 +542,7 @@ void draw2DImage(const video::ITexture* texture, } else { -#if !defined(USE_GLES2) - const video::COpenGLTexture *c_texture = - static_cast(texture); -#else - const video::COGLES2Texture *c_texture = - static_cast(texture); -#endif - drawTexQuad(c_texture->getOpenGLTextureName(), width, height, + drawTexQuad(texture->getOpenGLTextureName(), width, height, center_pos_x, center_pos_y, tex_center_pos_x, tex_center_pos_y, tex_width, tex_height); } @@ -657,14 +618,7 @@ void draw2DImage(const video::ITexture* texture, } else { -#if !defined(USE_GLES2) - const video::COpenGLTexture *c_texture = - static_cast(texture); -#else - const video::COGLES2Texture *c_texture = - static_cast(texture); -#endif - drawTexQuad(c_texture->getOpenGLTextureName(), width, height, + drawTexQuad(texture->getOpenGLTextureName(), width, height, center_pos_x, center_pos_y, tex_center_pos_x, tex_center_pos_y, tex_width, tex_height); } diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index f8667885c..6bbeb86c1 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -36,7 +36,10 @@ #include "graphics/shaders.hpp" #include "graphics/stk_animated_mesh.hpp" #include "graphics/stk_billboard.hpp" +#include "graphics/stk_mesh_loader.hpp" #include "graphics/stk_mesh_scene_node.hpp" +#include "graphics/stk_tex_manager.hpp" +#include "graphics/stk_texture.hpp" #include "graphics/sun.hpp" #include "graphics/texture_manager.hpp" #include "guiengine/engine.hpp" @@ -600,6 +603,9 @@ void IrrDriver::initDevice() m_scene_manager = m_device->getSceneManager(); m_gui_env = m_device->getGUIEnvironment(); m_video_driver = m_device->getVideoDriver(); + STKMeshLoader* sml = new STKMeshLoader(m_scene_manager); + m_scene_manager->addExternalMeshLoader(sml); + sml->drop(); m_actual_screen_size = m_video_driver->getCurrentRenderTargetSize(); #ifndef SERVER_ONLY @@ -1671,6 +1677,11 @@ video::ITexture *IrrDriver::getTexture(const std::string &filename, bool is_prediv, bool complain_if_not_found) { + if (CVS->isGLSL()) + { + return STKTexManager::getInstance()->getTexture(filename); + } + video::ITexture* out; if(!is_premul && !is_prediv) { diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index 32ba63e37..d5938ab95 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -399,12 +399,11 @@ Material::Material(const XMLNode *node, bool deprecated) m_high_tire_adhesion = true; } // Material //----------------------------------------------------------------------------- - -video::ITexture* Material::getTexture() +video::ITexture* Material::getTexture(bool srgb, bool premul_alpha) { if (!m_installed) { - install(); + install(srgb, premul_alpha); } return m_texture; } // getTexture @@ -489,7 +488,7 @@ void Material::init() } // init //----------------------------------------------------------------------------- -void Material::install() +void Material::install(bool srgb, bool premul_alpha) { // Don't load a texture that are not supposed to be loaded automatically if (m_installed) return; @@ -515,7 +514,7 @@ void Material::install() // now set the name to the basename, so that all tests work as expected m_texname = StringUtils::getBasename(m_texname); - if (m_mask.size() > 0) + if (!CVS->isGLSL() && m_mask.size() > 0) { irr_driver->applyMask(m_texture, m_mask); } diff --git a/src/graphics/material.hpp b/src/graphics/material.hpp index 0b4fe40ec..d51f0d753 100644 --- a/src/graphics/material.hpp +++ b/src/graphics/material.hpp @@ -267,7 +267,7 @@ private: bool m_installed; void init (); - void install (); + void install (bool srgb = false, bool premul_alpha = false); void initCustomSFX(const XMLNode *sfx); void initParticlesEffect(const XMLNode *node); @@ -290,7 +290,7 @@ public: void isInitiallyHidden(scene::IMeshBuffer* who); /** Returns the ITexture associated with this material. */ - video::ITexture *getTexture(); + video::ITexture *getTexture(bool srgb = false, bool premul_alpha = false); // ------------------------------------------------------------------------ bool isIgnore () const { return m_ignore; } // ------------------------------------------------------------------------ @@ -419,7 +419,8 @@ public: /** True if this texture should have the U coordinates mirrored. */ char getMirrorAxisInReverse() const { return m_mirror_axis_when_reverse; } // ------------------------------------------------------------------------ -} ; + const std::string getAlphaMask() const { return m_mask; } +}; #endif diff --git a/src/graphics/material_manager.cpp b/src/graphics/material_manager.cpp index 8666b125e..2e7e3d907 100644 --- a/src/graphics/material_manager.cpp +++ b/src/graphics/material_manager.cpp @@ -78,13 +78,8 @@ Material* MaterialManager::getMaterialFor(video::ITexture* t, } //----------------------------------------------------------------------------- - -Material* MaterialManager::getMaterialFor(video::ITexture* t, - video::E_MATERIAL_TYPE material_type) +Material* MaterialManager::getMaterialFor(video::ITexture* t) { - if (t == NULL) - return getDefaultMaterial(material_type); - core::stringc img_path = core::stringc(t->getName()); img_path.make_lower(); @@ -116,6 +111,19 @@ Material* MaterialManager::getMaterialFor(video::ITexture* t, } } // for i } + return NULL; +} + +//----------------------------------------------------------------------------- +Material* MaterialManager::getMaterialFor(video::ITexture* t, + video::E_MATERIAL_TYPE material_type) +{ + if (t == NULL) + return getDefaultMaterial(material_type); + + Material* m = getMaterialFor(t); + if (m != NULL) + return m; return getDefaultMaterial(material_type); } diff --git a/src/graphics/material_manager.hpp b/src/graphics/material_manager.hpp index 6f3a7f0a3..bd113008d 100644 --- a/src/graphics/material_manager.hpp +++ b/src/graphics/material_manager.hpp @@ -61,6 +61,7 @@ public: scene::IMeshBuffer *mb); Material* getMaterialFor(video::ITexture* t, video::E_MATERIAL_TYPE material_type); + Material* getMaterialFor(video::ITexture* t); void setAllMaterialFlags(video::ITexture* t, scene::IMeshBuffer *mb); void adjustForFog(video::ITexture* t, diff --git a/src/graphics/skybox.cpp b/src/graphics/skybox.cpp index 9cc16df59..80cd3c5b4 100644 --- a/src/graphics/skybox.cpp +++ b/src/graphics/skybox.cpp @@ -333,6 +333,7 @@ Out of legacy the sequence of textures maps to: */ Skybox::Skybox(const std::vector &skybox_textures) { + return; m_skybox_textures = skybox_textures; #if !defined(USE_GLES2) diff --git a/src/graphics/spherical_harmonics.cpp b/src/graphics/spherical_harmonics.cpp index 0d1f0657b..f9d301270 100644 --- a/src/graphics/spherical_harmonics.cpp +++ b/src/graphics/spherical_harmonics.cpp @@ -385,6 +385,7 @@ SphericalHarmonics::~SphericalHarmonics() /** Compute spherical harmonics coefficients from 6 textures */ void SphericalHarmonics::setTextures(const std::vector &spherical_harmonics_textures) { + return; assert(spherical_harmonics_textures.size() == 6); m_spherical_harmonics_textures = spherical_harmonics_textures; diff --git a/src/graphics/stk_mesh_loader.cpp b/src/graphics/stk_mesh_loader.cpp new file mode 100644 index 000000000..fa6a3c54b --- /dev/null +++ b/src/graphics/stk_mesh_loader.cpp @@ -0,0 +1,1109 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2017 SuperTuxKart-Team +// +// 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/stk_mesh_loader.hpp" +#include "graphics/central_settings.hpp" +#include "graphics/stk_texture.hpp" +#include "graphics/stk_tex_manager.hpp" + +#include +#include +#include "../../lib/irrlicht/source/Irrlicht/os.h" + +#undef _B3D_READER_DEBUG + +//! Constructor +STKMeshLoader::STKMeshLoader(scene::ISceneManager* smgr) +: SceneManager(smgr), AnimatedMesh(0), B3DFile(0), NormalsInFile(false), + HasVertexColors(false), ShowWarning(true) +{ + #ifdef _DEBUG + setDebugName("STKMeshLoader"); + #endif +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool STKMeshLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "b3d" ); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +scene::IAnimatedMesh* STKMeshLoader::createMesh(io::IReadFile* f) +{ + if (!f) + return 0; + + B3DFile = f; + AnimatedMesh = new scene::CSkinnedMesh(); + ShowWarning = true; // If true a warning is issued if too many textures are used + VerticesStart=0; + + if ( load() ) + { + AnimatedMesh->finalize(); + } + else + { + AnimatedMesh->drop(); + AnimatedMesh = 0; + } + + return AnimatedMesh; +} + + +bool STKMeshLoader::load() +{ + B3dStack.clear(); + + NormalsInFile=false; + HasVertexColors=false; + + //------ Get header ------ + + SB3dChunkHeader header; + B3DFile->read(&header, sizeof(header)); +#ifdef __BIG_ENDIAN__ + header.size = os::Byteswap::byteswap(header.size); +#endif + + if ( strncmp( header.name, "BB3D", 4 ) != 0 ) + { + os::Printer::log("File is not a b3d file. Loading failed (No header found)", B3DFile->getFileName(), ELL_ERROR); + return false; + } + + // Add main chunk... + B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8)); + + // Get file version, but ignore it, as it's not important with b3d files... + s32 fileVersion; + B3DFile->read(&fileVersion, sizeof(fileVersion)); +#ifdef __BIG_ENDIAN__ + fileVersion = os::Byteswap::byteswap(fileVersion); +#endif + + //------ Read main chunk ------ + + while ( (B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos() ) + { + B3DFile->read(&header, sizeof(header)); +#ifdef __BIG_ENDIAN__ + header.size = os::Byteswap::byteswap(header.size); +#endif + B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8)); + + if ( strncmp( B3dStack.getLast().name, "TEXS", 4 ) == 0 ) + { + if (!readChunkTEXS()) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "BRUS", 4 ) == 0 ) + { + if (!readChunkBRUS()) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 ) + { + if (!readChunkNODE((scene::CSkinnedMesh::SJoint*)0) ) + return false; + } + else + { + os::Printer::log("Unknown chunk found in mesh base - skipping"); + B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length); + B3dStack.erase(B3dStack.size()-1); + } + } + + B3dStack.clear(); + + BaseVertices.clear(); + AnimatedVertices_VertexID.clear(); + AnimatedVertices_BufferID.clear(); + + Materials.clear(); + Textures.clear(); + + return true; +} + + +bool STKMeshLoader::readChunkNODE(scene::CSkinnedMesh::SJoint *inJoint) +{ + scene::CSkinnedMesh::SJoint *joint = AnimatedMesh->addJoint(inJoint); + readString(joint->Name); + +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkNODE"; + os::Printer::log(logStr.c_str(), joint->Name.c_str()); +#endif + + f32 position[3], scale[3], rotation[4]; + + readFloats(position, 3); + readFloats(scale, 3); + readFloats(rotation, 4); + + joint->Animatedposition = core::vector3df(position[0],position[1],position[2]) ; + joint->Animatedscale = core::vector3df(scale[0],scale[1],scale[2]); + joint->Animatedrotation = core::quaternion(rotation[1], rotation[2], rotation[3], rotation[0]); + + //Build LocalMatrix: + + core::matrix4 positionMatrix; + positionMatrix.setTranslation( joint->Animatedposition ); + core::matrix4 scaleMatrix; + scaleMatrix.setScale( joint->Animatedscale ); + core::matrix4 rotationMatrix; + joint->Animatedrotation.getMatrix_transposed(rotationMatrix); + + joint->LocalMatrix = positionMatrix * rotationMatrix * scaleMatrix; + + if (inJoint) + joint->GlobalMatrix = inJoint->GlobalMatrix * joint->LocalMatrix; + else + joint->GlobalMatrix = joint->LocalMatrix; + + while(B3dStack.getLast().startposition + B3dStack.getLast().length > B3DFile->getPos()) // this chunk repeats + { + SB3dChunkHeader header; + B3DFile->read(&header, sizeof(header)); +#ifdef __BIG_ENDIAN__ + header.size = os::Byteswap::byteswap(header.size); +#endif + + B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8)); + + if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 ) + { + if (!readChunkNODE(joint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "MESH", 4 ) == 0 ) + { + VerticesStart=BaseVertices.size(); + if (!readChunkMESH(joint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "BONE", 4 ) == 0 ) + { + if (!readChunkBONE(joint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "KEYS", 4 ) == 0 ) + { + if(!readChunkKEYS(joint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "ANIM", 4 ) == 0 ) + { + if (!readChunkANIM()) + return false; + } + else + { + os::Printer::log("Unknown chunk found in node chunk - skipping"); + B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length); + B3dStack.erase(B3dStack.size()-1); + } + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + + +bool STKMeshLoader::readChunkMESH(scene::CSkinnedMesh::SJoint *inJoint) +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkMESH"; + os::Printer::log(logStr.c_str()); +#endif + + s32 brushID; + B3DFile->read(&brushID, sizeof(brushID)); +#ifdef __BIG_ENDIAN__ + brushID = os::Byteswap::byteswap(brushID); +#endif + + NormalsInFile=false; + HasVertexColors=false; + + while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats + { + SB3dChunkHeader header; + B3DFile->read(&header, sizeof(header)); +#ifdef __BIG_ENDIAN__ + header.size = os::Byteswap::byteswap(header.size); +#endif + + B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8)); + + if ( strncmp( B3dStack.getLast().name, "VRTS", 4 ) == 0 ) + { + if (!readChunkVRTS(inJoint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "TRIS", 4 ) == 0 ) + { + scene::SSkinMeshBuffer *meshBuffer = AnimatedMesh->addMeshBuffer(); + + if (brushID!=-1) + { + loadTextures(Materials[brushID]); + meshBuffer->Material=Materials[brushID].Material; + } + + if(readChunkTRIS(meshBuffer,AnimatedMesh->getMeshBuffers().size()-1, VerticesStart)==false) + return false; + + if (!NormalsInFile) + { + s32 i; + + for ( i=0; i<(s32)meshBuffer->Indices.size(); i+=3) + { + core::plane3df p(meshBuffer->getVertex(meshBuffer->Indices[i+0])->Pos, + meshBuffer->getVertex(meshBuffer->Indices[i+1])->Pos, + meshBuffer->getVertex(meshBuffer->Indices[i+2])->Pos); + + meshBuffer->getVertex(meshBuffer->Indices[i+0])->Normal += p.Normal; + meshBuffer->getVertex(meshBuffer->Indices[i+1])->Normal += p.Normal; + meshBuffer->getVertex(meshBuffer->Indices[i+2])->Normal += p.Normal; + } + + for ( i = 0; i<(s32)meshBuffer->getVertexCount(); ++i ) + { + meshBuffer->getVertex(i)->Normal.normalize(); + BaseVertices[VerticesStart+i].Normal=meshBuffer->getVertex(i)->Normal; + } + } + } + else + { + os::Printer::log("Unknown chunk found in mesh - skipping"); + B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length); + B3dStack.erase(B3dStack.size()-1); + } + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + + +/* +VRTS: + int flags ;1=normal values present, 2=rgba values present + int tex_coord_sets ;texture coords per vertex (eg: 1 for simple U/V) max=8 + but we only support 3 + int tex_coord_set_size ;components per set (eg: 2 for simple U/V) max=4 + { + float x,y,z ;always present + float nx,ny,nz ;vertex normal: present if (flags&1) + float red,green,blue,alpha ;vertex color: present if (flags&2) + float tex_coords[tex_coord_sets][tex_coord_set_size] ;tex coords + } +*/ +bool STKMeshLoader::readChunkVRTS(scene::CSkinnedMesh::SJoint *inJoint) +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "ChunkVRTS"; + os::Printer::log(logStr.c_str()); +#endif + + const s32 max_tex_coords = 3; + s32 flags, tex_coord_sets, tex_coord_set_size; + + B3DFile->read(&flags, sizeof(flags)); + B3DFile->read(&tex_coord_sets, sizeof(tex_coord_sets)); + B3DFile->read(&tex_coord_set_size, sizeof(tex_coord_set_size)); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); + tex_coord_sets = os::Byteswap::byteswap(tex_coord_sets); + tex_coord_set_size = os::Byteswap::byteswap(tex_coord_set_size); +#endif + + if (tex_coord_sets >= max_tex_coords || tex_coord_set_size >= 4) // Something is wrong + { + os::Printer::log("tex_coord_sets or tex_coord_set_size too big", B3DFile->getFileName(), ELL_ERROR); + return false; + } + + //------ Allocate Memory, for speed -----------// + + s32 numberOfReads = 3; + + if (flags & 1) + { + NormalsInFile = true; + numberOfReads += 3; + } + if (flags & 2) + { + numberOfReads += 4; + HasVertexColors=true; + } + + numberOfReads += tex_coord_sets*tex_coord_set_size; + + const s32 memoryNeeded = (B3dStack.getLast().length / sizeof(f32)) / numberOfReads; + + BaseVertices.reallocate(memoryNeeded + BaseVertices.size() + 1); + AnimatedVertices_VertexID.reallocate(memoryNeeded + AnimatedVertices_VertexID.size() + 1); + + //--------------------------------------------// + + while( (B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats + { + f32 position[3]; + f32 normal[3]={0.f, 0.f, 0.f}; + f32 color[4]={1.0f, 1.0f, 1.0f, 1.0f}; + f32 tex_coords[max_tex_coords][4]; + + readFloats(position, 3); + + if (flags & 1) + readFloats(normal, 3); + if (flags & 2) + readFloats(color, 4); + + for (s32 i=0; i= 1 && tex_coord_set_size >= 2) + { + tu=tex_coords[0][0]; + tv=tex_coords[0][1]; + } + + f32 tu2=0.0f, tv2=0.0f; + if (tex_coord_sets>1 && tex_coord_set_size>1) + { + tu2=tex_coords[1][0]; + tv2=tex_coords[1][1]; + } + + // Create Vertex... + video::S3DVertex2TCoords Vertex(position[0], position[1], position[2], + normal[0], normal[1], normal[2], + video::SColorf(color[0], color[1], color[2], color[3]).toSColor(), + tu, tv, tu2, tv2); + + // Transform the Vertex position by nested node... + inJoint->GlobalMatrix.transformVect(Vertex.Pos); + inJoint->GlobalMatrix.rotateVect(Vertex.Normal); + + //Add it... + BaseVertices.push_back(Vertex); + + AnimatedVertices_VertexID.push_back(-1); + AnimatedVertices_BufferID.push_back(-1); + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + + +bool STKMeshLoader::readChunkTRIS(scene::SSkinMeshBuffer *meshBuffer, u32 meshBufferID, s32 vertices_Start) +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "ChunkTRIS"; + os::Printer::log(logStr.c_str()); +#endif + + bool showVertexWarning=false; + + s32 triangle_brush_id; // Note: Irrlicht can't have different brushes for each triangle (using a workaround) + B3DFile->read(&triangle_brush_id, sizeof(triangle_brush_id)); +#ifdef __BIG_ENDIAN__ + triangle_brush_id = os::Byteswap::byteswap(triangle_brush_id); +#endif + + SB3dMaterial *B3dMaterial; + + if (triangle_brush_id != -1) + { + loadTextures(Materials[triangle_brush_id]); + B3dMaterial = &Materials[triangle_brush_id]; + meshBuffer->Material = B3dMaterial->Material; + } + else + B3dMaterial = 0; + + const s32 memoryNeeded = B3dStack.getLast().length / sizeof(s32); + meshBuffer->Indices.reallocate(memoryNeeded + meshBuffer->Indices.size() + 1); + + while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats + { + s32 vertex_id[3]; + + B3DFile->read(vertex_id, 3*sizeof(s32)); +#ifdef __BIG_ENDIAN__ + vertex_id[0] = os::Byteswap::byteswap(vertex_id[0]); + vertex_id[1] = os::Byteswap::byteswap(vertex_id[1]); + vertex_id[2] = os::Byteswap::byteswap(vertex_id[2]); +#endif + + //Make Ids global: + vertex_id[0] += vertices_Start; + vertex_id[1] += vertices_Start; + vertex_id[2] += vertices_Start; + + for(s32 i=0; i<3; ++i) + { + if ((u32)vertex_id[i] >= AnimatedVertices_VertexID.size()) + { + os::Printer::log("Illegal vertex index found", B3DFile->getFileName(), ELL_ERROR); + return false; + } + + if (AnimatedVertices_VertexID[ vertex_id[i] ] != -1) + { + if ( AnimatedVertices_BufferID[ vertex_id[i] ] != (s32)meshBufferID ) //If this vertex is linked in a different meshbuffer + { + AnimatedVertices_VertexID[ vertex_id[i] ] = -1; + AnimatedVertices_BufferID[ vertex_id[i] ] = -1; + showVertexWarning=true; + } + } + if (AnimatedVertices_VertexID[ vertex_id[i] ] == -1) //If this vertex is not in the meshbuffer + { + //Check for lightmapping: + if (BaseVertices[ vertex_id[i] ].TCoords2 != core::vector2df(0.f,0.f)) + meshBuffer->convertTo2TCoords(); //Will only affect the meshbuffer the first time this is called + + //Add the vertex to the meshbuffer: + if (meshBuffer->VertexType == video::EVT_STANDARD) + meshBuffer->Vertices_Standard.push_back( BaseVertices[ vertex_id[i] ] ); + else + meshBuffer->Vertices_2TCoords.push_back(BaseVertices[ vertex_id[i] ] ); + + //create vertex id to meshbuffer index link: + AnimatedVertices_VertexID[ vertex_id[i] ] = meshBuffer->getVertexCount()-1; + AnimatedVertices_BufferID[ vertex_id[i] ] = meshBufferID; + + if (B3dMaterial) + { + // Apply Material/Color/etc... + video::S3DVertex *Vertex=meshBuffer->getVertex(meshBuffer->getVertexCount()-1); + + if (!HasVertexColors) + Vertex->Color=B3dMaterial->Material.DiffuseColor; + else if (Vertex->Color.getAlpha() == 255) + Vertex->Color.setAlpha( (s32)(B3dMaterial->alpha * 255.0f) ); + + // Use texture's scale + if (B3dMaterial->Textures[0]) + { + Vertex->TCoords.X *= B3dMaterial->Textures[0]->Xscale; + Vertex->TCoords.Y *= B3dMaterial->Textures[0]->Yscale; + } + /* + if (B3dMaterial->Textures[1]) + { + Vertex->TCoords2.X *=B3dMaterial->Textures[1]->Xscale; + Vertex->TCoords2.Y *=B3dMaterial->Textures[1]->Yscale; + } + */ + } + } + } + + meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[0] ] ); + meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[1] ] ); + meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[2] ] ); + } + + B3dStack.erase(B3dStack.size()-1); + + if (showVertexWarning) + os::Printer::log("B3dMeshLoader: Warning, different meshbuffers linking to the same vertex, this will cause problems with animated meshes"); + + return true; +} + + +bool STKMeshLoader::readChunkBONE(scene::CSkinnedMesh::SJoint *inJoint) +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkBONE"; + os::Printer::log(logStr.c_str()); +#endif + + if (B3dStack.getLast().length > 8) + { + while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats + { + u32 globalVertexID; + f32 strength; + B3DFile->read(&globalVertexID, sizeof(globalVertexID)); + B3DFile->read(&strength, sizeof(strength)); +#ifdef __BIG_ENDIAN__ + globalVertexID = os::Byteswap::byteswap(globalVertexID); + strength = os::Byteswap::byteswap(strength); +#endif + globalVertexID += VerticesStart; + + if (AnimatedVertices_VertexID[globalVertexID]==-1) + { + os::Printer::log("B3dMeshLoader: Weight has bad vertex id (no link to meshbuffer index found)"); + } + else if (strength >0) + { + scene::CSkinnedMesh::SWeight *weight=AnimatedMesh->addWeight(inJoint); + weight->strength=strength; + //Find the meshbuffer and Vertex index from the Global Vertex ID: + weight->vertex_id = AnimatedVertices_VertexID[globalVertexID]; + weight->buffer_id = AnimatedVertices_BufferID[globalVertexID]; + } + } + } + + B3dStack.erase(B3dStack.size()-1); + return true; +} + + +bool STKMeshLoader::readChunkKEYS(scene::CSkinnedMesh::SJoint *inJoint) +{ +#ifdef _B3D_READER_DEBUG + // Only print first, that's just too much output otherwise + if ( !inJoint || (inJoint->PositionKeys.empty() && inJoint->ScaleKeys.empty() && inJoint->RotationKeys.empty()) ) + { + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkKEYS"; + os::Printer::log(logStr.c_str()); + } +#endif + + s32 flags; + B3DFile->read(&flags, sizeof(flags)); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + + scene::CSkinnedMesh::SPositionKey *oldPosKey=0; + core::vector3df oldPos[2]; + scene::CSkinnedMesh::SScaleKey *oldScaleKey=0; + core::vector3df oldScale[2]; + scene::CSkinnedMesh::SRotationKey *oldRotKey=0; + core::quaternion oldRot[2]; + bool isFirst[3]={true,true,true}; + while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats + { + s32 frame; + + B3DFile->read(&frame, sizeof(frame)); + #ifdef __BIG_ENDIAN__ + frame = os::Byteswap::byteswap(frame); + #endif + + // Add key frames, frames in Irrlicht are zero-based + f32 data[4]; + if (flags & 1) + { + readFloats(data, 3); + if ((oldPosKey!=0) && (oldPos[0]==oldPos[1])) + { + const core::vector3df pos(data[0], data[1], data[2]); + if (oldPos[1]==pos) + oldPosKey->frame = (f32)frame-1; + else + { + oldPos[0]=oldPos[1]; + oldPosKey=AnimatedMesh->addPositionKey(inJoint); + oldPosKey->frame = (f32)frame-1; + oldPos[1].set(oldPosKey->position.set(pos)); + } + } + else if (oldPosKey==0 && isFirst[0]) + { + oldPosKey=AnimatedMesh->addPositionKey(inJoint); + oldPosKey->frame = (f32)frame-1; + oldPos[0].set(oldPosKey->position.set(data[0], data[1], data[2])); + oldPosKey=0; + isFirst[0]=false; + } + else + { + if (oldPosKey!=0) + oldPos[0]=oldPos[1]; + oldPosKey=AnimatedMesh->addPositionKey(inJoint); + oldPosKey->frame = (f32)frame-1; + oldPos[1].set(oldPosKey->position.set(data[0], data[1], data[2])); + } + } + if (flags & 2) + { + readFloats(data, 3); + if ((oldScaleKey!=0) && (oldScale[0]==oldScale[1])) + { + const core::vector3df scale(data[0], data[1], data[2]); + if (oldScale[1]==scale) + oldScaleKey->frame = (f32)frame-1; + else + { + oldScale[0]=oldScale[1]; + oldScaleKey=AnimatedMesh->addScaleKey(inJoint); + oldScaleKey->frame = (f32)frame-1; + oldScale[1].set(oldScaleKey->scale.set(scale)); + } + } + else if (oldScaleKey==0 && isFirst[1]) + { + oldScaleKey=AnimatedMesh->addScaleKey(inJoint); + oldScaleKey->frame = (f32)frame-1; + oldScale[0].set(oldScaleKey->scale.set(data[0], data[1], data[2])); + oldScaleKey=0; + isFirst[1]=false; + } + else + { + if (oldScaleKey!=0) + oldScale[0]=oldScale[1]; + oldScaleKey=AnimatedMesh->addScaleKey(inJoint); + oldScaleKey->frame = (f32)frame-1; + oldScale[1].set(oldScaleKey->scale.set(data[0], data[1], data[2])); + } + } + if (flags & 4) + { + readFloats(data, 4); + if ((oldRotKey!=0) && (oldRot[0]==oldRot[1])) + { + // meant to be in this order since b3d stores W first + const core::quaternion rot(data[1], data[2], data[3], data[0]); + if (oldRot[1]==rot) + oldRotKey->frame = (f32)frame-1; + else + { + oldRot[0]=oldRot[1]; + oldRotKey=AnimatedMesh->addRotationKey(inJoint); + oldRotKey->frame = (f32)frame-1; + oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); + } + } + else if (oldRotKey==0 && isFirst[2]) + { + oldRotKey=AnimatedMesh->addRotationKey(inJoint); + oldRotKey->frame = (f32)frame-1; + // meant to be in this order since b3d stores W first + oldRot[0].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); + oldRotKey=0; + isFirst[2]=false; + } + else + { + if (oldRotKey!=0) + oldRot[0]=oldRot[1]; + oldRotKey=AnimatedMesh->addRotationKey(inJoint); + oldRotKey->frame = (f32)frame-1; + // meant to be in this order since b3d stores W first + oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); + } + } + } + + B3dStack.erase(B3dStack.size()-1); + return true; +} + + +bool STKMeshLoader::readChunkANIM() +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkANIM"; + os::Printer::log(logStr.c_str()); +#endif + + s32 animFlags; //not stored\used + s32 animFrames;//not stored\used + f32 animFPS; //not stored\used + + B3DFile->read(&animFlags, sizeof(s32)); + B3DFile->read(&animFrames, sizeof(s32)); + readFloats(&animFPS, 1); + if (animFPS>0.f) + AnimatedMesh->setAnimationSpeed(animFPS); + os::Printer::log("FPS", io::path((double)animFPS), ELL_DEBUG); + + #ifdef __BIG_ENDIAN__ + animFlags = os::Byteswap::byteswap(animFlags); + animFrames = os::Byteswap::byteswap(animFrames); + #endif + + B3dStack.erase(B3dStack.size()-1); + return true; +} + + +bool STKMeshLoader::readChunkTEXS() +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkTEXS"; + os::Printer::log(logStr.c_str()); +#endif + + while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats + { + Textures.push_back(SB3dTexture()); + SB3dTexture& B3dTexture = Textures.getLast(); + + readString(B3dTexture.TextureName); + B3dTexture.TextureName.replace('\\','/'); +#ifdef _B3D_READER_DEBUG + os::Printer::log("read Texture", B3dTexture.TextureName.c_str()); +#endif + + B3DFile->read(&B3dTexture.Flags, sizeof(s32)); + B3DFile->read(&B3dTexture.Blend, sizeof(s32)); +#ifdef __BIG_ENDIAN__ + B3dTexture.Flags = os::Byteswap::byteswap(B3dTexture.Flags); + B3dTexture.Blend = os::Byteswap::byteswap(B3dTexture.Blend); +#endif +#ifdef _B3D_READER_DEBUG + os::Printer::log("Flags", core::stringc(B3dTexture.Flags).c_str()); + os::Printer::log("Blend", core::stringc(B3dTexture.Blend).c_str()); +#endif + readFloats(&B3dTexture.Xpos, 1); + readFloats(&B3dTexture.Ypos, 1); + readFloats(&B3dTexture.Xscale, 1); + readFloats(&B3dTexture.Yscale, 1); + readFloats(&B3dTexture.Angle, 1); + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + + +bool STKMeshLoader::readChunkBRUS() +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkBRUS"; + os::Printer::log(logStr.c_str()); +#endif + + u32 n_texs; + B3DFile->read(&n_texs, sizeof(u32)); +#ifdef __BIG_ENDIAN__ + n_texs = os::Byteswap::byteswap(n_texs); +#endif + + // number of texture ids read for Irrlicht + const u32 num_textures = core::min_(n_texs, video::MATERIAL_MAX_TEXTURES); + // number of bytes to skip (for ignored texture ids) + const u32 n_texs_offset = (num_textures B3DFile->getPos()) //this chunk repeats + { + // This is what blitz basic calls a brush, like a Irrlicht Material + + core::stringc name; + readString(name); +#ifdef _B3D_READER_DEBUG + os::Printer::log("read Material", name); +#endif + Materials.push_back(SB3dMaterial()); + SB3dMaterial& B3dMaterial=Materials.getLast(); + + readFloats(&B3dMaterial.red, 1); + readFloats(&B3dMaterial.green, 1); + readFloats(&B3dMaterial.blue, 1); + readFloats(&B3dMaterial.alpha, 1); + readFloats(&B3dMaterial.shininess, 1); + + B3DFile->read(&B3dMaterial.blend, sizeof(B3dMaterial.blend)); + B3DFile->read(&B3dMaterial.fx, sizeof(B3dMaterial.fx)); +#ifdef __BIG_ENDIAN__ + B3dMaterial.blend = os::Byteswap::byteswap(B3dMaterial.blend); + B3dMaterial.fx = os::Byteswap::byteswap(B3dMaterial.fx); +#endif +#ifdef _B3D_READER_DEBUG + os::Printer::log("Blend", core::stringc(B3dMaterial.blend).c_str()); + os::Printer::log("FX", core::stringc(B3dMaterial.fx).c_str()); +#endif + + u32 i; + for (i=0; iread(&texture_id, sizeof(s32)); +#ifdef __BIG_ENDIAN__ + texture_id = os::Byteswap::byteswap(texture_id); +#endif + //--- Get pointers to the texture, based on the IDs --- + if ((u32)texture_id < Textures.size()) + { + B3dMaterial.Textures[i]=&Textures[texture_id]; +#ifdef _B3D_READER_DEBUG + os::Printer::log("Layer", core::stringc(i).c_str()); + os::Printer::log("using texture", Textures[texture_id].TextureName.c_str()); +#endif + } + else + B3dMaterial.Textures[i]=0; + } + // skip other texture ids + for (i=0; iread(&texture_id, sizeof(s32)); +#ifdef __BIG_ENDIAN__ + texture_id = os::Byteswap::byteswap(texture_id); +#endif + if (ShowWarning && (texture_id != -1) && (n_texs>video::MATERIAL_MAX_TEXTURES)) + { + os::Printer::log("Too many textures used in one material", B3DFile->getFileName(), ELL_WARNING); + ShowWarning = false; + } + } + + //Fixes problems when the lightmap is on the first texture: + if (B3dMaterial.Textures[0] != 0) + { + if (B3dMaterial.Textures[0]->Flags & 65536) // 65536 = secondary UV + { + SB3dTexture *TmpTexture; + TmpTexture = B3dMaterial.Textures[1]; + B3dMaterial.Textures[1] = B3dMaterial.Textures[0]; + B3dMaterial.Textures[0] = TmpTexture; + } + } + + //If a preceeding texture slot is empty move the others down: + for (i=num_textures; i>0; --i) + { + for (u32 j=i-1; jBlend == 5) //(Multiply 2) + B3dMaterial.Material.MaterialType = video::EMT_LIGHTMAP_M2; + else + B3dMaterial.Material.MaterialType = video::EMT_LIGHTMAP; + B3dMaterial.Material.Lighting = false; + } + else + { + B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + B3dMaterial.Material.ZWriteEnable = false; + } + } + else if (B3dMaterial.Textures[0]) //One texture: + { + // Flags & 0x1 is usual SOLID, 0x8 is mipmap (handled before) + if (B3dMaterial.Textures[0]->Flags & 0x2) //(Alpha mapped) + { + B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + B3dMaterial.Material.ZWriteEnable = false; + } + else if (B3dMaterial.Textures[0]->Flags & 0x4) //(Masked) + B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; // TODO: create color key texture + else if (B3dMaterial.Textures[0]->Flags & 0x40) + B3dMaterial.Material.MaterialType = video::EMT_SPHERE_MAP; + else if (B3dMaterial.Textures[0]->Flags & 0x80) + B3dMaterial.Material.MaterialType = video::EMT_SPHERE_MAP; // TODO: Should be cube map + else if (B3dMaterial.alpha == 1.f) + B3dMaterial.Material.MaterialType = video::EMT_SOLID; + else + { + B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + B3dMaterial.Material.ZWriteEnable = false; + } + } + else //No texture: + { + if (B3dMaterial.alpha == 1.f) + B3dMaterial.Material.MaterialType = video::EMT_SOLID; + else + { + B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + B3dMaterial.Material.ZWriteEnable = false; + } + } + + B3dMaterial.Material.DiffuseColor = video::SColorf(B3dMaterial.red, B3dMaterial.green, B3dMaterial.blue, B3dMaterial.alpha).toSColor(); + B3dMaterial.Material.ColorMaterial=video::ECM_NONE; + + //------ Material fx ------ + + if (B3dMaterial.fx & 1) //full-bright + { + B3dMaterial.Material.AmbientColor = video::SColor(255, 255, 255, 255); + B3dMaterial.Material.Lighting = false; + } + else + B3dMaterial.Material.AmbientColor = B3dMaterial.Material.DiffuseColor; + + if (B3dMaterial.fx & 2) //use vertex colors instead of brush color + B3dMaterial.Material.ColorMaterial=video::ECM_DIFFUSE_AND_AMBIENT; + + if (B3dMaterial.fx & 4) //flatshaded + B3dMaterial.Material.GouraudShading = false; + + if (B3dMaterial.fx & 16) //disable backface culling + B3dMaterial.Material.BackfaceCulling = false; + + if (B3dMaterial.fx & 32) //force vertex alpha-blending + { + B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + B3dMaterial.Material.ZWriteEnable = false; + } + + B3dMaterial.Material.Shininess = B3dMaterial.shininess; + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + + +void STKMeshLoader::loadTextures(SB3dMaterial& material) const +{ + const bool previous32BitTextureFlag = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_ALWAYS_32_BIT); + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true); + + // read texture from disk + // note that mipmaps might be disabled by Flags & 0x8 + const bool doMipMaps = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); + + for (u32 i=0; iTextureName.size() && !material.Material.getTexture(i)) + { + video::ITexture* tex = NULL; + if (!SceneManager->getParameters()->getAttributeAsBool(scene::B3D_LOADER_IGNORE_MIPMAP_FLAG)) + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, (B3dTexture->Flags & 0x8) ? true:false); + io::IFileSystem* fs = SceneManager->getFileSystem(); + io::path texnameWithUserPath( SceneManager->getParameters()->getAttributeAsString(scene::B3D_TEXTURE_PATH) ); + if ( texnameWithUserPath.size() ) + { + texnameWithUserPath += '/'; + texnameWithUserPath += B3dTexture->TextureName; + } + core::stringc full_path; + if (fs->existFile(texnameWithUserPath)) + full_path = texnameWithUserPath; + else if (fs->existFile(fs->getFileDir(B3DFile->getFileName()) +"/"+ fs->getFileBasename(B3dTexture->TextureName))) + full_path = fs->getFileDir(B3DFile->getFileName()) +"/"+ fs->getFileBasename(B3dTexture->TextureName); + else + full_path = fs->getFileBasename(B3dTexture->TextureName); + +#ifndef SERVER_ONLY + if (CVS->isGLSL()) + { + tex = STKTexManager::getInstance()->getTexture(full_path.c_str(), + i == 0 ? true : false/*is_srgb*/, false/*premul_alpha*/, + true/*set_material*/); + } + else +#endif // !SERVER_ONLY + { + tex = SceneManager->getVideoDriver()->getTexture(full_path); + } + material.Material.setTexture(i, tex); + if (material.Textures[i]->Flags & 0x10) // Clamp U + material.Material.TextureLayer[i].TextureWrapU=video::ETC_CLAMP; + if (material.Textures[i]->Flags & 0x20) // Clamp V + material.Material.TextureLayer[i].TextureWrapV=video::ETC_CLAMP; + } + } + + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, doMipMaps); + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, previous32BitTextureFlag); +} + + +void STKMeshLoader::readString(core::stringc& newstring) +{ + newstring=""; + while (B3DFile->getPos() <= B3DFile->getSize()) + { + c8 character; + B3DFile->read(&character, sizeof(character)); + if (character==0) + return; + newstring.append(character); + } +} + + +void STKMeshLoader::readFloats(f32* vec, u32 count) +{ + B3DFile->read(vec, count*sizeof(f32)); + #ifdef __BIG_ENDIAN__ + for (u32 n=0; n +#include +#include + +using namespace irr; + +class STKMeshLoader : public scene::IMeshLoader +{ +public: + + //! Constructor + STKMeshLoader(scene::ISceneManager* smgr); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".bsp") + virtual bool isALoadableFileExtension(const io::path& filename) const; + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IReferenceCounted::drop() for more information. + virtual scene::IAnimatedMesh* createMesh(io::IReadFile* file); + +private: + + struct SB3dChunkHeader + { + c8 name[4]; + s32 size; + }; + + struct SB3dChunk + { + SB3dChunk(const SB3dChunkHeader& header, long sp) + : length(header.size+8), startposition(sp) + { + name[0]=header.name[0]; + name[1]=header.name[1]; + name[2]=header.name[2]; + name[3]=header.name[3]; + } + + c8 name[4]; + s32 length; + long startposition; + }; + + struct SB3dTexture + { + core::stringc TextureName; + s32 Flags; + s32 Blend; + f32 Xpos; + f32 Ypos; + f32 Xscale; + f32 Yscale; + f32 Angle; + }; + + struct SB3dMaterial + { + SB3dMaterial() : red(1.0f), green(1.0f), + blue(1.0f), alpha(1.0f), shininess(0.0f), blend(1), + fx(0) + { + for (u32 i=0; i B3dStack; + + core::array Materials; + core::array Textures; + + core::array AnimatedVertices_VertexID; + + core::array AnimatedVertices_BufferID; + + core::array BaseVertices; + + scene::ISceneManager* SceneManager; + scene::CSkinnedMesh* AnimatedMesh; + io::IReadFile* B3DFile; + + //B3Ds have Vertex ID's local within the mesh I don't want this + // Variable needs to be class member due to recursion in calls + u32 VerticesStart; + + bool NormalsInFile; + bool HasVertexColors; + bool ShowWarning; +}; + +#endif + diff --git a/src/graphics/stk_tex_manager.cpp b/src/graphics/stk_tex_manager.cpp new file mode 100644 index 000000000..a9e887072 --- /dev/null +++ b/src/graphics/stk_tex_manager.cpp @@ -0,0 +1,126 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2017 SuperTuxKart-Team +// +// 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/stk_tex_manager.hpp" +#include "graphics/central_settings.hpp" +#include "graphics/stk_texture.hpp" +#include "io/file_manager.hpp" +#include "utils/string_utils.hpp" +#include "utils/log.hpp" + +#include +#include + +// ---------------------------------------------------------------------------- +STKTexManager::~STKTexManager() +{ +} // ~STKTexManager + +// ---------------------------------------------------------------------------- +STKTexture* STKTexManager::findTextureInFileSystem(const std::string& filename, + std::string* full_path) +{ + *full_path = file_manager->searchTexture(filename); + if (*full_path == "") + { + Log::warn("STKTexManager", "Failed to load %s.", filename.c_str()); + return NULL; + } + for (auto p : m_all_textures) + { + if (p.second == NULL) + continue; + if (*full_path == p.second->getName().getPtr()) + return p.second; + } + + return NULL; +} // findTextureInFileSystem + +// ---------------------------------------------------------------------------- +STKTexture* STKTexManager::findTexturePathless(const std::string& filename) +{ + for (auto p : m_all_textures) + { + if (p.second == NULL) + continue; + std::string lc_name = StringUtils::toLowerCase(filename); + std::string lc_path = + StringUtils::toLowerCase(p.second->getName().getPtr()); + std::string tex_name = StringUtils::getBasename(lc_path); + if (lc_name == tex_name || lc_name == lc_path) + return p.second; + } + + return NULL; +} // findTexturePathless + +// ---------------------------------------------------------------------------- +STKTexture* STKTexManager::getTexture(const std::string& path, bool srgb, + bool premul_alpha, bool set_material) +{ + auto ret = m_all_textures.find(path); + if (ret != m_all_textures.end()) + return ret->second; + + STKTexture* new_texture = NULL; + std::string full_path; + if (path.find('/') == std::string::npos) + { + new_texture = findTextureInFileSystem(path, &full_path); + if (full_path == "") + return NULL; + if (new_texture) + return new_texture; + } + + new_texture = new STKTexture(full_path == "" ? path : full_path, srgb, + premul_alpha, set_material); + new_texture->reload(); + if (new_texture->getOpenGLTextureName() == 0) + { + m_all_textures[new_texture->getName().getPtr()] = NULL; + delete new_texture; + return NULL; + } + + m_all_textures[new_texture->getName().getPtr()] = new_texture; + return new_texture; +} // getTexture + +// ---------------------------------------------------------------------------- +void STKTexManager::dumpAllTexture() +{ + for (auto p : m_all_textures) + { + Log::info("STKTexManager", "%s loc: %p", p.first.c_str(), p.second); + } +} // dumpAllTexture + +// ---------------------------------------------------------------------------- +int STKTexManager::dumpTextureUsage() +{ + int size = 0; + for (auto p : m_all_textures) + { + if (p.second == NULL) + continue; + size += p.second->getTextureSize() / 1024 / 1024; + } + Log::info("STKTexManager", "Total %dMB", size); + return size; +} // dumpAllTexture diff --git a/src/graphics/stk_tex_manager.hpp b/src/graphics/stk_tex_manager.hpp new file mode 100644 index 000000000..e7f239138 --- /dev/null +++ b/src/graphics/stk_tex_manager.hpp @@ -0,0 +1,61 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2016 SuperTuxKart-Team +// +// 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_STK_TEX_MANAGER_HPP +#define HEADER_STK_TEX_MANAGER_HPP + +#include "graphics/gl_headers.hpp" +#include "utils/no_copy.hpp" +#include "utils/singleton.hpp" + +#include +#include +#include + +class STKTexture; + +class STKTexManager : public Singleton, NoCopy +{ +private: + std::unordered_map m_all_textures; + +public: + // ------------------------------------------------------------------------ + STKTexManager() {} + // ------------------------------------------------------------------------ + ~STKTexManager(); + // ------------------------------------------------------------------------ + STKTexture* findTexturePathless(const std::string& filename); + // ------------------------------------------------------------------------ + STKTexture* findTextureInFileSystem(const std::string& filename, + std::string* full_path); + // ------------------------------------------------------------------------ + STKTexture* getTexture(const std::string& path, bool srgb = false, + bool premul_alpha = false, + bool set_material = false); + // ------------------------------------------------------------------------ + void removeTexture(STKTexture* t); + // ------------------------------------------------------------------------ + void dumpAllTexture(); + // ------------------------------------------------------------------------ + int dumpTextureUsage(); + // ------------------------------------------------------------------------ + void clean(); + +}; // STKTexManager + +#endif diff --git a/src/graphics/stk_texture.cpp b/src/graphics/stk_texture.cpp new file mode 100644 index 000000000..0c5d13dca --- /dev/null +++ b/src/graphics/stk_texture.cpp @@ -0,0 +1,214 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2017 SuperTuxKart-Team +// +// 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/stk_texture.hpp" +#include "graphics/central_settings.hpp" +#include "graphics/irr_driver.hpp" +#include "graphics/material.hpp" +#include "graphics/material_manager.hpp" +#include "io/file_manager.hpp" +#include "utils/string_utils.hpp" +#include "utils/log.hpp" + +#include +#include + +// ---------------------------------------------------------------------------- +STKTexture::STKTexture(const std::string& path, bool srgb, bool premul_alpha, + bool set_material) + : video::ITexture(path.c_str()), m_texture_handle(0), m_srgb(srgb), + m_premul_alpha(premul_alpha), m_mesh_texture(set_material), + m_material(NULL), m_texture_name(0), m_texture_size(0), + m_texture_image(NULL) +{ + if (set_material) + { + m_material = material_manager->getMaterialFor(this); + } +} // STKTexture + +// ---------------------------------------------------------------------------- +STKTexture::STKTexture(video::IImage* image) + : video::ITexture(""), m_texture_handle(0), m_srgb(false), + m_premul_alpha(false), + m_mesh_texture(false), m_texture_name(0), m_texture_size(0), + m_texture_image(image) +{ + m_size = m_texture_image->getDimension(); + m_orig_size = m_texture_image->getDimension(); +} // STKTexture + +// ---------------------------------------------------------------------------- +STKTexture::~STKTexture() +{ + if (m_texture_name != 0) + { + glDeleteTextures(1, &m_texture_name); + } + if (m_texture_image != NULL) + m_texture_image->drop(); +} // ~STKTexture + +// ---------------------------------------------------------------------------- +void STKTexture::reload() +{ +#ifndef SERVER_ONLY + irr_driver->getDevice()->getLogger()->setLogLevel(ELL_NONE); + video::IImage* orig_img = + irr_driver->getVideoDriver()->createImageFromFile(NamedPath); + if (orig_img == NULL) + { + Log::warn("STKTexture", "No image %s.", NamedPath.getPtr()); + return; + } + + if (orig_img->getDimension().Width == 0 || + orig_img->getDimension().Height == 0) + { + Log::warn("STKTexture", "image %s has 0 size.", NamedPath.getPtr()); + return; + } + + video::IImage* new_texture = convertImage(&orig_img); + applyMask(new_texture); + + const bool reload = m_texture_name != 0; + if (!reload) + glGenTextures(1, &m_texture_name); + + glBindTexture(GL_TEXTURE_2D, m_texture_name); + if (!reload) + { + glTexImage2D(GL_TEXTURE_2D, 0, m_srgb ? GL_SRGB_ALPHA : GL_RGBA, + new_texture->getDimension().Width, + new_texture->getDimension().Height, 0, GL_BGRA, GL_UNSIGNED_BYTE, + new_texture->lock()); + } + else + { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, + new_texture->getDimension().Width, + new_texture->getDimension().Height, GL_BGRA, GL_UNSIGNED_BYTE, + new_texture->lock()); + } + new_texture->unlock(); + m_size = new_texture->getDimension(); + m_orig_size = orig_img->getDimension(); + m_texture_size = m_size.Width * m_size.Height * 4 /*BRGA*/; + new_texture->drop(); + orig_img->drop(); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + irr_driver->getDevice()->getLogger()->setLogLevel(ELL_WARNING); +#endif // !SERVER_ONLY +} // reload + +// ---------------------------------------------------------------------------- +video::IImage* STKTexture::convertImage(video::IImage** orig_img) +{ +#ifndef SERVER_ONLY + video::IImage* image = *orig_img; + core::dimension2du size = image->getDimension(); + + bool scale_image = false; + const float ratio = float(size.Width) / float(size.Height); + const unsigned int drv_max_size = + irr_driver->getVideoDriver()->getMaxTextureSize().Width; + + if ((size.Width > drv_max_size) && (ratio >= 1.0f)) + { + size.Width = drv_max_size; + size.Height = (unsigned)(drv_max_size / ratio); + scale_image = true; + } + else if (size.Height > drv_max_size) + { + size.Height = drv_max_size; + size.Width = (unsigned)(drv_max_size * ratio); + scale_image = true; + } + if (scale_image) + { + video::IImage* new_img = irr_driver->getVideoDriver() + ->createImage(video::ECF_A8R8G8B8, size); + image->copyToScaling(new_img); + image->drop(); + image = new_img; + *orig_img = new_img; + } + + bool scale_texture = false; + size = size.getOptimalSize + (!irr_driver->getVideoDriver()->queryFeature(video::EVDF_TEXTURE_NPOT)); + const core::dimension2du& max_size = irr_driver->getVideoDriver() + ->getDriverAttributes().getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); + + if (max_size.Width > 0 && size.Width > max_size.Width) + { + size.Width = max_size.Width; + scale_texture = true; + } + if (max_size.Height > 0 && size.Height > max_size.Height) + { + size.Height = max_size.Height; + scale_texture = true; + } + + video::IImage* new_texture = + irr_driver->getVideoDriver()->createImage(video::ECF_A8R8G8B8, size); + if (scale_texture) + image->copyToScaling(new_texture); + else + image->copyTo(new_texture); + + return new_texture; +#endif // !SERVER_ONLY +} // convertImage + +// ---------------------------------------------------------------------------- +void STKTexture::applyMask(video::IImage* orig_img) +{ +#ifndef SERVER_ONLY + if (m_material && !m_material->getAlphaMask().empty()) + { + video::IImage* tmp_mask = irr_driver->getVideoDriver() + ->createImageFromFile(m_material->getAlphaMask().c_str()); + if (tmp_mask == NULL) + { + Log::warn("STKTexture", "Applying mask failed for '%s'!", + m_material->getAlphaMask().c_str()); + return; + } + video::IImage* converted_mask = convertImage(&tmp_mask); + tmp_mask->drop(); + if (converted_mask->lock()) + { + core::dimension2d dim = orig_img->getDimension(); + for (unsigned int x = 0; x < dim.Width; x++) + { + for (unsigned int y = 0; y < dim.Height; y++) + { + video::SColor col = orig_img->getPixel(x, y); + video::SColor alpha = converted_mask->getPixel(x, y); + col.setAlpha(alpha.getRed()); + orig_img->setPixel(x, y, col, false); + } // for y + } // for x + } + } +#endif // !SERVER_ONLY +} // applyMask diff --git a/src/graphics/stk_texture.hpp b/src/graphics/stk_texture.hpp new file mode 100644 index 000000000..9e6d9822d --- /dev/null +++ b/src/graphics/stk_texture.hpp @@ -0,0 +1,115 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2017 SuperTuxKart-Team +// +// 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_STK_TEXTURE_HPP +#define HEADER_STK_TEXTURE_HPP + +#include "graphics/gl_headers.hpp" +#include "utils/no_copy.hpp" + +#include +#include + +using namespace irr; + +class Material; + +class STKTexture : public video::ITexture, NoCopy +{ +private: + core::dimension2d m_size, m_orig_size; + + uint64_t m_texture_handle; + + bool m_srgb, m_premul_alpha, m_mesh_texture; + + Material* m_material; + + GLuint m_texture_name; + + unsigned int m_texture_size; + + video::IImage* m_texture_image; + + // ------------------------------------------------------------------------ + video::IImage* convertImage(video::IImage** orig_img); + // ------------------------------------------------------------------------ + void applyMask(video::IImage* orig_img); + +public: + // ------------------------------------------------------------------------ + STKTexture(const std::string& path, bool srgb = false, + bool premul_alpha = false, bool mesh_texture = false); + // ------------------------------------------------------------------------ + STKTexture(video::IImage* image); + // ------------------------------------------------------------------------ + ~STKTexture(); + // ------------------------------------------------------------------------ + virtual void* lock(video::E_TEXTURE_LOCK_MODE mode = + video::ETLM_READ_WRITE, u32 mipmap_level = 0) + { + if (m_texture_image) + return m_texture_image->lock(); + return NULL; + } + // ------------------------------------------------------------------------ + virtual void unlock() + { + if (m_texture_image) + m_texture_image->unlock(); + } + // ------------------------------------------------------------------------ + virtual const core::dimension2d& getOriginalSize() const + { return m_orig_size; } + // ------------------------------------------------------------------------ + virtual const core::dimension2d& getSize() const { return m_size; } + // ------------------------------------------------------------------------ + virtual video::E_DRIVER_TYPE getDriverType() const + { +#if defined(USE_GLES2) + return video::EDT_OGLES2; +#else + return video::EDT_OPENGL; +#endif + } + // ------------------------------------------------------------------------ + virtual video::ECOLOR_FORMAT getColorFormat() const + { return video::ECF_A8R8G8B8; } + // ------------------------------------------------------------------------ + virtual u32 getPitch() const { return 0; } + // ------------------------------------------------------------------------ + virtual void regenerateMipMapLevels(void* mipmap_data = NULL) {} + // ------------------------------------------------------------------------ + virtual u32 getOpenGLTextureName() const { return m_texture_name; } + // ------------------------------------------------------------------------ + uint64_t getTextureHandle() const { return m_texture_handle; } + // ------------------------------------------------------------------------ + bool isSrgb() const { return m_srgb; } + // ------------------------------------------------------------------------ + bool isPremulAlpha() const { return m_premul_alpha; } + // ------------------------------------------------------------------------ + bool isMeshTexture() const { return m_mesh_texture; } + // ------------------------------------------------------------------------ + void setMeshTexture(bool val) { m_mesh_texture = val; } + // ------------------------------------------------------------------------ + unsigned int getTextureSize() const { return m_texture_size; } + // ------------------------------------------------------------------------ + void reload(); + +}; // STKTexture + +#endif diff --git a/src/graphics/texture_manager.cpp b/src/graphics/texture_manager.cpp index 75c39a79d..84ffd9067 100644 --- a/src/graphics/texture_manager.cpp +++ b/src/graphics/texture_manager.cpp @@ -22,6 +22,7 @@ #include "graphics/central_settings.hpp" #include "graphics/irr_driver.hpp" #include "graphics/materials.hpp" +#include "graphics/stk_texture.hpp" #include "utils/string_utils.hpp" #if defined(USE_GLES2) @@ -40,22 +41,9 @@ GLuint getTextureGLuint(irr::video::ITexture *tex) { if (tex == NULL) return 0; -#if defined(USE_GLES2) - return static_cast(tex)->getOpenGLTextureName(); -#else - return static_cast(tex)->getOpenGLTextureName(); -#endif + return tex->getOpenGLTextureName(); } -GLuint getDepthTexture(irr::video::ITexture *tex) -{ - assert(tex->isRenderTarget()); -#if defined(USE_GLES2) - return static_cast(tex)->DepthBufferTexture; -#else - return static_cast(tex)->DepthBufferTexture; -#endif -} static std::set AlreadyTransformedTexture; static std::map unicolor_cache; @@ -94,6 +82,9 @@ void cleanUnicolorTextures() void compressTexture(irr::video::ITexture *tex, bool srgb, bool premul_alpha) { + STKTexture* stk_tex = dynamic_cast(tex); + if (stk_tex) return; + if (AlreadyTransformedTexture.find(tex) != AlreadyTransformedTexture.end()) return; AlreadyTransformedTexture.insert(tex); diff --git a/src/graphics/texture_manager.hpp b/src/graphics/texture_manager.hpp index 698d93b48..50518a10d 100644 --- a/src/graphics/texture_manager.hpp +++ b/src/graphics/texture_manager.hpp @@ -26,7 +26,7 @@ #include GLuint getTextureGLuint(irr::video::ITexture *tex); -GLuint getDepthTexture(irr::video::ITexture *tex); + void resetTextureTable(); void cleanUnicolorTextures(); void compressTexture(irr::video::ITexture *tex, bool srgb, bool premul_alpha = false);