Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/WolfireGames/overgrowth.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Graphics/texturepack.cpp')
-rw-r--r--Source/Graphics/texturepack.cpp264
1 files changed, 264 insertions, 0 deletions
diff --git a/Source/Graphics/texturepack.cpp b/Source/Graphics/texturepack.cpp
new file mode 100644
index 00000000..9862b81b
--- /dev/null
+++ b/Source/Graphics/texturepack.cpp
@@ -0,0 +1,264 @@
+//-----------------------------------------------------------------------------
+// Name: texturepack.cpp
+// Developer: Wolfire Games LLC
+// Description:
+// License: Read below
+//-----------------------------------------------------------------------------
+//
+//
+// Copyright 2022 Wolfire Games LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-----------------------------------------------------------------------------
+#include "texturepack.h"
+
+#include <Graphics/textures.h>
+#include <Graphics/graphics.h>
+#include <Graphics/shaders.h>
+
+#include <Math/vec2math.h>
+
+void DrawRect(const vec2 &rect_min, const vec2 &rect_max){
+ glBegin(GL_QUADS);
+ glTexCoord2f(0,0);
+ glVertex3f(rect_min[0],rect_min[1],0.0f);
+ glTexCoord2f(1,0);
+ glVertex3f(rect_max[0],rect_min[1],0.0f);
+ glTexCoord2f(1,1);
+ glVertex3f(rect_max[0],rect_max[1],0.0f);
+ glTexCoord2f(0,1);
+ glVertex3f(rect_min[0],rect_max[1],0.0f);
+ glEnd();
+}
+
+TexturePackNode::TexturePackNode():
+ filled(false)
+{
+ children[0] = NULL;
+ children[1] = NULL;
+}
+
+void TexturePackNode::SetRect(const vec2 _rect_min , const vec2 _rect_max)
+{
+ rect_min = _rect_min;
+ rect_max = _rect_max;
+}
+
+TexturePackNode* TexturePackNode::Insert( const TextureAssetRef &texture )
+{
+ TexturePackNode* new_node;
+
+ //If node has children, try to insert in each child
+ if(children[0]){
+ new_node = children[0]->Insert(texture);
+ if(new_node){
+ return new_node;
+ } else {
+ return children[1]->Insert(texture);
+ }
+ // If node has no children, try to insert in this node
+ } else {
+ // If node is full, can't do anything here!
+ if(filled){
+ return NULL;
+ }
+
+ // If image is bigger than node, can't fit here!
+ const vec2 rect_dimensions = rect_max - rect_min;
+ const int texture_width = Textures::Instance()->getWidth(texture->GetTextureRef());
+ const int texture_height = Textures::Instance()->getHeight(texture->GetTextureRef());
+ if(texture_width > rect_dimensions[0] ||
+ texture_height > rect_dimensions[1]){
+ return NULL;
+ }
+
+ // If image is exactly the size of this node, draw it in!
+ if(texture_width == rect_dimensions[0] &&
+ texture_height == rect_dimensions[1]){
+ Textures::Instance()->bindTexture(texture->GetTextureRef());
+ DrawRect(rect_min,rect_max);
+ filled = true;
+ return this;
+ }
+
+ // Image fits inside, but not perfectly.
+ // Time to split!
+ children[0] = new TexturePackNode();
+ children[1] = new TexturePackNode();
+
+ int extra_width = (int)rect_dimensions[0] - texture_width;
+ int extra_height = (int)rect_dimensions[1] - texture_height;
+ if(extra_width > extra_height){
+ children[0]->SetRect(rect_min, vec2(rect_min[0]+texture_width, rect_max[1]));
+ children[1]->SetRect(vec2(rect_min[0]+texture_width, rect_min[1]), rect_max);
+ } else {
+ children[0]->SetRect(rect_min, vec2(rect_max[0], rect_min[1]+texture_height));
+ children[1]->SetRect(vec2(rect_min[0], rect_min[1]+texture_height), rect_max);
+ }
+
+ // Insert in the correctly-sized child node
+ return children[0]->Insert(texture);
+ }
+}
+
+void TexturePackNode::Dispose()
+{
+ if(children[0]){
+ delete children[0];
+ children[0] = NULL;
+ }
+ if(children[1]){
+ delete children[1];
+ children[1] = NULL;
+ }
+ filled = false;
+}
+
+TexturePackNode::~TexturePackNode()
+{
+ Dispose();
+}
+
+const vec2& TexturePackNode::GetMin() const
+{
+ return rect_min;
+}
+
+const vec2& TexturePackNode::GetMax() const
+{
+ return rect_max;
+}
+
+TexturePack::TexturePack() {
+}
+
+
+struct TexturePackParamSort {
+ TexturePackParam param;
+ int area;
+ int orig_id;
+};
+
+struct TextureSizeSorter {
+ bool operator()(const TexturePackParamSort& a, const TexturePackParamSort& b){
+ return a.area > b.area;
+ }
+};
+
+void TexturePack::Create( int _size, std::vector<TexturePackParam> &textures )
+{
+ Dispose();
+
+ size = _size;
+
+ int widest = 0;
+ int tallest = 0;
+
+ std::vector<TexturePackParamSort> sorted_textures(textures.size());
+ for(unsigned i=0; i<sorted_textures.size(); i++){
+ sorted_textures[i].param = textures[i];
+ sorted_textures[i].orig_id = i;
+ Textures::Instance()->EnsureInVRAM(textures[i].texture->GetTextureRef());
+ sorted_textures[i].area = Textures::Instance()->getWidth(textures[i].texture->GetTextureRef())*
+ Textures::Instance()->getHeight(textures[i].texture->GetTextureRef());
+ textures[sorted_textures[i].orig_id].inserted = false;
+ }
+ sort(sorted_textures.begin(), sorted_textures.end(), TextureSizeSorter());
+
+ int total_area_remaining = size*size;
+ int cutoff = 0;
+ for(int i=(int)sorted_textures.size()-1; i>=0; i--){
+ total_area_remaining -= sorted_textures[i].area;
+ if(total_area_remaining<0){
+ cutoff = i+1;
+ break;
+ } else {
+ widest = max(widest, Textures::Instance()->getWidth(textures[sorted_textures[i].orig_id].texture->GetTextureRef()));
+ tallest = max(tallest, Textures::Instance()->getHeight(textures[sorted_textures[i].orig_id].texture->GetTextureRef()));
+ }
+ }
+
+ const int area_used = size*size - total_area_remaining;
+ while(area_used < size*size/4 && size >= widest*2 && size >= tallest*2){
+ size/=2;
+ }
+
+ //pack_texture = Textures::Instance()->makeTextureColor(size,size);
+ pack_texture = Textures::Instance()->makeTextureTestPattern(size,size);
+ Textures::Instance()->SetTextureName(pack_texture, "Texture Pack");
+
+ GLuint framebuffer;
+ Graphics::Instance()->genFramebuffers(&framebuffer, "texture_pack");
+ Graphics::Instance()->PushFramebuffer();
+ Graphics::Instance()->bindFramebuffer(framebuffer);
+ Graphics::Instance()->framebufferColorTexture2D(pack_texture);
+
+ Shaders::Instance()->noProgram();
+
+ GLState gl_state;
+ gl_state.blend = false;
+ gl_state.cull_face = false;
+ gl_state.depth_test = false;
+ gl_state.depth_write = false;
+
+ Graphics::Instance()->setGLState(gl_state);
+ glColor4f(1.0f,1.0f,1.0f,1.0f);
+
+ Graphics::Instance()->PushViewport();
+ Graphics::Instance()->setViewport(0,0,size,size);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(0,size,0,size,-100,100);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ root_node.SetRect(vec2(0.0f,0.0f),vec2((float)size,(float)size));
+
+ TexturePackNode *inserted;
+ for(unsigned i=cutoff; i<sorted_textures.size(); i++){
+ inserted = root_node.Insert(sorted_textures[i].param.texture);
+ if(inserted){
+ textures[sorted_textures[i].orig_id].offset[0] = inserted->GetMin()[0]/(float)size;
+ textures[sorted_textures[i].orig_id].offset[1] = inserted->GetMin()[1]/(float)size;
+ textures[sorted_textures[i].orig_id].offset[2] = Textures::Instance()->getWidth(textures[sorted_textures[i].orig_id].texture->GetTextureRef())/(float)size;
+ textures[sorted_textures[i].orig_id].offset[3] = Textures::Instance()->getHeight(textures[sorted_textures[i].orig_id].texture->GetTextureRef())/(float)size;
+ textures[sorted_textures[i].orig_id].inserted = true;
+ }
+ }
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ Graphics::Instance()->PopViewport();
+ Graphics::Instance()->PopFramebuffer();
+ Graphics::Instance()->deleteFramebuffer(&framebuffer);
+
+ //Textures::Instance()->SetDebugTextureAssetRef(pack_texture);
+ Textures::Instance()->DeleteUnusedTextures();
+}
+
+TexturePack::~TexturePack() {
+ Dispose();
+}
+
+void TexturePack::Dispose()
+{
+ root_node.Dispose();
+}