ゆとりーなの日記

日記的な事を書いて行くと思はれる

画像を扱うクラスとか

boost::flyweightsを作った瞬間落ちるとか、メンバ変数として巨大な配列持てないとか、動的配列は論外とか色々制約が大きいのでこんな感じになりました。東方の画像はPSPに移すに際して128*128になることが多いのでこういう実装になりました。32種類の画像を扱えるように128*128の配列を32個静的に用意して、同一ファイルを複数読み込まないようにしてみました。

// image.h
#ifndef TH06_PSP_IMAGE_H_
#define TH06_PSP_IMAGE_H_
#include <array>
#include <string>
#include <vector>
#include "attribute.h"

class image {
 public:
  explicit image(const std::string &file_name);
  image(const image &rhs);
  image &operator =(const image &rhs);
  ~image();
  void draw(float x, float y, float u, float v, float width, float height);
  void draw(float x, float y, float u, float v, float width, float height, float angle);
 private:
  static float lotate_x(float x, float y, float p, float angle);
  static float lotate_y(float x, float y, float p, float angle);
  class id_list_initializer {
   public:
    id_list_initializer();
  };
  class texture_data {
   public:
    void load_texture(const std::string &file_name);
    bool operator ==(const std::string &rhs) const;
    void add_ref();
    int release();
    void *pixel();
   private:
    int count_;
    std::string texture_name_;
    unsigned int __attribute__((aligned(16)))pixel_[128 * 128];
  };
  int id_;
  static std::vector<int> id_list_;
  static std::array<texture_data, 32> texture_list_;
};

#endif 

// imaeg.cc
#include "image.h"
#include <cmath>
#include <array>
#include <fstream>
#include <boost/range/algorithm/find.hpp>
#include <pspgu.h>
#include "application.h"
#include "vertex.h"

image::image(const std::string &file_name) : id_() {
  static id_list_initializer i;
  if (boost::find(texture_list_, file_name) == texture_list_.end()) {
    id_ = id_list_.at(id_list_.size() - 1);
    id_list_.pop_back();
    texture_list_.at(id_).load_texture(file_name);
  } else {
    texture_list_.at(id_).add_ref();
  }
}

image::image(const image &rhs) : id_(rhs.id_) {
  texture_list_.at(id_).add_ref();
}

image &image::operator =(const image &rhs) {
  if (!texture_list_.at(id_).release()) {
    id_list_.push_back(id_);
  }
  id_ = rhs.id_;
  texture_list_.at(id_).add_ref();
  return *this;
}

image::~image() {
  if (!texture_list_.at(id_).release()) {
    id_list_.push_back(id_);
  }
}
 
void image::draw(const float x, const float y, const float u, const float v, const float width, const float height) {
  application::begin_draw();
  sceGuTexImage(0, 128, 128, 128, texture_list_[id_].pixel());
  const std::array<image_vertex, 2> vertex = {{
    {u, v, 0xFFFFFFFF, x, y, 0.f},
    {u + width, v + height, 0xFFFFFFFF, x + width, y + height, 0.f}
  }};
  sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2, 0, &vertex.front());
  application::end_draw();
}

void image::draw(const float x, const float y, const float u, const float v, const float width, const float height, const float angle) {
  application::begin_draw();
  sceGuTexImage(0, 128, 128, 128, texture_list_[id_].pixel());
  const std::array<image_vertex, 4> vertex = {{
    {u, v, 0xFFFFFFFF, lotate_x(-width, -height, x, angle), lotate_y(-width, -height, y, angle), 0.f},
    {u + width, v, 0xFFFFFFFF, lotate_x(width, -height, x, angle), lotate_y(width, -height, y, angle), 0.f},
    {u, v + height, 0xFFFFFFFF, lotate_x(-width, height, x, angle), lotate_y(-width, height, y, angle), 0.f},
    {u + width, v + height, 0xFFFFFFFF, lotate_x(width, height, x, angle), lotate_y(width, height, y, angle), 0.f}
  }};
  sceGuDrawArray(GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_COLOR_8888 |GU_VERTEX_32BITF | GU_TRANSFORM_2D, 4, 0, &vertex.front());
  application::end_draw();
}

float image::lotate_x(const float x, const float y, const float p, const float angle) {
  return x / 2.f * cosf(angle) - y / 2.f * sinf(angle) + p;
}

float image::lotate_y(const float x, const float y, const float p, const float angle) {
  return x / 2.f * sinf(angle) + y / 2.f * cosf(angle) + p;
}

image::id_list_initializer::id_list_initializer() {
  for (int i = 0; i < 32; ++i) {
    id_list_.at(i) = i;
  }
}

void image::texture_data::load_texture(const std::string &file_name) {
  count_ = 1;
  texture_name_ = file_name;
  std::ifstream fin(file_name.c_str(), std::ios::in | std::ios::binary);
  fin.seekg(0x80);
  fin.read(reinterpret_cast<char *>(pixel_), 128 * 128 * 16);
}

bool image::texture_data::operator ==(const std::string &rhs) const {
  return texture_name_ == rhs;
}
 
void image::texture_data::add_ref() {
  count_++;
}

int image::texture_data::release() {
  --count_;
  if (!count_) {
    texture_name_ = "";
  }
  return count_;
}

void *image::texture_data::pixel() {
  return pixel_;
}

std::vector<int> image::id_list_(32);

std::array<image::texture_data, 32> image::texture_list_;

インターフェイスは現在検討中なのでまだ暫定ですが、最適化を凄く期待するフィルタ式の採用は見送りそうです。
メニュー表示もばっちりです。