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
Глава 21. Текстурированная поверхность – Игра в Написание Игры

Глава 21. Текстурированная поверхность

Теперь давайте наложим текстуру на более сложную много-вертексную поверхность, на правую (синюю) строну например. Надеюсь, понятно как написать текстурированный Phong шейдер, но мы сделаем это как-нибудь в другой раз. Пока обойдемся и простым (без света, который у нас уже есть). Нам понадобится:

  • передать желаемые координаты изображения в Modeler
  • и вычислить tUV координаты для каждого вовлеченного вертекса

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

  • Старые проекты, a998engine и a999hello, можно удалить.

Возьмем картинку C:\CPP\a997modeler\dt\sample_img.png из предыдущих глав.

Допустим, мы хотим не всю картину, а только 256×128 фрагмент с 11×12 позиции (2 левых рыцаря):

Также, скажем, мы хотим перевернуть ее вверх ногами.

Во-первых, нам надо пересчитать эти числа в GL-овский “tUV” формат, от 0 до 1. Потом надо реорганизовать полученные координаты чтобы отразить разворот. Сделаем это в отдельном классе.


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

Location – C:\CPP\engine\modeler

Код:

#pragma once
#include <string>

class TexCoords
{
public:
	float tuvTopLeft[2] = { 0.0f,0.0f };
	float tuvBottomRight[2] = { 1.0f,1.0f };
public:
	void set(int texN, float x, float y, float w, float h, std::string flip) { set(this, texN, x, y, w, h, flip); };
	static void set(TexCoords* pTC, int texN, float x, float y, float w, float h, std::string flipStr);
	static void set_GL(TexCoords* pTC, float x, float y, float w, float h, std::string flipStr);
	static void flip(TexCoords* pTC, std::string flipStr); //possible flips: "90" (CCW), "-90" (CW), "180", "h" (horizontal), "v" (vertical) 
};


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

Location – C:\CPP\engine\modeler

Код:

#include "TexCoords.h"
#include "Texture.h"

void TexCoords::set(TexCoords* pTC, int texN, float x, float y, float w, float h, std::string flipStr) {
	if (texN < 0)
		return;
	Texture* pTex = Texture::textures.at(texN);
	x = x / pTex->size[0];
	y = y / pTex->size[1];
	w = w / pTex->size[0];
	h = h / pTex->size[1];
	set_GL(pTC, x, y, w, h, flipStr);
}
void TexCoords::set_GL(TexCoords* pTC, float x, float y, float w, float h, std::string flipStr) {
	//assuming that x,y,w,h - in GL 0-to-1 format
	pTC->tuvTopLeft[0] = x;
	pTC->tuvTopLeft[1] = y;
	pTC->tuvBottomRight[0] = x + w;
	pTC->tuvBottomRight[1] = y + h;
	flip(pTC, flipStr);
}
void TexCoords::flip(TexCoords* pTC, std::string flipStr) {
	//possible flips: "90" (CCW), "-90" (CW), "180", "h" (horizontal), "v" (vertical) 
	if (flipStr.compare("") == 0)
		return;
	TexCoords outTC;
	if (flipStr.find("90") == 0) { //CCW
		outTC.tuvTopLeft[0] = pTC->tuvBottomRight[0];
		outTC.tuvTopLeft[1] = pTC->tuvTopLeft[1];
		outTC.tuvBottomRight[0] = pTC->tuvTopLeft[0];
		outTC.tuvBottomRight[1] = pTC->tuvBottomRight[1];
	}
	else if (flipStr.find("-90") == 0) { //CW
		outTC.tuvTopLeft[0] = pTC->tuvTopLeft[0];
		outTC.tuvTopLeft[1] = pTC->tuvBottomRight[1];
		outTC.tuvBottomRight[0] = pTC->tuvBottomRight[0];
		outTC.tuvBottomRight[1] = pTC->tuvTopLeft[1];
	}
	else if (flipStr.find("180") == 0) {
		outTC.tuvTopLeft[0] = pTC->tuvBottomRight[0];
		outTC.tuvTopLeft[1] = pTC->tuvBottomRight[1];
		outTC.tuvBottomRight[0] = pTC->tuvTopLeft[0];
		outTC.tuvBottomRight[1] = pTC->tuvTopLeft[1];
	}
	else if (flipStr.find("h") == 0) { //horizontal
		outTC.tuvTopLeft[0] = pTC->tuvBottomRight[0];
		outTC.tuvTopLeft[1] = pTC->tuvTopLeft[1];
		outTC.tuvBottomRight[0] = pTC->tuvTopLeft[0];
		outTC.tuvBottomRight[1] = pTC->tuvBottomRight[1];
	}
	else if (flipStr.find("v") == 0) { //vertical
		outTC.tuvTopLeft[0] = pTC->tuvTopLeft[0];
		outTC.tuvTopLeft[1] = pTC->tuvBottomRight[1];
		outTC.tuvBottomRight[0] = pTC->tuvBottomRight[0];
		outTC.tuvBottomRight[1] = pTC->tuvTopLeft[1];
	}
	memcpy(pTC, &outTC, sizeof(TexCoords));
}


В TheGame.cpp вместо смены цвета для правой стороны, заменим Material целиком. Еще будет нужно передать текстурные координаты TexCoords в функцию pMB->buildBoxFace.

4. Заменим TheGame.cpp код на:

#include "TheGame.h"
#include "platform.h"
#include "utils.h"
#include "linmath.h"
#include "Texture.h"
#include "Shader.h"
#include "DrawJob.h"
#include "ModelBuilder.h"
#include "TexCoords.h"

extern std::string filesRoot;

std::vector<GameSubj*> TheGame::gameSubjs;

int TheGame::getReady() {
    bExitGame = false;
    Shader::loadShaders();
    glEnable(GL_CULL_FACE);

    //=== create box ========================
    GameSubj* pGS = new GameSubj();
    gameSubjs.push_back(pGS);

    pGS->name.assign("box1");
    pGS->ownCoords.setPosition(0, 0, 0);
    pGS->ownCoords.setDegrees(0, 0, 0);
    pGS->ownSpeed.setDegrees(0,1,0);

    ModelBuilder* pMB = new ModelBuilder();
    pMB->useSubjN(gameSubjs.size() - 1);

    //define VirtualShape
    VirtualShape vs;
    vs.setShapeType("box-tank");
    vs.whl[0] = 60;
    vs.whl[1] = 160;
    vs.whl[2] = 390;
    vs.setExt(20);
    vs.extD = 0;
    vs.extF = 0; //to make front face "flat"
    vs.sectionsR = 2;

    Material mt;
    //define material - flat red
    mt.shaderN = Shader::spN_phong_ucolor;
    mt.primitiveType = GL_TRIANGLES;
    mt.uColor.setRGBA(255, 0, 0,255); //red
    pMB->useMaterial(&mt);

    pMB->buildBoxFace(pMB,"front v", &vs);
    pMB->buildBoxFace(pMB, "back v", &vs);
    pMB->buildBoxFace(pMB, "top", &vs);
    pMB->buildBoxFace(pMB, "bottom", &vs);
    pMB->buildBoxFace(pMB, "left all", &vs);

    mt.uColor.clear(); // set to zero;
    mt.uTex0 = Texture::loadTexture(filesRoot + "/dt/sample_img.png");
    mt.shaderN = Shader::spN_flat_tex;
    pMB->useMaterial(&mt);
    TexCoords tc;
    tc.set(mt.uTex0, 11, 12, 256, 128, "180");
    pMB->buildBoxFace(pMB, "right all", &vs, &tc);

    pMB->buildDrawJobs(gameSubjs);

    delete pMB;

    //===== set up camera
    v3set(mainCamera.ownCoords.pos, 0, 200, 1000); //set position
    float cameraDir[3];
    v3set(cameraDir, 0, -200, -1000); //set direction vector
    float cameraYawDg = v3yawDg(cameraDir);
    float cameraPitchDg = v3pitchDg(cameraDir);
    //mylog("cameraYaw=%f, cameraPitch=%f\n", cameraYawDg, cameraPitchDg);

    mainCamera.ownCoords.setDegrees(cameraPitchDg, cameraYawDg, 0);
    float cameraUp[4] = { 0,1,0,0 }; //y - up
    mat4x4_mul_vec4plus(cameraUp, *mainCamera.ownCoords.getRotationMatrix(), cameraUp, 0);

    mat4x4_look_at(mainCamera.lookAtMatrix, mainCamera.ownCoords.pos, pGS->ownCoords.pos, cameraUp);

    //===== set up light
    v3set(dirToMainLight, -1, 1, 1);
    vec3_norm(dirToMainLight, dirToMainLight);

    return 1;
}
int TheGame::drawFrame() {
    myPollEvents();

    //glClearColor(0.0, 0.0, 0.5, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    //calculate halfVector
    float dirToCamera[4] = { 0,0,-1,0 }; //-z
    mat4x4_mul_vec4plus(dirToCamera, *mainCamera.ownCoords.getRotationMatrix(), dirToCamera, 0);

    float uHalfVector[4] = { 0,0,0,0 };
    for (int i = 0; i < 3; i++)
        uHalfVector[i] = (dirToCamera[i] + dirToMainLight[i]) / 2;
    vec3_norm(uHalfVector, uHalfVector);

    mat4x4 mProjection, mViewProjection, mMVP, mMV4x4;
    //mat4x4_ortho(mProjection, -(float)screenSize[0] / 2, (float)screenSize[0] / 2, -(float)screenSize[1] / 2, (float)screenSize[1] / 2, 100.f, 500.f);
    mat4x4_perspective(mProjection, 3.14f / 6.0f, (float)screenSize[0] / screenSize[1], 700.f, 1300.f);
    mat4x4_mul(mViewProjection, mProjection, mainCamera.lookAtMatrix);
    //mViewProjection[1][3] = 0; //keystone effect

    //scan subjects
    int subjsN = gameSubjs.size();
    for (int subjN = 0; subjN < subjsN; subjN++) {
        GameSubj* pGS = gameSubjs.at(subjN);
        //behavior - apply rotation speed
        pGS->moveSubj();
        //prepare subject for rendering
        pGS->buildModelMatrix(pGS);
        //build MVP matrix for given subject
        mat4x4_mul(mMVP, mViewProjection, pGS->ownModelMatrix);
        //build Model-View (rotation) matrix for normals
        mat4x4_mul(mMV4x4, mainCamera.lookAtMatrix, (vec4*)pGS->ownCoords.getRotationMatrix());
        //convert to 3x3 matrix
        float mMV3x3[3][3];
        for (int y = 0; y < 3; y++)
            for (int x = 0; x < 3; x++)
                mMV3x3[y][x] = mMV4x4[y][x];
        //render subject
        for (int i = 0; i < pGS->djTotalN; i++) {
            DrawJob* pDJ = DrawJob::drawJobs.at(pGS->djStartN + i);
            pDJ->execute((float*)mMVP, *mMV3x3, dirToMainLight, uHalfVector, NULL);
        }
    }
    mySwapBuffers();
    return 1;
}

int TheGame::cleanUp() {
    int itemsN = gameSubjs.size();
    //delete all UISubjs
    for (int i = 0; i < itemsN; i++) {
        GameSubj* pGS = gameSubjs.at(i);
        delete pGS;
    }
    gameSubjs.clear();
    //clear all other classes
    Texture::cleanUp();
    Shader::cleanUp();
    DrawJob::cleanUp();
    return 1;
}
int TheGame::onScreenResize(int width, int height) {
    if (screenSize[0] == width && screenSize[1] == height)
        return 0;
    screenSize[0] = width;
    screenSize[1] = height;
    screenRatio = (float)width / (float)height;
    glViewport(0, 0, width, height);
    mylog(" screen size %d x %d\n", width, height);
    return 1;
}
int TheGame::run() {
    getReady();
    while (!bExitGame) {
        drawFrame();
    }
    cleanUp();
    return 1;
}


Теперь в функции ModelBuilder::buildBoxFace(…) у нас новые параметры TexCoords*. И новая функция ModelBuilder::groupApplyTexture2(…).

5. Заменим ModelBuilder.h код на:

#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 groupApplyTexture2(ModelBuilder* pMB, std::string applyTo, TexCoords* pTC, bool isNormakMap);
};


6. Заменим ModelBuilder.cpp еод на:

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

	groupApplyTexture2(pMB, "front", pTC, false);
	groupApplyTexture2(pMB, "front", pTC2nm, true); //for normal map

	//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::groupApplyTexture2(ModelBuilder* pMB, std::string applyTo, TexCoords* pTC, bool isNormakMap) {
	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 = pMB->vertices.size();
	for (int vN = pMB->pCurrentGroup->fromVertexN; vN < vertsN; vN++) {
		Vertex01* pVX = pMB->vertices.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 = pMB->pCurrentGroup->fromVertexN; vN < vertsN; vN++) {
		Vertex01* pVX = pMB->vertices.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(isNormakMap)
			pTuv = pVX->aTuv2;
		pTuv[0] = pTC->tuvTopLeft[0] + tuvRange[0] * xRate;
		pTuv[1] = pTC->tuvTopLeft[1] + tuvRange[1] * yRate;
	}
	return 1;
}


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

Отлично.


Теперь на

Андроиде

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


9. Под modeler добавим Existing Items

из C:\CPP\engine\modeler

  • TexCoords.cpp
  • TexCoords.h

Add.


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

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

Работает. Но, как обычно, не очень вписывается в экран.

Попробовал развернуть экран – еще и хуже:

Ну что ж, озадачимся этим в следующей главе…


Leave a Reply

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