diff --git a/shaders/galaxy_vert.glsl b/shaders/galaxy_vert.glsl index d0abd8628d..5359849077 100644 --- a/shaders/galaxy_vert.glsl +++ b/shaders/galaxy_vert.glsl @@ -27,10 +27,11 @@ void main(void) return; } - vec4 v = vec4(viewMat * vec3(in_TexCoord0.s * 2.0 - 1.0, in_TexCoord0.t * 2.0 - 1.0, 0.0) * s, 0.0); + vec4 v = vec4(viewMat * vec3(in_TexCoord0 * 2.0 - 1.0, 0.0) * s, 0.0); float alpha = (0.1 - screenFrac) * in_Brightness * brightness; - color = vec4(texture2D(colorTex, vec2(in_ColorIndex, 0.0)).rgb, alpha); + float premultalpha = sqrt(alpha); // faster and no so presize srgb->linear + color = vec4(texture2D(colorTex, vec2(in_ColorIndex, 0.0)).rgb * premultalpha, alpha); texCoord = in_TexCoord0; set_vp(p + v); } diff --git a/shaders/passthrough_frag.glsl b/shaders/passthrough_frag.glsl index c8ce87bfc2..13fc5679b8 100644 --- a/shaders/passthrough_frag.glsl +++ b/shaders/passthrough_frag.glsl @@ -2,7 +2,17 @@ varying vec2 texCoord; uniform sampler2D tex; +const float gamma = 2.2; + +float to_srgb(float v) +{ + return v <= 0.0031308 ? 12.92 * v : 1.055 * pow(v, 1.0/2.4) - 0.055; +} + void main(void) { - gl_FragColor = texture2D(tex, texCoord); +// gl_FragColor = texture2D(tex, texCoord); + vec3 color = texture2D(tex, texCoord).rgb; +// gl_FragColor = vec4(pow(color, vec3(1.0 / gamma)), 1.0); + gl_FragColor = vec4(to_srgb(color.r), to_srgb(color.g), to_srgb(color.b), 1.0); } diff --git a/src/celengine/framebuffer.cpp b/src/celengine/framebuffer.cpp index ddb9e1efe8..e562d01f7c 100644 --- a/src/celengine/framebuffer.cpp +++ b/src/celengine/framebuffer.cpp @@ -88,11 +88,12 @@ FramebufferObject::generateColorTexture() glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Set the texture dimensions - // Do we need to set GL_DEPTH_COMPONENT24 here? #ifdef GL_ES - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_width, m_height, 0, GL_RGB, GL_HALF_FLOAT_OES, nullptr); #else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, m_width, m_height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, m_width, m_height, 0, GL_RGBA, GL_FLOAT, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); #endif // Unbind the texture @@ -128,7 +129,6 @@ FramebufferObject::generateDepthTexture() // Set the texture dimensions // Do we need to set GL_DEPTH_COMPONENT24 here? - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, m_width, m_height, 0, GL_DEPTH_COMPONENT, CEL_DEPTH_FORMAT, nullptr); // Unbind the texture diff --git a/src/celengine/glsupport.cpp b/src/celengine/glsupport.cpp index 5a18c1000a..9da8354de5 100644 --- a/src/celengine/glsupport.cpp +++ b/src/celengine/glsupport.cpp @@ -8,9 +8,12 @@ namespace celestia::gl CELAPI bool OES_vertex_array_object = false; CELAPI bool OES_texture_border_clamp = false; CELAPI bool OES_geometry_shader = false; +CELAPI bool EXT_color_buffer_half_float = false; +CELAPI bool EXT_sRGB = false; #else CELAPI bool ARB_vertex_array_object = false; CELAPI bool ARB_framebuffer_object = false; +CELAPI bool ARB_color_buffer_float = false; #endif CELAPI bool ARB_shader_texture_lod = false; CELAPI bool EXT_texture_compression_s3tc = false; @@ -45,9 +48,12 @@ bool init(util::array_view ignore) noexcept OES_vertex_array_object = check_extension(ignore, "GL_OES_vertex_array_object"); OES_texture_border_clamp = check_extension(ignore, "GL_OES_texture_border_clamp") || check_extension(ignore, "GL_EXT_texture_border_clamp"); OES_geometry_shader = check_extension(ignore, "GL_OES_geometry_shader") || check_extension(ignore, "GL_EXT_geometry_shader"); + EXT_color_buffer_half_float = check_extension(ignore, "EXT_color_buffer_half_float"); + EXT_sRGB = check_extension(ignore, "EXT_sRGB"); #else ARB_vertex_array_object = check_extension(ignore, "GL_ARB_vertex_array_object"); ARB_framebuffer_object = check_extension(ignore, "GL_ARB_framebuffer_object") || check_extension(ignore, "GL_EXT_framebuffer_object"); + ARB_color_buffer_float = check_extension(ignore, "ARB_color_buffer_float"); #endif ARB_shader_texture_lod = check_extension(ignore, "GL_ARB_shader_texture_lod"); EXT_texture_compression_s3tc = check_extension(ignore, "GL_EXT_texture_compression_s3tc"); diff --git a/src/celengine/glsupport.h b/src/celengine/glsupport.h index dce2d25483..13e6560049 100644 --- a/src/celengine/glsupport.h +++ b/src/celengine/glsupport.h @@ -10,7 +10,7 @@ #define CELAPI __declspec(dllexport) #endif #else -#define CELAPI +#define CELAPI __attribute__((visibility("default"))) #endif #include @@ -47,9 +47,12 @@ extern CELAPI bool MESA_pack_invert; //NOSONAR extern CELAPI bool OES_vertex_array_object; //NOSONAR extern CELAPI bool OES_texture_border_clamp; //NOSONAR extern CELAPI bool OES_geometry_shader; //NOSONAR +extern CELAPI bool EXT_color_buffer_half_float; //NOSONAR +extern CELAPI bool EXT_sRGB; // NOSONAR #else extern CELAPI bool ARB_vertex_array_object; //NOSONAR extern CELAPI bool ARB_framebuffer_object; //NOSONAR +extern CELAPI bool ARB_color_buffer_float; //NOSONAR #endif extern CELAPI GLint maxPointSize; //NOSONAR extern CELAPI GLint maxTextureSize; //NOSONAR diff --git a/src/celengine/render.cpp b/src/celengine/render.cpp index e774a2fd9d..5b5cdc5f80 100644 --- a/src/celengine/render.cpp +++ b/src/celengine/render.cpp @@ -155,47 +155,49 @@ static const unsigned int OrbitCacheCullThreshold = 200; // Age in frames at which unused orbit paths may be eliminated from the cache static const uint32_t OrbitCacheRetireAge = 16; -Color Renderer::StarLabelColor (0.471f, 0.356f, 0.682f); -Color Renderer::PlanetLabelColor (0.407f, 0.333f, 0.964f); -Color Renderer::DwarfPlanetLabelColor (0.557f, 0.235f, 0.576f); -Color Renderer::MoonLabelColor (0.231f, 0.733f, 0.792f); -Color Renderer::MinorMoonLabelColor (0.231f, 0.733f, 0.792f); -Color Renderer::AsteroidLabelColor (0.596f, 0.305f, 0.164f); -Color Renderer::CometLabelColor (0.768f, 0.607f, 0.227f); -Color Renderer::SpacecraftLabelColor (0.93f, 0.93f, 0.93f); -Color Renderer::LocationLabelColor (0.24f, 0.89f, 0.43f); -Color Renderer::GalaxyLabelColor (0.0f, 0.45f, 0.5f); -Color Renderer::GlobularLabelColor (0.8f, 0.45f, 0.5f); -Color Renderer::NebulaLabelColor (0.541f, 0.764f, 0.278f); -Color Renderer::OpenClusterLabelColor (0.239f, 0.572f, 0.396f); -Color Renderer::ConstellationLabelColor (0.225f, 0.301f, 0.36f); -Color Renderer::EquatorialGridLabelColor(0.64f, 0.72f, 0.88f); -Color Renderer::PlanetographicGridLabelColor(0.8f, 0.8f, 0.8f); -Color Renderer::GalacticGridLabelColor (0.88f, 0.72f, 0.64f); -Color Renderer::EclipticGridLabelColor (0.72f, 0.64f, 0.88f); -Color Renderer::HorizonGridLabelColor (0.72f, 0.72f, 0.72f); - -Color Renderer::StarOrbitColor (0.5f, 0.5f, 0.8f); -Color Renderer::PlanetOrbitColor (0.3f, 0.323f, 0.833f); -Color Renderer::DwarfPlanetOrbitColor (0.557f, 0.235f, 0.576f); -Color Renderer::MoonOrbitColor (0.08f, 0.407f, 0.392f); -Color Renderer::MinorMoonOrbitColor (0.08f, 0.407f, 0.392f); -Color Renderer::AsteroidOrbitColor (0.58f, 0.152f, 0.08f); -Color Renderer::CometOrbitColor (0.639f, 0.487f, 0.168f); -Color Renderer::SpacecraftOrbitColor (0.4f, 0.4f, 0.4f); -Color Renderer::SelectionOrbitColor (1.0f, 0.0f, 0.0f); - -Color Renderer::ConstellationColor (0.0f, 0.24f, 0.36f); -Color Renderer::BoundaryColor (0.24f, 0.10f, 0.12f); -Color Renderer::EquatorialGridColor (0.28f, 0.28f, 0.38f); -Color Renderer::PlanetographicGridColor (0.8f, 0.8f, 0.8f); -Color Renderer::PlanetEquatorColor (0.5f, 1.0f, 1.0f); -Color Renderer::GalacticGridColor (0.38f, 0.38f, 0.28f); -Color Renderer::EclipticGridColor (0.38f, 0.28f, 0.38f); -Color Renderer::HorizonGridColor (0.38f, 0.38f, 0.38f); -Color Renderer::EclipticColor (0.5f, 0.1f, 0.1f); - -Color Renderer::SelectionCursorColor (1.0f, 0.0f, 0.0f); +Color Renderer::StarLabelColor (0.471f, 0.356f, 0.682f); +Color Renderer::PlanetLabelColor (0.407f, 0.333f, 0.964f); +Color Renderer::DwarfPlanetLabelColor (0.557f, 0.235f, 0.576f); +Color Renderer::MoonLabelColor (0.231f, 0.733f, 0.792f); +Color Renderer::MinorMoonLabelColor (0.231f, 0.733f, 0.792f); +Color Renderer::AsteroidLabelColor (0.596f, 0.305f, 0.164f); +Color Renderer::CometLabelColor (0.768f, 0.607f, 0.227f); +Color Renderer::SpacecraftLabelColor (0.93f, 0.93f, 0.93f); +Color Renderer::LocationLabelColor (0.24f, 0.89f, 0.43f); +Color Renderer::GalaxyLabelColor (0.0f, 0.45f, 0.5f); +Color Renderer::GlobularLabelColor (0.8f, 0.45f, 0.5f); +Color Renderer::NebulaLabelColor (0.541f, 0.764f, 0.278f); +Color Renderer::OpenClusterLabelColor (0.239f, 0.572f, 0.396f); +Color Renderer::ConstellationLabelColor (0.225f, 0.301f, 0.36f); +Color Renderer::EquatorialGridLabelColor (0.64f, 0.72f, 0.88f); +Color Renderer::PlanetographicGridLabelColor (0.8f, 0.8f, 0.8f); +Color Renderer::GalacticGridLabelColor (0.88f, 0.72f, 0.64f); +Color Renderer::EclipticGridLabelColor (0.72f, 0.64f, 0.88f); +Color Renderer::HorizonGridLabelColor (0.72f, 0.72f, 0.72f); + +Color Renderer::StarOrbitColor (0.5f, 0.5f, 0.8f); +Color Renderer::PlanetOrbitColor (0.3f, 0.323f, 0.833f); +Color Renderer::DwarfPlanetOrbitColor (0.557f, 0.235f, 0.576f); +Color Renderer::MoonOrbitColor (0.08f, 0.407f, 0.392f); +Color Renderer::MinorMoonOrbitColor (0.08f, 0.407f, 0.392f); +Color Renderer::AsteroidOrbitColor (0.58f, 0.152f, 0.08f); +Color Renderer::CometOrbitColor (0.639f, 0.487f, 0.168f); +Color Renderer::SpacecraftOrbitColor (0.4f, 0.4f, 0.4f); +Color Renderer::SelectionOrbitColor (1.0f, 0.0f, 0.0f); + +Color Renderer::ConstellationColor (0.0f, 0.24f, 0.36f); +Color Renderer::BoundaryColor (0.24f, 0.10f, 0.12f); +Color Renderer::EquatorialGridColor (0.28f, 0.28f, 0.38f); +Color Renderer::PlanetographicGridColor (0.8f, 0.8f, 0.8f); +Color Renderer::PlanetEquatorColor (0.5f, 1.0f, 1.0f); +Color Renderer::GalacticGridColor (0.38f, 0.38f, 0.28f); +Color Renderer::EclipticGridColor (0.38f, 0.28f, 0.38f); +Color Renderer::HorizonGridColor (0.38f, 0.38f, 0.38f); +Color Renderer::EclipticColor (0.5f, 0.1f, 0.1f); + +Color Renderer::SelectionCursorColor (1.0f, 0.0f, 0.0f); + +bool Renderer::linearMode = false; // Some useful unit conversions inline float mmToInches(float mm) @@ -236,7 +238,7 @@ Renderer::Renderer() : #ifndef GL_ES renderMode(GL_FILL), #endif - labelMode(LocationLabels), //def. NoLabels + labelMode(NoLabels), renderFlags(DefaultRenderFlags), orbitMask(Body::Planet | Body::Moon | Body::Stellar), brightnessBias(0.0f), @@ -355,7 +357,9 @@ static void BuildGaussianDiscMipLevel(unsigned char* mipPixels, float x = (float) j - size / 2; float r2 = x * x + y * y; float f = s * (float) exp(-r2 * isig2) * power; - +#if GL_ES + f = f <= 0.04045f ? f * (1.0f/12.92f) : std::pow((f + 0.055f)/1.055f, 2.4f); +#endif mipPixels[i * size + j] = (unsigned char) (255.99f * min(f, 1.0f)); } } @@ -377,6 +381,9 @@ static void BuildGlareMipLevel(unsigned char* mipPixels, float x = (float) j - size / 2; auto r = (float) sqrt(x * x + y * y); auto f = (float) pow(base, r * scale); +#if GL_ES + f = f <= 0.04045f ? f * (1.0f/12.92f) : std::pow((f + 0.055f)/1.055f, 2.4f); +#endif mipPixels[i * size + j] = (unsigned char) (255.99f * min(f, 1.0f)); } } @@ -414,7 +421,11 @@ static void BuildGlareMipLevel2(unsigned char* mipPixels, static Texture* BuildGaussianDiscTexture(unsigned int log2size) { unsigned int size = 1 << log2size; +#if GL_ES Image* img = new Image(PixelFormat::LUMINANCE, size, size, log2size + 1); +#else + Image* img = new Image(PixelFormat::SLUMINANCE, size, size, log2size + 1); +#endif for (unsigned int mipLevel = 0; mipLevel <= log2size; mipLevel++) { @@ -438,7 +449,11 @@ static Texture* BuildGaussianDiscTexture(unsigned int log2size) static Texture* BuildGaussianGlareTexture(unsigned int log2size) { unsigned int size = 1 << log2size; +#if GL_ES Image* img = new Image(PixelFormat::LUMINANCE, size, size, log2size + 1); +#else + Image* img = new Image(PixelFormat::SLUMINANCE, size, size, log2size + 1); +#endif for (unsigned int mipLevel = 0; mipLevel <= log2size; mipLevel++) { @@ -543,6 +558,51 @@ bool Renderer::init(int winWidth, int winHeight, const DetailOptions& _detailOpt commonDataInitialized = true; } + if (!linearMode) + { + StarLabelColor.linearize(); + PlanetLabelColor.linearize(); + DwarfPlanetLabelColor.linearize(); + MoonLabelColor.linearize(); + MinorMoonLabelColor.linearize(); + AsteroidLabelColor.linearize(); + CometLabelColor.linearize(); + SpacecraftLabelColor.linearize(); + LocationLabelColor.linearize(); + GalaxyLabelColor.linearize(); + GlobularLabelColor.linearize(); + NebulaLabelColor.linearize(); + OpenClusterLabelColor.linearize(); + ConstellationLabelColor.linearize(); + EquatorialGridLabelColor.linearize(); + PlanetographicGridLabelColor.linearize(); + GalacticGridLabelColor.linearize(); + EclipticGridLabelColor.linearize(); + HorizonGridLabelColor.linearize(); + + StarOrbitColor.linearize(); + PlanetOrbitColor.linearize(); + DwarfPlanetOrbitColor.linearize(); + MoonOrbitColor.linearize(); + MinorMoonOrbitColor.linearize(); + AsteroidOrbitColor.linearize(); + CometOrbitColor.linearize(); + SpacecraftOrbitColor.linearize(); + SelectionOrbitColor.linearize(); + + ConstellationColor.linearize(); + BoundaryColor.linearize(); + EquatorialGridColor.linearize(); + PlanetographicGridColor.linearize(); + PlanetEquatorColor.linearize(); + GalacticGridColor.linearize(); + EclipticGridColor.linearize(); + HorizonGridColor.linearize(); + EclipticColor.linearize(); + + SelectionCursorColor.linearize(); + } + glEnable(GL_CULL_FACE); glCullFace(GL_BACK); @@ -1605,7 +1665,7 @@ void Renderer::draw(const Observer& observer, // Calculate saturation magnitude satPoint = faintestMag - (1.0f - brightnessBias) / brightnessScale; - ambientColor = Color(ambientLightLevel, ambientLightLevel, ambientLightLevel); + ambientColor = Color::srgb(ambientLightLevel, ambientLightLevel, ambientLightLevel); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -2319,8 +2379,8 @@ void Renderer::renderObject(const Vector3f& pos, ri.color = obj.surface->color; } - ri.ambientColor = ambientColor; - ri.specularColor = obj.surface->specularColor; + ri.ambientColor = linearMode ? ambientColor : Color::srgb(ambientColor); + ri.specularColor = linearMode ? obj.surface->specularColor : Color::srgb(obj.surface->specularColor); ri.specularPower = obj.surface->specularPower; ri.lunarLambert = obj.surface->lunarLambert; @@ -2366,8 +2426,7 @@ void Renderer::renderObject(const Vector3f& pos, // If there's an atmosphere, we need to move the far plane // out so that the clouds and atmosphere shell aren't clipped. float atmosphereRadius = eradius + atmosphereHeight; - frustumFarPlane += (float) sqrt(square(atmosphereRadius) - - square(eradius)); + frustumFarPlane += std::sqrt(square(atmosphereRadius) - square(eradius)); } } } @@ -2509,8 +2568,16 @@ void Renderer::renderObject(const Vector3f& pos, { Eigen::Matrix4f modelView = celmath::rotate(getCameraOrientationf()); Matrices mvp = { m.projection, &modelView }; + Atmosphere atm(*atmosphere); + if (!linearMode) + { + atm.lowerColor = Color::srgb(atm.lowerColor); + atm.upperColor = Color::srgb(atm.upperColor); + atm.skyColor = Color::srgb(atm.skyColor); + atm.sunsetColor = Color::srgb(atm.sunsetColor); + } m_atmosphereRenderer->renderLegacy( - *atmosphere, + atm, ls, pos, obj.orientation, @@ -3053,7 +3120,7 @@ void Renderer::renderStar(const Star& star, // Use atmosphere effect to give stars a fuzzy fringe if (star.hasCorona() && rp.geometry == InvalidResource) { - Color atmColor(color.red() * 0.5f, color.green() * 0.5f, color.blue() * 0.5f); + Color atmColor = color * 0.5f; atmosphere.height = radius * CoronaHeight; atmosphere.lowerColor = atmColor; atmosphere.upperColor = atmColor; diff --git a/src/celengine/render.h b/src/celengine/render.h index f01605e615..af65a41d22 100644 --- a/src/celengine/render.h +++ b/src/celengine/render.h @@ -848,6 +848,8 @@ class Renderer static Color SelectionCursorColor; + static bool linearMode; + friend class PointStarRenderer; }; diff --git a/src/celengine/shadermanager.cpp b/src/celengine/shadermanager.cpp index fbb815cae2..8cdaac3dc8 100644 --- a/src/celengine/shadermanager.cpp +++ b/src/celengine/shadermanager.cpp @@ -3635,6 +3635,7 @@ CelestiaGLProgram::setLightParameters(const LightingState& ls, lights[i].color = light.color.toVector3(); lights[i].direction = light.direction_obj; +#if 0 // Include a phase-based normalization factor to prevent planets from appearing // too dim when rendered with non-Lambertian photometric functions. float cosPhaseAngle = light.direction_obj.dot(ls.eyeDir_obj); @@ -3643,6 +3644,7 @@ CelestiaGLProgram::setLightParameters(const LightingState& ls, float photometricNormFactor = std::max(1.0f, 1.0f + cosPhaseAngle * 0.5f); lightColor *= photometricNormFactor; } +#endif lights[i].diffuse = lightColor.cwiseProduct(diffuseColor); lights[i].brightness = lightColor.maxCoeff(); diff --git a/src/celengine/texture.cpp b/src/celengine/texture.cpp index 447e9521dd..47ebed1c49 100644 --- a/src/celengine/texture.cpp +++ b/src/celengine/texture.cpp @@ -74,6 +74,15 @@ getInternalFormat(PixelFormat format) case PixelFormat::DXT3: case PixelFormat::DXT5: return static_cast(format); + case PixelFormat::SRGB: + case PixelFormat::SRGB8: + return GL_SRGB8; + case PixelFormat::SRGBA: + case PixelFormat::SRGBA8: + case PixelFormat::DXT1_SRGBA: + case PixelFormat::DXT3_SRGBA: + case PixelFormat::DXT5_SRGBA: + return GL_SRGB8_ALPHA8; default: return GL_NONE; } @@ -108,7 +117,17 @@ GLenum getExternalFormat(PixelFormat format) { #ifdef GL_ES - return getInternalFormat(format); + switch (format) + { + case PixelFormat::SRGB: + case PixelFormat::SRGB8: + return GL_RGB; + case PixelFormat::SRGBA: + case PixelFormat::SRGBA8: + return GL_RGBA; + default: + return getInternalFormat(format); + } #else switch (format) { @@ -267,6 +286,8 @@ LoadMiplessTexture(const Image& img, GLenum target) { int internalFormat = getInternalFormat(img.getFormat()); + GetLogger()->info("Format, internal: {:X}, external {:X}\n", internalFormat, getExternalFormat(img.getFormat())); + if (img.isCompressed()) { glCompressedTexImage2D(target, @@ -279,6 +300,7 @@ LoadMiplessTexture(const Image& img, GLenum target) } else { + while (glGetError() != 0); glTexImage2D(target, 0, internalFormat, @@ -287,6 +309,8 @@ LoadMiplessTexture(const Image& img, GLenum target) getExternalFormat(img.getFormat()), GL_UNSIGNED_BYTE, img.getMipLevel(0)); + if (internalFormat >= 0x8c40 && internalFormat <= 0x8c43) + GetLogger()->info("GL error: {:X}\n", glGetError()); } } diff --git a/src/celestia/sdl/sdlmain.cpp b/src/celestia/sdl/sdlmain.cpp index 3869575b4e..9495045c5f 100644 --- a/src/celestia/sdl/sdlmain.cpp +++ b/src/celestia/sdl/sdlmain.cpp @@ -127,7 +127,7 @@ SDL_Application::init(std::string_view name, int w, int h) SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); #ifdef GL_ES SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #endif return std::make_shared(name, w, h); @@ -647,6 +647,9 @@ DumpGLInfo() s = reinterpret_cast(glGetString(GL_SHADING_LANGUAGE_VERSION)); if (s != nullptr) std::cout << s << '\n'; +#if GL_ES + std::cout << celestia::gl::EXT_sRGB << '\n'; +#endif } int @@ -672,7 +675,13 @@ sdlmain(int /* argc */, char ** /* argv */) return 1; } - auto app = SDL_Application::init("Celestia", 640, 480); +#if GL_ES + const char appName[] = "Celestia (OpenGL ES)"; +#else + const char appName[] = "Celestia (OpenGL)"; +#endif + + auto app = SDL_Application::init(appName, 640, 480); if (app == nullptr) { FatalError("Could not initialize SDL! Error: {}", SDL_GetError()); diff --git a/src/celimage/jpeg.cpp b/src/celimage/jpeg.cpp index e461472754..a3d2dc9a30 100644 --- a/src/celimage/jpeg.cpp +++ b/src/celimage/jpeg.cpp @@ -66,6 +66,8 @@ Image* LoadJPEGImage(const fs::path& filename) // VERY IMPORTANT: use "b" option to fopen() if you are on a machine that // requires it in order to read binary files. + GetLogger()->info("Loading {}\n", filename); + FILE *in; #ifdef _WIN32 in = _wfopen(filename.c_str(), L"rb"); @@ -132,9 +134,15 @@ Image* LoadJPEGImage(const fs::path& filename) // Here we use the library's state variable cinfo.output_scanline as the // loop counter, so that we don't have to keep track ourselves. +#ifdef GL_ES PixelFormat format = PixelFormat::RGB; if (cinfo.output_components == 1) format = PixelFormat::LUMINANCE; +#else + PixelFormat format = PixelFormat::SRGB; + if (cinfo.output_components == 1) + format = PixelFormat::SLUMINANCE; +#endif img = new Image(format, cinfo.image_width, cinfo.image_height); diff --git a/src/celimage/png.cpp b/src/celimage/png.cpp index bea0d77551..166328b618 100644 --- a/src/celimage/png.cpp +++ b/src/celimage/png.cpp @@ -99,29 +99,6 @@ Image* LoadPNGImage(const fs::path& filename) &color_type, &interlace_type, nullptr, nullptr); - PixelFormat format = PixelFormat::RGB; - switch (color_type) - { - case PNG_COLOR_TYPE_GRAY: - format = PixelFormat::LUMINANCE; - break; - case PNG_COLOR_TYPE_GRAY_ALPHA: - format = PixelFormat::LUM_ALPHA; - break; - case PNG_COLOR_TYPE_RGB: - format = PixelFormat::RGB; - break; - case PNG_COLOR_TYPE_PALETTE: - case PNG_COLOR_TYPE_RGB_ALPHA: - format = PixelFormat::RGBA; - break; - default: - // badness - break; - } - - img = new Image(format, width, height); - // TODO: consider using paletted textures if they're available if (color_type == PNG_COLOR_TYPE_PALETTE) { @@ -145,6 +122,47 @@ Image* LoadPNGImage(const fs::path& filename) else if (bit_depth < 8) png_set_packing(png_ptr); + double gamma = 1.0/2.2; +#ifdef GL_ES + bool isLinear = true; +#else + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) + png_get_gAMA(png_ptr, info_ptr, &gamma); + bool isLinear = bit_depth != 8 || gamma < 0.454 || gamma > 0.455; // treat images with nonstandard gamma as linear +#endif + + PixelFormat format = PixelFormat::RGB; + switch (color_type) + { + case PNG_COLOR_TYPE_GRAY: +#ifdef GL_ES + format = PixelFormat::LUMINANCE; +#else + format = isLinear ? PixelFormat::LUMINANCE : PixelFormat::SLUMINANCE; +#endif + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: +#ifdef GL_ES + format = PixelFormat::LUM_ALPHA; +#else + format = isLinear ? PixelFormat::LUM_ALPHA : PixelFormat::SLUM_ALPHA; +#endif + break; + case PNG_COLOR_TYPE_RGB: + format = isLinear ? PixelFormat::RGB : PixelFormat::SRGB; + break; + case PNG_COLOR_TYPE_PALETTE: + case PNG_COLOR_TYPE_RGB_ALPHA: + format = isLinear ? PixelFormat::RGBA : PixelFormat::SRGBA; + break; + default: + // badness + break; + } + GetLogger()->info("File: {}, gamma: {}, linear: {}, format: {:X}\n", filename, gamma, isLinear ? "yes" : "no", (int)format); + + img = new Image(format, width, height); + row_pointers = new png_bytep[height]; for (unsigned int i = 0; i < height; i++) row_pointers[i] = (png_bytep) img->getPixelRow(i); diff --git a/src/celrender/galaxyrenderer.cpp b/src/celrender/galaxyrenderer.cpp index b5f7f7f460..33c1d461f6 100644 --- a/src/celrender/galaxyrenderer.cpp +++ b/src/celrender/galaxyrenderer.cpp @@ -24,7 +24,6 @@ #include "galaxyrenderer.h" using celestia::engine::GalacticFormManager; -using celestia::engine::GalacticForm; namespace celestia::render { @@ -56,15 +55,15 @@ colorTextureEval(float u, float /*v*/, float /*w*/, std::uint8_t *pixel) void BindTextures() { - static Texture* galaxyTex = nullptr; - static Texture* colorTex = nullptr; + static std::unique_ptr galaxyTex = nullptr; + static std::unique_ptr colorTex = nullptr; if (galaxyTex == nullptr) { galaxyTex = CreateProceduralTexture(kGalaxyTextureSize, kGalaxyTextureSize, celestia::PixelFormat::LUMINANCE, - galaxyTextureEval).release(); + galaxyTextureEval); } assert(galaxyTex != nullptr); glActiveTexture(GL_TEXTURE0); @@ -72,10 +71,15 @@ BindTextures() if (colorTex == nullptr) { - colorTex = CreateProceduralTexture(256, 1, celestia::PixelFormat::RGBA, + colorTex = CreateProceduralTexture(256, 1, +#ifdef GL_ES + celestia::PixelFormat::RGBA, +#else + celestia::PixelFormat::SRGBA, +#endif colorTextureEval, Texture::EdgeClamp, - Texture::NoMipMaps).release(); + Texture::NoMipMaps); } assert(colorTex != nullptr); glActiveTexture(GL_TEXTURE1); @@ -97,7 +101,7 @@ struct GalaxyRenderer::Object Eigen::Vector3f offset; // distance to the galaxy float brightness; - float nearZ; // if nearZ != & farZ != then use custom projection matrix + float nearZ; // if nearZ != 0 & farZ != 0 then use custom projection matrix float farZ; const Galaxy *galaxy; }; @@ -132,7 +136,7 @@ GalaxyRenderer::render() if (m_objects.empty()) return; - if (gl::hasGeomShader()) + if (/*gl::hasGeomShader()*/false) renderGL3(); else renderGL2(); @@ -232,9 +236,9 @@ GalaxyRenderer::renderGL2() prog->setMVPMatrices(pr, m_renderer.getModelViewMatrix()); - prog->floatParam("size") = size; - prog->floatParam("brightness") = brightness; - prog->mat4Param("m") = m; + prog->floatParam("size") = size; + prog->floatParam("brightness") = brightness; + prog->mat4Param("m") = m; m_renderDataGL2[obj.galaxy->getFormId()].vo.draw(nPoints * 6); } diff --git a/src/celrender/globularrenderer.cpp b/src/celrender/globularrenderer.cpp index 0e48ee9cd7..aa43c8e50d 100644 --- a/src/celrender/globularrenderer.cpp +++ b/src/celrender/globularrenderer.cpp @@ -429,7 +429,13 @@ GlobularFormManager::getColorTex() { if (colorTex == nullptr) { - colorTex = CreateProceduralTexture(256, 1, celestia::PixelFormat::RGBA, + celestia::PixelFormat format; +#ifdef GL_ES + format = celestia::PixelFormat::RGBA; +#else + format = celestia::PixelFormat::SRGBA; +#endif + colorTex = CreateProceduralTexture(256, 1, format, colorTextureEval, Texture::EdgeClamp, Texture::NoMipMaps); diff --git a/src/celutil/color.h b/src/celutil/color.h index ea9b340e59..cf6316dcd5 100644 --- a/src/celutil/color.h +++ b/src/celutil/color.h @@ -11,11 +11,18 @@ #include #include +#include // std::pow #include #include #include +#if defined(__GNUC__) && !defined(__clang_version__) +// GCC >= 4.6 implements constexpr for in C++11 mode. Other compilers require C++26. +#define constexprmath constexpr +#else +#define constexprmath +#endif class Color { @@ -25,33 +32,58 @@ class Color return static_cast(std::clamp(a, 0.0f, 1.0f) * 255.99f); } + static constexprmath float linearize(float v) + { + return v <= 0.04045f ? v * (1.0f/12.92f) : std::pow((v + 0.055f)/1.055f, 2.4f); + } + std::array c; public: constexpr Color() noexcept : c({ 0, 0, 0, 0xff }) - {} - constexpr Color(float r, float g, float b, float a) noexcept : + { + } + + constexpr Color(float r, float g, float b, float a = 1.0f) noexcept : c({ scaleFloat(r), scaleFloat(g), scaleFloat(b), scaleFloat(a) }) - {} - constexpr Color(float r, float g, float b) noexcept : - Color(r, g, b, 1.0f) - {} - constexpr Color(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a) noexcept : + { + } + + constexpr Color(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a = 0xff) noexcept : c({ r, g, b, a }) - {} - constexpr Color(std::uint8_t r, std::uint8_t g, std::uint8_t b) noexcept: - Color(r, g, b, 0xff) - {} + { + } + constexpr Color(const Color &color, float alpha) noexcept : Color(color.red(), color.green(), color.blue(), alpha) - {} + { + } + Color(const Eigen::Vector3f &v) noexcept : Color(v.x(), v.y(), v.z()) - {} + { + } + Color(const Eigen::Vector4f &v) noexcept : Color(v.x(), v.y(), v.z(), v.w()) - {} + { + } + + constexprmath void linearize() + { + *this = srgb(*this); + } + + static constexprmath Color srgb(float r, float g, float b, float a = 1.0f) + { + return { linearize(r), linearize(g), linearize(b), a }; + } + + static constexprmath Color srgb(const Color &other) + { + return Color::srgb(other.red(), other.green(), other.blue(), other.alpha()); + } enum {