瀏覽代碼

image: more method renaming for consistency.

legacy
Sam Hocevar 8 年之前
父節點
當前提交
7558d0664a
共有 33 個檔案被更改,包括 717 行新增663 行删除
  1. +5
    -5
      doc/samples/simplex.cpp
  2. +4
    -4
      doc/tutorial/14_lol_lua.cpp
  3. +12
    -10
      src/gpu/framebuffer.cpp
  4. +11
    -9
      src/image/codec/dummy-image.cpp
  5. +7
    -7
      src/image/codec/gdiplus-image.cpp
  6. +7
    -7
      src/image/codec/imlib2-image.cpp
  7. +24
    -22
      src/image/codec/oric-image.cpp
  8. +7
    -7
      src/image/codec/sdl-image.cpp
  9. +15
    -13
      src/image/codec/zed-image.cpp
  10. +15
    -12
      src/image/codec/zed-palette-image.cpp
  11. +36
    -34
      src/image/combine.cpp
  12. +15
    -13
      src/image/crop.cpp
  13. +37
    -35
      src/image/dither/dbs.cpp
  14. +24
    -22
      src/image/dither/ediff.cpp
  15. +28
    -26
      src/image/dither/ordered.cpp
  16. +14
    -12
      src/image/dither/ostromoukhov.cpp
  17. +13
    -11
      src/image/dither/random.cpp
  18. +50
    -48
      src/image/filter/colors.cpp
  19. +53
    -51
      src/image/filter/convolution.cpp
  20. +76
    -74
      src/image/filter/dilate.cpp
  21. +54
    -52
      src/image/filter/median.cpp
  22. +18
    -16
      src/image/filter/yuv.cpp
  23. +27
    -27
      src/image/image.cpp
  24. +15
    -13
      src/image/kernel.cpp
  25. +11
    -9
      src/image/noise.cpp
  26. +33
    -33
      src/image/pixel.cpp
  27. +18
    -16
      src/image/resample.cpp
  28. +36
    -30
      src/lol/image/image.h
  29. +9
    -7
      src/lol/sys/file.h
  30. +11
    -9
      src/sys/file.cpp
  31. +2
    -2
      src/sys/threadtypes.cpp
  32. +7
    -7
      src/t/image/image.cpp
  33. +23
    -20
      src/textureimage.cpp

+ 5
- 5
doc/samples/simplex.cpp 查看文件

@@ -1,7 +1,7 @@
// //
// Lol Engine — Simplex Noise tutorial // Lol Engine — Simplex Noise tutorial
// //
// Copyright © 2010—2015 Sam Hocevar <sam@hocevar.net>
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
// © 2013-2014 Guillaume Bittoun <guillaume.bittoun@gmail.com> // © 2013-2014 Guillaume Bittoun <guillaume.bittoun@gmail.com>
// //
// Lol Engine is free software. It comes without any warranty, to // Lol Engine is free software. It comes without any warranty, to
@@ -31,8 +31,8 @@ int main(int argc, char **argv)
srand(time(nullptr)); srand(time(nullptr));


/* Create an image */ /* Create an image */
Image img(size);
array2d<vec4> &data = img.Lock2D<PixelFormat::RGBA_F32>();
image img(size);
array2d<vec4> &data = img.lock2d<PixelFormat::RGBA_F32>();


/* Declare plenty of allocators */ /* Declare plenty of allocators */
simplex_noise<2> s2; simplex_noise<2> s2;
@@ -141,7 +141,7 @@ int main(int argc, char **argv)
#endif #endif


/* Save image */ /* Save image */
img.Unlock2D(data);
img.Save("simplex.png");
img.unlock2d(data);
img.save("simplex.png");
} }



+ 4
- 4
doc/tutorial/14_lol_lua.cpp 查看文件

@@ -1,7 +1,7 @@
// //
// Lol Engine — Lua tutorial // Lol Engine — Lua tutorial
// //
// Copyright © 2014—2015 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
// Copyright © 2014—2017 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
// //
// Lol Engine is free software. It comes without any warranty, to // Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it // the extent permitted by applicable law. You can redistribute it
@@ -36,14 +36,14 @@ public:
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
static int AddFive(lua_State* l) static int AddFive(lua_State* l)
{ {
auto stack = LuaStack::Begin(l);
int32_t i = stack.Get<int32_t>();
auto stack = LuaStack::Begin(l);
int32_t i = stack.Get<int32_t>();


i += 5; i += 5;


return (stack << i).End(); return (stack << i).End();
} }
LOLUA_DECLARE_RETURN_METHOD_ARGS(AddTenInstance, GetPtr<DemoObject>(), AddTenMethod, Get<float>(), Get<int32_t>(), Get<int32_t>()); LOLUA_DECLARE_RETURN_METHOD_ARGS(AddTenInstance, GetPtr<DemoObject>(), AddTenMethod, Get<float>(), Get<int32_t>(), Get<int32_t>());
static int _AddTenInstance(lua_State* l) static int _AddTenInstance(lua_State* l)
{ {


+ 12
- 10
src/gpu/framebuffer.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -343,14 +345,14 @@ ivec2 Framebuffer::GetSize() const
return m_data->m_size; return m_data->m_size;
} }


Image Framebuffer::GetImage() const
image Framebuffer::GetImage() const
{ {
Image ret(m_data->m_size);
image ret(m_data->m_size);


u8vec4 *buffer = ret.Lock<PixelFormat::RGBA_8>();
u8vec4 *buffer = ret.lock<PixelFormat::RGBA_8>();
glReadPixels(0, 0, m_data->m_size.x, m_data->m_size.y, glReadPixels(0, 0, m_data->m_size.x, m_data->m_size.y,
GL_RGBA, GL_UNSIGNED_BYTE, buffer); GL_RGBA, GL_UNSIGNED_BYTE, buffer);
ret.Unlock(buffer);
ret.unlock(buffer);


return ret; return ret;
} }


+ 11
- 9
src/image/codec/dummy-image.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -39,9 +41,9 @@ ResourceCodecData* DummyImageCodec::Load(char const *path)
if (strcmp("DUMMY", path)) if (strcmp("DUMMY", path))
return nullptr; return nullptr;


auto data = new ResourceImageData(new Image(ivec2(256)));
auto data = new ResourceImageData(new image(ivec2(256)));
auto image = data->m_image; auto image = data->m_image;
u8vec4 *pixels = image->Lock<PixelFormat::RGBA_8>(), *tmp = pixels;
u8vec4 *pixels = image->lock<PixelFormat::RGBA_8>(), *tmp = pixels;
for (int j = 0; j < 256; j++) for (int j = 0; j < 256; j++)
for (int i = 0; i < 256; i++) for (int i = 0; i < 256; i++)
{ {
@@ -51,7 +53,7 @@ ResourceCodecData* DummyImageCodec::Load(char const *path)
tmp->a = (((i >> 4) ^ (j >> 4)) & 1) * 0xff; tmp->a = (((i >> 4) ^ (j >> 4)) & 1) * 0xff;
++tmp; ++tmp;
} }
image->Unlock(pixels);
image->unlock(pixels);


return data; return data;
} }


+ 7
- 7
src/image/codec/gdiplus-image.cpp 查看文件

@@ -1,7 +1,7 @@
// //
// Lol Engine // Lol Engine
// //
// Copyright © 2010—2016 Sam Hocevar <sam@hocevar.net>
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
// //
// Lol Engine is free software. It comes without any warranty, to // Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it // the extent permitted by applicable law. You can redistribute it
@@ -116,13 +116,13 @@ ResourceCodecData* GdiPlusImageCodec::Load(char const *path)
/* FIXME: GDI+ doesn't know about RGBA, only ARGB. And OpenGL doesn't /* FIXME: GDI+ doesn't know about RGBA, only ARGB. And OpenGL doesn't
* know about ARGB, only RGBA. So we swap bytes. We could also fix * know about ARGB, only RGBA. So we swap bytes. We could also fix
* this in the shader. */ * this in the shader. */
auto data = new ResourceImageData(new Image(ivec2(size)));
auto data = new ResourceImageData(new image(ivec2(size)));
auto image = data->m_image; auto image = data->m_image;
u8vec4 *pdst = image->Lock<PixelFormat::RGBA_8>();
u8vec4 *pdst = image->lock<PixelFormat::RGBA_8>();
u8vec4 *psrc = static_cast<u8vec4 *>(bdata.Scan0); u8vec4 *psrc = static_cast<u8vec4 *>(bdata.Scan0);
for (int n = 0; n < size.x * size.y; n++) for (int n = 0; n < size.x * size.y; n++)
pdst[n] = psrc[n].bgra; pdst[n] = psrc[n].bgra;
image->Unlock(pdst);
image->unlock(pdst);


bitmap->UnlockBits(&bdata); bitmap->UnlockBits(&bdata);
delete bitmap; delete bitmap;
@@ -184,7 +184,7 @@ bool GdiPlusImageCodec::Save(char const *path, ResourceCodecData* data)
} }


auto image = data_image->m_image; auto image = data_image->m_image;
ivec2 size = image->GetSize();
ivec2 size = image->size();


Gdiplus::Bitmap *b = new Gdiplus::Bitmap(size.x, size.y, Gdiplus::Bitmap *b = new Gdiplus::Bitmap(size.x, size.y,
PixelFormat32bppARGB); PixelFormat32bppARGB);
@@ -201,13 +201,13 @@ bool GdiPlusImageCodec::Save(char const *path, ResourceCodecData* data)
return false; return false;
} }


u8vec4 *psrc = image->Lock<PixelFormat::RGBA_8>();
u8vec4 *psrc = image->lock<PixelFormat::RGBA_8>();
u8vec4 *psrc0 = psrc; u8vec4 *psrc0 = psrc;
u8vec4 *pdst = static_cast<u8vec4 *>(bdata.Scan0); u8vec4 *pdst = static_cast<u8vec4 *>(bdata.Scan0);
for (int y = 0; y < size.y; y++) for (int y = 0; y < size.y; y++)
for (int x = 0; x < size.x; x++) for (int x = 0; x < size.x; x++)
*pdst++ = (*psrc++).bgra; *pdst++ = (*psrc++).bgra;
image->Unlock(psrc0);
image->unlock(psrc0);
b->UnlockBits(&bdata); b->UnlockBits(&bdata);


if (b->Save(wpath, &clsid, nullptr) != Gdiplus::Ok) if (b->Save(wpath, &clsid, nullptr) != Gdiplus::Ok)


+ 7
- 7
src/image/codec/imlib2-image.cpp 查看文件

@@ -1,7 +1,7 @@
// //
// Lol Engine // Lol Engine
// //
// Copyright © 2010—2016 Sam Hocevar <sam@hocevar.net>
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
// //
// Lol Engine is free software. It comes without any warranty, to // Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it // the extent permitted by applicable law. You can redistribute it
@@ -74,10 +74,10 @@ ResourceCodecData *Imlib2ImageCodec::Load(char const *path)
} }


ivec2 size(imlib_image_get_width(), imlib_image_get_height()); ivec2 size(imlib_image_get_width(), imlib_image_get_height());
auto data = new ResourceImageData(new Image(size));
auto data = new ResourceImageData(new image(size));
auto image = data->m_image; auto image = data->m_image;


u8vec4 *dstdata = image->Lock<PixelFormat::RGBA_8>();
u8vec4 *dstdata = image->lock<PixelFormat::RGBA_8>();


for (int i = 0; i < size.x * size.y; i++) for (int i = 0; i < size.x * size.y; i++)
{ {
@@ -86,7 +86,7 @@ ResourceCodecData *Imlib2ImageCodec::Load(char const *path)
else else
dstdata[i] = srcdata[i].bgra; dstdata[i] = srcdata[i].bgra;
} }
image->Unlock(dstdata);
image->unlock(dstdata);


imlib_free_image(); imlib_free_image();


@@ -100,13 +100,13 @@ bool Imlib2ImageCodec::Save(char const *path, ResourceCodecData *data)
return false; return false;


auto image = data_image->m_image; auto image = data_image->m_image;
ivec2 size = image->GetSize();
ivec2 size = image->size();
Imlib_Image priv = imlib_create_image(size.x, size.y); Imlib_Image priv = imlib_create_image(size.x, size.y);


imlib_context_set_image(priv); imlib_context_set_image(priv);
imlib_image_set_has_alpha(1); imlib_image_set_has_alpha(1);


u8vec4 const *srcdata = image->Lock<PixelFormat::RGBA_8>();
u8vec4 const *srcdata = image->lock<PixelFormat::RGBA_8>();
u8vec4 *dstdata = (u8vec4 *)imlib_image_get_data(); u8vec4 *dstdata = (u8vec4 *)imlib_image_get_data();


for (int i = 0; i < size.x * size.y; i++) for (int i = 0; i < size.x * size.y; i++)
@@ -118,7 +118,7 @@ bool Imlib2ImageCodec::Save(char const *path, ResourceCodecData *data)
} }


imlib_image_put_back_data((DATA32 *)dstdata); imlib_image_put_back_data((DATA32 *)dstdata);
image->Unlock(srcdata);
image->unlock(srcdata);


imlib_save_image(path); imlib_save_image(path);
imlib_free_image(); imlib_free_image();


+ 24
- 22
src/image/codec/oric-image.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -36,7 +38,7 @@ public:


private: private:
static String ReadScreen(char const *name); static String ReadScreen(char const *name);
static void WriteScreen(Image &image, array<uint8_t> &result);
static void WriteScreen(image &image, array<uint8_t> &result);
}; };


DECLARE_IMAGE_CODEC(OricImageCodec, 100) DECLARE_IMAGE_CODEC(OricImageCodec, 100)
@@ -63,12 +65,12 @@ ResourceCodecData* OricImageCodec::Load(char const *path)
if (screen.count() == 0) if (screen.count() == 0)
return nullptr; return nullptr;


auto data = new ResourceImageData(new Image(ivec2(WIDTH, screen.count() * 6 / WIDTH)));
auto image = data->m_image;
auto data = new ResourceImageData(new image(ivec2(WIDTH, screen.count() * 6 / WIDTH)));
auto img = data->m_image;


u8vec4 *pixels = image->Lock<PixelFormat::RGBA_8>();
u8vec4 *pixels = img->lock<PixelFormat::RGBA_8>();


for (int y = 0; y < image->GetSize().y; y++)
for (int y = 0; y < img->size().y; y++)
{ {
u8vec2 bgfg(0, 7); u8vec2 bgfg(0, 7);


@@ -101,7 +103,7 @@ ResourceCodecData* OricImageCodec::Load(char const *path)
} }
} }


image->Unlock(pixels);
img->unlock(pixels);


return data; return data;
} }
@@ -129,18 +131,18 @@ bool OricImageCodec::Save(char const *path, ResourceCodecData* data)
result << (uint8_t)name[0]; result << (uint8_t)name[0];
result << 0; result << 0;


auto image = data_image->m_image;
Image tmp;
ivec2 size = image->GetSize();
auto img = data_image->m_image;
image tmp;
ivec2 size = img->size();
if (size.x != WIDTH) if (size.x != WIDTH)
{ {
size.y = (int)((float)size.y * WIDTH / size.x); size.y = (int)((float)size.y * WIDTH / size.x);
size.x = WIDTH; size.x = WIDTH;
tmp = image->Resize(size, ResampleAlgorithm::Bresenham);
image = &tmp;
tmp = img->Resize(size, ResampleAlgorithm::Bresenham);
img = &tmp;
} }


WriteScreen(*image, result);
WriteScreen(*img, result);


File f; File f;
f.Open(path, FileAccess::Write); f.Open(path, FileAccess::Write);
@@ -469,10 +471,10 @@ static uint8_t bestmove(ivec3 const *in, u8vec2 bgfg,
return bestcommand; return bestcommand;
} }


void OricImageCodec::WriteScreen(Image &image, array<uint8_t> &result)
void OricImageCodec::WriteScreen(image &img, array<uint8_t> &result)
{ {
ivec2 size = image.GetSize();
vec4 *pixels = image.Lock<PixelFormat::RGBA_F32>();
ivec2 size = img.size();
vec4 *pixels = img.lock<PixelFormat::RGBA_F32>();


int stride = (size.x + 1); int stride = (size.x + 1);


@@ -526,7 +528,7 @@ void OricImageCodec::WriteScreen(Image &image, array<uint8_t> &result)
} }
} }


image.Unlock(pixels);
img.unlock(pixels);


//fprintf(stderr, " done.\n"); //fprintf(stderr, " done.\n");
} }


+ 7
- 7
src/image/codec/sdl-image.cpp 查看文件

@@ -1,7 +1,7 @@
// //
// Lol Engine // Lol Engine
// //
// Copyright © 2010—2016 Sam Hocevar <sam@hocevar.net>
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
// //
// Lol Engine is free software. It comes without any warranty, to // Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it // the extent permitted by applicable law. You can redistribute it
@@ -75,11 +75,11 @@ ResourceCodecData* SdlImageCodec::Load(char const *path)
surface = tmp; surface = tmp;
} }


auto data = new ResourceImageData(new Image(size));
auto data = new ResourceImageData(new image(size));
auto image = data->m_image; auto image = data->m_image;
u8vec4 *pixel_data = image->Lock<PixelFormat::RGBA_8>();
u8vec4 *pixel_data = image->lock<PixelFormat::RGBA_8>();
memcpy(pixel_data, surface->pixels, 4 * size.x * size.y); memcpy(pixel_data, surface->pixels, 4 * size.x * size.y);
image->Unlock(pixel_data);
image->unlock(pixel_data);


SDL_FreeSurface(surface); SDL_FreeSurface(surface);


@@ -93,12 +93,12 @@ bool SdlImageCodec::Save(char const *path, ResourceCodecData* data)
return false; return false;


auto image = data_image->m_image; auto image = data_image->m_image;
ivec2 size = image->GetSize();
ivec2 size = image->size();
SDL_Surface *surface = Create32BppSurface(size); SDL_Surface *surface = Create32BppSurface(size);


u8vec4 *pixel_data = image->Lock<PixelFormat::RGBA_8>();
u8vec4 *pixel_data = image->lock<PixelFormat::RGBA_8>();
memcpy(surface->pixels, pixel_data, 4 * size.x * size.y); memcpy(surface->pixels, pixel_data, 4 * size.x * size.y);
image->Unlock(pixel_data);
image->unlock(pixel_data);


int ret = SDL_SaveBMP(surface, path); int ret = SDL_SaveBMP(surface, path);
SDL_FreeSurface(surface); SDL_FreeSurface(surface);


+ 15
- 13
src/image/codec/zed-image.cpp 查看文件

@@ -1,12 +1,14 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2014 Benjamin Huet <huet.benjamin@gmail.com>
// 2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
// 2014 Benjamin Huet <huet.benjamin@gmail.com>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -43,8 +45,8 @@ ResourceCodecData* ZedImageCodec::Load(char const *path)
struct CompactSecondary struct CompactSecondary
{ {
CompactSecondary(int32_t size) { m_size = size; } CompactSecondary(int32_t size) { m_size = size; }
int32_t m_size;
array<int32_t> m_tiles;
int32_t m_size;
array<int32_t> m_tiles;
}; };
struct CompactMain struct CompactMain
{ {
@@ -108,7 +110,7 @@ ResourceCodecData* ZedImageCodec::Load(char const *path)
file.Open(path, FileAccess::Read, true); file.Open(path, FileAccess::Read, true);


//Put file in memory //Put file in memory
long file_size = file.GetSize();
long file_size = file.size();
array<uint8_t> file_buffer; array<uint8_t> file_buffer;
file_buffer.resize(file_size); file_buffer.resize(file_size);
file.Read((uint8_t*)&file_buffer[0], file_size); file.Read((uint8_t*)&file_buffer[0], file_size);
@@ -227,9 +229,9 @@ ResourceCodecData* ZedImageCodec::Load(char const *path)
tex_size <<= 1; tex_size <<= 1;


//Prepare final image //Prepare final image
auto data = new ResourceTilesetData(new Image(ivec2(tex_size)));
auto data = new ResourceTilesetData(new image(ivec2(tex_size)));
auto image = data->m_image; auto image = data->m_image;
uint8_t *pixels = image->Lock<PixelFormat::Y_8>();
uint8_t *pixels = image->lock<PixelFormat::Y_8>();


//Data refactor stage //Data refactor stage
ivec2 pos = ivec2(0); ivec2 pos = ivec2(0);
@@ -284,7 +286,7 @@ ResourceCodecData* ZedImageCodec::Load(char const *path)
j++; j++;
} }
} }
image->Unlock(pixels);
image->unlock(pixels);


data->m_tiles = tiles; data->m_tiles = tiles;




+ 15
- 12
src/image/codec/zed-palette-image.cpp 查看文件

@@ -1,11 +1,14 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
// 2014 Benjamin Huet <huet.benjamin@gmail.com>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -41,8 +44,8 @@ ResourceCodecData* ZedPaletteImageCodec::Load(char const *path)
File file; File file;
file.Open(path, FileAccess::Read, true); file.Open(path, FileAccess::Read, true);


//Put file in memory
long file_size = file.GetSize();
// Put file in memory
long file_size = file.size();
array<uint8_t> file_buffer; array<uint8_t> file_buffer;
file_buffer.resize(file_size); file_buffer.resize(file_size);
file.Read((uint8_t*)&file_buffer[0], file_size); file.Read((uint8_t*)&file_buffer[0], file_size);
@@ -53,18 +56,18 @@ ResourceCodecData* ZedPaletteImageCodec::Load(char const *path)
int32_t tex_size = 2; int32_t tex_size = 2;
while (tex_size < tex_sqrt) while (tex_size < tex_sqrt)
tex_size <<= 1; tex_size <<= 1;
auto data = new ResourceImageData(new Image(ivec2(tex_size)));
auto data = new ResourceImageData(new image(ivec2(tex_size)));
auto image = data->m_image; auto image = data->m_image;
#else #else
int32_t tex_sqrt = file_size / 3; int32_t tex_sqrt = file_size / 3;
int32_t tex_size = 2; int32_t tex_size = 2;
while (tex_size < tex_sqrt) while (tex_size < tex_sqrt)
tex_size <<= 1; tex_size <<= 1;
auto data = new ResourceImageData(new Image(ivec2(tex_size, 1)));
auto data = new ResourceImageData(new image(ivec2(tex_size, 1)));
auto image = data->m_image; auto image = data->m_image;
#endif #endif


u8vec4 *pixels = image->Lock<PixelFormat::RGBA_8>();
u8vec4 *pixels = image->lock<PixelFormat::RGBA_8>();
for (int i = 0; i < file_buffer.count();) for (int i = 0; i < file_buffer.count();)
{ {
pixels->r = file_buffer[i++]; pixels->r = file_buffer[i++];
@@ -73,7 +76,7 @@ ResourceCodecData* ZedPaletteImageCodec::Load(char const *path)
pixels->a = (i == 0) ? 0 : 255; pixels->a = (i == 0) ? 0 : 255;
++pixels; ++pixels;
} }
image->Unlock(pixels);
image->unlock(pixels);


return data; return data;
} }


+ 36
- 34
src/image/combine.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -33,18 +35,18 @@ enum class MergeMode
}; };


template<PixelFormat FORMAT, MergeMode MODE> template<PixelFormat FORMAT, MergeMode MODE>
static image GenericMerge(image &src1, image &src2, float alpha)
static image generic_merge(image &src1, image &src2, float alpha)
{ {
typedef typename PixelType<FORMAT>::type pixel_t; typedef typename PixelType<FORMAT>::type pixel_t;


ASSERT(src1.GetSize() == src2.GetSize());
int const count = src1.GetSize().x * src2.GetSize().y;
ASSERT(src1.size() == src2.size());
int const count = src1.size().x * src2.size().y;


image dst(src1.GetSize());
image dst(src1.size());


pixel_t const *src1p = src1.Lock<FORMAT>();
pixel_t const *src2p = src2.Lock<FORMAT>();
pixel_t *dstp = dst.Lock<FORMAT>();
pixel_t const *src1p = src1.lock<FORMAT>();
pixel_t const *src2p = src2.lock<FORMAT>();
pixel_t *dstp = dst.lock<FORMAT>();


for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
{ {
@@ -71,80 +73,80 @@ static image GenericMerge(image &src1, image &src2, float alpha)
dstp[n] = lol::abs(src1p[n] - src2p[n]); dstp[n] = lol::abs(src1p[n] - src2p[n]);
} }


src1.Unlock(src1p);
src2.Unlock(src2p);
dst.Unlock(dstp);
src1.unlock(src1p);
src2.unlock(src2p);
dst.unlock(dstp);


return dst; return dst;
} }


template<MergeMode MODE> template<MergeMode MODE>
static image GenericMerge(image &src1, image &src2, float alpha)
static image generic_merge(image &src1, image &src2, float alpha)
{ {
bool gray1 = src1.GetFormat() == PixelFormat::Y_8
|| src1.GetFormat() == PixelFormat::Y_F32;
bool gray2 = src2.GetFormat() == PixelFormat::Y_8
|| src2.GetFormat() == PixelFormat::Y_F32;
bool gray1 = src1.format() == PixelFormat::Y_8
|| src1.format() == PixelFormat::Y_F32;
bool gray2 = src2.format() == PixelFormat::Y_8
|| src2.format() == PixelFormat::Y_F32;
if (gray1 && gray2) if (gray1 && gray2)
return GenericMerge<PixelFormat::Y_F32, MODE>(src1, src2, alpha);
return generic_merge<PixelFormat::Y_F32, MODE>(src1, src2, alpha);
else else
return GenericMerge<PixelFormat::RGBA_F32, MODE>(src1, src2, alpha);
return generic_merge<PixelFormat::RGBA_F32, MODE>(src1, src2, alpha);


} }


image image::Merge(image &src1, image &src2, float alpha) image image::Merge(image &src1, image &src2, float alpha)
{ {
return GenericMerge<MergeMode::Mix>(src1, src2, alpha);
return generic_merge<MergeMode::Mix>(src1, src2, alpha);
} }


image image::Mean(image &src1, image &src2) image image::Mean(image &src1, image &src2)
{ {
return GenericMerge<MergeMode::Mix>(src1, src2, 0.5f);
return generic_merge<MergeMode::Mix>(src1, src2, 0.5f);
} }


image image::Min(image &src1, image &src2) image image::Min(image &src1, image &src2)
{ {
return GenericMerge<MergeMode::Min>(src1, src2, 0.0f);
return generic_merge<MergeMode::Min>(src1, src2, 0.0f);
} }


image image::Max(image &src1, image &src2) image image::Max(image &src1, image &src2)
{ {
return GenericMerge<MergeMode::Max>(src1, src2, 0.0f);
return generic_merge<MergeMode::Max>(src1, src2, 0.0f);
} }


image image::Overlay(image &src1, image &src2) image image::Overlay(image &src1, image &src2)
{ {
return GenericMerge<MergeMode::Overlay>(src1, src2, 0.0f);
return generic_merge<MergeMode::Overlay>(src1, src2, 0.0f);
} }


image image::Screen(image &src1, image &src2) image image::Screen(image &src1, image &src2)
{ {
return GenericMerge<MergeMode::Screen>(src1, src2, 0.0f);
return generic_merge<MergeMode::Screen>(src1, src2, 0.0f);
} }


image image::Divide(image &src1, image &src2) image image::Divide(image &src1, image &src2)
{ {
return GenericMerge<MergeMode::Divide>(src1, src2, 0.0f);
return generic_merge<MergeMode::Divide>(src1, src2, 0.0f);
} }


image image::Multiply(image &src1, image &src2) image image::Multiply(image &src1, image &src2)
{ {
return GenericMerge<MergeMode::Multiply>(src1, src2, 0.0f);
return generic_merge<MergeMode::Multiply>(src1, src2, 0.0f);
} }


image image::Add(image &src1, image &src2) image image::Add(image &src1, image &src2)
{ {
return GenericMerge<MergeMode::Add>(src1, src2, 0.0f);
return generic_merge<MergeMode::Add>(src1, src2, 0.0f);
} }


image image::Sub(image &src1, image &src2) image image::Sub(image &src1, image &src2)
{ {
return GenericMerge<MergeMode::Sub>(src1, src2, 0.0f);
return generic_merge<MergeMode::Sub>(src1, src2, 0.0f);
} }


image image::Difference(image &src1, image &src2) image image::Difference(image &src1, image &src2)
{ {
return GenericMerge<MergeMode::Difference>(src1, src2, 0.0f);
return generic_merge<MergeMode::Difference>(src1, src2, 0.0f);
} }


} /* namespace lol */ } /* namespace lol */


+ 15
- 13
src/image/crop.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -21,18 +23,18 @@ namespace lol


image image::Crop(ibox2 box) const image image::Crop(ibox2 box) const
{ {
ivec2 const srcsize = GetSize();
ivec2 const srcsize = size();
ivec2 const dstsize = box.extent(); ivec2 const dstsize = box.extent();


image dst(dstsize); image dst(dstsize);
PixelFormat format = GetFormat();
PixelFormat fmt = format();


if (format != PixelFormat::Unknown)
if (fmt != PixelFormat::Unknown)
{ {
dst.SetFormat(format);
uint8_t const *srcp = (uint8_t const *)m_data->m_pixels[(int)format];
uint8_t *dstp = (uint8_t *)dst.m_data->m_pixels[(int)format];
uint8_t bpp = BytesPerPixel(format);
dst.set_format(fmt);
uint8_t const *srcp = (uint8_t const *)m_data->m_pixels[(int)fmt];
uint8_t *dstp = (uint8_t *)dst.m_data->m_pixels[(int)fmt];
uint8_t bpp = BytesPerPixel(fmt);


int len = dstsize.x; int len = dstsize.x;




+ 37
- 35
src/image/dither/dbs.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2015 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -24,44 +26,44 @@ namespace lol


/* FIXME: though the algorithm is supposed to stop, we do not have a real, /* FIXME: though the algorithm is supposed to stop, we do not have a real,
* guaranteed stop condition here. */ * guaranteed stop condition here. */
Image Image::DitherDbs() const
image image::dither_dbs() const
{ {
ivec2 size = GetSize();
ivec2 isize = size();


/* Build our human visual system kernel. */ /* Build our human visual system kernel. */
array2d<float> kernel;
kernel.resize(ivec2(NN, NN));
array2d<float> ker;
ker.resize(ivec2(NN, NN));
float t = 0.f; float t = 0.f;
for (int j = 0; j < NN; j++) for (int j = 0; j < NN; j++)
for (int i = 0; i < NN; i++) for (int i = 0; i < NN; i++)
{ {
vec2 v = vec2(i - N, j - N); vec2 v = vec2(i - N, j - N);
kernel[i][j] = exp(-sqlength(v / 1.6f) / 2.f)
+ exp(-sqlength(v / 0.6f) / 2.f);
t += kernel[i][j];
ker[i][j] = exp(-sqlength(v / 1.6f) / 2.f)
+ exp(-sqlength(v / 0.6f) / 2.f);
t += ker[i][j];
} }


for (int j = 0; j < NN; j++) for (int j = 0; j < NN; j++)
for (int i = 0; i < NN; i++) for (int i = 0; i < NN; i++)
kernel[i][j] /= t;
ker[i][j] /= t;


/* A list of cells in our picture. If no change is done to a cell /* A list of cells in our picture. If no change is done to a cell
* for two iterations, we stop considering changes to it. */ * for two iterations, we stop considering changes to it. */
ivec2 const csize = (size + ivec2(CELL - 1)) / CELL;
ivec2 const csize = (isize + ivec2(CELL - 1)) / CELL;
array2d<int> changelist(csize); array2d<int> changelist(csize);
memset(changelist.data(), 0, changelist.bytes()); memset(changelist.data(), 0, changelist.bytes());


Image dst = *this;
dst.SetFormat(PixelFormat::Y_F32);
image dst = *this;
dst.set_format(PixelFormat::Y_F32);


Image tmp1 = dst.Convolution(kernel);
array2d<float> &tmp1data = tmp1.Lock2D<PixelFormat::Y_F32>();
image tmp1 = dst.Convolution(ker);
array2d<float> &tmp1data = tmp1.lock2d<PixelFormat::Y_F32>();


dst = dst.DitherRandom();
array2d<float> &dstdata = dst.Lock2D<PixelFormat::Y_F32>();
dst = dst.dither_random();
array2d<float> &dstdata = dst.lock2d<PixelFormat::Y_F32>();


Image tmp2 = dst.Convolution(kernel);
array2d<float> &tmp2data = tmp2.Lock2D<PixelFormat::Y_F32>();
image tmp2 = dst.Convolution(ker);
array2d<float> &tmp2data = tmp2.lock2d<PixelFormat::Y_F32>();


for (int run = 0, last_change = 0; ; ++run) for (int run = 0, last_change = 0; ; ++run)
{ {
@@ -84,7 +86,7 @@ Image Image::DitherDbs() const
ivec2 const pos(cx * CELL + pixel % CELL, ivec2 const pos(cx * CELL + pixel % CELL,
cy * CELL + pixel / CELL); cy * CELL + pixel / CELL);


if (!(pos >= ivec2(0)) || !(pos < size))
if (!(pos >= ivec2(0)) || !(pos < isize))
continue; continue;


/* The best operation we can do */ /* The best operation we can do */
@@ -103,7 +105,7 @@ Image Image::DitherDbs() const


for (ivec2 const op : op_list) for (ivec2 const op : op_list)
{ {
if (!(pos + op >= ivec2(0)) || !(pos + op < size))
if (!(pos + op >= ivec2(0)) || !(pos + op < isize))
continue; continue;


bool flip = (op == ivec2(0)); bool flip = (op == ivec2(0));
@@ -115,9 +117,9 @@ Image Image::DitherDbs() const


/* TODO: implement min/max for 3+ arguments */ /* TODO: implement min/max for 3+ arguments */
int imin = max(max(-N, op.x - N), -pos.x); int imin = max(max(-N, op.x - N), -pos.x);
int imax = min(min(N + 1, op.x + NN - N), size.x - pos.x);
int imax = min(min(N + 1, op.x + NN - N), isize.x - pos.x);
int jmin = max(max(-N, op.y - N), -pos.y); int jmin = max(max(-N, op.y - N), -pos.y);
int jmax = min(min(N + 1, op.y + NN - N), size.y - pos.y);
int jmax = min(min(N + 1, op.y + NN - N), isize.y - pos.y);


float error = 0.f; float error = 0.f;
for (int j = jmin; j < jmax; j++) for (int j = jmin; j < jmax; j++)
@@ -125,9 +127,9 @@ Image Image::DitherDbs() const
{ {
ivec2 pos2 = pos + ivec2(i, j); ivec2 pos2 = pos + ivec2(i, j);


float m = kernel[i + N][j + N];
float m = ker[i + N][j + N];
if (!flip) if (!flip)
m -= kernel[i - op.x + N][j - op.y + N];
m -= ker[i - op.x + N][j - op.y + N];
float p = tmp1data[pos2]; float p = tmp1data[pos2];
float q1 = tmp2data[pos2]; float q1 = tmp2data[pos2];
float q2 = q1 + m * (d2 - d); float q2 = q1 + m * (d2 - d);
@@ -154,13 +156,13 @@ Image Image::DitherDbs() const
for (int i = -N; i <= N; i++) for (int i = -N; i <= N; i++)
{ {
ivec2 off(i, j); ivec2 off(i, j);
float delta = (d2 - d) * kernel[i + N][j + N];
float delta = (d2 - d) * ker[i + N][j + N];


if (pos + off >= ivec2(0) && pos + off < size)
if (pos + off >= ivec2(0) && pos + off < isize)
tmp2data[pos + off] += delta; tmp2data[pos + off] += delta;


if (!flip && pos + off + best_op >= ivec2(0) if (!flip && pos + off + best_op >= ivec2(0)
&& pos + off + best_op < size)
&& pos + off + best_op < isize)
tmp2data[pos + off + best_op] -= delta; tmp2data[pos + off + best_op] -= delta;
} }


@@ -173,9 +175,9 @@ Image Image::DitherDbs() const
++changelist[cx][cy]; ++changelist[cx][cy];
} }


tmp1.Unlock2D(tmp1data);
tmp2.Unlock2D(tmp2data);
dst.Unlock2D(dstdata);
tmp1.unlock2d(tmp1data);
tmp2.unlock2d(tmp2data);
dst.unlock2d(dstdata);


return dst; return dst;
} }


+ 24
- 22
src/image/dither/ediff.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -23,49 +25,49 @@ namespace lol
* Making the matrix generic is not terribly slower: the performance * Making the matrix generic is not terribly slower: the performance
* hit is around 4% for Floyd-Steinberg and 13% for JaJuNi, with the * hit is around 4% for Floyd-Steinberg and 13% for JaJuNi, with the
* benefit of a lot less code. */ * benefit of a lot less code. */
Image Image::DitherEdiff(array2d<float> const &kernel, ScanMode scan) const
image image::dither_ediff(array2d<float> const &ker, ScanMode scan) const
{ {
Image dst = *this;
image dst = *this;


ivec2 size = dst.GetSize();
ivec2 ksize = kernel.size();
ivec2 isize = dst.size();
ivec2 ksize = ker.size();


int kx; int kx;
for (kx = 0; kx < ksize.x; kx++) for (kx = 0; kx < ksize.x; kx++)
if (kernel[kx][0] > 0.f)
if (ker[kx][0] > 0.f)
break; break;


float *pixels = dst.Lock<PixelFormat::Y_F32>();
for (int y = 0; y < size.y; y++)
float *pixels = dst.lock<PixelFormat::Y_F32>();
for (int y = 0; y < isize.y; y++)
{ {
bool reverse = (y & 1) && (scan == ScanMode::Serpentine); bool reverse = (y & 1) && (scan == ScanMode::Serpentine);


for (int x = 0; x < size.x; x++)
for (int x = 0; x < isize.x; x++)
{ {
int x2 = reverse ? size.x - 1 - x : x;
int x2 = reverse ? isize.x - 1 - x : x;
int s = reverse ? -1 : 1; int s = reverse ? -1 : 1;


float p = pixels[y * size.x + x2];
float p = pixels[y * isize.x + x2];
float q = p < 0.5f ? 0.f : 1.f; float q = p < 0.5f ? 0.f : 1.f;
pixels[y * size.x + x2] = q;
pixels[y * isize.x + x2] = q;


float e = (p - q); float e = (p - q);


for (int j = 0; j < ksize.y && y < size.y - j; j++)
for (int j = 0; j < ksize.y && y < isize.y - j; j++)
for (int i = 0; i < ksize.x; i++) for (int i = 0; i < ksize.x; i++)
{ {
if (j == 0 && i <= kx) if (j == 0 && i <= kx)
continue; continue;


if (x + i - kx < 0 || x + i - kx >= size.x)
if (x + i - kx < 0 || x + i - kx >= isize.x)
continue; continue;


pixels[(y + j) * size.x + x2 + (i - kx) * s]
+= e * kernel[i][j];
pixels[(y + j) * isize.x + x2 + (i - kx) * s]
+= e * ker[i][j];
} }
} }
} }
dst.Unlock(pixels);
dst.unlock(pixels);


return dst; return dst;
} }


+ 28
- 26
src/image/dither/ordered.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -17,51 +19,51 @@
namespace lol namespace lol
{ {


static Image DitherHelper(Image const &image, array2d<float> const &kernel,
float scale, float angle);
static image dither_helper(image const &img, array2d<float> const &ker,
float scale, float angle);


Image Image::DitherOrdered(array2d<float> const &kernel) const
image image::dither_ordered(array2d<float> const &ker) const
{ {
return DitherHelper(*this, kernel, 1.0f, 0.0f);
return dither_helper(*this, ker, 1.0f, 0.0f);
} }


Image Image::DitherHalftone(float radius, float angle) const
image image::dither_halftone(float radius, float angle) const
{ {
/* Increasing the precision is necessary or the rotation will look /* Increasing the precision is necessary or the rotation will look
* like crap. So we create a kernel PRECISION times larger, and ask * like crap. So we create a kernel PRECISION times larger, and ask
* the ditherer to scale it by 1/PRECISION. */ * the ditherer to scale it by 1/PRECISION. */
float const PRECISION = 4.f; float const PRECISION = 4.f;
int k = (radius * PRECISION * lol::sqrt(2.f) + 0.5f); int k = (radius * PRECISION * lol::sqrt(2.f) + 0.5f);
array2d<float> kernel = Image::HalftoneKernel(ivec2(k, k));
array2d<float> ker = image::kernel::halftone(ivec2(k, k));


return DitherHelper(*this, kernel, 1.f / PRECISION, angle + F_PI / 4.f);
return dither_helper(*this, ker, 1.f / PRECISION, angle + F_PI / 4.f);
} }


static Image DitherHelper(Image const &image, array2d<float> const &kernel,
float scale, float angle)
static image dither_helper(image const &img, array2d<float> const &ker,
float scale, float angle)
{ {
ivec2 size = image.GetSize();
ivec2 ksize = kernel.size();
ivec2 isize = img.size();
ivec2 ksize = ker.size();


float cost = lol::cos(angle); float cost = lol::cos(angle);
float sint = lol::sin(angle); float sint = lol::sin(angle);


Image ret = image;
float *dstp = ret.Lock<PixelFormat::Y_F32>();
image ret = img;
float *dstp = ret.lock<PixelFormat::Y_F32>();


for (int y = 0; y < size.y; y++)
for (int y = 0; y < isize.y; y++)
{ {
for (int x = 0; x < size.x; x++)
for (int x = 0; x < isize.x; x++)
{ {
int kx = (int)((cost * x - sint * y + 2 * size.x * size.y) / scale) % ksize.x;
int ky = (int)((cost * y + sint * x + 2 * size.x * size.y) / scale) % ksize.y;
int kx = (int)((cost * x - sint * y + 2 * isize.x * isize.y) / scale) % ksize.x;
int ky = (int)((cost * y + sint * x + 2 * isize.x * isize.y) / scale) % ksize.y;


float p = dstp[y * size.x + x];
dstp[y * size.x + x] = (p > kernel[kx][ky]) ? 1.f : 0.f;
float p = dstp[y * isize.x + x];
dstp[y * isize.x + x] = (p > ker[kx][ky]) ? 1.f : 0.f;
} }
} }


ret.Unlock(dstp);
ret.unlock(dstp);


return ret; return ret;
} }


+ 14
- 12
src/image/dither/ostromoukhov.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -69,13 +71,13 @@ static inline vec3 GetDiffusion(float v)
return ret; return ret;
} }


Image Image::DitherOstromoukhov(ScanMode scan) const
image image::dither_ostromoukhov(ScanMode scan) const
{ {
Image dst = *this;
image dst = *this;


float *pixels = dst.Lock<PixelFormat::Y_F32>();
int w = dst.GetSize().x;
int h = dst.GetSize().y;
float *pixels = dst.lock<PixelFormat::Y_F32>();
int w = dst.size().x;
int h = dst.size().y;


for (int y = 0; y < h; y++) for (int y = 0; y < h; y++)
{ {
@@ -103,7 +105,7 @@ Image Image::DitherOstromoukhov(ScanMode scan) const
} }
} }


dst.Unlock(pixels);
dst.unlock(pixels);


return dst; return dst;
} }


+ 13
- 11
src/image/dither/random.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -17,19 +19,19 @@
namespace lol namespace lol
{ {


Image Image::DitherRandom() const
image image::dither_random() const
{ {
Image dst = *this;
image dst = *this;


float *pixels = dst.Lock<PixelFormat::Y_F32>();
int count = GetSize().x * GetSize().y;
float *pixels = dst.lock<PixelFormat::Y_F32>();
int count = size().x * size().y;


for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
{ {
pixels[n] = (pixels[n] > lol::rand(0.5f)) ? 1.f : 0.f; pixels[n] = (pixels[n] > lol::rand(0.5f)) ? 1.f : 0.f;
} }


dst.Unlock(pixels);
dst.unlock(pixels);


return dst; return dst;
} }


+ 50
- 48
src/image/filter/colors.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -17,34 +19,34 @@
namespace lol namespace lol
{ {


Image Image::Brightness(float val) const
image image::Brightness(float val) const
{ {
Image ret = *this;
int count = GetSize().x * GetSize().y;
image ret = *this;
int count = size().x * size().y;


if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
if (format() == PixelFormat::Y_8 || format() == PixelFormat::Y_F32)
{ {
float *pixels = ret.Lock<PixelFormat::Y_F32>();
float *pixels = ret.lock<PixelFormat::Y_F32>();
for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
pixels[n] = lol::clamp(pixels[n] + val, 0.f, 1.f); pixels[n] = lol::clamp(pixels[n] + val, 0.f, 1.f);
ret.Unlock(pixels);
ret.unlock(pixels);
} }
else else
{ {
vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>();
vec4 *pixels = ret.lock<PixelFormat::RGBA_F32>();
for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
pixels[n] = vec4(lol::clamp(pixels[n].rgb + vec3(val), 0.f, 1.f), pixels[n] = vec4(lol::clamp(pixels[n].rgb + vec3(val), 0.f, 1.f),
pixels[n].a); pixels[n].a);
ret.Unlock(pixels);
ret.unlock(pixels);
} }


return ret; return ret;
} }


Image Image::Contrast(float val) const
image image::Contrast(float val) const
{ {
Image ret = *this;
int count = GetSize().x * GetSize().y;
image ret = *this;
int count = size().x * size().y;


if (val >= 0.f) if (val >= 0.f)
{ {
@@ -58,22 +60,22 @@ Image Image::Contrast(float val) const
val = lol::clamp(1.f + val, 0.f, 1.f); val = lol::clamp(1.f + val, 0.f, 1.f);
} }


if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
if (format() == PixelFormat::Y_8 || format() == PixelFormat::Y_F32)
{ {
float add = -0.5f * val + 0.5f; float add = -0.5f * val + 0.5f;
float *pixels = ret.Lock<PixelFormat::Y_F32>();
float *pixels = ret.lock<PixelFormat::Y_F32>();
for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
pixels[n] = lol::clamp(pixels[n] * val + add, 0.f, 1.f); pixels[n] = lol::clamp(pixels[n] * val + add, 0.f, 1.f);
ret.Unlock(pixels);
ret.unlock(pixels);
} }
else else
{ {
vec3 add = vec3(-0.5f * val + 0.5f); vec3 add = vec3(-0.5f * val + 0.5f);
vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>();
vec4 *pixels = ret.lock<PixelFormat::RGBA_F32>();
for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
pixels[n] = vec4(lol::clamp(pixels[n].rgb * val + add, 0.f, 1.f), pixels[n] = vec4(lol::clamp(pixels[n].rgb * val + add, 0.f, 1.f),
pixels[n].a); pixels[n].a);
ret.Unlock(pixels);
ret.unlock(pixels);
} }


return ret; return ret;
@@ -83,16 +85,16 @@ Image Image::Contrast(float val) const
* TODO: the current approach is naive; we should use the histogram in order * TODO: the current approach is naive; we should use the histogram in order
* to decide how to change the contrast. * to decide how to change the contrast.
*/ */
Image Image::AutoContrast() const
image image::AutoContrast() const
{ {
Image ret = *this;
image ret = *this;


float min_val = 1.f, max_val = 0.f; float min_val = 1.f, max_val = 0.f;
int count = GetSize().x * GetSize().y;
int count = size().x * size().y;


if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
if (format() == PixelFormat::Y_8 || format() == PixelFormat::Y_F32)
{ {
float *pixels = ret.Lock<PixelFormat::Y_F32>();
float *pixels = ret.lock<PixelFormat::Y_F32>();
for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
{ {
min_val = lol::min(min_val, pixels[n]); min_val = lol::min(min_val, pixels[n]);
@@ -103,11 +105,11 @@ Image Image::AutoContrast() const
for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
pixels[n] = (pixels[n] - min_val) * t; pixels[n] = (pixels[n] - min_val) * t;


ret.Unlock(pixels);
ret.unlock(pixels);
} }
else else
{ {
vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>();
vec4 *pixels = ret.lock<PixelFormat::RGBA_F32>();
for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
{ {
min_val = lol::min(min_val, pixels[n].r); min_val = lol::min(min_val, pixels[n].r);
@@ -125,60 +127,60 @@ Image Image::AutoContrast() const
(pixels[n].b - min_val) * t, (pixels[n].b - min_val) * t,
pixels[n].a);; pixels[n].a);;


ret.Unlock(pixels);
ret.unlock(pixels);
} }


return ret; return ret;
} }


Image Image::Invert() const
image image::Invert() const
{ {
Image ret = *this;
int count = GetSize().x * GetSize().y;
image ret = *this;
int count = size().x * size().y;


if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
if (format() == PixelFormat::Y_8 || format() == PixelFormat::Y_F32)
{ {
float *pixels = ret.Lock<PixelFormat::Y_F32>();
float *pixels = ret.lock<PixelFormat::Y_F32>();
for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
pixels[n] = 1.f - pixels[n]; pixels[n] = 1.f - pixels[n];
ret.Unlock(pixels);
ret.unlock(pixels);
} }
else else
{ {
vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>();
vec4 *pixels = ret.lock<PixelFormat::RGBA_F32>();
for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
pixels[n] = vec4(vec3(1.f) -pixels[n].rgb, pixels[n].a); pixels[n] = vec4(vec3(1.f) -pixels[n].rgb, pixels[n].a);
ret.Unlock(pixels);
ret.unlock(pixels);
} }


return ret; return ret;
} }


Image Image::Threshold(float val) const
image image::Threshold(float val) const
{ {
Image ret = *this;
int count = GetSize().x * GetSize().y;
image ret = *this;
int count = size().x * size().y;


float *pixels = ret.Lock<PixelFormat::Y_F32>();
float *pixels = ret.lock<PixelFormat::Y_F32>();
for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
pixels[n] = pixels[n] > val ? 1.f : 0.f; pixels[n] = pixels[n] > val ? 1.f : 0.f;
ret.Unlock(pixels);
ret.unlock(pixels);


return ret; return ret;
} }


Image Image::Threshold(vec3 val) const
image image::Threshold(vec3 val) const
{ {
Image ret = *this;
int count = GetSize().x * GetSize().y;
image ret = *this;
int count = size().x * size().y;


vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>();
vec4 *pixels = ret.lock<PixelFormat::RGBA_F32>();
for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
pixels[n] = vec4(pixels[n].r > val.r ? 1.f : 0.f, pixels[n] = vec4(pixels[n].r > val.r ? 1.f : 0.f,
pixels[n].g > val.g ? 1.f : 0.f, pixels[n].g > val.g ? 1.f : 0.f,
pixels[n].b > val.b ? 1.f : 0.f, pixels[n].b > val.b ? 1.f : 0.f,
pixels[n].a); pixels[n].a);
ret.Unlock(pixels);
ret.unlock(pixels);


return ret; return ret;
} }


+ 53
- 51
src/image/filter/convolution.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -17,21 +19,21 @@
namespace lol namespace lol
{ {


static Image SepConv(Image &src, array<float> const &hvec,
static image SepConv(image &src, array<float> const &hvec,
array<float> const &vvec); array<float> const &vvec);
static Image NonSepConv(Image &src, array2d<float> const &kernel);
static image NonSepConv(image &src, array2d<float> const &in_kernel);


Image Image::Convolution(array2d<float> const &kernel)
image image::Convolution(array2d<float> const &in_kernel)
{ {
/* Find the cell with the largest value */ /* Find the cell with the largest value */
ivec2 ksize = kernel.size();
ivec2 ksize = in_kernel.size();
int bestx = -1, besty = -1; int bestx = -1, besty = -1;
float tmp = 0.f; float tmp = 0.f;
for (int dy = 0; dy < ksize.y; ++dy) for (int dy = 0; dy < ksize.y; ++dy)
for (int dx = 0; dx < ksize.x; ++dx) for (int dx = 0; dx < ksize.x; ++dx)
if (lol::sq(kernel[dx][dy]) > tmp)
if (lol::sq(in_kernel[dx][dy]) > tmp)
{ {
tmp = sq(kernel[dx][dy]);
tmp = sq(in_kernel[dx][dy]);
bestx = dx; bestx = dx;
besty = dy; besty = dy;
} }
@@ -52,8 +54,8 @@ Image Image::Convolution(array2d<float> const &kernel)
if (dx == bestx) if (dx == bestx)
continue; continue;


float p = kernel[dx][dy] * kernel[bestx][besty];
float q = kernel[dx][besty] * kernel[bestx][dy];
float p = in_kernel[dx][dy] * in_kernel[bestx][besty];
float q = in_kernel[dx][besty] * in_kernel[bestx][dy];


if (lol::abs(p - q) > 1.0e-8f) if (lol::abs(p - q) > 1.0e-8f)
separable = false; separable = false;
@@ -65,29 +67,29 @@ Image Image::Convolution(array2d<float> const &kernel)
/* Matrix rank is 1! Separate the filter. */ /* Matrix rank is 1! Separate the filter. */
array<float> hvec, vvec; array<float> hvec, vvec;


float norm = 1.0f / lol::sqrt(lol::abs(kernel[bestx][besty]));
float norm = 1.0f / lol::sqrt(lol::abs(in_kernel[bestx][besty]));
for (int dx = 0; dx < ksize.x; dx++) for (int dx = 0; dx < ksize.x; dx++)
hvec << norm * kernel[dx][besty];
hvec << norm * in_kernel[dx][besty];
for (int dy = 0; dy < ksize.y; dy++) for (int dy = 0; dy < ksize.y; dy++)
vvec << norm * kernel[bestx][dy];
vvec << norm * in_kernel[bestx][dy];


return SepConv(*this, hvec, vvec); return SepConv(*this, hvec, vvec);
} }
else else
{ {
return NonSepConv(*this, kernel);
return NonSepConv(*this, in_kernel);
} }
} }


Image Image::Sharpen(array2d<float> const &kernel)
image image::Sharpen(array2d<float> const &in_kernel)
{ {
ivec2 ksize = kernel.size();
ivec2 ksize = in_kernel.size();
array2d<float> newkernel(ksize); array2d<float> newkernel(ksize);


for (int dy = 0; dy < ksize.y; ++dy) for (int dy = 0; dy < ksize.y; ++dy)
for (int dx = 0; dx < ksize.x; ++dx) for (int dx = 0; dx < ksize.x; ++dx)
{ {
newkernel[dx][dy] = - kernel[dx][dy];
newkernel[dx][dy] = - in_kernel[dx][dy];
if (dx == ksize.x / 2 && dy == ksize.y / 2) if (dx == ksize.x / 2 && dy == ksize.y / 2)
newkernel[dx][dy] += 2.f; newkernel[dx][dy] += 2.f;
} }
@@ -96,16 +98,16 @@ Image Image::Sharpen(array2d<float> const &kernel)
} }


template<PixelFormat FORMAT, int WRAP_X, int WRAP_Y> template<PixelFormat FORMAT, int WRAP_X, int WRAP_Y>
static Image NonSepConv(Image &src, array2d<float> const &kernel)
static image NonSepConv(image &src, array2d<float> const &in_kernel)
{ {
typedef typename PixelType<FORMAT>::type pixel_t; typedef typename PixelType<FORMAT>::type pixel_t;


ivec2 const size = src.GetSize();
ivec2 const ksize = kernel.size();
Image dst(size);
ivec2 const size = src.size();
ivec2 const ksize = in_kernel.size();
image dst(size);


array2d<pixel_t> const &srcp = src.Lock2D<FORMAT>();
array2d<pixel_t> &dstp = dst.Lock2D<FORMAT>();
array2d<pixel_t> const &srcp = src.lock2d<FORMAT>();
array2d<pixel_t> &dstp = dst.lock2d<FORMAT>();


for (int y = 0; y < size.y; y++) for (int y = 0; y < size.y; y++)
{ {
@@ -123,7 +125,7 @@ static Image NonSepConv(Image &src, array2d<float> const &kernel)


for (int dx = 0; dx < ksize.x; dx++) for (int dx = 0; dx < ksize.x; dx++)
{ {
float f = kernel[dx][dy];
float f = in_kernel[dx][dy];


int x2 = x + dx - ksize.x / 2; int x2 = x + dx - ksize.x / 2;
if (x2 < 0) if (x2 < 0)
@@ -139,33 +141,33 @@ static Image NonSepConv(Image &src, array2d<float> const &kernel)
} }
} }


src.Unlock2D(srcp);
dst.Unlock2D(dstp);
src.unlock2d(srcp);
dst.unlock2d(dstp);


return dst; return dst;
} }


static Image NonSepConv(Image &src, array2d<float> const &kernel)
static image NonSepConv(image &src, array2d<float> const &in_kernel)
{ {
bool const wrap_x = src.GetWrapX() == WrapMode::Repeat; bool const wrap_x = src.GetWrapX() == WrapMode::Repeat;
bool const wrap_y = src.GetWrapY() == WrapMode::Repeat; bool const wrap_y = src.GetWrapY() == WrapMode::Repeat;


if (src.GetFormat() == PixelFormat::Y_8
|| src.GetFormat() == PixelFormat::Y_F32)
if (src.format() == PixelFormat::Y_8
|| src.format() == PixelFormat::Y_F32)
{ {
if (wrap_x) if (wrap_x)
{ {
if (wrap_y) if (wrap_y)
return NonSepConv<PixelFormat::Y_F32, 1, 1>(src, kernel);
return NonSepConv<PixelFormat::Y_F32, 1, 1>(src, in_kernel);
else else
return NonSepConv<PixelFormat::Y_F32, 1, 0>(src, kernel);
return NonSepConv<PixelFormat::Y_F32, 1, 0>(src, in_kernel);
} }
else else
{ {
if (wrap_y) if (wrap_y)
return NonSepConv<PixelFormat::Y_F32, 0, 1>(src, kernel);
return NonSepConv<PixelFormat::Y_F32, 0, 1>(src, in_kernel);
else else
return NonSepConv<PixelFormat::Y_F32, 0, 0>(src, kernel);
return NonSepConv<PixelFormat::Y_F32, 0, 0>(src, in_kernel);
} }
} }
else else
@@ -173,32 +175,32 @@ static Image NonSepConv(Image &src, array2d<float> const &kernel)
if (wrap_x) if (wrap_x)
{ {
if (wrap_y) if (wrap_y)
return NonSepConv<PixelFormat::RGBA_F32, 1, 1>(src, kernel);
return NonSepConv<PixelFormat::RGBA_F32, 1, 1>(src, in_kernel);
else else
return NonSepConv<PixelFormat::RGBA_F32, 1, 0>(src, kernel);
return NonSepConv<PixelFormat::RGBA_F32, 1, 0>(src, in_kernel);
} }
else else
{ {
if (wrap_y) if (wrap_y)
return NonSepConv<PixelFormat::RGBA_F32, 0, 1>(src, kernel);
return NonSepConv<PixelFormat::RGBA_F32, 0, 1>(src, in_kernel);
else else
return NonSepConv<PixelFormat::RGBA_F32, 0, 0>(src, kernel);
return NonSepConv<PixelFormat::RGBA_F32, 0, 0>(src, in_kernel);
} }
} }
} }


template<PixelFormat FORMAT, int WRAP_X, int WRAP_Y> template<PixelFormat FORMAT, int WRAP_X, int WRAP_Y>
static Image SepConv(Image &src, array<float> const &hvec,
static image SepConv(image &src, array<float> const &hvec,
array<float> const &vvec) array<float> const &vvec)
{ {
typedef typename PixelType<FORMAT>::type pixel_t; typedef typename PixelType<FORMAT>::type pixel_t;


ivec2 const size = src.GetSize();
ivec2 const size = src.size();
ivec2 const ksize(hvec.count(), vvec.count()); ivec2 const ksize(hvec.count(), vvec.count());
Image dst(size);
image dst(size);


array2d<pixel_t> const &srcp = src.Lock2D<FORMAT>();
array2d<pixel_t> &dstp = dst.Lock2D<FORMAT>();
array2d<pixel_t> const &srcp = src.lock2d<FORMAT>();
array2d<pixel_t> &dstp = dst.lock2d<FORMAT>();


array2d<pixel_t> tmp(size); array2d<pixel_t> tmp(size);


@@ -244,20 +246,20 @@ static Image SepConv(Image &src, array<float> const &hvec,
} }
} }


src.Unlock2D(srcp);
dst.Unlock2D(dstp);
src.unlock2d(srcp);
dst.unlock2d(dstp);


return dst; return dst;
} }


static Image SepConv(Image &src, array<float> const &hvec,
static image SepConv(image &src, array<float> const &hvec,
array<float> const &vvec) array<float> const &vvec)
{ {
bool const wrap_x = src.GetWrapX() == WrapMode::Repeat; bool const wrap_x = src.GetWrapX() == WrapMode::Repeat;
bool const wrap_y = src.GetWrapY() == WrapMode::Repeat; bool const wrap_y = src.GetWrapY() == WrapMode::Repeat;


if (src.GetFormat() == PixelFormat::Y_8
|| src.GetFormat() == PixelFormat::Y_F32)
if (src.format() == PixelFormat::Y_8
|| src.format() == PixelFormat::Y_F32)
{ {
if (wrap_x) if (wrap_x)
{ {


+ 76
- 74
src/image/filter/dilate.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -22,115 +24,115 @@
namespace lol namespace lol
{ {


Image Image::Dilate()
image image::Dilate()
{ {
ivec2 const size = GetSize();
Image ret(size);
ivec2 isize = size();
image ret(isize);


if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
if (format() == PixelFormat::Y_8 || format() == PixelFormat::Y_F32)
{ {
float const *srcp = Lock<PixelFormat::Y_F32>();
float *dstp = ret.Lock<PixelFormat::Y_F32>();
float const *srcp = lock<PixelFormat::Y_F32>();
float *dstp = ret.lock<PixelFormat::Y_F32>();


for (int y = 0; y < size.y; ++y)
for (int x = 0; x < size.x; ++x)
for (int y = 0; y < isize.y; ++y)
for (int x = 0; x < isize.x; ++x)
{ {
int y2 = lol::max(y - 1, 0); int y2 = lol::max(y - 1, 0);
int x2 = lol::max(x - 1, 0); int x2 = lol::max(x - 1, 0);
int y3 = lol::min(y + 1, size.y - 1);
int x3 = lol::min(x + 1, size.x - 1);
float t = srcp[y * size.x + x];
t = lol::max(t, srcp[y * size.x + x2]);
t = lol::max(t, srcp[y * size.x + x3]);
t = lol::max(t, srcp[y2 * size.x + x]);
t = lol::max(t, srcp[y3 * size.x + x]);
dstp[y * size.x + x] = t;
int y3 = lol::min(y + 1, isize.y - 1);
int x3 = lol::min(x + 1, isize.x - 1);
float t = srcp[y * isize.x + x];
t = lol::max(t, srcp[y * isize.x + x2]);
t = lol::max(t, srcp[y * isize.x + x3]);
t = lol::max(t, srcp[y2 * isize.x + x]);
t = lol::max(t, srcp[y3 * isize.x + x]);
dstp[y * isize.x + x] = t;
} }


Unlock(srcp);
ret.Unlock(dstp);
unlock(srcp);
ret.unlock(dstp);
} }
else else
{ {
vec4 const *srcp = Lock<PixelFormat::RGBA_F32>();
vec4 *dstp = ret.Lock<PixelFormat::RGBA_F32>();
vec4 const *srcp = lock<PixelFormat::RGBA_F32>();
vec4 *dstp = ret.lock<PixelFormat::RGBA_F32>();


for (int y = 0; y < size.y; ++y)
for (int x = 0; x < size.x; ++x)
for (int y = 0; y < isize.y; ++y)
for (int x = 0; x < isize.x; ++x)
{ {
int y2 = lol::max(y - 1, 0); int y2 = lol::max(y - 1, 0);
int x2 = lol::max(x - 1, 0); int x2 = lol::max(x - 1, 0);
int y3 = lol::min(y + 1, size.y - 1);
int x3 = lol::min(x + 1, size.x - 1);
vec3 t = srcp[y * size.x + x].rgb;
t = lol::max(t, srcp[y * size.x + x2].rgb);
t = lol::max(t, srcp[y * size.x + x3].rgb);
t = lol::max(t, srcp[y2 * size.x + x].rgb);
t = lol::max(t, srcp[y3 * size.x + x].rgb);
dstp[y * size.x + x] = vec4(t, srcp[y * size.x + x].a);
int y3 = lol::min(y + 1, isize.y - 1);
int x3 = lol::min(x + 1, isize.x - 1);
vec3 t = srcp[y * isize.x + x].rgb;
t = lol::max(t, srcp[y * isize.x + x2].rgb);
t = lol::max(t, srcp[y * isize.x + x3].rgb);
t = lol::max(t, srcp[y2 * isize.x + x].rgb);
t = lol::max(t, srcp[y3 * isize.x + x].rgb);
dstp[y * isize.x + x] = vec4(t, srcp[y * isize.x + x].a);
} }


Unlock(srcp);
ret.Unlock(dstp);
unlock(srcp);
ret.unlock(dstp);
} }


return ret; return ret;
} }


Image Image::Erode()
image image::Erode()
{ {
ivec2 const size = GetSize();
Image ret(size);
ivec2 isize = size();
image ret(isize);


if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
if (format() == PixelFormat::Y_8 || format() == PixelFormat::Y_F32)
{ {
float const *srcp = Lock<PixelFormat::Y_F32>();
float *dstp = ret.Lock<PixelFormat::Y_F32>();
float const *srcp = lock<PixelFormat::Y_F32>();
float *dstp = ret.lock<PixelFormat::Y_F32>();


for (int y = 0; y < size.y; ++y)
for (int x = 0; x < size.x; ++x)
for (int y = 0; y < isize.y; ++y)
for (int x = 0; x < isize.x; ++x)
{ {
int y2 = lol::max(y - 1, 0); int y2 = lol::max(y - 1, 0);
int x2 = lol::max(x - 1, 0); int x2 = lol::max(x - 1, 0);
int y3 = lol::min(y + 1, size.y - 1);
int x3 = lol::min(x + 1, size.x - 1);
float t = srcp[y * size.x + x];
t = lol::max(t, srcp[y * size.x + x2]);
t = lol::max(t, srcp[y * size.x + x3]);
t = lol::max(t, srcp[y2 * size.x + x]);
t = lol::max(t, srcp[y3 * size.x + x]);
dstp[y * size.x + x] = t;
int y3 = lol::min(y + 1, isize.y - 1);
int x3 = lol::min(x + 1, isize.x - 1);
float t = srcp[y * isize.x + x];
t = lol::max(t, srcp[y * isize.x + x2]);
t = lol::max(t, srcp[y * isize.x + x3]);
t = lol::max(t, srcp[y2 * isize.x + x]);
t = lol::max(t, srcp[y3 * isize.x + x]);
dstp[y * isize.x + x] = t;
} }


Unlock(srcp);
ret.Unlock(dstp);
unlock(srcp);
ret.unlock(dstp);
} }
else else
{ {
vec4 const *srcp = Lock<PixelFormat::RGBA_F32>();
vec4 *dstp = ret.Lock<PixelFormat::RGBA_F32>();
vec4 const *srcp = lock<PixelFormat::RGBA_F32>();
vec4 *dstp = ret.lock<PixelFormat::RGBA_F32>();


for (int y = 0; y < size.y; ++y)
for (int x = 0; x < size.x; ++x)
for (int y = 0; y < isize.y; ++y)
for (int x = 0; x < isize.x; ++x)
{ {
int y2 = lol::max(y - 1, 0); int y2 = lol::max(y - 1, 0);
int x2 = lol::max(x - 1, 0); int x2 = lol::max(x - 1, 0);
int y3 = lol::min(y + 1, size.y - 1);
int x3 = lol::min(x + 1, size.x - 1);
vec3 t = srcp[y * size.x + x].rgb;
t = lol::min(t, srcp[y * size.x + x2].rgb);
t = lol::min(t, srcp[y * size.x + x3].rgb);
t = lol::min(t, srcp[y2 * size.x + x].rgb);
t = lol::min(t, srcp[y3 * size.x + x].rgb);
dstp[y * size.x + x] = vec4(t, srcp[y * size.x + x].a);
int y3 = lol::min(y + 1, isize.y - 1);
int x3 = lol::min(x + 1, isize.x - 1);
vec3 t = srcp[y * isize.x + x].rgb;
t = lol::min(t, srcp[y * isize.x + x2].rgb);
t = lol::min(t, srcp[y * isize.x + x3].rgb);
t = lol::min(t, srcp[y2 * isize.x + x].rgb);
t = lol::min(t, srcp[y3 * isize.x + x].rgb);
dstp[y * isize.x + x] = vec4(t, srcp[y * isize.x + x].a);
} }


Unlock(srcp);
ret.Unlock(dstp);
unlock(srcp);
ret.unlock(dstp);
} }


return ret; return ret;


+ 54
- 52
src/image/filter/median.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -33,38 +35,38 @@ static int cmpfloat(void const *i1, void const *i2)
return (a > b) - (a < b); return (a > b) - (a < b);
} }


Image Image::Median(ivec2 ksize) const
image image::Median(ivec2 ksize) const
{ {
ivec2 const size = GetSize();
Image tmp = *this;
Image ret(size);
ivec2 const isize = size();
image tmp = *this;
image ret(isize);


if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
if (format() == PixelFormat::Y_8 || format() == PixelFormat::Y_F32)
{ {
ivec2 const lsize = 2 * ksize + ivec2(1); ivec2 const lsize = 2 * ksize + ivec2(1);
array2d<float> list(lsize); array2d<float> list(lsize);


float *srcp = tmp.Lock<PixelFormat::Y_F32>();
float *dstp = ret.Lock<PixelFormat::Y_F32>();
float *srcp = tmp.lock<PixelFormat::Y_F32>();
float *dstp = ret.lock<PixelFormat::Y_F32>();


for (int y = 0; y < size.y; y++)
for (int y = 0; y < isize.y; y++)
{ {
for (int x = 0; x < size.x; x++)
for (int x = 0; x < isize.x; x++)
{ {
/* Make a list of neighbours */ /* Make a list of neighbours */
for (int j = -ksize.y; j <= ksize.y; j++) for (int j = -ksize.y; j <= ksize.y; j++)
{ {
int y2 = y + j; int y2 = y + j;
if (y2 < 0) y2 = size.y - 1 - ((-y2 - 1) % size.y);
else if (y2 > 0) y2 = y2 % size.y;
if (y2 < 0) y2 = isize.y - 1 - ((-y2 - 1) % isize.y);
else if (y2 > 0) y2 = y2 % isize.y;


for (int i = -ksize.x; i <= ksize.x; i++) for (int i = -ksize.x; i <= ksize.x; i++)
{ {
int x2 = x + i; int x2 = x + i;
if (x2 < 0) x2 = size.x - 1 - ((-x2 - 1) % size.x);
else if (x2 > 0) x2 = x2 % size.x;
if (x2 < 0) x2 = isize.x - 1 - ((-x2 - 1) % isize.x);
else if (x2 > 0) x2 = x2 % isize.x;


list[i + ksize.x][j + ksize.y] = srcp[y2 * size.x + x2];
list[i + ksize.x][j + ksize.y] = srcp[y2 * isize.x + x2];
} }
} }


@@ -72,39 +74,39 @@ Image Image::Median(ivec2 ksize) const
qsort(&list[0][0], lsize.x * lsize.y, sizeof(float), cmpfloat); qsort(&list[0][0], lsize.x * lsize.y, sizeof(float), cmpfloat);


/* Store the median value */ /* Store the median value */
dstp[y * size.x + x] = *(&list[0][0] + lsize.x * lsize.y / 2);
dstp[y * isize.x + x] = *(&list[0][0] + lsize.x * lsize.y / 2);
} }
} }


tmp.Unlock(srcp);
ret.Unlock(dstp);
tmp.unlock(srcp);
ret.unlock(dstp);
} }
else else
{ {
ivec2 const lsize = 2 * ksize + ivec2(1); ivec2 const lsize = 2 * ksize + ivec2(1);
array2d<vec3> list(lsize); array2d<vec3> list(lsize);


vec4 *srcp = tmp.Lock<PixelFormat::RGBA_F32>();
vec4 *dstp = ret.Lock<PixelFormat::RGBA_F32>();
vec4 *srcp = tmp.lock<PixelFormat::RGBA_F32>();
vec4 *dstp = ret.lock<PixelFormat::RGBA_F32>();


for (int y = 0; y < size.y; y++)
for (int y = 0; y < isize.y; y++)
{ {
for (int x = 0; x < size.x; x++)
for (int x = 0; x < isize.x; x++)
{ {
/* Make a list of neighbours */ /* Make a list of neighbours */
for (int j = -ksize.y; j <= ksize.y; j++) for (int j = -ksize.y; j <= ksize.y; j++)
{ {
int y2 = y + j; int y2 = y + j;
if (y2 < 0) y2 = size.y - 1 - ((-y2 - 1) % size.y);
else if (y2 > 0) y2 = y2 % size.y;
if (y2 < 0) y2 = isize.y - 1 - ((-y2 - 1) % isize.y);
else if (y2 > 0) y2 = y2 % isize.y;


for (int i = -ksize.x; i <= ksize.x; i++) for (int i = -ksize.x; i <= ksize.x; i++)
{ {
int x2 = x + i; int x2 = x + i;
if (x2 < 0) x2 = size.x - 1 - ((-x2 - 1) % size.x);
else if (x2 > 0) x2 = x2 % size.x;
if (x2 < 0) x2 = isize.x - 1 - ((-x2 - 1) % isize.x);
else if (x2 > 0) x2 = x2 % isize.x;


list[i + ksize.x][j + ksize.y] = srcp[y2 * size.x + x2].rgb;
list[i + ksize.x][j + ksize.y] = srcp[y2 * isize.x + x2].rgb;
} }
} }


@@ -139,26 +141,26 @@ Image Image::Median(ivec2 ksize) const
} }


/* Store the median value */ /* Store the median value */
dstp[y * size.x + x] = vec4(median, srcp[y * size.x + x].a);
dstp[y * isize.x + x] = vec4(median, srcp[y * isize.x + x].a);
} }
} }


tmp.Unlock(srcp);
ret.Unlock(dstp);
tmp.unlock(srcp);
ret.unlock(dstp);
} }


return ret; return ret;
} }


Image Image::Median(array2d<float> const &kernel) const
image image::Median(array2d<float> const &kernel) const
{ {
ivec2 const size = GetSize();
Image tmp = *this;
Image ret(size);
ivec2 const isize = size();
image tmp = *this;
image ret(isize);


/* FIXME: TODO */ /* FIXME: TODO */
#if 0 #if 0
if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
if (format() == PixelFormat::Y_8 || format() == PixelFormat::Y_F32)
{ {
} }
else else
@@ -167,27 +169,27 @@ Image Image::Median(array2d<float> const &kernel) const
ivec2 const ksize = kernel.size(); ivec2 const ksize = kernel.size();
array2d<vec3> list(ksize); array2d<vec3> list(ksize);


vec4 *srcp = tmp.Lock<PixelFormat::RGBA_F32>();
vec4 *dstp = ret.Lock<PixelFormat::RGBA_F32>();
vec4 *srcp = tmp.lock<PixelFormat::RGBA_F32>();
vec4 *dstp = ret.lock<PixelFormat::RGBA_F32>();


for (int y = 0; y < size.y; y++)
for (int y = 0; y < isize.y; y++)
{ {
for (int x = 0; x < size.x; x++)
for (int x = 0; x < isize.x; x++)
{ {
/* Make a list of neighbours */ /* Make a list of neighbours */
for (int j = 0; j < ksize.y; j++) for (int j = 0; j < ksize.y; j++)
{ {
int y2 = y + j - ksize.y / 2; int y2 = y + j - ksize.y / 2;
if (y2 < 0) y2 = size.y - 1 - ((-y2 - 1) % size.y);
else if (y2 > 0) y2 = y2 % size.y;
if (y2 < 0) y2 = isize.y - 1 - ((-y2 - 1) % isize.y);
else if (y2 > 0) y2 = y2 % isize.y;


for (int i = 0; i < ksize.x; i++) for (int i = 0; i < ksize.x; i++)
{ {
int x2 = x + i - ksize.x / 2; int x2 = x + i - ksize.x / 2;
if (x2 < 0) x2 = size.x - 1 - ((-x2 - 1) % size.x);
else if (x2 > 0) x2 = x2 % size.x;
if (x2 < 0) x2 = isize.x - 1 - ((-x2 - 1) % isize.x);
else if (x2 > 0) x2 = x2 % isize.x;


list[i][j] = srcp[y2 * size.x + x2].rgb;
list[i][j] = srcp[y2 * isize.x + x2].rgb;
} }
} }


@@ -222,12 +224,12 @@ Image Image::Median(array2d<float> const &kernel) const
} }


/* Store the median value */ /* Store the median value */
dstp[y * size.x + x] = vec4(median, srcp[y * size.x + x].a);
dstp[y * isize.x + x] = vec4(median, srcp[y * isize.x + x].a);
} }
} }


tmp.Unlock(srcp);
ret.Unlock(dstp);
tmp.unlock(srcp);
ret.unlock(dstp);
} }


return ret; return ret;


+ 18
- 16
src/image/filter/yuv.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -17,28 +19,28 @@
namespace lol namespace lol
{ {


Image Image::YUVToRGB() const
image image::YUVToRGB() const
{ {
Image ret = *this;
int count = GetSize().x * GetSize().y;
image ret = *this;
int count = size().x * size().y;


vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>();
vec4 *pixels = ret.lock<PixelFormat::RGBA_F32>();
for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
pixels[n] = Color::YUVToRGB(pixels[n]); pixels[n] = Color::YUVToRGB(pixels[n]);
ret.Unlock(pixels);
ret.unlock(pixels);


return ret; return ret;
} }


Image Image::RGBToYUV() const
image image::RGBToYUV() const
{ {
Image ret = *this;
int count = GetSize().x * GetSize().y;
image ret = *this;
int count = size().x * size().y;


vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>();
vec4 *pixels = ret.lock<PixelFormat::RGBA_F32>();
for (int n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
pixels[n] = Color::RGBToYUV(pixels[n]); pixels[n] = Color::RGBToYUV(pixels[n]);
ret.Unlock(pixels);
ret.unlock(pixels);


return ret; return ret;
} }


+ 27
- 27
src/image/image.cpp 查看文件

@@ -1,7 +1,7 @@
// //
// Lol Engine // Lol Engine
// //
// Copyright © 2010—2016 Sam Hocevar <sam@hocevar.net>
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
// //
// Lol Engine is free software. It comes without any warranty, to // Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it // the extent permitted by applicable law. You can redistribute it
@@ -20,7 +20,7 @@ namespace lol
{ {


/* /*
* Public Image class
* Public image class
*/ */


image::image() image::image()
@@ -31,13 +31,13 @@ image::image()
image::image(char const *path) image::image(char const *path)
: m_data(new image_data()) : m_data(new image_data())
{ {
Load(path);
load(path);
} }


image::image(ivec2 size) image::image(ivec2 size)
: m_data(new image_data()) : m_data(new image_data())
{ {
SetSize(size);
resize(size);
} }


image::image (image const &other) image::image (image const &other)
@@ -65,21 +65,21 @@ image::~image()
void image::Copy(uint8_t* src_pixels, ivec2 const& size, PixelFormat fmt) void image::Copy(uint8_t* src_pixels, ivec2 const& size, PixelFormat fmt)
{ {
ASSERT(fmt != PixelFormat::Unknown); ASSERT(fmt != PixelFormat::Unknown);
SetSize(size);
SetFormat(fmt);
resize(size);
set_format(fmt);
memcpy(m_data->m_pixels[(int)fmt]->data(), src_pixels, memcpy(m_data->m_pixels[(int)fmt]->data(), src_pixels,
size.x * size.y * BytesPerPixel(fmt)); size.x * size.y * BytesPerPixel(fmt));
} }


void image::Copy(image const &src) void image::Copy(image const &src)
{ {
ivec2 size = src.GetSize();
PixelFormat fmt = src.GetFormat();
ivec2 size = src.size();
PixelFormat fmt = src.format();


SetSize(size);
resize(size);
if (fmt != PixelFormat::Unknown) if (fmt != PixelFormat::Unknown)
{ {
SetFormat(fmt);
set_format(fmt);
memcpy(m_data->m_pixels[(int)fmt]->data(), memcpy(m_data->m_pixels[(int)fmt]->data(),
src.m_data->m_pixels[(int)fmt]->data(), src.m_data->m_pixels[(int)fmt]->data(),
size.x * size.y * BytesPerPixel(fmt)); size.x * size.y * BytesPerPixel(fmt));
@@ -88,10 +88,10 @@ void image::Copy(image const &src)


void image::DummyFill() void image::DummyFill()
{ {
Load("DUMMY");
load("DUMMY");
} }


bool image::Load(char const *path)
bool image::load(char const *path)
{ {
auto resource = ResourceLoader::Load(path); auto resource = ResourceLoader::Load(path);
if (resource == nullptr) if (resource == nullptr)
@@ -109,7 +109,7 @@ bool image::Load(char const *path)
return true; return true;
} }


bool image::Save(char const *path)
bool image::save(char const *path)
{ {
auto data = new ResourceImageData(new image(*this)); auto data = new ResourceImageData(new image(*this));
auto result = ResourceLoader::Save(path, data); auto result = ResourceLoader::Save(path, data);
@@ -117,12 +117,12 @@ bool image::Save(char const *path)
return result; return result;
} }


ivec2 image::GetSize() const
ivec2 image::size() const
{ {
return m_data->m_size; return m_data->m_size;
} }


void image::SetSize(ivec2 size)
void image::resize(ivec2 size)
{ {
ASSERT(size.x > 0); ASSERT(size.x > 0);
ASSERT(size.y > 0); ASSERT(size.y > 0);
@@ -158,24 +158,24 @@ void image::SetWrap(WrapMode wrap_x, WrapMode wrap_y)
m_data->m_wrap_y = wrap_y; m_data->m_wrap_y = wrap_y;
} }


/* The Lock() method */
template<PixelFormat T> typename PixelType<T>::type *image::Lock()
/* The lock() method */
template<PixelFormat T> typename PixelType<T>::type *image::lock()
{ {
SetFormat(T);
set_format(T);


return (typename PixelType<T>::type *)m_data->m_pixels[(int)T]->data(); return (typename PixelType<T>::type *)m_data->m_pixels[(int)T]->data();
} }


/* The Lock2D() method */
void *image::Lock2DHelper(PixelFormat T)
/* The lock2d() method */
void *image::lock2d_helper(PixelFormat T)
{ {
SetFormat(T);
set_format(T);


return m_data->m_pixels[(int)T]->data2d(); return m_data->m_pixels[(int)T]->data2d();
} }


template<typename T> template<typename T>
void image::Unlock2D(array2d<T> const &array)
void image::unlock2d(array2d<T> const &array)
{ {
ASSERT(m_data->m_pixels.has_key((int)m_data->m_format)); ASSERT(m_data->m_pixels.has_key((int)m_data->m_format));
ASSERT(array.data() == m_data->m_pixels[(int)m_data->m_format]->data()); ASSERT(array.data() == m_data->m_pixels[(int)m_data->m_format]->data());
@@ -183,9 +183,9 @@ void image::Unlock2D(array2d<T> const &array)


/* Explicit specialisations for the above templates */ /* Explicit specialisations for the above templates */
#define _T(T) \ #define _T(T) \
template PixelType<T>::type *image::Lock<T>(); \
template array2d<PixelType<T>::type> &image::Lock2D<T>(); \
template void image::Unlock2D(array2d<PixelType<T>::type> const &array);
template PixelType<T>::type *image::lock<T>(); \
template array2d<PixelType<T>::type> &image::lock2d<T>(); \
template void image::unlock2d(array2d<PixelType<T>::type> const &array);
_T(PixelFormat::Y_8) _T(PixelFormat::Y_8)
_T(PixelFormat::RGB_8) _T(PixelFormat::RGB_8)
_T(PixelFormat::RGBA_8) _T(PixelFormat::RGBA_8)
@@ -195,14 +195,14 @@ _T(PixelFormat::RGBA_F32)
#undef _T #undef _T


/* Special case for the "any" format: return the last active buffer */ /* Special case for the "any" format: return the last active buffer */
void *image::Lock()
void *image::lock()
{ {
ASSERT(m_data->m_format != PixelFormat::Unknown); ASSERT(m_data->m_format != PixelFormat::Unknown);


return m_data->m_pixels[(int)m_data->m_format]->data(); return m_data->m_pixels[(int)m_data->m_format]->data();
} }


void image::Unlock(void const *pixels)
void image::unlock(void const *pixels)
{ {
ASSERT(m_data->m_pixels.has_key((int)m_data->m_format)); ASSERT(m_data->m_pixels.has_key((int)m_data->m_format));
ASSERT(pixels == m_data->m_pixels[(int)m_data->m_format]->data()); ASSERT(pixels == m_data->m_pixels[(int)m_data->m_format]->data());


+ 15
- 13
src/image/kernel.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -17,7 +19,7 @@
namespace lol namespace lol
{ {


array2d<float> image::BayerKernel(ivec2 size)
array2d<float> image::kernel::bayer(ivec2 size)
{ {
array2d<float> ret(size); array2d<float> ret(size);


@@ -46,7 +48,7 @@ array2d<float> image::BayerKernel(ivec2 size)
return ret; return ret;
} }


array2d<float> image::HalftoneKernel(ivec2 size)
array2d<float> image::kernel::halftone(ivec2 size)
{ {
array2d<float> ret(size); array2d<float> ret(size);


@@ -72,10 +74,10 @@ array2d<float> image::HalftoneKernel(ivec2 size)
ret[x][y] = flip ? 10.f - r : r; ret[x][y] = flip ? 10.f - r : r;
} }


return NormalizeKernel(ret);
return normalize(ret);
} }


array2d<float> image::BlueNoiseKernel(ivec2 size, ivec2 gsize)
array2d<float> image::kernel::blue_noise(ivec2 size, ivec2 gsize)
{ {
float const epsilon = 1.f / (size.x * size.y + 1); float const epsilon = 1.f / (size.x * size.y + 1);
gsize = lol::min(size, gsize); gsize = lol::min(size, gsize);
@@ -180,7 +182,7 @@ static int cmpdot(const void *p1, const void *p2)
return ((Dot const *)p1)->val > ((Dot const *)p2)->val; return ((Dot const *)p1)->val > ((Dot const *)p2)->val;
} }


array2d<float> image::NormalizeKernel(array2d<float> const &kernel)
array2d<float> image::kernel::normalize(array2d<float> const &kernel)
{ {
ivec2 size = kernel.size(); ivec2 size = kernel.size();


@@ -209,7 +211,7 @@ array2d<float> image::NormalizeKernel(array2d<float> const &kernel)
return dst; return dst;
} }


array2d<float> image::EdiffKernel(EdiffAlgorithm algorithm)
array2d<float> image::kernel::ediff(EdiffAlgorithm algorithm)
{ {
switch (algorithm) switch (algorithm)
{ {
@@ -270,7 +272,7 @@ array2d<float> image::EdiffKernel(EdiffAlgorithm algorithm)
* there is little chance that any value below 0.2 will be useful. */ * there is little chance that any value below 0.2 will be useful. */
#define BLUR_EPSILON 0.2f #define BLUR_EPSILON 0.2f


array2d<float> image::GaussianKernel(vec2 radius, float angle, vec2 delta)
array2d<float> image::kernel::gaussian(vec2 radius, float angle, vec2 delta)
{ {
array2d<float> kernel; array2d<float> kernel;




+ 11
- 9
src/image/noise.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -19,8 +21,8 @@ namespace lol


bool image::RenderRandom(ivec2 size) bool image::RenderRandom(ivec2 size)
{ {
SetSize(size);
vec4 *pixels = Lock<PixelFormat::RGBA_F32>();
resize(size);
vec4 *pixels = lock<PixelFormat::RGBA_F32>();


for (int n = 0; n < size.x * size.y; ++n) for (int n = 0; n < size.x * size.y; ++n)
pixels[n] = vec4(lol::rand(1.f), pixels[n] = vec4(lol::rand(1.f),
@@ -28,7 +30,7 @@ bool image::RenderRandom(ivec2 size)
lol::rand(1.f), lol::rand(1.f),
1.f); 1.f);


Unlock(pixels);
unlock(pixels);


return true; return true;
} }


+ 33
- 33
src/image/pixel.cpp 查看文件

@@ -1,7 +1,7 @@
// //
// Lol Engine // Lol Engine
// //
// Copyright © 2004—2015 Sam Hocevar <sam@hocevar.net>
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
// //
// Lol Engine is free software. It comes without any warranty, to // Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it // the extent permitted by applicable law. You can redistribute it
@@ -60,7 +60,7 @@ static u8vec4 f32tou8(vec4 pixel)
* Pixel-level image manipulation * Pixel-level image manipulation
*/ */


PixelFormat image::GetFormat() const
PixelFormat image::format() const
{ {
return m_data->m_format; return m_data->m_format;
} }
@@ -81,41 +81,41 @@ PixelFormat image::GetFormat() const
* x lossless conversion (u8 to float) * x lossless conversion (u8 to float)
* # lossy conversion (dithering and/or convert color→gray) * # lossy conversion (dithering and/or convert color→gray)
*/ */
void image::SetFormat(PixelFormat fmt)
void image::set_format(PixelFormat fmt)
{ {
PixelFormat old_fmt = m_data->m_format; PixelFormat old_fmt = m_data->m_format;


/* Preliminary intermediate conversions */ /* Preliminary intermediate conversions */
if (old_fmt == PixelFormat::RGBA_8 && fmt == PixelFormat::Y_F32) if (old_fmt == PixelFormat::RGBA_8 && fmt == PixelFormat::Y_F32)
SetFormat(PixelFormat::RGBA_F32);
set_format(PixelFormat::RGBA_F32);
else if (old_fmt == PixelFormat::RGB_8 && fmt == PixelFormat::Y_F32) else if (old_fmt == PixelFormat::RGB_8 && fmt == PixelFormat::Y_F32)
SetFormat(PixelFormat::RGBA_F32);
set_format(PixelFormat::RGBA_F32);
else if (old_fmt == PixelFormat::Y_F32 && fmt == PixelFormat::RGBA_8) else if (old_fmt == PixelFormat::Y_F32 && fmt == PixelFormat::RGBA_8)
SetFormat(PixelFormat::RGBA_F32);
set_format(PixelFormat::RGBA_F32);
else if (old_fmt == PixelFormat::Y_F32 && fmt == PixelFormat::RGB_8) else if (old_fmt == PixelFormat::Y_F32 && fmt == PixelFormat::RGB_8)
SetFormat(PixelFormat::RGBA_F32);
set_format(PixelFormat::RGBA_F32);
else if (old_fmt == PixelFormat::RGB_F32 && fmt == PixelFormat::RGBA_8) else if (old_fmt == PixelFormat::RGB_F32 && fmt == PixelFormat::RGBA_8)
SetFormat(PixelFormat::RGBA_F32);
set_format(PixelFormat::RGBA_F32);
else if (old_fmt == PixelFormat::RGBA_F32 && fmt == PixelFormat::Y_F32) else if (old_fmt == PixelFormat::RGBA_F32 && fmt == PixelFormat::Y_F32)
SetFormat(PixelFormat::RGB_F32);
set_format(PixelFormat::RGB_F32);
else if (old_fmt == PixelFormat::RGBA_F32 && fmt == PixelFormat::RGB_8) else if (old_fmt == PixelFormat::RGBA_F32 && fmt == PixelFormat::RGB_8)
SetFormat(PixelFormat::RGB_F32);
set_format(PixelFormat::RGB_F32);
else if (old_fmt == PixelFormat::RGB_8 && fmt == PixelFormat::Y_8) else if (old_fmt == PixelFormat::RGB_8 && fmt == PixelFormat::Y_8)
SetFormat(PixelFormat::RGB_F32);
set_format(PixelFormat::RGB_F32);
else if (old_fmt == PixelFormat::RGBA_8 && fmt == PixelFormat::Y_8) else if (old_fmt == PixelFormat::RGBA_8 && fmt == PixelFormat::Y_8)
SetFormat(PixelFormat::RGB_F32);
set_format(PixelFormat::RGB_F32);
else if (old_fmt == PixelFormat::RGB_F32 && fmt == PixelFormat::Y_8) else if (old_fmt == PixelFormat::RGB_F32 && fmt == PixelFormat::Y_8)
SetFormat(PixelFormat::Y_F32);
set_format(PixelFormat::Y_F32);
else if (old_fmt == PixelFormat::RGBA_F32 && fmt == PixelFormat::Y_8) else if (old_fmt == PixelFormat::RGBA_F32 && fmt == PixelFormat::Y_8)
SetFormat(PixelFormat::Y_F32);
set_format(PixelFormat::Y_F32);


old_fmt = m_data->m_format; old_fmt = m_data->m_format;


/* Set the new active pixel format */ /* Set the new active pixel format */
m_data->m_format = fmt; m_data->m_format = fmt;


ivec2 size = GetSize();
int count = size.x * size.y;
ivec2 isize = size();
int count = isize.x * isize.y;


/* If we never used this format, allocate a new buffer: we will /* If we never used this format, allocate a new buffer: we will
* obviously need it. */ * obviously need it. */
@@ -131,17 +131,17 @@ void image::SetFormat(PixelFormat fmt)
case PixelFormat::Unknown: case PixelFormat::Unknown:
break; break;
case PixelFormat::Y_8: case PixelFormat::Y_8:
data = new PixelData<PixelFormat::Y_8>(size); break;
data = new PixelData<PixelFormat::Y_8>(isize); break;
case PixelFormat::RGB_8: case PixelFormat::RGB_8:
data = new PixelData<PixelFormat::RGB_8>(size); break;
data = new PixelData<PixelFormat::RGB_8>(isize); break;
case PixelFormat::RGBA_8: case PixelFormat::RGBA_8:
data = new PixelData<PixelFormat::RGBA_8>(size); break;
data = new PixelData<PixelFormat::RGBA_8>(isize); break;
case PixelFormat::Y_F32: case PixelFormat::Y_F32:
data = new PixelData<PixelFormat::Y_F32>(size); break;
data = new PixelData<PixelFormat::Y_F32>(isize); break;
case PixelFormat::RGB_F32: case PixelFormat::RGB_F32:
data = new PixelData<PixelFormat::RGB_F32>(size); break;
data = new PixelData<PixelFormat::RGB_F32>(isize); break;
case PixelFormat::RGBA_F32: case PixelFormat::RGBA_F32:
data = new PixelData<PixelFormat::RGBA_F32>(size); break;
data = new PixelData<PixelFormat::RGBA_F32>(isize); break;
} }
#if __GNUC__ #if __GNUC__
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
@@ -314,31 +314,31 @@ void image::SetFormat(PixelFormat fmt)
#if 0 #if 0
init_tables(); init_tables();


for (int y = 0; y < size.y; y++)
for (int x = 0; x < size.x; x++)
for (int y = 0; y < isize.y; y++)
for (int x = 0; x < isize.x; x++)
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
double p, e; double p, e;
uint8_t d; uint8_t d;


p = src[4 * (y * size.x + x) + i];
p = src[4 * (y * isize.x + x) + i];


if (p < 0.) d = 0.; if (p < 0.) d = 0.;
else if (p > 1.) d = 255; else if (p > 1.) d = 255;
else d = (int)(255.999 * pow(p, 1. / global_gamma)); else d = (int)(255.999 * pow(p, 1. / global_gamma));


dest[4 * (y * size.x + x) + i] = d;
dest[4 * (y * isize.x + x) + i] = d;


e = (p - u8tof32(d)) / 16; e = (p - u8tof32(d)) / 16;
if (x < size.x - 1)
src[4 * (y * size.x + x + 1) + i] += e * 7;
if (y < size.y - 1)
if (x < isize.x - 1)
src[4 * (y * isize.x + x + 1) + i] += e * 7;
if (y < isize.y - 1)
{ {
if (x > 0) if (x > 0)
src[4 * ((y + 1) * size.x + x - 1) + i] += e * 3;
src[4 * ((y + 1) * size.x + x) + i] += e * 5;
if (x < size.x - 1)
src[4 * ((y + 1) * size.x + x + 1) + i] += e;
src[4 * ((y + 1) * isize.x + x - 1) + i] += e * 3;
src[4 * ((y + 1) * isize.x + x) + i] += e * 5;
if (x < isize.x - 1)
src[4 * ((y + 1) * isize.x + x + 1) + i] += e;
} }
} }
#endif #endif


+ 18
- 16
src/image/resample.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2004—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -35,10 +37,10 @@ image image::Resize(ivec2 size, ResampleAlgorithm algorithm)
static image ResizeBicubic(image &src, ivec2 size) static image ResizeBicubic(image &src, ivec2 size)
{ {
image dst(size); image dst(size);
ivec2 const oldsize = src.GetSize();
ivec2 const oldsize = src.size();


vec4 const *srcp = src.Lock<PixelFormat::RGBA_F32>();
vec4 *dstp = dst.Lock<PixelFormat::RGBA_F32>();
vec4 const *srcp = src.lock<PixelFormat::RGBA_F32>();
vec4 *dstp = dst.lock<PixelFormat::RGBA_F32>();


float scalex = size.x > 1 ? (oldsize.x - 1.f) / (size.x - 1) : 1.f; float scalex = size.x > 1 ? (oldsize.x - 1.f) / (size.x - 1) : 1.f;
float scaley = size.y > 1 ? (oldsize.y - 1.f) / (size.y - 1) : 1.f; float scaley = size.y > 1 ? (oldsize.y - 1.f) / (size.y - 1) : 1.f;
@@ -121,8 +123,8 @@ static image ResizeBicubic(image &src, ivec2 size)
} }
} }


dst.Unlock(dstp);
src.Unlock(srcp);
dst.unlock(dstp);
src.unlock(srcp);


return dst; return dst;
} }
@@ -137,11 +139,11 @@ static image ResizeBicubic(image &src, ivec2 size)
static image ResizeBresenham(image &src, ivec2 size) static image ResizeBresenham(image &src, ivec2 size)
{ {
image dst(size); image dst(size);
ivec2 const oldsize = src.GetSize();
ivec2 const oldsize = src.size();
float const invswsh = 1.0f / (oldsize.x * oldsize.y); float const invswsh = 1.0f / (oldsize.x * oldsize.y);


vec4 const *srcp = src.Lock<PixelFormat::RGBA_F32>();
vec4 *dstp = dst.Lock<PixelFormat::RGBA_F32>();
vec4 const *srcp = src.lock<PixelFormat::RGBA_F32>();
vec4 *dstp = dst.lock<PixelFormat::RGBA_F32>();


array<vec4> aline, line; array<vec4> aline, line;
aline.resize(size.x); aline.resize(size.x);
@@ -198,8 +200,8 @@ static image ResizeBresenham(image &src, ivec2 size)
dstp[y * size.x + x] = aline[x] * invswsh; dstp[y * size.x + x] = aline[x] * invswsh;
} }


dst.Unlock(dstp);
src.Unlock(srcp);
dst.unlock(dstp);
src.unlock(srcp);


return dst; return dst;
} }


+ 36
- 30
src/lol/image/image.h 查看文件

@@ -1,7 +1,7 @@
// //
// Lol Engine // Lol Engine
// //
// Copyright © 2010—2015 Sam Hocevar <sam@hocevar.net>
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
// //
// Lol Engine is free software. It comes without any warranty, to // Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it // the extent permitted by applicable law. You can redistribute it
@@ -76,46 +76,52 @@ public:
void DummyFill(); void DummyFill();
void Copy(uint8_t* pixels, ivec2 const& size, PixelFormat fmt); void Copy(uint8_t* pixels, ivec2 const& size, PixelFormat fmt);
void Copy(image const &other); void Copy(image const &other);
bool Load(char const *path);
bool Save(char const *path);
bool load(char const *path);
bool save(char const *path);


/* Low level access */ /* Low level access */
ivec2 GetSize() const;
void SetSize(ivec2);
ivec2 size() const;
void resize(ivec2);


PixelFormat GetFormat() const;
void SetFormat(PixelFormat fmt);
PixelFormat format() const;
void set_format(PixelFormat fmt);


WrapMode GetWrapX() const; WrapMode GetWrapX() const;
WrapMode GetWrapY() const; WrapMode GetWrapY() const;
void SetWrap(WrapMode wrap_x, WrapMode wrap_y); void SetWrap(WrapMode wrap_x, WrapMode wrap_y);


/* Lock continuous arrays of pixels for writing */ /* Lock continuous arrays of pixels for writing */
template<PixelFormat T> typename PixelType<T>::type *Lock();
void *Lock();
void Unlock(void const *pixels);
template<PixelFormat T> typename PixelType<T>::type *lock();
void *lock();
void unlock(void const *pixels);


/* Lock 2D arrays of pixels for writing */ /* Lock 2D arrays of pixels for writing */
template<PixelFormat T> template<PixelFormat T>
inline array2d<typename PixelType<T>::type> &Lock2D()
inline array2d<typename PixelType<T>::type> &lock2d()
{ {
/* Hack: this indirection is needed because of a Visual Studio ICE */ /* Hack: this indirection is needed because of a Visual Studio ICE */
return *(array2d<typename PixelType<T>::type> *)Lock2DHelper(T);
return *(array2d<typename PixelType<T>::type> *)lock2d_helper(T);
} }


template<typename T> template<typename T>
void Unlock2D(array2d<T> const &);
void unlock2d(array2d<T> const &);


/* Image processing kernels */ /* Image processing kernels */
static array2d<float> BayerKernel(ivec2 size);
static array2d<float> HalftoneKernel(ivec2 size);
static array2d<float> BlueNoiseKernel(ivec2 size,
ivec2 gsize = ivec2(7, 7));
static array2d<float> EdiffKernel(EdiffAlgorithm algorithm);
static array2d<float> NormalizeKernel(array2d<float> const &kernel);
static array2d<float> GaussianKernel(vec2 radius,
float angle = 0.f,
vec2 delta = vec2(0.f, 0.f));
struct kernel
{
kernel() = delete;

static array2d<float> normalize(array2d<float> const &kernel);

static array2d<float> bayer(ivec2 size);
static array2d<float> halftone(ivec2 size);
static array2d<float> blue_noise(ivec2 size,
ivec2 gsize = ivec2(7, 7));
static array2d<float> ediff(EdiffAlgorithm algorithm);
static array2d<float> gaussian(vec2 radius,
float angle = 0.f,
vec2 delta = vec2(0.f, 0.f));
};


/* Rendering */ /* Rendering */
bool RenderRandom(ivec2 size); bool RenderRandom(ivec2 size);
@@ -141,13 +147,13 @@ public:
image YUVToRGB() const; image YUVToRGB() const;


/* Dithering */ /* Dithering */
image DitherRandom() const;
image DitherEdiff(array2d<float> const &kernel,
ScanMode scan = ScanMode::Raster) const;
image DitherOstromoukhov(ScanMode scan = ScanMode::Raster) const;
image DitherOrdered(array2d<float> const &kernel) const;
image DitherHalftone(float radius, float angle) const;
image DitherDbs() const;
image dither_random() const;
image dither_ediff(array2d<float> const &kernel,
ScanMode scan = ScanMode::Raster) const;
image dither_ostromoukhov(ScanMode scan = ScanMode::Raster) const;
image dither_ordered(array2d<float> const &kernel) const;
image dither_halftone(float radius, float angle) const;
image dither_dbs() const;


/* Combine images */ /* Combine images */
static image Merge(image &src1, image &src2, float alpha); static image Merge(image &src1, image &src2, float alpha);
@@ -163,7 +169,7 @@ public:
static image Difference(image &src1, image &src2); static image Difference(image &src1, image &src2);


private: private:
void *Lock2DHelper(PixelFormat T);
void *lock2d_helper(PixelFormat T);


class image_data *m_data; class image_data *m_data;
}; };


+ 9
- 7
src/lol/sys/file.h 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#pragma once #pragma once
@@ -81,7 +83,7 @@ public:
int WriteString(const String &buf); int WriteString(const String &buf);
long int GetPosFromStart(); long int GetPosFromStart();
void SetPosFromStart(long int pos); void SetPosFromStart(long int pos);
long int GetSize();
long int size();
long int GetModificationTime(); long int GetModificationTime();


private: private:


+ 11
- 9
src/sys/file.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -182,7 +184,7 @@ class FileData
#endif #endif
} }


long int GetSize()
long int size()
{ {
#if __ANDROID__ #if __ANDROID__
return 0; return 0;
@@ -321,9 +323,9 @@ void File::SetPosFromStart(long int pos)
} }


//-- //--
long int File::GetSize()
long int File::size()
{ {
return m_data->GetSize();
return m_data->size();
} }


//-- //--


+ 2
- 2
src/sys/threadtypes.cpp 查看文件

@@ -1,7 +1,7 @@
// //
// Lol Engine // Lol Engine
// //
// Copyright © 2010—2015 Sam Hocevar <sam@hocevar.net>
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
// © 2014—2015 Benjamin “Touky” Huet <huet.benjamin@gmail.com> // © 2014—2015 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
// //
// Lol Engine is free software. It comes without any warranty, to // Lol Engine is free software. It comes without any warranty, to
@@ -175,7 +175,7 @@ public:
protected: protected:
virtual bool DoWork() virtual bool DoWork()
{ {
return m_image.Load(m_path.C());
return m_image.load(m_path.C());
} }


String m_path; String m_path;


+ 7
- 7
src/t/image/image.cpp 查看文件

@@ -1,7 +1,7 @@
// //
// Lol Engine — Unit tests // Lol Engine — Unit tests
// //
// Copyright © 2010—2015 Sam Hocevar <sam@hocevar.net>
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
// //
// Lol Engine is free software. It comes without any warranty, to // Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it // the extent permitted by applicable law. You can redistribute it
@@ -23,13 +23,13 @@ lolunit_declare_fixture(image_test)
{ {
lolunit_declare_test(open_image) lolunit_declare_test(open_image)
{ {
Image image("data/gradient.png");
image img("data/gradient.png");


ivec2 size = image.GetSize();
lolunit_assert_equal(size.x, 256);
lolunit_assert_equal(size.y, 16);
ivec2 isize = img.size();
lolunit_assert_equal(isize.x, 256);
lolunit_assert_equal(isize.y, 16);


u8vec4 *data = image.Lock<PixelFormat::RGBA_8>();
u8vec4 *data = img.lock<PixelFormat::RGBA_8>();
lolunit_assert(data); lolunit_assert(data);


lolunit_assert_equal((int)data[0].r, 0x00); lolunit_assert_equal((int)data[0].r, 0x00);
@@ -40,7 +40,7 @@ lolunit_declare_fixture(image_test)
lolunit_assert_equal((int)data[255].g, 0xff); lolunit_assert_equal((int)data[255].g, 0xff);
lolunit_assert_equal((int)data[255].b, 0xff); lolunit_assert_equal((int)data[255].b, 0xff);


image.Unlock(data);
img.unlock(data);
} }
}; };




+ 23
- 20
src/textureimage.cpp 查看文件

@@ -1,11 +1,13 @@
// //
// Lol Engine
// Lol Engine
// //
// Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
// //


#include <lol/engine-internal.h> #include <lol/engine-internal.h>
@@ -44,10 +46,10 @@ TextureImage::TextureImage(char const *path)
Init(path); Init(path);
} }


TextureImage::TextureImage(char const *path, Image* image)
TextureImage::TextureImage(char const *path, image* img)
: m_data(GetNewData()) : m_data(GetNewData())
{ {
Init(path, image);
Init(path, img);
} }


TextureImage::~TextureImage() TextureImage::~TextureImage()
@@ -66,19 +68,19 @@ void TextureImage::Init(char const *path, ResourceCodecData* loaded_data)
auto image_data = dynamic_cast<ResourceImageData*>(loaded_data); auto image_data = dynamic_cast<ResourceImageData*>(loaded_data);
if (image_data != nullptr) if (image_data != nullptr)
{ {
Init(path, new Image(*image_data->m_image));
Init(path, new image(*image_data->m_image));
} }


delete image_data; delete image_data;
} }


void TextureImage::Init(char const *path, Image* image)
void TextureImage::Init(char const *path, image* img)
{ {
m_data->m_name = String("<textureimage> ") + path; m_data->m_name = String("<textureimage> ") + path;


m_data->m_texture = nullptr; m_data->m_texture = nullptr;
m_data->m_image = image;
m_data->m_image_size = m_data->m_image->GetSize();
m_data->m_image = img;
m_data->m_image_size = m_data->m_image->size();
m_data->m_texture_size = ivec2(PotUp(m_data->m_image_size.x), m_data->m_texture_size = ivec2(PotUp(m_data->m_image_size.x),
PotUp(m_data->m_image_size.y)); PotUp(m_data->m_image_size.y));


@@ -111,13 +113,13 @@ void TextureImage::TickDraw(float seconds, Scene &scene)
m_data->m_texture = nullptr; m_data->m_texture = nullptr;
} }


PixelFormat format = m_data->m_image->GetFormat();
PixelFormat format = m_data->m_image->format();
int planes = BytesPerPixel(format); int planes = BytesPerPixel(format);


int w = m_data->m_texture_size.x; int w = m_data->m_texture_size.x;
int h = m_data->m_texture_size.y; int h = m_data->m_texture_size.y;


uint8_t *pixels = (uint8_t *)m_data->m_image->Lock();
uint8_t *pixels = (uint8_t *)m_data->m_image->lock();
bool resized = false; bool resized = false;
if (w != m_data->m_image_size.x || h != m_data->m_image_size.y) if (w != m_data->m_image_size.x || h != m_data->m_image_size.y)
{ {
@@ -129,6 +131,7 @@ void TextureImage::TickDraw(float seconds, Scene &scene)
pixels = tmp; pixels = tmp;
resized = false; resized = false;
} }
/* FIXME: no unlock? */


m_data->m_texture = new Texture(ivec2(w, h), format); m_data->m_texture = new Texture(ivec2(w, h), format);
m_data->m_texture->SetData(pixels); m_data->m_texture->SetData(pixels);
@@ -146,12 +149,12 @@ char const *TextureImage::GetName()
return m_data->m_name.C(); return m_data->m_name.C();
} }


void TextureImage::UpdateTexture(Image* image)
void TextureImage::UpdateTexture(image* img)
{ {
m_data->m_image = image;
m_data->m_image_size = m_data->m_image->GetSize();
m_data->m_image = img;
m_data->m_image_size = m_data->m_image->size();
m_data->m_texture_size = ivec2(PotUp(m_data->m_image_size.x), m_data->m_texture_size = ivec2(PotUp(m_data->m_image_size.x),
PotUp(m_data->m_image_size.y));
PotUp(m_data->m_image_size.y));
} }


Texture * TextureImage::GetTexture() Texture * TextureImage::GetTexture()
@@ -164,12 +167,12 @@ Texture const * TextureImage::GetTexture() const
return m_data->m_texture; return m_data->m_texture;
} }


Image * TextureImage::GetImage()
image * TextureImage::GetImage()
{ {
return m_data->m_image; return m_data->m_image;
} }


Image const * TextureImage::GetImage() const
image const * TextureImage::GetImage() const
{ {
return m_data->m_image; return m_data->m_image;
} }


Loading…
取消
儲存