diff --git a/shaders/galaxy_frag.glsl b/shaders/galaxy_frag.glsl new file mode 100644 index 00000000..638ce5c9 --- /dev/null +++ b/shaders/galaxy_frag.glsl @@ -0,0 +1,11 @@ +#version 120 + +varying vec4 color; +varying vec2 texCoord; + +uniform sampler2D galaxyTex; + +void main(void) +{ + gl_FragColor = texture2D(galaxyTex, texCoord) * color; +} diff --git a/shaders/galaxy_vert.glsl b/shaders/galaxy_vert.glsl new file mode 100644 index 00000000..3abd4994 --- /dev/null +++ b/shaders/galaxy_vert.glsl @@ -0,0 +1,21 @@ +#version 120 + +uniform sampler2D colorTex; + +varying vec4 color; +varying vec2 texCoord; + +void main(void) +{ + // we pass color index as short int + // reusing gl_MultiTexCoord0.z + // we use 255 only because we have 256 color indices + float t = gl_MultiTexCoord0.z / 255.0f; // [0, 255] -> [0, 1] + // we pass alpha values as as short int + // reusing gl_MultiTexCoord0.w + // we use 65535 for better precision + float a = gl_MultiTexCoord0.w / 65535.0f; // [0, 65535] -> [0, 1] + color = vec4(texture2D(colorTex, vec2(t, 0.0f)).rgb, a); + texCoord = gl_MultiTexCoord0.st; + gl_Position = ftransform(); +} diff --git a/src/celengine/galaxy.cpp b/src/celengine/galaxy.cpp index a64bac79..d3b792ed 100644 --- a/src/celengine/galaxy.cpp +++ b/src/celengine/galaxy.cpp @@ -31,7 +31,6 @@ using namespace std; using namespace celmath; static int width = 128, height = 128; -static Vector3f colorTable[256]; static const unsigned int GALAXY_POINTS = 3500; static bool formsInitialized = false; @@ -41,6 +40,7 @@ static GalacticForm** ellipticalForms = nullptr; static GalacticForm* irregularForm = nullptr; static Texture* galaxyTex = nullptr; +static Texture* colorTex = nullptr; static void InitializeForms(); static GalacticForm* buildGalacticForms(const fs::path& filename); @@ -106,6 +106,21 @@ static void GalaxyTextureEval(float u, float v, float /*w*/, unsigned char *pixe pixel[3] = pixVal; } +static void ColorTextureEval(float u, float v, float /*w*/, unsigned char *pixel) +{ + unsigned int i = (u*0.5f + 0.5f)*255.99f; // [-1, 1] -> [0, 255] + + // generic Hue profile as deduced from true-color imaging for spirals + // Hue in degrees + float hue = 25 * tanh(0.0615f * (27 - i)); + if (i >= 28) hue += 220; + //convert Hue to RGB + float r, g, b; + DeepSkyObject::hsv2rgb(&r, &g, &b, hue, 0.20f, 1.0f); + pixel[0] = (unsigned char) (r * 255.99f); + pixel[1] = (unsigned char) (g * 255.99f); + pixel[2] = (unsigned char) (b * 255.99f); +} float Galaxy::getDetail() const { @@ -257,7 +272,7 @@ void Galaxy::render(const Vector3f& offset, const Quaternionf& viewerOrientation, float brightness, float pixelSize, - const Renderer* /* unused */) + const Renderer* renderer) { if (form == nullptr) { @@ -265,20 +280,30 @@ void Galaxy::render(const Vector3f& offset, } else { - renderGalaxyPointSprites(offset, viewerOrientation, brightness, pixelSize); + renderGalaxyPointSprites(offset, viewerOrientation, brightness, pixelSize, renderer); } } - -inline void glVertex4(const Vector4f& v) +struct GalaxyVertex { - glVertex3fv(v.data()); + EIGEN_MAKE_ALIGNED_OPERATOR_NEW; + + Vector4f position; + Matrix texCoord; // texCoord.x = x, texCoord.y = y, texCoord.z = color index, texCoord.w = alpha +}; + +static void draw(const GalaxyVertex *v, size_t count, void *indices) +{ + glVertexPointer(4, GL_FLOAT, sizeof(GalaxyVertex), &v->position); + glTexCoordPointer(4, GL_SHORT, sizeof(GalaxyVertex), &v->texCoord); + glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, indices); } void Galaxy::renderGalaxyPointSprites(const Vector3f& offset, const Quaternionf& viewerOrientation, float brightness, - float pixelSize) + float pixelSize, + const Renderer* renderer) { if (form == nullptr) return; @@ -297,16 +322,28 @@ void Galaxy::renderGalaxyPointSprites(const Vector3f& offset, if (size < minimumFeatureSize) return; + auto *prog = renderer->getShaderManager().getShader("galaxy"); + if (prog == nullptr) + return; + if (galaxyTex == nullptr) { galaxyTex = CreateProceduralTexture(width, height, GL_RGBA, GalaxyTextureEval); } assert(galaxyTex != nullptr); - - glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); galaxyTex->bind(); + if (colorTex == nullptr) + { + colorTex = CreateProceduralTexture(256, 1, GL_RGBA, + ColorTextureEval); + } + assert(colorTex != nullptr); + glActiveTexture(GL_TEXTURE1); + colorTex->bind(); + Matrix3f viewMat = viewerOrientation.conjugate().toRotationMatrix(); Vector4f v0(Vector4f::Zero()); Vector4f v1(Vector4f::Zero()); @@ -317,12 +354,7 @@ void Galaxy::renderGalaxyPointSprites(const Vector3f& offset, v2.head(3) = viewMat * Vector3f( 1, 1, 0) * size; v3.head(3) = viewMat * Vector3f(-1, 1, 0) * size; - //Mat4f m = (getOrientation().toMatrix4() * - // Mat4f::scaling(form->scale) * - // Mat4f::scaling(getRadius())); - Quaternionf orientation = getOrientation().conjugate(); - Matrix3f mScale = form->scale.asDiagonal() * size; Matrix3f mLinear = orientation.toRotationMatrix() * mScale; @@ -330,7 +362,7 @@ void Galaxy::renderGalaxyPointSprites(const Vector3f& offset, m.topLeftCorner(3,3) = mLinear; m.block<3,1>(0, 3) = offset; - int pow2 = 1; + int pow2 = 1; BlobVector* points = form->blobs; unsigned int nPoints = (unsigned int) (points->size() * clamp(getDetail())); @@ -357,10 +389,22 @@ void Galaxy::renderGalaxyPointSprites(const Vector3f& offset, glPushMatrix(); glTranslatef(-offset.x(), -offset.y(), -offset.z()); - float btot = ((type > SBc) && (type < Irr))? 2.5f: 5.0f; + const float btot = ((type > SBc) && (type < Irr)) ? 2.5f : 5.0f; const float spriteScaleFactor = 1.0f / 1.55f; - glBegin(GL_QUADS); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + vector> vertices; + vertices.reserve(4096 / sizeof(GalaxyVertex)); + vector indices; + indices.reserve(4096 / sizeof(GalaxyVertex) / 4 * 6); // 6 indices per 4 vertices + unsigned short j = 0; + + prog->use(); + prog->samplerParam("galaxyTex") = 0; + prog->samplerParam("colorTex") = 1; + for (unsigned int i = 0; i < nPoints; ++i) { if ((i & pow2) != 0) @@ -379,22 +423,52 @@ void Galaxy::renderGalaxyPointSprites(const Vector3f& offset, Vector4f p = m * b.position; float br = b.brightness / 255.0f; - Vector3f c = colorTable[b.colorIndex]; // lookup static color table - float screenFrac = size / p.norm(); if (screenFrac < 0.1f) { - float a = btot * (0.1f - screenFrac) * brightness_corr * brightness * br; - glColor4f(c.x(), c.y(), c.z(), (4.0f * lightGain + 1.0f) * a); - glTexCoord2f(0, 0); glVertex4(p + v0); - glTexCoord2f(1, 0); glVertex4(p + v1); - glTexCoord2f(1, 1); glVertex4(p + v2); - glTexCoord2f(0, 1); glVertex4(p + v3); + float a = (4.0f * lightGain + 1.0f) * btot * (0.1f - screenFrac) * brightness_corr * brightness * br; + short alpha = (short) (a * 65535.99f); + short color = (short)b.colorIndex; + GalaxyVertex vtx; + vtx.position = p + v0; + vtx.texCoord = { 0, 0, color, alpha }; + vertices.push_back(vtx); + vtx.position = p + v1; + vtx.texCoord = { 1, 0, color, alpha }; + vertices.push_back(vtx); + vtx.position = p + v2; + vtx.texCoord = { 1, 1, color, alpha }; + vertices.push_back(vtx); + vtx.position = p + v3; + vtx.texCoord = { 0, 1, color, alpha }; + vertices.push_back(vtx); + + indices.push_back(j+0); + indices.push_back(j+1); + indices.push_back(j+2); + indices.push_back(j+0); + indices.push_back(j+2); + indices.push_back(j+3); + j += 4; + + if ((vertices.size() + 4) * sizeof(GalaxyVertex) > 4096) + { + draw(&vertices[0], indices.size(), indices.data()); + vertices.clear(); + indices.clear(); + j = 0; + } } } - glEnd(); + if (indices.size() > 0) + draw(&vertices[0], indices.size(), indices.data()); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glUseProgram(0); glPopMatrix(); + glActiveTexture(GL_TEXTURE0); } @@ -495,12 +569,7 @@ float Galaxy::getLightGain() void Galaxy::setLightGain(float lg) { - if (lg < 0.0f) - lightGain = 0.0f; - else if (lg > 1.0f) - lightGain = 1.0f; - else - lightGain = lg; + lightGain = clamp(lg); } @@ -601,23 +670,6 @@ GalacticForm* buildGalacticForms(const fs::path& filename) void InitializeForms() { - // build color table: - - for (unsigned int i = 0; i < 256; i++) - { - float rr, gg, bb; - // - // generic Hue profile as deduced from true-color imaging for spirals - // Hue in degrees - - float hue = (i < 28)? 25 * tanh(0.0615f * (27 - i)): 25 * tanh(0.0615f * (27 - i)) + 220; - - //convert Hue to RGB - - DeepSkyObject::hsv2rgb(&rr, &gg, &bb, hue, 0.20f, 1.0f); - Color c(rr, gg, bb); - colorTable[i] = Vector3f(c.red(), c.green(), c.blue()); - } // Spiral Galaxies, 7 classical Hubble types spiralForms = new GalacticForm*[7]; diff --git a/src/celengine/galaxy.h b/src/celengine/galaxy.h index 88571c2e..426fe5d3 100644 --- a/src/celengine/galaxy.h +++ b/src/celengine/galaxy.h @@ -47,7 +47,7 @@ class Galaxy : public DeepSkyObject const Eigen::Quaternionf& viewerOrientation, float brightness, float pixelSize, - const Renderer* r = nullptr) override; + const Renderer* r) override; GalacticForm* getForm() const; @@ -85,7 +85,8 @@ class Galaxy : public DeepSkyObject void renderGalaxyPointSprites(const Eigen::Vector3f& offset, const Eigen::Quaternionf& viewerOrientation, float brightness, - float pixelSize); + float pixelSize, + const Renderer* r); #if 0 void renderGalaxyEllipsoid(const Eigen::Vector3f& offset, const Eigen::Quaternionf& viewerOrientation,