From e90cc2f48733c3ef49d100dacba42174ae19a54b Mon Sep 17 00:00:00 2001 From: Jerboa <84378622+Jerboa-app@users.noreply.github.com> Date: Wed, 11 Sep 2024 18:59:23 +0100 Subject: [PATCH] Sprite and Shape use ptrs (#92) * Sprite and Shape use ptrs --- CMakeLists.txt | 3 - examples/CMakeLists.txt | 3 +- examples/Shape/main.cpp | 14 +- examples/Sprite/main.cpp | 188 ++++++++++++------ examples/SpriteBenchmark/CMakeLists.txt | 25 +++ examples/SpriteBenchmark/main.cpp | 149 ++++++++++++++ examples/SpriteBenchmark/main.h | 45 +++++ examples/SpriteBenchmark/rand.cpp | 5 + examples/SpriteBenchmark/rand.h | 22 ++ .../resource/texture/HEART.png | Bin 0 -> 6158 bytes .../SpriteBenchmark/resource/texture/Pi.png | Bin 0 -> 2664 bytes .../resource/texture/atlas.png | Bin 0 -> 574 bytes .../resource/texture/random.png | Bin 0 -> 2587 bytes include/jGL/OpenGL/glShapeRenderer.h | 2 +- include/jGL/OpenGL/glSpriteRenderer.h | 31 +-- include/jGL/Vulkan/vkShapeRenderer.h | 2 +- include/jGL/Vulkan/vkSpriteRenderer.h | 14 +- include/jGL/priorityStore.h | 34 ++-- include/jGL/shape.h | 32 +-- include/jGL/shapeRenderer.h | 12 +- include/jGL/sprite.h | 103 ++++------ include/jGL/spriteRenderer.h | 125 +++++------- src/jGL/OpenGL/glShapeRenderer.cpp | 20 +- src/jGL/OpenGL/glSpriteRenderer.cpp | 61 +++--- src/jGL/spriteRenderer.cpp | 29 --- 25 files changed, 570 insertions(+), 349 deletions(-) create mode 100644 examples/SpriteBenchmark/CMakeLists.txt create mode 100644 examples/SpriteBenchmark/main.cpp create mode 100644 examples/SpriteBenchmark/main.h create mode 100644 examples/SpriteBenchmark/rand.cpp create mode 100644 examples/SpriteBenchmark/rand.h create mode 100644 examples/SpriteBenchmark/resource/texture/HEART.png create mode 100644 examples/SpriteBenchmark/resource/texture/Pi.png create mode 100644 examples/SpriteBenchmark/resource/texture/atlas.png create mode 100644 examples/SpriteBenchmark/resource/texture/random.png delete mode 100644 src/jGL/spriteRenderer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dde9fc7..56223f51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,6 @@ if (ANDROID) "src/font.cpp" "src/glyph.cpp" "src/shader.cpp" - "src/spriteRenderer.cpp" "src/warning.cpp" "src/jGL/common.cpp" "src/id.cpp" @@ -161,7 +160,6 @@ IF (TEST_SUITE) "src/jGL/OpenGL/*.cpp" "src/jGL/shader.cpp" "src/jGL/warning.cpp" - "src/jGL/spriteRenderer.cpp" "src/id.cpp" "src/jGL/Display/*.cpp" "src/jGL/common.cpp" @@ -219,7 +217,6 @@ IF (TEST_SUITE) ${TEST_SRC} "src/jGL/shader.cpp" "src/jGL/warning.cpp" - "src/jGL/spriteRenderer.cpp" "src/id.cpp" "src/jGL/font.cpp" "src/jGL/glyph.cpp" diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ca0edcf0..54803fdf 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(Particles) add_subdirectory(Sprite) -add_subdirectory(Shape) \ No newline at end of file +add_subdirectory(Shape) +add_subdirectory(SpriteBenchmark) \ No newline at end of file diff --git a/examples/Shape/main.cpp b/examples/Shape/main.cpp index c7b9f910..3f249084 100644 --- a/examples/Shape/main.cpp +++ b/examples/Shape/main.cpp @@ -33,8 +33,9 @@ int main(int argv, char ** argc) jGLInstance->setTextProjection(glm::ortho(0.0,double(resX),0.0,double(resY))); jGLInstance->setMSAA(1); - std::vector> shapes; + std::vector shapes; std::vector trans; + std::vector cols; RNG rng; uint64_t n = 1000000; @@ -46,16 +47,17 @@ int main(int argv, char ** argc) shapes.reserve(n); trans.reserve(n); + cols.reserve(n); for (unsigned i = 0; i < n; i++) { trans.push_back(jGL::Transform(rng.nextFloat(), rng.nextFloat(), 0.0, 0.001f)); + cols.push_back(glm::vec4(rng.nextFloat(), rng.nextFloat(), rng.nextFloat(), 1.0)); shapes.push_back ( - std::make_shared - ( - trans[i], - glm::vec4(rng.nextFloat(), rng.nextFloat(), rng.nextFloat(), 1.0) - ) + { + &trans[i], + &cols[i] + } ); circles->add(shapes[i], std::to_string(i)); diff --git a/examples/Sprite/main.cpp b/examples/Sprite/main.cpp index b6d2bf11..d21de652 100644 --- a/examples/Sprite/main.cpp +++ b/examples/Sprite/main.cpp @@ -9,17 +9,17 @@ int main(int argv, char ** argc) #ifdef MACOS conf.COCOA_RETINA = true; #endif - + jGL::DesktopDisplay display(glm::ivec2(resX, resY), "Sprite", conf); glewInit(); - + jGLInstance = std::move(std::make_unique(display.getRes())); jGL::OrthoCam camera(resX, resY, glm::vec2(0.0,0.0)); camera.setPosition(0.0f, 0.0f); - + jLog::Log log; high_resolution_clock::time_point tic, tock; @@ -85,14 +85,42 @@ int main(int argv, char ** argc) {"highest", jGL::Transform(0.6f, 0.2f, 0.0f, 0.1f)} }; + std::vector animationFrames + { + jGL::TextureRegion(0, 0, 16, 16), + jGL::TextureRegion(16, 0, 16, 16), + jGL::TextureRegion(0, 16, 16, 16), + jGL::TextureRegion(16, 16, 16, 16) + }; + + std::map reg = + { + {"sAtlas1", jGL::TextureRegion(0, 0, 16, 16)}, + {"sAtlas2", jGL::TextureRegion(16, 0, 16, 16)}, + {"sAtlas3", jGL::TextureRegion(0, 16, 16, 16)}, + {"sAtlas4", jGL::TextureRegion(16, 16, 16, 16)}, + {"sAtlasFull", animationFrames[0]}, + {"sAtlasAnimated", jGL::TextureRegion(0, 0, 16, 16)}, + {"sJerboa", jGL::TextureRegion()}, + {"sPi", jGL::TextureRegion()}, + {"sHeart", jGL::TextureRegion()}, + {"sRandom", jGL::TextureRegion()}, + {"lowest", jGL::TextureRegion()}, + {"middle", jGL::TextureRegion()}, + {"highest", jGL::TextureRegion()} + }; + + glm::vec4 colour(1.0); + sprites->setProjection(camera.getVP()); sprites->add ( { - trans["sJerboa"], - jGL::TextureRegion(), - jerboa + &trans["sJerboa"], + ®["sJerboa"], + jerboa.get(), + &colour }, "sJerboa" ); @@ -100,9 +128,10 @@ int main(int argv, char ** argc) sprites->add ( { - trans["sAtlas1"], - jGL::TextureRegion(0, 0, 16, 16), - atlas + &trans["sAtlas1"], + ®["sAtlas1"], + atlas.get(), + &colour }, "sAtlas1" ); @@ -110,9 +139,10 @@ int main(int argv, char ** argc) sprites->add ( { - trans["sAtlas2"], - jGL::TextureRegion(16, 0, 16, 16), - atlas + &trans["sAtlas2"], + ®["sAtlas2"], + atlas.get(), + &colour }, "sAtlas2" ); @@ -120,9 +150,10 @@ int main(int argv, char ** argc) sprites->add ( { - trans["sAtlas3"], - jGL::TextureRegion(0, 16, 16, 16), - atlas + &trans["sAtlas3"], + ®["sAtlas3"], + atlas.get(), + &colour }, "sAtlas3" ); @@ -130,9 +161,10 @@ int main(int argv, char ** argc) sprites->add ( { - trans["sAtlas4"], - jGL::TextureRegion(16, 16, 16, 16), - atlas + &trans["sAtlas4"], + ®["sAtlas4"], + atlas.get(), + &colour }, "sAtlas4" ); @@ -140,28 +172,23 @@ int main(int argv, char ** argc) sprites->add ( { - trans["sAtlasFull"], - jGL::TextureRegion(), - atlas + &trans["sAtlasFull"], + ®["sAtlasFull"], + atlas.get(), + &colour }, "sAtlasFull" ); - std::vector animationFrames - { - jGL::TextureRegion(0, 0, 16, 16), - jGL::TextureRegion(16, 0, 16, 16), - jGL::TextureRegion(0, 16, 16, 16), - jGL::TextureRegion(16, 16, 16, 16) - }; uint8_t animationFrame = 0; sprites->add ( { - trans["sAtlasAnimated"], - animationFrames[animationFrame], - atlas + &trans["sAtlasAnimated"], + ®["sAtlasAnimated"], + atlas.get(), + &colour }, "sAtlasAnimated" ); @@ -170,9 +197,10 @@ int main(int argv, char ** argc) sprites->add ( { - trans["sPi"], - jGL::TextureRegion(), - Pi + &trans["sPi"], + ®["sPi"], + Pi.get(), + &colour }, "sPi" ); @@ -180,9 +208,10 @@ int main(int argv, char ** argc) sprites->add ( { - trans["sHeart"], - jGL::TextureRegion(), - heart + &trans["sHeart"], + ®["sHeart"], + heart.get(), + &colour }, "sHeart" ); @@ -190,9 +219,10 @@ int main(int argv, char ** argc) sprites->add ( { - trans["sRandom"], - jGL::TextureRegion(), - random + &trans["sRandom"], + ®["sRandom"], + random.get(), + &colour }, "sRandom" ); @@ -200,9 +230,10 @@ int main(int argv, char ** argc) sprites->add ( { - trans["lowest"], - jGL::TextureRegion(), - Pi + &trans["lowest"], + ®["lowest"], + Pi.get(), + &colour }, "lowest" ); @@ -210,10 +241,10 @@ int main(int argv, char ** argc) sprites->add ( { - trans["middle"], - jGL::TextureRegion(), - heart, - 0.5f + &trans["middle"], + ®["middle"], + heart.get(), + &colour }, "middle", 1000 @@ -222,9 +253,10 @@ int main(int argv, char ** argc) sprites->add ( { - trans["highest"], - jGL::TextureRegion(), - jerboa + &trans["highest"], + ®["highest"], + jerboa.get(), + &colour }, "highest", 100000 @@ -235,21 +267,27 @@ int main(int argv, char ** argc) 2 ); - std::vector shapeTrans = + std::vector shapeTrans = { jGL::Transform(0.0, 0.0, 0.0, 1.0), jGL::Transform(0.0, 0.0, 0.0, 1.0) }; + std::vector shapeCols = + { + glm::vec4(1.0, 0.0, 0.0, 0.3), + glm::vec4(1.0, 0.0, 0.0, 0.3) + }; - auto bbPi = std::make_shared + auto bbPi = jGL::Shape ( - shapeTrans[0], - glm::vec4(1.0, 0.0, 0.0, 0.3) + &shapeTrans[0], + &shapeCols[0] ); - auto bbHeart = std::make_shared + + auto bbHeart = jGL::Shape ( - shapeTrans[1], - glm::vec4(1.0, 0.0, 0.0, 0.3) + &shapeTrans[1], + &shapeCols[1] ); shapes->add(bbPi, "pi"); @@ -275,7 +313,7 @@ int main(int argv, char ** argc) trans["sHeart"] = jGL::Transform(0.5f, 0.5f, theta, 0.1f); trans["sPi"] = jGL::Transform(0.2f, 0.2f, theta, scale); - sprites->getSprite("sAtlasAnimated").setTextureRegion(animationFrames[animationFrame]); + reg["sAtlasAnimated"] = animationFrames[animationFrame]; if (frameId % 15 == 0) { animationFrame = (animationFrame+1)%animationFrames.size(); @@ -287,26 +325,46 @@ int main(int argv, char ** argc) sprites->draw(); shapes->draw(); + if (frameId == 1) + { + sprites->remove("sJerboa"); + shapes->remove("heart"); + } + else if (frameId == 30) + { + sprites->add + ( + { + &trans["sJerboa"], + ®["sJerboa"], + jerboa.get(), + &colour + }, + "sJerboa" + ); + shapes->add(bbHeart, "heart"); + } + delta = 0.0; for (int n = 0; n < 60; n++) { delta += deltas[n]; } delta /= 60.0; - + std::stringstream debugText; double mouseX, mouseY; display.mousePosition(mouseX,mouseY); debugText << "Delta: " << fixedLengthNumber(delta,6) - << " ( FPS: " << fixedLengthNumber(1.0/delta,4) + << " ( FPS: " << fixedLengthNumber(1.0/delta,4) << ")\n" - << "Render draw time: \n" + << "Render draw time: \n" << " " << fixedLengthNumber(rdt, 6) << "\n" - << "Mouse (" << fixedLengthNumber(mouseX,4) - << "," - << fixedLengthNumber(mouseY,4) + << "Mouse (" << fixedLengthNumber(mouseX,4) + << "," + << fixedLengthNumber(mouseY,4) << ")\n" << "Mouse in Pi's BB? " << sprites->getSprite("sPi").getScreenBoundingBox(camera).in(mouseX, mouseY); @@ -334,7 +392,7 @@ int main(int argv, char ** argc) deltas[frameId] = duration_cast>(tock-tic).count(); frameId = (frameId+1) % 60; - + } jGLInstance->finish(); diff --git a/examples/SpriteBenchmark/CMakeLists.txt b/examples/SpriteBenchmark/CMakeLists.txt new file mode 100644 index 00000000..95827384 --- /dev/null +++ b/examples/SpriteBenchmark/CMakeLists.txt @@ -0,0 +1,25 @@ +set(OUTPUT_NAME SpriteBenchmark) + +file(GLOB_RECURSE SRC + "*.cpp" +) + +if (WINDOWS) + if (RELEASE) + # launch as windows, not console app - so cmd does not open as well + add_link_options(-mwindows) + endif () +else() + # so nautilus etc recognise target as executable rather than .so + add_link_options(-no-pie) +endif() + +include_directories(.) + +add_executable(${OUTPUT_NAME} ${SRC}) + +target_link_libraries(${OUTPUT_NAME} jGL) + +set_target_properties(${OUTPUT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Examples/${OUTPUT_NAME}") + +file(COPY resource DESTINATION "${CMAKE_BINARY_DIR}/Examples/${OUTPUT_NAME}/") \ No newline at end of file diff --git a/examples/SpriteBenchmark/main.cpp b/examples/SpriteBenchmark/main.cpp new file mode 100644 index 00000000..35725768 --- /dev/null +++ b/examples/SpriteBenchmark/main.cpp @@ -0,0 +1,149 @@ +#include + +int main(int argv, char ** argc) +{ + + jGL::DesktopDisplay::Config conf; + + conf.VULKAN = false; + #ifdef MACOS + conf.COCOA_RETINA = true; + #endif + + jGL::DesktopDisplay display(glm::ivec2(resX, resY), "Sprite", conf); + + glewInit(); + + jGLInstance = std::move(std::make_unique(display.getRes())); + + jGL::OrthoCam camera(resX, resY, glm::vec2(0.0,0.0)); + + camera.setPosition(0.0f, 0.0f); + + jLog::Log log; + + high_resolution_clock::time_point tic, tock; + double rdt = 0.0; + + jGLInstance->setTextProjection(glm::ortho(0.0,double(resX),0.0,double(resY))); + jGLInstance->setMSAA(1); + + std::shared_ptr jerboa = jGLInstance->createTexture + ( + std::vector(LOGO32.begin(), LOGO32.end()), + jGL::Texture::Type::RGBA + ); + + int n = 500000; + + std::shared_ptr sprites = jGLInstance->createSpriteRenderer + ( + n + ); + + float scale = camera.screenToWorld(8.0f, 0.0f).x; + + std::vector animationFrames + { + jGL::TextureRegion(0, 0, 16, 16), + jGL::TextureRegion(16, 0, 16, 16), + jGL::TextureRegion(0, 16, 16, 16), + jGL::TextureRegion(16, 16, 16, 16) + }; + + glm::vec4 colour(1.0); + + std::vector trans; + trans.reserve(n); + RNG rng; + for (int i = 0; i < n; i++) + { + trans.push_back(jGL::Transform(rng.nextFloat(), rng.nextFloat(), 0.0, scale)); + } + + for (int i = 0; i < n; i++) + { + sprites->add + ( + {&trans[i], &animationFrames[i % animationFrames.size()], jerboa.get(), &colour}, + std::to_string(i) + ); + } + + sprites->setProjection(camera.getVP()); + + double delta = 0.0; + + float dt = 1.0/600.0; + + while (display.isOpen()) + { + tic = high_resolution_clock::now(); + + jGLInstance->beginFrame(); + + jGLInstance->clear(); + + for (auto & tr : trans) + { + tr.x = tr.x+dt*(rng.nextFloat()-0.5); + tr.y = tr.y+dt*(rng.nextFloat()-0.5); + tr.theta = tr.theta; + tr.scaleX = tr.scaleX; + } + + sprites->draw(); + + delta = 0.0; + for (int n = 0; n < 60; n++) + { + delta += deltas[n]; + } + delta /= 60.0; + + std::stringstream debugText; + + double mouseX, mouseY; + display.mousePosition(mouseX,mouseY); + + debugText << "Delta: " << fixedLengthNumber(delta,6) + << " ( FPS: " << fixedLengthNumber(1.0/delta,4) + << ")\n" + << "Render draw time: \n" + << " " << fixedLengthNumber(rdt, 6) << "\n" + << "Mouse (" << fixedLengthNumber(mouseX,4) + << "," + << fixedLengthNumber(mouseY,4) + << ")\n"; + + jGLInstance->text( + debugText.str(), + glm::vec2(resX*0.5f, resY-64.0f), + 0.5f, + glm::vec4(0.0f,0.0f,0.0f,1.0f), + glm::bvec2(true,true) + ); + + if (frameId == 30) + { + if (log.size() > 0) + { + std::cout << log << "\n"; + } + } + + jGLInstance->endFrame(); + + display.loop(); + + tock = high_resolution_clock::now(); + + deltas[frameId] = duration_cast>(tock-tic).count(); + frameId = (frameId+1) % 60; + + } + + jGLInstance->finish(); + + return 0; +} \ No newline at end of file diff --git a/examples/SpriteBenchmark/main.h b/examples/SpriteBenchmark/main.h new file mode 100644 index 00000000..2d5ad74c --- /dev/null +++ b/examples/SpriteBenchmark/main.h @@ -0,0 +1,45 @@ +#ifndef MAIN_H +#define MAIN_H + +#include +#include + +#include +#include +#include + +#include + +#include + +#include +using namespace std::chrono; + +const int resX = 800; +const int resY = 1000; + +uint8_t frameId = 0; +double deltas[60]; + +std::unique_ptr jGLInstance; + +std::string fixedLengthNumber(double x, unsigned length) +{ + std::string d = std::to_string(x); + std::string dtrunc(length,' '); + for (unsigned c = 0; c < dtrunc.length(); c++/*ayy lmao*/) + { + + if (c >= d.length()) + { + dtrunc[c] = '0'; + } + else + { + dtrunc[c] = d[c]; + } + } + return dtrunc; +} + +#endif /* MAIN_H */ diff --git a/examples/SpriteBenchmark/rand.cpp b/examples/SpriteBenchmark/rand.cpp new file mode 100644 index 00000000..8bd4a7e1 --- /dev/null +++ b/examples/SpriteBenchmark/rand.cpp @@ -0,0 +1,5 @@ +#include + +std::uniform_real_distribution RNG::floatU; +std::random_device RNG::device; +std::mt19937 RNG::engine(device()); diff --git a/examples/SpriteBenchmark/rand.h b/examples/SpriteBenchmark/rand.h new file mode 100644 index 00000000..d703110c --- /dev/null +++ b/examples/SpriteBenchmark/rand.h @@ -0,0 +1,22 @@ +#ifndef RAND_H +#define RAND_H + +#include + +class RNG +{ + +public: + + float nextFloat(){ return floatU(engine); } + +private: + + static std::uniform_real_distribution floatU; + static std::random_device device; + static std::mt19937 engine; + +}; + +#endif /* RAND_H */ + diff --git a/examples/SpriteBenchmark/resource/texture/HEART.png b/examples/SpriteBenchmark/resource/texture/HEART.png new file mode 100644 index 0000000000000000000000000000000000000000..9d44ab97cfc2cb61acd666ef9bcdfdd1fcbba86e GIT binary patch literal 6158 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 literal 0 HcmV?d00001 diff --git a/examples/SpriteBenchmark/resource/texture/Pi.png b/examples/SpriteBenchmark/resource/texture/Pi.png new file mode 100644 index 0000000000000000000000000000000000000000..c811289d59dedac843c4dcec639020b566e87b9c GIT binary patch literal 2664 zcmV-u3YYbXP)430THOLwH7Ib`ofwRNerNg#((e;|1pt2 z)EEP5z=XsY6BB|lAQ~hXf(hjzU>mJG+D0g_TSO>OOIxff*!KFz>DBAzclX|zd(N5P z-ri3#p}_8$ncnX`GjnF<+yQKv1FQf}1{MK}fd#5< zebAw6pHR3SchqbKpXQwsiQh8`uM30yrJ`4Y16jMIEj@ zkpH2s08R#e2b^HioDOd`=6|RofTh5_z>?5HJXALE`uw?crJABw!-{4`m+UQ*;l% zZR|&$>qONL4g%XrAFAw%P8kDk0G7~$UdzCXf#tn^IFf$@zXk3F{scS+>;+~b5yc+? z!;1CgYyz%Ff*$(~>=zjZ&I7JG@=psk^S}P=tMT(0^7kCf?dT})5Td-Q;L+!m>MNG( zsb1k&Fax+bqP-7yi2Ah|MQ;xB2PHeD z6d(9#LtEQ`I|F}b1bA=5dW$@!Xe*YB6m4x*wAGWM09H4&bxXwWTm&4`u-+n%DB6l; zt)eY+0pz@y=Ht~F5%u1vP;arEAJGO)mZR5~r#u>*dw_)v?L1Dn`<;QVyUc*CiuPhy zr)X=FqODSL0le7IPK^6s1svb7-Xc!}uPEA!VcH3x$UVfls@=#C63X`?>nkh2ifDr- z!@#TP^~Y*Yp_Ca3`tmAr9M7C$lxZih5?GHc&E_LJ zc9S`by!D%bTanOjC~pN$jrhH(cvRV5D4O$`hk<`7+Uq;6Lig>@NPAyl06A@=)tBqM z8lGay6m+A1Ad|mwWt$z`2U{HsR>ayak{g{mV(Y2e201J$u&xkhcKNLlR49k|8mLRA>v@ zJp$;-chO(|J?Ywm|7Q?*p`=|g_8@gZg>h{32>T$ z-INnRZTD|}0%$Ux0{Ezr-IM~*-2H==kNmticG04xOE+7-Zeu$lcI#wM>o9UiIK#=7MN-{$+0 z@6~IUR3YGn=x0U0&9w&wtcQTb#9bJvLn`-w3HnRVWbWTu02ZP z1)zOWw#Zfr`EDJt=#$$O@LpI6U=UjYqzD1O6Zvj}HtuHtidYHY9Be->kzxg~!NBG} zNqnWmW^vEA3MfBY>6Ij*~?W;P?S0V8qydUmOH25+eYw;1BpGg0RjzXf3c{Vg&FJ^;VSQ zeRj?|S<`Z3`@w_?U_O4)Kk&Z>X6*s2E}29VDu8tnztaToi=Y-M?TdJN&su~&Ot0NP z@IM6%_RF+0u{~@OOo#wxp`RmvDt6+(ZrOUL>^-pW1roN~_D3fzq( zjC>9m_VS@I?-_hTvQ_K^zL~laQ!u7sq)Gs5H7W_DpYG59kUmN1 z*aH^z*nSnYs{Bl=Bc2C5+r+KNVUF=c^^Ya0w__4>fLrkQ03Y+{ zTt|J@BX6b0!+(uFykXQK$H=~cq=B^*K)-KN9rX+WUq?1e_LvQ+yC zvTkqk;3t3|V~~_10000H$*# literal 0 HcmV?d00001 diff --git a/examples/SpriteBenchmark/resource/texture/atlas.png b/examples/SpriteBenchmark/resource/texture/atlas.png new file mode 100644 index 0000000000000000000000000000000000000000..12865efff137e16b070c80d1e29d2c0d417558c4 GIT binary patch literal 574 zcmV-E0>S->P)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10n155 zK~z|U?UheU0znvuA7lNK9wMZO+Ae~0D2RfHI;bb@+BfLdsY{>0!h3b^J4g^A1zjqr zQv`bP5EUC0W_A#E1+@-J;5xfaZe@@!4D7u7o8LV9GV`trc*8-&VlgMn>2tLD8{%&R z_?zR`0j7Wxpxhj1z{}+s*0FkWlZ!)CtFFoceK-P@{1O zpG|pDCmhvvRo?vBqQ~8v=y@0Dw(j4{rkYpcTab^KotAAUOxK~kcj|uE)e~NVTUVcJ=l8-a@djvEkGY zrQXIC=QnWG<3+ijsZVORdI3T9==K>(M~pMqXAIQx$5c*MDe-csHBg}TrT}n*WbCOF zrMm!Exiz9wzKQ_9G~vR64iCKd{f>$^{>`8xnVHtR<9Du%bpqN^4&M=;z0C86N8ciq zLakb?-w8r6&_U%hG6C;ukh&T z=$AG;g62Hh1w+&0)whhxM)^^wgO;hfni>EwFfd5U&Q4fbaudAb3v+UED!1WLH2($fr<#Rz^uFsl4*?-r4fn+DmvMac=c<9SqBTo&?8G zrh&CD4MatwvQcp{F-XqU5b-p*OBpQ2rlwTC#eU8KuRC{eWHS4PZFMUiC>Vev9U4NOulsCyj}fSL}a*ibCT1pKgGpGnpe?MTjN82Kf7yxRv3*+~ zdv|qoRj5XB^*n zbBKB;dna`?A7K>E*xog%HOprl5cv$kwD!M+NW;+UXht?)uQ@gwMKn(r1)PKNi4bXH?<{H6!gZWwK9h$ZC zjHi226(X>iSY~tJZ*p{nOqOlrhTY=o1tY>P!$) zU!Q4b%6~nEPlDFe*3Qm$#+ki1JUsMS9+8v(IHsKh6}%eE&qxike&FOJriNmB8JxyU z4sC10nORtvR^$zT%ZP8N)}}xwnnMI6BqT;wCSLha1KD_)$$!0#M$t&_LwE|b z3Ux-{+_^CGvfCzc(zc;@OyYRMxgGN>9~TEHS%c(hbVzn~cCY)84h0H23)NDIRD+q> z**Ar}*I_c+o}P*+Sl`#S9L4!Y$HaApjg1WuAR{ZDpK4kABq=RTK17vsWC1{~ zNvWf&D^cm;RC5T$�)uccogM=kap$j}ho#Oo3^*`25EF$7BogZoDJUq& zw&9QK#;&YLbHK*NrexF|{3Y&pbUMAg$S}R?W+y`YzA3y7JcCA~ODZet_Mki`qvy}N z(v)nN{V(}*)Bvq@61)HWV*+9@^Jg0kFCM0o*P0?@B%1zS&fm=rb{<$?RShaKiA_u6 zEiscOJJC-VEOvIfjfx3a7sX<+gCipm zlauz_J3CHeE*@A!xI@10V^yloKDpG<@l*U zmK|DwyM0><6fSCH#LUdxoQz3#Q|4cvZewtEc6J=fC&(%)ItR`n(SVb#u5Ojb5|5@WD3A%2-7^D5X-*{p}@A&`AtVPLfOL zu`^JPH*RX;7ccU#v9aMd!B-_^Wax#kCnL3EKzo_x)?Zy+9e?S;H`FTv(&p0X+;BMD z?1hJiN2z^QI8qx(HGntS8z~(R=3V0#5GZ)m2d_%{@$b~!!On`A2Z(Ny24y&3tIqFV z>Iwd5f2!9+{q`E*HLEBL#aRiZyu)jxBOS$B>c5K0Z3k*HGBU<2`a%@( z#lzQEtZf0L)5UoCWIfQ0l27T%VHAJ=B9-rNKwhZ|7AmFOD3pQJ$qnUE_{-jtq|>os znqu|R?&TJ0QI%n{`9e9Go14LanQ_HWy1KWqQDgZYei6!nN2eD&ecCm93{!RO z?}$Y5C8ee5{-;!F6%{Vf4lSDkcM5CIu(05~yp(oK+nU?qxvh=&wCqxkN+~_x1v|cX#ujJwt%OZE0;S%Dk*I>x$p> zw{Nknt=gXBRgkc-F!OK8$W{Q1_Mm5b`^hUF`G5I=rGvxy7^I95QBg=VHKTgX8o0=N zW3I}DJv33vCalGiz|N;VpCQq@-9kuvHOR1cRF>MyIh_Mo%Y0#vzE}jrB%WnraAR shader, - std::vector>> & shapes, + std::vector> & shapes, UpdateInfo info = UpdateInfo() ); diff --git a/include/jGL/OpenGL/glSpriteRenderer.h b/include/jGL/OpenGL/glSpriteRenderer.h index 8d4c7add..05da6184 100644 --- a/include/jGL/OpenGL/glSpriteRenderer.h +++ b/include/jGL/OpenGL/glSpriteRenderer.h @@ -6,10 +6,10 @@ #include namespace jGL::GL -{ +{ /** * @brief Opengl implementation of SpriteRenderer - * + * */ class glSpriteRenderer : public SpriteRenderer { @@ -23,8 +23,8 @@ namespace jGL::GL textureRegion = std::vector(sizeHint*textureRegionDim+padSprites*textureRegionDim,0.0f); textureOptions = std::vector(sizeHint*textureOptionsDim+padSprites*textureOptionsDim,0.0f); initGL(); - defaultShader = std::make_shared(vertexShader, fragmentShader); - defaultShader->use(); + shader = std::make_shared(vertexShader, fragmentShader); + shader->use(); } ~glSpriteRenderer() @@ -32,25 +32,28 @@ namespace jGL::GL freeGL(); } - void draw(std::shared_ptr shader, std::multimap ids); - void draw(std::multimap ids) { draw(defaultShader, ids); } - private: + void draw + ( + std::shared_ptr shader, + std::vector> & sprites + ); + GLuint vao, a_position, a_xytheta, a_scale, a_textureRegion, a_textureOption; - float quad[6*4] = + float quad[6*4] = { // positions / texture coords 0.5f, 0.5f, 1.0f, 1.0f, // top right 0.5f, -0.5f, 1.0f, 0.0f, // bottom right -0.5f, -0.5f, 0.0f, 0.0f, // bottom left - -0.5f, 0.5f, 0.0f, 1.0f, // top left + -0.5f, 0.5f, 0.0f, 1.0f, // top left -0.5f, -0.5f, 0.0f, 0.0f, // bottom left 0.5f, 0.5f, 1.0f, 1.0f // top right }; - std::vector xytheta; + std::vector xytheta; size_t xythetaDim = 3; size_t xythetaAttribute = 1; @@ -71,9 +74,7 @@ namespace jGL::GL void initGL(); void freeGL(); - std::shared_ptr defaultShader; - - const char * vertexShader = + const char * vertexShader = "#version " GLSL_VERSION "\n" "precision lowp float; precision lowp int;\n" "layout(location=0) in vec4 a_position;\n" @@ -97,7 +98,7 @@ namespace jGL::GL "alpha = a_textureOptions.y;\n" "}"; - const char * fragmentShader = + const char * fragmentShader = "#version " GLSL_VERSION "\n" "precision lowp float; precision lowp int;\n" "uniform sampler2D sampler0;\n" @@ -108,7 +109,7 @@ namespace jGL::GL "flat in float alpha;\n" "flat in int tex;\n" "layout(location=0) out vec4 colour;\n" - "void main(){\n" + "void main(){\n" // is this mental? "if (tex == 0) {colour = texture(sampler0, texCoord);}\n" "else if (tex == 1) {colour = texture(sampler1, texCoord);}\n" diff --git a/include/jGL/Vulkan/vkShapeRenderer.h b/include/jGL/Vulkan/vkShapeRenderer.h index 1064a0d2..0e3eb16f 100644 --- a/include/jGL/Vulkan/vkShapeRenderer.h +++ b/include/jGL/Vulkan/vkShapeRenderer.h @@ -17,7 +17,7 @@ namespace jGL::Vulkan void draw ( std::shared_ptr shader, - std::vector>> & shapes, + std::vector> & shapes, UpdateInfo info = UpdateInfo() ){} }; diff --git a/include/jGL/Vulkan/vkSpriteRenderer.h b/include/jGL/Vulkan/vkSpriteRenderer.h index b40b0587..e6df180a 100644 --- a/include/jGL/Vulkan/vkSpriteRenderer.h +++ b/include/jGL/Vulkan/vkSpriteRenderer.h @@ -13,14 +13,12 @@ namespace jGL::Vulkan vkSpriteRenderer(size_t sizeHint) : SpriteRenderer(sizeHint) {} - - void draw(std::shared_ptr shader, std::multimap ids) {TODO("jGL::Vulkan::vkSprite::draw");} - void draw(std::multimap ids) {TODO("jGL::Vulkan::vkSprite::draw");} - - - void draw(std::shared_ptr shader, std::vector ids) {TODO("jGL::Vulkan::vkSprite::draw");} - void draw(std::vector ids) {TODO("jGL::Vulkan::vkSprite::draw");} - + private: + void draw + ( + std::shared_ptr shader, + std::vector> & sprites + ){} }; } diff --git a/include/jGL/priorityStore.h b/include/jGL/priorityStore.h index d19931eb..02db87d9 100644 --- a/include/jGL/priorityStore.h +++ b/include/jGL/priorityStore.h @@ -61,7 +61,7 @@ class PriorityStore cache.reserve(sizeHint); } - void clear() + virtual void clear() { idToElement.clear(); cache.clear(); @@ -75,7 +75,7 @@ class PriorityStore * @param priority its priority. * @remark Throws std::runtime_error if the id already exists. */ - void add(std::shared_ptr s, ElementId id, Priority priority = 0) + virtual void add(T s, ElementId id, Priority priority = 0) { if (idToElement.find(id) != idToElement.end()) { @@ -87,20 +87,20 @@ class PriorityStore ( cache.begin(), cache.end(), - std::pair(Info(id, priority), nullptr), + priority, [] ( - std::pair> l, - std::pair> r + Priority p, + std::pair r ) { - return l.first.priority < r.first.priority; + return p < r.first.priority; } ); cache.insert(pos, std::pair(Info(id, priority), s)); } - void remove(ElementId id) + virtual void remove(ElementId id) { if (idToElement.find(id) == idToElement.end()) { return; } @@ -110,7 +110,7 @@ class PriorityStore ( cache.begin(), cache.end(), - [id](std::pair> v) + [id](std::pair v) { return v.first.id == id; } @@ -134,16 +134,16 @@ class PriorityStore * @brief Return a vector from overriding priorities. * * @param oids overriding priorities. - * @return std::vector>> cached values. + * @return std::vector> cached values. * @remark Overriding is expensive, but useful for drawing partially with * modest element counts. */ - std::vector>> vectorise + std::vector> vectorise ( std::multimap & oids ) { - std::vector>> s; + std::vector> s; s.reserve(oids.size()); for (const auto & id : oids) { @@ -152,19 +152,21 @@ class PriorityStore return s; } - std::shared_ptr & operator [](ElementId id) { return idToElement[id].first; } + T & operator [](ElementId id) { return idToElement[id].first; } - typename std::vector>>::const_iterator begin() const { return cache.cbegin(); } - typename std::vector>>::const_iterator end() const { return cache.cend(); } + typename std::vector>::const_iterator begin() const { return cache.cbegin(); } + typename std::vector>::const_iterator end() const { return cache.cend(); } uint64_t size() const { return cache.size(); } + bool hasId(const ElementId id) const { return idToElement.find(id) != idToElement.end(); } + protected: // fast lookup of ids - std::unordered_map, Priority>> idToElement; + std::unordered_map> idToElement; // contiguous for efficient drawing/iteration - std::vector>> cache; + std::vector> cache; }; #endif /* PRIORITYSTORE_H */ diff --git a/include/jGL/shape.h b/include/jGL/shape.h index 53ab74d3..fe657779 100644 --- a/include/jGL/shape.h +++ b/include/jGL/shape.h @@ -8,28 +8,32 @@ namespace jGL { /** * @brief A drawable shape - * @remark Detailed geometry is assumed defined in the shader. Circle and Rectangle are provided in ShapeRenderer. + * @remark Detailed geometry is assumed defined in the shader. Circle and Rectangle are provided in ShapeRenderer. */ class Shape { - + public: - Shape(const Transform & tra, glm::vec4 c) + Shape() + : transform(nullptr), colour(nullptr) + {} + + Shape(const Transform * tra, const glm::vec4 * c) : transform(tra), colour(c) {} - const Transform & transform; - glm::vec4 colour; + const Transform * transform; + const glm::vec4 * colour; /** * @brief Get the WorldBoundingBox of the Shape. - * - * @return WorldBoundingBox + * + * @return WorldBoundingBox */ WorldBoundingBox getWorldBoundingBox() const { - WorldBoundingBox wbb = + WorldBoundingBox wbb = { { glm::vec2(-0.5, -0.5), @@ -39,11 +43,11 @@ namespace jGL } }; - float ct = std::cos(transform.theta); float st = std::sin(transform.theta); + float ct = std::cos(transform->theta); float st = std::sin(transform->theta); glm::mat2 rot(ct, -st, st, ct); - glm::vec2 pos(transform.x, transform.y); - glm::vec2 scale(transform.scaleX, transform.scaleY); - + glm::vec2 pos(transform->x, transform->y); + glm::vec2 scale(transform->scaleX, transform->scaleY); + for (uint8_t i = 0; i < wbb.vertices.size(); i++) { @@ -55,9 +59,9 @@ namespace jGL /** * @brief Get the ScreenBoundingBox of the Shape. - * + * * @param camera for projection to the screen. - * @return ScreenBoundingBox + * @return ScreenBoundingBox */ ScreenBoundingBox getScreenBoundingBox(const OrthoCam & camera) { diff --git a/include/jGL/shapeRenderer.h b/include/jGL/shapeRenderer.h index 7ce7e62f..5319f454 100644 --- a/include/jGL/shapeRenderer.h +++ b/include/jGL/shapeRenderer.h @@ -64,10 +64,10 @@ namespace jGL : PriorityStore(sizeHint), shader(shader) {} - std::shared_ptr getShape(ShapeId id) { return this->operator[](id); } + Shape & getShape(ShapeId id) { return this->operator[](id); } - const Transform & getTransform(ShapeId id) { return getShape(id)->transform; } - const glm::vec4 & getColour(ShapeId id) { return getShape(id)->colour; } + const Transform * getTransform(ShapeId id) { return getShape(id).transform; } + const glm::vec4 * getColour(ShapeId id) { return getShape(id).colour; } /** * @brief Draw with overriding render priority and shader. @@ -86,7 +86,7 @@ namespace jGL UpdateInfo info = UpdateInfo() ) { - std::vector>> shapes = vectorise(ids); + std::vector> shapes = vectorise(ids); draw(shader, shapes, info); } @@ -105,7 +105,7 @@ namespace jGL UpdateInfo info = UpdateInfo() ) { - std::vector>> shapes = vectorise(ids); + std::vector> shapes = vectorise(ids); draw(shader, shapes, info); } @@ -144,7 +144,7 @@ namespace jGL virtual void draw ( std::shared_ptr shader, - std::vector>> & shapes, + std::vector> & shapes, UpdateInfo info = UpdateInfo() ) = 0; diff --git a/include/jGL/sprite.h b/include/jGL/sprite.h index eebdfa98..2288300d 100644 --- a/include/jGL/sprite.h +++ b/include/jGL/sprite.h @@ -10,11 +10,11 @@ /** * @brief A drawable graphic. - * + * * Observes a Transform (position, orientation, scale), and a Texture. - * + * * Rendered using the TextureRegion (pixel units) region of the Texture, at the alpha value. - * + * */ namespace jGL @@ -24,6 +24,8 @@ namespace jGL public: + Sprite() = default; + /** * @brief Construct a Sprite * @@ -33,69 +35,31 @@ namespace jGL * @param alpha Transparency modifier (alpha * texture alpha) */ Sprite - ( - const Transform & tra, - TextureRegion to, - const std::shared_ptr tex, - float alpha = 1.0f + ( + Transform * tra, + TextureRegion * to, + Texture * tex, + glm::vec4 * colour ) - : transform(tra), texture(tex), alpha(std::clamp(alpha, 0.0f, 1.0f)), texOffset(toNormalised(to)) + : transform(tra), + texOffset(to), + texture(tex), + colour(colour) {} - /** - * @brief Sets the sprite alpha modifier. - * - * @param a alpha value, clamping is applied: std::clamp(a, 0.0f, 1.0f). - */ - inline virtual void setAlpha(float a) { alpha = std::clamp(a, 0.0f, 1.0f); } - - /** - * @brief Get the alpha modifer. - * - * @return const float, which is in [0.0, 1.0]. - */ - const float getAlpha() const { return alpha; } - - /** - * @brief Get the TextureRegion in pixel units. - * - * @return TextureRegion - */ - TextureRegion getTextureRegion() const - { - return fromNormalised(texOffset); - } - - /** - * @brief Get the NormalisedTextureRegion in normalised units. - * - * @return TextureRegion - */ - NormalisedTextureRegion getNormalisedTextureRegion() const - { - return texOffset; - } - - /** - * @brief Set the Texture Offset from a pixel region. - * - * @remark Values outside of the textures pixel range will be clamped. - * @remark Lengths lx or ly < 0 will be set to maximum. - * - */ - void setTextureRegion(TextureRegion to) { texOffset = toNormalised(to); } - - const Transform & transform; - const std::shared_ptr texture; + Transform * transform; + TextureRegion * texOffset; + Texture * texture; + glm::vec4 * colour; /** * @brief Get the WorldBoundingBox of the Sprite. - * - * @return WorldBoundingBox + * + * @return WorldBoundingBox */ WorldBoundingBox getWorldBoundingBox() const { - WorldBoundingBox wbb = + WorldBoundingBox wbb = { { glm::vec2(-0.5, -0.5), @@ -105,11 +69,11 @@ namespace jGL } }; - float ct = std::cos(transform.theta); float st = std::sin(transform.theta); + float ct = std::cos(transform->theta); float st = std::sin(transform->theta); glm::mat2 rot(ct, -st, st, ct); - glm::vec2 pos(transform.x, transform.y); - glm::vec2 scale(transform.scaleX, transform.scaleY); - + glm::vec2 pos(transform->x, transform->y); + glm::vec2 scale(transform->scaleX, transform->scaleY); + for (uint8_t i = 0; i < wbb.vertices.size(); i++) { @@ -121,9 +85,9 @@ namespace jGL /** * @brief Get the ScreenBoundingBox of the Sprite. - * + * * @param camera for projection to the screen. - * @return ScreenBoundingBox + * @return ScreenBoundingBox */ ScreenBoundingBox getScreenBoundingBox(const OrthoCam & camera) { @@ -139,11 +103,16 @@ namespace jGL return sbb; } + NormalisedTextureRegion getNormalisedTextureRegion() const + { + return toNormalised(*texOffset); + } + protected: - NormalisedTextureRegion toNormalised(TextureRegion to) + NormalisedTextureRegion toNormalised(TextureRegion to) const { - glm::vec3 whc = texture->size(); + glm::vec3 whc = texture->size(); if (to.lx == 0){ to.lx = whc.x; } if (to.ly == 0){ to.ly = whc.y; } return NormalisedTextureRegion( @@ -164,10 +133,6 @@ namespace jGL uint16_t(to.ly * whc.y) ); } - - float alpha; - NormalisedTextureRegion texOffset; - }; } diff --git a/include/jGL/spriteRenderer.h b/include/jGL/spriteRenderer.h index 380bd1a4..333f63db 100644 --- a/include/jGL/spriteRenderer.h +++ b/include/jGL/spriteRenderer.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -12,132 +13,100 @@ namespace jGL { - /** + /** * @brief User name for a Sprite. - * @typedef SpriteId + * @typedef SpriteId * */ typedef std::string SpriteId; /** * @brief Renders sprites in batches, with optional render priority. - * + * * @remark Currently there are 4 texture slots loaded at once. * @remark Keeping to 4 textures is most efficient (1 draw call), atlas textures are useful for this. - * @remark RenderPriority of Sprites may lead to inefficient batching across textures. + * @remark RenderPriority of Sprites may lead to inefficient batching across textures. * Try to keep similar RenderPriority within the same texture/ group of 4 textures. */ - class SpriteRenderer + class SpriteRenderer : public PriorityStore { public: /** * @brief Largest number of concurrent textures bound for one batch. - * + * */ static const uint8_t MAX_BATCH_BOUND_TEXTURES = MAX_SPRITE_BATCH_BOUND_TEXTURES; - + /** * @brief Construct a new SpriteRenderer. - * + * * @param sizeHint Reserve some memory for this many Sprites. */ SpriteRenderer(size_t sizeHint = 8) - { - sprites.reserve(sizeHint); - textures.reserve(MAX_BATCH_BOUND_TEXTURES); - } + : PriorityStore(sizeHint) + {} - Sprite & getSprite(SpriteId id); - - const Transform & getTransform(SpriteId id) { return getSprite(id).transform; } - - /** - * @brief Get a Sprites TextureRegion - * @remark In pixel units, see TextureRegion::getTextureRegion() - * - * @param id - * @return const TextureRegion - */ - const TextureRegion getTextureRegion(SpriteId id) { return getSprite(id).getTextureRegion(); } + Sprite & getSprite(SpriteId id){ return this->operator[](id); } /** * @brief Draw with overriding render priority and shader. - * + * * @param shader An OpenGL Shader to draw all the Sprites with. * @param ids Render priorities for the Sprites. + * @remark Overriding priorities with many sprites performs poorly on cpu. + * Consider SpriteRenderer::updatePriority to cache priority. */ - virtual void draw(std::shared_ptr shader, std::multimap ids) = 0; + virtual void draw + ( + std::shared_ptr shader, + std::multimap ids + ) + { + std::vector> sprites = vectorise(ids); + draw(shader, sprites); + } /** * @brief Draw with overriding render priority. - * + * * @param ids Render priorities for the Sprites. + * @remark Overriding priorities with many sprites performs poorly on cpu. + * Consider SpritRenderer::updatePriority to cache priority. */ - virtual void draw(std::multimap ids) = 0; - + virtual void draw(std::multimap ids) + { + std::vector> sprites = vectorise(ids); + draw(shader, sprites); + } + /** * @brief Draw with overriding shader. - * - * @param shader An Shader to draw all the Sprites with. + * + * @param shader A Shader to draw all the Sprites with. */ - virtual void draw(std::shared_ptr shader) { draw(shader, ids); } + virtual void draw(std::shared_ptr shader) + { + draw(shader, cache); + } /** * @brief Draw with default shader and priority. - * + * */ - virtual void draw() { draw(ids); } - - virtual void add(Sprite s, SpriteId id, RenderPriority priority = 0); - - virtual void remove(SpriteId id) - { - if (sprites.find(id) != sprites.end()) - { - sprites.erase(id); - } - - for (auto & e : ids) - { - if (e.second == id) - { - ids.erase(e.first); - break; - } - } - } - - bool hasId(const SpriteId id) const { return sprites.find(id) != sprites.end(); } - - virtual void clear() { ids.clear(); sprites.clear(); } + virtual void draw() { draw(shader, cache); } virtual void setProjection(glm::mat4 p) {projection = p;} - virtual void updatePriority(SpriteId id, RenderPriority newPriority) - { - if (sprites.find(id) == sprites.end()){ return; } - - std::multimap::iterator iter; - for (iter = ids.begin(); iter != ids.end(); iter++) - { - if (iter->second == id) - { - ids.erase(iter); - ids.insert(std::pair(newPriority, id)); - break; - } - } - } - protected: - std::vector> textures; - - std::unordered_map sprites; - std::unordered_map spriteToTexture; + virtual void draw + ( + std::shared_ptr shader, + std::vector> & sprites + ) = 0; - std::multimap ids; + std::shared_ptr shader; glm::mat4 projection = glm::mat4(0.0f); diff --git a/src/jGL/OpenGL/glShapeRenderer.cpp b/src/jGL/OpenGL/glShapeRenderer.cpp index 896a3e7a..3cc654f3 100644 --- a/src/jGL/OpenGL/glShapeRenderer.cpp +++ b/src/jGL/OpenGL/glShapeRenderer.cpp @@ -48,7 +48,7 @@ namespace jGL::GL void glShapeRenderer::draw ( std::shared_ptr shader, - std::vector>> & shapes, + std::vector> & shapes, UpdateInfo info ) { @@ -70,23 +70,23 @@ namespace jGL::GL { if (info.xytheta) { - xytheta[i*xythetaDim] = shape.second->transform.x; - xytheta[i*xythetaDim+1] = shape.second->transform.y; - xytheta[i*xythetaDim+2] = shape.second->transform.theta; + xytheta[i*xythetaDim] = shape.second.transform->x; + xytheta[i*xythetaDim+1] = shape.second.transform->y; + xytheta[i*xythetaDim+2] = shape.second.transform->theta; } if (info.scale) { - scale[i*scaleDim] = shape.second->transform.scaleX; - scale[i*scaleDim+1] = shape.second->transform.scaleY; + scale[i*scaleDim] = shape.second.transform->scaleX; + scale[i*scaleDim+1] = shape.second.transform->scaleY; } if (info.colour) { - colours[i*coloursDim] = shape.second->colour.r; - colours[i*coloursDim+1] = shape.second->colour.g; - colours[i*coloursDim+2] = shape.second->colour.b; - colours[i*coloursDim+3] = shape.second->colour.a; + colours[i*coloursDim] = shape.second.colour->r; + colours[i*coloursDim+1] = shape.second.colour->g; + colours[i*coloursDim+2] = shape.second.colour->b; + colours[i*coloursDim+3] = shape.second.colour->a; } i += 1; diff --git a/src/jGL/OpenGL/glSpriteRenderer.cpp b/src/jGL/OpenGL/glSpriteRenderer.cpp index 8d4a767a..b28b8dcc 100644 --- a/src/jGL/OpenGL/glSpriteRenderer.cpp +++ b/src/jGL/OpenGL/glSpriteRenderer.cpp @@ -2,10 +2,14 @@ namespace jGL::GL { - void glSpriteRenderer::draw(std::shared_ptr shader, std::multimap ids) + void glSpriteRenderer::draw + ( + std::shared_ptr shader, + std::vector> & sprites + ) { - uint32_t n = ids.size(); + uint32_t n = idToElement.size(); if (xytheta.size() < xythetaDim*n) { @@ -17,46 +21,49 @@ namespace jGL::GL initGL(); } - std::vector textureIndices(ids.size(), 0); - std::vector>> batches; + std::vector>> batches; batches.reserve(n); uint64_t i = 0; - std::vector batch; + std::vector batch; - for (auto & sid : ids) + for (auto & sprite : sprites) { - size_t textureIndex = spriteToTexture[sid.second]; - bool newTexture = std::find(batch.begin(), batch.end(), textureIndex) == batch.end(); - if (newTexture) + size_t textureIndex; + Id textureId = sprite.second.texture->getId(); + auto is_equal = [textureId](Texture * t) { return t->getId() == textureId; }; + auto match = std::find_if(batch.begin(), batch.end(), is_equal); + if (match == batch.end()) { if (batch.size() == MAX_BATCH_BOUND_TEXTURES) { batches.push_back(std::pair(i, batch)); batch.clear(); } - batch.push_back(textureIndex); + batch.push_back(sprite.second.texture); + textureIndex = batch.size()-1; + } + else + { + textureIndex = std::distance(batch.begin(), match); } - const Sprite & sprite = sprites.at(sid.second); - const Transform & trans = sprite.transform; - const NormalisedTextureRegion toff = sprite.getNormalisedTextureRegion(); - const float alpha = sprite.getAlpha(); + const NormalisedTextureRegion toff = sprite.second.getNormalisedTextureRegion(); - xytheta[i*xythetaDim] = trans.x; - xytheta[i*xythetaDim+1] = trans.y; - xytheta[i*xythetaDim+2] = trans.theta; + xytheta[i*xythetaDim] = sprite.second.transform->x; + xytheta[i*xythetaDim+1] = sprite.second.transform->y; + xytheta[i*xythetaDim+2] = sprite.second.transform->theta; - scale[i*scaleDim] = trans.scaleX; - scale[i*scaleDim+1] = trans.scaleY; + scale[i*scaleDim] = sprite.second.transform->scaleX; + scale[i*scaleDim+1] = sprite.second.transform->scaleY; textureRegion[i*textureRegionDim] = toff.tx; textureRegion[i*textureRegionDim+1] = toff.ty; textureRegion[i*textureRegionDim+2] = toff.lx; textureRegion[i*textureRegionDim+3] = toff.ly; - textureOptions[i*textureOptionsDim] = float(std::distance(batch.begin(), std::find(batch.begin(), batch.end(), textureIndex))); - textureOptions[i*textureOptionsDim+1] = alpha; + textureOptions[i*textureOptionsDim] = float(textureIndex); + textureOptions[i*textureOptionsDim+1] = sprite.second.colour->a; i++; } @@ -65,7 +72,7 @@ namespace jGL::GL uint64_t b = 0; uint64_t current = 0; uint64_t next = batches[b].first-1; - std::vector::const_iterator biter; + std::vector::const_iterator biter; while (b < batches.size()) { @@ -73,7 +80,7 @@ namespace jGL::GL for (unsigned slot = 0; slot < MAX_BATCH_BOUND_TEXTURES; slot++) { if (biter == batches[b].second.cend()) { break; } - textures[*biter]->bind(slot); + (*biter)->bind(slot); biter++; } @@ -98,7 +105,7 @@ namespace jGL::GL &xytheta[current*xythetaDim] ); glBindBuffer(GL_ARRAY_BUFFER, 0); - + glBindBuffer(GL_ARRAY_BUFFER, a_scale); glBufferSubData @@ -199,7 +206,7 @@ namespace jGL::GL 0 ); glVertexAttribDivisor(0,0); - + glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, a_xytheta); @@ -223,7 +230,7 @@ namespace jGL::GL 0 ); glVertexAttribDivisor(xythetaAttribute, 1); - + glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, a_scale); @@ -247,7 +254,7 @@ namespace jGL::GL 0 ); glVertexAttribDivisor(scaleAttribute, 1); - + glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, a_textureRegion); diff --git a/src/jGL/spriteRenderer.cpp b/src/jGL/spriteRenderer.cpp deleted file mode 100644 index 39139d62..00000000 --- a/src/jGL/spriteRenderer.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include - -namespace jGL -{ - Sprite & SpriteRenderer::getSprite(SpriteId id) - { - return sprites.at(id); - } - - void SpriteRenderer::add(Sprite s, SpriteId id, RenderPriority priority) - { - Id textureId = s.texture->getId(); - auto is_equal = [textureId](std::shared_ptr t) { return t->getId() == textureId; }; - auto match = std::find_if(textures.begin(), textures.end(), is_equal); - - if (match == textures.end()) - { - textures.push_back(s.texture); - spriteToTexture[id] = textures.size()-1; - } - else - { - spriteToTexture[id] = std::distance(textures.begin(), match); - } - - sprites.insert(std::pair(id, s)); - ids.insert(std::pair(priority, id)); - } -} \ No newline at end of file