atlas: Should work now
This commit is contained in:
parent
f516f4984d
commit
feca5c5471
@ -4,6 +4,8 @@
|
||||
#include <Context.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <Texture2D.h>
|
||||
#include <Graphics.h>
|
||||
#include <Image.h>
|
||||
|
||||
namespace interface {
|
||||
|
||||
@ -20,18 +22,19 @@ struct CTextureAtlasRegistry: public TextureAtlasRegistry
|
||||
const AtlasSegmentReference add_segment(
|
||||
const AtlasSegmentDefinition &segment_def)
|
||||
{
|
||||
throw Exception("Not implemented");
|
||||
// Get Texture2D resource
|
||||
magic::ResourceCache *magic_cache =
|
||||
m_context->GetSubsystem<magic::ResourceCache>();
|
||||
magic::Texture2D *texture = magic_cache->GetResource<magic::Texture2D>(
|
||||
segment_def.resource_name);
|
||||
magic::Image *seg_img = magic_cache->GetResource<magic::Image>(
|
||||
segment_def.resource_name.c_str());
|
||||
if(seg_img == nullptr)
|
||||
throw Exception("Couldn't find image: "+segment_def.resource_name);
|
||||
// Get resolution of texture
|
||||
magic::IntVector2 texture_size(texture->GetWidth(), texture->GetHeight());
|
||||
magic::IntVector2 seg_img_size(seg_img->GetWidth(), seg_img->GetHeight());
|
||||
// Try to find a texture atlas for this texture size
|
||||
TextureAtlasDefinition *atlas_def = NULL;
|
||||
TextureAtlasDefinition *atlas_def = nullptr;
|
||||
for(TextureAtlasDefinition &def0 : m_defs){
|
||||
if(def0.segment_resolution == texture_size){
|
||||
if(def0.segment_resolution == seg_img_size){
|
||||
size_t max = def0.total_segments.x_ * def0.total_segments.y_;
|
||||
if(atlas_def->segments.size() >= max)
|
||||
continue; // Full
|
||||
@ -47,26 +50,56 @@ struct CTextureAtlasRegistry: public TextureAtlasRegistry
|
||||
atlas_def->id = m_defs.size()-1;
|
||||
// Calculate segment resolution
|
||||
atlas_def->segment_resolution = magic::IntVector2(
|
||||
texture_size.x_ / segment_def.total_segments.x_,
|
||||
texture_size.y_ / segment_def.total_segments.y_
|
||||
seg_img_size.x_ / segment_def.total_segments.x_,
|
||||
seg_img_size.y_ / segment_def.total_segments.y_
|
||||
);
|
||||
// Calculate total segments based on segment resolution
|
||||
int max_res = 2048;
|
||||
const int max_res = 2048;
|
||||
atlas_def->total_segments = magic::IntVector2(
|
||||
max_res / atlas_def->segment_resolution.x_,
|
||||
max_res / atlas_def->segment_resolution.y_,
|
||||
max_res / atlas_def->segment_resolution.y_
|
||||
);
|
||||
magic::IntVector2 atlas_resolution(
|
||||
atlas_def->total_segments.x_ * atlas_def->segment_resolution.x_,
|
||||
atlas_def->total_segments.y_ * atlas_def->segment_resolution.y_
|
||||
);
|
||||
// Create image for new atlas
|
||||
magic::Image *atlas_img = new magic::Image(m_context);
|
||||
atlas_img->SetSize(atlas_resolution.x_, atlas_resolution.y_, 4);
|
||||
// Create texture for new atlas
|
||||
// TODO: Extend cache to fit this atlas if it doesn't yet
|
||||
// TODO: Set texture of cached atlas
|
||||
magic::Texture2D *atlas_tex = new magic::Texture2D(m_context);
|
||||
// TODO: Use TEXTURE_STATIC or TEXTURE_DYNAMIC?
|
||||
atlas_tex->SetSize(atlas_resolution.x_, atlas_resolution.y_,
|
||||
magic::Graphics::GetRGBAFormat(), magic::TEXTURE_STATIC);
|
||||
// Add new atlas to cache
|
||||
const auto &id = atlas_def->id;
|
||||
m_cache.resize(id+1);
|
||||
TextureAtlasCache *cache = &m_cache[id];
|
||||
cache->image = atlas_img;
|
||||
cache->texture = atlas_tex;
|
||||
cache->segment_resolution = atlas_def->segment_resolution;
|
||||
cache->total_segments = atlas_def->total_segments;
|
||||
}
|
||||
// TODO: Add this definition to the atlas
|
||||
// Add this segment to the atlas definition
|
||||
uint seg_id = atlas_def->segments.size();
|
||||
atlas_def->segments.resize(seg_id + 1);
|
||||
atlas_def->segments[seg_id] = segment_def;
|
||||
// Update this segment in cache
|
||||
TextureAtlasCache &atlas_cache = m_cache[atlas_def->id];
|
||||
atlas_cache.segments.resize(seg_id + 1);
|
||||
AtlasSegmentCache &seg_cache = atlas_cache.segments[seg_id];
|
||||
update_segment_cache(seg_id, seg_img, seg_cache, segment_def, atlas_cache);
|
||||
// Return reference to new segment
|
||||
AtlasSegmentReference ref;
|
||||
ref.atlas_id = atlas_def->id;
|
||||
ref.segment_id = seg_id;
|
||||
return ref;
|
||||
}
|
||||
|
||||
const TextureAtlasDefinition* get_atlas_definition(uint atlas_id)
|
||||
{
|
||||
if(atlas_id >= m_defs.size())
|
||||
return NULL;
|
||||
return nullptr;
|
||||
return &m_defs[atlas_id];
|
||||
}
|
||||
|
||||
@ -75,47 +108,68 @@ struct CTextureAtlasRegistry: public TextureAtlasRegistry
|
||||
{
|
||||
const TextureAtlasDefinition *atlas = get_atlas_definition(ref.atlas_id);
|
||||
if(!atlas)
|
||||
return NULL;
|
||||
return nullptr;
|
||||
if(ref.segment_id >= atlas->segments.size())
|
||||
return NULL;
|
||||
return nullptr;
|
||||
return &atlas->segments[ref.segment_id];
|
||||
}
|
||||
|
||||
void update_segment_cache(AtlasSegmentCache &cache,
|
||||
const AtlasSegmentDefinition &def, const TextureAtlasDefinition &atlas)
|
||||
void update_segment_cache(uint seg_id, magic::Image *seg_img,
|
||||
AtlasSegmentCache &cache, const AtlasSegmentDefinition &def,
|
||||
const TextureAtlasCache &atlas)
|
||||
{
|
||||
// TODO
|
||||
// TODO: Get Texture2D resource
|
||||
// TODO: Check that resolution of texture matches with atlas
|
||||
// TODO:
|
||||
// Check if atlas is full
|
||||
size_t max_segments = atlas.total_segments.x_ * atlas.total_segments.y_;
|
||||
if(atlas.segments.size() >= max_segments)
|
||||
throw Exception("Atlas is full");
|
||||
// Set segment texture
|
||||
cache.texture = atlas.texture;
|
||||
// Calculate segment's position in atlas texture
|
||||
uint seg_iy = seg_id / atlas.total_segments.x_;
|
||||
uint seg_ix = seg_id - seg_iy;
|
||||
magic::IntVector2 seg_size = atlas.segment_resolution;
|
||||
magic::IntVector2 dst_p0(seg_ix * seg_size.x_, seg_iy * seg_size.y_);
|
||||
magic::IntVector2 dst_p1 = dst_p0 + seg_size;
|
||||
// Set coordinates in cache
|
||||
cache.coord0 = magic::Vector2(
|
||||
(float)dst_p0.x_ / (float)(atlas.total_segments.x_ * seg_size.x_),
|
||||
(float)dst_p0.y_ / (float)(atlas.total_segments.y_ * seg_size.y_)
|
||||
);
|
||||
cache.coord0 = magic::Vector2(
|
||||
(float)dst_p1.x_ / (float)(atlas.total_segments.x_ * seg_size.x_),
|
||||
(float)dst_p1.y_ / (float)(atlas.total_segments.y_ * seg_size.y_)
|
||||
);
|
||||
// Draw segment into atlas image
|
||||
magic::IntVector2 seg_img_size(seg_img->GetWidth(), seg_img->GetHeight());
|
||||
magic::IntVector2 src_off(
|
||||
seg_img_size.x_ / def.total_segments.x_ * def.select_segment.x_,
|
||||
seg_img_size.y_ / def.total_segments.y_ * def.select_segment.y_
|
||||
);
|
||||
for(int y=0; y<seg_size.y_; y++){
|
||||
for(int x=0; x<seg_size.x_; x++){
|
||||
magic::IntVector2 src_p = src_off + magic::IntVector2(x, y);
|
||||
magic::IntVector2 dst_p = dst_p0 + magic::IntVector2(x ,y);
|
||||
magic::Color c = seg_img->GetPixel(src_p.x_, src_p.y_);
|
||||
atlas.image->SetPixel(dst_p.x_, dst_p.y_, c);
|
||||
}
|
||||
}
|
||||
// Update atlas texture from atlas image
|
||||
// TODO: Does this require something more?
|
||||
atlas.texture->SetData(atlas.image);
|
||||
}
|
||||
|
||||
const AtlasSegmentCache* get_texture(const AtlasSegmentReference &ref)
|
||||
{
|
||||
if(ref.atlas_id >= m_cache.size()){
|
||||
if(ref.atlas_id >= m_defs.size())
|
||||
return NULL;
|
||||
// New atlases are left with valid=false
|
||||
m_cache.resize(m_defs.size());
|
||||
// Cache is always up-to-date
|
||||
return nullptr;
|
||||
}
|
||||
TextureAtlasCache &cache = m_cache[ref.atlas_id];
|
||||
if(!cache.valid){
|
||||
const auto &id = ref.atlas_id;
|
||||
cache.segment_resolution = m_defs[id].segment_resolution;
|
||||
cache.total_segments = m_defs[id].total_segments;
|
||||
// New segments are left with valid=false
|
||||
cache.segments.resize(m_defs[id].segments.size());
|
||||
cache.valid = true;
|
||||
if(ref.segment_id >= cache.segments.size()){
|
||||
// Cache is always up-to-date
|
||||
return nullptr;
|
||||
}
|
||||
if(ref.segment_id >= cache.segments.size())
|
||||
return NULL;
|
||||
AtlasSegmentCache &seg_cache = cache.segments[ref.segment_id];
|
||||
if(seg_cache.valid)
|
||||
return &seg_cache;
|
||||
TextureAtlasDefinition &atlas_def = m_defs[ref.atlas_id];
|
||||
const AtlasSegmentDefinition &seg_def = atlas_def.segments[ref.segment_id];
|
||||
update_segment_cache(seg_cache, seg_def, atlas_def);
|
||||
seg_cache.valid = true;
|
||||
return &seg_cache;
|
||||
}
|
||||
};
|
||||
|
@ -3,11 +3,13 @@
|
||||
#pragma once
|
||||
#include "core/types.h"
|
||||
#include <Vector2.h>
|
||||
#include <Ptr.h>
|
||||
|
||||
namespace Urho3D
|
||||
{
|
||||
class Context;
|
||||
class Texture2D;
|
||||
class Image;
|
||||
}
|
||||
|
||||
namespace interface
|
||||
@ -30,8 +32,7 @@ namespace interface
|
||||
|
||||
struct AtlasSegmentCache
|
||||
{
|
||||
bool valid = false;
|
||||
magic::Texture2D *texture = NULL;
|
||||
magic::Texture2D *texture = nullptr;
|
||||
magic::Vector2 coord0;
|
||||
magic::Vector2 coord1;
|
||||
};
|
||||
@ -46,8 +47,8 @@ namespace interface
|
||||
|
||||
struct TextureAtlasCache
|
||||
{
|
||||
bool valid = false;
|
||||
magic::Texture2D *texture = NULL;
|
||||
magic::SharedPtr<magic::Image> image;
|
||||
magic::Texture2D *texture = nullptr;
|
||||
magic::IntVector2 segment_resolution;
|
||||
magic::IntVector2 total_segments;
|
||||
sv_<AtlasSegmentCache> segments;
|
||||
|
Loading…
x
Reference in New Issue
Block a user