/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "watchmaker/3d/material.h" #include "common/util.h" #include "watchmaker/3d/render/opengl_2d.h" #include "watchmaker/render.h" namespace Watchmaker { MaterialPtr rAddMaterial(gMaterial &Material, const Common::String &TextName, int NumFaces, unsigned int LoaderFlags) { // TODO: This is duplicated in opengl_3d.cpp warning("TODO: Fix rAddMaterial"); #if 0 bool AlreadyLoaded = FALSE; int len = strlen(TextName); if (((TextName[len - 1 - 0] == 'i') || (TextName[len - 1 - 0] == 'I')) && ((TextName[len - 1 - 1] == 'v') || (TextName[len - 1 - 1] == 'V')) && ((TextName[len - 1 - 2] == 'a') || (TextName[len - 1 - 2] == 'A'))) { if ((Material.Movie = gLoadMovie(TextName)) == NULL) return NULL; if ((Material.Texture = gUserTexture(64, 128)) == NULL) // if( (Material->Texture=gUserTexture( Material->Movie->g_psiStreamInfo.rcFrame.right, // Material->Movie->g_psiStreamInfo.rcFrame.bottom)) == NULL ) return NULL; Material.Flags |= T3D_MATERIAL_MOVIE; } else { if ((Material.Texture = gLoadTexture(TextName, LoaderFlags)) == NULL) return NULL; } //f //f Material->FacesList=(WORD *)t3dRealloc(Material->FacesList,sizeof(WORD)*3*NumFaces+1); //f Material->NumAllocatedFaces+=3*NumFaces+1; Material.FacesList.resize(Material.FacesList.size() + NumFaces * 3); Material.NumAllocatedFaces += NumFaces * 3; //f Material.Flags |= T3D_MATERIAL_NOLIGHTMAP; return Material; #endif return nullptr; } void gMaterial::addProperty(int flag) { this->Flags |= flag; } void gMaterial::clearFlag(int flag) { this->Flags &= ~flag; } bool gMaterial::hasFlag(int flag) { return this->Flags & flag; } void gMaterial::addColor(unsigned char r_add, unsigned char g_add, unsigned char b_add) { int rr, gg, bb; rr = this->r; gg = this->g; bb = this->b; rr += r; gg += g; bb += b; rr = MIN(MAX(rr, 0), 255); gg = MIN(MAX(gg, 0), 255); bb = MIN(MAX(bb, 0), 255); this->r = (unsigned char)rr; this->g = (unsigned char)gg; this->b = (unsigned char)bb; } bool gMaterial::addNumFacesAdditionalMaterial(MaterialPtr am, unsigned int num) { if (!num || !am) return false; Common::SharedPtr cm; int i; for (i = 0; i < this->NumAddictionalMaterial; i++) { cm = this->AddictionalMaterial[i]; if (cm->Texture->ID == am->Texture->ID) break; } if (i == this->NumAddictionalMaterial) { this->AddictionalMaterial.push_back(Common::SharedPtr(new gMaterial(*am))); cm = this->AddictionalMaterial.back(); cm->FacesList.resize(0); this->NumAddictionalMaterial++; } return true; } bool gMaterial::addNumFaces(unsigned int num) { // TODO: Remove, as this is not necessary with a Common::Array return true; } MaterialPtr rMergeMaterial(MaterialPtr Mat1, MaterialPtr Mat2) { if (!Mat1 || !Mat2) return nullptr; for (int i = 0; i < Mat2->NumAddictionalMaterial; i++) { Mat1->addNumFacesAdditionalMaterial(Mat2->AddictionalMaterial[i], /*Mat2->AddictionalMaterial[i]->NumAllocatedFaces*/ Mat2->AddictionalMaterial[i]->NumFaces()); } //reset mat2 rRemoveMaterial(Mat2); *Mat2 = gMaterial(); return Mat1; } void rRemoveMaterials(Common::Array> &m) { for (auto &material : m) { material->clear(); } m.clear(); } Common::SharedPtr rCopyMaterial(Common::SharedPtr Mat1, Common::SharedPtr Mat2) { if (!Mat1 || !Mat2) return nullptr; Mat1->clearFaceList(); Mat1->AddictionalMaterial.clear(); Mat1->clearFaceList(); Mat1->VertsList.clear(); //t3dFree(Mat1->FlagsList); *Mat1 = gMaterial(); if (Mat2->NumFaces()) { for (int i = 0; i < Mat2->NumFaces(); i++) { Mat1->addFace(Mat2->getFace(i)); } } for (int i = 0; i < Mat2->NumFaces(); i++) { if (Mat2->getFace(i) >= Mat2->VertsList.size()) { warning("TODO"); } } if (Mat2->NumAllocatedVerts()) { Mat1->VertsList = Mat2->VertsList; } if (Mat2->NumAllocatedMesh) { Mat1->FlagsList = Mat2->FlagsList; } Mat1->Texture = Mat2->Texture; Mat1->Movie = Mat2->Movie; Mat1->Flags = Mat2->Flags; Mat1->VBO = Mat2->VBO; Mat1->NumAllocatedMesh = Mat2->NumAllocatedMesh; Mat1->r = Mat2->r; Mat1->g = Mat2->g; Mat1->b = Mat2->b; Mat1->NumAddictionalMaterial = Mat2->NumAddictionalMaterial; rCopyMaterialList(Mat1->AddictionalMaterial, Mat2->AddictionalMaterial, Mat2->NumAddictionalMaterial); // TODO: Does this mean that we don't copy any extras? return Mat1; } void rCopyMaterialList(MaterialTable &dst, MaterialTable &src, uint count) { dst.resize(count); if (count > src.size()) { error("Copying more materials than there are in the src"); } for (uint i = 0; i < count; i++) { if (!dst[i]) { dst[i] = Common::SharedPtr(new gMaterial()); } rCopyMaterial(dst[i], src[i]); } } void gMaterial::clear() { // TODO: This flag clearing doesn't happen in the original, but shouldn't matter as the class is instantiated again when used in Particles. Flags = 0; if (Movie) { Movie = nullptr; } FacesList.clear(); VertsList.clear(); FlagsList.clear(); // rDeleteVertexBuffer(m->VB); VBO = 0; for (int j = 0; j < NumAddictionalMaterial; j++) { Common::SharedPtr cm = AddictionalMaterial[j]; cm->FacesList.clear(); cm->VertsList.clear(); cm->FlagsList.clear(); // rDeleteVertexBuffer(cm->VB); cm->VBO = 0; } AddictionalMaterial.clear(); } void rRemoveMaterial(Common::SharedPtr &m) { m->clear(); } /* -----------------29/07/99 15.53------------------- * Aggiunge un materiale alla MaterialList * --------------------------------------------------*/ void rAddToMaterialList(gMaterial &mat, signed short int ViewMatrixNum) { gBatchBlock *bb = nullptr; if ((mat.Flags & T3D_MATERIAL_MOVIE)) { warning("Movie: %s %d", mat.Movie->_name.c_str(), mat.Texture->ID); mat.Movie->updateMovie(); } if ((mat.NumFaces() >= 3) && (mat.VBO)) { if (mat.Texture) { // if (mat.Texture->name == "./TMaps/bianco.tga") // return; } bb = rNewBatchBlock(mat.Texture->ID, mat.Flags, 0, 0); bb->ViewMatrixNum = ViewMatrixNum; bb->FacesList = mat.getFacesList(); bb->VBO = mat.VBO; for (uint f = 0; f < bb->FacesList.size(); f++) { if (bb->FacesList[f] >= bb->VBO->_buffer.size()) { for (uint o = 0; o < bb->FacesList.size(); o++) { warning("%d", bb->FacesList[o]); } warning("%d > %d (%d)", bb->FacesList[f], bb->VBO->_buffer.size(), bb->NumVerts()); } } mat.emptyFacesList(); // We may want to keep the reservation to avoid the extra reallocs here. } for (auto &cm : mat.AddictionalMaterial) { if (cm->NumFaces() < 3) continue; if (cm->VBO == NULL) continue; bb = rNewBatchBlock(mat.Texture->ID, mat.Flags, cm->Texture->ID, cm->Flags); bb->ViewMatrixNum = ViewMatrixNum; bb->FacesList = cm->getFacesList(); bb->VBO = cm->VBO; cm->emptyFacesList(); } } void rAddToMaterialList(MaterialPtr mat, signed short int ViewMatrixNum) { if (mat) { rAddToMaterialList(*mat, ViewMatrixNum); } } /* -----------------31/05/99 10.07------------------- * Costruisce la lista dei materiali ordinata * --------------------------------------------------*/ void rBuildMaterialList(MaterialTable &MatList, unsigned int NumMat, signed short int ViewMatrixNum) { if (NumMat == 0) return; for (auto &mat : MatList) { rAddToMaterialList(mat, ViewMatrixNum); } } MaterialTable rCreateMaterialList(int num) { MaterialTable list; // We avoid actually allocating the gMaterial-objects, as we want the size() to // represent the actually loaded elements. list.reserve(num); return list; } } // End of namespace Watchmaker