diff --git a/resources/cats.data b/resources/cats.data new file mode 100644 index 000000000..a11ae8d53 Binary files /dev/null and b/resources/cats.data differ diff --git a/resources/cats.xcf b/resources/cats.xcf new file mode 100644 index 000000000..8bfe64240 Binary files /dev/null and b/resources/cats.xcf differ diff --git a/resources/meson.build b/resources/meson.build index 80912fb7d..4c6862dbd 100644 --- a/resources/meson.build +++ b/resources/meson.build @@ -119,3 +119,4 @@ data_files += to_array.process('save_local.png', extra_args: 'save_local_png') data_files += to_array.process('save_online.png', extra_args: 'save_online_png') data_files += to_array.process('font.bz2', extra_args: 'compressed_font_data') data_files += to_array.process('elements.wav.bz2', extra_args: 'elements_wav_bz2') +data_files += to_array.process('cats.data', extra_args: 'cats_data') diff --git a/src/graphics/Renderer.h b/src/graphics/Renderer.h index 452a9dd63..8569dde42 100644 --- a/src/graphics/Renderer.h +++ b/src/graphics/Renderer.h @@ -163,4 +163,10 @@ public: private: int gridSize; + + static constexpr Vec2 kitcatSpriteConfig { 3, 4 }; + static constexpr int kitcatSpriteSize = 13; + static uint8_t SampleSpriteSheet(Vec2 spritePos, Vec2 samplePos, int scale); + static PlaneAdapter> MakeMipMap(int scale, const char * filterName); + static std::array>, (kitcatSpriteSize * 2)-1> kitcatmipmap; }; diff --git a/src/graphics/RendererBasic.cpp b/src/graphics/RendererBasic.cpp index 6caa6944e..6d23e2da2 100644 --- a/src/graphics/RendererBasic.cpp +++ b/src/graphics/RendererBasic.cpp @@ -5,6 +5,9 @@ #include "simulation/ElementClasses.h" #include "simulation/ElementGraphics.h" #include "simulation/Simulation.h" +#include "Misc.h" +#include "cats.data.h" +#include "resampler/resampler.h" constexpr auto VIDXRES = WINDOWW; constexpr auto VIDYRES = WINDOWH; @@ -61,38 +64,60 @@ void Renderer::FinaliseParts() } } +uint8_t Renderer::SampleSpriteSheet(Vec2 spritePos, Vec2 samplePos, int scale) { + int x = samplePos.X; + int y = samplePos.Y; + + if(scale >= kitcatmipmap.size()) { + x = int(std::floor((float(samplePos.X)/float(scale)) * kitcatSpriteSize)); + y = int(std::floor((float(samplePos.Y)/float(scale)) * kitcatSpriteSize)); + scale = kitcatSpriteSize; + } + + return kitcatmipmap[scale][{x + spritePos.X*scale, y + spritePos.Y * scale}]; +} + +int xorshift(int x) { + x ^= x >> 11; + x ^= x << 5; + return x; +} + void Renderer::RenderZoom() { if(!zoomEnabled) return; - { - int x, y, i, j; - pixel pix; - DrawFilledRect(RectSized(zoomWindowPosition, { zoomScopeSize * ZFACTOR, zoomScopeSize * ZFACTOR }), 0x000000_rgb); - DrawRect(RectSized(zoomWindowPosition - Vec2{ 2, 2 }, Vec2{ zoomScopeSize*ZFACTOR+3, zoomScopeSize*ZFACTOR+3 }), 0xC0C0C0_rgb); - DrawRect(RectSized(zoomWindowPosition - Vec2{ 1, 1 }, Vec2{ zoomScopeSize*ZFACTOR+1, zoomScopeSize*ZFACTOR+1 }), 0x000000_rgb); - for (j=0; jpmap[j + zoomScopePosition.Y][i + zoomScopePosition.X]); + for (y=0; yframeCount/10) + (part%51)) %51==0; + bool panik = sim->parts[part].temp > 600; + auto sample = (part && xorshift(part)%21==0) ? SampleSpriteSheet({ panik ? 2 : (blink ? 1 : 0), part%4 }, { x, y }, ZFACTOR-1) : 0; + + video[{ i * ZFACTOR + x + zoomWindowPosition.X, j * ZFACTOR + y + zoomWindowPosition.Y }] = RGBA::Unpack(pix).NoAlpha().Blend(RGBA(0, 0, 0, sample)).Pack(); + } } + + for (j=-1; j<=zoomScopeSize; j++) + { + XorPixel(zoomScopePosition + Vec2{ j, -1 }); + XorPixel(zoomScopePosition + Vec2{ j, zoomScopeSize }); + } + for (j=0; j pos) const return video[pos]; } +PlaneAdapter> Renderer::MakeMipMap(int scale, const char * filterName) { + int scaledX = int((kitcatSpriteSize * kitcatSpriteConfig.X) * (float(scale)/kitcatSpriteSize)); + int scaledY = int((kitcatSpriteSize * kitcatSpriteConfig.Y) * (float(scale)/kitcatSpriteSize)); + PlaneAdapter> mipmap({scaledX, scaledY}); + Resampler resampler( + kitcatSpriteSize * kitcatSpriteConfig.X, kitcatSpriteSize * kitcatSpriteConfig.Y, // source size + scaledX, scaledY, + Resampler::BOUNDARY_CLAMP, + 0.0f, 255.0f, + filterName, + NULL, NULL, + 0.75f, 0.75f + ); + auto line = std::make_unique(kitcatSpriteSize * kitcatSpriteConfig.X); + auto destY = 0; + for (int y = 0; y < kitcatSpriteConfig.Y * kitcatSpriteSize; y++) + { + for(int x = 0; x < kitcatSpriteConfig.X * kitcatSpriteSize; x++) { + line[x] = cats_data[x + (y * kitcatSpriteConfig.X * kitcatSpriteSize)]; + } + resampler.put_line(line.get()); + while(auto outLine = resampler.get_line()) { + for(int destX = 0; destX < scaledX; destX++) { + mipmap.data()[destX + (destY * scaledX)] = uint8_t(outLine[destX]); + } + destY++; + } + } + return mipmap; +} + std::vector> Renderer::flameTable; std::vector> Renderer::plasmaTable; std::vector> Renderer::heatTable; std::vector> Renderer::clfmTable; std::vector> Renderer::firwTable; +std::array>, (Renderer::kitcatSpriteSize*2)-1> Renderer::kitcatmipmap; static bool tablesPopulated = false; static std::mutex tablesPopulatedMx; void Renderer::PopulateTables() @@ -221,6 +278,17 @@ void Renderer::PopulateTables() { 0xFFFF00_rgb, 0.80f }, { 0xFF0000_rgb, 1.00f }, }, 200); + + for(int scale = 1; scale < kitcatmipmap.size(); scale++) { + if(scale == kitcatSpriteSize) { + kitcatmipmap[scale] = PlaneAdapter>({kitcatSpriteConfig.X * kitcatSpriteSize, kitcatSpriteConfig.Y * kitcatSpriteSize}); + std::copy(reinterpret_cast(cats_data), reinterpret_cast(cats_data+cats_data_size), kitcatmipmap[scale].data()); + } else if(scale > kitcatSpriteSize) { + kitcatmipmap[scale] = MakeMipMap(scale, "mitchell"); + } else { + kitcatmipmap[scale] = MakeMipMap(scale, "lanczos4"); + } + } } }