We are STILL trying to "draw" the joint (slit) between the pack and the lid, as a small normal map applied to existing textured mesh's fragment.
At this point we do have fragments with their own "native" Materials. In the last sample we just replaced them (Materials) by Phong green. Instead we need to use native Materials, but with added normal map. So, we need a way to adjust existing materials.
Implementation:
Windows
1. Start VS, open C:\CPP\a997modeler\p_windows\p_windows.sln.
2. Under modeler add new header file MaterialAdjust.h
Location: C:\CPP\engine\modeler
Code:
#pragma once
#include "Material.h"
class MaterialAdjust : public Material
{
public:
bool b_shaderType = false;
bool b_primitiveType = false;
bool b_uColor = false;
bool b_uTex0 = false;
bool b_uTex1mask = false;
bool b_uTex2nm = false;
bool b_uTex3 = false;
bool b_uTex1alphaChannelN = false;
bool b_uTex1alphaNegative = false;
bool b_uTex0translateChannelN = false;
bool b_uAlphaBlending = false;
bool b_uAlphaFactor = false;
bool b_uAmbient = false;
//specular light parameters
bool b_uSpecularIntencity = false;
bool b_uSpecularMinDot = false;
bool b_uSpecularPowerOf = false;
public:
static int adjust(Material* pMT, MaterialAdjust* pMA);
static int setWhat2adjust(MaterialAdjust* pMA, std::string tagStr);
};
- Please note: it inherits Material class.
3. Under modeler add new C++ file MaterialAdjust.cpp
Location: C:\CPP\engine\modeler
Code:
#include "MaterialAdjust.h"
int MaterialAdjust::adjust(Material* pMT, MaterialAdjust* pMA) {
if (pMA->b_shaderType)
pMT->setShaderType(pMA->shaderType);
if (pMA->b_primitiveType)
pMT->primitiveType = pMA->primitiveType;
if (pMA->b_uColor) {
memcpy(&pMT->uColor, &pMA->uColor, sizeof(MyColor));
pMT->uTex0 = -1;
}
if (pMA->b_uTex0) {
pMT->uTex0 = pMA->uTex0;
pMT->uColor.setUint32(0);
}
if (pMA->b_uTex1mask)
pMT->uTex1mask = pMA->uTex1mask;
if (pMA->b_uTex2nm)
pMT->uTex2nm = pMA->uTex2nm;
if (pMA->b_uTex3)
pMT->uTex3 = pMA->uTex3;
if (pMA->b_uTex1alphaChannelN)
pMT->uTex1alphaChannelN = pMA->uTex1alphaChannelN;
if (pMA->b_uTex1alphaNegative)
pMT->uTex1alphaNegative = pMA->uTex1alphaNegative;
if (pMA->b_uTex0translateChannelN)
pMT->uTex0translateChannelN = pMA->uTex0translateChannelN;
if (pMA->b_uAlphaBlending)
pMT->uAlphaBlending = pMA->uAlphaBlending;
if (pMA->b_uAlphaFactor)
pMT->uAlphaFactor = pMA->uAlphaFactor;
if (pMA->b_uAmbient)
pMT->uAmbient = pMA->uAmbient;
if (pMA->b_uSpecularIntencity)
pMT->uSpecularIntencity = pMA->uSpecularIntencity;
if (pMA->b_uSpecularMinDot)
pMT->uSpecularMinDot = pMA->uSpecularMinDot;
if (pMA->b_uSpecularPowerOf)
pMT->uSpecularPowerOf = pMA->uSpecularPowerOf;
return 1;
}
int MaterialAdjust::setWhat2adjust(MaterialAdjust* pMA, std::string tagStr) {
if (tagStr.find("uTex0") != std::string::npos)
if(pMA->uTex0 >= 0)
pMA->b_uTex0 = true;
if (tagStr.find("uTex1mask") != std::string::npos)
pMA->b_uTex1mask = true;
if (tagStr.find("uTex2nm") != std::string::npos)
pMA->b_uTex2nm = true;
if (tagStr.find("uTex3") != std::string::npos)
pMA->b_uTex3 = true;
if (tagStr.find("mt_type") != std::string::npos)
pMA->b_shaderType = true;
if (tagStr.find("uColor") != std::string::npos)
pMA->b_uColor = true;
if (tagStr.find("primitiveType") != std::string::npos)
pMA->b_primitiveType = true;
if (tagStr.find("uTex1alphaChannelN") != std::string::npos)
pMA->b_uTex1alphaChannelN = true;
if (tagStr.find("uTex0translateChannelN") != std::string::npos)
pMA->b_uTex0translateChannelN = true;
if (tagStr.find("uAlphaBlending") != std::string::npos)
pMA->b_uAlphaBlending = true;
if (tagStr.find("uAlphaFactor") != std::string::npos)
pMA->b_uAlphaFactor = true;
if (tagStr.find("uAmbient") != std::string::npos)
pMA->b_uAmbient = true;
if (tagStr.find("uSpecularIntencity") != std::string::npos)
pMA->b_uSpecularIntencity = true;
if (tagStr.find("uSpecularMinDot") != std::string::npos)
pMA->b_uSpecularMinDot = true;
if (tagStr.find("uSpecularPowerOf") != std::string::npos)
pMA->b_uSpecularPowerOf = true;
return 1;
}
Please note: this class has all inherited functionality from Material class plus 2 new functions:
- setWhat2adjust(..) which checks given tag and marks what Material's properties need to be adjusted (overwritten).
- and adjust(..) which actually adjusts given Material's properties.
In root01.txt we have a new tag now:
<mt_adjust uTex2nm_use="tx0" >
4. Copy following code to a Text Editor and save (overwrite) it to/as
C:\CPP\a997modeler\dt\models\misc\marlboro01\root01.txt
<texture_as="tx0" src="marlboro03small.png" ckey="#00ff00"/>
<mt_type="phong" uTex0_use="tx0" />
<vs="box_tank" whl="53,83,21" ext=1 sectR=1 />
<a="front v" xywh="2,1,323,495" mark="box_front"/>
<a="back v" xywh="2,1,323,495" mark="box_back"/>
<a="right all" xywh="327,1,128,495" mark="box_right"/>
<a="left all" xywh="457,1,128,495" mark="box_left"/>
<a="top" xywh="588,1,323,133"/>
<a="bottom" xywh="587,136,324,134"/>
//golden prints
<vs="box" whl="55.1,85.1,23.1" />
<texture_as="whitenoise" src="/dt/common/img/whitenoise/wn64_blur3.bmp"/>
<texture_as="gold" src="/dt/common/img/materials/gold02roman.bmp" />
<mt_type="mirror" uAlphaBlending uTex1mask_use="tx0" uTex1alphaChannelN=1 uTex0_use="whitenoise" uTex0translateChannelN=0 uTex3_use="gold" />
//side golden prints
<a="right" xywh="342,12,101,10" whl="x,1.8,18.1" pxyz="x,39.8, -0.3" /> //Please do not litter
<a="right" xywh="339,144,105,89" whl="x,15.35,18.9" pxyz="x,10.3,-0.12" /> //For special offers...
<a="left" xywh="475,15,95,48" whl="x,8.4,17" pxyz="x,36, 0.3" /> //Underage sale...
//front prints
<group>
//bottom golden print "20 class a..."
<a="front" xywh="20,498,289,13" whl="47.5,2,x" pxyz="1,-36,x" />
//blazon/emblem
<mt_type="mirror" uAlphaBlending uTex2nm_use="tx0" uTex0_use="whitenoise" uTex0translateChannelN=0 uTex3_use="gold" />
<a="front" xywh2nm="589,415,128,94" whl="20.7,16,x" pxyz="0.3,6.1,x" /> //emblem
//"Marlboro
<mt_type="phong" uAlphaBlending uTex2nm_use="tx0" uColor="#1E211E" />
<a="front" xywh2nm="590,275,301,136" whl="49.2,23.3,x" pxyz="0.21,-18,x" /> //marlboro
</group>
<clone ay=180 />
//joint (slit) between the pack and the lid
<group>
<mt_adjust uTex2nm_use="tx0" >
<a2mesh wh="50,1" xywh2nm="582,497,1,4" all markedAs="box_right" onThe="right" py=24.6 az=31 />
<a2mesh wh="50,1" xywh2nm="582,497,1,4" all markedAs="box_left" onThe="left" py=24.6 az=-31 />
<a2mesh wh="53,1" xywh2nm="582,497,1,4" all markedAs="box_front" py=17.8 />
<a2mesh wh="6 ,1" xywh2nm="582,497,1,4" all markedAs="box_back" onThe="back" py=31.5 px=23.5 />
<a2mesh wh="6 ,1" xywh2nm="582,497,1,4" all markedAs="box_back" onThe="back" py=31.5 px=-23.5 />
</mt_adjust>
</group sizeD="0.1,0,0.1">
- Please note: in a2mesh tags now we have a new property xywh2nm - texture coordinates for normal map.
Now - reading and executing new tags/properties:
5. Open ModelLoader.h and replace code by:
#pragma once
#include "XMLparser.h"
#include "ModelBuilder.h"
#include "GroupTransform.h"
#include "MaterialAdjust.h"
class ModelLoader : public XMLparser
{
public:
ModelBuilder* pModelBuilder = NULL;
bool ownModelBuilder = false;
std::vector<GameSubj*>* pSubjsVector = NULL;
MaterialAdjust* pMaterialAdjust = NULL;
public:
ModelLoader(std::vector<GameSubj*>* pSubjsVector0, int subjN, ModelBuilder* pMB, std::string filePath) : XMLparser(filePath) {
pSubjsVector = pSubjsVector0;
if (pMB != NULL) {
ownModelBuilder = false;
pModelBuilder = pMB;
}
else {
ownModelBuilder = true;
pModelBuilder = new ModelBuilder();
pModelBuilder->lockGroup(pModelBuilder);
}
pModelBuilder->useSubjN(pModelBuilder,subjN);
};
virtual ~ModelLoader() {
if (!ownModelBuilder)
return;
pModelBuilder->buildDrawJobs(pModelBuilder, *pSubjsVector);
delete pModelBuilder;
};
static int processTag_a(ModelLoader* pML); //apply
static int setValueFromIntHashMap(int* pInt, std::map<std::string, int> intHashMap, std::string varName, std::string tagStr);
static int setTexture(ModelLoader* pML, int* pInt, std::string txName);
static int setMaterialTextures(ModelLoader* pML, Material* pMT);
static int fillProps_vs(VirtualShape* pVS, std::string tagStr); //virtual shape
static int fillProps_mt(Material* pMT, std::string tagStr, ModelLoader* pML); //Material
static int fillProps_gt(GroupTransform* pGS, ModelBuilder* pMB, std::string tagStr);
virtual int processTag() { return processTag(this); };
static int processTag(ModelLoader* pML);
static int loadModel(std::vector<GameSubj*>* pSubjsVector0, std::string sourceFile, std::string subjClass);
static int processTag_clone(ModelLoader* pML);
static int addMark(char* marks, std::string newMark);
static int processTag_do(ModelLoader* pML);
static int processTag_a2mesh(ModelLoader* pML);
};
6. Open ModelLoader.cpp and replace code by:
#include "ModelLoader.h"
#include "platform.h"
#include "TheGame.h"
#include "DrawJob.h"
#include "Texture.h"
#include "utils.h"
#include "Polygon.h"
extern TheGame theGame;
int ModelLoader::loadModel(std::vector<GameSubj*>* pSubjsVector0, std::string sourceFile, std::string subjClass) {
//returns element's (Subj) number or -1
int subjN = pSubjsVector0->size();
GameSubj* pGS = theGame.newGameSubj(subjClass);
pSubjsVector0->push_back(pGS);
//pGS->djStartN = DrawJob::drawJobs.size();
ModelLoader* pML = new ModelLoader(pSubjsVector0, subjN, NULL, sourceFile);
processSource(pML);
delete pML;
//pGS->djTotalN = DrawJob::drawJobs.size() - pGS->djStartN;
return subjN;
}
int ModelLoader::setValueFromIntHashMap(int* pInt, std::map<std::string, int> intHashMap, std::string varName, std::string tagStr) {
if (!varExists(varName, tagStr))
return 0;
std::string str0 = getStringValue(varName, tagStr);
if (intHashMap.find(str0) == intHashMap.end()) {
mylog("ERROR in ModelLoader::setValueFromIntMap, %s not found, %s\n", varName.c_str(), tagStr.c_str());
return -1;
}
*pInt = intHashMap[getStringValue(varName, tagStr)];
return 1;
}
int ModelLoader::setTexture(ModelLoader* pML, int* pInt, std::string txName) {
ModelBuilder* pMB = pML->pModelBuilder;
std::string varName = txName + "_use";
if (setValueFromIntHashMap(pInt, pMB->texturesHashMap, varName, pML->currentTag) == 0) {
//the texture is not in hash table
varName = txName + "_src";
if (varExists(varName, pML->currentTag)) {
std::string txFile = getStringValue(varName, pML->currentTag);
varName = txName + "_ckey";
unsigned int intCkey = 0;
setUintColorValue(&intCkey, varName, pML->currentTag);
*pInt = Texture::loadTexture(buildFullPath(pML, txFile), intCkey);
}
}
return 1;
}
int ModelLoader::setMaterialTextures(ModelLoader* pML, Material* pMT) {
setTexture(pML, &pMT->uTex0, "uTex0");
setTexture(pML, &pMT->uTex1mask, "uTex1mask");
setTexture(pML, &pMT->uTex2nm, "uTex2nm");
setTexture(pML, &pMT->uTex3, "uTex3");
return 1;
}
int ModelLoader::fillProps_mt(Material* pMT, std::string tagStr, ModelLoader* pML) {
setCharsValue(pMT->shaderType, 20, "mt_type", tagStr);
setMaterialTextures(pML, pMT);
//color
if (varExists("uColor", tagStr)) {
unsigned int uintColor = 0;
setUintColorValue(&uintColor, "uColor", tagStr);
pMT->uColor.setUint32(uintColor);
}
//mylog("mt.uTex0=%d, mt.uTex1mask=%d\n", mt.uTex0, mt.uTex1mask);
if (varExists("primitiveType", tagStr)) {
std::string str0 = getStringValue("primitiveType", tagStr);
if (str0.compare("GL_POINTS") == 0) pMT->primitiveType = GL_POINTS;
else if (str0.compare("GL_LINES") == 0) pMT->primitiveType = GL_LINES;
else if (str0.compare("GL_LINE_STRIP") == 0) pMT->primitiveType = GL_LINE_STRIP;
else if (str0.compare("GL_LINE_LOOP") == 0) pMT->primitiveType = GL_LINE_LOOP;
else if (str0.compare("GL_TRIANGLE_STRIP") == 0) pMT->primitiveType = GL_TRIANGLE_STRIP;
else if (str0.compare("GL_TRIANGLE_FAN") == 0) pMT->primitiveType = GL_TRIANGLE_FAN;
else pMT->primitiveType = GL_TRIANGLES;
}
setIntValue(&pMT->uTex1alphaChannelN, "uTex1alphaChannelN", tagStr);
setIntValue(&pMT->uTex0translateChannelN, "uTex0translateChannelN", tagStr);
setIntBoolValue(&pMT->uAlphaBlending, "uAlphaBlending", tagStr);
setFloatValue(&pMT->uAlphaFactor, "uAlphaFactor", tagStr);
setFloatValue(&pMT->uAmbient, "uAmbient", tagStr);
setFloatValue(&pMT->uSpecularIntencity, "uSpecularIntencity", tagStr);
setFloatValue(&pMT->uSpecularMinDot, "uSpecularMinDot", tagStr);
setFloatValue(&pMT->uSpecularPowerOf, "uSpecularPowerOf", tagStr);
return 1;
}
int ModelLoader::processTag(ModelLoader* pML) {
ModelBuilder* pMB = pML->pModelBuilder;
if (pML->tagName.compare("texture_as") == 0) {
//saves texture N in texturesMap under given name
std::string keyName = getStringValue("texture_as", pML->currentTag);
if (pMB->texturesHashMap.find(keyName) != pMB->texturesHashMap.end())
return pMB->texturesHashMap[keyName];
else { //add new
std::string txFile = getStringValue("src", pML->currentTag);
unsigned int intCkey = 0;
setUintColorValue(&intCkey, "ckey", pML->currentTag);
int txN = Texture::loadTexture(buildFullPath(pML, txFile), intCkey);
pMB->texturesHashMap[keyName] = txN;
//mylog("%s=%d\n", keyName.c_str(), pMB->texturesMap[keyName]);
return txN;
}
}
if (pML->tagName.compare("mt_type") == 0) {
//sets current material
ModelBuilder* pMB = pML->pModelBuilder;
if (!pML->closedTag) {
//save previous material in stack
if (pMB->usingMaterialN >= 0)
pMB->materialsStack.push_back(pMB->usingMaterialN);
}
Material mt;
fillProps_mt(&mt, pML->currentTag, pML);
pMB->usingMaterialN = pMB->getMaterialN(pMB, &mt);
return 1;
}
if (pML->tagName.compare("/mt_type") == 0) {
//restore previous material
if (pMB->materialsStack.size() > 0) {
pMB->usingMaterialN = pMB->materialsStack.back();
pMB->materialsStack.pop_back();
}
return 1;
}
if (pML->tagName.compare("vs") == 0) {
//sets virtual shape
ModelBuilder* pMB = pML->pModelBuilder;
if (pML->closedTag) {
if (pMB->pCurrentVShape != NULL)
delete pMB->pCurrentVShape;
}
else { //open tag
//save previous vshape in stack
if (pMB->pCurrentVShape != NULL)
pMB->vShapesStack.push_back(pMB->pCurrentVShape);
}
pMB->pCurrentVShape = new VirtualShape();
fillProps_vs(pMB->pCurrentVShape, pML->currentTag);
return 1;
}
if (pML->tagName.compare("/vs") == 0) {
//restore previous virtual shape
if (pMB->vShapesStack.size() > 0) {
if (pMB->pCurrentVShape != NULL)
delete(pMB->pCurrentVShape);
pMB->pCurrentVShape = pMB->vShapesStack.back();
pMB->vShapesStack.pop_back();
}
return 1;
}
if (pML->tagName.compare("group") == 0) {
std::string notAllowed[] = { "pxyz","axyz","align","headTo" };
int notAllowedLn = sizeof(notAllowed) / sizeof(notAllowed[0]);
for (int i = 0; i < notAllowedLn; i++)
if (varExists(notAllowed[i], pML->currentTag)) {
mylog("ERROR in ModelLoader::processTag: use %s in </group>: %s\n", notAllowed[i].c_str(), pML->currentTag.c_str());
return -1;
}
pMB->lockGroup(pMB);
//mark
if (varExists("mark", pML->currentTag))
addMark(pMB->pCurrentGroup->marks, getStringValue("mark", pML->currentTag));
return 1;
}
if (pML->tagName.compare("/group") == 0) {
GroupTransform gt;
fillProps_gt(>, pMB, pML->currentTag);
gt.executeGroupTransform(pMB);
pMB->releaseGroup(pMB);
return 1;
}
if (pML->tagName.compare("a") == 0)
return processTag_a(pML); //apply
if (pML->tagName.compare("clone") == 0)
return processTag_clone(pML);
if (pML->tagName.compare("/clone") == 0)
return processTag_clone(pML);
if (pML->tagName.compare("do") == 0)
return processTag_do(pML);
if (pML->tagName.compare("a2mesh") == 0)
return processTag_a2mesh(pML);
if (pML->tagName.compare("mt_adjust") == 0) {
if (pML->pMaterialAdjust != NULL)
mylog("ERROR in ModelLoader::processTag %s, pMaterialAdjust is still busy. File: %s\n", pML->currentTag.c_str(), pML->fullPath.c_str());
pML->pMaterialAdjust = new (MaterialAdjust);
fillProps_mt(pML->pMaterialAdjust, pML->currentTag, pML);
pML->pMaterialAdjust->setWhat2adjust(pML->pMaterialAdjust, pML->currentTag);
return 1;
}
if (pML->tagName.compare("/mt_adjust") == 0) {
if (pML->pMaterialAdjust != NULL) {
delete pML->pMaterialAdjust;
pML->pMaterialAdjust = NULL;
}
return 1;
}
//mylog("%s, %s /group?=%d\n",pML->currentTag.c_str(), pML->tagName.c_str(), (pML->tagName.compare("/group") == 0));
mylog("ERROR in ModelLoader::processTag, unhandled tag %s, file %s\n", pML->currentTag.c_str(), pML->fullPath.c_str());
return -1;
}
int ModelLoader::fillProps_vs(VirtualShape* pVS, std::string tagStr) {
//sets virtual shape
setCharsValue(pVS->shapeType, 20, "vs", tagStr);
setFloatArray(pVS->whl, 3, "whl", tagStr);
//extensions
float ext;
if (varExists("ext", tagStr)) {
setFloatValue(&ext, "ext", tagStr);
pVS->setExt(ext);
}
if (varExists("extX", tagStr)) {
setFloatValue(&ext, "extX", tagStr);
pVS->setExtX(ext);
}
if (varExists("extY", tagStr)) {
setFloatValue(&ext, "extY", tagStr);
pVS->setExtY(ext);
}
if (varExists("extZ", tagStr)) {
setFloatValue(&ext, "extZ", tagStr);
pVS->setExtZ(ext);
}
setFloatValue(&pVS->extU, "extU", tagStr);
setFloatValue(&pVS->extD, "extD", tagStr);
setFloatValue(&pVS->extL, "extL", tagStr);
setFloatValue(&pVS->extR, "extR", tagStr);
setFloatValue(&pVS->extF, "extF", tagStr);
setFloatValue(&pVS->extB, "extB", tagStr);
//sections
setIntValue(&pVS->sectionsR, "sectR", tagStr);
setIntValue(&pVS->sections[0], "sectX", tagStr);
setIntValue(&pVS->sections[1], "sectY", tagStr);
setIntValue(&pVS->sections[2], "sectZ", tagStr);
//mylog("pVS->shapeType=%s whl=%fx%fx%f\n", pVS->shapeType, pVS->whl[0], pVS->whl[1], pVS->whl[2]);
return 1;
}
int ModelLoader::processTag_a(ModelLoader* pML) {
//apply
ModelBuilder* pMB = pML->pModelBuilder;
std::string tagStr = pML->currentTag;
pMB->lockGroup(pMB);
//mark
if (varExists("mark", tagStr))
addMark(pMB->pCurrentGroup->marks, getStringValue("mark", tagStr));
std::vector<std::string> applyTosVector = splitString(pML->getStringValue("a", tagStr), ",");
Material* pMT = pMB->materialsList.at(pMB->usingMaterialN);
int texN = pMT->uTex1mask;
if (texN < 0)
texN = pMT->uTex0;
float xywh[4] = { 0,0,1,1 };
TexCoords* pTC = NULL;
if (varExists("xywh", tagStr)) {
setFloatArray(xywh, 4, "xywh", tagStr);
std::string flipStr = getStringValue("flip", tagStr);
TexCoords tc;
tc.set(texN, xywh[0], xywh[1], xywh[2], xywh[3], flipStr);
pTC = &tc;
}
TexCoords* pTC2nm = NULL;
if (varExists("xywh2nm", tagStr)) {
setFloatArray(xywh, 4, "xywh2nm", tagStr);
std::string flipStr = getStringValue("flip2nm", tagStr);
TexCoords tc2nm;
tc2nm.set(pMT->uTex2nm, xywh[0], xywh[1], xywh[2], xywh[3], flipStr);
pTC2nm = &tc2nm;
}
//adjusted VirtualShape
VirtualShape* pVS_a = new VirtualShape(*pMB->pCurrentVShape);
fillProps_vs(pVS_a, tagStr);
for (int aN = 0; aN < (int)applyTosVector.size(); aN++) {
pMB->buildFace(pMB, applyTosVector.at(aN), pVS_a, pTC, pTC2nm);
}
delete pVS_a;
//mylog("vertsN=%d\n",pMB->vertices.size());
GroupTransform GT_a;
fillProps_gt(>_a, pMB, tagStr);
GT_a.executeGroupTransform(pMB);
pMB->releaseGroup(pMB);
return 1;
}
int ModelLoader::processTag_clone(ModelLoader* pML) {
ModelBuilder* pMB = pML->pModelBuilder;
if (pML->tagName.compare("clone") == 0) {
//mark what to clone
GroupTransform gt;
gt.pGroup = pMB->pLastClosedGroup;
gt.flagSelection(>, &pMB->vertices, &pMB->triangles);
//cloning
pMB->lockGroup(pMB);
gt.cloneFlagged(pMB, &pMB->vertices, &pMB->triangles, &pMB->vertices, &pMB->triangles);
}
GroupTransform gt;
fillProps_gt(>, pMB, pML->currentTag);
gt.executeGroupTransform(pMB);
if (pML->tagName.compare("/clone") == 0 || pML->closedTag) {
pMB->releaseGroup(pMB);
}
return 1;
}
int ModelLoader::addMark(char* marks, std::string newMark) {
if (newMark.empty())
return 0;
std::string allMarks;
allMarks.assign(marks);
allMarks.append("<" + newMark + ">");
myStrcpy_s(marks, 124, allMarks.c_str());
return 1;
}
int ModelLoader::fillProps_gt(GroupTransform* pGT, ModelBuilder* pMB, std::string tagStr) {
pGT->pGroup = pMB->pCurrentGroup;
//position
setFloatArray(pGT->shift, 3, "pxyz", tagStr);
setFloatValue(&pGT->shift[0], "px", tagStr);
setFloatValue(&pGT->shift[1], "py", tagStr);
setFloatValue(&pGT->shift[2], "pz", tagStr);
//angles
setFloatArray(pGT->spin, 3, "axyz", tagStr);
setFloatValue(&pGT->spin[0], "ax", tagStr);
setFloatValue(&pGT->spin[1], "ay", tagStr);
setFloatValue(&pGT->spin[2], "az", tagStr);
//scale
setFloatArray(pGT->scale, 3, "scale", tagStr);
pGT->onThe = getStringValue("onThe", tagStr);
pGT->allign = getStringValue("allign", tagStr);
pGT->headZto = getStringValue("headZto", tagStr);
//limit to
if (varExists("all", tagStr))
pGT->pGroup = NULL;
if (varExists("lastClosedGroup", tagStr))
pGT->pGroup = pMB->pLastClosedGroup;
if (varExists("markedAs", tagStr))
pGT->limit2mark(pGT, getStringValue("markedAs", tagStr));
setFloatArray(pGT->pMin, 3, "xyzMin", tagStr);
setFloatArray(pGT->pMax, 3, "xyzMax", tagStr);
if (varExists("sizeD", tagStr)) { //re-size
float sizeD[3];
setFloatArray(sizeD, 3, "sizeD", tagStr);
//bounding box
pGT->flagSelection(pGT, &pMB->vertices, NULL);
float bbMin[3];
float bbMax[3];
pGT->buildBoundingBoxFlagged(bbMin, bbMax, &pMB->vertices);
for (int i = 0; i < 3; i++) {
float size = bbMax[i] - bbMin[i];
pGT->scale[i] = (size + sizeD[i]) / size;
}
}
return 1;
}
int ModelLoader::processTag_do(ModelLoader* pML) {
ModelBuilder* pMB = pML->pModelBuilder;
GroupTransform gt;
fillProps_gt(>, pMB, pML->currentTag);
gt.flagSelection(>, &pMB->vertices, &pMB->triangles);
gt.transformFlagged(>, &pMB->vertices);
return 1;
}
int ModelLoader::processTag_a2mesh(ModelLoader* pML) {
ModelBuilder* pMB = pML->pModelBuilder;
std::string tagStr = pML->currentTag;
GroupTransform gt;
fillProps_gt(>, pMB, pML->currentTag);
gt.flagSelection(>, &pMB->vertices, &pMB->triangles);
//clone a copy
std::vector<Vertex01*> vx1;
std::vector<Triangle01*> tr1;
gt.cloneFlagged(NULL, &vx1, &tr1, &pMB->vertices, &pMB->triangles);
// build transform and inverted martrices
mat4x4 transformMatrix;
gt.buildTransformMatrix(>, &transformMatrix);
mat4x4 transformMatrixInverted;
mat4x4_invert(transformMatrixInverted, transformMatrix);
//move/rotate cloned
gt.flagAll(&vx1, &tr1);
//gt.transformFlagged(&pMB->vertices, &transformMatrixInverted);
gt.transformFlaggedMx(&vx1, &transformMatrixInverted);
//gt.cloneFlagged(pMB, &pMB->vertices, &pMB->triangles, &vx1, &tr1);
float wh[2];
setFloatArray(wh, 2, "wh", tagStr);
Polygon frame;
frame.setRectangle(&frame, wh[0], wh[1]);
//destination arrays
std::vector<Vertex01*> vx2;
std::vector<Triangle01*> tr2;
Polygon triangle;
for (int i = tr1.size() - 1; i >= 0; i--) {
triangle.setTriangle(&triangle, tr1.at(i), &vx1);
Polygon intersection;
int pointsN = Polygon::xyIntersection(&intersection, &frame, &triangle);
if (pointsN > 2) {
Polygon::buildTriangles(&intersection);
GroupTransform::flagAll(&intersection.vertices, &intersection.triangles);
GroupTransform::cloneFlagged(NULL, &vx2, &tr2, &intersection.vertices, &intersection.triangles);
}
}
gt.flagAll(&vx2, &tr2);
//at this point we have cutted fragment facing us
int vxTotal = vx2.size();
int trTotal = tr2.size();
//apply adjusted material ?
if (pML->pMaterialAdjust != NULL) {
//scan vertices to find new (unupdated) material
int materialNsrc = -1; //which N to replace
int materialNdst = -1; //replace by N
for (int vN = 0; vN < vxTotal; vN++) {
Vertex01* pV = vx2.at(vN);
if (pV->flag < 0)
continue;
if (materialNsrc == pV->materialN)
continue;
//have new material
materialNsrc = pV->materialN;
Material mt;
Material* pMt0 = pMB->materialsList.at(materialNsrc);
memcpy(&mt, pMt0, sizeof(Material));
//modify material
MaterialAdjust::adjust(&mt, pML->pMaterialAdjust);
materialNdst = pMB->getMaterialN(pMB, &mt);
if (materialNsrc != materialNdst) {
//replace mtN in vx and tr arrays
for (int vN2 = vN; vN2 < vxTotal; vN2++) {
Vertex01* pV2 = vx2.at(vN2);
if (pV2->flag < 0)
continue;
if (materialNsrc == pV2->materialN)
pV2->materialN = materialNdst;
}
for (int tN2 = 0; tN2 < trTotal; tN2++) {
Triangle01* pT2 = tr2.at(tN2);
if (pT2->flag < 0)
continue;
if (materialNsrc == pT2->materialN)
pT2->materialN = materialNdst;
}
materialNsrc = materialNdst;
}
}
}
else { // pML->pMaterialAdjust == NULL, use pMB->usingMaterialN
for (int vN2 = 0; vN2 < vxTotal; vN2++) {
Vertex01* pV2 = vx2.at(vN2);
if (pV2->flag < 0)
continue;
pV2->materialN = pMB->usingMaterialN;
}
for (int tN2 = 0; tN2 < trTotal; tN2++) {
Triangle01* pT2 = tr2.at(tN2);
if (pT2->flag < 0)
continue;
pT2->materialN = pMB->usingMaterialN;
}
}
//apply xywh/2nm ?
if (varExists("xywh", tagStr) || varExists("xywh2nm", tagStr)) {
Material* pMT = pMB->materialsList.at(vx2.at(0)->materialN);
float xywh[4] = { 0,0,1,1 };
TexCoords* pTC = NULL;
if (varExists("xywh", tagStr)) {
setFloatArray(xywh, 4, "xywh", tagStr);
std::string flipStr = getStringValue("flip", tagStr);
int texN = pMT->uTex1mask;
if (texN < 0)
texN = pMT->uTex0;
TexCoords tc;
tc.set(texN, xywh[0], xywh[1], xywh[2], xywh[3], flipStr);
pTC = &tc;
}
TexCoords* pTC2nm = NULL;
if (varExists("xywh2nm", tagStr)) {
setFloatArray(xywh, 4, "xywh2nm", tagStr);
std::string flipStr = getStringValue("flip2nm", tagStr);
TexCoords tc2nm;
tc2nm.set(pMT->uTex2nm, xywh[0], xywh[1], xywh[2], xywh[3], flipStr);
pTC2nm = &tc2nm;
}
pMB->applyTexture2flagged(&vx2, "front", pTC, false);
pMB->applyTexture2flagged(&vx2, "front", pTC2nm, true);
}
//move/rotate
gt.transformFlaggedMx(&vx2, &transformMatrix);
//clone back to modelBuilder arrays
gt.cloneFlagged(pMB, &pMB->vertices, &pMB->triangles, &vx2, &tr2);
//clear memory
for (int i = vx1.size() - 1; i >= 0; i--)
delete vx1.at(i);
vx1.clear();
for (int i = tr1.size() - 1; i >= 0; i--)
delete tr1.at(i);
tr1.clear();
for (int i = vx2.size() - 1; i >= 0; i--)
delete vx2.at(i);
vx2.clear();
for (int i = tr2.size() - 1; i >= 0; i--)
delete tr2.at(i);
tr2.clear();
return 1;
}
- New code is in function processTag_a2mesh(..) from line 411.
New ModelLoader requires some new functionality in ModelBuilder class.
7. Open ModelBuilder1base.h and replace code by:
#pragma once
#include <string>
#include <vector>
#include "Vertex01.h"
#include "Triangle01.h"
#include "VirtualShape.h"
#include "Group01.h"
#include "Material.h"
#include "GameSubj.h"
#include <map>
class ModelBuilder1base
{
public:
std::vector<Vertex01*> vertices;
std::vector<Triangle01*> triangles;
std::vector<int> subjNumbersList;
int usingSubjN = -1;
std::vector<Group01*> groupsStack;
Group01* pCurrentGroup = NULL;
Group01* pLastClosedGroup = NULL;
std::vector<VirtualShape*> vShapesStack;
VirtualShape* pCurrentVShape = NULL;
std::vector<Material*> materialsList;
int usingMaterialN = -1;
std::vector<int> materialsStack;
std::map<std::string, int> texturesHashMap;
public:
virtual ~ModelBuilder1base();
static int useSubjN(ModelBuilder1base* pMB, int subjN);
static int getMaterialN(ModelBuilder1base* pMB, Material* pMT);
static void lockGroup(ModelBuilder1base* pMB);
static void releaseGroup(ModelBuilder1base* pMB);
static int addVertex(ModelBuilder1base* pMB, float kx, float ky, float kz, float nx, float ny, float nz);
static int add2triangles(ModelBuilder1base* pMB, int nNW, int nNE, int nSW, int nSE, int n);
static int addTriangle(ModelBuilder1base* pMB, int n0, int n1, int n2);
static int buildDrawJobs(ModelBuilder1base* pMB, std::vector<GameSubj*> gameSubjs);
static int rearrangeArraysForDrawJob(ModelBuilder1base* pMB, std::vector<Vertex01*> allVertices, std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles);
static int buildSingleDrawJob(Material* pMT, std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles);
static int moveGroupDg(ModelBuilder1base* pMB, float aX, float aY, float aZ, float kX, float kY, float kZ);
static int calculateTangentSpace(std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles);
};
- New function here is getMaterialN(..)
8. Open ModelBuilder1base.cpp and replace code by:
#include "ModelBuilder1base.h"
#include "platform.h"
#include "utils.h"
#include "DrawJob.h"
#include "Shader.h"
extern float degrees2radians;
ModelBuilder1base::~ModelBuilder1base() {
releaseGroup(this);
//clear all vectors
int itemsN = vertices.size();
for (int i = 0; i < itemsN; i++)
delete vertices.at(i);
vertices.clear();
itemsN = triangles.size();
for (int i = 0; i < itemsN; i++)
delete triangles.at(i);
triangles.clear();
itemsN = vShapesStack.size();
for (int i = 0; i < itemsN; i++)
delete vShapesStack.at(i);
vShapesStack.clear();
itemsN = groupsStack.size();
for (int i = 0; i < itemsN; i++)
delete groupsStack.at(i);
groupsStack.clear();
if (pCurrentGroup != NULL)
delete pCurrentGroup;
if (pLastClosedGroup != NULL)
delete pLastClosedGroup;
itemsN = materialsList.size();
for (int i = 0; i < itemsN; i++)
delete materialsList.at(i);
materialsList.clear();
subjNumbersList.clear();
}
int ModelBuilder1base::useSubjN(ModelBuilder1base* pMB, int subjN) {
pMB->usingSubjN = subjN;
int itemsN = pMB->subjNumbersList.size();
bool newN = true;
if (itemsN > 0)
for (int i = 0; i < itemsN; i++)
if (pMB->subjNumbersList.at(i) == subjN) {
newN = false;
break;
}
if (newN)
pMB->subjNumbersList.push_back(subjN);
return subjN;
}
int ModelBuilder1base::getMaterialN(ModelBuilder1base* pMB, Material* pMT) {
int itemsN = pMB->materialsList.size();
if (itemsN > 0)
for (int i = 0; i < itemsN; i++)
if (memcmp(pMB->materialsList.at(i), pMT, sizeof(Material)) == 0) {
return i;
}
//if here - add new material to the list
Material* pMTnew = new Material(*pMT);
pMB->materialsList.push_back(pMTnew);
return itemsN;
}
int ModelBuilder1base::add2triangles(ModelBuilder1base* pMB, int nNW, int nNE, int nSW, int nSE, int n) {
//indexes: NorthWest, NorthEast, SouthWest,SouthEast
if (n % 2 == 0) { //even number
addTriangle(pMB, nNW, nSW, nNE);
addTriangle(pMB, nNE, nSW, nSE);
}
else { //odd number
addTriangle(pMB, nNW, nSE, nNE);
addTriangle(pMB, nNW, nSW, nSE);
}
return pMB->triangles.size() - 1;
}
int ModelBuilder1base::addTriangle(ModelBuilder1base* pMB, int i0, int i1, int i2) {
Triangle01* pTR = new Triangle01();
pMB->triangles.push_back(pTR);
pTR->idx[0] = i0;
pTR->idx[1] = i1;
pTR->idx[2] = i2;
pTR->subjN = pMB->usingSubjN;
pTR->materialN = pMB->usingMaterialN;
//mark
if (pMB->pCurrentGroup != NULL)
if (strcmp(pMB->pCurrentGroup->marks, "") != 0)
myStrcpy_s(pTR->marks, 124, pMB->pCurrentGroup->marks);
return pMB->triangles.size() - 1;
}
int ModelBuilder1base::addVertex(ModelBuilder1base* pMB, float kx, float ky, float kz, float nx, float ny, float nz) {
Vertex01* pVX = new Vertex01();
pMB->vertices.push_back(pVX);
pVX->aPos[0] = kx;
pVX->aPos[1] = ky;
pVX->aPos[2] = kz;
//normal
pVX->aNormal[0] = nx;
pVX->aNormal[1] = ny;
pVX->aNormal[2] = nz;
pVX->subjN = pMB->usingSubjN;
pVX->materialN = pMB->usingMaterialN;
//mark
if (pMB->pCurrentGroup != NULL)
if (strcmp(pMB->pCurrentGroup->marks, "") != 0)
myStrcpy_s(pVX->marks, 124, pMB->pCurrentGroup->marks);
return pMB->vertices.size() - 1;
}
int ModelBuilder1base::buildDrawJobs(ModelBuilder1base* pMB, std::vector<GameSubj*> gameSubjs) {
int totalSubjsN = pMB->subjNumbersList.size();
if (totalSubjsN < 1) {
pMB->subjNumbersList.push_back(-1);
totalSubjsN = 1;
}
int totalMaterialsN = pMB->materialsList.size();
if (totalSubjsN < 2 && totalMaterialsN < 2) {
//simple single DrawJob
Material* pMT = pMB->materialsList.at(0);
GameSubj* pGS = NULL;
int gsN = pMB->subjNumbersList.at(0);
if (gsN >= 0)
pGS = gameSubjs.at(gsN);
if (pGS != NULL)
pGS->djStartN = DrawJob::drawJobs.size();
buildSingleDrawJob(pMT, pMB->vertices, pMB->triangles);
if (pGS != NULL)
pGS->djTotalN = DrawJob::drawJobs.size() - pGS->djStartN;
return 1;
}
int totalVertsN = pMB->vertices.size();
int totalTrianglesN = pMB->triangles.size();
//clear flags
for (int vN = 0; vN < totalVertsN; vN++) {
Vertex01* pVX = pMB->vertices.at(vN);
pVX->flag = 0;
}
for (int tN = 0; tN < totalTrianglesN; tN++) {
Triangle01* pTR = pMB->triangles.at(tN);
pTR->flag = 0;
}
int addedDJs = 0;
for (int sN = 0; sN < totalSubjsN; sN++) {
GameSubj* pGS = NULL;
int gsN = pMB->subjNumbersList.at(sN);
if (gsN >= 0)
pGS = gameSubjs.at(gsN);
if (pGS != NULL)
pGS->djStartN = DrawJob::drawJobs.size();
for (int mtN = 0; mtN < totalMaterialsN; mtN++) {
Material* pMT = pMB->materialsList.at(mtN);
std::vector<Vertex01*> useVertices;
std::vector<Triangle01*> useTriangles;
for (int vN = 0; vN < totalVertsN; vN++) {
Vertex01* pVX = pMB->vertices.at(vN);
if (pVX->flag != 0)
continue;
if (pVX->subjN != gsN)
continue;
if (pVX->materialN != mtN)
continue;
//if here - make a copy
Vertex01* pVX2 = new Vertex01(*pVX);
useVertices.push_back(pVX2);
pVX2->altN = vN;
pVX->flag = 1;
if (pVX->endOfSequence > 0) {
rearrangeArraysForDrawJob(pMB, pMB->vertices, useVertices, useTriangles);
buildSingleDrawJob(pMT, useVertices, useTriangles);
addedDJs++;
//clear and proceed to next sequence
int useVerticesN = useVertices.size();
for (int i = 0; i < useVerticesN; i++)
delete useVertices.at(i);
useVertices.clear();
}
}
int useVerticesN = useVertices.size();
if (useVerticesN < 1)
continue; //to next material
//pick triangles
for (int tN = 0; tN < totalTrianglesN; tN++) {
Triangle01* pTR = pMB->triangles.at(tN);
if (pTR->flag != 0)
continue;
if (pTR->subjN != gsN)
continue;
if (pTR->materialN != mtN)
continue;
//if here - make a copy
Triangle01* pTR2 = new Triangle01(*pTR);
useTriangles.push_back(pTR2);
pTR->flag = 1;
}
rearrangeArraysForDrawJob(pMB, pMB->vertices, useVertices, useTriangles);
buildSingleDrawJob(pMT, useVertices, useTriangles);
addedDJs++;
//clear all for next material
for (int i = 0; i < useVerticesN; i++)
delete useVertices.at(i);
useVertices.clear();
int useTrianglesN = useTriangles.size();
for (int i = 0; i < useTrianglesN; i++)
delete useTriangles.at(i);
useTriangles.clear();
}
if (pGS != NULL)
pGS->djTotalN = DrawJob::drawJobs.size() - pGS->djStartN;
}
return addedDJs;
}
int ModelBuilder1base::buildSingleDrawJob(Material* pMT, std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles) {
int totalVertsN = useVertices.size();
if (totalVertsN < 1)
return 0;
if (pMT->uTex2nm >= 0)
calculateTangentSpace(useVertices, useTriangles);
pMT->pickShaderNumber();
DrawJob* pDJ = new DrawJob();
//copy material to DJ
memcpy(&pDJ->mt, pMT, sizeof(Material));
//calculate VBO element size (stride) and variables offsets in VBO
int VBOid = DrawJob::newBufferId();
int stride = 0;
pDJ->setDesirableOffsets(&stride, pDJ->mt.shaderN, VBOid);
//create an array for VBO
int bufferSize = totalVertsN * stride;
float* vertsBuffer = new float[bufferSize];
//fill vertsBuffer
Shader* pSh = Shader::shaders.at(pDJ->mt.shaderN);
int floatSize = sizeof(float);
for (int vN = 0; vN < totalVertsN; vN++) {
Vertex01* pVX = useVertices.at(vN);
int idx = vN * stride / floatSize;
//pick data from vertex and move to the buffer
memcpy(&vertsBuffer[idx + pDJ->aPos.offset / floatSize], pVX->aPos, 3 * floatSize);
if (pSh->l_aNormal >= 0) //normal
memcpy(&vertsBuffer[idx + pDJ->aNormal.offset / floatSize], pVX->aNormal, 3 * floatSize);
if (pSh->l_aTuv >= 0) //attribute TUV (texture coordinates)
memcpy(&vertsBuffer[idx + pDJ->aTuv.offset / floatSize], pVX->aTuv, 2 * floatSize);
if (pSh->l_aTuv2 >= 0) //attribute TUV2 (normal maps)
memcpy(&vertsBuffer[idx + pDJ->aTuv2.offset / floatSize], pVX->aTuv2, 2 * floatSize);
if (pSh->l_aTangent >= 0)
memcpy(&vertsBuffer[idx + pDJ->aTangent.offset / floatSize], pVX->aTangent, 3 * floatSize);
if (pSh->l_aBinormal >= 0)
memcpy(&vertsBuffer[idx + pDJ->aBinormal.offset / floatSize], pVX->aBinormal, 3 * floatSize);
}
//buffer is ready, create VBO
glBindBuffer(GL_ARRAY_BUFFER, VBOid);
glBufferData(GL_ARRAY_BUFFER, bufferSize * floatSize, vertsBuffer, GL_STATIC_DRAW);
delete[] vertsBuffer;
pDJ->pointsN = totalVertsN;
int totalTrianglesN = useTriangles.size();
if (totalTrianglesN > 0) {
//create EBO
int totalIndexesN = totalTrianglesN * 3;
//create buffer
GLushort* indexBuffer = new GLushort[totalIndexesN];
for (int tN = 0; tN < totalTrianglesN; tN++) {
Triangle01* pTR = useTriangles[tN];
int idx = tN * 3;
indexBuffer[idx] = (GLushort)pTR->idx[0];
indexBuffer[idx + 1] = (GLushort)pTR->idx[1];
indexBuffer[idx + 2] = (GLushort)pTR->idx[2];
}
//buffer is ready, create IBO
pDJ->glEBOid = DrawJob::newBufferId();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pDJ->glEBOid);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, totalIndexesN * sizeof(GLushort), indexBuffer, GL_STATIC_DRAW);
delete[] indexBuffer;
pDJ->pointsN = totalIndexesN;
}
//create and fill vertex attributes array (VAO)
pDJ->buildVAO();
return 1;
}
int ModelBuilder1base::rearrangeArraysForDrawJob(ModelBuilder1base* pMB, std::vector<Vertex01*> allVertices, std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles) {
int totalTrianglesN = useTriangles.size();
if (totalTrianglesN < 1)
return 0;
int totalVerticesN = useVertices.size();
//save new vertices order in original vertices array
//since triangles indices refer to original vertices order
for (int i = 0; i < totalVerticesN; i++) {
Vertex01* pVX1 = useVertices.at(i);
Vertex01* pVX0 = allVertices.at(pVX1->altN);
pVX0->altN = i;
}
//replace triangle original indices by new numbers saved in original vertices altN
for (int tN = 0; tN < totalTrianglesN; tN++) {
Triangle01* pTR = useTriangles.at(tN);
for (int i = 0; i < 3; i++) {
Vertex01* pVX0 = allVertices.at(pTR->idx[i]);
pTR->idx[i] = pVX0->altN;
}
}
return 1;
}
int ModelBuilder1base::moveGroupDg(ModelBuilder1base* pMB, float aX, float aY, float aZ, float kX, float kY, float kZ) {
//moves and rotates vertex group
//rotation angles are set in degrees
mat4x4 transformMatrix = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
mat4x4_translate(transformMatrix, kX, kY, kZ);
//rotation order: Z-X-Y
if (aY != 0) mat4x4_rotate_Y(transformMatrix, transformMatrix, degrees2radians * aY);
if (aX != 0) mat4x4_rotate_X(transformMatrix, transformMatrix, degrees2radians * aX);
if (aZ != 0) mat4x4_rotate_Z(transformMatrix, transformMatrix, degrees2radians * aZ);
int vertsN = pMB->vertices.size();
for (int i = pMB->pCurrentGroup->fromVertexN; i < vertsN; i++) {
Vertex01* pVX = pMB->vertices.at(i);
mat4x4_mul_vec4plus(pVX->aPos, transformMatrix, pVX->aPos, 1);
mat4x4_mul_vec4plus(pVX->aNormal, transformMatrix, pVX->aNormal, 0);
}
return 1;
}
int ModelBuilder1base::calculateTangentSpace(std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles) {
int totalVertsN = useVertices.size();
if (totalVertsN < 1)
return 0;
int totalTrianglesN = useTriangles.size();
//assuming that GL_TRIANGLES
//clear flags
for (int vN = 0; vN < totalVertsN; vN++) {
Vertex01* pV = useVertices.at(vN);
pV->flag = 0;
}
for (int vN = 0; vN < totalVertsN; vN++) {
Vertex01* pVX = useVertices.at(vN);
if (pVX->flag != 0)
continue;
Triangle01* pT = NULL;
for (int tN = 0; tN < totalTrianglesN; tN++) {
pT = useTriangles.at(tN);
bool haveTriangle = false;
for (int i = 0; i < 3; i++)
if (pT->idx[i] == vN) {
haveTriangle = true;
break;
}
if (haveTriangle)
break;
}
Vertex01* pV[3];
for (int i = 0; i < 3; i++)
pV[i] = useVertices.at(pT->idx[i]);
float dPos1[3];
float dPos2[3];
float dUV1[2];
float dUV2[2];
for (int i = 0; i < 3; i++) {
dPos1[i] = pV[1]->aPos[i] - pV[0]->aPos[i];
dPos2[i] = pV[2]->aPos[i] - pV[0]->aPos[i];
}
for (int i = 0; i < 2; i++) {
dUV1[i] = pV[1]->aTuv2[i] - pV[0]->aTuv2[i];
dUV2[i] = pV[2]->aTuv2[i] - pV[0]->aTuv2[i];
}
float tangent[3];
float binormal[3];
float divider = dUV1[0] * dUV2[1] - dUV1[1] * dUV2[0];
if (divider == 0) {
v3set(tangent, 1, 0, 0);
v3set(binormal, 0, -1, 0);
}
else {
float r = 1.0f / divider;
for (int i = 0; i < 3; i++) {
tangent[i] = (dPos1[i] * dUV2[1] - dPos2[i] * dUV1[1]) * r;
binormal[i] = -(dPos2[i] * dUV1[0] - dPos1[i] * dUV2[0]) * r;
}
vec3_norm(tangent, tangent);
vec3_norm(binormal, binormal);
}
//add to all 3 vertices
for (int n = 0; n < 3; n++) {
if (pV[n]->flag > 0)
continue;
v3copy(pV[n]->aTangent, tangent);
v3copy(pV[n]->aBinormal, binormal);
pV[n]->flag = 1;
}
}
//normalize tangent and binormal around normal
for (int vN = 0; vN < totalVertsN; vN++) {
Vertex01* pV = useVertices.at(vN);
float v3out[3];
//tangent
vec3_mul_cross(v3out, pV->aNormal, pV->aBinormal);
if (v3dotProduct(pV->aTangent, v3out) < 0)
v3inverse(v3out);
v3copy(pV->aTangent, v3out);
//binormal
vec3_mul_cross(v3out, pV->aNormal, pV->aTangent);
if (v3dotProduct(pV->aBinormal, v3out) < 0)
v3inverse(v3out);
v3copy(pV->aBinormal, v3out);
}
return 1;
}
void ModelBuilder1base::lockGroup(ModelBuilder1base* pMB) {
Group01* pPrevGroup = pMB->pCurrentGroup;
if (pMB->pCurrentGroup != NULL)
pMB->groupsStack.push_back(pMB->pCurrentGroup);
pMB->pCurrentGroup = new Group01();
pMB->pCurrentGroup->fromVertexN = pMB->vertices.size();
pMB->pCurrentGroup->fromTriangleN = pMB->triangles.size();
//marks
if(pPrevGroup != NULL)
if (strcmp(pPrevGroup->marks, "") != 0)
myStrcpy_s(pMB->pCurrentGroup->marks, 124, pPrevGroup->marks);
}
void ModelBuilder1base::releaseGroup(ModelBuilder1base* pMB) {
if (pMB->pLastClosedGroup != NULL)
delete pMB->pLastClosedGroup;
pMB->pLastClosedGroup = pMB->pCurrentGroup;
if (pMB->groupsStack.size() > 0) {
pMB->pCurrentGroup = pMB->groupsStack.back();
pMB->groupsStack.pop_back();
}
else
pMB->pCurrentGroup = NULL;
}
9. Open ModelBuilder.h and replace code by:
#pragma once
#include "ModelBuilder1base.h"
#include "TexCoords.h"
class ModelBuilder : public ModelBuilder1base
{
public:
virtual ~ModelBuilder();
static int buildFace(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS, TexCoords* pTC = NULL, TexCoords* pTC2nm = NULL);
static int buildBoxFace(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS, TexCoords* pTC = NULL, TexCoords* pTC2nm = NULL);
static int buildBoxFacePlain(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS);
static int buildBoxFaceTank(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS);
static int cylinderWrap(ModelBuilder* pMB, VirtualShape* pVS, float angleFrom, float angleTo);
static int capWrap(ModelBuilder* pMB, VirtualShape* pVS, float angleFrom, float angleTo);
static int groupApplyTexture(ModelBuilder* pMB, std::string applyTo, TexCoords* pTC, TexCoords* pTC2nm = NULL);
static int applyTexture2flagged(std::vector<Vertex01*>* pVX, std::string applyTo, TexCoords* pTC, bool isNormalMap);
};
- New function here is applyTexture2flagged(..)
10. Open ModelBuilder.cpp and replace code by:
#include "ModelBuilder.h"
#include "platform.h"
#include "utils.h"
#include "DrawJob.h"
#include "Shader.h"
extern float degrees2radians;
ModelBuilder::~ModelBuilder() {
}
int ModelBuilder::buildFace(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS, TexCoords* pTC, TexCoords* pTC2nm) {
if (strstr(pVS->shapeType, "box") == pVS->shapeType)
return buildBoxFace(pMB, applyTo, pVS, pTC, pTC2nm);
return -1;
}
int ModelBuilder::buildBoxFace(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS, TexCoords* pTC, TexCoords* pTC2nm) {
//this code is for simple box
VirtualShape vs; //face VS,
mat4x4 transformMatrix = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
vs.sectionsR = pVS->sectionsR;
//rotate desirable side to face us.
if (applyTo.find("front") == 0) {
//Side <front> is facing us as is.
vs.whl[0] = pVS->whl[0];
vs.whl[1] = pVS->whl[1];
vs.sections[0] = pVS->sections[0];
vs.sections[1] = pVS->sections[1];
//extensions
vs.extF = pVS->extF;
vs.extL = pVS->extL;
vs.extR = pVS->extR;
vs.extU = pVS->extU;
vs.extD = pVS->extD;
//define how to move/place generated face back to the VirtualShape
//just shift closer to us by length/2
mat4x4_translate(transformMatrix, 0, 0, pVS->whl[2] / 2);
}
else if (applyTo.find("back") == 0) {
vs.whl[0] = pVS->whl[0];
vs.whl[1] = pVS->whl[1];
vs.sections[0] = pVS->sections[0];
vs.sections[1] = pVS->sections[1];
//extensions
vs.extF = pVS->extB;
vs.extL = pVS->extR;
vs.extR = pVS->extL;
vs.extU = pVS->extU;
vs.extD = pVS->extD;
//rotate 180 degrees around Y and shift farther from us by half-length
mat4x4_translate(transformMatrix, 0, 0, -pVS->whl[2] / 2);
mat4x4_rotate_Y(transformMatrix, transformMatrix, degrees2radians * 180);
}
else if (applyTo.find("left") == 0) {
vs.whl[0] = pVS->whl[2]; //width = original length
vs.whl[1] = pVS->whl[1];
vs.sections[0] = pVS->sections[2];
vs.sections[1] = pVS->sections[1];
//extensions
vs.extF = pVS->extL;
vs.extL = pVS->extB;
vs.extR = pVS->extF;
vs.extU = pVS->extU;
vs.extD = pVS->extD;
//rotate -90 degrees around Y (CW) and shift half-width to the left
mat4x4_translate(transformMatrix, -pVS->whl[0] / 2, 0, 0);
mat4x4_rotate_Y(transformMatrix, transformMatrix, -degrees2radians * 90);
}
else if (applyTo.find("right") == 0) {
vs.whl[0] = pVS->whl[2]; //width = original length
vs.whl[1] = pVS->whl[1];
vs.sections[0] = pVS->sections[2];
vs.sections[1] = pVS->sections[1];
//extensions
vs.extF = pVS->extR;
vs.extL = pVS->extF;
vs.extR = pVS->extB;
vs.extU = pVS->extU;
vs.extD = pVS->extD;
//rotate +90 degrees around Y (CCW) and shift half-width to the right
mat4x4_translate(transformMatrix, pVS->whl[0] / 2, 0, 0);
mat4x4_rotate_Y(transformMatrix, transformMatrix, degrees2radians * 90);
}
else if (applyTo.find("top") == 0) {
vs.whl[0] = pVS->whl[0];
vs.whl[1] = pVS->whl[2]; //height = original length
vs.sections[0] = pVS->sections[0];
vs.sections[1] = pVS->sections[2];
//extensions
vs.extF = pVS->extU;
vs.extL = pVS->extR;
vs.extR = pVS->extL;
vs.extU = pVS->extF;
vs.extD = pVS->extB;
//rotate -90 degrees around X (CW) and 180 around Y, and shift half-height up
mat4x4_translate(transformMatrix, 0, pVS->whl[1] / 2, 0);
mat4x4_rotate_Y(transformMatrix, transformMatrix, degrees2radians * 180);
mat4x4_rotate_X(transformMatrix, transformMatrix, -degrees2radians * 90);
}
else if (applyTo.find("bottom") == 0) {
vs.whl[0] = pVS->whl[0];
vs.whl[1] = pVS->whl[2]; //height = original length
vs.sections[0] = pVS->sections[0];
vs.sections[1] = pVS->sections[2];
//extensions
vs.extF = pVS->extD;
vs.extL = pVS->extL;
vs.extR = pVS->extR;
vs.extU = pVS->extF;
vs.extD = pVS->extB;
//rotate 90 around X (CCW) and shift half-height down
mat4x4_translate(transformMatrix, 0, -pVS->whl[1] / 2, 0);
mat4x4_rotate_X(transformMatrix, transformMatrix, degrees2radians * 90);
}
lockGroup(pMB);
//create vertices
if (strstr(pVS->shapeType, "tank") != nullptr)
buildBoxFaceTank(pMB, applyTo, &vs);
else
buildBoxFacePlain(pMB, applyTo, &vs);
groupApplyTexture(pMB, "front", pTC, pTC2nm);
//move face to it's place (apply transform matrix)
int vertsN = pMB->vertices.size();
for (int i = pMB->pCurrentGroup->fromVertexN; i < vertsN; i++) {
Vertex01* pVX = pMB->vertices.at(i);
mat4x4_mul_vec4plus(pVX->aPos, transformMatrix, pVX->aPos, 1);
mat4x4_mul_vec4plus(pVX->aNormal, transformMatrix, pVX->aNormal, 0);
}
releaseGroup(pMB);
return 1;
}
int ModelBuilder::buildBoxFacePlain(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS) {
if (pVS->whl[0] == 0 || pVS->whl[1] == 0)
return 0;
//create vertices
int sectionsX = pVS->sections[0];
int sectionsY = pVS->sections[1];
int pointsX = sectionsX + 1;
int pointsY = sectionsY + 1;
float stepX = pVS->whl[0] / sectionsX;
float stepY = pVS->whl[1] / sectionsY;
float kY = pVS->whl[1] / 2;
for (int iy = 0; iy < pointsY; iy++) {
float kX = -pVS->whl[0] / 2;
for (int ix = 0; ix < pointsX; ix++) {
int nSE = addVertex(pMB, kX, kY, pVS->extF, 0, 0, 1); //vertex number on south-east
if (iy > 0 && ix > 0) {
//add 2 triangles
int nSW = nSE - 1; //vertex number south-west
int nNE = nSE - pointsX; //north-east
int nNW = nSW - pointsX; //north-west
add2triangles(pMB, nNW, nNE, nSW, nSE, iy + ix);
}
kX += stepX;
}
kY -= stepY;
}
return 1;
}
int ModelBuilder::buildBoxFaceTank(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS) {
//for diamond effect - sectionsRad=1, don't merge normals
bool drawMiddle = true;
//edges
bool drawTop = false;
bool drawBottom = false;
bool drawLeft = false;
bool drawRight = false;
//corners
bool drawTopLeft = false;
bool drawTopRight = false;
bool drawBottomLeft = false;
bool drawBottomRight = false;
if (pVS->extF == 0 || applyTo.find(" all") != std::string::npos) {
drawTop = true;
drawBottom = true;
drawLeft = true;
drawRight = true;
drawTopLeft = true;
drawTopRight = true;
drawBottomLeft = true;
drawBottomRight = true;
}
else if (applyTo.find(" h") != std::string::npos) {
drawLeft = true;
drawRight = true;
}
else if (applyTo.find(" v") != std::string::npos) {
drawTop = true;
drawBottom = true;
}
if (applyTo.find(" no") != std::string::npos) {
if (applyTo.find(" noM") != std::string::npos) {
//middle
if (applyTo.find(" noMrow") != std::string::npos) {
drawMiddle = false;
drawLeft = false;
drawRight = false;
}
if (applyTo.find(" noMcol") != std::string::npos) {
drawMiddle = false;
drawTop = false;
drawBottom = false;
}
if (applyTo.find(" noMid") != std::string::npos)
drawMiddle = false;
}
if (applyTo.find(" noN") != std::string::npos) {
//north
if (applyTo.find(" noNrow") != std::string::npos) {
drawTop = false;
drawTopLeft = false;
drawTopRight = false;
}
if (applyTo.find(" noNedge") != std::string::npos)
drawTop = false;
if (applyTo.find(" noNW") != std::string::npos)
drawTopLeft = false;
if (applyTo.find(" noNE") != std::string::npos)
drawTopRight = false;
}
if (applyTo.find(" noS") != std::string::npos) {
//south
if (applyTo.find(" noSrow") != std::string::npos) {
drawBottom = false;
drawBottomLeft = false;
drawBottomRight = false;
}
if (applyTo.find(" noSedge") != std::string::npos)
drawBottom = false;
if (applyTo.find(" noSW") != std::string::npos)
drawBottomLeft = false;
if (applyTo.find(" noSE") != std::string::npos)
drawBottomRight = false;
}
if (applyTo.find(" noW") != std::string::npos) {
//west
if (applyTo.find(" noWcol") != std::string::npos) {
drawLeft = false;
drawTopLeft = false;
drawBottomLeft = false;
}
if (applyTo.find(" noWedge") != std::string::npos)
drawLeft = false;
}
if (applyTo.find(" noE") != std::string::npos) {
//east
if (applyTo.find(" noEcol") != std::string::npos) {
drawRight = false;
drawTopRight = false;
drawBottomRight = false;
}
if (applyTo.find(" noEedge") != std::string::npos)
drawRight = false;
}
}
lockGroup(pMB);
//middle
if (pVS->whl[0] > 0 && pVS->whl[1] > 0 && drawMiddle) {
buildBoxFacePlain(pMB, applyTo, pVS);
}
VirtualShape vs;
//edges
//vs.type.assign("cylinder");
vs.sectionsR = pVS->sectionsR;
if (pVS->whl[0] > 0) {
vs.sections[2] = pVS->sections[0]; //cylinder Z sections n
vs.whl[2] = pVS->whl[0]; //cylinder length Z
vs.whl[0] = pVS->extF * 2; //cylinder diameter X
if (pVS->extU > 0 && drawTop) {
vs.whl[1] = pVS->extU * 2; //cylinder diameter Y
lockGroup(pMB);
cylinderWrap(pMB, &vs, 0, 90);
//rotate -90 degrees around Y and shift up
moveGroupDg(pMB, 0, -90, 0, 0, pVS->whl[1] * 0.5f, 0);
releaseGroup(pMB);
}
if (pVS->extD > 0 && drawBottom) {
vs.whl[1] = pVS->extD * 2; //cylinder diameter Y
lockGroup(pMB);
cylinderWrap(pMB, &vs, -90, 0);
//rotate -90 degrees around Y and shift down
moveGroupDg(pMB, 0, -90, 0, 0, -pVS->whl[1] * 0.5f, 0);
releaseGroup(pMB);
}
}
if (pVS->whl[1] > 0) {
vs.sections[2] = pVS->sections[1]; //cylinder Z sections n
vs.whl[2] = pVS->whl[1]; //cylinder length Z
vs.whl[1] = pVS->extF * 2; //cylinder diameter Y
if (pVS->extL > 0 && drawLeft) {
vs.whl[0] = pVS->extL * 2; //cylinder diameter X
lockGroup(pMB);
cylinderWrap(pMB, &vs, 90, 180);
//rotate 90 degrees around Y and shift left
moveGroupDg(pMB, 90, 0, 0, -pVS->whl[0] * 0.5f, 0, 0);
releaseGroup(pMB);
}
if (pVS->extR > 0 && drawRight) {
vs.whl[0] = pVS->extR * 2; //cylinder diameter X
lockGroup(pMB);
cylinderWrap(pMB, &vs, 0, 90);
//rotate 90 degrees around Y and shift left
moveGroupDg(pMB, 90, 0, 0, pVS->whl[0] * 0.5f, 0, 0);
releaseGroup(pMB);
}
}
//corners
//vs.type.assign("cap");
vs.sectionsR = pVS->sectionsR;
vs.sections[2] = pVS->sectionsR;
vs.whl[2] = pVS->extF;
if (pVS->extU > 0) {
//top corners
vs.whl[1] = pVS->extU * 2;
if (pVS->extL > 0 && drawTopLeft) {
vs.whl[0] = pVS->extL * 2;
lockGroup(pMB);
capWrap(pMB, &vs, 90, 180);
//rotate 90 degrees around Y and shift left
moveGroupDg(pMB, 0, 0, 0, -pVS->whl[0] * 0.5f, pVS->whl[1] * 0.5f, 0);
releaseGroup(pMB);
}
if (pVS->extR > 0 && drawTopRight) {
vs.whl[0] = pVS->extR * 2;
lockGroup(pMB);
capWrap(pMB, &vs, 0, 90);
//rotate 90 degrees around Y and shift left
moveGroupDg(pMB, 0, 0, 0, pVS->whl[0] * 0.5f, pVS->whl[1] * 0.5f, 0);
releaseGroup(pMB);
}
}
if (pVS->extD > 0) {
//bottom corners
vs.whl[1] = pVS->extD * 2;
if (pVS->extL > 0 && drawBottomLeft) {
vs.whl[0] = pVS->extL * 2;
lockGroup(pMB);
capWrap(pMB, &vs, -180, -90);
//rotate 90 degrees around Y and shift left
moveGroupDg(pMB, 0, 0, 0, -pVS->whl[0] * 0.5f, -pVS->whl[1] * 0.5f, 0);
releaseGroup(pMB);
}
if (pVS->extR > 0 && drawBottomRight) {
vs.whl[0] = pVS->extR * 2;
lockGroup(pMB);
capWrap(pMB, &vs, -90, 0);
//rotate 90 degrees around Y and shift left
moveGroupDg(pMB, 0, 0, 0, pVS->whl[0] * 0.5f, -pVS->whl[1] * 0.5f, 0);
releaseGroup(pMB);
}
}
if (pVS->extF == 0) {
int vertsN = pMB->vertices.size();
for (int i = pMB->pCurrentGroup->fromVertexN; i < vertsN; i++) {
Vertex01* pVX = pMB->vertices.at(i);
//normal
v3set(pVX->aNormal, 0, 0, 1);
}
}
releaseGroup(pMB);
return 1;
}
int ModelBuilder::cylinderWrap(ModelBuilder* pMB, VirtualShape* pVS, float angleFrom, float angleTo) {
// angleFrom/To - in degrees
lockGroup(pMB);
float stepZ = pVS->whl[2] / pVS->sections[2];
float stepDg = (angleTo - angleFrom) / pVS->sectionsR; //in degrees
for (int nz = 0; nz <= pVS->sections[2]; nz++) {
float kz = stepZ * nz - pVS->whl[2] * 0.5f;
for (int rpn = 0; rpn <= pVS->sectionsR; rpn++) {
// rpn - radial point number
float angleRd = (angleFrom + stepDg * rpn) * degrees2radians;
float kx = cosf(angleRd);
float ky = sinf(angleRd);
int nSE = addVertex(pMB, kx, ky, kz, kx, ky, 0);
if (nz > 0 && rpn > 0) {
int nSW = nSE - 1;
int nNW = nSW - pVS->sectionsR - 1;
int nNE = nSE - pVS->sectionsR - 1;
add2triangles(pMB, nNE, nNW, nSE, nSW, nz + rpn);
}
}
}
//scale to desirable diameters
mat4x4 transformMatrix = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
mat4x4_scale_aniso(transformMatrix, transformMatrix, pVS->whl[0] * 0.5f, pVS->whl[1] * 0.5f, 1);
int vertsN = pMB->vertices.size();
for (int i = pMB->pCurrentGroup->fromVertexN; i < vertsN; i++) {
Vertex01* pVX = pMB->vertices.at(i);
mat4x4_mul_vec4plus(pVX->aPos, transformMatrix, pVX->aPos, 1);
}
releaseGroup(pMB);
return 1;
}
int ModelBuilder::capWrap(ModelBuilder* pMB, VirtualShape* pVS, float angleFrom, float angleTo) {
// angleFrom/To - in degrees
lockGroup(pMB);
//center point
int n0 = addVertex(pMB, 0, 0, 1, 0, 0, 1);
float stepZdg = 90.0f / pVS->sections[2]; //in degrees
float stepRdg = (angleTo - angleFrom) / pVS->sectionsR; //in degrees
for (int nz = 1; nz <= pVS->sections[2]; nz++) {
float angleZrd = stepZdg * nz * degrees2radians;
float kz = cosf(angleZrd);
float R = sinf(angleZrd);
for (int rpn = 0; rpn <= pVS->sectionsR; rpn++) {
// rpn - radial point number
float angleRd = (angleFrom + stepRdg * rpn) * degrees2radians;
float kx = cosf(angleRd) * R;
float ky = sinf(angleRd) * R;
int nSE = addVertex(pMB, kx, ky, kz, kx, ky, kz);
if (rpn > 0) {
if (nz == 1) {
int nSW = nSE - 1;
addTriangle(pMB, n0, nSW, nSE);
}
else {
int nSW = nSE - 1;
int nNW = nSW - pVS->sectionsR - 1;
int nNE = nSE - pVS->sectionsR - 1;
add2triangles(pMB, nNW, nNE, nSW, nSE, nz + rpn);
}
}
}
}
//scale to desirable diameters
mat4x4 transformMatrix = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
mat4x4_scale_aniso(transformMatrix, transformMatrix, pVS->whl[0] * 0.5f, pVS->whl[1] * 0.5f, pVS->whl[2]);
int vertsN = pMB->vertices.size();
for (int i = pMB->pCurrentGroup->fromVertexN; i < vertsN; i++) {
Vertex01* pVX = pMB->vertices.at(i);
mat4x4_mul_vec4plus(pVX->aPos, transformMatrix, pVX->aPos, 1);
}
releaseGroup(pMB);
return 1;
}
int ModelBuilder::groupApplyTexture(ModelBuilder* pMB, std::string applyTo, TexCoords* pTC, TexCoords* pTC2nm) {
int vertsN = pMB->vertices.size();
for (int vN = 0; vN < vertsN; vN++) {
Vertex01* pVX = pMB->vertices.at(vN);
if(vN < pMB->pCurrentGroup->fromVertexN)
pVX->flag = -1;
else
pVX->flag = 0;
}
applyTexture2flagged(&pMB->vertices, applyTo, pTC, false);
applyTexture2flagged(&pMB->vertices, applyTo, pTC2nm, true);
return 1;
}
int ModelBuilder::applyTexture2flagged(std::vector<Vertex01*>* pVerts, std::string applyTo, TexCoords* pTC, bool isNormalMap) {
if (pTC == NULL)
return 0;
float posMin[3];
float posMax[3];
float posRange[3];
for (int i = 0; i < 3; i++) {
posMin[i] = 1000000;
posMax[i] = -1000000;
}
int vertsN = pVerts->size();
for (int vN = 0; vN < vertsN; vN++) {
Vertex01* pVX = pVerts->at(vN);
if (pVX->flag < 0) //ignore
continue;
for (int i = 0; i < 3; i++) {
if (posMin[i] > pVX->aPos[i])
posMin[i] = pVX->aPos[i];
if (posMax[i] < pVX->aPos[i])
posMax[i] = pVX->aPos[i];
}
}
//here we have coordinates range
for (int i = 0; i < 3; i++)
posRange[i] = posMax[i] - posMin[i];
//for "front"
int xRateIndex = 0;
bool xRateInverse = false;
int yRateIndex = 1;
bool yRateInverse = true;
if (applyTo.find("front") == 0)
; //do nothing
else if (applyTo.find("back") == 0)
xRateInverse = true;
else if (applyTo.find("left") == 0)
xRateIndex = 2;
else if (applyTo.find("right") == 0) {
xRateIndex = 2;
xRateInverse = true;
}
else if (applyTo.find("top") == 0) {
xRateInverse = true;
yRateIndex = 2;
}
else if (applyTo.find("bottom") == 0)
yRateIndex = 2;
float xRate = 0;
float yRate = 0;
float tuvRange[2];
tuvRange[0] = pTC->tuvBottomRight[0] - pTC->tuvTopLeft[0];
tuvRange[1] = pTC->tuvBottomRight[1] - pTC->tuvTopLeft[1];
for (int vN = 0; vN < vertsN; vN++) {
Vertex01* pVX = pVerts->at(vN);
if (pVX->flag < 0) //ignore
continue;
if (posRange[xRateIndex] == 0)
xRate = 0;
else {
xRate = (pVX->aPos[xRateIndex] - posMin[xRateIndex]) / posRange[xRateIndex];
if (xRateInverse)
xRate = 1.0f - xRate;
}
if (posRange[yRateIndex] == 0)
yRate = 0;
else {
yRate = (pVX->aPos[yRateIndex] - posMin[yRateIndex]) / posRange[yRateIndex];
if (yRateInverse)
yRate = 1.0f - yRate;
}
float* pTuv = pVX->aTuv;
if(isNormalMap)
pTuv = pVX->aTuv2;
pTuv[0] = pTC->tuvTopLeft[0] + tuvRange[0] * xRate;
pTuv[1] = pTC->tuvTopLeft[1] + tuvRange[1] * yRate;
}
return 1;
}
11. Build and run. Result:
Before:
After:
Now - with slit.
Android
12. Close and re-start VS. Open C:\CPP\a997modeler\p_android\p_android.sln.
13. Under modeler add Existing Item from C:\CPP\engine\modeler
- MaterialAdjust.cpp
- MaterialAdjust.h
Add
14. Switch on, unlock, plug in, allow.
Build and run. Works.
VS top menu -> Debug -> Stop Debugging