Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the antispam-bee domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /home/ruwritingagame/public_html/wp-includes/functions.php on line 6131
Глава 30. Манипуляции группой вертексов – Игра в Написание Игры

Глава 30. Манипуляции группой вертексов

Здесь я зочу добавить золоченые принты на пачке. Для этого понадобится по ходу изменять (подправлять) размеры и позиции проекций.

Новый 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,back v" xywh="2,1,323,495"/>
<a="right all" xywh="327,1,128,495"/>
<a="left all" xywh="457,1,128,495"/>
<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 uTex1mask_use="tx0" uTex0_use="whitenoise" uTex0translateChannelN=0 uTex3_use="gold" />
	<a="front" xywh="589,415,128,94" whl="20.7,16,x" pxyz="0.3,6.1,x" /> //emblem	
</group> 
<clone ay=180 />

1. Скопируем этот код в Текстовый редактор и сохраним его (overwrite) to/as

C:\CPP\a997modeler\dt\models\misc\marlboro01\root01.txt

Обратите внимание:

  • В тагах “a” теперь есть новые параметры/properties: whl (измененный размер) и pxyz (позиция прекции).
  • “x” в размерах/координатах означает использовать значение по умолчанию (из виртуальной формы).
  • Еще появился новый таг “clone” (последняя строка), который копирует/дублирует последнюю закрытую группу (в этом примере – золоченые принты на лицевой стороне) и размещает ее (копию) на обратной стороне.


В предыдущих примерах мы использовали текстуру gold01.bmp. Но для нашей пачки она слишком желтая. Я добавил еще одну, “римское золото”:

Менее желтую и по-зеленоватее.

2. Сгрузим BMP файл тут

и сохраним его to/as:

C:\CPP\engine\dt\common\img\materials\gold02roman.bmp


Теперь – программная сторона.

Windows

3. Запускаем VS, открываем C:\CPP\a997modeler\p_windows\p_windows.sln.


4. Под modeler добавим новый header file GroupTransform.h

Location: C:\CPP\engine\modeler

Код:

#pragma once
#include "ModelBuilder.h"

class GroupTransform
{
public:
	float shift[4] = { 0,0,0,0 };
	float spin[3] = { 0,0,0 }; //in degrees
public:
	int executeGroupTransform(ModelBuilder* pMB) { return executeGroupTransform(pMB, this); };
	static int executeGroupTransform(ModelBuilder* pMB, GroupTransform* pGT);
};


5. Под modeler добавим новый C++ file GroupTransform.cpp

Location: C:\CPP\engine\modeler

Код:

#include "GroupTransform.h"

int GroupTransform::executeGroupTransform(ModelBuilder* pMB, GroupTransform* pGT) {
	pMB->moveGroupDg(pMB, pGT->spin[0], pGT->spin[1], pGT->spin[2], pGT->shift[0], pGT->shift[1], pGT->shift[2]);
	return 1;
}


В ModelLoader-е – новый функционал:

  • fillProps_gt(..) – чтение/заполнение GroupTrandform info.
  • processTag_a(..) подправлен для приема под-настроек VirtualShape и обработки GroupTrandform инструкций (которые относятся к исполняемой группе “a”).
  • добавлена обработка тага “clone” – processTag_clone(..)

6. Заменим ModelLoader.h код на:

#pragma once
#include "XMLparser.h"
#include "ModelBuilder.h"
#include "GroupTransform.h"

class ModelLoader : public XMLparser
{
public:
	ModelBuilder* pModelBuilder = NULL;
	bool ownModelBuilder = false;
	std::vector<GameSubj*>* pSubjsVector = 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->useSubjN(subjN);
	};
	virtual ~ModelLoader() {
		if (!ownModelBuilder)
			return;
		pModelBuilder->buildDrawJobs(*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, std::string tagStr);
	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);
};


7. Заменим ModelLoader.cpp код на:

#include "ModelLoader.h"
#include "platform.h"
#include "TheGame.h"
#include "DrawJob.h"
#include "Texture.h"
#include "utils.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);

	pML->pModelBuilder->useMaterial(pMT);
	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.find("mt_") == 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;
		return fillProps_mt(&mt, pML->currentTag, pML);
	}
	if (pML->tagName.find("/mt_") == 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);
		return 1;
	}
	if (pML->tagName.compare("/group") == 0) {
		GroupTransform groupTransform;
		fillProps_gt(&groupTransform, pML->currentTag);
		groupTransform.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);

	//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::fillProps_gt(GroupTransform* pGS, std::string tagStr) {
	//position
	setFloatArray(pGS->shift, 3, "pxyz", tagStr);
	setFloatValue(&pGS->shift[0], "px", tagStr);
	setFloatValue(&pGS->shift[1], "py", tagStr);
	setFloatValue(&pGS->shift[2], "pz", tagStr);
	//angles
	setFloatArray(pGS->spin, 3, "axyz", tagStr);
	setFloatValue(&pGS->spin[0], "ax", tagStr);
	setFloatValue(&pGS->spin[1], "ay", tagStr);
	setFloatValue(&pGS->spin[2], "az", tagStr);

	return 1;
}
int ModelLoader::processTag_a(ModelLoader* pML) {
	//apply
	ModelBuilder* pMB = pML->pModelBuilder;
	std::string tagStr = pML->currentTag;
	pMB->lockGroup(pMB);

	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 };
	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);

	setFloatArray(xywh, 4, "xywh2nm", tagStr);
	flipStr = getStringValue("flip2nm", tagStr);
	TexCoords tc2nm;
	tc2nm.set(pMT->uTex2nm, xywh[0], xywh[1], xywh[2], xywh[3], flipStr);

	//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), pMB->pCurrentVShape, &tc, &tc2nm);
		pMB->buildFace(pMB, applyTosVector.at(aN), pVS_a, &tc, &tc2nm);
	}
	delete pVS_a;
	//mylog("vertsN=%d\n",pMB->vertices.size());

	GroupTransform GT_a;
	fillProps_gt(&GT_a, 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) {
		//cloning
		int vertsN = pMB->vertices.size() - pMB->pLastClosedGroup->fromVertexN;
		int trianglesN = pMB->triangles.size() - pMB->pLastClosedGroup->fromTriangleN;
		pMB->lockGroup(pMB);
		for (int i = 0; i < vertsN; i++) {
			int vN = pMB->pLastClosedGroup->fromVertexN + i;
			Vertex01* pV = new Vertex01(*pMB->vertices.at(vN));
			pMB->vertices.push_back(pV);
		}
		for (int i = 0; i < trianglesN; i++) {
			int tN = pMB->pLastClosedGroup->fromTriangleN + i;
			Triangle01* pT = new Triangle01(*pMB->triangles.at(tN));
			for (int n = 0; n < 3; n++)
				pT->idx[n] += vertsN;
			pMB->triangles.push_back(pT);
		}
	}
	GroupTransform groupTransform;
	fillProps_gt(&groupTransform, pML->currentTag);
	groupTransform.executeGroupTransform(pMB);
	if (pML->tagName.compare("/clone") == 0 || pML->closedTag) {
		pMB->releaseGroup(pMB);
	}
	return 1;
}


Таг “clone” в ModelLoader-е полагается на новую переменную pLastClosedGroup в ModelBuilder1base.

8. Заменим ModelBuilder1base.h код на:

#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();
	int useSubjN(int subjN) { return useSubjN(this, subjN); };
	static int useSubjN(ModelBuilder1base* pMB, int subjN);
	int useMaterial(Material* pMT) { return useMaterial(this, pMT); };
	static int useMaterial(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);
	int buildDrawJobs(std::vector<GameSubj*> gameSubjs) { return buildDrawJobs(this, gameSubjs); };
	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);
};


Эта новая переменная pLastClosedGroup отслеживается в ModelBuilder1base::releaseGroup()

9. Заменим ModelBuilder1base.cpp код на:

#include "ModelBuilder1base.h"
#include "platform.h"
#include "utils.h"
#include "DrawJob.h"
#include "Shader.h"

extern float degrees2radians;

ModelBuilder1base::~ModelBuilder1base() {
	//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();

	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::useMaterial(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) {
				pMB->usingMaterialN = i;
				return i;
			}
	//if here - add new material to the list
	pMB->usingMaterialN = itemsN;
	//create a copy of new Material and add 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;
	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;
	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;
}

void ModelBuilder1base::lockGroup(ModelBuilder1base* pMB) {
	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();
}
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;
}


10. Компиляция и запуск.

До:

После:

Теперь – с золочеными принтАми.


Android

11. Пере-запускаем VS. Открываем C:\CPP\a997modeler\p_android\p_android.sln.


12. под modeler добавим Existing Item

из C:\CPP\engine\modeler

Файлы:

  • GroupTransform.cpp
  • GroupTransform.h

Add


13. Включаем, разблокируем, подключаем, разрешаем.

Компиляция и запуск.

Ok.

VS top menu -> Debug -> Stop Debugging.


Leave a Reply

Your email address will not be published. Required fields are marked *