Material support suggestion for both A2C and Billboarding
struct MobjMat {
float ambient[4];
float diffuse[4];
float specular[4];
float shininess; // [0 = min shininess, 1 = max shininess]
float alpha; // [0 = fully transparent, 1 = fully opaque]
std::string defMapFileName;
std::string colorMapFilename; // ML: let those stay for a while; haven't decided yet if we need them at all h
std::string bumpMapFilename;
long illum;
// ML: EXTRA
std::string ambiMapFilename; // ditto
std::string specMapFilename;
std::string reflMapFilename;
// To those IDs that follow below, assign *IN ADVANCE AND ONLY ONCE PER MATERIAL* whatever this code:
// ....
// if (memcmp(pszTextName, &pMaterial->color|bump|ambi|specMapFilename[0], strlen(pszTextName)) == 0) {
// glBindTexture(GL_TEXTURE_2D, gt_texObj[nCount].Texture);
// break;
// }
// ....
// returns in its "gt_texObj[nCount].Texture" in every texture loop of your Mobj_DrawUsing...() procs
// in every frame they render again and again. There is absolutely no need to do it that way. You're
// killing your FPS rate with your own hands by comparing turtle slow string names all over again in
// each frame.
// This is your *ABSOLUTELY HIGHEST PRIORITY* task.
// Please take any such loop out of render procs into a separate procedure and run it just once for
// all the textures in all the materials of the model, so that
// &pMaterial->ambi|diff|bump|specMapID = gt_texObj[nCount].Texture;
// then delete all those loops from the render procs and just use
// glBindTexture(GL_TEXTURE_2D, &pMaterial->ambi|diff|bump|specMapID);
// as appropriate.
long colorMapID;
long ambiMapID; // OpenGL numeric texture "names" (IDs) to be assigned as I described above
long bumpMapID;
long specMapID;
long reflMapID;
long isA2C; // PAT: 01-07-2018
long isBillboard; // PAT: 01-07-2018
};
void Mobj_importMaterials(const char *pszFilename) {
FILE* pFile = fopen(pszFilename, "r");
if (pFile == 0) { return; }
MobjMat* pMaterial = 0;
long K = 0, nI = 0, nIllum = 0, nNumMaterials = 0;
char szBuffer[MAX_PATH] = { 0 };
char fullPath[MAX_PATH] = { 0 };
Mobj_gl_cw(0, 1); // 10-29-2015
Mobj_ambient(0, 1); // 11-19-2015
Mobj_AlphathresholdValue(0.0f, 1); // 12-14-2015
Mobj_bothsides(0, 1); // 05-02-2016
Mobj_AlphaToCoverage(0, 1); // 12-11-2017
long nGlobal = -1; // PAT: 01-07-2018
// Count the number of materials in the MTL file.
while (fscanf(pFile, "%s", szBuffer) != EOF) {
CharLowerA(szBuffer);
switch (szBuffer[0]) {
case 'n': // newmtl
if (strcmp(szBuffer, "newmtl") == 0) { // 12-12-2015 ML: n can also mean lowercase Ns
++nNumMaterials;
fgets(szBuffer, sizeof(szBuffer), pFile);
sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
nGlobal = 0;
} else {
fgets(szBuffer, sizeof(szBuffer), pFile);
}
break;
case '#': // Shall we use a specific wallpaper or clockwise polygons
if (nGlobal) {
if (strcmp(szBuffer, "#wallpaper") == 0) {
fgets(szBuffer, sizeof(szBuffer), pFile);
sscanf(szBuffer, "%s", szBuffer);
memset(&gsw_wallpaper[0], 0, sizeof(WCHAR) * MAX_PATH);
MultiByteToWideChar(CP_ACP, 0, szBuffer, (long)strlen(szBuffer), gsw_wallpaper, MAX_PATH);
} else if (strcmp(szBuffer, "#gl_cw") == 0) {
Mobj_gl_cw(-1, 1);
} else if (strcmp(szBuffer, "#ambient") == 0) {
Mobj_ambient(-1, 1);
} else if(strcmp(szBuffer, "#bothsides") == 0) {
Mobj_bothsides(-1, 1);
} else if (strcmp(szBuffer, "#threshold") == 0) {
fgets(szBuffer, sizeof(szBuffer), pFile);
sscanf(szBuffer, "%s", szBuffer);
Mobj_AlphathresholdValue((float) atof(szBuffer), 1);
} else if(strcmp(szBuffer, "#alphatocoverage") == 0) {
Mobj_AlphaToCoverage(-1, 1);
} else {
fgets(szBuffer, sizeof(szBuffer), pFile);
}
}
break;
default:
fgets(szBuffer, sizeof(szBuffer), pFile);
break;
}
}
rewind(pFile);
gnm_numberOfMaterials = nNumMaterials;
gtm_materials.resize(gnm_numberOfMaterials);
gnm_numberOfTextures = 0;
nNumMaterials = 0;
// Load the materials in the MTL file.
while (fscanf(pFile, "%s", szBuffer) != EOF) {
CharLowerA(szBuffer);
switch (szBuffer[0]) {
case 'n': // Ns
if (szBuffer[1] == 's') {
fscanf(pFile, "%f", &pMaterial->shininess);
// Wavefront .MTL file shininess is from [0,1000].
// Scale back to a generic [0,1] range.
pMaterial->shininess /= 1000.0f;
} else if (strstr(szBuffer, "newmtl") != 0) {
fgets(szBuffer, sizeof(szBuffer), pFile);
sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
// Material
pMaterial = >m_materials[nNumMaterials];
pMaterial->ambient[0] = 0.2f;
pMaterial->ambient[1] = 0.2f;
pMaterial->ambient[2] = 0.2f;
pMaterial->ambient[3] = 1.0f;
pMaterial->diffuse[0] = 0.8f;
pMaterial->diffuse[1] = 0.8f;
pMaterial->diffuse[2] = 0.8f;
pMaterial->diffuse[3] = 1.0f;
pMaterial->specular[0] = 0.0f;
pMaterial->specular[1] = 0.0f;
pMaterial->specular[2] = 0.0f;
pMaterial->specular[3] = 1.0f;
pMaterial->shininess = 1.0f;
pMaterial->alpha = 1.0f;
pMaterial->defMapFileName = szBuffer;
pMaterial->colorMapFilename.clear();
pMaterial->bumpMapFilename.clear();
pMaterial->illum = 1;
pMaterial->ambiMapFilename.clear();
pMaterial->specMapFilename.clear();
pMaterial->reflMapFilename.clear();
pMaterial->colorMapID = 0;
pMaterial->ambiMapID = 0;
pMaterial->bumpMapID = 0;
pMaterial->specMapID = 0;
pMaterial->reflMapID = 0;
m_materialCache[pMaterial->defMapFileName] = nNumMaterials;
++nNumMaterials;
}
break;
case 'k': // Ka, Kd, or Ks
switch (szBuffer[1]) {
case 'a': // Ka
fscanf(pFile, "%f %f %f",
&pMaterial->ambient[0],
&pMaterial->ambient[1],
&pMaterial->ambient[2]);
pMaterial->ambient[3] = 1.0f;
break;
case 'd': // Kd
fscanf(pFile, "%f %f %f",
&pMaterial->diffuse[0],
&pMaterial->diffuse[1],
&pMaterial->diffuse[2]);
pMaterial->diffuse[3] = 1.0f;
break;
case 's': // Ks
fscanf(pFile, "%f %f %f",
&pMaterial->specular[0],
&pMaterial->specular[1],
&pMaterial->specular[2]);
pMaterial->specular[3] = 1.0f;
break;
default:
fgets(szBuffer, sizeof(szBuffer), pFile);
break;
}
break;
case 't': // Tr
switch (szBuffer[1]) {
case 'r': // Tr
if (pMaterial->alpha == 1.0f) { // 12-06-2015 ML: only if alpha is still default
fscanf(pFile, "%f", &pMaterial->alpha);
if (pMaterial->alpha > 0.0f) {
pMaterial->alpha = 1.0f - pMaterial->alpha; // 12-06-2015 ML: follow OBJ specs
}
if (pMaterial->alpha == 0.0f) { pMaterial->alpha = 1.0f; } // 02-05-2016
} else {
fgets(szBuffer, sizeof(szBuffer), pFile); // 12-06-2015 ML: ignore
}
break;
default:
fgets(szBuffer, sizeof(szBuffer), pFile);
break;
}
break;
case 'd':
fscanf(pFile, "%f", &pMaterial->alpha);
break;
case 'i': // illum
fscanf(pFile, "%d", &nIllum);
pMaterial->illum = nIllum;
if (nIllum == 1) {
pMaterial->specular[0] = 0.0f;
pMaterial->specular[1] = 0.0f;
pMaterial->specular[2] = 0.0f;
pMaterial->specular[3] = 1.0f;
}
break;
case 'm': // map_Kd, map_bump
// 11-02-2015 added support for map_Ka, map_Ks
if (strstr(szBuffer, "map_kd")) {
fgets(szBuffer, sizeof(szBuffer), pFile);
sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
Path_CombineA(fullPath, (char*)gsm_directoryPath.c_str(), szBuffer);
if (FileExistA(fullPath)) {
pMaterial->colorMapFilename = fullPath;
++gnm_numberOfTextures;
}
} else if (strstr(szBuffer, "map_bump")) {
fgets(szBuffer, sizeof(szBuffer), pFile);
sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
Path_CombineA(fullPath, (char*)gsm_directoryPath.c_str(), szBuffer);
if (FileExistA(fullPath)) {
pMaterial->bumpMapFilename = fullPath;
++gnm_numberOfTextures; // 03-24-2015
}
// 11-02-2015
} else if (strstr(szBuffer, "map_ka")) {
fgets(szBuffer, sizeof(szBuffer), pFile);
sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
Path_CombineA(fullPath, (char*)gsm_directoryPath.c_str(), szBuffer);
if (FileExistA(fullPath)) {
pMaterial->ambiMapFilename = fullPath;
++gnm_numberOfTextures; // 03-24-2015
}
// 11-02-2015
} else if (strstr(szBuffer, "map_ks")) {
fgets(szBuffer, sizeof(szBuffer), pFile);
sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
Path_CombineA(fullPath, (char*)gsm_directoryPath.c_str(), szBuffer);
if (FileExistA(fullPath)) {
pMaterial->specMapFilename = fullPath;
++gnm_numberOfTextures; // 03-24-2015
}
} else {
fgets(szBuffer, sizeof(szBuffer), pFile);
}
break;
case 'r': // refl
if (strstr(szBuffer, "refl")) {
fgets(szBuffer, sizeof(szBuffer), pFile);
sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
Path_CombineA(fullPath, (char*)gsm_directoryPath.c_str(), szBuffer);
if (FileExistA(fullPath)) {
pMaterial->reflMapFilename = fullPath;
++gnm_numberOfTextures; // 03-24-2015
}
}
break;
case '#': // PAT: 01-07-2018 meta specific for material
if (strcmp(szBuffer, "#alphatocoverage") == 0) {
if (Mobj_AlphaToCoverage(0, 0) == 0) {
pMaterial->isA2C = -1;
}
} else if(strcmp(szBuffer, "#billboard") == 0) {
pMaterial->isBillboard = -1;
}
break;
default:
fgets(szBuffer, sizeof(szBuffer), pFile);
break;
}
}
fclose(pFile);
}