#最初に
初投稿です
Qiitaの使い方はよくわかりません
・2018/01/18
修正案がありました
コードに色がつきました
#内容
タイトルの通りです
C#とSDL2を使いました
コードが複雑かも
まだ改善の余地はありそう
白い画像なら色調で自由に色を変えられる、という点を使った小技です
(白以外だと、別の色に変えられない場合があるし、
黒だと色を変えること自体ができないため)
この方法なら、色違いのキャラクターとかを表現できるはずです
おそらくSDL2でなくてもできる
果たしてこれは誰かの役に立つのか?
#ソースコード
/*
使用言語 C#
SDL2の色調を用いて、
画像の色違いを表現してみるサンプル
画像が8ビットの時専用?の方法なことに注意
画像が32ビットの時はできない?らしいので注意
〇ソースコードを少し変更しました
8ビット形式以外の画像を読み込んだ時に例外を出すように変更
また、ブログにコードを載せた際に、一部のコードが抜け落ちていたので、
少しコードを修正
*/
using System;
using System.Collections.Generic;
using System.IO;
using SDL2;
namespace Test {
static class Program {
static void Main() {
try {
InitSDL();
Start();
QuitSDL();
}
catch {
QuitSDL();
}
}
static void InitSDL() {
SDL.SDL_Init(SDL.SDL_INIT_EVERYTHING);
SDL_image.IMG_Init(SDL_image.IMG_InitFlags.IMG_INIT_PNG);
}
static void QuitSDL() {
SDL.SDL_Quit();
SDL_image.IMG_Quit();
}
static void Start() {
var window = SDL.SDL_CreateWindow("画像色変えテスト",
SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED,
300, 300,
SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN);
var renderer = SDL.SDL_CreateRenderer(window,
-1,
SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED);
var textureAry = CreateTextureList(renderer);
var colorArgs = CreateArrayColorArgs(textureAry.Length);
while (true) {
var e = new SDL.SDL_Event();
SDL.SDL_PollEvent(out e);
if (e.type == SDL.SDL_EventType.SDL_QUIT) break;
//描画内容の初期化
SDL.SDL_RenderClear(renderer);
//描画の開始
for (var i = 0; i < textureAry.Length; i++) {
//テクスチャの描画
RenderTexture(renderer, textureAry[i], colorArgs[i]);
}
//描画の初期化
SDL.SDL_RenderPresent(renderer);
SDL.SDL_Delay(1000 / 30);
}
}
//画像が8ビット形式かをチェック
static unsafe void CheckImageTypeBit8(SDL.SDL_PixelFormat* format) {
if (format->BitsPerPixel != 8) {
throw new Exception("画像が8ビットでありません");
}
}
//描画用テクスチャのリストを作る
static unsafe IntPtr[] CreateTextureList(IntPtr renderer) {
//テクスチャ用配列の宣言
var texture_ary = default(IntPtr[]);
//画像サーフェスを読み込み
//(今回は、「test.png」を読み込みます)
var surface_p = SDL_image.IMG_Load("test.png");
//画像サーフェスのデータを取得
var surface = (SDL.SDL_Surface*)surface_p;
var format = (SDL.SDL_PixelFormat*)surface->format;
//画像が8ビット形式かをチェック
CheckImageTypeBit8(format);
//画像サーフェスのカラーパレットデータを取得
var pallete = (SDL.SDL_Palette*)format->palette;
var colors = (SDL.SDL_Color*)pallete->colors;
//テクスチャ用配列を作成
texture_ary = new IntPtr[pallete->ncolors];
//サーフェスの色データのコピー
var colorArray = CreateColorDataCopy(pallete);
//画像サーフェスで使われている色の数だけループが実行される
for (var i = 0; i < pallete->ncolors; i++) {
//サーフェスを色ごとに分割するためのループ
for (var n = 0; n < pallete->ncolors; n++) {
//サーフェスの色データをすべて白にする
ColorPtrWhiteOut(colors, n);
//違う色の部分は、透明にしておく
//こうして、サーフェスを色ごとに分割できる
if (i != n) ColorPtrHide(colors, n);
}
//切り分けたテクスチャの追加
texture_ary[i] = SDL.SDL_CreateTextureFromSurface(renderer, surface_p);
//サーフェスの色データを元に戻す
ResetColorPtr(colorArray, pallete);
}
//使い終わったサーフェスは削除しよう
SDL.SDL_FreeSurface(surface_p);
return texture_ary;
}
static unsafe void ColorPtrWhiteOut(SDL.SDL_Color* colorPtr, int index) {
//テクスチャの色を白にしておく
//こうすることで、色調を使うことでどんな色にも変化させられる
colorPtr[index].r = byte.MaxValue;
colorPtr[index].g = byte.MaxValue;
colorPtr[index].b = byte.MaxValue;
}
static unsafe void ColorPtrHide(SDL.SDL_Color* colorPtr, int index) {
//違う色の部分は透明にしておく
//そうしないと、画像の全域が同じ色で表示されてしまう
colorPtr[index].a = byte.MinValue;
}
//サーフェスの色データのコピーを作る
//
//サーフェスの色データをいじるので、
//元に戻すための配列コピーは必要
static unsafe SDL.SDL_Color[] CreateColorDataCopy(SDL.SDL_Palette* pallete) {
var colors = new SDL.SDL_Color[pallete->ncolors];
for (var i = 0; i < colors.Length; i++) {
colors[i] = ((SDL.SDL_Color*)pallete->colors)[i];
}
return colors;
}
//サーフェスのパレットカラーを元に戻す
static unsafe void ResetColorPtr(SDL.SDL_Color[] colors, SDL.SDL_Palette* pallete) {
for (var n = 0; n < pallete->ncolors; n++) {
((SDL.SDL_Color*)pallete->colors)[n] = colors[n];
}
}
//テクスチャの描画
static void RenderTexture(IntPtr renderer, IntPtr texture, SDL.SDL_Color color) {
//必ずブレンドモードにすること!
//(ブレンドモードにしないと、正しく表示されないことがあるため)
SDL.SDL_SetTextureBlendMode(texture, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
//テクスチャの色を指定する
SDL.SDL_SetTextureColorMod(texture, color.r, color.g, color.b);
//テクスチャの描画
SDL.SDL_RenderCopy(renderer, texture, IntPtr.Zero, IntPtr.Zero);
}
//乱数を使って色を指定しています
//
//もちろん、乱数を使わずに色指定してもよい
static SDL.SDL_Color[] CreateArrayColorArgs(int length) {
var rand = new Random();
var colorArgs = new SDL.SDL_Color[length];
for (var i = 0; i < colorArgs.Length; i++) {
//テクスチャの色はかならず指定すること
//指定しないで描画すると、真っ黒な画像が表示されてしまう
//
//色指定に必要なのは、RGB値の3つだけ
//(A値は指定しても変化がないので不要)
colorArgs[i].r = (byte)rand.Next(byte.MaxValue);
colorArgs[i].g = (byte)rand.Next(byte.MaxValue);
colorArgs[i].b = (byte)rand.Next(byte.MaxValue);
}
return colorArgs;
}
}
}
#最後に
ブログにのせたコードが読みにくいので、試しにこの記事を作りました
コードが読みやすかったらうれしい
↓ブログにのせたコード(一応)
http://mini09memo.blog.fc2.com/blog-entry-348.html