pioneer/src/GasGiantJobs.cpp

281 lines
9.0 KiB
C++

// Copyright © 2008-2015 Pioneer Developers. See AUTHORS.txt for details
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
#include "GasGiantJobs.h"
#include "GasGiant.h"
#include "Pi.h"
#include "RefCounted.h"
#include "graphics/Frustum.h"
#include "graphics/Graphics.h"
#include "graphics/Material.h"
#include "graphics/Renderer.h"
#include "graphics/Texture.h"
#include "graphics/TextureBuilder.h"
#include "graphics/Types.h"
#include "graphics/VertexArray.h"
#include "graphics/opengl/GenGasGiantColourMaterial.h"
#include "perlin.h"
#include "vcacheopt/vcacheopt.h"
#include <algorithm>
#include <deque>
namespace GasGiantJobs {
static const vector3d s_patchFaces[NUM_PATCHES][4] = {
{ p5, p1, p4, p8 }, // +x
{ p2, p6, p7, p3 }, // -x
{ p2, p1, p5, p6 }, // +y
{ p7, p8, p4, p3 }, // -y
{ p6, p5, p8, p7 }, // +z - NB: these are actually reversed!
{ p1, p2, p3, p4 } // -z
};
const vector3d &GetPatchFaces(const Uint32 patch, const Uint32 face) { return s_patchFaces[patch][face]; }
STextureFaceRequest::STextureFaceRequest(const vector3d *v_, const SystemPath &sysPath_, const Sint32 face_, const Sint32 uvDIMs_, Terrain *pTerrain_) :
corners(v_),
sysPath(sysPath_),
face(face_),
uvDIMs(uvDIMs_),
pTerrain(pTerrain_)
{
colors = new Color[NumTexels()];
}
// RUNS IN ANOTHER THREAD!! MUST BE THREAD SAFE!
// Use only data local to this object
void STextureFaceRequest::OnRun()
{
PROFILE_SCOPED()
assert(corners != nullptr);
double fracStep = 1.0 / double(UVDims() - 1);
for (Sint32 v = 0; v < UVDims(); v++) {
for (Sint32 u = 0; u < UVDims(); u++) {
// where in this row & colum are we now.
const double ustep = double(u) * fracStep;
const double vstep = double(v) * fracStep;
// get point on the surface of the sphere
const vector3d p = GetSpherePoint(ustep, vstep);
// get colour using `p`
const vector3d colour = pTerrain->GetColor(p, 0.0, p);
// convert to ubyte and store
Color *col = colors + (u + (v * UVDims()));
col[0].r = Uint8(colour.x * 255.0);
col[0].g = Uint8(colour.y * 255.0);
col[0].b = Uint8(colour.z * 255.0);
col[0].a = 255;
}
}
}
// ********************************************************************************
// Overloaded PureJob class to handle generating the mesh for each patch
// ********************************************************************************
SingleTextureFaceJob::~SingleTextureFaceJob()
{
PROFILE_SCOPED()
if (mpResults) {
mpResults->OnCancel();
delete mpResults;
mpResults = nullptr;
}
}
void SingleTextureFaceJob::OnRun() // RUNS IN ANOTHER THREAD!! MUST BE THREAD SAFE!
{
PROFILE_SCOPED()
mData->OnRun();
// add this patches data
STextureFaceResult *sr = new STextureFaceResult(mData->Face());
sr->addResult(mData->Colors(), mData->UVDims());
// store the result
mpResults = sr;
}
void SingleTextureFaceJob::OnFinish() // runs in primary thread of the context
{
PROFILE_SCOPED()
GasGiant::OnAddTextureFaceResult(mData->SysPath(), mpResults);
mpResults = nullptr;
}
// ********************************************************************************
GenFaceQuad::GenFaceQuad(Graphics::Renderer *r, const vector2f &size, Graphics::RenderState *state, const Uint32 GGQuality)
{
PROFILE_SCOPED()
assert(state);
m_renderState = state;
Graphics::MaterialDescriptor desc;
desc.effect = Graphics::EFFECT_GEN_GASGIANT_TEXTURE;
desc.quality = GGQuality;
desc.textures = 3;
m_material.reset(r->CreateMaterial(desc));
// setup noise textures
m_material->texture0 = Graphics::TextureBuilder::Raw("textures/permTexture.png").GetOrCreateTexture(Pi::renderer, "noise");
m_material->texture1 = Graphics::TextureBuilder::Raw("textures/gradTexture.png").GetOrCreateTexture(Pi::renderer, "noise");
// pick the correct colour basis texture for the planet
switch (0x0000FFFF & GGQuality) {
case Graphics::OGL::GEN_JUPITER_TEXTURE:
m_material->texture2 = Graphics::TextureBuilder::Raw("textures/gasgiants/jupiterramp.png").GetOrCreateTexture(Pi::renderer, "gasgiant");
break;
case Graphics::OGL::GEN_SATURN_TEXTURE:
m_material->texture2 = Graphics::TextureBuilder::Raw("textures/gasgiants/saturnramp.png").GetOrCreateTexture(Pi::renderer, "gasgiant");
break;
case Graphics::OGL::GEN_SATURN2_TEXTURE:
m_material->texture2 = Graphics::TextureBuilder::Raw("textures/gasgiants/saturn2ramp.png").GetOrCreateTexture(Pi::renderer, "gasgiant");
break;
case Graphics::OGL::GEN_NEPTUNE_TEXTURE:
m_material->texture2 = Graphics::TextureBuilder::Raw("textures/gasgiants/neptuneramp.png").GetOrCreateTexture(Pi::renderer, "gasgiant");
break;
case Graphics::OGL::GEN_NEPTUNE2_TEXTURE:
m_material->texture2 = Graphics::TextureBuilder::Raw("textures/gasgiants/neptune2ramp.png").GetOrCreateTexture(Pi::renderer, "gasgiant");
break;
case Graphics::OGL::GEN_URANUS_TEXTURE:
m_material->texture2 = Graphics::TextureBuilder::Raw("textures/gasgiants/uranusramp.png").GetOrCreateTexture(Pi::renderer, "gasgiant");
break;
}
// these might need to be reversed
const vector2f &texSize(size);
Graphics::VertexArray vertices(Graphics::ATTRIB_POSITION | Graphics::ATTRIB_UV0);
vertices.Add(vector3f(0.0f, 0.0f, 0.0f), vector2f(0.0f, texSize.y));
vertices.Add(vector3f(0.0f, size.y, 0.0f), vector2f(0.0f, 0.0f));
vertices.Add(vector3f(size.x, 0.0f, 0.0f), vector2f(texSize.x, texSize.y));
vertices.Add(vector3f(size.x, size.y, 0.0f), vector2f(texSize.x, 0.0f));
//Create vtx & index buffers and copy data
Graphics::VertexBufferDesc vbd;
vbd.attrib[0].semantic = Graphics::ATTRIB_POSITION;
vbd.attrib[0].format = Graphics::ATTRIB_FORMAT_FLOAT3;
vbd.attrib[1].semantic = Graphics::ATTRIB_UV0;
vbd.attrib[1].format = Graphics::ATTRIB_FORMAT_FLOAT2;
vbd.numVertices = vertices.GetNumVerts();
vbd.usage = Graphics::BUFFER_USAGE_STATIC;
m_vertexBuffer.reset(r->CreateVertexBuffer(vbd));
m_vertexBuffer->Populate(vertices);
}
void GenFaceQuad::Draw(Graphics::Renderer *r)
{
PROFILE_SCOPED()
r->DrawBuffer(m_vertexBuffer.get(), m_renderState, m_material.get(), Graphics::TRIANGLE_STRIP);
}
// ********************************************************************************
SGPUGenRequest::SGPUGenRequest(const SystemPath &sysPath_, const Sint32 uvDIMs_, Terrain *pTerrain_, const float planetRadius_, const float hueAdjust_, GenFaceQuad *pQuad_, Graphics::Texture *pTex_) :
m_texture(pTex_),
sysPath(sysPath_),
uvDIMs(uvDIMs_),
pTerrain(pTerrain_),
planetRadius(planetRadius_),
hueAdjust(hueAdjust_),
pQuad(pQuad_)
{
PROFILE_SCOPED()
assert(m_texture.Valid());
}
void SGPUGenRequest::SetupMaterialParams(const int face)
{
PROFILE_SCOPED()
m_specialParams.v = &GetPatchFaces(face, 0);
m_specialParams.fracStep = 1.0f / float(uvDIMs);
m_specialParams.planetRadius = planetRadius;
m_specialParams.time = 0.0f;
for (Uint32 i = 0; i < 3; i++) {
m_specialParams.frequency[i] = float(pTerrain->GetFracDef(i).frequency);
}
m_specialParams.hueAdjust = hueAdjust;
pQuad->GetMaterial()->specialParameter0 = &m_specialParams;
}
// ********************************************************************************
void SGPUGenResult::addResult(Graphics::Texture *t_, Sint32 uvDims_)
{
PROFILE_SCOPED()
mData = SGPUGenData(t_, uvDims_);
}
void SGPUGenResult::OnCancel()
{
if (mData.texture) {
mData.texture.Reset();
}
}
// ********************************************************************************
// Overloaded JobGPU class to handle generating the mesh for each patch
// ********************************************************************************
SingleGPUGenJob::SingleGPUGenJob(SGPUGenRequest *data) :
mData(data),
mpResults(nullptr)
{ /* empty */
}
SingleGPUGenJob::~SingleGPUGenJob()
{
PROFILE_SCOPED()
if (mpResults) {
mpResults->OnCancel();
delete mpResults;
mpResults = nullptr;
}
}
void SingleGPUGenJob::OnRun() // Runs in the main thread, may trash the GPU state
{
PROFILE_SCOPED()
Graphics::Renderer::StateTicket ticket(Pi::renderer);
// enter ortho
Pi::renderer->SetViewport({ 0, 0, mData->UVDims(), mData->UVDims() });
Pi::renderer->SetOrthographicProjection(0, mData->UVDims(), mData->UVDims(), 0, -1, 1);
Pi::renderer->SetTransform(matrix4x4f::Identity());
GasGiant::BeginRenderTarget();
for (Uint32 iFace = 0; iFace < NUM_PATCHES; iFace++) {
// render the scene
GasGiant::SetRenderTargetCubemap(iFace, mData->Texture());
Pi::renderer->BeginFrame();
// draw to the texture here
mData->SetupMaterialParams(iFace);
mData->Quad()->Draw(Pi::renderer);
Pi::renderer->EndFrame();
GasGiant::SetRenderTargetCubemap(iFace, nullptr);
}
GasGiant::EndRenderTarget();
// add this patches data
SGPUGenResult *sr = new SGPUGenResult();
sr->addResult(mData->Texture(), mData->UVDims());
// store the result
mpResults = sr;
// leave ortho when ticket is destroyed
}
void SingleGPUGenJob::OnFinish() // runs in primary thread of the context
{
PROFILE_SCOPED()
GasGiant::OnAddGPUGenResult(mData->SysPath(), mpResults);
mpResults = nullptr;
}
} // namespace GasGiantJobs