2018-01-01 12:22:12 -08:00
|
|
|
// Copyright © 2008-2018 Pioneer Developers. See AUTHORS.txt for details
|
2013-03-27 14:33:37 -07:00
|
|
|
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
|
|
|
|
|
|
|
|
#include "libs.h"
|
|
|
|
#include "GeoPatchJobs.h"
|
|
|
|
#include "GeoSphere.h"
|
2014-02-04 12:53:09 -08:00
|
|
|
#include "GeoPatch.h"
|
2013-03-27 14:33:37 -07:00
|
|
|
#include "perlin.h"
|
|
|
|
#include "Pi.h"
|
|
|
|
#include "RefCounted.h"
|
|
|
|
|
2017-03-05 05:15:55 -08:00
|
|
|
inline void setColour(Color3ub &r, const vector3d &v) {
|
|
|
|
r.r=static_cast<unsigned char>(Clamp(v.x*255.0, 0.0, 255.0));
|
|
|
|
r.g=static_cast<unsigned char>(Clamp(v.y*255.0, 0.0, 255.0));
|
2013-03-27 14:33:37 -07:00
|
|
|
r.b=static_cast<unsigned char>(Clamp(v.z*255.0, 0.0, 255.0));
|
|
|
|
}
|
|
|
|
|
2016-10-12 10:53:23 -07:00
|
|
|
// in patch surface coords, [0,1]
|
|
|
|
inline vector3d GetSpherePoint(const vector3d &v0, const vector3d &v1, const vector3d &v2, const vector3d &v3, const double x, const double y) {
|
|
|
|
return (v0 + x*(1.0-y)*(v1-v0) + x*y*(v2-v0) + (1.0-x)*y*(v3-v0)).Normalized();
|
|
|
|
}
|
|
|
|
|
2013-03-27 15:33:58 -07:00
|
|
|
// ********************************************************************************
|
2013-03-27 14:33:37 -07:00
|
|
|
// Overloaded PureJob class to handle generating the mesh for each patch
|
2013-03-27 15:33:58 -07:00
|
|
|
// ********************************************************************************
|
2013-03-27 14:33:37 -07:00
|
|
|
|
2017-03-05 05:15:55 -08:00
|
|
|
// Generates full-detail vertices, and also non-edge normals and colors
|
|
|
|
void SinglePatchJob::GenerateMesh(double *heights, vector3f *normals, Color3ub *colors,
|
2013-04-01 04:40:23 -07:00
|
|
|
double *borderHeights, vector3d *borderVertexs,
|
|
|
|
const vector3d &v0,
|
|
|
|
const vector3d &v1,
|
|
|
|
const vector3d &v2,
|
|
|
|
const vector3d &v3,
|
|
|
|
const int edgeLen,
|
|
|
|
const double fracStep,
|
|
|
|
const Terrain *pTerrain) const
|
2013-03-27 14:33:37 -07:00
|
|
|
{
|
2016-10-12 04:46:17 -07:00
|
|
|
const int borderedEdgeLen = edgeLen+(BORDER_SIZE*2);
|
2013-03-27 14:33:37 -07:00
|
|
|
const int numBorderedVerts = borderedEdgeLen*borderedEdgeLen;
|
|
|
|
|
|
|
|
// generate heights plus a 1 unit border
|
2013-04-01 04:40:23 -07:00
|
|
|
double *bhts = borderHeights;
|
|
|
|
vector3d *vrts = borderVertexs;
|
2016-10-12 04:46:17 -07:00
|
|
|
for (int y=-BORDER_SIZE; y<borderedEdgeLen-BORDER_SIZE; y++) {
|
2013-03-27 14:33:37 -07:00
|
|
|
const double yfrac = double(y) * fracStep;
|
2016-10-12 04:46:17 -07:00
|
|
|
for (int x=-BORDER_SIZE; x<borderedEdgeLen-BORDER_SIZE; x++) {
|
2013-03-27 14:33:37 -07:00
|
|
|
const double xfrac = double(x) * fracStep;
|
|
|
|
const vector3d p = GetSpherePoint(v0, v1, v2, v3, xfrac, yfrac);
|
|
|
|
const double height = pTerrain->GetHeight(p);
|
2013-09-19 05:19:25 -07:00
|
|
|
assert(height >= 0.0f && height <= 1.0f);
|
2013-03-27 14:33:37 -07:00
|
|
|
*(bhts++) = height;
|
|
|
|
*(vrts++) = p * (height + 1.0);
|
|
|
|
}
|
|
|
|
}
|
2013-04-01 04:40:23 -07:00
|
|
|
assert(bhts==&borderHeights[numBorderedVerts]);
|
2013-03-27 14:33:37 -07:00
|
|
|
|
|
|
|
// Generate normals & colors for non-edge vertices since they never change
|
|
|
|
Color3ub *col = colors;
|
|
|
|
vector3f *nrm = normals;
|
|
|
|
double *hts = heights;
|
2013-04-01 04:40:23 -07:00
|
|
|
vrts = borderVertexs;
|
2016-10-12 04:46:17 -07:00
|
|
|
for (int y=BORDER_SIZE; y<borderedEdgeLen-BORDER_SIZE; y++) {
|
|
|
|
for (int x=BORDER_SIZE; x<borderedEdgeLen-BORDER_SIZE; x++) {
|
2013-03-27 14:33:37 -07:00
|
|
|
// height
|
2013-04-01 04:40:23 -07:00
|
|
|
const double height = borderHeights[x + y*borderedEdgeLen];
|
2013-03-27 14:33:37 -07:00
|
|
|
assert(hts!=&heights[edgeLen*edgeLen]);
|
|
|
|
*(hts++) = height;
|
|
|
|
|
|
|
|
// normal
|
2016-10-12 10:53:23 -07:00
|
|
|
const vector3d &x1 = vrts[(x-1) + y*borderedEdgeLen];
|
|
|
|
const vector3d &x2 = vrts[(x+1) + y*borderedEdgeLen];
|
|
|
|
const vector3d &y1 = vrts[x + (y-1)*borderedEdgeLen];
|
|
|
|
const vector3d &y2 = vrts[x + (y+1)*borderedEdgeLen];
|
2013-03-27 14:33:37 -07:00
|
|
|
const vector3d n = ((x2-x1).Cross(y2-y1)).Normalized();
|
|
|
|
assert(nrm!=&normals[edgeLen*edgeLen]);
|
|
|
|
*(nrm++) = vector3f(n);
|
|
|
|
|
|
|
|
// color
|
2016-10-12 04:46:17 -07:00
|
|
|
const vector3d p = GetSpherePoint(v0, v1, v2, v3, (x-BORDER_SIZE)*fracStep, (y-BORDER_SIZE)*fracStep);
|
2013-03-27 14:33:37 -07:00
|
|
|
setColour(*col, pTerrain->GetColor(p, height, n));
|
|
|
|
assert(col!=&colors[edgeLen*edgeLen]);
|
|
|
|
++col;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(hts==&heights[edgeLen*edgeLen]);
|
|
|
|
assert(nrm==&normals[edgeLen*edgeLen]);
|
|
|
|
assert(col==&colors[edgeLen*edgeLen]);
|
|
|
|
}
|
|
|
|
|
2013-03-27 15:33:58 -07:00
|
|
|
// ********************************************************************************
|
2013-03-27 14:33:37 -07:00
|
|
|
// Overloaded PureJob class to handle generating the mesh for each patch
|
2013-03-27 15:33:58 -07:00
|
|
|
// ********************************************************************************
|
2013-04-23 15:46:32 -07:00
|
|
|
void SinglePatchJob::OnFinish() // runs in primary thread of the context
|
2013-03-27 14:33:37 -07:00
|
|
|
{
|
2014-01-05 07:22:59 -08:00
|
|
|
GeoSphere::OnAddSingleSplitResult( mData->sysPath, mpResults );
|
2014-02-04 12:53:09 -08:00
|
|
|
mpResults = nullptr;
|
2013-04-23 15:46:32 -07:00
|
|
|
BasePatchJob::OnFinish();
|
2013-03-27 14:33:37 -07:00
|
|
|
}
|
|
|
|
|
2013-04-23 15:46:32 -07:00
|
|
|
void SinglePatchJob::OnRun() // RUNS IN ANOTHER THREAD!! MUST BE THREAD SAFE!
|
2013-03-27 14:33:37 -07:00
|
|
|
{
|
2013-04-23 15:46:32 -07:00
|
|
|
BasePatchJob::OnRun();
|
|
|
|
|
2013-10-29 04:44:49 -07:00
|
|
|
const SSingleSplitRequest &srd = *mData;
|
2013-03-27 14:33:37 -07:00
|
|
|
|
|
|
|
// fill out the data
|
2013-10-29 04:44:49 -07:00
|
|
|
GenerateMesh(srd.heights, srd.normals, srd.colors, srd.borderHeights.get(), srd.borderVertexs.get(),
|
2017-03-05 05:15:55 -08:00
|
|
|
srd.v0, srd.v1, srd.v2, srd.v3,
|
2013-04-24 14:42:43 -07:00
|
|
|
srd.edgeLen, srd.fracStep, srd.pTerrain.Get());
|
2013-03-27 14:33:37 -07:00
|
|
|
// add this patches data
|
|
|
|
SSingleSplitResult *sr = new SSingleSplitResult(srd.patchID.GetPatchFaceIdx(), srd.depth);
|
2017-03-05 05:15:55 -08:00
|
|
|
sr->addResult(srd.heights, srd.normals, srd.colors,
|
|
|
|
srd.v0, srd.v1, srd.v2, srd.v3,
|
2013-03-27 14:33:37 -07:00
|
|
|
srd.patchID.NextPatchID(srd.depth+1, 0));
|
|
|
|
// store the result
|
|
|
|
mpResults = sr;
|
|
|
|
}
|
|
|
|
|
2014-02-04 12:53:09 -08:00
|
|
|
SinglePatchJob::~SinglePatchJob()
|
|
|
|
{
|
|
|
|
if(mpResults) {
|
|
|
|
mpResults->OnCancel();
|
|
|
|
delete mpResults;
|
|
|
|
mpResults = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-27 15:33:58 -07:00
|
|
|
// ********************************************************************************
|
2013-03-27 14:33:37 -07:00
|
|
|
// Overloaded PureJob class to handle generating the mesh for each patch
|
2013-03-27 15:33:58 -07:00
|
|
|
// ********************************************************************************
|
2013-04-23 15:46:32 -07:00
|
|
|
void QuadPatchJob::OnFinish() // runs in primary thread of the context
|
2013-03-27 14:33:37 -07:00
|
|
|
{
|
2014-01-05 07:22:59 -08:00
|
|
|
GeoSphere::OnAddQuadSplitResult( mData->sysPath, mpResults );
|
2014-02-04 12:53:09 -08:00
|
|
|
mpResults = nullptr;
|
2013-04-23 15:46:32 -07:00
|
|
|
BasePatchJob::OnFinish();
|
2013-03-27 14:33:37 -07:00
|
|
|
}
|
|
|
|
|
2013-04-23 15:46:32 -07:00
|
|
|
void QuadPatchJob::OnRun() // RUNS IN ANOTHER THREAD!! MUST BE THREAD SAFE!
|
2013-03-27 14:33:37 -07:00
|
|
|
{
|
2013-04-23 15:46:32 -07:00
|
|
|
BasePatchJob::OnRun();
|
|
|
|
|
2013-10-29 04:44:49 -07:00
|
|
|
const SQuadSplitRequest &srd = *mData;
|
2016-10-12 10:53:23 -07:00
|
|
|
|
|
|
|
GenerateBorderedData(srd.borderHeights.get(), srd.borderVertexs.get(),
|
|
|
|
srd.v0, srd.v1, srd.v2, srd.v3,
|
|
|
|
srd.edgeLen, srd.fracStep, srd.pTerrain.Get());
|
|
|
|
|
2013-03-27 14:33:37 -07:00
|
|
|
const vector3d v01 = (srd.v0+srd.v1).Normalized();
|
|
|
|
const vector3d v12 = (srd.v1+srd.v2).Normalized();
|
|
|
|
const vector3d v23 = (srd.v2+srd.v3).Normalized();
|
|
|
|
const vector3d v30 = (srd.v3+srd.v0).Normalized();
|
|
|
|
const vector3d cn = (srd.centroid).Normalized();
|
|
|
|
const vector3d vecs[4][4] = {
|
|
|
|
{srd.v0, v01, cn, v30},
|
|
|
|
{v01, srd.v1, v12, cn},
|
|
|
|
{cn, v12, srd.v2, v23},
|
|
|
|
{v30, cn, v23, srd.v3}
|
|
|
|
};
|
|
|
|
|
2016-10-13 06:16:23 -07:00
|
|
|
const int borderedEdgeLen = (srd.edgeLen*2)+(BORDER_SIZE*2)-1;
|
2016-10-12 10:53:23 -07:00
|
|
|
const int offxy[4][2] = {
|
|
|
|
{0,0},
|
2016-10-13 06:16:23 -07:00
|
|
|
{srd.edgeLen-1,0},
|
|
|
|
{srd.edgeLen-1,srd.edgeLen-1},
|
|
|
|
{0,srd.edgeLen-1}
|
2016-10-12 10:53:23 -07:00
|
|
|
};
|
|
|
|
|
2013-03-27 14:33:37 -07:00
|
|
|
SQuadSplitResult *sr = new SQuadSplitResult(srd.patchID.GetPatchFaceIdx(), srd.depth);
|
|
|
|
for (int i=0; i<4; i++)
|
|
|
|
{
|
|
|
|
// fill out the data
|
2016-10-12 10:53:23 -07:00
|
|
|
GenerateSubPatchData(srd.heights[i], srd.normals[i], srd.colors[i], srd.borderHeights.get(), srd.borderVertexs.get(),
|
2017-03-05 05:15:55 -08:00
|
|
|
vecs[i][0], vecs[i][1], vecs[i][2], vecs[i][3],
|
|
|
|
srd.edgeLen, offxy[i][0], offxy[i][1],
|
2016-10-12 10:53:23 -07:00
|
|
|
borderedEdgeLen, srd.fracStep, srd.pTerrain.Get());
|
|
|
|
|
2013-03-27 14:33:37 -07:00
|
|
|
// add this patches data
|
2017-03-05 05:15:55 -08:00
|
|
|
sr->addResult(i, srd.heights[i], srd.normals[i], srd.colors[i],
|
|
|
|
vecs[i][0], vecs[i][1], vecs[i][2], vecs[i][3],
|
2013-03-27 14:33:37 -07:00
|
|
|
srd.patchID.NextPatchID(srd.depth+1, i));
|
|
|
|
}
|
|
|
|
mpResults = sr;
|
|
|
|
}
|
2014-02-04 12:53:09 -08:00
|
|
|
|
|
|
|
QuadPatchJob::~QuadPatchJob()
|
|
|
|
{
|
|
|
|
if(mpResults) {
|
|
|
|
mpResults->OnCancel();
|
|
|
|
delete mpResults;
|
|
|
|
mpResults = NULL;
|
|
|
|
}
|
|
|
|
}
|
2016-10-13 09:24:53 -07:00
|
|
|
|
2017-03-05 05:15:55 -08:00
|
|
|
// Generates full-detail vertices, and also non-edge normals and colors
|
2016-10-13 09:24:53 -07:00
|
|
|
void QuadPatchJob::GenerateBorderedData(
|
|
|
|
double *borderHeights, vector3d *borderVertexs,
|
|
|
|
const vector3d &v0,
|
|
|
|
const vector3d &v1,
|
|
|
|
const vector3d &v2,
|
|
|
|
const vector3d &v3,
|
|
|
|
const int edgeLen,
|
|
|
|
const double fracStep,
|
|
|
|
const Terrain *pTerrain) const
|
|
|
|
{
|
|
|
|
const int borderedEdgeLen = (edgeLen * 2) + (BORDER_SIZE * 2) - 1;
|
|
|
|
const int numBorderedVerts = borderedEdgeLen*borderedEdgeLen;
|
|
|
|
|
|
|
|
// generate heights plus a N=BORDER_SIZE unit border
|
|
|
|
double *bhts = borderHeights;
|
|
|
|
vector3d *vrts = borderVertexs;
|
|
|
|
for ( int y = -BORDER_SIZE; y < (borderedEdgeLen - BORDER_SIZE); y++ ) {
|
|
|
|
const double yfrac = double(y) * (fracStep*0.5);
|
|
|
|
for ( int x = -BORDER_SIZE; x < (borderedEdgeLen - BORDER_SIZE); x++ ) {
|
|
|
|
const double xfrac = double(x) * (fracStep*0.5);
|
|
|
|
const vector3d p = GetSpherePoint(v0, v1, v2, v3, xfrac, yfrac);
|
|
|
|
const double height = pTerrain->GetHeight(p);
|
|
|
|
assert(height >= 0.0f && height <= 1.0f);
|
|
|
|
*(bhts++) = height;
|
|
|
|
*(vrts++) = p * (height + 1.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(bhts == &borderHeights[numBorderedVerts]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void QuadPatchJob::GenerateSubPatchData(
|
2017-03-05 05:15:55 -08:00
|
|
|
double *heights, vector3f *normals, Color3ub *colors,
|
2016-10-13 09:24:53 -07:00
|
|
|
double *borderHeights, vector3d *borderVertexs,
|
|
|
|
const vector3d &v0,
|
|
|
|
const vector3d &v1,
|
|
|
|
const vector3d &v2,
|
|
|
|
const vector3d &v3,
|
|
|
|
const int edgeLen,
|
2017-03-05 05:15:55 -08:00
|
|
|
const int xoff,
|
2016-10-13 09:24:53 -07:00
|
|
|
const int yoff,
|
|
|
|
const int borderedEdgeLen,
|
|
|
|
const double fracStep,
|
|
|
|
const Terrain *pTerrain) const
|
|
|
|
{
|
|
|
|
// Generate normals & colors for vertices
|
|
|
|
vector3d *vrts = borderVertexs;
|
|
|
|
Color3ub *col = colors;
|
|
|
|
vector3f *nrm = normals;
|
|
|
|
double *hts = heights;
|
|
|
|
|
|
|
|
// step over the small square
|
|
|
|
for ( int y = 0; y < edgeLen; y++ ) {
|
|
|
|
const int by = (y + BORDER_SIZE) + yoff;
|
|
|
|
for ( int x = 0; x < edgeLen; x++ ) {
|
|
|
|
const int bx = (x + BORDER_SIZE) + xoff;
|
|
|
|
|
|
|
|
// height
|
|
|
|
const double height = borderHeights[bx + (by * borderedEdgeLen)];
|
|
|
|
assert(hts != &heights[edgeLen * edgeLen]);
|
|
|
|
*(hts++) = height;
|
|
|
|
|
|
|
|
// normal
|
|
|
|
const vector3d &x1 = vrts[(bx - 1) + (by * borderedEdgeLen)];
|
|
|
|
const vector3d &x2 = vrts[(bx + 1) + (by * borderedEdgeLen)];
|
|
|
|
const vector3d &y1 = vrts[bx + ((by - 1) * borderedEdgeLen)];
|
|
|
|
const vector3d &y2 = vrts[bx + ((by + 1) * borderedEdgeLen)];
|
|
|
|
const vector3d n = ((x2 - x1).Cross(y2 - y1)).Normalized();
|
|
|
|
assert(nrm != &normals[edgeLen * edgeLen]);
|
|
|
|
*(nrm++) = vector3f(n);
|
|
|
|
|
|
|
|
// color
|
|
|
|
const vector3d p = GetSpherePoint(v0, v1, v2, v3, x * fracStep, y * fracStep);
|
|
|
|
setColour(*col, pTerrain->GetColor(p, height, n));
|
|
|
|
assert(col != &colors[edgeLen * edgeLen]);
|
|
|
|
++col;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(hts == &heights[edgeLen*edgeLen]);
|
|
|
|
assert(nrm == &normals[edgeLen*edgeLen]);
|
|
|
|
assert(col == &colors[edgeLen*edgeLen]);
|
|
|
|
}
|