mirror of
https://github.com/overte-org/overte.git
synced 2025-08-05 17:37:22 +02:00
325 lines
No EOL
10 KiB
C++
325 lines
No EOL
10 KiB
C++
#ifdef Q_OS_WIN
|
|
|
|
//
|
|
// Created by Bradley Austin Davis on 2015/05/29
|
|
// Copyright 2015 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
#include "OglplusHelpers.h"
|
|
|
|
using namespace oglplus;
|
|
using namespace oglplus::shapes;
|
|
|
|
static const char * SIMPLE_TEXTURED_VS = R"VS(#version 410 core
|
|
#pragma line __LINE__
|
|
|
|
uniform mat4 Projection = mat4(1);
|
|
uniform mat4 ModelView = mat4(1);
|
|
|
|
layout(location = 0) in vec3 Position;
|
|
layout(location = 1) in vec2 TexCoord;
|
|
|
|
out vec2 vTexCoord;
|
|
|
|
void main() {
|
|
gl_Position = Projection * ModelView * vec4(Position, 1);
|
|
vTexCoord = TexCoord;
|
|
}
|
|
|
|
)VS";
|
|
|
|
static const char * SIMPLE_TEXTURED_FS = R"FS(#version 410 core
|
|
#pragma line __LINE__
|
|
|
|
uniform sampler2D sampler;
|
|
uniform float Alpha = 1.0;
|
|
|
|
in vec2 vTexCoord;
|
|
out vec4 vFragColor;
|
|
|
|
void main() {
|
|
vec4 c = texture(sampler, vTexCoord);
|
|
c.a = min(Alpha, c.a);
|
|
vFragColor = c;
|
|
}
|
|
|
|
)FS";
|
|
|
|
|
|
ProgramPtr loadDefaultShader() {
|
|
ProgramPtr result;
|
|
compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_FS);
|
|
return result;
|
|
}
|
|
|
|
void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs) {
|
|
using namespace oglplus;
|
|
try {
|
|
result = ProgramPtr(new Program());
|
|
// attach the shaders to the program
|
|
result->AttachShader(
|
|
VertexShader()
|
|
.Source(GLSLSource(vs))
|
|
.Compile()
|
|
);
|
|
result->AttachShader(
|
|
FragmentShader()
|
|
.Source(GLSLSource(fs))
|
|
.Compile()
|
|
);
|
|
result->Link();
|
|
} catch (ProgramBuildError & err) {
|
|
Q_UNUSED(err);
|
|
Q_ASSERT_X(false, "compileProgram", "Failed to build shader program");
|
|
qFatal((const char*)err.Message);
|
|
result.reset();
|
|
}
|
|
}
|
|
|
|
|
|
ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect) {
|
|
using namespace oglplus;
|
|
Vec3f a(1, 0, 0);
|
|
Vec3f b(0, 1, 0);
|
|
if (aspect > 1) {
|
|
b[1] /= aspect;
|
|
} else {
|
|
a[0] *= aspect;
|
|
}
|
|
return ShapeWrapperPtr(
|
|
new shapes::ShapeWrapper({ "Position", "TexCoord" }, shapes::Plane(a, b), *program)
|
|
);
|
|
}
|
|
|
|
// Return a point's cartesian coordinates on a sphere from pitch and yaw
|
|
static glm::vec3 getPoint(float yaw, float pitch) {
|
|
return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)),
|
|
glm::sin(-pitch),
|
|
glm::cos(-pitch) * (-glm::cos(yaw)));
|
|
}
|
|
|
|
|
|
class SphereSection : public DrawingInstructionWriter, public DrawMode {
|
|
public:
|
|
using IndexArray = std::vector<GLuint>;
|
|
using PosArray = std::vector<float>;
|
|
using TexArray = std::vector<float>;
|
|
/// The type of the index container returned by Indices()
|
|
// vertex positions
|
|
PosArray _pos_data;
|
|
// vertex tex coords
|
|
TexArray _tex_data;
|
|
IndexArray _idx_data;
|
|
unsigned int _prim_count{ 0 };
|
|
|
|
public:
|
|
SphereSection(
|
|
const float fov,
|
|
const float aspectRatio,
|
|
const int slices_,
|
|
const int stacks_) {
|
|
//UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm
|
|
if (fov >= PI) {
|
|
qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues";
|
|
}
|
|
|
|
int gridSize = std::max(slices_, stacks_);
|
|
int gridSizeLog2 = 1;
|
|
while (1 << gridSizeLog2 < gridSize) {
|
|
++gridSizeLog2;
|
|
}
|
|
gridSize = (1 << gridSizeLog2) + 1;
|
|
// Compute number of vertices needed
|
|
int vertices = gridSize * gridSize;
|
|
_pos_data.resize(vertices * 3);
|
|
_tex_data.resize(vertices * 2);
|
|
|
|
// Compute vertices positions and texture UV coordinate
|
|
for (int y = 0; y <= gridSize; ++y) {
|
|
for (int x = 0; x <= gridSize; ++x) {
|
|
|
|
}
|
|
}
|
|
for (int i = 0; i < gridSize; i++) {
|
|
float stacksRatio = (float)i / (float)(gridSize - 1); // First stack is 0.0f, last stack is 1.0f
|
|
// abs(theta) <= fov / 2.0f
|
|
float pitch = -fov * (stacksRatio - 0.5f);
|
|
for (int j = 0; j < gridSize; j++) {
|
|
float slicesRatio = (float)j / (float)(gridSize - 1); // First slice is 0.0f, last slice is 1.0f
|
|
// abs(phi) <= fov * aspectRatio / 2.0f
|
|
float yaw = -fov * aspectRatio * (slicesRatio - 0.5f);
|
|
int vertex = i * gridSize + j;
|
|
int posOffset = vertex * 3;
|
|
int texOffset = vertex * 2;
|
|
vec3 pos = getPoint(yaw, pitch);
|
|
_pos_data[posOffset] = pos.x;
|
|
_pos_data[posOffset + 1] = pos.y;
|
|
_pos_data[posOffset + 2] = pos.z;
|
|
_tex_data[texOffset] = slicesRatio;
|
|
_tex_data[texOffset + 1] = stacksRatio;
|
|
}
|
|
} // done with vertices
|
|
|
|
int rowLen = gridSize;
|
|
|
|
// gridsize now refers to the triangles, not the vertices, so reduce by one
|
|
// or die by fencepost error http://en.wikipedia.org/wiki/Off-by-one_error
|
|
--gridSize;
|
|
int quads = gridSize * gridSize;
|
|
for (int t = 0; t < quads; ++t) {
|
|
int x =
|
|
((t & 0x0001) >> 0) |
|
|
((t & 0x0004) >> 1) |
|
|
((t & 0x0010) >> 2) |
|
|
((t & 0x0040) >> 3) |
|
|
((t & 0x0100) >> 4) |
|
|
((t & 0x0400) >> 5) |
|
|
((t & 0x1000) >> 6) |
|
|
((t & 0x4000) >> 7);
|
|
int y =
|
|
((t & 0x0002) >> 1) |
|
|
((t & 0x0008) >> 2) |
|
|
((t & 0x0020) >> 3) |
|
|
((t & 0x0080) >> 4) |
|
|
((t & 0x0200) >> 5) |
|
|
((t & 0x0800) >> 6) |
|
|
((t & 0x2000) >> 7) |
|
|
((t & 0x8000) >> 8);
|
|
int i = x * (rowLen) + y;
|
|
|
|
_idx_data.push_back(i);
|
|
_idx_data.push_back(i + 1);
|
|
_idx_data.push_back(i + rowLen + 1);
|
|
|
|
_idx_data.push_back(i + rowLen + 1);
|
|
_idx_data.push_back(i + rowLen);
|
|
_idx_data.push_back(i);
|
|
}
|
|
_prim_count = quads * 2;
|
|
}
|
|
|
|
/// Returns the winding direction of faces
|
|
FaceOrientation FaceWinding(void) const {
|
|
return FaceOrientation::CCW;
|
|
}
|
|
|
|
typedef GLuint(SphereSection::*VertexAttribFunc)(std::vector<GLfloat>&) const;
|
|
|
|
/// Makes the vertex positions and returns the number of values per vertex
|
|
template <typename T>
|
|
GLuint Positions(std::vector<T>& dest) const {
|
|
dest.clear();
|
|
dest.insert(dest.begin(), _pos_data.begin(), _pos_data.end());
|
|
return 3;
|
|
}
|
|
|
|
/// Makes the vertex normals and returns the number of values per vertex
|
|
template <typename T>
|
|
GLuint Normals(std::vector<T>& dest) const {
|
|
dest.clear();
|
|
return 3;
|
|
}
|
|
|
|
/// Makes the vertex tangents and returns the number of values per vertex
|
|
template <typename T>
|
|
GLuint Tangents(std::vector<T>& dest) const {
|
|
dest.clear();
|
|
return 3;
|
|
}
|
|
|
|
/// Makes the vertex bi-tangents and returns the number of values per vertex
|
|
template <typename T>
|
|
GLuint Bitangents(std::vector<T>& dest) const {
|
|
dest.clear();
|
|
return 3;
|
|
}
|
|
|
|
/// Makes the texture coordinates returns the number of values per vertex
|
|
template <typename T>
|
|
GLuint TexCoordinates(std::vector<T>& dest) const {
|
|
dest.clear();
|
|
dest.insert(dest.begin(), _tex_data.begin(), _tex_data.end());
|
|
return 2;
|
|
}
|
|
|
|
typedef VertexAttribsInfo<
|
|
SphereSection,
|
|
std::tuple<
|
|
VertexPositionsTag,
|
|
VertexNormalsTag,
|
|
VertexTangentsTag,
|
|
VertexBitangentsTag,
|
|
VertexTexCoordinatesTag
|
|
>
|
|
> VertexAttribs;
|
|
|
|
Spheref MakeBoundingSphere(void) const {
|
|
GLfloat min_x = _pos_data[3], max_x = _pos_data[3];
|
|
GLfloat min_y = _pos_data[4], max_y = _pos_data[4];
|
|
GLfloat min_z = _pos_data[5], max_z = _pos_data[5];
|
|
for (std::size_t v = 0, vn = _pos_data.size() / 3; v != vn; ++v) {
|
|
GLfloat x = _pos_data[v * 3 + 0];
|
|
GLfloat y = _pos_data[v * 3 + 1];
|
|
GLfloat z = _pos_data[v * 3 + 2];
|
|
|
|
if (min_x > x) min_x = x;
|
|
if (min_y > y) min_y = y;
|
|
if (min_z > z) min_z = z;
|
|
if (max_x < x) max_x = x;
|
|
if (max_y < y) max_y = y;
|
|
if (max_z < z) max_z = z;
|
|
}
|
|
|
|
Vec3f c(
|
|
(min_x + max_x) * 0.5f,
|
|
(min_y + max_y) * 0.5f,
|
|
(min_z + max_z) * 0.5f
|
|
);
|
|
|
|
return Spheref(
|
|
c.x(), c.y(), c.z(),
|
|
Distance(c, Vec3f(min_x, min_y, min_z))
|
|
);
|
|
}
|
|
|
|
/// Queries the bounding sphere coordinates and dimensions
|
|
template <typename T>
|
|
void BoundingSphere(oglplus::Sphere<T>& bounding_sphere) const {
|
|
bounding_sphere = oglplus::Sphere<T>(MakeBoundingSphere());
|
|
}
|
|
|
|
|
|
/// Returns element indices that are used with the drawing instructions
|
|
const IndexArray & Indices(Default = Default()) const {
|
|
return _idx_data;
|
|
}
|
|
|
|
/// Returns the instructions for rendering of faces
|
|
DrawingInstructions Instructions(PrimitiveType primitive) const {
|
|
DrawingInstructions instr = this->MakeInstructions();
|
|
DrawOperation operation;
|
|
operation.method = DrawOperation::Method::DrawElements;
|
|
operation.mode = primitive;
|
|
operation.first = 0;
|
|
operation.count = _prim_count * 3;
|
|
operation.restart_index = DrawOperation::NoRestartIndex();
|
|
operation.phase = 0;
|
|
this->AddInstruction(instr, operation);
|
|
return std::move(instr);
|
|
}
|
|
|
|
/// Returns the instructions for rendering of faces
|
|
DrawingInstructions Instructions(Default = Default()) const {
|
|
return Instructions(PrimitiveType::Triangles);
|
|
}
|
|
};
|
|
|
|
ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov, float aspect, int slices, int stacks) {
|
|
using namespace oglplus;
|
|
return ShapeWrapperPtr(
|
|
new shapes::ShapeWrapper({ "Position", "TexCoord" }, SphereSection(fov, aspect, slices, stacks), *program)
|
|
);
|
|
}
|
|
#endif |