add oversampler

This commit is contained in:
2024-05-24 13:28:31 +02:00
parent e4a4a661a0
commit 989dba5a6b
484 changed files with 313937 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
#ifndef _LICE_CURVE_RASTER_BUFFER_H_
#define _LICE_CURVE_RASTER_BUFFER_H_
class CurveRasterBuffer
{
static void CopyPixelNoClip(LICE_IBitmap *bmp, int x, int y, LICE_pixel col, double alpha)
{
LICE_pixel *p=bmp->getBits()+y*bmp->getRowSpan()+x;
if (*p == col || alpha <= 0.0) return;
if (alpha >= 1.0)
{
*p=col;
return;
}
const int ia=256-(int)(alpha*256.0);
int r=LICE_GETR(col), g=LICE_GETG(col), b=LICE_GETB(col);
LICE_pixel_chan *c=(LICE_pixel_chan*)p;
c[LICE_PIXEL_R]=r+((c[LICE_PIXEL_R]-r)*ia)/256;
c[LICE_PIXEL_G]=g+((c[LICE_PIXEL_G]-g)*ia)/256;
c[LICE_PIXEL_B]=b+((c[LICE_PIXEL_B]-b)*ia)/256;
}
static void DrawSlice(LICE_IBitmap* bmp, int x, double y1, double y2, int pxh, LICE_pixel color, float alpha)
{
const int iy1=(int)y1, iy2=(int)y2;
if (iy1 == iy2)
{
if (iy1 >= 0 && iy1 < pxh) CopyPixelNoClip(bmp, x, iy1, color, (y2-y1)*alpha);
}
else
{
if (iy1 >= 0 && iy1 < pxh) CopyPixelNoClip(bmp, x, iy1, color, (1+iy1-y1)*alpha);
if (iy2 > iy1+1)
{
int iy;
const int n=min(iy2, pxh);
for (iy=max(iy1+1, 0); iy < n; ++iy)
{
CopyPixelNoClip(bmp, x, iy, color, alpha);
}
}
if (iy2 >= 0 && iy2 < pxh) CopyPixelNoClip(bmp, x, iy2, color, (y2-iy2)*alpha);
}
}
public:
int xext[2],bmw;
float *sb;
CurveRasterBuffer(int w, WDL_TypedBuf<float> *sbuf)
{
xext[0]=bmw=w;
xext[1]=0;
sb = sbuf->ResizeOK(w*2,false);
}
void addpt(int xpos, double ypos)
{
if (xpos >= 0 && xpos < bmw)
{
float *p = sb + xpos*2;
const int ext0=xext[0], ext1=xext[1];
if (ext0 <= ext1) // existing range
{
if (xpos < ext0)
{
memset(p+2, 0, (ext0-xpos-1)*2*sizeof(*p));
p[0]=p[1]=ypos;
xext[0]=xpos;
}
else if (xpos > ext1)
{
memset(sb + (ext1+1)*2, 0, (xpos-(ext1+1))*2*sizeof(*p));
p[0]=p[1]=ypos;
xext[1]=xpos;
}
else if (p[0] == 0.0 && p[1] == 0.0) p[0] = p[1] = ypos;
else
{
if (ypos < p[0]) p[0] = ypos;
else if (ypos > p[1]) p[1] = ypos;
}
}
else // first point
{
xext[0]=xext[1] = xpos;
p[0]=p[1]=ypos;
}
}
}
void Draw(LICE_IBitmap *bm, LICE_pixel color, float alpha)
{
int bmh = bm->getHeight();
const int sc = (int) (INT_PTR)bm->Extended(LICE_EXT_GET_SCALING,NULL);
if (sc > 256) bmh = bmh * sc / 256;
const int xmax = xext[1];
int x = xext[0];
const float *sbuf = sb+x*2;
for (; x <= xmax; x ++)
{
const double v1 = sbuf[0], v2 = sbuf[1];
if (v2>v1) DrawSlice(bm, x,v1,v2, bmh, color,alpha);
sbuf+= 2;
}
}
};
#endif

View File

@@ -0,0 +1,631 @@
#ifndef __wglext_h_
#define __wglext_h_
#ifdef __cplusplus
extern "C" {
#endif
/*
** License Applicability. Except to the extent portions of this file are
** made subject to an alternative license as permitted in the SGI Free
** Software License B, Version 1.1 (the "License"), the contents of this
** file are subject only to the provisions of the License. You may not use
** this file except in compliance with the License. You may obtain a copy
** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
**
** http://oss.sgi.com/projects/FreeB
**
** Note that, as provided in the License, the Software is distributed on an
** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
**
** Original Code. The Original Code is: OpenGL Sample Implementation,
** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
** Inc. The Original Code is Copyright (c) 1991-2004 Silicon Graphics, Inc.
** Copyright in any portions created by third parties is as indicated
** elsewhere herein. All Rights Reserved.
**
** Additional Notice Provisions: This software was created using the
** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has
** not been independently verified as being compliant with the OpenGL(R)
** version 1.2.1 Specification.
*/
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#endif
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
#ifndef GLAPI
#define GLAPI extern
#endif
/*************************************************************/
/* Header file version number */
/* wglext.h last updated 2005/01/07 */
/* Current version at http://oss.sgi.com/projects/ogl-sample/registry/ */
#define WGL_WGLEXT_VERSION 6
#ifndef WGL_ARB_buffer_region
#define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001
#define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002
#define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004
#define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008
#endif
#ifndef WGL_ARB_multisample
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
#define WGL_SAMPLES_ARB 0x2042
#endif
#ifndef WGL_ARB_extensions_string
#endif
#ifndef WGL_ARB_pixel_format
#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_DRAW_TO_BITMAP_ARB 0x2002
#define WGL_ACCELERATION_ARB 0x2003
#define WGL_NEED_PALETTE_ARB 0x2004
#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
#define WGL_SWAP_METHOD_ARB 0x2007
#define WGL_NUMBER_OVERLAYS_ARB 0x2008
#define WGL_NUMBER_UNDERLAYS_ARB 0x2009
#define WGL_TRANSPARENT_ARB 0x200A
#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
#define WGL_SHARE_DEPTH_ARB 0x200C
#define WGL_SHARE_STENCIL_ARB 0x200D
#define WGL_SHARE_ACCUM_ARB 0x200E
#define WGL_SUPPORT_GDI_ARB 0x200F
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_STEREO_ARB 0x2012
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_COLOR_BITS_ARB 0x2014
#define WGL_RED_BITS_ARB 0x2015
#define WGL_RED_SHIFT_ARB 0x2016
#define WGL_GREEN_BITS_ARB 0x2017
#define WGL_GREEN_SHIFT_ARB 0x2018
#define WGL_BLUE_BITS_ARB 0x2019
#define WGL_BLUE_SHIFT_ARB 0x201A
#define WGL_ALPHA_BITS_ARB 0x201B
#define WGL_ALPHA_SHIFT_ARB 0x201C
#define WGL_ACCUM_BITS_ARB 0x201D
#define WGL_ACCUM_RED_BITS_ARB 0x201E
#define WGL_ACCUM_GREEN_BITS_ARB 0x201F
#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
#define WGL_AUX_BUFFERS_ARB 0x2024
#define WGL_NO_ACCELERATION_ARB 0x2025
#define WGL_GENERIC_ACCELERATION_ARB 0x2026
#define WGL_FULL_ACCELERATION_ARB 0x2027
#define WGL_SWAP_EXCHANGE_ARB 0x2028
#define WGL_SWAP_COPY_ARB 0x2029
#define WGL_SWAP_UNDEFINED_ARB 0x202A
#define WGL_TYPE_RGBA_ARB 0x202B
#define WGL_TYPE_COLORINDEX_ARB 0x202C
#endif
#ifndef WGL_ARB_make_current_read
#define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043
#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054
#endif
#ifndef WGL_ARB_pbuffer
#define WGL_DRAW_TO_PBUFFER_ARB 0x202D
#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E
#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F
#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030
#define WGL_PBUFFER_LARGEST_ARB 0x2033
#define WGL_PBUFFER_WIDTH_ARB 0x2034
#define WGL_PBUFFER_HEIGHT_ARB 0x2035
#define WGL_PBUFFER_LOST_ARB 0x2036
#endif
#ifndef WGL_ARB_render_texture
#define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070
#define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071
#define WGL_TEXTURE_FORMAT_ARB 0x2072
#define WGL_TEXTURE_TARGET_ARB 0x2073
#define WGL_MIPMAP_TEXTURE_ARB 0x2074
#define WGL_TEXTURE_RGB_ARB 0x2075
#define WGL_TEXTURE_RGBA_ARB 0x2076
#define WGL_NO_TEXTURE_ARB 0x2077
#define WGL_TEXTURE_CUBE_MAP_ARB 0x2078
#define WGL_TEXTURE_1D_ARB 0x2079
#define WGL_TEXTURE_2D_ARB 0x207A
#define WGL_MIPMAP_LEVEL_ARB 0x207B
#define WGL_CUBE_MAP_FACE_ARB 0x207C
#define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D
#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E
#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F
#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080
#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081
#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082
#define WGL_FRONT_LEFT_ARB 0x2083
#define WGL_FRONT_RIGHT_ARB 0x2084
#define WGL_BACK_LEFT_ARB 0x2085
#define WGL_BACK_RIGHT_ARB 0x2086
#define WGL_AUX0_ARB 0x2087
#define WGL_AUX1_ARB 0x2088
#define WGL_AUX2_ARB 0x2089
#define WGL_AUX3_ARB 0x208A
#define WGL_AUX4_ARB 0x208B
#define WGL_AUX5_ARB 0x208C
#define WGL_AUX6_ARB 0x208D
#define WGL_AUX7_ARB 0x208E
#define WGL_AUX8_ARB 0x208F
#define WGL_AUX9_ARB 0x2090
#endif
#ifndef WGL_ARB_pixel_format_float
#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0
#endif
#ifndef WGL_EXT_make_current_read
#define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043
#endif
#ifndef WGL_EXT_pixel_format
#define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000
#define WGL_DRAW_TO_WINDOW_EXT 0x2001
#define WGL_DRAW_TO_BITMAP_EXT 0x2002
#define WGL_ACCELERATION_EXT 0x2003
#define WGL_NEED_PALETTE_EXT 0x2004
#define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005
#define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006
#define WGL_SWAP_METHOD_EXT 0x2007
#define WGL_NUMBER_OVERLAYS_EXT 0x2008
#define WGL_NUMBER_UNDERLAYS_EXT 0x2009
#define WGL_TRANSPARENT_EXT 0x200A
#define WGL_TRANSPARENT_VALUE_EXT 0x200B
#define WGL_SHARE_DEPTH_EXT 0x200C
#define WGL_SHARE_STENCIL_EXT 0x200D
#define WGL_SHARE_ACCUM_EXT 0x200E
#define WGL_SUPPORT_GDI_EXT 0x200F
#define WGL_SUPPORT_OPENGL_EXT 0x2010
#define WGL_DOUBLE_BUFFER_EXT 0x2011
#define WGL_STEREO_EXT 0x2012
#define WGL_PIXEL_TYPE_EXT 0x2013
#define WGL_COLOR_BITS_EXT 0x2014
#define WGL_RED_BITS_EXT 0x2015
#define WGL_RED_SHIFT_EXT 0x2016
#define WGL_GREEN_BITS_EXT 0x2017
#define WGL_GREEN_SHIFT_EXT 0x2018
#define WGL_BLUE_BITS_EXT 0x2019
#define WGL_BLUE_SHIFT_EXT 0x201A
#define WGL_ALPHA_BITS_EXT 0x201B
#define WGL_ALPHA_SHIFT_EXT 0x201C
#define WGL_ACCUM_BITS_EXT 0x201D
#define WGL_ACCUM_RED_BITS_EXT 0x201E
#define WGL_ACCUM_GREEN_BITS_EXT 0x201F
#define WGL_ACCUM_BLUE_BITS_EXT 0x2020
#define WGL_ACCUM_ALPHA_BITS_EXT 0x2021
#define WGL_DEPTH_BITS_EXT 0x2022
#define WGL_STENCIL_BITS_EXT 0x2023
#define WGL_AUX_BUFFERS_EXT 0x2024
#define WGL_NO_ACCELERATION_EXT 0x2025
#define WGL_GENERIC_ACCELERATION_EXT 0x2026
#define WGL_FULL_ACCELERATION_EXT 0x2027
#define WGL_SWAP_EXCHANGE_EXT 0x2028
#define WGL_SWAP_COPY_EXT 0x2029
#define WGL_SWAP_UNDEFINED_EXT 0x202A
#define WGL_TYPE_RGBA_EXT 0x202B
#define WGL_TYPE_COLORINDEX_EXT 0x202C
#endif
#ifndef WGL_EXT_pbuffer
#define WGL_DRAW_TO_PBUFFER_EXT 0x202D
#define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E
#define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F
#define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030
#define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031
#define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032
#define WGL_PBUFFER_LARGEST_EXT 0x2033
#define WGL_PBUFFER_WIDTH_EXT 0x2034
#define WGL_PBUFFER_HEIGHT_EXT 0x2035
#endif
#ifndef WGL_EXT_depth_float
#define WGL_DEPTH_FLOAT_EXT 0x2040
#endif
#ifndef WGL_3DFX_multisample
#define WGL_SAMPLE_BUFFERS_3DFX 0x2060
#define WGL_SAMPLES_3DFX 0x2061
#endif
#ifndef WGL_EXT_multisample
#define WGL_SAMPLE_BUFFERS_EXT 0x2041
#define WGL_SAMPLES_EXT 0x2042
#endif
#ifndef WGL_I3D_digital_video_control
#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050
#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051
#define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052
#define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053
#endif
#ifndef WGL_I3D_gamma
#define WGL_GAMMA_TABLE_SIZE_I3D 0x204E
#define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F
#endif
#ifndef WGL_I3D_genlock
#define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044
#define WGL_GENLOCK_SOURCE_EXTENAL_SYNC_I3D 0x2045
#define WGL_GENLOCK_SOURCE_EXTENAL_FIELD_I3D 0x2046
#define WGL_GENLOCK_SOURCE_EXTENAL_TTL_I3D 0x2047
#define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048
#define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049
#define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A
#define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B
#define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C
#endif
#ifndef WGL_I3D_image_buffer
#define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001
#define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002
#endif
#ifndef WGL_I3D_swap_frame_lock
#endif
#ifndef WGL_NV_render_depth_texture
#define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3
#define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4
#define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5
#define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6
#define WGL_DEPTH_COMPONENT_NV 0x20A7
#endif
#ifndef WGL_NV_render_texture_rectangle
#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0
#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1
#define WGL_TEXTURE_RECTANGLE_NV 0x20A2
#endif
#ifndef WGL_ATI_pixel_format_float
#define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0
#endif
#ifndef WGL_NV_float_buffer
#define WGL_FLOAT_COMPONENTS_NV 0x20B0
#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1
#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2
#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3
#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4
#define WGL_TEXTURE_FLOAT_R_NV 0x20B5
#define WGL_TEXTURE_FLOAT_RG_NV 0x20B6
#define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7
#define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8
#endif
/*************************************************************/
#ifndef WGL_ARB_pbuffer
DECLARE_HANDLE(HPBUFFERARB);
#endif
#ifndef WGL_EXT_pbuffer
DECLARE_HANDLE(HPBUFFEREXT);
#endif
#ifndef WGL_ARB_buffer_region
#define WGL_ARB_buffer_region 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern HANDLE WINAPI wglCreateBufferRegionARB (HDC, int, UINT);
extern VOID WINAPI wglDeleteBufferRegionARB (HANDLE);
extern BOOL WINAPI wglSaveBufferRegionARB (HANDLE, int, int, int, int);
extern BOOL WINAPI wglRestoreBufferRegionARB (HANDLE, int, int, int, int, int, int);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType);
typedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion);
typedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height);
typedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc);
#endif
#ifndef WGL_ARB_multisample
#define WGL_ARB_multisample 1
#endif
#ifndef WGL_ARB_extensions_string
#define WGL_ARB_extensions_string 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern const char * WINAPI wglGetExtensionsStringARB (HDC);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc);
#endif
#ifndef WGL_ARB_pixel_format
#define WGL_ARB_pixel_format 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern BOOL WINAPI wglGetPixelFormatAttribivARB (HDC, int, int, UINT, const int *, int *);
extern BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC, int, int, UINT, const int *, FLOAT *);
extern BOOL WINAPI wglChoosePixelFormatARB (HDC, const int *, const FLOAT *, UINT, int *, UINT *);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues);
typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
#endif
#ifndef WGL_ARB_make_current_read
#define WGL_ARB_make_current_read 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern BOOL WINAPI wglMakeContextCurrentARB (HDC, HDC, HGLRC);
extern HDC WINAPI wglGetCurrentReadDCARB (void);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void);
#endif
#ifndef WGL_ARB_pbuffer
#define WGL_ARB_pbuffer 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern HPBUFFERARB WINAPI wglCreatePbufferARB (HDC, int, int, int, const int *);
extern HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB);
extern int WINAPI wglReleasePbufferDCARB (HPBUFFERARB, HDC);
extern BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB);
extern BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB, int, int *);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);
typedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer);
typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC);
typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer);
typedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue);
#endif
#ifndef WGL_ARB_render_texture
#define WGL_ARB_render_texture 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern BOOL WINAPI wglBindTexImageARB (HPBUFFERARB, int);
extern BOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB, int);
extern BOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB, const int *);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer);
typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer);
typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList);
#endif
#ifndef WGL_ARB_pixel_format_float
#define WGL_ARB_pixel_format_float 1
#endif
#ifndef WGL_EXT_display_color_table
#define WGL_EXT_display_color_table 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort);
extern GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *, GLuint);
extern GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort);
extern VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id);
typedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length);
typedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id);
typedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id);
#endif
#ifndef WGL_EXT_extensions_string
#define WGL_EXT_extensions_string 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern const char * WINAPI wglGetExtensionsStringEXT (void);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void);
#endif
#ifndef WGL_EXT_make_current_read
#define WGL_EXT_make_current_read 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern BOOL WINAPI wglMakeContextCurrentEXT (HDC, HDC, HGLRC);
extern HDC WINAPI wglGetCurrentReadDCEXT (void);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void);
#endif
#ifndef WGL_EXT_pbuffer
#define WGL_EXT_pbuffer 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC, int, int, int, const int *);
extern HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT);
extern int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT, HDC);
extern BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT);
extern BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT, int, int *);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);
typedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer);
typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC);
typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer);
typedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue);
#endif
#ifndef WGL_EXT_pixel_format
#define WGL_EXT_pixel_format 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC, int, int, UINT, int *, int *);
extern BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC, int, int, UINT, int *, FLOAT *);
extern BOOL WINAPI wglChoosePixelFormatEXT (HDC, const int *, const FLOAT *, UINT, int *, UINT *);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues);
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues);
typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
#endif
#ifndef WGL_EXT_swap_control
#define WGL_EXT_swap_control 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern BOOL WINAPI wglSwapIntervalEXT (int);
extern int WINAPI wglGetSwapIntervalEXT (void);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void);
#endif
#ifndef WGL_EXT_depth_float
#define WGL_EXT_depth_float 1
#endif
#ifndef WGL_NV_vertex_array_range
#define WGL_NV_vertex_array_range 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern void* WINAPI wglAllocateMemoryNV (GLsizei, GLfloat, GLfloat, GLfloat);
extern void WINAPI wglFreeMemoryNV (void *);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef void* (WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority);
typedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer);
#endif
#ifndef WGL_3DFX_multisample
#define WGL_3DFX_multisample 1
#endif
#ifndef WGL_EXT_multisample
#define WGL_EXT_multisample 1
#endif
#ifndef WGL_OML_sync_control
#define WGL_OML_sync_control 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern BOOL WINAPI wglGetSyncValuesOML (HDC, INT64 *, INT64 *, INT64 *);
extern BOOL WINAPI wglGetMscRateOML (HDC, INT32 *, INT32 *);
extern INT64 WINAPI wglSwapBuffersMscOML (HDC, INT64, INT64, INT64);
extern INT64 WINAPI wglSwapLayerBuffersMscOML (HDC, int, INT64, INT64, INT64);
extern BOOL WINAPI wglWaitForMscOML (HDC, INT64, INT64, INT64, INT64 *, INT64 *, INT64 *);
extern BOOL WINAPI wglWaitForSbcOML (HDC, INT64, INT64 *, INT64 *, INT64 *);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc);
typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator);
typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder);
typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);
typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc);
typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc);
#endif
#ifndef WGL_I3D_digital_video_control
#define WGL_I3D_digital_video_control 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern BOOL WINAPI wglGetDigitalVideoParametersI3D (HDC, int, int *);
extern BOOL WINAPI wglSetDigitalVideoParametersI3D (HDC, int, const int *);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue);
typedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue);
#endif
#ifndef WGL_I3D_gamma
#define WGL_I3D_gamma 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern BOOL WINAPI wglGetGammaTableParametersI3D (HDC, int, int *);
extern BOOL WINAPI wglSetGammaTableParametersI3D (HDC, int, const int *);
extern BOOL WINAPI wglGetGammaTableI3D (HDC, int, USHORT *, USHORT *, USHORT *);
extern BOOL WINAPI wglSetGammaTableI3D (HDC, int, const USHORT *, const USHORT *, const USHORT *);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue);
typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue);
typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue);
typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue);
#endif
#ifndef WGL_I3D_genlock
#define WGL_I3D_genlock 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern BOOL WINAPI wglEnableGenlockI3D (HDC);
extern BOOL WINAPI wglDisableGenlockI3D (HDC);
extern BOOL WINAPI wglIsEnabledGenlockI3D (HDC, BOOL *);
extern BOOL WINAPI wglGenlockSourceI3D (HDC, UINT);
extern BOOL WINAPI wglGetGenlockSourceI3D (HDC, UINT *);
extern BOOL WINAPI wglGenlockSourceEdgeI3D (HDC, UINT);
extern BOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC, UINT *);
extern BOOL WINAPI wglGenlockSampleRateI3D (HDC, UINT);
extern BOOL WINAPI wglGetGenlockSampleRateI3D (HDC, UINT *);
extern BOOL WINAPI wglGenlockSourceDelayI3D (HDC, UINT);
extern BOOL WINAPI wglGetGenlockSourceDelayI3D (HDC, UINT *);
extern BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC, UINT *, UINT *);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC);
typedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC);
typedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag);
typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource);
typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource);
typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge);
typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge);
typedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate);
typedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate);
typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay);
typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay);
typedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay);
#endif
#ifndef WGL_I3D_image_buffer
#define WGL_I3D_image_buffer 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern LPVOID WINAPI wglCreateImageBufferI3D (HDC, DWORD, UINT);
extern BOOL WINAPI wglDestroyImageBufferI3D (HDC, LPVOID);
extern BOOL WINAPI wglAssociateImageBufferEventsI3D (HDC, const HANDLE *, const LPVOID *, const DWORD *, UINT);
extern BOOL WINAPI wglReleaseImageBufferEventsI3D (HDC, const LPVOID *, UINT);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags);
typedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress);
typedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count);
typedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count);
#endif
#ifndef WGL_I3D_swap_frame_lock
#define WGL_I3D_swap_frame_lock 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern BOOL WINAPI wglEnableFrameLockI3D (void);
extern BOOL WINAPI wglDisableFrameLockI3D (void);
extern BOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *);
extern BOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void);
typedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void);
typedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag);
typedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag);
#endif
#ifndef WGL_I3D_swap_frame_usage
#define WGL_I3D_swap_frame_usage 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern BOOL WINAPI wglGetFrameUsageI3D (float *);
extern BOOL WINAPI wglBeginFrameTrackingI3D (void);
extern BOOL WINAPI wglEndFrameTrackingI3D (void);
extern BOOL WINAPI wglQueryFrameTrackingI3D (DWORD *, DWORD *, float *);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage);
typedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void);
typedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void);
typedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage);
#endif
#ifndef WGL_ATI_pixel_format_float
#define WGL_ATI_pixel_format_float 1
#endif
#ifndef WGL_NV_float_buffer
#define WGL_NV_float_buffer 1
#endif
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,639 @@
#ifndef _LICE_H
#define _LICE_H
/*
Cockos WDL - LICE - Lightweight Image Compositing Engine
Copyright (C) 2007 and later, Cockos Incorporated
Portions Copyright (C) 2007 "schwa"
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifdef _WIN32
#include <windows.h>
#else
#include "../swell/swell-types.h" // use SWELL on other systems
#endif
// one of these can be defined in your project if you choose:
//#define LICE_FAVOR_SPEED // optimizes some stuff that doesnt seem to benefit much (like LICE_DeltaBlit/LICE_RotatedBlit/LICE_TransformBlit)
// (nothing) default probably good overall
//#define LICE_FAVOR_SIZE // reduces code size of normal/scaled blit functions
//#define LICE_FAVOR_SIZE_EXTREME // same as LICE_FAVOR_SIZE w/ smaller gains with bigger perf penalties (solid fills etc)
#ifdef LICE_FAVOR_SPEED
#ifdef LICE_FAVOR_SIZE_EXTREME
#undef LICE_FAVOR_SIZE_EXTREME
#endif
#ifdef LICE_FAVOR_SIZE
#undef LICE_FAVOR_SIZE
#endif
#endif
#if defined(LICE_FAVOR_SIZE_EXTREME) && !defined(LICE_FAVOR_SIZE)
#define LICE_FAVOR_SIZE
#endif
typedef unsigned int LICE_pixel;
typedef unsigned char LICE_pixel_chan;
#define LICE_RGBA(r,g,b,a) (((b)&0xff)|(((g)&0xff)<<8)|(((r)&0xff)<<16)|(((a)&0xff)<<24))
#define LICE_GETB(v) ((v)&0xff)
#define LICE_GETG(v) (((v)>>8)&0xff)
#define LICE_GETR(v) (((v)>>16)&0xff)
#define LICE_GETA(v) (((v)>>24)&0xff)
#if defined(__APPLE__) && defined(__ppc__)
#define LICE_PIXEL_A 0
#define LICE_PIXEL_R 1
#define LICE_PIXEL_G 2
#define LICE_PIXEL_B 3
#else
#define LICE_PIXEL_B 0
#define LICE_PIXEL_G 1
#define LICE_PIXEL_R 2
#define LICE_PIXEL_A 3
#endif
static inline LICE_pixel LICE_RGBA_FROMNATIVE(LICE_pixel col, int alpha=0)
{
return LICE_RGBA(GetRValue(col),GetGValue(col),GetBValue(col),alpha);
}
// bitmap interface, and some built-in types (memory bitmap and system bitmap)
class LICE_IBitmap
{
public:
virtual ~LICE_IBitmap() { }
virtual LICE_pixel *getBits()=0;
virtual int getWidth()=0;
virtual int getHeight()=0;
virtual int getRowSpan()=0; // includes any off-bitmap data
virtual bool isFlipped() { return false; }
virtual bool resize(int w, int h)=0;
virtual HDC getDC() { return 0; } // only sysbitmaps have to implement this
virtual INT_PTR Extended(int id, void* data) { return 0; }
};
#define LICE_EXT_SET_SCALING 0x2000 // data = int *, scaling is .8 fixed point. returns true if supported. affects LICE_*() draw operations
#define LICE_EXT_GET_SCALING 0x2001 // data ignored, returns .8 fixed point, returns 0 if unscaled
#define LICE_EXT_SET_ADVISORY_SCALING 0x2002 // data = int *, scaling is .8 fixed point. returns true if supported. does not affect draw operations
#define LICE_EXT_GET_ADVISORY_SCALING 0x2003 // data ignored, returns .8 fixed point. returns 0 if unscaled
#define LICE_EXT_GET_ANY_SCALING 0x2004 // data ignored, returns .8 fixed point, 0 if unscaled
#define LICE_MEMBITMAP_ALIGNAMT 63
class LICE_MemBitmap : public LICE_IBitmap
{
public:
LICE_MemBitmap(int w=0, int h=0, unsigned int linealign=4);
virtual ~LICE_MemBitmap();
// LICE_IBitmap interface
virtual LICE_pixel *getBits()
{
const UINT_PTR extra=LICE_MEMBITMAP_ALIGNAMT;
return (LICE_pixel *) (((UINT_PTR)m_fb + extra)&~extra);
}
virtual int getWidth() { return m_width; }
virtual int getHeight() { return m_height; }
virtual int getRowSpan() { return (m_width+m_linealign)&~m_linealign; }
virtual bool resize(int w, int h) { return __resize(w,h); } // returns TRUE if a resize occurred
// todo: LICE_EXT_SET_SCALING ?
private:
bool __resize(int w, int h);
LICE_pixel *m_fb;
int m_width, m_height;
int m_allocsize;
unsigned int m_linealign;
};
class LICE_SysBitmap : public LICE_IBitmap
{
public:
LICE_SysBitmap(int w=0, int h=0);
virtual ~LICE_SysBitmap();
// LICE_IBitmap interface
virtual LICE_pixel *getBits() { return m_bits; }
virtual int getWidth() { return m_width; }
virtual int getHeight() { return m_height; }
virtual int getRowSpan() { return m_allocw; };
virtual bool resize(int w, int h) { return __resize(w,h); } // returns TRUE if a resize occurred
virtual INT_PTR Extended(int id, void* data)
{
switch (id)
{
case LICE_EXT_SET_ADVISORY_SCALING:
{
int sc = data && *(int*)data != 256 ? *(int *)data : 0;
if (sc < 0) sc = 0;
m_adv_scaling = sc;
}
return 1;
case LICE_EXT_SET_SCALING:
{
int sc = data && *(int*)data != 256 ? *(int *)data : 0;
if (sc < 0) sc = 0;
if (m_draw_scaling != sc)
{
const int tmp=m_width;
m_draw_scaling = sc;
m_width=0;
resize(tmp,m_height);
}
}
return 1;
case LICE_EXT_GET_SCALING:
return m_draw_scaling;
case LICE_EXT_GET_ADVISORY_SCALING:
return m_adv_scaling;
case LICE_EXT_GET_ANY_SCALING:
if (m_draw_scaling > 0)
{
if (m_adv_scaling > 0)
return (m_adv_scaling * m_draw_scaling) >> 8;
return m_draw_scaling;
}
return m_adv_scaling;
}
return 0;
}
// sysbitmap specific calls
virtual HDC getDC() { return m_dc; }
private:
bool __resize(int w, int h);
int m_width, m_height;
HDC m_dc;
LICE_pixel *m_bits;
int m_allocw, m_alloch;
#ifdef _WIN32
HBITMAP m_bitmap;
HGDIOBJ m_oldbitmap;
#endif
int m_draw_scaling, m_adv_scaling;
};
class LICE_WrapperBitmap : public LICE_IBitmap
{
public:
LICE_WrapperBitmap(LICE_pixel *buf, int w, int h, int span, bool flipped)
{
m_buf=buf;
m_w=w;
m_h=h;
m_span=span;
m_flipped=flipped;
}
virtual ~LICE_WrapperBitmap() {}
virtual bool resize(int w, int h) { return false; }
virtual LICE_pixel *getBits() { return m_buf; }
virtual int getWidth() { return m_w; }
virtual int getHeight() { return m_h; }
virtual int getRowSpan() { return m_span; }
virtual HDC getDC() { return NULL; }
virtual bool isFlipped() { return m_flipped; }
LICE_pixel *m_buf;
int m_w,m_h,m_span;
bool m_flipped;
};
class LICE_SubBitmap : public LICE_IBitmap // note: you should only keep these around as long as they are needed, and don't resize the parent while this is allocated
{
public:
LICE_SubBitmap(LICE_IBitmap *parent, int x, int y, int w, int h)
{
m_parent=parent;
if(x<0)x=0;
if(y<0)y=0;
m_x=x;m_y=y;
__resize(w,h);
}
virtual ~LICE_SubBitmap() { }
virtual bool resize(int w, int h) { return __resize(w,h); }
bool __resize(int w, int h)
{
m_w=0;m_h=0;
if (m_parent && m_x >= 0 && m_y >= 0 && m_x < m_parent->getWidth() && m_y < m_parent->getHeight())
{
if (w > m_parent->getWidth()-m_x) w=m_parent->getWidth()-m_x;
if (h > m_parent->getHeight()-m_y) h=m_parent->getHeight()-m_y;
m_w=w;
m_h=h;
}
return true;
}
virtual bool isFlipped() { return m_parent && m_parent->isFlipped(); }
virtual LICE_pixel *getBits()
{
if (!m_parent) return 0;
int xc = m_x, yc = m_y, h = m_h;
const int scale = (int)m_parent->Extended(LICE_EXT_GET_SCALING,NULL);
if (scale > 0)
{
xc = (xc*scale)>>8;
yc = (yc*scale)>>8;
h = (h*scale)>>8;
}
LICE_pixel* parentptr=m_parent->getBits();
if (m_parent->isFlipped()) parentptr += (m_parent->getHeight() - (yc+h))*m_parent->getRowSpan()+xc;
else parentptr += yc*m_parent->getRowSpan()+xc;
return parentptr;
}
enum {
LICE_GET_SUBBITMAP_VERSION = 0x51b7000,
LICE_SUBBITMAP_VERSION = 0x1000 // if we change any of this struct, then we *must* increment this version.
};
virtual INT_PTR Extended(int id, void* data)
{
if (id == LICE_GET_SUBBITMAP_VERSION) return LICE_SUBBITMAP_VERSION;
if (!m_parent) return 0;
return m_parent->Extended(id, data);
}
virtual int getWidth() { return m_w; }
virtual int getHeight() { return m_h; }
virtual int getRowSpan() { return m_parent ? m_parent->getRowSpan() : 0; }
virtual HDC getDC() { return NULL; }
int m_w,m_h,m_x,m_y;
LICE_IBitmap *m_parent;
};
// flags that most blit functions can take
#define LICE_BLIT_MODE_MASK 0xff
#define LICE_BLIT_MODE_COPY 0
#define LICE_BLIT_MODE_ADD 1
#define LICE_BLIT_MODE_DODGE 2
#define LICE_BLIT_MODE_MUL 3
#define LICE_BLIT_MODE_OVERLAY 4
#define LICE_BLIT_MODE_HSVADJ 5
#define LICE_BLIT_MODE_CHANCOPY 0xf0 // in this mode, only available for LICE_Blit(), the low nibble is 2 bits of source channel (low 2), 2 bits of dest channel (high 2)
#define LICE_BLIT_FILTER_MASK 0xff00
#define LICE_BLIT_FILTER_NONE 0
#define LICE_BLIT_FILTER_BILINEAR 0x100 // currently pretty slow! ack
#define LICE_BLIT_IGNORE_SCALING 0x20000
#define LICE_BLIT_USE_ALPHA 0x10000 // use source's alpha channel
#ifndef lice_max
#define lice_max(x,y) ((x)<(y)?(y):(x))
#define lice_min(x,y) ((x)<(y)?(x):(y))
#endif
#ifdef _MSC_VER
#include <float.h>
#define lice_isfinite(x) _finite(x)
#else
#define lice_isfinite(x) isfinite(x)
#endif
// Reaper exports most LICE functions, so the function declarations below
// will collide with reaper_plugin.h
#ifndef LICE_PROVIDED_BY_APP
// bitmap loaders
// dispatch to a linked loader implementation based on file extension
LICE_IBitmap* LICE_LoadImage(const char* filename, LICE_IBitmap* bmp=NULL, bool tryIgnoreExtension=false);
char *LICE_GetImageExtensionList(bool wantAllSup=true, bool wantAllFiles=true); // returns doublenull terminated GetOpenFileName() style list -- free() when done.
bool LICE_ImageIsSupported(const char *filename); // must be a filename that ends in .jpg, etc. if you want to check the extension, pass .ext
// pass a bmp if you wish to load it into that bitmap. note that if it fails bmp will not be deleted.
LICE_IBitmap *LICE_LoadPNG(const char *filename, LICE_IBitmap *bmp=NULL); // returns a bitmap (bmp if nonzero) on success
LICE_IBitmap *LICE_LoadPNGFromMemory(const void *data_in, int buflen, LICE_IBitmap *bmp=NULL);
LICE_IBitmap *LICE_LoadPNGFromResource(HINSTANCE hInst, const char *resid, LICE_IBitmap *bmp=NULL); // returns a bitmap (bmp if nonzero) on success
#ifndef _WIN32
LICE_IBitmap *LICE_LoadPNGFromNamedResource(const char *name, LICE_IBitmap *bmp=NULL); // returns a bitmap (bmp if nonzero) on success
#endif
LICE_IBitmap *LICE_LoadBMP(const char *filename, LICE_IBitmap *bmp=NULL); // returns a bitmap (bmp if nonzero) on success
LICE_IBitmap *LICE_LoadBMPFromResource(HINSTANCE hInst, const char *resid, LICE_IBitmap *bmp=NULL); // returns a bitmap (bmp if nonzero) on success
LICE_IBitmap *LICE_LoadIcon(const char *filename, int reqiconsz=16, LICE_IBitmap *bmp=NULL); // returns a bitmap (bmp if nonzero) on success
LICE_IBitmap *LICE_LoadIconFromResource(HINSTANCE hInst, const char *resid, int reqiconsz=16, LICE_IBitmap *bmp=NULL); // returns a bitmap (bmp if nonzero) on success
LICE_IBitmap *LICE_LoadJPG(const char *filename, LICE_IBitmap *bmp=NULL);
LICE_IBitmap *LICE_LoadJPGFromMemory(const void *data_in, int buflen, LICE_IBitmap *bmp = NULL);
LICE_IBitmap* LICE_LoadJPGFromResource(HINSTANCE hInst, const char *resid, LICE_IBitmap* bmp = 0);
LICE_IBitmap *LICE_LoadGIF(const char *filename, LICE_IBitmap *bmp=NULL, int *nframes=NULL); // if nframes set, will be set to number of images (stacked vertically), otherwise first frame used
LICE_IBitmap *LICE_LoadPCX(const char *filename, LICE_IBitmap *bmp=NULL); // returns a bitmap (bmp if nonzero) on success
// bitmap saving
bool LICE_WritePNG(const char *filename, LICE_IBitmap *bmp, bool wantalpha=true);
bool LICE_WriteJPG(const char *filename, LICE_IBitmap *bmp, int quality=95, bool force_baseline=true);
bool LICE_WriteGIF(const char *filename, LICE_IBitmap *bmp, int transparent_alpha=0, bool dither=true); // if alpha<transparent_alpha then transparent. if transparent_alpha<0, then intra-frame checking is used
// animated GIF API. use transparent_alpha=-1 to encode unchanged pixels as transparent
void *LICE_WriteGIFBegin(const char *filename, LICE_IBitmap *firstframe, int transparent_alpha=0, int frame_delay=0, bool dither=true, int nreps=0); // nreps=0 for infinite
void *LICE_WriteGIFBeginNoFrame(const char *filename, int w, int h, int transparent_alpha=0, bool dither=true, bool is_append=false);
bool LICE_WriteGIFFrame(void *handle, LICE_IBitmap *frame, int xpos, int ypos, bool perImageColorMap=false, int frame_delay=0, int nreps=0); // nreps only used on the first frame, 0=infinite
unsigned int LICE_WriteGIFGetSize(void *handle); // gets current output size
bool LICE_WriteGIFEnd(void *handle);
int LICE_SetGIFColorMapFromOctree(void *wr, void *octree, int numcolors); // can use after LICE_WriteGIFBeginNoFrame and before LICE_WriteGIFFrame
// animated GIF reading
void *LICE_GIF_LoadEx(const char *filename);
void LICE_GIF_Close(void *handle);
void LICE_GIF_Rewind(void *handle);
unsigned int LICE_GIF_GetFilePos(void *handle); // gets current read position
int LICE_GIF_UpdateFrame(void *handle, LICE_IBitmap *bm); // returns duration in msec (0 or more), or <0 if no more frames. bm will be modified/resized with new frame data
// basic primitives
void LICE_PutPixel(LICE_IBitmap *bm, int x, int y, LICE_pixel color, float alpha, int mode);
LICE_pixel LICE_GetPixel(LICE_IBitmap *bm, int x, int y);
// blit functions
void LICE_Copy(LICE_IBitmap *dest, LICE_IBitmap *src); // resizes dest to fit
//alpha parameter = const alpha (combined with source alpha if spcified)
void LICE_Blit(LICE_IBitmap *dest, LICE_IBitmap *src, int dstx, int dsty, const RECT *srcrect, float alpha, int mode);
void LICE_Blit(LICE_IBitmap *dest, LICE_IBitmap *src, int dstx, int dsty, int srcx, int srcy, int srcw, int srch, float alpha, int mode);
void LICE_Blur(LICE_IBitmap *dest, LICE_IBitmap *src, int dstx, int dsty, int srcx, int srcy, int srcw, int srch);
// dstw/dsty can be negative, srcw/srch can be as well (for flipping)
void LICE_ScaledBlit(LICE_IBitmap *dest, LICE_IBitmap *src, int dstx, int dsty, int dstw, int dsth,
float srcx, float srcy, float srcw, float srch, float alpha, int mode);
void LICE_HalveBlitAA(LICE_IBitmap *dest, LICE_IBitmap *src); // AA's src down to dest. uses the minimum size of both (use with LICE_SubBitmap to do sections)
// if cliptosourcerect is false, then areas outside the source rect can get in (otherwise they are not drawn)
void LICE_RotatedBlit(LICE_IBitmap *dest, LICE_IBitmap *src,
int dstx, int dsty, int dstw, int dsth,
float srcx, float srcy, float srcw, float srch,
float angle,
bool cliptosourcerect, float alpha, int mode,
float rotxcent=0.0, float rotycent=0.0); // these coordinates are offset from the center of the image, in source pixel coordinates
void LICE_TransformBlit(LICE_IBitmap *dest, LICE_IBitmap *src,
int dstx, int dsty, int dstw, int dsth,
const float *srcpoints, int div_w, int div_h, // srcpoints coords should be div_w*div_h*2 long, and be in source image coordinates
float alpha, int mode);
void LICE_TransformBlit2(LICE_IBitmap *dest, LICE_IBitmap *src,
int dstx, int dsty, int dstw, int dsth,
const double *srcpoints, int div_w, int div_h, // srcpoints coords should be div_w*div_h*2 long, and be in source image coordinates
float alpha, int mode);
void LICE_TransformBlit2Alpha(LICE_IBitmap *dest, LICE_IBitmap *src,
int dstx, int dsty, int dstw, int dsth,
const double *srcpoints, int div_w, int div_h, // srcpoints coords should be div_w*div_h*3 long, and be in source image coordinates + alpha
int mode);
// if cliptosourcerect is false, then areas outside the source rect can get in (otherwise they are not drawn)
void LICE_DeltaBlit(LICE_IBitmap *dest, LICE_IBitmap *src,
int dstx, int dsty, int dstw, int dsth,
float srcx, float srcy, float srcw, float srch,
double dsdx, double dtdx, double dsdy, double dtdy,
double dsdxdy, double dtdxdy,
bool cliptosourcerect, float alpha, int mode);
void LICE_DeltaBlitAlpha(LICE_IBitmap *dest, LICE_IBitmap *src,
int dstx, int dsty, int dstw, int dsth,
float srcx, float srcy, float srcw, float srch,
double dsdx, double dtdx, double dsdy, double dtdy,
double dsdxdy, double dtdxdy,
bool cliptosourcerect, float alpha, int mode, double dadx, double dady, double dadxdy);
// only LICE_BLIT_MODE_ADD or LICE_BLIT_MODE_COPY are used by this, for flags
// ir-ia should be 0.0..1.0 (or outside that and they'll be clamped)
// drdx should be X/dstw, drdy X/dsth etc
void LICE_GradRect(LICE_IBitmap *dest, int dstx, int dsty, int dstw, int dsth,
float ir, float ig, float ib, float ia,
float drdx, float dgdx, float dbdx, float dadx,
float drdy, float dgdy, float dbdy, float dady,
int mode);
void LICE_FillRect(LICE_IBitmap *dest, int x, int y, int w, int h, LICE_pixel color, float alpha = 1.0f, int mode = 0);
void LICE_ProcessRect(LICE_IBitmap *dest, int x, int y, int w, int h, void (*procFunc)(LICE_pixel *p, void *parm), void *parm);
void LICE_Clear(LICE_IBitmap *dest, LICE_pixel color);
void LICE_ClearRect(LICE_IBitmap *dest, int x, int y, int w, int h, LICE_pixel mask=0, LICE_pixel orbits=0);
void LICE_MultiplyAddRect(LICE_IBitmap *dest, int x, int y, int w, int h,
float rsc, float gsc, float bsc, float asc, // 0-1, or -100 .. +100 if you really are insane
float radd, float gadd, float badd, float aadd); // 0-255 is the normal range on these.. of course its clamped
void LICE_SetAlphaFromColorMask(LICE_IBitmap *dest, LICE_pixel color);
// non-flood fill. simply scans up/down and left/right
void LICE_SimpleFill(LICE_IBitmap *dest, int x, int y, LICE_pixel newcolor,
LICE_pixel comparemask=LICE_RGBA(255,255,255,0),
LICE_pixel keepmask=LICE_RGBA(0,0,0,0));
// texture generators
void LICE_TexGen_Marble(LICE_IBitmap *dest, const RECT *rect, float rv, float gv, float bv, float intensity); //fills whole bitmap if rect == NULL
//this function generates a Perlin noise
//fills whole bitmap if rect == NULL
//smooth needs to be a multiple of 2
enum
{
NOISE_MODE_NORMAL = 0,
NOISE_MODE_WOOD,
};
void LICE_TexGen_Noise(LICE_IBitmap *dest, const RECT *rect, float rv, float gv, float bv, float intensity, int mode=NOISE_MODE_NORMAL, int smooth=1);
//this function generates a Perlin noise in a circular fashion
//fills whole bitmap if rect == NULL
//size needs to be a multiple of 2
void LICE_TexGen_CircNoise(LICE_IBitmap *dest, const RECT *rect, float rv, float gv, float bv, float nrings, float power, int size);
// bitmapped text drawing:
void LICE_DrawChar(LICE_IBitmap *bm, int x, int y, char c,
LICE_pixel color, float alpha, int mode);
void LICE_DrawText(LICE_IBitmap *bm, int x, int y, const char *string,
LICE_pixel color, float alpha, int mode);
void LICE_MeasureText(const char *string, int *w, int *h);
// line drawing functions
void LICE_Line(LICE_IBitmap *dest, int x1, int y1, int x2, int y2, LICE_pixel color, float alpha=1.0f, int mode=0, bool aa=true);
void LICE_FLine(LICE_IBitmap* dest, float x1, float y1, float x2, float y2, LICE_pixel color, float alpha=1.0f, int mode=0, bool aa=true);
void LICE_ThickFLine(LICE_IBitmap* dest, double x1, double y1, double x2, double y2, LICE_pixel color, float alpha, int mode, int wid); // always AA. wid is not affected by scaling (1 is always normal line, 2 is always 2 physical pixels, etc)
void LICE_DashedLine(LICE_IBitmap* dest, int x1, int y1, int x2, int y2, int pxon, int pxoff, LICE_pixel color, float alpha=1.0f, int mode=0, bool aa=false); // straight lines only for now
void LICE_FillTrapezoidF(LICE_IBitmap* dest, double fx1a, double fx1b, int y1, double fx2a, double fx2b, int y2, LICE_pixel color, float alpha, int mode);
void LICE_FillTrapezoid(LICE_IBitmap* dest, int x1a, int x1b, int y1, int x2a, int x2b, int y2, LICE_pixel color, float alpha, int mode);
void LICE_FillConvexPolygon(LICE_IBitmap* dest, const int* x, const int* y, int npoints, LICE_pixel color, float alpha, int mode);
void LICE_FillTriangle(LICE_IBitmap *dest, int x1, int y1, int x2, int y2, int x3, int y3, LICE_pixel color, float alpha=1.0f, int mode=0);
// Returns false if the line is entirely offscreen.
bool LICE_ClipLine(int* pX1, int* pY1, int* pX2, int* pY2, int xLo, int yLo, int xHi, int yHi);
bool LICE_ClipFLine(float* px1, float* py1, float* px2, float* py2, float xlo, float ylo, float xhi, float yhi);
void LICE_Arc(LICE_IBitmap* dest, float cx, float cy, float r, float minAngle, float maxAngle,
LICE_pixel color, float alpha=1.0f, int mode=0, bool aa=true);
void LICE_Circle(LICE_IBitmap* dest, float cx, float cy, float r, LICE_pixel color, float alpha=1.0f, int mode=0, bool aa=true);
void LICE_FillCircle(LICE_IBitmap* dest, float cx, float cy, float r, LICE_pixel color, float alpha=1.0f, int mode=0, bool aa=true);
void LICE_RoundRect(LICE_IBitmap *drawbm, float xpos, float ypos, float w, float h, int cornerradius,
LICE_pixel col, float alpha, int mode, bool aa);
// useful for drawing shapes from a cache
void LICE_DrawGlyph(LICE_IBitmap* dest, int x, int y, LICE_pixel color, const LICE_pixel_chan* alphas, int glyph_w, int glyph_h, float alpha=1.0f, int mode = 0);
void LICE_DrawGlyphEx(LICE_IBitmap* dest, int x, int y, LICE_pixel color, const LICE_pixel_chan* alphas, int glyph_w, int glyph_span, int glyph_h, float alpha=1.0f, int mode = 0);
void LICE_DrawMonoGlyph(LICE_IBitmap* dest, int x, int y, LICE_pixel color, const unsigned char* alphas, int glyph_w, int glyph_span, int glyph_h, float alpha=1.0f, int mode = 0);
// quadratic bezier
// tol means try to draw segments no longer than tol px
void LICE_DrawQBezier(LICE_IBitmap* dest, double xstart, double ystart, double xctl, double yctl, double xend, double yend,
LICE_pixel color, float alpha=1.0f, int mode=0, bool aa=true, double tol=0.0);
// cubic bezier
// tol means try to draw segments no longer than tol px
void LICE_DrawCBezier(LICE_IBitmap* dest, double xstart, double ystart, double xctl1, double yctl1,
double xctl2, double yctl2, double xend, double yend, LICE_pixel color, float alpha=1.0f, int mode=0, bool aa=true, double tol=0.0);
void LICE_DrawThickCBezier(LICE_IBitmap* dest, double xstart, double ystart, double xctl1, double yctl1,
double xctl2, double yctl2, double xend, double yend, LICE_pixel color, float alpha=1.0f, int mode=0, int wid=2, double tol=0.0);
// vertical fill from y=yfill
void LICE_FillCBezier(LICE_IBitmap* dest, double xstart, double ystart, double xctl1, double yctl1,
double xctl2, double yctl2, double xend, double yend, int yfill, LICE_pixel color, float alpha=1.0f, int mode=0, double tol=0.0);
// horizontal fill from x=xfill
void LICE_FillCBezierX(LICE_IBitmap* dest, double xstart, double ystart, double xctl1, double yctl1,
double xctl2, double yctl2, double xend, double yend, int xfill, LICE_pixel color, float alpha=1.0f, int mode=0, double tol=0.0);
// convenience functions
void LICE_DrawRect(LICE_IBitmap *dest, int x, int y, int w, int h, LICE_pixel color, float alpha=1.0f, int mode=0);
void LICE_BorderedRect(LICE_IBitmap *dest, int x, int y, int w, int h, LICE_pixel bgcolor, LICE_pixel fgcolor, float alpha=1.0f, int mode=0);
// bitmap compare-by-value function
int LICE_BitmapCmp(LICE_IBitmap* a, LICE_IBitmap* b, int *coordsOut=NULL);
int LICE_BitmapCmpEx(LICE_IBitmap* a, LICE_IBitmap* b, LICE_pixel mask, int *coordsOut=NULL);
// colorspace functions
void LICE_RGB2HSV(int r, int g, int b, int* h, int* s, int* v); // rgb, sv: [0,256), h: [0,384)
void LICE_HSV2RGB(int h, int s, int v, int* r, int* g, int* b); // rgb, sv: [0,256), h: [0,384)
LICE_pixel LICE_HSV2Pix(int h, int s, int v, int alpha); // sv: [0,256), h: [0,384)
LICE_pixel LICE_AlterColorHSV(LICE_pixel color, float d_hue, float d_saturation, float d_value); // hue is rolled over, saturation and value are clamped, all 0..1
void LICE_AlterBitmapHSV(LICE_IBitmap* src, float d_hue, float d_saturation, float d_value); // hue is rolled over, saturation and value are clamped, all 0..1
void LICE_AlterRectHSV(LICE_IBitmap* src, int x, int y, int w, int h, float d_hue, float d_saturation, float d_value, int mode=0); // hue is rolled over, saturation and value are clamped, all 0..1. mode only used for scaling disable
LICE_pixel LICE_CombinePixels(LICE_pixel dest, LICE_pixel src, float alpha, int mode);
void LICE_CombinePixels2(LICE_pixel *destptr, int r, int g, int b, int a, int ia, int mode); // does not clamp
void LICE_CombinePixels2Clamp(LICE_pixel *destptr, int r, int g, int b, int a, int ia, int mode);
//// LVG
class ProjectStateContext;
void *LICE_LoadLVG(const char *filename);
void *LICE_LoadLVGFromContext(ProjectStateContext *ctx, const char *nameInfo=NULL, int defw=0, int defh=0);
void *LICE_GetSubLVG(void *lvg, const char *subname);
LICE_IBitmap *LICE_RenderLVG(void *lvg, int reqw=0, int reqh=0, LICE_IBitmap *useBM=NULL);
void LICE_DestroyLVG(void *lvg);
/// palette
void* LICE_CreateOctree(int maxcolors);
void LICE_DestroyOctree(void* octree);
void LICE_ResetOctree(void *octree, int maxcolors); // resets back to stock, but with spares (to avoid mallocs)
int LICE_BuildOctree(void* octree, LICE_IBitmap* bmp);
int LICE_BuildOctreeForAlpha(void* octree, LICE_IBitmap* bmp, unsigned int minalpha);
int LICE_BuildOctreeForDiff(void* octree, LICE_IBitmap* bmp, LICE_IBitmap* refbmp, LICE_pixel mask=LICE_RGBA(255,255,255,0));
int LICE_FindInOctree(void* octree, LICE_pixel color);
int LICE_ExtractOctreePalette(void* octree, LICE_pixel* palette);
// wrapper
int LICE_BuildPalette(LICE_IBitmap* bmp, LICE_pixel* palette, int maxcolors);
void LICE_TestPalette(LICE_IBitmap* bmp, LICE_pixel* palette, int numcolors);
struct _LICE_ImageLoader_rec
{
LICE_IBitmap *(*loadfunc)(const char *filename, bool checkFileName, LICE_IBitmap *bmpbase);
const char *(*get_extlist)(); // returns GetOpenFileName sort of list "JPEG files (*.jpg)\0*.jpg\0"
struct _LICE_ImageLoader_rec *_next;
};
extern _LICE_ImageLoader_rec *LICE_ImageLoader_list;
#endif // LICE_PROVIDED_BY_APP
#ifdef __APPLE__
#define LICE_Scale_BitBlt(hdc, x,y,w,h, src, sx,sy, mode) do { \
const int _x=(x), _y=(y), _w=(w), _h=(h), _sx = (sx), _sy = (sy), _mode=(mode); \
const int rsc = (int) (src)->Extended(LICE_EXT_GET_SCALING,NULL); \
if (rsc>0) \
StretchBlt(hdc,_x,_y,_w,_h,(src)->getDC(),(_sx*rsc)/256,(_sy*rsc)/256,(_w*rsc)>>8,(_h*rsc)>>8,_mode); \
else BitBlt(hdc,_x,_y,_w,_h,(src)->getDC(),_sx,_sy,_mode); \
} while (0)
#else
#define LICE_Scale_BitBlt(hdc, x,y,w,h, src, sx,sy, mode) BitBlt(hdc,x,y,w,h,(src)->getDC(),sx,sy,mode)
#endif
#endif

View File

@@ -0,0 +1,731 @@
#ifndef WDL_NO_DEFINE_MINMAX
#define WDL_NO_DEFINE_MINMAX
#endif
#include "lice.h"
#include "lice_combine.h"
#include <math.h>
#define _PI 3.141592653589793238f
#define IGNORE_SCALING(mode) ((mode)&LICE_BLIT_IGNORE_SCALING)
template <class T> inline void _SWAP(T& a, T& b) { T tmp = a; a = b; b = tmp; }
#define A(x) ((LICE_pixel_chan)((x)*255.0+0.5))
#define AF(x) (255)
#define DEF_ALPHAS(dim) \
static const LICE_pixel_chan alphas_unfill[] = { __ALPHAS__(A) }; \
static const LICE_pixel_chan alphas_fill[] = { __ALPHAS__(AF) }; \
const LICE_pixel_chan * const alphas = fill ? alphas_fill : alphas_unfill; \
((void)sizeof(char[1 - 2*(sizeof(alphas_unfill) != dim*dim)])); \
((void)sizeof(char[1 - 2*(sizeof(alphas_fill) != dim*dim)]));
static bool CachedCircle(LICE_IBitmap* dest, float cx, float cy, float r, LICE_pixel color, float alpha, int mode, bool aa, bool fill)
{
// fast draw for some small circles
if (r == 1.5f)
{
if (aa)
{
#define __ALPHAS__(B) \
A(0.31), A(1.00), A(1.00), A(0.31), \
A(1.00), B(0.06), B(0.06), A(1.00), \
A(1.00), B(0.06), B(0.06), A(1.00), \
A(0.31), A(1.00), A(1.00), A(0.31),
DEF_ALPHAS(4)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 4, 4, alpha, mode);
}
else
{
#define __ALPHAS__(B) \
A(0.00), A(1.00), A(1.00), A(0.00), \
A(1.00), B(0.00), B(0.00), A(1.00), \
A(1.00), B(0.00), B(0.00), A(1.00), \
A(0.00), A(1.00), A(1.00), A(0.00),
DEF_ALPHAS(4)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 4, 4, alpha, mode);
}
return true;
}
else if (r == 2.0f)
{
if (aa)
{
#define __ALPHAS__(B) \
A(0.06), A(0.75), A(1.00), A(0.75), A(0.06), \
A(0.75), A(0.82), B(0.31), A(0.82), A(0.75), \
A(1.00), B(0.31), B(0.00), B(0.31), A(1.00), \
A(0.75), A(0.82), B(0.31), A(0.82), A(0.75), \
A(0.06), A(0.75), A(1.00), A(0.75), A(0.06)
DEF_ALPHAS(5)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 5, 5, alpha, mode);
}
else
{
#define __ALPHAS__(B) \
A(0.00), A(0.00), A(1.00), A(0.00), A(0.00), \
A(0.00), A(1.00), B(0.00), A(1.00), A(0.00), \
A(1.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(0.00), A(1.00), B(0.00), A(1.00), A(0.00), \
A(0.00), A(0.00), A(1.00), A(0.00), A(0.00)
DEF_ALPHAS(5)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 5, 5, alpha, mode);
}
return true;
}
else if (r == 2.5f) {
if (aa) {
#define __ALPHAS__(B) \
A(0.06), A(0.75), A(1.00), A(1.00), A(0.75), A(0.06), \
A(0.75), A(0.82), B(0.31), B(0.31), A(0.82), A(0.75), \
A(1.00), B(0.31), B(0.00), B(0.00), B(0.31), A(1.00), \
A(1.00), B(0.31), B(0.00), B(0.00), B(0.31), A(1.00), \
A(0.75), A(0.82), B(0.31), B(0.31), A(0.82), A(0.75), \
A(0.06), A(0.75), A(1.00), A(1.00), A(0.75), A(0.06)
DEF_ALPHAS(6)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 6, 6, alpha, mode);
}
else {
#define __ALPHAS__(B) \
A(0.00), A(0.00), A(1.00), A(1.00), A(0.00), A(0.00), \
A(0.00), A(1.00), B(0.00), B(0.00), A(1.00), A(0.00), \
A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(0.00), A(1.00), B(0.00), B(0.00), A(1.00), A(0.00), \
A(0.00), A(0.00), A(1.00), A(1.00), A(0.00), A(0.00)
DEF_ALPHAS(6)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 6, 6, alpha, mode);
}
return true;
}
else if (r == 3.0f) {
if (aa) {
#define __ALPHAS__(B) \
A(0.00), A(0.56), A(1.00), A(1.00), A(1.00), A(0.56), A(0.00), \
A(0.56), A(1.00), B(0.38), B(0.25), B(0.38), A(1.00), A(0.56), \
A(1.00), B(0.44), B(0.00), B(0.00), B(0.00), B(0.44), A(1.00), \
A(1.00), B(0.19), B(0.00), B(0.00), B(0.00), B(0.19), A(1.00), \
A(1.00), B(0.44), B(0.00), B(0.00), B(0.00), B(0.44), A(1.00), \
A(0.56), A(1.00), B(0.38), B(0.25), B(0.38), A(1.00), A(0.56), \
A(0.00), A(0.56), A(1.00), A(1.00), A(1.00), A(0.56), A(0.00)
DEF_ALPHAS(7)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 7, 7, alpha, mode);
}
else {
#define __ALPHAS__(B) \
A(0.00), A(0.00), A(1.00), A(1.00), A(1.00), A(0.00), A(0.00), \
A(0.00), A(1.00), B(0.00), B(0.00), B(0.00), A(1.00), A(0.00), \
A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(0.00), A(1.00), B(0.00), B(0.00), B(0.00), A(1.00), A(0.00), \
A(0.00), A(0.00), A(1.00), A(1.00), A(1.00), A(0.00), A(0.00)
DEF_ALPHAS(7)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 7, 7, alpha, mode);
}
return true;
}
else if (r == 3.5f) {
if (aa) {
#define __ALPHAS__(B) \
A(0.00), A(0.31), A(0.87), A(1.00), A(1.00), A(0.87), A(0.31), A(0.00), \
A(0.31), A(1.00), A(0.69), B(0.25), B(0.25), A(0.69), A(1.00), A(0.31), \
A(0.87), A(0.69), B(0.00), B(0.00), B(0.00), B(0.00), A(0.69), A(0.87), \
A(1.00), B(0.25), B(0.00), B(0.00), B(0.00), B(0.00), B(0.25), A(1.00), \
A(1.00), B(0.25), B(0.00), B(0.00), B(0.00), B(0.00), B(0.25), A(1.00), \
A(0.87), A(0.69), B(0.00), B(0.00), B(0.00), B(0.00), A(0.69), A(0.87), \
A(0.31), A(1.00), A(0.69), B(0.25), B(0.25), A(0.69), A(1.00), A(0.31), \
A(0.00), A(0.31), A(0.87), A(1.00), A(1.00), A(0.87), A(0.31), A(0.00)
DEF_ALPHAS(8)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 8, 8, alpha, mode);
}
else {
#define __ALPHAS__(B) \
A(0.00), A(0.00), A(1.00), A(1.00), A(1.00), A(1.00), A(0.00), A(0.00), \
A(0.00), A(1.00), A(1.00), B(0.00), B(0.00), A(1.00), A(1.00), A(0.00), \
A(1.00), A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), A(1.00), \
A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(1.00), A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), A(1.00), \
A(0.00), A(1.00), A(1.00), B(0.00), B(0.00), A(1.00), A(1.00), A(0.00), \
A(0.00), A(0.00), A(1.00), A(1.00), A(1.00), A(1.00), A(0.00), A(0.00)
DEF_ALPHAS(8)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 8, 8, alpha, mode);
}
return true;
}
else if (r == 4.0f) {
if (aa) {
#define __ALPHAS__(B) \
A(0.00), A(0.12), A(0.69), A(1.00), A(1.00), A(1.00), A(0.69), A(0.12), A(0.00), \
A(0.12), A(0.94), A(0.82), B(0.31), B(0.25), B(0.31), A(0.82), A(0.94), A(0.12), \
A(0.69), A(0.82), B(0.06), B(0.00), B(0.00), B(0.00), B(0.06), A(0.82), A(0.69), \
A(1.00), B(0.31), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.31), A(1.00), \
A(1.00), B(0.19), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.19), A(1.00), \
A(1.00), B(0.31), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.31), A(1.00), \
A(0.69), A(0.82), B(0.06), B(0.00), B(0.00), B(0.00), B(0.06), A(0.82), A(0.69), \
A(0.12), A(0.94), A(0.82), B(0.31), B(0.25), B(0.31), A(0.82), A(0.94), A(0.12), \
A(0.00), A(0.12), A(0.69), A(1.00), A(1.00), A(1.00), A(0.69), A(0.12), A(0.00)
DEF_ALPHAS(9)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 9, 9, alpha, mode);
}
else {
#define __ALPHAS__(B) \
A(0.00), A(0.00), A(1.00), A(1.00), A(1.00), A(1.00), A(1.00), A(0.00), A(0.00), \
A(0.00), A(1.00), A(1.00), B(0.00), B(0.00), B(0.00), A(1.00), A(1.00), A(0.00), \
A(1.00), A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), A(1.00), \
A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(1.00), A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), A(1.00), \
A(0.00), A(1.00), A(1.00), B(0.00), B(0.00), B(0.00), A(1.00), A(1.00), A(0.00), \
A(0.00), A(0.00), A(1.00), A(1.00), A(1.00), A(1.00), A(1.00), A(0.00), A(0.00)
DEF_ALPHAS(9)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 9, 9, alpha, mode);
}
return true;
}
else if (r == 5.0f)
{
if (aa) {
#define __ALPHAS__(B) \
A(0.00), A(0.00), A(0.00), A(0.58), A(0.90), A(1.00), A(0.90), A(0.58), A(0.00), A(0.00), A(0.00), \
A(0.00), A(0.00), A(1.00), B(0.42), B(0.10), B(0.00), B(0.10), B(0.42), A(1.00), A(0.00), A(0.00), \
A(0.00), A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), A(0.00), \
A(0.58), B(0.42), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.42), A(0.58), \
A(0.90), B(0.10), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.10), A(0.90), \
A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(0.90), B(0.10), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.10), A(0.90), \
A(0.58), B(0.42), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.42), A(0.58), \
A(0.00), A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), A(0.00), \
A(0.00), A(0.00), A(1.00), B(0.42), B(0.10), B(0.00), B(0.10), B(0.42), A(1.00), A(0.00), A(0.00), \
A(0.00), A(0.00), A(0.00), A(0.58), A(0.90), A(1.00), A(0.90), A(0.58), A(0.00), A(0.00), A(0.00)
DEF_ALPHAS(11)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 11, 11, alpha, mode);
return true;
}
}
else if (r == 6.0f)
{
if (aa) {
#define __ALPHAS__(B) \
A(0.00), A(0.00), A(0.00), A(0.20), A(0.66), A(0.92), A(1.00), A(0.92), A(0.66), A(0.20), A(0.00), A(0.00), A(0.00), \
A(0.00), A(0.00), A(0.47), A(0.81), B(0.35), B(0.09), B(0.00), B(0.09), B(0.35), A(0.81), A(0.47), A(0.00), A(0.00), \
A(0.00), A(0.47), B(0.53), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.53), A(0.47), A(0.00), \
A(0.20), A(0.81), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(0.81), A(0.20), \
A(0.66), B(0.35), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.35), A(0.66), \
A(0.92), B(0.09), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.09), A(0.92), \
A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(0.92), B(0.09), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.09), A(0.92), \
A(0.66), B(0.35), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.35), A(0.66), \
A(0.20), A(0.81), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(0.81), A(0.20), \
A(0.00), A(0.47), B(0.53), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.53), A(0.47), A(0.00), \
A(0.00), A(0.00), A(0.47), A(0.81), B(0.35), B(0.09), B(0.00), B(0.09), B(0.35), A(0.81), A(0.47), A(0.00), A(0.00), \
A(0.00), A(0.00), A(0.00), A(0.20), A(0.66), A(0.92), A(1.00), A(0.92), A(0.66), A(0.20), A(0.00), A(0.00), A(0.00),
DEF_ALPHAS(13)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 13, 13, alpha, mode);
return true;
}
}
else if (r == 7.0f)
{
if (aa) {
#define __ALPHAS__(B) \
A(0.00), A(0.00), A(0.00), A(0.00), A(0.33), A(0.71), A(0.93), A(1.00), A(0.93), A(0.71), A(0.33), A(0.00), A(0.00), A(0.00), A(0.00), \
A(0.00), A(0.00), A(0.00), A(0.75), A(0.68), B(0.29), B(0.07), B(0.00), B(0.07), B(0.29), A(0.68), A(0.75), A(0.00), A(0.00), A(0.00), \
A(0.00), A(0.00), A(0.90), B(0.26), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.34), A(0.90), A(0.00), A(0.00), \
A(0.00), A(0.75), B(0.34), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.26), A(0.75), A(0.00), \
A(0.33), A(0.68), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(0.68), A(0.33), \
A(0.71), B(0.29), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.29), A(0.71), \
A(0.93), B(0.07), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.07), A(0.93), \
A(1.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(1.00), \
A(0.93), B(0.07), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.07), A(0.93), \
A(0.71), B(0.29), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.29), A(0.71), \
A(0.33), A(0.68), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), A(0.68), A(0.33), \
A(0.00), A(0.75), B(0.34), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.26), A(0.75), A(0.00), \
A(0.00), A(0.00), A(0.90), B(0.26), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.00), B(0.34), A(0.90), A(0.00), A(0.00), \
A(0.00), A(0.00), A(0.00), A(0.75), A(0.68), B(0.29), B(0.07), B(0.00), B(0.07), B(0.29), A(0.68), A(0.75), A(0.00), A(0.00), A(0.00), \
A(0.00), A(0.00), A(0.00), A(0.00), A(0.33), A(0.71), A(0.93), A(1.00), A(0.93), A(0.71), A(0.33), A(0.00), A(0.00), A(0.00), A(0.00),
DEF_ALPHAS(15)
#undef __ALPHAS__
LICE_DrawGlyph(dest, cx-r, cy-r, color, alphas, 15, 15, alpha, mode);
return true;
}
}
return false;
}
template <class COMBFUNC> class _LICE_CircleDrawer
{
public:
static void DrawClippedPt(LICE_IBitmap* dest, int x, int y, const int *clip,
int r, int g, int b, int a, int alpha, bool doclip)
{
if (doclip && (x < clip[0] || x >= clip[2] || y < clip[1] || y >= clip[3])) return;
LICE_pixel* px = dest->getBits()+y*dest->getRowSpan()+x;
COMBFUNC::doPix((LICE_pixel_chan*)px, r, g, b, a, alpha);
}
static void DrawClippedHorzLine(LICE_IBitmap* dest, int y, int xlo, int xhi, const int *clip,
int r, int g, int b, int a, int alpha, bool doclip)
{
if (doclip)
{
if (y < clip[1] || y >= clip[3]) return;
xlo = lice_max(xlo, clip[0]);
xhi = lice_min(xhi, clip[2]-1);
}
LICE_pixel* px = dest->getBits()+y*dest->getRowSpan()+xlo;
while (xlo <= xhi)
{
COMBFUNC::doPix((LICE_pixel_chan*)px, r, g, b, a, alpha);
++px;
++xlo;
}
}
static void DrawClippedVertLine(LICE_IBitmap* dest, int x, int ylo, int yhi, const int *clip,
int r, int g, int b, int a, int alpha, bool doclip)
{
if (doclip)
{
if (x < clip[0] || x >= clip[2]) return;
ylo = lice_max(ylo, clip[1]);
yhi = lice_min(yhi, clip[3]-1);
}
int span=dest->getRowSpan();
LICE_pixel* px = dest->getBits()+ylo*span+x;
while (ylo <= yhi)
{
COMBFUNC::doPix((LICE_pixel_chan*)px, r, g, b, a, alpha);
px += span;
++ylo;
}
}
static void DrawClippedCircleAA(LICE_IBitmap* dest, float cx, float cy, float rad,
const int *clip, LICE_pixel color, int ai, bool filled, bool doclip)
{
int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);
const int cx0=(int)floor(cx+0.5f);
const int cy0=(int)floor(cy+0.5f);
int y=(int)rad;
double w=rad-floor(rad);
int wa=(int)((double)ai*w);
DrawClippedPt(dest, cx0, cy0-y-1, clip, r, g, b, a, wa, doclip);
DrawClippedPt(dest, cx0, cy0+y+1, clip, r, g, b, a, wa, doclip);
DrawClippedPt(dest, cx0-y-1, cy0, clip, r, g, b, a, wa, doclip);
DrawClippedPt(dest, cx0+y+1, cy0, clip, r, g, b, a, wa, doclip);
if (filled)
{
DrawClippedVertLine(dest, cx0, cy0-y, cy0-1, clip, r, g, b, a, ai, doclip);
DrawClippedVertLine(dest, cx0, cy0+1, cy0+y, clip, r, g, b, a, ai, doclip);
DrawClippedHorzLine(dest, cy0, cx0-y, cx0+y, clip, r, g, b, a, ai, doclip);
}
else
{
int iwa=ai-wa;
DrawClippedPt(dest, cx0, cy0-y, clip, r, g, b, a, iwa, doclip);
DrawClippedPt(dest, cx0+y, cy0, clip, r, g, b, a, iwa, doclip);
DrawClippedPt(dest, cx0, cy0+y, clip, r, g, b, a, iwa, doclip);
DrawClippedPt(dest, cx0-y, cy0, clip, r, g, b, a, iwa, doclip);
}
double r2=rad*rad;
double yf=sqrt(r2-1.0);
int yl=(int)(yf+0.5);
int x=1;
while (x <= yl)
{
y=(int)yf;
w=yf-floor(yf);
wa=(int)((double)ai*w);
DrawClippedPt(dest, cx0-x, cy0-y-1, clip, r, g, b, a, wa, doclip);
DrawClippedPt(dest, cx0-x, cy0+y+1, clip, r, g, b, a, wa, doclip);
DrawClippedPt(dest, cx0+x, cy0-y-1, clip, r, g, b, a, wa, doclip);
DrawClippedPt(dest, cx0+x, cy0+y+1, clip, r, g, b, a, wa, doclip);
if (x != yl)
{
DrawClippedPt(dest, cx0-y-1, cy0-x, clip, r, g, b, a, wa, doclip);
DrawClippedPt(dest, cx0+y+1, cy0-x, clip, r, g, b, a, wa, doclip);
DrawClippedPt(dest, cx0-y-1, cy0+x, clip, r, g, b, a, wa, doclip);
DrawClippedPt(dest, cx0+y+1, cy0+x, clip, r, g, b, a, wa, doclip);
}
if (filled)
{
DrawClippedVertLine(dest, cx0-x, cy0-y, cy0-x-1, clip, r, g, b, a, ai, doclip);
DrawClippedVertLine(dest, cx0-x, cy0+x+1, cy0+y, clip, r, g, b, a, ai, doclip);
DrawClippedHorzLine(dest, cy0-x, cx0-y, cx0-x, clip, r, g, b, a, ai, doclip);
DrawClippedHorzLine(dest, cy0-x, cx0+x, cx0+y, clip, r, g, b, a, ai, doclip);
DrawClippedHorzLine(dest, cy0+x, cx0-y, cx0-x, clip, r, g, b, a, ai, doclip);
DrawClippedHorzLine(dest, cy0+x, cx0+x, cx0+y, clip, r, g, b, a, ai, doclip);
DrawClippedVertLine(dest, cx0+x, cy0-y, cy0-x-1, clip, r, g, b, a, ai, doclip);
DrawClippedVertLine(dest, cx0+x, cy0+x+1, cy0+y, clip, r, g, b, a, ai, doclip);
}
else
{
int iwa=ai-wa;
DrawClippedPt(dest, cx0-y, cy0-x, clip, r, g, b, a, iwa, doclip);
DrawClippedPt(dest, cx0+y, cy0-x, clip, r, g, b, a, iwa, doclip);
DrawClippedPt(dest, cx0-x, cy0+y, clip, r, g, b, a, iwa, doclip);
DrawClippedPt(dest, cx0+x, cy0+y, clip, r, g, b, a, iwa, doclip);
if (x != yl)
{
DrawClippedPt(dest, cx0-x, cy0-y, clip, r, g, b, a, iwa, doclip);
DrawClippedPt(dest, cx0+x, cy0-y, clip, r, g, b, a, iwa, doclip);
DrawClippedPt(dest, cx0-y, cy0+x, clip, r, g, b, a, iwa, doclip);
DrawClippedPt(dest, cx0+y, cy0+x, clip, r, g, b, a, iwa, doclip);
}
}
++x;
yf=sqrt(r2-(double)(x*x));
yl=(int)(yf+0.5);
}
}
static void DrawClippedCircle(LICE_IBitmap* dest, float cx, float cy, float rad,
const int *clip, LICE_pixel color, int ai, bool filled, bool doclip)
{
const int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);
const int cx0=(int)floor(cx+0.5f);
const int cy0=(int)floor(cy+0.5f);
const int r0=(int)(rad+0.5f);
if (filled)
{
DrawClippedVertLine(dest, cx0, cy0-r0, cy0-1, clip, r, g, b, a, ai, doclip);
DrawClippedVertLine(dest, cx0, cy0+1, cy0+r0, clip, r, g, b, a, ai, doclip);
DrawClippedHorzLine(dest, cy0, cx0-r0, cx0+r0, clip, r, g, b, a, ai, doclip);
}
else
{
DrawClippedPt(dest, cx0, cy0-r0, clip, r, g, b, a, ai, doclip);
DrawClippedPt(dest, cx0+r0, cy0, clip, r, g, b, a, ai, doclip);
DrawClippedPt(dest, cx0, cy0+r0, clip, r, g, b, a, ai, doclip);
DrawClippedPt(dest, cx0-r0, cy0, clip, r, g, b, a, ai, doclip);
}
int x=0;
int y=r0;
int e=-r0;
while (++x < y)
{
if (e < 0)
{
e += 2*x+1;
}
else
{
--y;
e += 2*(x-y)+1;
}
if (filled)
{
DrawClippedVertLine(dest, cx0-x, cy0-y, cy0-x-1, clip, r, g, b, a, ai, doclip);
DrawClippedVertLine(dest, cx0-x, cy0+x+1, cy0+y, clip, r, g, b, a, ai, doclip);
DrawClippedHorzLine(dest, cy0-x, cx0-y, cx0-x, clip, r, g, b, a, ai, doclip);
DrawClippedHorzLine(dest, cy0-x, cx0+x, cx0+y, clip, r, g, b, a, ai, doclip);
DrawClippedHorzLine(dest, cy0+x, cx0-y, cx0-x, clip, r, g, b, a, ai, doclip);
DrawClippedHorzLine(dest, cy0+x, cx0+x, cx0+y, clip, r, g, b, a, ai, doclip);
DrawClippedVertLine(dest, cx0+x, cy0-y, cy0-x-1, clip, r, g, b, a, ai, doclip);
DrawClippedVertLine(dest, cx0+ x, cy0+x+1, cy0+y, clip, r, g, b, a, ai, doclip);
}
else
{
DrawClippedPt(dest, cx0-x, cy0-y, clip, r, g, b, a, ai, doclip);
DrawClippedPt(dest, cx0-x, cy0+y, clip, r, g, b, a, ai, doclip);
DrawClippedPt(dest, cx0+x, cy0-y, clip, r, g, b, a, ai, doclip);
DrawClippedPt(dest, cx0+x, cy0+y, clip, r, g, b, a, ai, doclip);
if (x != y)
{
DrawClippedPt(dest, cx0-y, cy0-x, clip, r, g, b, a, ai, doclip);
DrawClippedPt(dest, cx0-y, cy0+x, clip, r, g, b, a, ai, doclip);
DrawClippedPt(dest, cx0+y, cy0-x, clip, r, g, b, a, ai, doclip);
DrawClippedPt(dest, cx0+y, cy0+x, clip, r, g, b, a, ai, doclip);
}
}
}
}
};
static void __DrawCircleClipped(LICE_IBitmap* dest, float cx, float cy, float rad,
LICE_pixel color, int ia, bool aa, bool filled, int mode, const int *clip, bool doclip)
{
// todo: more clipped/filled versions (to optimize constants out?)
if (aa)
{
#define __LICE__ACTION(COMBFUNC) _LICE_CircleDrawer<COMBFUNC>::DrawClippedCircleAA(dest, cx, cy, rad, clip, color, ia, filled, doclip)
__LICE_ACTION_NOSRCALPHA(mode, ia,false)
#undef __LICE__ACTION
}
else
{
#define __LICE__ACTION(COMBFUNC) _LICE_CircleDrawer<COMBFUNC>::DrawClippedCircle(dest, cx, cy, rad, clip, color, ia, filled, doclip)
__LICE_ACTION_CONSTANTALPHA(mode,ia,false)
#undef __LICE__ACTION
}
}
static void __DrawArc(int w, int h, LICE_IBitmap* dest, float cx, float cy, float rad, double anglo, double anghi,
LICE_pixel color, int ialpha, bool aa, int mode)
{
const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
if (__sc>0)
{
__LICE_SCU(w);
__LICE_SCU(h);
if (!IGNORE_SCALING(mode))
{
__LICE_SC(cx);
__LICE_SC(cy);
__LICE_SC(rad);
}
}
// -2PI <= anglo <= anghi <= 2PI
anglo += 2.0*_PI;
anghi += 2.0*_PI;
// 0 <= anglo <= anghi <= 4PI
double next_ang = anglo - fmod(anglo,0.5*_PI);
int ly = (int)floor(cy - rad*cos(anglo) + 0.5);
int lx = (int)floor(cx + rad*sin(anglo) + 0.5);
while (anglo < anghi)
{
next_ang += 0.5*_PI;
if (next_ang > anghi) next_ang = anghi;
int yhi = (int) floor(cy-rad*cos(next_ang)+0.5);
int xhi = (int) floor(cx+rad*sin(next_ang)+0.5);
int ylo = ly;
int xlo = lx;
ly = yhi;
lx = xhi;
if (yhi < ylo) { int tmp = ylo; ylo = yhi; yhi=tmp; }
if (xhi < xlo) { int tmp = xlo; xlo = xhi; xhi=tmp; }
anglo = next_ang;
if (xhi != cx) xhi++;
if (yhi != cy) yhi++;
const int clip[4]={lice_max(xlo,0),lice_max(0, ylo),lice_min(w,xhi+1),lice_min(h, yhi+1)};
__DrawCircleClipped(dest,cx,cy,rad,color,ialpha,aa,false,mode,clip,true);
}
}
void LICE_Arc(LICE_IBitmap* dest, float cx, float cy, float r, float minAngle, float maxAngle,
LICE_pixel color, float alpha, int mode, bool aa)
{
if (!dest) return;
if (dest->isFlipped()) { cy=dest->getHeight()-1-cy; minAngle=_PI-minAngle; maxAngle=_PI-maxAngle; }
if (maxAngle < minAngle)
{
float tmp=maxAngle;
maxAngle=minAngle;
minAngle=tmp;
}
if (maxAngle - minAngle >= 2.0f*_PI)
{
LICE_Circle(dest,cx,cy,r,color,alpha,mode,aa);
return;
}
if (maxAngle >= 2.0f*_PI)
{
float tmp = fmod(maxAngle,2.0f*_PI);
minAngle -= maxAngle - tmp; // reduce by factors of 2PI
maxAngle = tmp;
}
else if (minAngle <= -2.0f*_PI)
{
float tmp = fmod(minAngle,2.0f*_PI);
maxAngle -= minAngle - tmp; // toward zero by factors of 2pi
minAngle = tmp;
}
// -2PI <= minAngle <= maxAngle <= 2PI
int ia = (int) (alpha*256.0f);
if (!ia) return;
__DrawArc(dest->getWidth(),dest->getHeight(),dest,cx,cy,r,minAngle,maxAngle,color,ia,aa,mode);
}
void LICE_Circle(LICE_IBitmap* dest, float cx, float cy, float r, LICE_pixel color, float alpha, int mode, bool aa)
{
if (!dest) return;
int w = dest->getWidth(), h = dest->getHeight();
const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
if (__sc>0)
{
__LICE_SCU(w);
__LICE_SCU(h);
if (!IGNORE_SCALING(mode))
{
__LICE_SC(cx);
__LICE_SC(cy);
__LICE_SC(r);
}
}
const int clip[4] = { 0, 0, w, h };
if (w < 1 || h <1 || r<0 ||
(int)cx+(int)r < -2 || (int)cy + (int)r < - 2 ||
(int)cx-(int)r > w + 2 || (int)cy - (int)r > h + 2
) return;
int ia = (int) (alpha*256.0f);
if (!ia) return;
if (CachedCircle(dest, cx, cy, r, color, alpha, mode|LICE_BLIT_IGNORE_SCALING, aa, false)) return;
if (dest->isFlipped()) cy=h-1-cy;
const bool doclip = !(cx-r-2 >= 0 && cy-r-2 >= 0 && cx+r+2 < w && cy+r+2 < h);
__DrawCircleClipped(dest,cx,cy,r,color,ia,aa,false,mode,clip,doclip);
}
void LICE_FillCircle(LICE_IBitmap* dest, float cx, float cy, float r, LICE_pixel color, float alpha, int mode, bool aa)
{
if (!dest) return;
int w = dest->getWidth(), h = dest->getHeight();
const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
if (__sc>0)
{
__LICE_SCU(w);
__LICE_SCU(h);
if (!IGNORE_SCALING(mode))
{
__LICE_SC(cx);
__LICE_SC(cy);
__LICE_SC(r);
}
}
if (w < 1 || h < 1 || r < 0.0 ||
(int)cx+(int)r < -2 || (int)cy + (int)r < - 2 ||
(int)cx-(int)r > w + 2 || (int)cy - (int)r > h + 2
) return;
const int ia = (int) (alpha*256.0f);
if (!ia) return;
if (CachedCircle(dest, cx, cy, r, color, alpha, mode|LICE_BLIT_IGNORE_SCALING, aa, true)) return;
if (dest->isFlipped()) cy=h-1-cy;
const int clip[4] = { 0, 0, w, h };
const bool doclip = !(cx-r-2 >= 0 && cy-r-2 >= 0 && cx+r+2 < w && cy+r+2 < h);
__DrawCircleClipped(dest,cx,cy,r,color,ia,aa,true,mode,clip,doclip);
}
void LICE_RoundRect(LICE_IBitmap *drawbm, float xpos, float ypos, float w, float h, int cornerradius,
LICE_pixel col, float alpha, int mode, bool aa)
{
xpos = floor(xpos+0.5);
ypos = floor(ypos+0.5);
w = floor(w+0.5);
h = floor(h+0.5);
if (cornerradius>0)
{
float cr=cornerradius;
if (cr > w*0.5) cr=w*0.5;
if (cr > h*0.5) cr=h*0.5;
cr=floor(cr);
if (cr>=2)
{
double adj = 0.0;
const int __sc = IGNORE_SCALING(mode) ? 0 : drawbm ? (int)drawbm->Extended(LICE_EXT_GET_SCALING,NULL) : 0;
if (__sc>0)
{
adj = 1.0 - 256.0/__sc;
LICE_FLine(drawbm,xpos+cr+adj,ypos+adj,xpos+w-cr,ypos+adj,col,alpha,mode,true);
LICE_FLine(drawbm,xpos+cr-1+adj,ypos+h-adj,xpos+w-cr-adj,ypos+h-adj,col,alpha,mode,true);
LICE_FLine(drawbm,xpos+w-adj,ypos+cr+adj,xpos+w-adj,ypos+h-cr-adj,col,alpha,mode,true);
LICE_FLine(drawbm,xpos+adj,ypos+cr-1+adj,xpos+adj,ypos+h-cr-adj,col,alpha,mode,true);
// aa=true;
}
else
{
LICE_Line(drawbm,xpos+cr,ypos,xpos+w-cr,ypos,col,alpha,mode,aa);
LICE_Line(drawbm,xpos+cr-1,ypos+h,xpos+w-cr,ypos+h,col,alpha,mode,aa);
LICE_Line(drawbm,xpos+w,ypos+cr,xpos+w,ypos+h-cr,col,alpha,mode,aa);
LICE_Line(drawbm,xpos,ypos+cr-1,xpos,ypos+h-cr,col,alpha,mode,aa);
}
LICE_Arc(drawbm,xpos+cr+adj,ypos+cr+adj,cr,-_PI*0.5f,0,col,alpha,mode,aa);
LICE_Arc(drawbm,xpos+w-cr-adj,ypos+cr+adj,cr,0,_PI*0.5f,col,alpha,mode,aa);
LICE_Arc(drawbm,xpos+w-cr-adj,ypos+h-cr-adj,cr,_PI*0.5f,_PI,col,alpha,mode,aa);
LICE_Arc(drawbm,xpos+cr+adj,ypos+h-cr-adj,cr,_PI,_PI*1.5f,col,alpha,mode,aa);
return;
}
}
LICE_DrawRect(drawbm, (int)xpos, (int)ypos, (int)w, (int)h, col, alpha, mode);
}

View File

@@ -0,0 +1,306 @@
#ifndef _LICE_BEZIER_
#define _LICE_BEZIER_
#include "lice.h"
#include <math.h>
// Returns quadratic bezier x, y for a given t in [0,1].
template <class T>
void LICE_Bezier(T ctrl_x1, T ctrl_x2, T ctrl_x3,
T ctrl_y1, T ctrl_y2, T ctrl_y3, double t, T* pX, T* pY)
{
double it = 1.0 - t;
double a = it * it;
double b = 2.0 * it * t;
double c = t * t;
*pX = (T) (a * (double) ctrl_x1 + b * (double) ctrl_x2 + c * (double) ctrl_x3);
*pY = (T) (a * (double) ctrl_y1 + b * (double) ctrl_y2 + c * (double) ctrl_y3);
}
template <class T>
void LICE_CBezier_GetCoeffs(T ctrl_x1, T ctrl_x2, T ctrl_x3, T ctrl_x4,
T ctrl_y1, T ctrl_y2, T ctrl_y3, T ctrl_y4,
double* pAX, double* pBX, double* pCX,
double* pAY, double* pBY, double* pCY)
{
double cx = *pCX = 3.0 * (double) (ctrl_x2 - ctrl_x1);
double bx = *pBX = 3.0 * (double) (ctrl_x3 - ctrl_x2) - cx;
*pAX = (double) (ctrl_x4 - ctrl_x1) - cx - bx;
double cy = *pCY = 3.0 * (double) (ctrl_y2 - ctrl_y1);
double by = *pBY = 3.0 * (double) (ctrl_y3 - ctrl_y2) - cy;
*pAY = (double) (ctrl_y4 - ctrl_y1) - cy - by;
}
// Returns cubic bezier x, y for a given t in [0,1].
template <class T>
void LICE_CBezier(T ctrl_x1, T ctrl_x2, T ctrl_x3, T ctrl_x4,
T ctrl_y1, T ctrl_y2, T ctrl_y3, T ctrl_y4, double t, T* pX, T* pY)
{
double ax, bx, cx, ay, by, cy;
LICE_CBezier_GetCoeffs(ctrl_x1, ctrl_x2, ctrl_x3, ctrl_x4,
ctrl_y1, ctrl_y2, ctrl_y3, ctrl_y4,
&ax, &bx, &cx, &ay, &by, &cy);
double t2 = t * t;
double t3 = t * t2;
*pX = (T) (ax * t3 + bx * t2 + cx * t) + ctrl_x1;
*pY = (T) (ay * t3 + by * t2 + cy * t) + ctrl_y1;
}
// Returns quadratic bezier y for a given x in [x1, x3] (for rasterizing).
// ctrl_x1 < ctrl_x3 required.
template <class T>
T LICE_Bezier_GetY(T ctrl_x1, T ctrl_x2, T ctrl_x3, T ctrl_y1, T ctrl_y2, T ctrl_y3, T x, double* pt=0)
{
if (x <= ctrl_x1)
{
if (pt) *pt = 0.0;
return ctrl_y1;
}
if (x >= ctrl_x3)
{
if (pt) *pt = 1.0;
return ctrl_y3;
}
double t, a = (double) ctrl_x1 - (double) (2 * ctrl_x2) + (double) ctrl_x3;
if (a == 0.0)
{
t=(ctrl_x1 == ctrl_x3) ? 0.0 : (x-ctrl_x1)/(ctrl_x3-ctrl_x1);
}
else
{
t = (double) (ctrl_x2 - ctrl_x1);
t = (-t + sqrt(t * t - a * (ctrl_x1 - x))) / a;
}
const double it = 1.0 - t;
if (pt) *pt = t;
return (T) (it * it * (double) ctrl_y1 + t * (2.0*it*(double)ctrl_y2 + t * (double) ctrl_y3));
}
// Special case for x = y = [0,1]
template <class T>
void LICE_Bezier_Norm(T ctrl_x2, T ctrl_y2, double t, T* pX, T* pY)
{
double b = 2.0 * (1.0 - t) * t;
double c = t * t;
*pX = (T) (b * (double) ctrl_x2 + c);
*pY = (T) (b * (double) ctrl_y2 + c);
}
// special case for x = y = [0,1].
template <class T>
T LICE_Bezier_GetY_Norm(T ctrl_x2, T ctrl_y2, T x)
{
if (x < (T) 0.0) {
return (T) 0.0;
}
if (x >= (T) 1.0) {
return (T) 1.0;
}
if (ctrl_x2 == (T) 0.5) { // linear
return x;
}
/*
// this causes ICC 11.0 to produce bad results on OSX/386
double b = (double) (2 * ctrl_x2);
double a = 1.0 - b;
double c = (double) -x;
double t = (-b + sqrt(b * b - 4.0 * a * c)) / (2.0 * a);
b = 2.0 * (1.0 - t) * t;
c = t * t;
return (T) (b * (double) ctrl_y2 + c);
// the simplified math below works properly
*/
const double t = (-ctrl_x2 + sqrt(ctrl_x2 * (ctrl_x2 - 2.0*x) + x)) / (1.0-2.0*ctrl_x2);
return (T) (((2.0 * (1.0-t)) * ctrl_y2 + t)*t);
}
// Finds the cardinal bezier control points surrounding x2.
// Cubic bezier over (x1,x1b,x2a,x2), (y1,y1b,y2a,y2) or
// quadratic bezier over (x1,x1b,mid(x1b,x2a)), (y1,y1b,mid(y1b,y2a))
// will smoothly interpolate between (x1,y1) and (x2,y2) while preserving all existing values.
// The lower alpha is, the more tame the bezier curve will be (0.25 = subtle).
template <class T>
void LICE_Bezier_FindCardinalCtlPts(double alpha, T x1, T x2, T x3, T y1, T y2, T y3,
T* ctrl_x2a, T* ctrl_x2b, T* ctrl_y2a, T* ctrl_y2b)
{
double dxa = alpha * (double) (x2 - x1);
double dxb = alpha * (double) (x3 - x2);
if (ctrl_x2a) *ctrl_x2a = x2 - (T) dxa;
if (ctrl_x2b) *ctrl_x2b = x2 + (T) dxb;
if (x1 == x3)
{
if (ctrl_y2a) *ctrl_y2a = y2;
if (ctrl_y2b) *ctrl_y2b = y2;
}
else
{
double m = (double) (y3 - y1) / (double) (x3 - x1);
if (ctrl_y2a) *ctrl_y2a = y2 - (T) (m * dxa);
if (ctrl_y2b) *ctrl_y2b = y2 + (T) (m * dxb);
}
}
// Basic quadratic nurbs. Given a set of n (x,y) pairs,
// populate pDest with the unit-spaced nurbs curve.
// pDest must be passed in with size (int) (*(pX+n-1) - *pX).
// pX must be monotonically increasing and no duplicates.
template <class T>
inline void LICE_QNurbs(T* pDest, int pDest_sz, int *pX, T* pY, int n, bool hit_each_point=false)
{
int x1 = *pX++, x2 = *pX++;
T y1 = *pY++, y2 = *pY++;
double xm1, xm2 = 0.5 * (x1 + x2);
double ym1, ym2 = 0.5 * (y1 + y2);
double yi = y1, m = (y2 - y1) / (double) (x2 - x1);
int xi = x1, iend = (int)floor(xm2+0.5); // this (and below) was previously ceil(), but can't see any reason why it should matter (this should be more correct, I'd imagine)
for (; xi < iend; xi++, yi += m)
{
if (--pDest_sz<0) return;
*pDest++ = (T) yi;
}
for (int i = 2; i < n; ++i)
{
x1 = x2;
x2 = *pX++;
y1 = y2;
y2 = *pY++;
xm1 = xm2;
xm2 = 0.5 * (x1 + x2);
ym1 = ym2;
ym2 = 0.5 * (y1 + y2);
iend = (int)floor(xm2+0.5);
if (ym1 == ym2 && y1 == ym1)
{
for (; xi < iend; xi++)
{
if (--pDest_sz<0) return;
*pDest++ = (T) y1;
}
}
else
{
double y1u = y1;
if (hit_each_point)
{
// y1 = LICE_Bezier_GetY(0,0.5,1.0, ym1,y1u,ym2,0.5), this is the inverse
y1u = 2.0 * y1 - 0.5 * (ym1 + ym2);
}
for (; xi < iend; xi++)
{
if (--pDest_sz<0) return;
*pDest++ = (T) LICE_Bezier_GetY(xm1, (double)x1, xm2, ym1, (double)y1u, ym2, (double)xi);
}
}
}
m = (y2 - y1) / (double) (x2 - x1);
yi = ym2;
for (; xi < x2; xi++, yi += m)
{
if (--pDest_sz<0) return;
*pDest++ = (T) yi;
}
}
#define CBEZ_ITERS 8
#define EVAL_CBEZ(tx,a,b,c,d,t) \
{ \
double _t2=t*t; \
tx=(a*t*_t2+b*_t2+c*t+d); \
}
#define EVAL_CBEZXY(tx, ty, ax, bx, cx, dx, ay, by, cy, dy, t) \
{ \
double _t2=t*t; \
double _t3=t*_t2; \
tx=ax*_t3+bx*_t2+cx*t+dx; \
ty=ay*_t3+by*_t2+cy*t+dy; \
}
template <class T>
T LICE_CBezier_GetY(T ctrl_x1, T ctrl_x2, T ctrl_x3, T ctrl_x4,
T ctrl_y1, T ctrl_y2, T ctrl_y3, T ctrl_y4, T x,
T* pNextX = 0, T* pdYdX = 0, double* ptLo = 0, double* ptHi = 0)
{
if (x < ctrl_x1)
{
if (pNextX) *pNextX = ctrl_x1;
if (pdYdX) *pdYdX = (T) 0.0;
return ctrl_y1;
}
if (x >= ctrl_x4)
{
if (pNextX) *pNextX = ctrl_x4;
if (pdYdX) *pdYdX = (T) 0.0;
return ctrl_y4;
}
double ax, bx, cx, ay, by, cy;
LICE_CBezier_GetCoeffs(ctrl_x1, ctrl_x2, ctrl_x3, ctrl_x4,
ctrl_y1, ctrl_y2, ctrl_y3, ctrl_y4,
&ax, &bx, &cx, &ay, &by, &cy);
double tx, t, tLo = 0.0, tHi = 1.0;
double xLo=0.0, xHi=0.0, yLo, yHi;
int i;
for (i = 0; i < CBEZ_ITERS; ++i)
{
t = 0.5 * (tLo + tHi);
EVAL_CBEZ(tx, ax, bx, cx, (double) ctrl_x1, t);
if (tx < (double) x)
{
tLo = t;
xLo = tx;
}
else if (tx > (double) x)
{
tHi = t;
xHi = tx;
}
else
{
tLo = t;
xLo = tx;
tHi = t + 1.0/pow(2.0,CBEZ_ITERS);
if (tHi > 1.0) tHi = 1.0; // floating point error
EVAL_CBEZ(xHi, ax, bx, cx, (double) ctrl_x1, tHi);
break;
}
}
if (tLo == 0.0) EVAL_CBEZ(xLo, ax, bx, cx, (double) ctrl_x1, 0.0);
if (tHi == 1.0) EVAL_CBEZ(xHi, ax, bx, cx, (double) ctrl_x1, 1.0);
EVAL_CBEZ(yLo, ay, by, cy, (double) ctrl_y1, tLo);
EVAL_CBEZ(yHi, ay, by, cy, (double) ctrl_y1, tHi);
double dYdX = (xLo == xHi ? 0.0 : (yHi - yLo) / (xHi - xLo));
double y = yLo + ((double) x - xLo) * dYdX;
if (pNextX) *pNextX = (T) xHi;
if (pdYdX) *pdYdX = (T) dYdX;
if (ptLo) *ptLo = tLo;
if (ptHi) *ptHi = tHi;
return (T) y;
}
#endif

View File

@@ -0,0 +1,122 @@
/*
Cockos WDL - LICE - Lightweight Image Compositing Engine
Copyright (C) 2007 and later, Cockos Incorporated
File: lice_bmp.cpp (BMP loading for LICE)
See lice.h for license and other information
*/
#ifndef WDL_NO_DEFINE_MINMAX
#define WDL_NO_DEFINE_MINMAX
#endif
#include "lice.h"
#include "../wdltypes.h"
#ifndef _WIN32
#include "../swell/swell.h"
#endif
static LICE_IBitmap *hbmToBit(HBITMAP hbm, LICE_IBitmap *bmp)
{
BITMAP bm;
GetObject(hbm, sizeof(BITMAP), (LPSTR)&bm);
LICE_SysBitmap sysbitmap(bm.bmWidth,bm.bmHeight);
#ifdef _WIN32
HDC hdc=CreateCompatibleDC(NULL);
HGDIOBJ oldBM=SelectObject(hdc,hbm);
BitBlt(sysbitmap.getDC(),0,0,bm.bmWidth,bm.bmHeight,hdc,0,0,SRCCOPY);
GdiFlush();
if (!bmp) bmp=new WDL_NEW LICE_MemBitmap(bm.bmWidth,bm.bmHeight);
LICE_Copy(bmp,&sysbitmap);
SelectObject(hdc,oldBM);
DeleteDC(hdc);
#else
LICE_Clear(&sysbitmap,0);
RECT r={0,0,bm.bmWidth,bm.bmHeight};
DrawImageInRect(sysbitmap.getDC(),hbm,&r);
if (!bmp) bmp=new WDL_NEW LICE_MemBitmap(bm.bmWidth,bm.bmHeight);
LICE_Copy(bmp,&sysbitmap);
#endif
if (bmp) LICE_FillRect(bmp,0,0,bmp->getWidth(),bmp->getHeight(),LICE_RGBA(0,0,0,255),1.0f,LICE_BLIT_MODE_ADD);
return bmp;
}
LICE_IBitmap *LICE_LoadBMP(const char *filename, LICE_IBitmap *bmp) // returns a bitmap (bmp if nonzero) on success
{
HBITMAP bm=NULL;
#ifdef _WIN32
#ifndef WDL_NO_SUPPORT_UTF8
#ifdef WDL_SUPPORT_WIN9X
if (GetVersion()<0x80000000)
#endif
{
WCHAR wf[2048];
if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,wf,2048))
bm = (HBITMAP) LoadImageW(NULL,wf,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_LOADFROMFILE);
}
#endif
if (!bm) bm=(HBITMAP) LoadImage(NULL,filename,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_LOADFROMFILE);
#else
bm=(HBITMAP) LoadNamedImage(filename,false);
#endif
if (!bm) return 0;
LICE_IBitmap *ret=hbmToBit(bm,bmp);
DeleteObject(bm);
return ret;
}
#ifdef _WIN32
LICE_IBitmap *LICE_LoadBMPFromResource(HINSTANCE hInst, const char *resid, LICE_IBitmap *bmp) // returns a bitmap (bmp if nonzero) on success
{
HBITMAP bm=(HBITMAP) LoadImage(hInst,resid,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
if (!bm) return 0;
LICE_IBitmap *ret=hbmToBit(bm,bmp);
DeleteObject(bm);
return ret;
}
#endif
class LICE_BMPLoader
{
public:
_LICE_ImageLoader_rec rec;
LICE_BMPLoader()
{
rec.loadfunc = loadfunc;
rec.get_extlist = get_extlist;
rec._next = LICE_ImageLoader_list;
LICE_ImageLoader_list = &rec;
}
static LICE_IBitmap *loadfunc(const char *filename, bool checkFileName, LICE_IBitmap *bmpbase)
{
if (checkFileName)
{
const char *p=filename;
while (*p)p++;
while (p>filename && *p != '\\' && *p != '/' && *p != '.') p--;
if (stricmp(p,".bmp")) return 0;
}
return LICE_LoadBMP(filename,bmpbase);
}
static const char *get_extlist()
{
return "BMP files (*.BMP)\0*.BMP\0";
}
};
LICE_BMPLoader LICE_bmpldr;

View File

@@ -0,0 +1,151 @@
#ifndef WDL_NO_DEFINE_MINMAX
#define WDL_NO_DEFINE_MINMAX
#endif
#include "lice.h"
#include <math.h>
#define LICE_COMBINE_IMPLEMENT_HSV
#include "lice_combine.h"
LICE_pixel LICE_AlterColorHSV_int(LICE_pixel color, int dH, int dS, int dV) // H is rolled over [0,384), S and V are clamped [0,255)
{
int h, s, v;
LICE_RGB2HSV(LICE_GETR(color), LICE_GETG(color), LICE_GETB(color), &h, &s, &v);
h += dH;
s += dS;
v += dV;
if (h < 0) h += 384;
else if (h >= 384) h -= 384;
if (s & ~255)
{
if (s<0) s = 0;
else s = 255;
}
if (v&~255)
{
if (v < 0) v = 0.;
else v = 255;
}
return LICE_HSV2Pix(h, s, v, LICE_GETA(color));
}
LICE_pixel LICE_AlterColorHSV(LICE_pixel color, float dH, float dS, float dV) // H is rolled over, S and V are clamped, all [0,1)
{
int dHi = (int)(dH*384.0f);
int dSi = (int)(dS*255.0f);
int dVi = (int)(dV*255.0f);
return LICE_AlterColorHSV_int(color, dHi, dSi, dVi);
}
void LICE_AlterBitmapHSV(LICE_IBitmap* src, float dH, float dS, float dV) // H is rolled over, S and V are clamped
{
if (src) LICE_AlterRectHSV(src,0,0,src->getWidth(),src->getHeight(),dH,dS,dV);
}
void LICE_AlterRectHSV(LICE_IBitmap* src, int xpos, int ypos, int w, int h, float dH, float dS, float dV, int mode) // H is rolled over, S and V are clamped
{
if (!src) return;
int destbm_w = src->getWidth(), destbm_h = src->getHeight();
const int __sc = (int)src->Extended(LICE_EXT_GET_SCALING,NULL);
if (__sc>0)
{
__LICE_SCU(destbm_w);
__LICE_SCU(destbm_h);
if (!(mode & LICE_BLIT_IGNORE_SCALING))
{
__LICE_SC(w);
__LICE_SC(h);
__LICE_SC(xpos);
__LICE_SC(ypos);
}
}
if (xpos < 0) {
w += xpos;
xpos = 0;
}
if (ypos < 0) {
h += ypos;
ypos = 0;
}
const int span = src->getRowSpan();
if (span < 1 || w < 1 || h < 1 || xpos >= destbm_w || ypos >= destbm_h) return;
if (w > destbm_w - xpos) w = destbm_w - xpos;
if (h > destbm_h - ypos) h = destbm_h - ypos;
LICE_pixel* px = src->getBits()+ypos*span+xpos;
int dHi = (int)(dH*384.0f);
int dSi = (int)(dS*255.0f);
int dVi = (int)(dV*255.0f);
if (dHi > 383) dHi=383;
else if (dHi < -383) dHi=-383;
if (!dHi && !dSi && !dVi) return; // no mod
if (w*h > 8192)
{
// generate a table of HSV translations with clip/clamp
unsigned char stab[256], vtab[256];
short htab[384];
int x;
for(x=0;x<256;x++)
{
int a=x+dSi;
if(a<0)a=0; else if (a>255)a=255;
stab[x]=a;
a=x+dVi;
if(a<0)a=0; else if (a>255)a=255;
vtab[x]=a;
a=x+dHi;
if(a<0)a+=384; else if (a>=384)a-=384;
htab[x]=a;
}
for(;x<384;x++)
{
int a=x+dHi;
if(a<0)a+=384; else if (a>=384)a-=384;
htab[x]=a;
}
while (h-->0)
{
LICE_pixel* tpx = px;
px+=span;
int xi=w;
while (xi-->0)
{
LICE_pixel color = *tpx;
int hh,s,v;
LICE_RGB2HSV(LICE_GETR(color), LICE_GETG(color), LICE_GETB(color), &hh, &s, &v);
*tpx++ = LICE_HSV2Pix(htab[hh],stab[s],vtab[v],LICE_GETA(color));
}
}
}
else
{
while (h-->0)
{
LICE_pixel* tpx = px;
px+=span;
int xi=w;
while (xi-->0)
{
*tpx = LICE_AlterColorHSV_int(*tpx, dHi, dSi, dVi);
tpx++;
}
}
}
}

View File

@@ -0,0 +1,846 @@
#ifndef _LICE_COMBINE_H_
#define _LICE_COMBINE_H_
#include "../wdltypes.h"
#if defined(_MSC_VER)
#pragma warning(disable:4244) // float-to-int
#endif
#define __LICE_BOUND(x,lo,hi) ((x)<(lo)?(lo):((x)>(hi)?(hi):(x)))
#define LICE_PIXEL_HALF(x) (((x)>>1)&0x7F7F7F7F)
#define LICE_PIXEL_QUARTER(x) (((x)>>2)&0x3F3F3F3F)
#define LICE_PIXEL_EIGHTH(x) (((x)>>3)&0x1F1F1F1F)
static inline void __LICE_BilinearFilterI(int *r, int *g, int *b, int *a, const LICE_pixel_chan *pin, const LICE_pixel_chan *pinnext, unsigned int xfrac, unsigned int yfrac)
{
const unsigned int f4=(xfrac*yfrac)>>16;
const unsigned int f3=yfrac-f4; // (1.0-xfrac)*yfrac;
const unsigned int f2=xfrac-f4; // xfrac*(1.0-yfrac);
const unsigned int f1=65536-yfrac-xfrac+f4; // (1.0-xfrac)*(1.0-yfrac);
#define DOCHAN(output, inchan) \
(output)=(pin[(inchan)]*f1 + pin[4+(inchan)]*f2 + pinnext[(inchan)]*f3 + pinnext[4+(inchan)]*f4)>>16;
DOCHAN(*r,LICE_PIXEL_R)
DOCHAN(*g,LICE_PIXEL_G)
DOCHAN(*b,LICE_PIXEL_B)
DOCHAN(*a,LICE_PIXEL_A)
#undef DOCHAN
}
static inline void __LICE_BilinearFilterIPixOut(LICE_pixel_chan *out, const LICE_pixel_chan *pin, const LICE_pixel_chan *pinnext, unsigned int xfrac, unsigned int yfrac)
{
const unsigned int f4=(xfrac*yfrac)>>16;
const unsigned int f3=yfrac-f4; // (1.0-xfrac)*yfrac;
const unsigned int f2=xfrac-f4; // xfrac*(1.0-yfrac);
const unsigned int f1=65536-yfrac-xfrac+f4; // (1.0-xfrac)*(1.0-yfrac);
#define DOCHAN(inchan) \
(out[inchan])=(pin[(inchan)]*f1 + pin[4+(inchan)]*f2 + pinnext[(inchan)]*f3 + pinnext[4+(inchan)]*f4)>>16;
DOCHAN(LICE_PIXEL_R)
DOCHAN(LICE_PIXEL_G)
DOCHAN(LICE_PIXEL_B)
DOCHAN(LICE_PIXEL_A)
#undef DOCHAN
}
static inline void __LICE_BilinearFilterI_2(int *r, int *g, int *b, int *a, const LICE_pixel_chan *pin, const LICE_pixel_chan *pinnext, int npoffs, unsigned int xfrac, unsigned int yfrac)
{
const unsigned int f4=(xfrac*yfrac)>>16;
const unsigned int f3=yfrac-f4; // (1.0-xfrac)*yfrac;
const unsigned int f2=xfrac-f4; // xfrac*(1.0-yfrac);
const unsigned int f1=65536-yfrac-xfrac+f4; // (1.0-xfrac)*(1.0-yfrac);
*r=(pin[LICE_PIXEL_R]*f1 + pin[npoffs+LICE_PIXEL_R]*f2 + pinnext[LICE_PIXEL_R]*f3 + pinnext[npoffs+LICE_PIXEL_R]*f4)>>16;
*g=(pin[LICE_PIXEL_G]*f1 + pin[npoffs+LICE_PIXEL_G]*f2 + pinnext[LICE_PIXEL_G]*f3 + pinnext[npoffs+LICE_PIXEL_G]*f4)>>16;
*b=(pin[LICE_PIXEL_B]*f1 + pin[npoffs+LICE_PIXEL_B]*f2 + pinnext[LICE_PIXEL_B]*f3 + pinnext[npoffs+LICE_PIXEL_B]*f4)>>16;
*a=(pin[LICE_PIXEL_A]*f1 + pin[npoffs+LICE_PIXEL_A]*f2 + pinnext[LICE_PIXEL_A]*f3 + pinnext[npoffs+LICE_PIXEL_A]*f4)>>16;
}
static inline void __LICE_LinearFilterI(int *r, int *g, int *b, int *a, const LICE_pixel_chan *pin, const LICE_pixel_chan *pinnext, unsigned int frac)
{
const unsigned int f=65536-frac;
*r=(pin[LICE_PIXEL_R]*f + pinnext[LICE_PIXEL_R]*frac)>>16;
*g=(pin[LICE_PIXEL_G]*f + pinnext[LICE_PIXEL_G]*frac)>>16;
*b=(pin[LICE_PIXEL_B]*f + pinnext[LICE_PIXEL_B]*frac)>>16;
*a=(pin[LICE_PIXEL_A]*f + pinnext[LICE_PIXEL_A]*frac)>>16;
}
static inline void __LICE_LinearFilterIPixOut(LICE_pixel_chan *out, const LICE_pixel_chan *pin, const LICE_pixel_chan *pinnext, unsigned int frac)
{
const unsigned int f=65536-frac;
out[LICE_PIXEL_R]=(pin[LICE_PIXEL_R]*f + pinnext[LICE_PIXEL_R]*frac)>>16;
out[LICE_PIXEL_G]=(pin[LICE_PIXEL_G]*f + pinnext[LICE_PIXEL_G]*frac)>>16;
out[LICE_PIXEL_B]=(pin[LICE_PIXEL_B]*f + pinnext[LICE_PIXEL_B]*frac)>>16;
out[LICE_PIXEL_A]=(pin[LICE_PIXEL_A]*f + pinnext[LICE_PIXEL_A]*frac)>>16;
}
static void inline _LICE_MakePixelClamp(LICE_pixel_chan *out, int r, int g, int b, int a)
{
#define LICE_PIX_MAKECHAN(a,b) out[a] = (b&~0xff) ? (b<0?0:255) : b;
LICE_PIX_MAKECHAN(LICE_PIXEL_B,b)
LICE_PIX_MAKECHAN(LICE_PIXEL_G,g)
LICE_PIX_MAKECHAN(LICE_PIXEL_R,r)
LICE_PIX_MAKECHAN(LICE_PIXEL_A,a)
#undef LICE_PIX_MAKECHAN
}
static void inline _LICE_MakePixelNoClamp(LICE_pixel_chan *out, LICE_pixel_chan r, LICE_pixel_chan g, LICE_pixel_chan b, LICE_pixel_chan a)
{
#define LICE_PIX_MAKECHAN(a,b) out[a] = b;
LICE_PIX_MAKECHAN(LICE_PIXEL_B,b)
LICE_PIX_MAKECHAN(LICE_PIXEL_G,g)
LICE_PIX_MAKECHAN(LICE_PIXEL_R,r)
LICE_PIX_MAKECHAN(LICE_PIXEL_A,a)
#undef LICE_PIX_MAKECHAN
}
#define HSV_P v*(256-s)/256
#define HSV_Q(hval) v*(16384-(hval)*s)/16384
#define HSV_T(hval) v*(16384-(64-(hval))*s)/16384
#define HSV_X v
extern unsigned short _LICE_RGB2HSV_invtab[256]; // 65536/idx - 1
#ifdef LICE_COMBINE_IMPLEMENT_HSV
LICE_pixel LICE_HSV2Pix(int h, int s, int v, int alpha)
#define __LICE_HSV2Pix LICE_HSV2Pix
#else
static inline LICE_pixel __LICE_HSV2Pix(int h, int s, int v, int alpha)
#endif
{
if (h<192)
{
if (h<64) return LICE_RGBA(HSV_X,HSV_T(h),HSV_P,alpha);
if (h<128) return LICE_RGBA(HSV_Q(h-64),HSV_X,HSV_P,alpha);
return LICE_RGBA(HSV_P,HSV_X,HSV_T(h-128),alpha);
}
if (h < 256) return LICE_RGBA(HSV_P,HSV_Q(h-192),HSV_X,alpha);
if (h < 320) return LICE_RGBA(HSV_T(h-256),HSV_P,HSV_X,alpha);
return LICE_RGBA(HSV_X,HSV_P,HSV_Q(h-320),alpha);
}
#ifdef LICE_COMBINE_IMPLEMENT_HSV
void LICE_HSV2RGB(int h, int s, int v, int* r, int* g, int* b)
#define __LICE_HSV2RGB LICE_HSV2RGB
#else
static inline void __LICE_HSV2RGB(int h, int s, int v, int* r, int* g, int* b)
#endif
{
if (h<192)
{
if (h<64)
{
*r = HSV_X; *g = HSV_T(h); *b = HSV_P;
}
else if (h<128)
{
*r = HSV_Q(h-64); *g = HSV_X; *b = HSV_P;
}
else
{
*r = HSV_P; *g = HSV_X; *b = HSV_T(h-128);
}
}
else
{
if (h < 256)
{
*r = HSV_P; *g = HSV_Q(h-192); *b = HSV_X;
}
else if (h < 320)
{
*r = HSV_T(h-256); *g = HSV_P; *b = HSV_X;
}
else
{
*r = HSV_X; *g = HSV_P; *b = HSV_Q(h-320);
}
}
}
#define LICE_RGB2HSV_USE_TABLE
// h = [0,384), s and v = [0,256)
#ifdef LICE_COMBINE_IMPLEMENT_HSV
void LICE_RGB2HSV(int r, int g, int b, int* h, int* s, int* v)
#define __LICE_RGB2HSV LICE_RGB2HSV
#else
static inline void __LICE_RGB2HSV(int r, int g, int b, int* h, int* s, int* v)
#endif
{
// this makes it just 3 conditional branches per call
int df,d,maxrgb;
int degoffs;
if (g > r)
{
if (g>b) // green max
{
maxrgb=g;
degoffs=128;
df = maxrgb - lice_min(b,r);
d=b-r;
}
else // blue max
{
maxrgb=b;
degoffs=256;
df = maxrgb - lice_min(g,r);
d=r-g;
}
}
else // r >= g
{
if (r > b) // red max
{
maxrgb=r;
if (g<b)
{
degoffs=383; // not technically correct, but close enough (and simplifies the rounding case -- if you want more accuracy, set to 384,
// then add a if (*h == 384) *h=0; after the *h assignment below
df = maxrgb - g;
}
else
{
degoffs=0;
df = maxrgb - b;
}
d=g-b;
}
else // blue max
{
maxrgb=b;
degoffs=256;
df = maxrgb - lice_min(g,r);
d=r-g;
}
}
*v = maxrgb;
#ifndef LICE_RGB2HSV_USE_TABLE // table mode doesnt need this check
if (!df) {
*h = *s = 0;
}
else
#endif
{
#ifdef LICE_RGB2HSV_USE_TABLE
*h = (d*((int)(_LICE_RGB2HSV_invtab[df]+1)))/1024 + degoffs;
*s = (df*((int)_LICE_RGB2HSV_invtab[maxrgb]))/256;
#else
*h = ((d*64)/df) + degoffs;
*s = (df*256)/(maxrgb+1);
#endif
}
}
//void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha) // alpha is ignored.
// generally speaking, the "a" is 0-255, and alpha is 0-256/1-256.
// Optimization when a=255 and alpha=1.0f, useful for doing a big vector drawn fill or something.
// This could be called _LICE_PutPixel but that would probably be confusing.
class _LICE_CombinePixelsClobberNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha) // alpha is ignored.
{
_LICE_MakePixelNoClamp(dest, r, g, b, a);
}
};
class _LICE_CombinePixelsClobberClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha) // alpha is ignored.
{
_LICE_MakePixelClamp(dest, r, g, b, a);
}
};
class _LICE_CombinePixelsClobberFAST
{
public:
static inline void doPixFAST(LICE_pixel *dest, LICE_pixel src) // alpha is ignored.
{
*dest = src;
}
};
class _LICE_CombinePixelsHalfMixNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
_LICE_MakePixelNoClamp(dest,
(dest[LICE_PIXEL_R]+r)>>1,
(dest[LICE_PIXEL_G]+g)>>1,
(dest[LICE_PIXEL_B]+b)>>1,
(dest[LICE_PIXEL_A]+a)>>1);
}
};
class _LICE_CombinePixelsHalfMixFAST
{
public:
static inline void doPixFAST(LICE_pixel *dest, LICE_pixel src) // src is full range
{
*dest = ((*dest>>1) &0x7f7f7f7f) + ((src>>1)&0x7f7f7f7f);
}
};
class _LICE_CombinePixelsHalfMixClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
_LICE_MakePixelClamp(dest,
(dest[LICE_PIXEL_R]+r)>>1,
(dest[LICE_PIXEL_G]+g)>>1,
(dest[LICE_PIXEL_B]+b)>>1,
(dest[LICE_PIXEL_A]+a)>>1);
}
};
class _LICE_CombinePixelsHalfMix2FAST
{
public:
static inline void doPixFAST(LICE_pixel *dest, LICE_pixel src) // src is pre-halfed and masked
{
*dest = ((*dest>>1) &0x7f7f7f7f) + src;
}
};
class _LICE_CombinePixelsQuarterMix2FAST
{
public:
static inline void doPixFAST(LICE_pixel *dest, LICE_pixel src) // src is pre-quartered and masked
{
LICE_pixel tmp = *dest;
*dest = ((tmp>>1) &0x7f7f7f7f) + ((tmp>>2) &0x3f3f3f3f) + src;
}
};
class _LICE_CombinePixelsThreeEighthMix2FAST
{
public:
static inline void doPixFAST(LICE_pixel *dest, LICE_pixel src) // src is pre-three-eighthed and masked
{
LICE_pixel tmp = *dest;
*dest = ((tmp>>1) &0x7f7f7f7f) + ((tmp>>3) &0x1f1f1f1f) + src;
}
};
class _LICE_CombinePixelsThreeQuarterMix2FAST
{
public:
static inline void doPixFAST(LICE_pixel *dest, LICE_pixel src) // src is pre-three-quartered and masked
{
*dest = ((*dest>>2) &0x3f3f3f3f) + src;
}
};
class _LICE_CombinePixelsCopyNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
const int sc=(256-alpha);
// don't check alpha=0 here, since the caller should (since alpha is usually used for static alphas)
_LICE_MakePixelNoClamp(dest,
r + ((dest[LICE_PIXEL_R]-r)*sc)/256,
g + ((dest[LICE_PIXEL_G]-g)*sc)/256,
b + ((dest[LICE_PIXEL_B]-b)*sc)/256,
a + ((dest[LICE_PIXEL_A]-a)*sc)/256);
}
};
class _LICE_CombinePixelsCopyClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
const int sc=(256-alpha);
// don't check alpha=0 here, since the caller should (since alpha is usually used for static alphas)
_LICE_MakePixelClamp(dest,
r + ((dest[LICE_PIXEL_R]-r)*sc)/256,
g + ((dest[LICE_PIXEL_G]-g)*sc)/256,
b + ((dest[LICE_PIXEL_B]-b)*sc)/256,
a + ((dest[LICE_PIXEL_A]-a)*sc)/256);
}
};
class _LICE_CombinePixelsCopySourceAlphaNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
const int sc2=(alpha*(a+1))/256;
const int sc = 256 - sc2;
_LICE_MakePixelNoClamp(dest,
r + ((dest[LICE_PIXEL_R]-r)*sc)/256,
g + ((dest[LICE_PIXEL_G]-g)*sc)/256,
b + ((dest[LICE_PIXEL_B]-b)*sc)/256,
lice_min(255,sc2 + dest[LICE_PIXEL_A]));
}
}
};
class _LICE_CombinePixelsCopySourceAlphaClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
const int sc2=(alpha*(a+1))/256;
const int sc = 256 - sc2;
_LICE_MakePixelClamp(dest,
r + ((dest[LICE_PIXEL_R]-r)*sc)/256,
g + ((dest[LICE_PIXEL_G]-g)*sc)/256,
b + ((dest[LICE_PIXEL_B]-b)*sc)/256,
sc2 + dest[LICE_PIXEL_A]);
}
}
};
class _LICE_CombinePixelsCopySourceAlphaIgnoreAlphaParmNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
if (a==255)
{
_LICE_MakePixelNoClamp(dest,r,g,b,a);
}
else
{
const int sc=(255-a);
_LICE_MakePixelNoClamp(dest,
r + ((dest[LICE_PIXEL_R]-r)*sc)/256,
g + ((dest[LICE_PIXEL_G]-g)*sc)/256,
b + ((dest[LICE_PIXEL_B]-b)*sc)/256,
lice_min(255,a + dest[LICE_PIXEL_A]));
}
}
}
};
class _LICE_CombinePixelsCopySourceAlphaIgnoreAlphaParmClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
if (a==255)
{
_LICE_MakePixelClamp(dest,r,g,b,a);
}
else
{
const int sc=(255-a);
_LICE_MakePixelClamp(dest,
r + ((dest[LICE_PIXEL_R]-r)*sc)/256,
g + ((dest[LICE_PIXEL_G]-g)*sc)/256,
b + ((dest[LICE_PIXEL_B]-b)*sc)/256,
a + dest[LICE_PIXEL_A]);
}
}
}
};
#ifndef LICE_DISABLE_BLEND_ADD
class _LICE_CombinePixelsAdd
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
// don't check alpha=0 here, since the caller should (since alpha is usually used for static alphas)
_LICE_MakePixelClamp(dest,
dest[LICE_PIXEL_R]+(r*alpha)/256,
dest[LICE_PIXEL_G]+(g*alpha)/256,
dest[LICE_PIXEL_B]+(b*alpha)/256,
dest[LICE_PIXEL_A]+(a*alpha)/256);
}
};
class _LICE_CombinePixelsAddSourceAlpha
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
alpha=(alpha*(a+1))/256;
_LICE_MakePixelClamp(dest,
dest[LICE_PIXEL_R]+(r*alpha)/256,
dest[LICE_PIXEL_G]+(g*alpha)/256,
dest[LICE_PIXEL_B]+(b*alpha)/256,
dest[LICE_PIXEL_A]+(a*alpha)/256);
}
}
};
#else // !LICE_DISABLE_BLEND_ADD
#define _LICE_CombinePixelsAddSourceAlpha _LICE_CombinePixelsCopySourceAlphaClamp
#define _LICE_CombinePixelsAdd _LICE_CombinePixelsCopyClamp
#endif
#ifndef LICE_DISABLE_BLEND_DODGE
class _LICE_CombinePixelsColorDodge
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
const int src_r = 256-r*alpha/256;
const int src_g = 256-g*alpha/256;
const int src_b = 256-b*alpha/256;
const int src_a = 256-a*alpha/256;
_LICE_MakePixelClamp(dest,
src_r > 1 ? 256*dest[LICE_PIXEL_R] / src_r : 256*dest[LICE_PIXEL_R],
src_g > 1 ? 256*dest[LICE_PIXEL_G] / src_g : 256*dest[LICE_PIXEL_G],
src_b > 1 ? 256*dest[LICE_PIXEL_B] / src_b : 256*dest[LICE_PIXEL_B],
src_a > 1 ? 256*dest[LICE_PIXEL_A] / src_a : 256*dest[LICE_PIXEL_A]);
}
};
class _LICE_CombinePixelsColorDodgeSourceAlpha
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
const int ualpha=(alpha*(a+1))/256;
const int src_r = 256-r*ualpha/256;
const int src_g = 256-g*ualpha/256;
const int src_b = 256-b*ualpha/256;
const int src_a = 256-a*ualpha/256;
_LICE_MakePixelClamp(dest,
src_r > 1 ? 256*dest[LICE_PIXEL_R] / src_r : 256*dest[LICE_PIXEL_R],
src_g > 1 ? 256*dest[LICE_PIXEL_G] / src_g : 256*dest[LICE_PIXEL_G],
src_b > 1 ? 256*dest[LICE_PIXEL_B] / src_b : 256*dest[LICE_PIXEL_B],
src_a > 1 ? 256*dest[LICE_PIXEL_A] / src_a : 256*dest[LICE_PIXEL_A]);
}
};
#else // !LICE_DISABLE_BLEND_DODGE
#define _LICE_CombinePixelsColorDodgeSourceAlpha _LICE_CombinePixelsCopySourceAlphaClamp
#define _LICE_CombinePixelsColorDodge _LICE_CombinePixelsCopyClamp
#endif
#ifndef LICE_DISABLE_BLEND_MUL
class _LICE_CombinePixelsMulNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
// we could check alpha=0 here, but the caller should (since alpha is usually used for static alphas)
const int da=(256-alpha)*256;
_LICE_MakePixelNoClamp(dest,
(dest[LICE_PIXEL_R]*(da + (r*alpha)))>>16,
(dest[LICE_PIXEL_G]*(da + (g*alpha)))>>16,
(dest[LICE_PIXEL_B]*(da + (b*alpha)))>>16,
(dest[LICE_PIXEL_A]*(da + (a*alpha)))>>16);
}
};
class _LICE_CombinePixelsMulClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
// we could check alpha=0 here, but the caller should (since alpha is usually used for static alphas)
const int da=(256-alpha)*256;
_LICE_MakePixelClamp(dest,
(dest[LICE_PIXEL_R]*(da + (r*alpha)))>>16,
(dest[LICE_PIXEL_G]*(da + (g*alpha)))>>16,
(dest[LICE_PIXEL_B]*(da + (b*alpha)))>>16,
(dest[LICE_PIXEL_A]*(da + (a*alpha)))>>16);
}
};
class _LICE_CombinePixelsMulSourceAlphaNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
const int ualpha=(alpha*(a+1))/256;
const int da=(256-ualpha)*256;
_LICE_MakePixelNoClamp(dest,
(dest[LICE_PIXEL_R]*(da + (r*ualpha)))>>16,
(dest[LICE_PIXEL_G]*(da + (g*ualpha)))>>16,
(dest[LICE_PIXEL_B]*(da + (b*ualpha)))>>16,
(dest[LICE_PIXEL_A]*(da + (a*ualpha)))>>16);
}
}
};
class _LICE_CombinePixelsMulSourceAlphaClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
const int ualpha=(alpha*(a+1))/256;
const int da=(256-ualpha)*256;
_LICE_MakePixelClamp(dest,
(dest[LICE_PIXEL_R]*(da + (r*ualpha)))>>16,
(dest[LICE_PIXEL_G]*(da + (g*ualpha)))>>16,
(dest[LICE_PIXEL_B]*(da + (b*ualpha)))>>16,
(dest[LICE_PIXEL_A]*(da + (a*ualpha)))>>16);
}
}
};
#else // !LICE_DISABLE_BLEND_MUL
#define _LICE_CombinePixelsMulSourceAlphaNoClamp _LICE_CombinePixelsCopySourceAlphaNoClamp
#define _LICE_CombinePixelsMulSourceAlphaClamp _LICE_CombinePixelsCopySourceAlphaClamp
#define _LICE_CombinePixelsMulNoClamp _LICE_CombinePixelsCopyNoClamp
#define _LICE_CombinePixelsMulClamp _LICE_CombinePixelsCopyClamp
#endif
//#define LICE_DISABLE_BLEND_OVERLAY
#ifndef LICE_DISABLE_BLEND_OVERLAY
class _LICE_CombinePixelsOverlay
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
// we could check alpha=0 here, but the caller should (since alpha is usually used for static alphas)
int destr = dest[LICE_PIXEL_R], destg = dest[LICE_PIXEL_G], destb = dest[LICE_PIXEL_B], desta = dest[LICE_PIXEL_A];
#if 0
int srcr = r*alpha, srcg = g*alpha, srcb = b*alpha, srca = a*alpha;
int da=(256-alpha)*256;
int mr = (destr*(da+srcr))/65536;
int mg = (destg*(da+srcg))/65536;
int mb = (destb*(da+srcb))/65536;
int ma = (desta*(da+srca))/65536;
int sr = 256-(65536-srcr)*(256-destr)/65536;
int sg = 256-(65536-srcg)*(256-destg)/65536;
int sb = 256-(65536-srcb)*(256-destb)/65536;
int sa = 256-(65536-srca)*(256-desta)/65536;
destr = (destr*sr+(256-destr)*mr)/256;
destg = (destg*sg+(256-destg)*mg)/256;
destb = (destb*sb+(256-destb)*mb)/256;
desta = (desta*sa+(256-desta)*ma)/256;
#else
// can produce slightly diff (+-1) results from above due to rounding
const int da=(256-alpha)*128;
const int srcr = r*alpha+da, srcg = g*alpha+da, srcb = b*alpha+da, srca = a*alpha + da;
destr = ( destr*( (destr*(32768-srcr))/256 + srcr ) ) >> 15;
destg = ( destg*( (destg*(32768-srcg))/256 + srcg ) ) >> 15;
destb = ( destb*( (destb*(32768-srcb))/256 + srcb ) ) >> 15;
desta = ( desta*( (desta*(32768-srca))/256 + srca ) ) >> 15;
#endif
_LICE_MakePixelClamp(dest, destr, destg, destb, desta);
}
};
class _LICE_CombinePixelsOverlaySourceAlpha
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
_LICE_CombinePixelsOverlay::doPix(dest, r, g, b, a, (alpha*(a+1))/256);
}
};
#else // !LICE_DISABLE_BLEND_OVERLAY
#define _LICE_CombinePixelsOverlaySourceAlpha _LICE_CombinePixelsCopySourceAlphaClamp
#define _LICE_CombinePixelsOverlay _LICE_CombinePixelsCopyClamp
#endif
//#define LICE_DISABLE_BLEND_HSVADJ
#ifndef LICE_DISABLE_BLEND_HSVADJ
class _LICE_CombinePixelsHSVAdjust
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
int h,s,v;
__LICE_RGB2HSV(dest[LICE_PIXEL_R],dest[LICE_PIXEL_G],dest[LICE_PIXEL_B],&h,&s,&v);
h+=(((r+r/2) - 192) * alpha)/256;
if (h<0)h+=384;
else if (h>=384) h-=384;
s+=((g-128)*alpha)/128;
if (s&~0xff)
{
if (s<0)s=0;
else s=255;
}
v+=((b-128)*alpha)/128;
if (v&~0xff)
{
if (v<0)v=0;
else v=255;
}
*(LICE_pixel *)dest = __LICE_HSV2Pix(h,s,v,a);
}
};
class _LICE_CombinePixelsHSVAdjustSourceAlpha
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
_LICE_CombinePixelsHSVAdjust::doPix(dest, r, g, b, a, (alpha*(a+1))/256);
}
};
#else // !LICE_DISABLE_BLEND_HSVADJ
#define _LICE_CombinePixelsHSVAdjustSourceAlpha _LICE_CombinePixelsCopySourceAlphaClamp
#define _LICE_CombinePixelsHSVAdjust _LICE_CombinePixelsCopyClamp
#endif
// note: the "clamp" parameter would generally be false, unless you're working with
// input colors that need to be clamped (i.e. if you have a r value of >255 or <0, etc.
// if your input is LICE_pixel only then use false, and it will clamp as needed depending
// on the blend mode..
//#define __LICE__ACTION(comb) templateclass<comb>::function(parameters)
//__LICE_ACTION_SRCALPHA(mode,alpha,clamp);
//#undef __LICE__ACTION
// use this for paths that support LICE_BLIT_USE_ALPHA (source-alpha combining), but
// otherwise have constant alpha
#define __LICE_ACTION_SRCALPHA(mode,ia,clamp) \
if ((ia)!=0) switch ((mode)&(LICE_BLIT_MODE_MASK|LICE_BLIT_USE_ALPHA)) { \
case LICE_BLIT_MODE_COPY: if ((ia)>0) { \
if (clamp) { \
if ((ia)==256) { __LICE__ACTION(_LICE_CombinePixelsClobberClamp); } \
else { __LICE__ACTION(_LICE_CombinePixelsCopyClamp); } \
} else { \
if ((ia)==256) { __LICE__ACTION(_LICE_CombinePixelsClobberNoClamp); } \
else { __LICE__ACTION(_LICE_CombinePixelsCopyNoClamp); } \
} \
} \
break; \
case LICE_BLIT_MODE_ADD: __LICE__ACTION(_LICE_CombinePixelsAdd); break; \
case LICE_BLIT_MODE_DODGE: __LICE__ACTION(_LICE_CombinePixelsColorDodge); break; \
case LICE_BLIT_MODE_MUL: \
if (clamp) { __LICE__ACTION(_LICE_CombinePixelsMulClamp); } \
else { __LICE__ACTION(_LICE_CombinePixelsMulNoClamp); } \
break; \
case LICE_BLIT_MODE_OVERLAY: __LICE__ACTION(_LICE_CombinePixelsOverlay); break; \
case LICE_BLIT_MODE_HSVADJ: __LICE__ACTION(_LICE_CombinePixelsHSVAdjust); break; \
case LICE_BLIT_MODE_COPY|LICE_BLIT_USE_ALPHA: \
if (clamp) { \
if ((ia)==256) { __LICE__ACTION(_LICE_CombinePixelsCopySourceAlphaIgnoreAlphaParmClamp);} \
else { __LICE__ACTION(_LICE_CombinePixelsCopySourceAlphaClamp); } \
} else { \
if ((ia)==256) { __LICE__ACTION(_LICE_CombinePixelsCopySourceAlphaIgnoreAlphaParmNoClamp); } \
else { __LICE__ACTION(_LICE_CombinePixelsCopySourceAlphaNoClamp); } \
} \
break; \
case LICE_BLIT_MODE_ADD|LICE_BLIT_USE_ALPHA: \
__LICE__ACTION(_LICE_CombinePixelsAddSourceAlpha); \
break; \
case LICE_BLIT_MODE_DODGE|LICE_BLIT_USE_ALPHA: \
__LICE__ACTION(_LICE_CombinePixelsColorDodgeSourceAlpha); \
break; \
case LICE_BLIT_MODE_MUL|LICE_BLIT_USE_ALPHA: \
if (clamp) { __LICE__ACTION(_LICE_CombinePixelsMulSourceAlphaClamp); } \
else { __LICE__ACTION(_LICE_CombinePixelsMulSourceAlphaNoClamp); } \
break; \
case LICE_BLIT_MODE_OVERLAY|LICE_BLIT_USE_ALPHA: \
__LICE__ACTION(_LICE_CombinePixelsOverlaySourceAlpha); \
break; \
case LICE_BLIT_MODE_HSVADJ|LICE_BLIT_USE_ALPHA: \
__LICE__ACTION(_LICE_CombinePixelsHSVAdjustSourceAlpha); \
break; \
}
// use this for paths that can have per pixel alpha, but calculate it themselves
#define __LICE_ACTION_NOSRCALPHA(mode, ia,clamp) \
if ((ia)!=0) switch ((mode)&LICE_BLIT_MODE_MASK) { \
case LICE_BLIT_MODE_COPY: if ((ia)>0) { if (clamp) { __LICE__ACTION(_LICE_CombinePixelsCopyClamp); } else { __LICE__ACTION(_LICE_CombinePixelsCopyNoClamp); } } break; \
case LICE_BLIT_MODE_ADD: __LICE__ACTION(_LICE_CombinePixelsAdd); break; \
case LICE_BLIT_MODE_DODGE: __LICE__ACTION(_LICE_CombinePixelsColorDodge); break; \
case LICE_BLIT_MODE_MUL: if (clamp) { __LICE__ACTION(_LICE_CombinePixelsMulClamp); } else { __LICE__ACTION(_LICE_CombinePixelsMulNoClamp); } break; \
case LICE_BLIT_MODE_OVERLAY: __LICE__ACTION(_LICE_CombinePixelsOverlay); break; \
case LICE_BLIT_MODE_HSVADJ: __LICE__ACTION(_LICE_CombinePixelsHSVAdjust); break; \
}
// For drawing where there is constant alpha and no per-pixel alpha.
#define __LICE_ACTION_CONSTANTALPHA(mode,ia,clamp) \
if ((ia)!=0) switch ((mode)&LICE_BLIT_MODE_MASK) { \
case LICE_BLIT_MODE_COPY: \
if ((ia)==256) { if (clamp) { __LICE__ACTION(_LICE_CombinePixelsClobberClamp); } else { __LICE__ACTION(_LICE_CombinePixelsClobberNoClamp); } } \
else if ((ia)==128) { if (clamp) { __LICE__ACTION(_LICE_CombinePixelsHalfMixClamp); } else { __LICE__ACTION(_LICE_CombinePixelsHalfMixNoClamp); } } \
else if ((ia)>0) { if (clamp) { __LICE__ACTION(_LICE_CombinePixelsCopyClamp); } else { __LICE__ACTION(_LICE_CombinePixelsCopyNoClamp); } } \
break; \
case LICE_BLIT_MODE_ADD: __LICE__ACTION(_LICE_CombinePixelsAdd); break; \
case LICE_BLIT_MODE_DODGE: __LICE__ACTION(_LICE_CombinePixelsColorDodge); break; \
case LICE_BLIT_MODE_MUL: if (clamp) { __LICE__ACTION(_LICE_CombinePixelsMulClamp); } else { __LICE__ACTION(_LICE_CombinePixelsMulNoClamp); } break; \
case LICE_BLIT_MODE_OVERLAY: __LICE__ACTION(_LICE_CombinePixelsOverlay); break; \
case LICE_BLIT_MODE_HSVADJ: __LICE__ACTION(_LICE_CombinePixelsHSVAdjust); break; \
}
typedef void (*LICE_COMBINEFUNC)(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha);
static void WDL_STATICFUNC_UNUSED __LICE_SC_INTERNAL(int &x, int __sc) {
const WDL_INT64 t = (((WDL_INT64) x*(__sc))/256);
x = (int) wdl_clamp(t, -WDL_INT64_CONST(0x80000000), WDL_INT64_CONST(0x7fffffff));
}
static void __LICE_SCU_INTERNAL(int &x, int __sc) {
const WDL_UINT64 t = (((WDL_UINT64) x*(__sc))>>8);
x = (unsigned int) wdl_min(t, WDL_UINT64_CONST(0xffffffff));
}
#if defined(_WIN32) || (defined(__APPLE__) && !defined(__LP64__))
static void WDL_STATICFUNC_UNUSED __LICE_SC_INTERNAL(LONG &x, int __sc) {
const WDL_INT64 t = (((WDL_INT64) x*(__sc))/256);
x = (LONG) wdl_clamp(t, -WDL_INT64_CONST(0x80000000), WDL_INT64_CONST(0x7fffffff));
}
#endif
static void WDL_STATICFUNC_UNUSED __LICE_SC_INTERNAL(float &x, int __sc) { x = (float) (((double)x * __sc) / 256.0); }
static void WDL_STATICFUNC_UNUSED __LICE_SC_INTERNAL(double &x, int __sc) { x = (x * __sc) / 256.0; }
#define __LICE_SC(x) __LICE_SC_INTERNAL(x,__sc)
#define __LICE_SCU(x) __LICE_SCU_INTERNAL(x,__sc)
#endif // _LICE_COMBINE_H_

View File

@@ -0,0 +1,164 @@
#ifndef _LICE_EXTENDED_
#define _LICE_EXTENDED_
#include "lice.h"
#define DISABLE_LICE_EXTENSIONS
// stuff to pass to LICE_IBitmap::Extended
enum // IDs
{
LICE_EXT_SUPPORTS_ID, // data = ID, returns 1 if that extension ID is supported
LICE_EXT_CLEAR_ACCEL,
LICE_EXT_LINE_ACCEL,
LICE_EXT_FILLRECT_ACCEL,
LICE_EXT_DRAWCBEZIER_ACCEL,
LICE_EXT_DRAWGLYPH_ACCEL,
LICE_EXT_BLIT_ACCEL,
LICE_EXT_SCALEDBLIT_ACCEL,
LICE_EXT_GETFBOTEX_ACCEL, // if the bitmap is implemented as an openGL framebuffer object, get its texture backing store
LICE_EXT_DASHEDLINE_ACCEL,
LICE_EXT_GETPIXEL_ACCEL,
LICE_EXT_PUTPIXEL_ACCEL,
LICE_EXT_SETCLIP, // data == 0 to clear clip
LICE_EXT_WINDOW_BLIT,
LICE_EXT_FORGET, // optimizations can sometimes happen if a bitmap can be told it doesn't need to retain data after it's accessed
LICE_EXT_DRAWTRIANGLE_ACCEL,
};
struct LICE_Ext_Line_acceldata
{
float x1, y1, x2, y2;
LICE_pixel color;
float alpha;
int mode;
bool aa;
LICE_Ext_Line_acceldata(float _x1, float _y1, float _x2, float _y2, LICE_pixel _color, float _alpha, int _mode, bool _aa)
: x1(_x1), y1(_y1), x2(_x2), y2(_y2), color(_color), alpha(_alpha), mode(_mode), aa(_aa) {}
};
struct LICE_Ext_FillRect_acceldata
{
int x, y, w, h;
LICE_pixel color;
float alpha;
int mode;
LICE_Ext_FillRect_acceldata(int _x, int _y, int _w, int _h, LICE_pixel _color, float _alpha, int _mode)
: x(_x), y(_y), w(_w), h(_h), color(_color), alpha(_alpha), mode(_mode) {}
};
struct LICE_Ext_DrawCBezier_acceldata
{
float xstart, ystart, xctl1, yctl1, xctl2, yctl2, xend, yend;
LICE_pixel color;
float alpha;
int mode;
bool aa;
LICE_Ext_DrawCBezier_acceldata(float _xstart, float _ystart, float _xctl1, float _yctl1, float _xctl2, float _yctl2, float _xend, float _yend,
LICE_pixel _color, float _alpha, int _mode, bool _aa)
: xstart(_xstart), ystart(_ystart), xctl1(_xctl1), yctl1(_yctl1), xctl2(_xctl2), yctl2(_yctl2), xend(_xend), yend(_yend),
color(_color), alpha(_alpha), mode(_mode), aa(_aa) {}
};
struct LICE_Ext_DrawGlyph_acceldata
{
int x;
int y;
LICE_pixel color;
const LICE_pixel_chan* alphas;
int glyph_w, glyph_h;
float alpha;
int mode;
LICE_Ext_DrawGlyph_acceldata(int _x, int _y, LICE_pixel _color, LICE_pixel_chan* _alphas, int _glyph_w, int _glyph_h, float _alpha, int _mode)
: x(_x), y(_y), color(_color), alphas(_alphas), glyph_w(_glyph_w), glyph_h(_glyph_h), alpha(_alpha), mode(_mode) {}
};
struct LICE_Ext_Blit_acceldata
{
LICE_IBitmap* src;
int dstx, dsty, srcx, srcy, srcw, srch;
float alpha;
int mode;
LICE_Ext_Blit_acceldata(LICE_IBitmap* _src, int _dstx, int _dsty, int _srcx, int _srcy, int _srcw, int _srch, float _alpha, int _mode)
: src(_src), dstx(_dstx), dsty(_dsty), srcx(_srcx), srcy(_srcy), srcw(_srcw), srch(_srch), alpha(_alpha), mode(_mode) {}
};
struct LICE_Ext_ScaledBlit_acceldata
{
LICE_IBitmap* src;
int dstx, dsty, dstw, dsth;
float srcx, srcy, srcw, srch;
float alpha;
int mode;
LICE_Ext_ScaledBlit_acceldata(LICE_IBitmap* _src, int _dstx, int _dsty, int _dstw, int _dsth, float _srcx, float _srcy, float _srcw, float _srch, float _alpha, int _mode)
: src(_src), dstx(_dstx), dsty(_dsty), dstw(_dstw), dsth(_dsth), srcx(_srcx), srcy(_srcy), srcw(_srcw), srch(_srch), alpha(_alpha), mode(_mode) {}
};
struct LICE_Ext_DashedLine_acceldata
{
float x1, y1, x2, y2;
int pxon, pxoff;
LICE_pixel color;
float alpha;
int mode;
bool aa;
LICE_Ext_DashedLine_acceldata(float _x1, float _y1, float _x2, float _y2, int _pxon, int _pxoff, LICE_pixel _color, float _alpha, int _mode, bool _aa)
: x1(_x1), y1(_y1), x2(_x2), y2(_y2), pxon(_pxon), pxoff(_pxoff), color(_color), alpha(_alpha), mode(_mode), aa(_aa) {}
};
struct LICE_Ext_GetPixel_acceldata
{
int x, y;
LICE_pixel px; // return
LICE_Ext_GetPixel_acceldata(int _x, int _y)
: x(_x), y(_y), px(0) {}
};
struct LICE_Ext_PutPixel_acceldata
{
int x, y;
LICE_pixel color;
float alpha;
int mode;
LICE_Ext_PutPixel_acceldata(int _x, int _y, LICE_pixel _color, float _alpha, int _mode)
: x(_x), y(_y), color(_color), alpha(_alpha), mode(_mode) {}
};
struct LICE_Ext_SetClip_data
{
int x, y, w, h;
LICE_Ext_SetClip_data(int _x, int _y, int _w, int _h)
: x(_x), y(_y), w(_w), h(_h) {}
};
class pl_Mat;
struct LICE_Ext_DrawTriangle_acceldata
{
pl_Mat *mat; // will need to include plush.h to access this
double VertexShades[3][3]; // for solid element
float scrx[3], scry[3], scrz[3]; // scrz = 1/Zdist
double mapping_coords[2][3][2]; // [texture or texture2][vertex][uv]
};
struct LICE_Ext_WindowBlit_data
{
HWND hwnd;
int destx, desty, srcx, srcy, w, h;
LICE_Ext_WindowBlit_data(HWND _hwnd, int _destx, int _desty, int _srcx, int _srcy, int _w, int _h)
: hwnd(_hwnd), destx(_destx), desty(_desty), srcx(_srcx), srcy(_srcy), w(_w), h(_h) {}
};
#endif

View File

@@ -0,0 +1,462 @@
/*
Cockos WDL - LICE - Lightweight Image Compositing Engine
Copyright (C) 2007 and later, Cockos Incorporated
File: lice_gif.cpp (GIF loading for LICE)
See lice.h for license and other information
*/
#include "lice.h"
#include "../heapbuf.h"
#include "../fileread.h"
#include <stdio.h>
extern "C" {
#include "../giflib/gif_lib.h"
int _GifError;
};
static void applyGifFrameToBitmap(LICE_IBitmap *bmp, GifFileType *fp, int transparent_pix, bool clear)
{
const int width=fp->Image.Width,height=fp->Image.Height;
LICE_pixel cmap[256];
GifPixelType _linebuf[2048];
GifPixelType *linebuf=width > 2048 ? (GifPixelType*)malloc(width*sizeof(GifPixelType)) : _linebuf;
int y;
if (bmp)
{
y=0;
if (fp->Image.ColorMap && fp->Image.ColorMap->Colors) for (;y<256 && y < fp->Image.ColorMap->ColorCount;y++)
{
GifColorType *ct=fp->Image.ColorMap->Colors+y;
cmap[y]=LICE_RGBA(ct->Red,ct->Green,ct->Blue,255);
}
if (fp->SColorMap && fp->SColorMap->Colors) for (;y<256 && y < fp->SColorMap->ColorCount;y++)
{
GifColorType *ct=fp->SColorMap->Colors+y;
cmap[y]=LICE_RGBA(ct->Red,ct->Green,ct->Blue,255);
}
for (;y<256;y++) cmap[y]=0;
if (clear)
{
LICE_pixel col = 0;
if (fp->SColorMap && fp->SColorMap->Colors && fp->SBackGroundColor >= 0 && fp->SBackGroundColor < fp->SColorMap->ColorCount)
{
GifColorType *ct=fp->SColorMap->Colors+fp->SBackGroundColor;
col = LICE_RGBA(ct->Red,ct->Green,ct->Blue,0);
}
else if (fp->SBackGroundColor>=0 && fp->SBackGroundColor<256)
{
col = cmap[fp->SBackGroundColor] & LICE_RGBA(255,255,255,0);
}
LICE_Clear(bmp,col);
}
}
const int bmp_h = bmp ? bmp->getHeight() : 0;
const int bmp_w = bmp ? bmp->getWidth() : 0;
LICE_pixel *bmp_ptr = bmp ? bmp->getBits() : NULL;
int bmp_span = bmp ? bmp->getRowSpan() : 0;
if (bmp && bmp->isFlipped() )
{
bmp_ptr += (bmp_h-1)*bmp_span;
bmp_span = -bmp_span;
}
const int xpos = fp->Image.Left;
int skip=0;
int use_width = width;
if (xpos < 0) skip = -xpos;
if (use_width > bmp_w - xpos) use_width = bmp_w - xpos;
int ystate = 0, ypass=0;
for (y=0; y < height; y ++)
{
if (DGifGetLine(fp,linebuf,width)==GIF_ERROR) break;
int ypos;
if (fp->Image.Interlace)
{
if (ypass == 0)
{
ypos = ystate++ * 8;
if (ypos >= height) { ypass++; ystate=0; }
}
if (ypass == 1)
{
ypos = ystate++ * 8 + 4;
if (ypos >= height) { ypass++; ystate=0; }
}
if (ypass == 2)
{
ypos = ystate++ * 4 + 2;
if (ypos >= height) { ypass++; ystate=0; }
}
if (ypass==3) ypos = ystate++ * 2 + 1;
}
else
{
ypos = ystate++;
}
ypos += fp->Image.Top;
if (ypos < 0 || ypos >= bmp_h) continue;
LICE_pixel *p = bmp_ptr + ypos*bmp_span + xpos;
int x;
for (x = skip; x < use_width; x ++)
{
const int a = (int) linebuf[x];
if (a != transparent_pix) p[x]=cmap[a];
}
}
if (linebuf != _linebuf) free(linebuf);
}
static int readfunc_fh(GifFileType *fh, GifByteType *buf, int sz)
{
return ((WDL_FileRead*)fh->UserData)->Read(buf,sz);
}
LICE_IBitmap *LICE_LoadGIF(const char *filename, LICE_IBitmap *bmp, int *nframes)
{
WDL_FileRead fpp(filename,0,65536);
if (nframes) *nframes=0;
if (!fpp.IsOpen()) return 0;
GifFileType *fp=DGifOpen(&fpp, readfunc_fh);
if (!fp) return 0;
int transparent_pix = -1;
bool had_image = false;
bool had_delay = false;
bool need_new_frame = false;
const bool own_bmp = !bmp;
GifRecordType RecordType;
GifByteType *Extension;
int ExtCode;
LICE_WrapperBitmap workbm(NULL,0,0,0,false);
WDL_HeapBuf workbuf(128*1024);
do
{
if (DGifGetRecordType(fp, &RecordType) == GIF_ERROR) break;
switch (RecordType)
{
case IMAGE_DESC_RECORD_TYPE:
if (DGifGetImageDesc(fp) == GIF_ERROR)
{
RecordType = TERMINATE_RECORD_TYPE;
break;
}
if (!bmp) bmp=new WDL_NEW LICE_MemBitmap;
if (!had_image || (nframes && need_new_frame))
{
if (had_image)
{
// implies nframes
const int ht = (*nframes+1) * (int)fp->SHeight;
workbm.m_h = ht;
workbm.m_w = (int)fp->SWidth;
workbm.m_span = (workbm.m_w+3)&~3;
workbm.m_buf = (LICE_pixel *) workbuf.ResizeOK(ht * sizeof(LICE_pixel) * workbm.m_span);
if (!workbm.m_buf)
{
RecordType = TERMINATE_RECORD_TYPE;
break;
}
}
else
{
if (bmp) bmp->resize(fp->SWidth,fp->SHeight);
if (!bmp || bmp->getWidth() != (int)fp->SWidth || bmp->getHeight() != (int)fp->SHeight)
{
RecordType = TERMINATE_RECORD_TYPE;
break;
}
}
if (nframes)
{
if (*nframes > 0)
{
if (*nframes == 1)
LICE_Blit(&workbm,bmp,0,0,0,0,bmp->getWidth(),bmp->getHeight(),1.0,LICE_BLIT_MODE_COPY);
LICE_Blit(&workbm,&workbm,0,workbm.getHeight()-(int)fp->SHeight,0,
workbm.getHeight()-(int)fp->SHeight*2, workbm.getWidth(), (int)fp->SHeight,1.0f,LICE_BLIT_MODE_COPY);
}
*nframes += 1;
}
}
if (nframes)
{
LICE_SubBitmap tmp(&workbm, 0,workbm.getHeight() - (int) fp->SHeight, workbm.getWidth(), (int)fp->SHeight);
applyGifFrameToBitmap(&tmp,fp,transparent_pix,!had_image);
}
else
applyGifFrameToBitmap(bmp,fp,transparent_pix,!had_image);
had_image = true;
need_new_frame = false;
transparent_pix = -1;
if (had_delay)
{
if (!nframes)
{
RecordType = TERMINATE_RECORD_TYPE; // finish up if first frame is finished
}
else
{
need_new_frame = true;
}
had_delay = false;
}
break;
case EXTENSION_RECORD_TYPE:
if (DGifGetExtension(fp, &ExtCode, &Extension) == GIF_ERROR)
{
RecordType = TERMINATE_RECORD_TYPE;
}
else
{
while (Extension != NULL)
{
if (ExtCode == 0xF9 && *Extension >= 4)
{
transparent_pix = -1;
if (Extension[1]&1)
{
transparent_pix = Extension[4];
}
if (Extension[2] || Extension[3]) had_delay=true;
}
if (DGifGetExtensionNext(fp, &Extension) == GIF_ERROR)
{
RecordType = TERMINATE_RECORD_TYPE;
break;
}
}
}
break;
case TERMINATE_RECORD_TYPE:
break;
default: /* Should be traps by DGifGetRecordType. */
break;
}
}
while (RecordType != TERMINATE_RECORD_TYPE);
DGifCloseFile(fp);
if (had_image)
{
if (workbm.getWidth()) LICE_Copy(bmp,&workbm);
return bmp;
}
if (own_bmp) delete bmp;
return NULL;
}
class LICE_GIFLoader
{
public:
_LICE_ImageLoader_rec rec;
LICE_GIFLoader()
{
rec.loadfunc = loadfunc;
rec.get_extlist = get_extlist;
rec._next = LICE_ImageLoader_list;
LICE_ImageLoader_list = &rec;
}
static LICE_IBitmap *loadfunc(const char *filename, bool checkFileName, LICE_IBitmap *bmpbase)
{
if (checkFileName)
{
const char *p=filename;
while (*p)p++;
while (p>filename && *p != '\\' && *p != '/' && *p != '.') p--;
if (stricmp(p,".gif")) return 0;
}
return LICE_LoadGIF(filename,bmpbase,NULL);
}
static const char *get_extlist()
{
return "GIF files (*.GIF)\0*.GIF\0";
}
};
LICE_GIFLoader LICE_gifldr;
struct lice_gif_read_ctx
{
WDL_FileRead *fh;
GifFileType *gif;
int msecpos;
int state;
WDL_FILEREAD_POSTYPE ipos;
};
void *LICE_GIF_LoadEx(const char *filename)
{
WDL_FileRead *fpp = new WDL_FileRead(filename,0,32768);
if (!fpp->IsOpen())
{
delete fpp;
return 0;
}
GifFileType *gif=DGifOpen(fpp, readfunc_fh);
if (!gif)
{
delete fpp;
return 0;
}
lice_gif_read_ctx *ret = (lice_gif_read_ctx*)calloc(sizeof(lice_gif_read_ctx), 1);
if (!ret)
{
DGifCloseFile(gif);
delete fpp;
return NULL;
}
ret->fh = fpp;
ret->gif = gif;
ret->msecpos = 0;
ret->state = 0;
ret->ipos = fpp->GetPosition();
return ret;
}
void LICE_GIF_Close(void *handle)
{
lice_gif_read_ctx *h = (lice_gif_read_ctx*)handle;
if (h)
{
DGifCloseFile(h->gif);
delete h->fh;
free(h);
}
}
void LICE_GIF_Rewind(void *handle)
{
lice_gif_read_ctx *h = (lice_gif_read_ctx*)handle;
if (h)
{
h->state = 0;
h->msecpos = 0;
h->fh->SetPosition(h->ipos);
// todo: flush giflib too
}
}
unsigned int LICE_GIF_GetFilePos(void *handle)
{
// only used for accounting at the moment, so meh
lice_gif_read_ctx *h = (lice_gif_read_ctx*)handle;
if (h && h->fh)
{
return (unsigned int) h->fh->GetPosition();
}
return 0;
}
int LICE_GIF_UpdateFrame(void *handle, LICE_IBitmap *bm)
{
lice_gif_read_ctx *h = (lice_gif_read_ctx*)handle;
if (!h||h->state<0) return -2;
GifFileType *fp = h->gif;
if (bm)
{
bm->resize(fp->SWidth, fp->SHeight);
if (bm->getWidth() != (int)fp->SWidth || bm->getHeight() != (int)fp->SHeight) return -3;
}
int has_delay = 0;
int transparent_pix = -1;
GifRecordType RecordType;
GifByteType *Extension;
int ExtCode;
do
{
if (DGifGetRecordType(fp, &RecordType) == GIF_ERROR) return h->state = -5;
switch (RecordType)
{
case IMAGE_DESC_RECORD_TYPE:
if (DGifGetImageDesc(fp) == GIF_ERROR) return h->state = -4;
applyGifFrameToBitmap(bm,fp,transparent_pix,!h->state);
h->state += 1;
h->msecpos += has_delay*10;
return has_delay*10;
case EXTENSION_RECORD_TYPE:
if (DGifGetExtension(fp, &ExtCode, &Extension) == GIF_ERROR)
{
return h->state = -9;
}
else
{
while (Extension != NULL)
{
if (ExtCode == 0xF9 && *Extension >= 4)
{
transparent_pix = -1;
if (Extension[1]&1)
{
transparent_pix = Extension[4];
}
has_delay = ((int)Extension[3] << 8) + Extension[2];
if (has_delay == 1) has_delay = 10; // https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist
}
if (DGifGetExtensionNext(fp, &Extension) == GIF_ERROR) return h->state = -8;
}
}
break;
case TERMINATE_RECORD_TYPE:
break;
default: /* Should be traps by DGifGetRecordType. */
break;
}
}
while (RecordType != TERMINATE_RECORD_TYPE);
return h->state = -10;
}

View File

@@ -0,0 +1,491 @@
/*
Cockos WDL - LICE - Lightweight Image Compositing Engine
Copyright (C) 2007 and later, Cockos Incorporated
File: lice_gif.cpp (GIF loading for LICE)
See lice.h for license and other information
*/
#include "lice.h"
#include <stdio.h>
#include "../wdltypes.h"
#include "../filewrite.h"
extern "C" {
#include "../giflib/gif_lib.h"
//int _GifError;
};
struct liceGifWriteRec
{
GifFileType *f;
WDL_FileWrite *fh;
ColorMapObject *cmap;
GifPixelType *linebuf;
LICE_IBitmap *prevframe; // used when multiframe, transalpha<0
void *last_octree;
LICE_pixel last_palette[256];
unsigned char from15to8bit[32][32][32];//r,g,b
int transalpha;
int w,h;
bool append;
bool dither;
bool has_had_frame;
bool has_global_cmap;
bool has_from15to8bit; // set when last_octree has been generated into from15to8bit
};
static inline GifPixelType QuantPixel(LICE_pixel p, liceGifWriteRec *wr)
{
return wr->from15to8bit[LICE_GETR(p)>>3][LICE_GETG(p)>>3][LICE_GETB(p)>>3];
}
static int generate_palette_from_octree(void *ww, void *octree, int numcolors)
{
liceGifWriteRec *wr = (liceGifWriteRec *)ww;
if (!octree||!ww||numcolors>256) return 0;
ColorMapObject *cmap = wr->cmap;
int palette_sz=0;
// store palette
{
LICE_pixel* palette=wr->last_palette;
palette_sz = LICE_ExtractOctreePalette(octree, palette);
int i;
for (i = 0; i < palette_sz; ++i)
{
cmap->Colors[i].Red = LICE_GETR(palette[i]);
cmap->Colors[i].Green = LICE_GETG(palette[i]);
cmap->Colors[i].Blue = LICE_GETB(palette[i]);
}
for (i = palette_sz; i < numcolors; ++i)
{
cmap->Colors[i].Red = cmap->Colors[i].Green = cmap->Colors[i].Blue = 0;
}
}
wr->has_from15to8bit = false;
wr->has_global_cmap=true;
return palette_sz;
}
static void generate15to8(void *ww, void *octree)
{
liceGifWriteRec *wr = (liceGifWriteRec *)ww;
if (!octree||!ww) return;
// map palette to 16 bit
unsigned char r,g,b;
for(r=0;r<32;r++)
{
unsigned char cr = r<<3;
for (g=0;g<32;g++)
{
unsigned char cg = g<<3;
for (b=0;b<32;b++)
{
unsigned char cb = b<<3;
LICE_pixel col = LICE_RGBA(cr,cg,cb,0);
wr->from15to8bit[r][g][b] = LICE_FindInOctree(octree, col);
}
}
}
wr->has_from15to8bit=true;
}
int LICE_SetGIFColorMapFromOctree(void *ww, void *octree, int numcolors)
{
const int rv = generate_palette_from_octree(ww,octree,numcolors);
generate15to8(ww,octree);
return rv;
}
unsigned int LICE_WriteGIFGetSize(void *handle)
{
if (handle)
{
liceGifWriteRec *wr = (liceGifWriteRec*)handle;
if (wr->fh) return (unsigned int) ((WDL_FileWrite *)wr->fh)->GetPosition();
}
return 0;
}
bool LICE_WriteGIFFrame(void *handle, LICE_IBitmap *frame, int xpos, int ypos, bool perImageColorMap, int frame_delay, int nreps)
{
liceGifWriteRec *wr = (liceGifWriteRec*)handle;
if (!wr) return false;
bool isFirst=false;
if (!wr->has_had_frame)
{
wr->has_had_frame=true;
isFirst=true;
if (!perImageColorMap && !wr->has_global_cmap)
{
const int ccnt = 256 - (wr->transalpha?1:0);
void* octree = wr->last_octree;
if (!octree) wr->last_octree = octree = LICE_CreateOctree(ccnt);
else LICE_ResetOctree(octree,ccnt);
if (octree)
{
LICE_BuildOctree(octree, frame);
// sets has_global_cmap
int pcnt = generate_palette_from_octree(wr, octree, ccnt);
if (pcnt < 256 && wr->transalpha) pcnt++;
int nb = 1;
while (nb < 8 && (1<<nb) < pcnt) nb++;
wr->cmap->ColorCount = 1<<nb;
wr->cmap->BitsPerPixel=nb;
}
}
if (!wr->append) EGifPutScreenDesc(wr->f,wr->w,wr->h,8,0,wr->has_global_cmap ? wr->cmap : 0);
}
int usew=frame->getWidth(), useh=frame->getHeight();
if (xpos+usew > wr->w) usew = wr->w-xpos;
if (ypos+useh > wr->h) useh = wr->h-ypos;
if (usew<1||useh<1) return false;
int pixcnt=usew*useh;
const int trans_chan_mask = wr->transalpha&0xff; // -1 means 0xff by default, user can change this accordingly
const LICE_pixel trans_mask = LICE_RGBA(trans_chan_mask,trans_chan_mask,trans_chan_mask,0);
const bool advanced_trans_stats = !!(wr->transalpha&0x100);
if (perImageColorMap && !wr->has_global_cmap)
{
const int ccnt = 256 - (wr->transalpha?1:0);
void* octree = wr->last_octree;
if (!octree) wr->last_octree = octree = LICE_CreateOctree(ccnt);
else LICE_ResetOctree(octree,ccnt);
if (octree)
{
if ((!isFirst || frame_delay) && wr->transalpha<0 && wr->prevframe)
{
LICE_SubBitmap tmpprev(wr->prevframe, xpos, ypos, usew, useh);
int pc=LICE_BuildOctreeForDiff(octree,frame,&tmpprev,trans_mask);
if (!advanced_trans_stats) pixcnt = pc;
}
else if (wr->transalpha>0)
pixcnt=LICE_BuildOctreeForAlpha(octree, frame,wr->transalpha&0xff);
else
LICE_BuildOctree(octree, frame);
// sets has_global_cmap (clear below)
int pcnt = generate_palette_from_octree(wr, octree, ccnt);
wr->has_global_cmap=false;
if (pcnt < 256 && wr->transalpha) pcnt++;
int nb = 1;
while (nb < 8 && (1<<nb) < pcnt) nb++;
wr->cmap->ColorCount = 1<<nb;
wr->cmap->BitsPerPixel=nb;
}
}
if (!wr->has_from15to8bit && pixcnt > 40000 && wr->last_octree)
{
generate15to8(wr,wr->last_octree);
}
const unsigned char transparent_pix = wr->cmap->ColorCount-1;
unsigned char gce[4] = { 0, };
if (wr->transalpha)
{
gce[0] |= 1;
gce[3] = transparent_pix;
}
int a = frame_delay/10;
if(a<2&&frame_delay)a=2; // https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist
else if (a>60000) a=60000;
gce[1]=(a)&255;
gce[2]=(a)>>8;
if (isFirst && frame_delay && nreps!=1 && !wr->append)
{
int nr = nreps > 1 && nreps <= 65536 ? nreps-1 : 0;
unsigned char ext[]={0xB, 'N','E','T','S','C','A','P','E','2','.','0',3,1,(unsigned char) (nr&0xff), (unsigned char) ((nr>>8)&0xff)};
EGifPutExtension(wr->f,0xFF, sizeof(ext),ext);
}
if (gce[0]||gce[1]||gce[2])
EGifPutExtension(wr->f, 0xF9, sizeof(gce), gce);
EGifPutImageDesc(wr->f, xpos, ypos, usew,useh, 0, wr->has_global_cmap ? NULL : wr->cmap);
GifPixelType *linebuf = wr->linebuf;
int y;
void *use_octree = wr->has_from15to8bit ? NULL : wr->last_octree;
if ((!isFirst || frame_delay) && wr->transalpha<0)
{
bool ignFr=false;
if (!wr->prevframe)
{
ignFr=true;
wr->prevframe = new WDL_NEW LICE_MemBitmap(wr->w,wr->h);
LICE_Clear(wr->prevframe,0);
}
LICE_SubBitmap tmp(wr->prevframe,xpos,ypos,usew,useh);
LICE_pixel last_pixel_rgb=0;
GifPixelType last_pixel_idx=transparent_pix;
int pix_stats[256];
if (advanced_trans_stats) memset(pix_stats,0,sizeof(pix_stats));
pix_stats[transparent_pix] = -8;
for(y=0;y<useh;y++)
{
int rdy=y,rdy2=y;
if (frame->isFlipped()) rdy = frame->getHeight()-1-y;
if (tmp.isFlipped()) rdy2 = tmp.getHeight()-1-y;
const LICE_pixel *in = frame->getBits() + rdy*frame->getRowSpan();
const LICE_pixel *in2 = tmp.getBits() + rdy2*tmp.getRowSpan();
int x;
if (advanced_trans_stats)
{
if (use_octree) for(x=0;x<usew;x++)
{
const LICE_pixel p = in[x]&trans_mask;
if (last_pixel_idx == transparent_pix || last_pixel_rgb!=p)
{
if (ignFr || p != (in2[x]&trans_mask)) last_pixel_idx = LICE_FindInOctree(use_octree,p);
else
{
const GifPixelType np = LICE_FindInOctree(use_octree,p);
if (p != (wr->last_palette[np]&trans_mask) || pix_stats[transparent_pix] > pix_stats[np])
last_pixel_idx = transparent_pix;
else
last_pixel_idx = np;
}
}
linebuf[x] = last_pixel_idx;
pix_stats[last_pixel_idx]++;
last_pixel_rgb = p;
}
else for(x=0;x<usew;x++)
{
const LICE_pixel p = in[x]&trans_mask;
if (last_pixel_idx == transparent_pix || last_pixel_rgb!=p)
{
if (ignFr || p != (in2[x]&trans_mask)) last_pixel_idx = QuantPixel(p,wr);
else
{
const GifPixelType np = QuantPixel(p,wr);
if (p != (wr->last_palette[np]&trans_mask) || pix_stats[transparent_pix] > pix_stats[np])
last_pixel_idx = transparent_pix;
else
last_pixel_idx = np;
}
}
linebuf[x] = last_pixel_idx;
pix_stats[last_pixel_idx]++;
last_pixel_rgb = p;
}
}
else
{
// optimize solids by reusing the same value if previous rgb was the same, also avoid switching between
// from color to transparent if the color hasn't changed
if (use_octree) for(x=0;x<usew;x++)
{
const LICE_pixel p = in[x]&trans_mask;
if (last_pixel_idx == transparent_pix || last_pixel_rgb!=p)
{
if (ignFr || p != (in2[x]&trans_mask)) last_pixel_idx = LICE_FindInOctree(use_octree,last_pixel_rgb = p);
else last_pixel_idx = transparent_pix;
}
linebuf[x] = last_pixel_idx;
}
else for(x=0;x<usew;x++)
{
const LICE_pixel p = in[x]&trans_mask;
if (last_pixel_idx == transparent_pix || last_pixel_rgb!=p)
{
if (ignFr || p != (in2[x]&trans_mask)) last_pixel_idx = QuantPixel(last_pixel_rgb = p,wr);
else last_pixel_idx = transparent_pix;
}
linebuf[x] = last_pixel_idx;
}
}
EGifPutLine(wr->f, linebuf, usew);
}
LICE_Blit(&tmp,frame,0,0,0,0,usew,useh,1.0f,LICE_BLIT_MODE_COPY);
}
else if (wr->transalpha>0)
{
const unsigned int al = wr->transalpha&0xff;
for(y=0;y<useh;y++)
{
int rdy=y;
if (frame->isFlipped()) rdy = frame->getHeight()-1-y;
const LICE_pixel *in = frame->getBits() + rdy*frame->getRowSpan();
int x;
if (use_octree) for(x=0;x<usew;x++)
{
const LICE_pixel p = in[x];
if (LICE_GETA(p)<al) linebuf[x]=transparent_pix;
else linebuf[x] = LICE_FindInOctree(use_octree,p);
}
else for(x=0;x<usew;x++)
{
const LICE_pixel p = in[x];
if (LICE_GETA(p)<al) linebuf[x]=transparent_pix;
else linebuf[x] = QuantPixel(p,wr);
}
EGifPutLine(wr->f, linebuf, usew);
}
}
else for(y=0;y<useh;y++)
{
int rdy=y;
if (frame->isFlipped()) rdy = frame->getHeight()-1-y;
const LICE_pixel *in = frame->getBits() + rdy*frame->getRowSpan();
int x;
if (use_octree) for(x=0;x<usew;x++) linebuf[x] = LICE_FindInOctree(use_octree,in[x]);
else for(x=0;x<usew;x++) linebuf[x] = QuantPixel(in[x],wr);
EGifPutLine(wr->f, linebuf, usew);
}
return true;
}
static int writefunc_fh(GifFileType *fh, const GifByteType *buf, int sz)
{
return ((WDL_FileWrite *)fh->UserData)->Write(buf,sz);
}
void *LICE_WriteGIFBeginNoFrame(const char *filename, int w, int h, int transparent_alpha, bool dither, bool is_append)
{
WDL_FileWrite *fp = new WDL_FileWrite(filename,1,65536,16,16,is_append);
if (!fp->IsOpen())
{
delete fp;
return NULL;
}
EGifSetGifVersion("89a");
GifFileType *f = EGifOpen(fp,writefunc_fh);
if (!f)
{
delete fp;
return NULL;
}
liceGifWriteRec *wr = (liceGifWriteRec*)calloc(sizeof(liceGifWriteRec),1);
wr->f = f;
wr->fh = fp;
wr->append = is_append;
wr->dither = dither;
wr->w=w;
wr->h=h;
wr->cmap = (ColorMapObject*)calloc(sizeof(ColorMapObject)+256*sizeof(GifColorType),1);
wr->cmap->Colors = (GifColorType*)(wr->cmap+1);
wr->cmap->ColorCount=256;
wr->cmap->BitsPerPixel=8;
wr->has_had_frame=false;
wr->has_global_cmap=false;
wr->has_from15to8bit=false;
wr->last_octree=NULL;
wr->linebuf = (GifPixelType*)malloc(wr->w*sizeof(GifPixelType));
wr->transalpha = transparent_alpha;
return wr;
}
void *LICE_WriteGIFBegin(const char *filename, LICE_IBitmap *firstframe, int transparent_alpha, int frame_delay, bool dither, int nreps)
{
if (!firstframe) return NULL;
void *wr=LICE_WriteGIFBeginNoFrame(filename,firstframe->getWidth(),firstframe->getHeight(),transparent_alpha,dither);
if (wr) LICE_WriteGIFFrame(wr,firstframe,0,0,true,frame_delay,nreps);
return wr;
}
bool LICE_WriteGIFEnd(void *handle)
{
liceGifWriteRec *wr = (liceGifWriteRec*)handle;
if (!wr) return false;
int ret = EGifCloseFile(wr->f);
free(wr->linebuf);
free(wr->cmap);
if (wr->last_octree) LICE_DestroyOctree(wr->last_octree);
delete wr->prevframe;
delete wr->fh;
free(wr);
return ret!=GIF_ERROR;
}
bool LICE_WriteGIF(const char *filename, LICE_IBitmap *bmp, int transparent_alpha, bool dither)
{
// todo: alpha?
if (!bmp) return false;
int has_transparent = 0;
if (transparent_alpha>0)
{
int y=bmp->getHeight();
LICE_pixel *p = bmp->getBits();
int w = bmp->getWidth();
while (y--&&!has_transparent)
{
int x=w;
while(x--)
{
if (LICE_GETA(*p) < (unsigned int)transparent_alpha)
{
has_transparent=1;
break;
}
p++;
}
p+=bmp->getRowSpan()-w;
}
}
void *wr=LICE_WriteGIFBeginNoFrame(filename,bmp->getWidth(),bmp->getHeight(),has_transparent?transparent_alpha:0,dither);
if (!wr) return false;
LICE_WriteGIFFrame(wr,bmp,0,0,false,0);
return LICE_WriteGIFEnd(wr);
}

View File

@@ -0,0 +1,264 @@
#include "lice_gl_ctx.h"
#define MAX_CACHED_GLYPHS 4096
// create one hidden window per process to hold the openGL state,
// its GL render context stays current for the life of the process,
// we serve all framebuffers from the same render context
class LICE_GL_ctx
{
public:
LICE_GL_ctx();
~LICE_GL_ctx();
bool IsValid();
HWND GetWindow() { return m_hwnd; }
void Close();
GLUnurbsObj* GetNurbsObj(int linetol=8); // linetol = maximum number of straight-line pixels
int GetTexFromGlyph(const unsigned char* glyph, int glyph_w, int glyph_h);
void ClearTex();
struct GlyphCache
{
unsigned int tex;
unsigned char* glyph; // lives on the heap
int glyph_w, glyph_h;
};
private:
bool Init();
bool m_init_tried;
HINSTANCE m_gldll;
HWND m_hwnd;
HGLRC m_glrc;
GLUnurbsObj* m_nurbs; // keep this here for easy reuse
GlyphCache m_glyphCache[MAX_CACHED_GLYPHS];
int m_nCachedGlyphs;
};
LICE_GL_ctx::LICE_GL_ctx()
{
m_init_tried = false;
m_gldll = 0;
m_hwnd = 0;
m_glrc = 0;
m_nurbs = 0;
memset(m_glyphCache, 0, MAX_CACHED_GLYPHS*sizeof(GlyphCache));
m_nCachedGlyphs = 0;
}
LICE_GL_ctx::~LICE_GL_ctx()
{
Close();
}
bool LICE_GL_ctx::Init()
{
m_init_tried = true;
m_gldll = LoadLibrary("opengl32.dll");
if (!m_gldll)
{
Close();
return false;
}
// create a minimal GL render context to serve FBOs out of
WNDCLASS wc;
memset(&wc, 0, sizeof(WNDCLASS));
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = "LICE_GL_ctx";
RegisterClass(&wc);
m_hwnd = CreateWindow("LICE_GL_ctx", "LICE_GL_ctx", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, GetModuleHandle(0), 0);
HDC dc = GetDC(m_hwnd);
if (!dc)
{
Close();
return false;
}
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cAlphaBits = 8;
int pxfmt = ChoosePixelFormat(dc, &pfd);
if (!SetPixelFormat(dc, pxfmt, &pfd))
{
Close();
return false;
}
m_glrc = wglCreateContext(dc);
if (!wglMakeCurrent(dc, m_glrc)) // render context should stay current throughout
{
Close();
return false;
}
char *rendstr = (char*) glGetString(GL_RENDERER);
if (!rendstr || strstr(rendstr, "GDI"))
{
Close();
return false;
}
// check now for all the extension functions we will ever need
if (glewInit() != GLEW_OK ||
!glewIsSupported("GL_EXT_framebuffer_object") ||
!glewIsSupported("GL_ARB_texture_rectangle"))
{
Close();
return false;
}
// any one-time initialization goes here
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
ReleaseDC(m_hwnd, dc);
return true;
}
bool LICE_GL_ctx::IsValid()
{
if (m_gldll && m_glrc) return true;
if (!m_init_tried) return Init();
return false;
}
void LICE_GL_ctx::Close()
{
ClearTex();
if (m_nurbs)
{
gluDeleteNurbsRenderer(m_nurbs);
m_nurbs = 0;
}
if (m_glrc)
{
wglMakeCurrent(0, 0);
wglDeleteContext(m_glrc);
m_glrc = 0;
}
if (m_hwnd)
{
DestroyWindow(m_hwnd);
m_hwnd = 0;
}
if (m_gldll)
{
FreeLibrary(m_gldll);
m_gldll = 0;
}
}
GLUnurbsObj* LICE_GL_ctx::GetNurbsObj(int linetol)
{
if (!IsValid()) return 0;
if (!m_nurbs) m_nurbs = gluNewNurbsRenderer();
if (m_nurbs) gluNurbsProperty(m_nurbs, GLU_SAMPLING_TOLERANCE, (float)linetol);
return m_nurbs;
}
void LICE_GL_ctx::ClearTex()
{
int i;
for (i = 0; i < m_nCachedGlyphs; ++i)
{
glDeleteTextures(1, &m_glyphCache[i].tex);
free(m_glyphCache[i].glyph);
memset(&m_glyphCache[i], 0, sizeof(GlyphCache));
}
m_nCachedGlyphs = 0;
}
static int _glyphcmp(const void* p1, const void* p2)
{
LICE_GL_ctx::GlyphCache* gc1 = (LICE_GL_ctx::GlyphCache*) p1;
LICE_GL_ctx::GlyphCache* gc2 = (LICE_GL_ctx::GlyphCache*) p2;
if (gc1->glyph_w < gc2->glyph_w) return -1;
if (gc1->glyph_w > gc2->glyph_w) return 1;
if (gc1->glyph_h < gc2->glyph_h) return -1;
if (gc1->glyph_h > gc2->glyph_h) return 1;
return memcmp(gc1->glyph, gc2->glyph, gc1->glyph_w*gc1->glyph_h);
}
int LICE_GL_ctx::GetTexFromGlyph(const unsigned char* glyph, int glyph_w, int glyph_h)
{
if (!IsValid()) return false;
GlyphCache gc;
gc.tex = 0;
gc.glyph = (unsigned char *)glyph;
gc.glyph_w = glyph_w;
gc.glyph_h = glyph_h;
GlyphCache* p = (GlyphCache*) bsearch(&gc, m_glyphCache, m_nCachedGlyphs, sizeof(GlyphCache), _glyphcmp);
if (p) return p->tex;
glGenTextures(1, &gc.tex);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, gc.tex);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_ALPHA8, glyph_w, glyph_h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, glyph);
if (m_nCachedGlyphs >= MAX_CACHED_GLYPHS) ClearTex(); // quick & dirty
gc.glyph = (unsigned char*) malloc(glyph_w*glyph_h);
memcpy(gc.glyph, glyph, glyph_w*glyph_h);
m_glyphCache[m_nCachedGlyphs++] = gc; // copy
qsort(m_glyphCache, m_nCachedGlyphs, sizeof(GlyphCache), _glyphcmp);
return gc.tex;
}
////////
static LICE_GL_ctx s_glctx; // one static opengl context object per process
bool LICE_GL_IsValid()
{
return s_glctx.IsValid();
}
HWND LICE_GL_GetWindow()
{
if (s_glctx.IsValid()) return s_glctx.GetWindow();
return 0;
}
void LICE_GL_CloseCtx()
{
s_glctx.Close();
}
GLUnurbsObj* LICE_GL_GetNurbsObj(int linetol) // linetol = maximum number of straight-line pixels
{
return s_glctx.GetNurbsObj(linetol);
}
GLuint LICE_GL_GetTexFromGlyph(const unsigned char* glyph, int glyph_w, int glyph_h)
{
return s_glctx.GetTexFromGlyph(glyph, glyph_w, glyph_h);
}
void LICE_GL_ClearTex()
{
s_glctx.ClearTex();
}

View File

@@ -0,0 +1,27 @@
#ifndef _GL_CTX_
#define _GL_CTX_
#include "lice.h"
#define GLEW_STATIC
#include "glew/include/gl/glew.h"
#include "glew/include/gl/wglew.h"
#include "glew/include/gl/wglext.h"
// GL context functions
// opening and managing GL context is handled behind the scenes
bool LICE_GL_IsValid(); // GL context is initialized (will be lazy initialized on first call) and valid
HWND LICE_GL_GetWindow(); // Get the window that owns the GL context (one per process)
void LICE_GL_CloseCtx(); // Something failed, turn off GL context forever so we don't keep failing
GLUnurbsObj* LICE_GL_GetNurbsObj(int linetol=8); // linetol = maximum number of straight-line pixels
// facility for associating a glyph with a texture
GLuint LICE_GL_GetTexFromGlyph(const unsigned char* glyph, int glyph_w, int glyph_h);
void LICE_GL_ClearTex();
#endif

View File

@@ -0,0 +1,708 @@
#include "lice_glbitmap.h"
#include "lice_gl_ctx.h"
#include "../plush2/plush.h"
LICE_GLBitmap::LICE_GLBitmap()
{
m_bmp = 0;
m_fbo = 0;
m_tex = 0;
m_bufloc = EMPTY;
}
// This is separate from the constructor for initialization order reasons
void LICE_GLBitmap::Init(LICE_IBitmap* bmp, int w, int h)
{
m_bmp = bmp;
if (w > 0 && h > 0) CreateFBO(w, h);
}
bool LICE_GLBitmap::CreateFBO(int w, int h)
{
if (LICE_GL_IsValid())
{
if (m_fbo) ReleaseFBO();
glGenFramebuffersEXT(1, &m_fbo); // create a new empty FBO
if (m_fbo)
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); // bind this FBO so it is the rendering target
glEnable(GL_TEXTURE_RECTANGLE_ARB); // enable texturing
glGenTextures(1, &m_tex); // create a new texture to be the backing store
if (m_tex)
{
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_tex); // bind this texture so it is the texturing target
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // we won't be scaling it for this purpose
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); // size the texture
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_tex, 0); // attach the texture as the backing store for the FBO
}
glDisable(GL_TEXTURE_RECTANGLE_ARB); // done texturing
}
return BindFBO(); // this tests the FBO for validity
}
return false;
}
LICE_GL_SysBitmap::LICE_GL_SysBitmap(int w, int h)
: m_sysbmp(w, h)
{
Init(&m_sysbmp, w, h);
}
LICE_GL_MemBitmap::LICE_GL_MemBitmap(int w, int h)
: m_membmp(w, h)
{
Init(&m_membmp, w, h);
}
HDC LICE_GL_SysBitmap::getDC()
{
// no known way to get a DC directly from an offscreen openGL render context, sadly
FramebufferFromGPU();
OutputDebugString("GL to screen");
return m_sysbmp.getDC();
}
LICE_GL_SubBitmap::LICE_GL_SubBitmap(LICE_IBitmap *parent, int x, int y, int w, int h)
{
m_parent = parent;
m_x = x;
m_y = y;
m_w = w;
m_h = h;
}
LICE_pixel* LICE_GL_SubBitmap::getBits()
{
if (!m_parent) return 0;
return m_parent->getBits()+m_y*m_parent->getRowSpan()+m_x;
}
bool LICE_GL_SubBitmap::resize(int w, int h)
{
if (w == m_w && h == m_h) return false;
m_w = w;
m_h = h;
return true;
}
INT_PTR LICE_GL_SubBitmap::Extended(int id, void* data)
{
if (!m_parent) return 0;
if (id == LICE_EXT_SUPPORTS_ID) return m_parent->Extended(id, data);
LICE_Ext_SetClip_data clipdata(m_x, m_y, m_w, m_h);
if (!m_parent->Extended(LICE_EXT_SETCLIP, &clipdata)) return 0;
INT_PTR ret = m_parent->Extended(id, data);
m_parent->Extended(LICE_EXT_SETCLIP, 0);
return ret;
}
bool LICE_GLBitmap::SetClip_ext(LICE_Ext_SetClip_data* p)
{
if (!FramebufferToGPU()) return false;
if (p)
{
GLdouble c0[4] = { 1.0, 0.0, 0.0, -p->x };
GLdouble c1[4] = { -1.0, 0.0, 0.0, p->x+p->w };
GLdouble c2[4] = { 0.0, 1.0, 0.0, -p->y};
GLdouble c3[4] = { 0.0, -1.0, 0.0, p->y+p->h };
glClipPlane(GL_CLIP_PLANE0, c0);
glClipPlane(GL_CLIP_PLANE1, c1);
glClipPlane(GL_CLIP_PLANE2, c2);
glClipPlane(GL_CLIP_PLANE3, c3);
glEnable(GL_CLIP_PLANE0);
glEnable(GL_CLIP_PLANE1);
glEnable(GL_CLIP_PLANE2);
glEnable(GL_CLIP_PLANE3);
}
else
{
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);
glDisable(GL_CLIP_PLANE2);
glDisable(GL_CLIP_PLANE3);
}
return true;
}
LICE_GLBitmap::~LICE_GLBitmap()
{
ReleaseFBO();
}
int LICE_GLBitmap::getWidth()
{
return m_bmp->getWidth();
}
int LICE_GLBitmap::getHeight()
{
return m_bmp->getHeight();
}
int LICE_GLBitmap::getRowSpan()
{
return m_bmp->getRowSpan();
}
LICE_pixel* LICE_GLBitmap::getBits()
{
FramebufferFromGPU();
return m_bmp->getBits();
}
bool LICE_GLBitmap::resize(int w, int h)
{
int oldw = getWidth();
int oldh = getHeight();
if (w == oldw && h == oldh) return false;
if (oldw == 0 && oldh == 0 && w > 0 && h > 0)
{
m_bmp->resize(w, h);
CreateFBO(w, h);
return true;
}
if (!m_fbo || !m_tex) return m_bmp->resize(w, h);
OutputDebugString("GL resizing");
// the framebuffer/GPU transfer overhead is per-call, so it's important to be able
// to move the entire bitmap back and forth in one call, which means keeping m_sysbmp width == rowspan
int oldloc = m_bufloc;
FramebufferFromGPU(); // copy out the GPU data (this binds the FBO so it is the rendering target)
glEnable(GL_TEXTURE_RECTANGLE_ARB); // enable texturing
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_tex); // bind this texture so it is the texturing target
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // we won't be scaling it for this purpose
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); // size the texture
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_tex, 0); // attach the texture as the backing store for the FBO
glDisable(GL_TEXTURE_RECTANGLE_ARB); // done texturing
if (!BindFBO()) return m_bmp->resize(w, h); // this tests the FBO for validity
static LICE_MemBitmap tmpbmp;
tmpbmp.resize(w, h);
LICE_Blit(&tmpbmp, m_bmp, 0, 0, 0, 0, oldw, oldh, 1.0f, LICE_BLIT_MODE_COPY);
m_bmp->resize(0, 0); // force it to resize down
LICE_Copy(m_bmp, &tmpbmp);
if (oldloc == EMPTY) m_bufloc = EMPTY; // else bufloc remains INMEM
return true;
}
bool LICE_GLBitmap::BindFBO()
{
bool valid = false;
if (m_fbo)
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); // bind this FBO so it is the rendering target
valid = (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT);
if (valid)
{
int w = getWidth();
int h = getHeight();
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, w, 0.0, h);
}
else
{
ReleaseFBO();
LICE_GL_CloseCtx(); // if we fail once we're done with GL
}
}
return valid;
}
void LICE_GLBitmap::ReleaseFBO()
{
if (m_fbo)
{
glDeleteFramebuffersEXT(1, &m_fbo);
m_fbo = 0;
}
if (m_tex)
{
glDeleteTextures(1, &m_tex);
m_tex = 0;
}
}
bool LICE_GLBitmap::FramebufferToGPU()
{
if (BindFBO())
{
if (m_bufloc == INMEM)
{
OutputDebugString("GL to GPU");
glDisable(GL_BLEND);
glRasterPos2i(0, 0);
glDrawPixels(getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, m_bmp->getBits());
}
m_bufloc = INGPU;
}
return (m_bufloc == INGPU);
}
void LICE_GLBitmap::FramebufferFromGPU()
{
if (m_bufloc == INGPU && BindFBO())
{
OutputDebugString("GL to mem");
glFinish();
glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, m_bmp->getBits());
}
m_bufloc = INMEM;
}
INT_PTR LICE_GLBitmap::Extended(int id, void* data)
{
if (id == LICE_EXT_SUPPORTS_ID)
{
int extid = (int) data;
if (extid == LICE_EXT_LINE_ACCEL) return 1;
if (extid == LICE_EXT_FILLRECT_ACCEL) return 1;
if (extid == LICE_EXT_DRAWCBEZIER_ACCEL) return 1;
if (extid == LICE_EXT_DRAWGLYPH_ACCEL) return 1;
if (extid == LICE_EXT_BLIT_ACCEL) return 1;
if (extid == LICE_EXT_SCALEDBLIT_ACCEL) return 1;
if (extid == LICE_EXT_GETFBOTEX_ACCEL) return 1;
if (extid == LICE_EXT_CLEAR_ACCEL) return 1;
if (extid == LICE_EXT_DASHEDLINE_ACCEL) return 1;
if (extid == LICE_EXT_GETPIXEL_ACCEL) return 1;
if (extid == LICE_EXT_PUTPIXEL_ACCEL) return 1;
if (extid == LICE_EXT_SETCLIP) return 1;
if (extid == LICE_EXT_WINDOW_BLIT) return 1;
if (extid == LICE_EXT_FORGET) return 1;
if (extid == LICE_EXT_DRAWTRIANGLE_ACCEL) return 1;
return 0;
}
if (id == LICE_EXT_CLEAR_ACCEL) return Clear_accel((LICE_pixel*)data);
if (id == LICE_EXT_LINE_ACCEL) return Line_accel((LICE_Ext_Line_acceldata*)data);
if (id == LICE_EXT_FILLRECT_ACCEL) return FillRect_accel((LICE_Ext_FillRect_acceldata*) data);
if (id == LICE_EXT_DRAWCBEZIER_ACCEL) return DrawCBezier_accel((LICE_Ext_DrawCBezier_acceldata*)data);
if (id == LICE_EXT_DRAWGLYPH_ACCEL) return DrawGlyph_accel((LICE_Ext_DrawGlyph_acceldata*)data);
if (id == LICE_EXT_BLIT_ACCEL) return Blit_accel((LICE_Ext_Blit_acceldata*)data);
if (id == LICE_EXT_SCALEDBLIT_ACCEL) return ScaledBlit_accel((LICE_Ext_ScaledBlit_acceldata*)data);
if (id == LICE_EXT_DASHEDLINE_ACCEL) return DashedLine_accel((LICE_Ext_DashedLine_acceldata*)data);
if (id == LICE_EXT_GETPIXEL_ACCEL) return GetPixel_accel((LICE_Ext_GetPixel_acceldata*)data);
if (id == LICE_EXT_PUTPIXEL_ACCEL) return PutPixel_accel((LICE_Ext_PutPixel_acceldata*)data);
if (id == LICE_EXT_SETCLIP) return SetClip_ext((LICE_Ext_SetClip_data*)data);
if (id == LICE_EXT_DRAWTRIANGLE_ACCEL) return DrawTriangle_accel((LICE_Ext_DrawTriangle_acceldata*)data);
if (id == LICE_EXT_WINDOW_BLIT) return WindowBlit((LICE_Ext_WindowBlit_data*)data);
if (id == LICE_EXT_FORGET)
{
m_bufloc = EMPTY;
return 1;
}
if (id == LICE_EXT_GETFBOTEX_ACCEL)
{
if (FramebufferToGPU()) return m_tex;
return 0;
}
return 0;
}
static void SetGLAliasing(bool aa)
{
if (aa)
{
glEnable(GL_LINE_SMOOTH);
}
else
{
glDisable(GL_LINE_SMOOTH);
}
}
static void SetGLColor(LICE_pixel color, float alpha, int licemode)
{
int a = 255;
if (licemode&LICE_BLIT_USE_ALPHA) a = LICE_GETA(color);
a = (float)a*alpha;
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glColor4ub(LICE_GETB(color), LICE_GETG(color), LICE_GETR(color), a);
//glColor4ub(LICE_GETR(color), LICE_GETG(color), LICE_GETB(color), a);
}
bool LICE_GLBitmap::Clear_accel(LICE_pixel* color)
{
if (!color) return false;
LICE_pixel col = *color;
if (!FramebufferToGPU()) return false;
float r = (float)LICE_GETR(col)/255.0f;
float g = (float)LICE_GETG(col)/255.0f;
float b = (float)LICE_GETB(col)/255.0f;
float a = (float)LICE_GETA(col)/255.0f;
glClearColor(b, g, r, a);
//glClearColor(r, g, b, a);
glClear(GL_COLOR_BUFFER_BIT);
return true;
}
bool LICE_GLBitmap::Line_accel(LICE_Ext_Line_acceldata* p)
{
if (!p) return false;
if (!FramebufferToGPU()) return false;
SetGLColor(p->color, p->alpha, p->mode);
SetGLAliasing(p->aa);
glBegin(GL_LINES);
glVertex2f(p->x1, p->y1);
glVertex2f(p->x2, p->y2);
glEnd();
return true;
}
bool LICE_GLBitmap::DashedLine_accel(LICE_Ext_DashedLine_acceldata* p)
{
if (!p) return false;
if (!FramebufferToGPU()) return false;
SetGLColor(p->color, p->alpha, p->mode);
SetGLAliasing(p->aa);
glEnable(GL_LINE_STIPPLE);
int n = (p->pxon+p->pxoff)/2; // todo properly when pxon != pxoff
glLineStipple(n, 0xAAAA);
glBegin(GL_LINES);
glVertex2f(p->x1, p->y1);
glVertex2f(p->x2, p->y2);
glEnd();
glLineStipple(1, 65535);
glDisable(GL_LINE_STIPPLE);
return true;
}
bool LICE_GLBitmap::FillRect_accel(LICE_Ext_FillRect_acceldata* p)
{
if (!p) return false;
if (!FramebufferToGPU()) return false;
SetGLColor(p->color, p->alpha, p->mode);
glBegin(GL_POLYGON);
glVertex2i(p->x, p->y);
glVertex2i(p->x+p->w, p->y);
glVertex2i(p->x+p->w, p->y+p->h);
glVertex2i(p->x, p->y+p->h);
glEnd();
return true;
}
bool LICE_GLBitmap::DrawCBezier_accel(LICE_Ext_DrawCBezier_acceldata* p)
{
if (!p) return false;
if (!FramebufferToGPU()) return false;
GLUnurbsObj* nurbs = LICE_GL_GetNurbsObj();
if (!nurbs) return false;
p->color = LICE_RGBA(255,255,255,255); // temp for easy ID of GL rendering
SetGLColor(p->color, p->alpha, p->mode);
SetGLAliasing(p->aa);
float ctlpts[] =
{
p->xstart, p->ystart, 0.0f,
p->xctl1, p->yctl1, 0.0f,
p->xctl2, p->yctl2, 0.0f,
p->xend, p->yend, 0.0f
};
float knots[] = { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f };
gluBeginCurve(nurbs);
gluNurbsCurve(nurbs, 8, knots, 3, ctlpts, 4, GL_MAP1_VERTEX_3);
gluEndCurve(nurbs);
return true;
}
bool LICE_GLBitmap::DrawGlyph_accel(LICE_Ext_DrawGlyph_acceldata* p)
{
if (!p) return false;
if (!FramebufferToGPU()) return false;
glEnable(GL_TEXTURE_RECTANGLE_ARB);
int texID = LICE_GL_GetTexFromGlyph(p->alphas, p->glyph_w, p->glyph_h);
if (!texID) return false;
SetGLColor(p->color, p->alpha, p->mode);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texID);
glBegin(GL_POLYGON);
glTexCoord2i(0, 0);
glVertex2i(p->x, p->y);
glTexCoord2i(p->glyph_w, 0);
glVertex2i(p->x+p->glyph_w, p->y);
glTexCoord2i(p->glyph_w, p->glyph_h);
glVertex2i(p->x+p->glyph_w, p->y+p->glyph_h);
glTexCoord2i(0, p->glyph_h);
glVertex2i(p->x, p->y+p->glyph_h);
glEnd();
glDisable(GL_TEXTURE_RECTANGLE_ARB);
return true;
}
bool LICE_GLBitmap::Blit_accel(LICE_Ext_Blit_acceldata* p)
{
if (!p || !p->src) return false;
if (!FramebufferToGPU()) return false;
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
GLuint src_tex = p->src->Extended(LICE_EXT_GETFBOTEX_ACCEL, 0); // this binds the src's FBO
if (src_tex)
{
if (!BindFBO()) return false; // re-bind dest FBO
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, src_tex);
glBegin(GL_POLYGON);
glTexCoord2i(p->srcx, p->srcy);
glVertex2i(p->dstx, p->dsty);
glTexCoord2i(p->srcx+p->srcw, p->srcy);
glVertex2i(p->dstx+p->srcw, p->dsty);
glTexCoord2i(p->srcx+p->srcw, p->srcy+p->srch);
glVertex2i(p->dstx+p->srcw, p->dsty+p->srch);
glTexCoord2i(p->srcx, p->srcy+p->srch);
glVertex2i(p->dstx, p->dsty+p->srch);
glEnd();
glDisable(GL_TEXTURE_RECTANGLE_ARB);
return true;
}
int srcspan = p->src->getRowSpan();
if (p->srcx == 0 && p->srcy == 0 && p->srcw == srcspan)
{
glRasterPos2i(p->dstx, p->dsty);
glDrawPixels(p->srcw, p->srch, GL_RGBA, GL_UNSIGNED_BYTE, p->src->getBits());
return true;
}
LICE_pixel* srcrow = p->src->getBits()+p->srcy*srcspan+p->srcx;
int y;
for (y = 0; y < p->srch; ++y, srcrow += srcspan)
{
glRasterPos2i(p->dstx, p->dsty+y);
glDrawPixels(p->srcw, 1, GL_RGBA, GL_UNSIGNED_BYTE, srcrow);
}
return true;
}
bool LICE_GLBitmap::ScaledBlit_accel(LICE_Ext_ScaledBlit_acceldata* p)
{
if (!p || !p->src) return false;
if (!FramebufferToGPU()) return false;
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
GLuint src_tex = p->src->Extended(LICE_EXT_GETFBOTEX_ACCEL, 0); // this binds the src's FBO
bool src_has_tex = (src_tex > 0);
if (src_has_tex)
{
if (!BindFBO()) return false; // re-bind dest FBO
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, src_tex);
}
else
{
// create texture from src bits
glGenTextures(1, &src_tex);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, src_tex);
int srcspan = p->src->getRowSpan();
if (p->srcx == 0 && p->srcy == 0 && srcspan == p->srcw)
{
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, p->srcw, p->srch, 0, GL_RGBA, GL_UNSIGNED_BYTE, p->src->getBits());
}
else
{
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, p->srcw, p->srch, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); // size the texture
LICE_pixel* srcrow = p->src->getBits()+(int)p->srcy*srcspan+(int)p->srcx;
int y;
for (y = 0; y < p->srch; ++y, srcrow += srcspan)
{
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, y, p->srcw, 1, GL_RGBA, GL_UNSIGNED_BYTE, srcrow);
}
}
}
if (!src_tex) return false;
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // filter
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBegin(GL_POLYGON);
glTexCoord2i(p->srcx, p->srcy);
glVertex2i(p->dstx, p->dsty);
glTexCoord2i(p->srcx+p->srcw, p->srcy);
glVertex2i(p->dstx+p->dstw, p->dsty);
glTexCoord2i(p->srcx+p->srcw, p->srcy+p->srch);
glVertex2i(p->dstx+p->dstw, p->dsty+p->dsth);
glTexCoord2i(p->srcx, p->srcy+p->srch);
glVertex2i(p->dstx, p->dsty+p->dsth);
glEnd();
if (!src_has_tex) glDeleteTextures(1, &src_tex);
glDisable(GL_TEXTURE_RECTANGLE_ARB);
return true;
}
bool LICE_GLBitmap::GetPixel_accel(LICE_Ext_GetPixel_acceldata* p)
{
if (!p) return false;
if (!FramebufferToGPU()) return false;
p->px = 0;
glReadPixels(p->x, p->y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &p->px);
return true;
}
bool LICE_GLBitmap::PutPixel_accel(LICE_Ext_PutPixel_acceldata* p)
{
if (!p) return false;
if (!FramebufferToGPU()) return false;
SetGLColor(p->color, p->alpha, p->mode);
glBegin(GL_POINTS);
glVertex2i(p->x, p->y);
glEnd();
return true;
}
bool LICE_GLBitmap::DrawTriangle_accel(LICE_Ext_DrawTriangle_acceldata *p)
{
if (!p) return false;
if (!FramebufferToGPU()) return false;
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
// todo: finish implementing zbuffering, (multi)texture mapping, alpha, etc
glColor4f(p->VertexShades[0][0],
p->VertexShades[0][1],
p->VertexShades[0][2],
p->mat->SolidOpacity);
glBegin(GL_TRIANGLES);
int x;
for(x=0;x<3;x++)
{
glVertex2i(p->scrx[x], p->scry[x]);
}
glEnd();
return true;
}
bool LICE_GLBitmap::WindowBlit(LICE_Ext_WindowBlit_data* p)
{
if (!p) return false;
if (!FramebufferToGPU()) return false;
HWND hwnd = p->hwnd;
if (hwnd != LICE_GL_GetWindow()) return 0;
glFinish();
//HDC dc = GetDC(hwnd);
//HGLRC rc = wglCreateContext(dc);
//wglMakeCurrent(dc, rc);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
/*
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, w, 0.0, h);
*/
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_tex);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// the src image is upside down
// todo positioning
glBegin(GL_POLYGON);
glTexCoord2i(0, p->h);
glVertex2i(0, 0);
glTexCoord2i(p->w, p->h);
glVertex2i(p->w, 0);
glTexCoord2i(p->w, 0);
glVertex2i(p->w-1, p->h);
glTexCoord2i(0, 0);
glVertex2i(0, p->h);
glEnd();
glDisable(GL_TEXTURE_RECTANGLE_ARB);
//wglMakeCurrent(0, 0);
//wglDeleteContext(rc);
// ReleaseDC(hwnd, dc);
return true;
}

View File

@@ -0,0 +1,110 @@
#include "lice.h"
#include "lice_extended.h"
// interface class for LICE_GL_SysBitmap and LICE_GL_MemBitmap
class LICE_GLBitmap : public LICE_IBitmap
{
public:
LICE_GLBitmap();
~LICE_GLBitmap();
LICE_pixel* getBits();
int getWidth();
int getHeight();
int getRowSpan();
bool resize(int w, int h);
virtual HDC getDC() = 0; // re-virtualize this to prevent instantiating LICE_GLBitmap directly
INT_PTR Extended(int id, void* data);
private:
bool Clear_accel(LICE_pixel* color);
bool Line_accel(LICE_Ext_Line_acceldata* p);
bool FillRect_accel(LICE_Ext_FillRect_acceldata* p);
bool DrawCBezier_accel(LICE_Ext_DrawCBezier_acceldata* p);
bool DrawGlyph_accel(LICE_Ext_DrawGlyph_acceldata* p);
bool Blit_accel(LICE_Ext_Blit_acceldata* p);
bool ScaledBlit_accel(LICE_Ext_ScaledBlit_acceldata* p);
bool DashedLine_accel(LICE_Ext_DashedLine_acceldata* p);
bool GetPixel_accel(LICE_Ext_GetPixel_acceldata* p);
bool PutPixel_accel(LICE_Ext_PutPixel_acceldata* p);
bool SetClip_ext(LICE_Ext_SetClip_data* p);
bool DrawTriangle_accel(LICE_Ext_DrawTriangle_acceldata *p);
// etc
bool WindowBlit(LICE_Ext_WindowBlit_data* p);
bool CreateFBO(int w, int h);
bool BindFBO(); // bind this FBO so it is the current rendering target, and test for validity
void ReleaseFBO();
unsigned int m_fbo; // framebuffer object: rendering target for drawing on this glbitmap
unsigned int m_tex; // texture object: backing store for this framebuffer object
enum { EMPTY, INGPU, INMEM };
int m_bufloc; // where is the current framebuffer?
LICE_IBitmap* m_bmp;
protected:
void Init(LICE_IBitmap* bmp, int w, int h);
bool FramebufferToGPU();
void FramebufferFromGPU();
};
class LICE_GL_SysBitmap : public LICE_GLBitmap
{
public:
LICE_GL_SysBitmap(int w=0, int h=0);
HDC getDC();
private:
LICE_SysBitmap m_sysbmp;
};
class LICE_GL_MemBitmap : public LICE_GLBitmap
{
public:
LICE_GL_MemBitmap(int w=0, int h=0);
HDC getDC() { return 0; }
private:
LICE_MemBitmap m_membmp;
};
class LICE_GL_SubBitmap : public LICE_IBitmap
{
public:
LICE_GL_SubBitmap(LICE_IBitmap *parent, int x, int y, int w, int h);
LICE_pixel* getBits();
int getWidth() { return m_w; }
int getHeight() { return m_h; }
int getRowSpan() { return (m_parent ? m_parent->getRowSpan() : 0); }
bool resize(int w, int h);
HDC getDC() { return (m_parent ? m_parent->getDC() : 0); }
INT_PTR Extended(int id, void* data);
private:
LICE_IBitmap* m_parent;
int m_x, m_y, m_w, m_h;
};

View File

@@ -0,0 +1,191 @@
/*
Cockos WDL - LICE - Lightweight Image Compositing Engine
Copyright (C) 2007 and later, Cockos Incorporated
File: lice_ico.cpp (ICO icon file loading for LICE)
See lice.h for license and other information
This file contains some code from Microsoft's MSDN ICO loading sample
see: http://msdn2.microsoft.com/en-us/library/ms997538.aspx
*/
#include "lice.h"
#include "../wdltypes.h"
#ifndef _WIN32
#include "../swell/swell.h"
#endif
static LICE_IBitmap *icoToBitmap(HICON icon, LICE_IBitmap *bmpOut)
{
int icon_w = 16, icon_h=16;
#ifdef _WIN32
ICONINFO ii={0,};
if (GetIconInfo(icon,&ii))
{
bool blah=false;
if (ii.hbmColor)
{
BITMAP bm={0,};
if (GetObject(ii.hbmColor,sizeof(bm),&bm) && bm.bmWidth && bm.bmHeight)
{
icon_w=bm.bmWidth;
icon_h=bm.bmHeight;
blah=true;
}
DeleteObject(ii.hbmColor);
}
if (ii.hbmMask)
{
BITMAP bm={0,};
if (!blah && GetObject(ii.hbmMask,sizeof(bm),&bm) && bm.bmWidth && bm.bmHeight)
{
icon_w=bm.bmWidth;
icon_h=bm.bmHeight;
}
DeleteObject(ii.hbmMask);
}
}
#else
BITMAP bm={0,};
if (GetObject(icon,sizeof(bm),&bm) && bm.bmWidth && bm.bmHeight) // SWELL's GetObject() works on icons
{
icon_w=bm.bmWidth;
icon_h=bm.bmHeight;
}
#endif
LICE_SysBitmap tempbm(icon_w*2,icon_h);
LICE_FillRect(&tempbm,0,0,icon_w,icon_h,LICE_RGBA(0,0,0,255),1.0f,LICE_BLIT_MODE_COPY);
#ifdef _WIN32
DrawIconEx(tempbm.getDC(),0,0,icon,icon_w,icon_h,0,NULL,DI_NORMAL);
#else
{
RECT r={0,0,icon_w,icon_h};
DrawImageInRect(tempbm.getDC(),icon,&r);
}
#endif
LICE_FillRect(&tempbm,icon_w,0,icon_w,icon_h,LICE_RGBA(255,255,255,255),1.0f,LICE_BLIT_MODE_COPY);
#ifdef _WIN32
DrawIconEx(tempbm.getDC(),icon_w,0,icon,icon_w,icon_h,0,NULL,DI_NORMAL);
#else
{
RECT r={icon_w,0,icon_w+icon_w,icon_h};
DrawImageInRect(tempbm.getDC(),icon,&r);
}
#endif
if (!bmpOut) bmpOut = new WDL_NEW LICE_MemBitmap(icon_w,icon_h);
else bmpOut->resize(icon_w,icon_h);
int y; // since we have the image drawn on white and on black, we can calculate the alpha channel...
if (bmpOut) for(y=0;y<icon_h;y++)
{
int x;
for(x=0;x<icon_w;x++)
{
LICE_pixel p = LICE_GetPixel(&tempbm,x,y);
LICE_pixel p2 = LICE_GetPixel(&tempbm,x+icon_w,y);
int r1=LICE_GETR(p);
int g1=LICE_GETG(p);
int b1=LICE_GETB(p);
int alpha=255 - (LICE_GETR(p2)-r1);
if (alpha>=255) alpha=255;
else if (alpha>0)
{
r1 = (r1*255)/alpha; // LICE stores its alpha channel non-premultiplied, so we need to scale these up.
g1 = (g1*255)/alpha;
b1 = (b1*255)/alpha;
if (r1>255)r1=255;
if (g1>255)g1=255;
if (b1>255)b1=255;
}
else alpha=0;
LICE_PutPixel(bmpOut,x,y,LICE_RGBA(r1,g1,b1,alpha),1.0f,LICE_BLIT_MODE_COPY);
}
}
return bmpOut;
}
LICE_IBitmap *LICE_LoadIcon(const char *filename, int reqiconsz, LICE_IBitmap *bmp) // returns a bitmap (bmp if nonzero) on success
{
if (reqiconsz<1) reqiconsz=16;
HICON icon = NULL;
#ifdef _WIN32
#ifndef WDL_NO_SUPPORT_UTF8
#ifdef WDL_SUPPORT_WIN9X
if (GetVersion()<0x80000000)
#endif
{
WCHAR wf[2048];
if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,wf,2048))
icon = (HICON)LoadImageW(NULL,wf,IMAGE_ICON,reqiconsz,reqiconsz,LR_LOADFROMFILE);
}
#endif
if (!icon) icon = (HICON)LoadImage(NULL,filename,IMAGE_ICON,reqiconsz,reqiconsz,LR_LOADFROMFILE);
#else
icon = (HICON)LoadNamedImage(filename,false);
#endif
if (!icon) return 0;
LICE_IBitmap *ret=icoToBitmap(icon,bmp);
DestroyIcon(icon);
return ret;
}
LICE_IBitmap *LICE_LoadIconFromResource(HINSTANCE hInst, const char *resid, int reqiconsz, LICE_IBitmap *bmp) // returns a bitmap (bmp if nonzero) on success
{
#ifdef _WIN32
if (reqiconsz<1) reqiconsz=16;
HICON icon = (HICON)LoadImage(hInst,resid,IMAGE_ICON,reqiconsz,reqiconsz,0);
if (!icon) return 0;
LICE_IBitmap *ret=icoToBitmap(icon,bmp);
DestroyIcon(icon);
return ret;
#else
return 0;
#endif
}
class LICE_ICOLoader
{
public:
_LICE_ImageLoader_rec rec;
LICE_ICOLoader()
{
rec.loadfunc = loadfunc;
rec.get_extlist = get_extlist;
rec._next = LICE_ImageLoader_list;
LICE_ImageLoader_list = &rec;
}
static LICE_IBitmap *loadfunc(const char *filename, bool checkFileName, LICE_IBitmap *bmpbase)
{
if (checkFileName)
{
const char *p=filename;
while (*p)p++;
while (p>filename && *p != '\\' && *p != '/' && *p != '.') p--;
if (stricmp(p,".ico")) return 0;
}
return LICE_LoadIcon(filename,16,bmpbase);
}
static const char *get_extlist()
{
return "ICO files (*.ICO)\0*.ICO\0";
}
};
LICE_ICOLoader LICE_icoldr;

View File

@@ -0,0 +1,147 @@
#include "lice.h"
LICE_IBitmap* LICE_LoadImage(const char* filename, LICE_IBitmap* bmp, bool tryIgnoreExtension)
{
_LICE_ImageLoader_rec *hdr = LICE_ImageLoader_list;
while (hdr)
{
LICE_IBitmap *ret = hdr->loadfunc(filename,true,bmp);
if (ret) return ret;
hdr=hdr->_next;
}
if (tryIgnoreExtension)
{
hdr = LICE_ImageLoader_list;
while (hdr)
{
LICE_IBitmap *ret = hdr->loadfunc(filename,false,bmp);
if (ret) return ret;
hdr=hdr->_next;
}
}
return 0;
}
static bool grow_buf(char **buf, int *bufsz, int *wrpos, const char *rd, int len)
{
if (*wrpos + len > *bufsz)
{
char *nbuf=(char*)realloc(*buf,*bufsz = *wrpos+len+4096);
if (!nbuf) return true; // ugh
*buf = nbuf;
}
memcpy(*buf+*wrpos,rd,len);
*wrpos+=len;
return false;
}
char *LICE_GetImageExtensionList(bool wantAllSup, bool wantAllFiles)
{
_LICE_ImageLoader_rec *hdr = LICE_ImageLoader_list;
int bufsz=4096;
int wrpos=0;
char *buf=(char *)malloc(bufsz);
buf[0]=buf[1]=buf[2]=0;
if (wantAllSup)
{
static const char af[]="All supported images";
if (grow_buf(&buf,&bufsz,&wrpos,af,sizeof(af))) { free(buf); return NULL; } // fail
int cnt=0;
while (hdr)
{
const char *rd = hdr->get_extlist();
if (rd && *rd)
{
bool st=false;
const char *p=rd;
while (*p)
{
if (st)
{
if (cnt++)
if (grow_buf(&buf,&bufsz,&wrpos,";",1)) { free(buf); return NULL; } // fail
if (grow_buf(&buf,&bufsz,&wrpos,p,(int)strlen(p)+1)) { free(buf); return NULL; } // fail
wrpos--;
}
while (*p) p++;
p++;
st=!st;
}
}
hdr=hdr->_next;
}
if (!cnt)
{
wrpos=0; // reset if nothing meaningful added
buf[0]=buf[1]=buf[2]=0;
}
else wrpos++;
hdr = LICE_ImageLoader_list;
}
while (hdr)
{
const char *rd = hdr->get_extlist();
if (rd && *rd)
{
int len = 0;
while (rd[len] || rd[len+1]) len++; // doublenull terminated list
if (len)
{
if (grow_buf(&buf, &bufsz, &wrpos, rd, len+2)) return buf; // fail
wrpos--; // remove doublenull on next round
}
}
hdr=hdr->_next;
}
if (wantAllFiles)
{
static const char af[]="All files (*.*)\0*.*\0";
if (grow_buf(&buf,&bufsz,&wrpos,af,sizeof(af))) return buf; // fail
wrpos--;
}
return buf;
}
bool LICE_ImageIsSupported(const char *filename)
{
const char *extension = filename;
while (*extension)extension++;
while (extension>=filename && *extension != '/' && *extension != '.' && *extension != '\\') extension--;
if (extension<filename || *extension != '.') return false;
const size_t extlen = strlen(extension);
_LICE_ImageLoader_rec *hdr = LICE_ImageLoader_list;
while (hdr)
{
const char *el = hdr->get_extlist();
if (el)
{
while (*el) el++; // skip desc
++el;
// scan rest of buffer
while (*el)
{
if (!strnicmp(el,extension,extlen))
{
if (el[extlen] == 0|| el[extlen] == ';') return true;
}
el++;
}
}
hdr=hdr->_next;
}
return false;
}

View File

@@ -0,0 +1,84 @@
#define LICE_TEXT_NO_DECLARE_CACHEDFONT
#ifdef LICE_IMPORT_INTERFACE_ONLY
#define LICE_FUNC_DEF_DECL extern
#else
#define LICE_FUNC_DEF_DECL
#endif
#include "lice_text.h"
LICE_FUNC_DEF_DECL LICE_IBitmap *(*__LICE_CreateBitmap)(int, int, int);
LICE_FUNC_DEF_DECL void (*__LICE_PutPixel)(LICE_IBitmap* dest, int x, int y, LICE_pixel color, float alpha, int mode);
LICE_FUNC_DEF_DECL void (*__LICE_Line)(LICE_IBitmap *dest, int x1, int y1, int x2, int y2, LICE_pixel color, float alpha, int mode, bool aa);
LICE_FUNC_DEF_DECL void (*__LICE_FLine)(LICE_IBitmap *dest, float x1, float y1, float x2, float y2, LICE_pixel color, float alpha, int mode, bool aa);
LICE_FUNC_DEF_DECL void (*__LICE_DashedLine)(LICE_IBitmap *dest, int x1, int y1, int x2, int y2, int on, int off, LICE_pixel color, float alpha, int mode, bool aa);
LICE_FUNC_DEF_DECL void (*__LICE_FillRect)(LICE_IBitmap *dest, int x, int y, int w, int h, LICE_pixel color, float alpha , int mode);
LICE_FUNC_DEF_DECL void (*__LICE_DrawRect)(LICE_IBitmap *dest, int x, int y, int w, int h, LICE_pixel color, float alpha , int mode);
LICE_FUNC_DEF_DECL void (*__LICE_BorderedRect)(LICE_IBitmap *dest, int x, int y, int w, int h, LICE_pixel bgcolor, LICE_pixel fgcolor, float alpha, int mode);
LICE_FUNC_DEF_DECL void (*__LICE_Circle)(LICE_IBitmap* dest, float cx, float cy, float r, LICE_pixel color, float alpha, int mode, bool aa);
LICE_FUNC_DEF_DECL void (*__LICE_FillCircle)(LICE_IBitmap* dest, float cx, float cy, float r, LICE_pixel color, float alpha, int mode, bool aa);
LICE_FUNC_DEF_DECL void (*__LICE_Clear)(LICE_IBitmap *dest, LICE_pixel color);
LICE_FUNC_DEF_DECL void (*__LICE_Blit)(LICE_IBitmap *dest, LICE_IBitmap *src, int dstx, int dsty, int srcx, int srcy, int srcw, int srch, float alpha, int mode);
LICE_FUNC_DEF_DECL void (*__LICE_RotatedBlit)(LICE_IBitmap *dest, LICE_IBitmap *src, int dstx, int dsty, int dstw, int dsth, float srcx, float srcy, float srcw, float srch, float angle, bool cliptosourcerect, float alpha, int mode, float rotxcent, float rotycent);
LICE_FUNC_DEF_DECL void (*__LICE_DrawGlyph)(LICE_IBitmap* dest, int x, int y, LICE_pixel color, LICE_pixel_chan* glyph, int glyph_w, int glyph_h, float alpha, int mode);
LICE_FUNC_DEF_DECL void (*__LICE_FillTriangle)(LICE_IBitmap *dest, int x1, int y1, int x2, int y2, int x3, int y3, LICE_pixel color, float alpha, int mode);
LICE_FUNC_DEF_DECL void (*__LICE_Arc)(LICE_IBitmap* dest, float cx, float cy, float r, float alo, float ahi, LICE_pixel color, float alpha, int mode, bool aa);
LICE_FUNC_DEF_DECL void (*__LICE_FillTrapezoid)(LICE_IBitmap* dest, int x1a, int x1b, int y1, int x2a, int x2b, int y2, LICE_pixel color, float alpha, int mode);
LICE_FUNC_DEF_DECL void (*__LICE_FillConvexPolygon)(LICE_IBitmap* dest, int* x, int* y, int npoints, LICE_pixel color, float alpha, int mode);
LICE_FUNC_DEF_DECL void (*__LICE_Copy)(LICE_IBitmap* dest, LICE_IBitmap* src);
LICE_FUNC_DEF_DECL void (*__LICE_DrawText)(LICE_IBitmap *bm, int x, int y, const char *string, LICE_pixel color, float alpha, int mode);
LICE_FUNC_DEF_DECL void (*__LICE_MeasureText)(const char *string, int *w, int *h);
LICE_FUNC_DEF_DECL void (*__LICE_ScaledBlit)(LICE_IBitmap *dest, LICE_IBitmap *src, int dstx, int dsty, int dstw, int dsth, float srcx, float srcy, float srcw, float srch, float alpha, int mode);
LICE_FUNC_DEF_DECL void * (*LICE_CreateFont)();
#define LICE_PutPixel __LICE_PutPixel
#define LICE_Line __LICE_Line
#define LICE_FLine __LICE_FLine
#define LICE_DashedLine __LICE_DashedLine
#define LICE_FillRect __LICE_FillRect
#define LICE_DrawRect __LICE_DrawRect
#define LICE_Circle __LICE_Circle
#define LICE_Clear __LICE_Clear
#define LICE_Blit __LICE_Blit
#define LICE_RotatedBlit __LICE_RotatedBlit
#define LICE_DrawGlyph __LICE_DrawGlyph
#define LICE_FillCircle __LICE_FillCircle
#define LICE_BorderedRect __LICE_BorderedRect
#define LICE_FillTriangle __LICE_FillTriangle
#define LICE_Arc __LICE_Arc
#define LICE_FillTrapezoid __LICE_FillTrapezoid
#define LICE_FillConvexPolygon __LICE_FillConvexPolygon
#define LICE_Copy __LICE_Copy
#define LICE_DrawText __LICE_DrawText
#define LICE_MeasureText __LICE_MeasureText
#define LICE_ScaledBlit __LICE_ScaledBlit
#define LICE_CreateMemBitmap(w,h) (__LICE_CreateBitmap ? __LICE_CreateBitmap(0,w,h) : 0)
#define LICE_CreateSysBitmap(w,h) (__LICE_CreateBitmap ? __LICE_CreateBitmap(1,w,h) : 0)
#define LICE_CreateTextCache() ((LICE_IFont*)(LICE_CreateFont?LICE_CreateFont():0))
#undef LICE_FUNC_DEF_DECL
#define IMPORT_LICE_FUNCS(IMPORT_FUNC) \
IMPORT_FUNC(__LICE_CreateBitmap,"LICE_CreateBitmap") \
IMPORT_FUNC(__LICE_PutPixel,"LICE_PutPixel") \
IMPORT_FUNC(__LICE_Line,"LICE_LineInt") \
IMPORT_FUNC(__LICE_FLine,"LICE_Line") \
IMPORT_FUNC(__LICE_DashedLine, "LICE_DashedLine") \
IMPORT_FUNC(__LICE_Circle,"LICE_Circle") \
IMPORT_FUNC(__LICE_FillCircle,"LICE_FillCircle") \
IMPORT_FUNC(__LICE_FillRect,"LICE_FillRect") \
IMPORT_FUNC(__LICE_DrawRect,"LICE_DrawRect") \
IMPORT_FUNC(__LICE_BorderedRect,"LICE_BorderedRect") \
IMPORT_FUNC(__LICE_Clear,"LICE_Clear") \
IMPORT_FUNC(__LICE_Blit,"LICE_Blit") \
IMPORT_FUNC(__LICE_RotatedBlit,"LICE_RotatedBlit") \
IMPORT_FUNC(__LICE_DrawGlyph,"LICE_DrawGlyph") \
IMPORT_FUNC(LICE_CreateFont,"LICE_CreateFont") \
IMPORT_FUNC(LICE_FillTriangle,"LICE_FillTriangle") \
IMPORT_FUNC(LICE_Arc,"LICE_Arc") \
IMPORT_FUNC(LICE_FillTrapezoid,"LICE_FillTrapezoid") \
IMPORT_FUNC(LICE_FillConvexPolygon,"LICE_FillConvexPolygon") \
IMPORT_FUNC(LICE_Copy,"LICE_Copy") \
IMPORT_FUNC(__LICE_ScaledBlit,"LICE_ScaledBlit") \
IMPORT_FUNC(__LICE_MeasureText,"LICE_MeasureText") \
IMPORT_FUNC(__LICE_DrawText,"LICE_DrawText")

View File

@@ -0,0 +1,404 @@
/*
Cockos WDL - LICE - Lightweight Image Compositing Engine
Copyright (C) 2007 and later, Cockos Incorporated
File: lice_jpg.cpp (JPG loading for LICE)
See lice.h for license and other information
*/
#include <stdio.h>
#include "lice.h"
#include <setjmp.h>
#include "../wdltypes.h"
extern "C" {
#include "../jpeglib/jpeglib.h"
};
struct my_error_mgr {
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
static void LICEJPEG_Error(j_common_ptr cinfo)
{
longjmp(((my_error_mgr*)cinfo->err)->setjmp_buffer,1);
}
static void LICEJPEG_EmitMsg(j_common_ptr cinfo, int msg_level) { }
static void LICEJPEG_FmtMsg(j_common_ptr cinfo, char *) { }
static void LICEJPEG_OutMsg(j_common_ptr cinfo) { }
static void LICEJPEG_reset_error_mgr(j_common_ptr cinfo)
{
cinfo->err->num_warnings = 0;
cinfo->err->msg_code = 0;
}
#ifdef _WIN32
static void LICEJPEG_init_source(j_decompress_ptr cinfo) {}
static unsigned char EOI_data[2] = { 0xFF, 0xD9 };
static boolean LICEJPEG_fill_input_buffer(j_decompress_ptr cinfo)
{
cinfo->src->next_input_byte = EOI_data;
cinfo->src->bytes_in_buffer = 2;
return TRUE;
}
static void LICEJPEG_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
{
if (num_bytes > 0)
{
if (num_bytes > (long) cinfo->src->bytes_in_buffer)
{
num_bytes = (long) cinfo->src->bytes_in_buffer;
}
cinfo->src->next_input_byte += (size_t) num_bytes;
cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
}
}
static void LICEJPEG_term_source(j_decompress_ptr cinfo) {}
#endif
LICE_IBitmap *LICE_LoadJPGFromResource(HINSTANCE hInst, const char *resid, LICE_IBitmap *bmp)
{
#ifdef _WIN32
HRSRC hResource = FindResource(hInst, resid, "JPG");
if(!hResource) return NULL;
DWORD imageSize = SizeofResource(hInst, hResource);
if(imageSize < 8) return NULL;
HGLOBAL res = LoadResource(hInst, hResource);
const void* pResourceData = LockResource(res);
if(!pResourceData) return NULL;
unsigned char *data = (unsigned char *)pResourceData;
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr={0,};
JSAMPARRAY buffer;
int row_stride;
jerr.pub.error_exit = LICEJPEG_Error;
jerr.pub.emit_message = LICEJPEG_EmitMsg;
jerr.pub.output_message = LICEJPEG_OutMsg;
jerr.pub.format_message = LICEJPEG_FmtMsg;
jerr.pub.reset_error_mgr = LICEJPEG_reset_error_mgr;
cinfo.err = &jerr.pub;
if (setjmp(jerr.setjmp_buffer))
{
jpeg_destroy_decompress(&cinfo);
return 0;
}
jpeg_create_decompress(&cinfo);
cinfo.src = (struct jpeg_source_mgr *) (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT, sizeof (struct jpeg_source_mgr));
cinfo.src->init_source = LICEJPEG_init_source;
cinfo.src->fill_input_buffer = LICEJPEG_fill_input_buffer;
cinfo.src->skip_input_data = LICEJPEG_skip_input_data;
cinfo.src->resync_to_restart = jpeg_resync_to_restart;
cinfo.src->term_source = LICEJPEG_term_source;
cinfo.src->next_input_byte = data;
cinfo.src->bytes_in_buffer = imageSize;
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
row_stride = cinfo.output_width * cinfo.output_components;
buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
LICE_IBitmap *delbmp = NULL;
if (bmp) bmp->resize(cinfo.output_width,cinfo.output_height);
else delbmp = bmp = new WDL_NEW LICE_MemBitmap(cinfo.output_width,cinfo.output_height);
if (!bmp || bmp->getWidth() != (int)cinfo.output_width || bmp->getHeight() != (int)cinfo.output_height)
{
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
delete delbmp;
return 0;
}
LICE_pixel *bmpptr = bmp->getBits();
int dbmpptr=bmp->getRowSpan();
if (bmp->isFlipped())
{
bmpptr += dbmpptr*(bmp->getHeight()-1);
dbmpptr=-dbmpptr;
}
while (cinfo.output_scanline < cinfo.output_height)
{
/* jpeg_read_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could ask for
* more than one scanline at a time if that's more convenient.
*/
jpeg_read_scanlines(&cinfo, buffer, 1);
/* Assume put_scanline_someplace wants a pointer and sample count. */
// put_scanline_someplace(buffer[0], row_stride);
if (cinfo.output_components==3)
{
int x;
for (x = 0; x < (int)cinfo.output_width; x++)
{
bmpptr[x]=LICE_RGBA(buffer[0][x*3],buffer[0][x*3+1],buffer[0][x*3+2],255);
}
}
else if (cinfo.output_components==1)
{
int x;
for (x = 0; x < (int)cinfo.output_width; x++)
{
int v=buffer[0][x];
bmpptr[x]=LICE_RGBA(v,v,v,255);
}
}
else
{
memset(bmpptr,0,4*cinfo.output_width);
}
bmpptr+=dbmpptr;
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo); // we created cinfo.src with some special alloc so I think it gets collected
return bmp;
#else
return 0;
#endif
}
LICE_IBitmap *LICE_LoadJPG(const char *filename, LICE_IBitmap *bmp)
{
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr={{0},};
JSAMPARRAY buffer;
int row_stride;
FILE *fp=NULL;
#if defined(_WIN32) && !defined(WDL_NO_SUPPORT_UTF8)
#ifdef WDL_SUPPORT_WIN9X
if (GetVersion()<0x80000000)
#endif
{
WCHAR wf[2048];
if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,wf,2048))
fp = _wfopen(wf,L"rb");
}
#endif
if (!fp) fp = WDL_fopenA(filename,"rb");
if (!fp) return 0;
jerr.pub.error_exit = LICEJPEG_Error;
jerr.pub.emit_message = LICEJPEG_EmitMsg;
jerr.pub.output_message = LICEJPEG_OutMsg;
jerr.pub.format_message = LICEJPEG_FmtMsg;
jerr.pub.reset_error_mgr = LICEJPEG_reset_error_mgr;
cinfo.err = &jerr.pub;
if (setjmp(jerr.setjmp_buffer))
{
jpeg_destroy_decompress(&cinfo);
fclose(fp);
return 0;
}
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, fp);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
row_stride = cinfo.output_width * cinfo.output_components;
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
LICE_IBitmap *delbmp = NULL;
if (bmp) bmp->resize(cinfo.output_width,cinfo.output_height);
else delbmp = bmp = new WDL_NEW LICE_MemBitmap(cinfo.output_width,cinfo.output_height);
if (!bmp || bmp->getWidth() != (int)cinfo.output_width || bmp->getHeight() != (int)cinfo.output_height)
{
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(fp);
delete delbmp;
return 0;
}
LICE_pixel *bmpptr = bmp->getBits();
int dbmpptr=bmp->getRowSpan();
if (bmp->isFlipped())
{
bmpptr += dbmpptr*(bmp->getHeight()-1);
dbmpptr=-dbmpptr;
}
while (cinfo.output_scanline < cinfo.output_height) {
/* jpeg_read_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could ask for
* more than one scanline at a time if that's more convenient.
*/
jpeg_read_scanlines(&cinfo, buffer, 1);
/* Assume put_scanline_someplace wants a pointer and sample count. */
// put_scanline_someplace(buffer[0], row_stride);
if (cinfo.output_components==3)
{
int x;
for (x = 0; x < (int)cinfo.output_width; x++)
{
bmpptr[x]=LICE_RGBA(buffer[0][x*3],buffer[0][x*3+1],buffer[0][x*3+2],255);
}
}
else if (cinfo.output_components==1)
{
int x;
for (x = 0; x < (int)cinfo.output_width; x++)
{
int v=buffer[0][x];
bmpptr[x]=LICE_RGBA(v,v,v,255);
}
}
else
memset(bmpptr,0,4*cinfo.output_width);
bmpptr+=dbmpptr;
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(fp);
return bmp;
}
LICE_IBitmap *LICE_LoadJPGFromMemory(const void *data_in, int buflen, LICE_IBitmap *bmp)
{
if (buflen < 8) return NULL;
unsigned char *data = (unsigned char *)(void *)data_in;
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr={{0},};
JSAMPARRAY buffer;
int row_stride;
jerr.pub.error_exit = LICEJPEG_Error;
jerr.pub.emit_message = LICEJPEG_EmitMsg;
jerr.pub.output_message = LICEJPEG_OutMsg;
jerr.pub.format_message = LICEJPEG_FmtMsg;
jerr.pub.reset_error_mgr = LICEJPEG_reset_error_mgr;
cinfo.err = &jerr.pub;
if (setjmp(jerr.setjmp_buffer))
{
jpeg_destroy_decompress(&cinfo);
return 0;
}
jpeg_create_decompress(&cinfo);
jpeg_mem_src(&cinfo, data, buflen);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
row_stride = cinfo.output_width * cinfo.output_components;
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
LICE_IBitmap *delbmp = NULL;
if (bmp) bmp->resize(cinfo.output_width,cinfo.output_height);
else delbmp = bmp = new WDL_NEW LICE_MemBitmap(cinfo.output_width,cinfo.output_height);
if (!bmp || bmp->getWidth() != (int)cinfo.output_width || bmp->getHeight() != (int)cinfo.output_height)
{
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
delete delbmp;
return 0;
}
LICE_pixel *bmpptr = bmp->getBits();
int dbmpptr=bmp->getRowSpan();
if (bmp->isFlipped())
{
bmpptr += dbmpptr*(bmp->getHeight()-1);
dbmpptr=-dbmpptr;
}
while (cinfo.output_scanline < cinfo.output_height) {
/* jpeg_read_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could ask for
* more than one scanline at a time if that's more convenient.
*/
jpeg_read_scanlines(&cinfo, buffer, 1);
/* Assume put_scanline_someplace wants a pointer and sample count. */
// put_scanline_someplace(buffer[0], row_stride);
if (cinfo.output_components==3)
{
int x;
for (x = 0; x < (int)cinfo.output_width; x++)
{
bmpptr[x]=LICE_RGBA(buffer[0][x*3],buffer[0][x*3+1],buffer[0][x*3+2],255);
}
}
else if (cinfo.output_components==1)
{
int x;
for (x = 0; x < (int)cinfo.output_width; x++)
{
int v=buffer[0][x];
bmpptr[x]=LICE_RGBA(v,v,v,255);
}
}
else
memset(bmpptr,0,4*cinfo.output_width);
bmpptr+=dbmpptr;
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return bmp;
}
class LICE_JPGLoader
{
public:
_LICE_ImageLoader_rec rec;
LICE_JPGLoader()
{
rec.loadfunc = loadfunc;
rec.get_extlist = get_extlist;
rec._next = LICE_ImageLoader_list;
LICE_ImageLoader_list = &rec;
}
static LICE_IBitmap *loadfunc(const char *filename, bool checkFileName, LICE_IBitmap *bmpbase)
{
if (checkFileName)
{
const char *p=filename;
while (*p)p++;
while (p>filename && *p != '\\' && *p != '/' && *p != '.') p--;
if (stricmp(p,".jpg")&&stricmp(p,".jpeg")&&stricmp(p,".jfif")) return 0;
}
return LICE_LoadJPG(filename,bmpbase);
}
static const char *get_extlist()
{
return "JPEG files (*.JPG;*.JPEG;*.JFIF)\0*.JPG;*.JPEG;*.JFIF\0";
}
};
LICE_JPGLoader LICE_jgpldr;

View File

@@ -0,0 +1,119 @@
/*
Cockos WDL - LICE - Lightweight Image Compositing Engine
Copyright (C) 2007 and later, Cockos Incorporated
File: lice_jpg_write.cpp (JPG writing for LICE)
See lice.h for license and other information
*/
#include <stdio.h>
#include "lice.h"
#include <setjmp.h>
extern "C" {
#include "../jpeglib/jpeglib.h"
};
struct my_error_mgr {
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
static void LICEJPEG_Error(j_common_ptr cinfo)
{
longjmp(((my_error_mgr*)cinfo->err)->setjmp_buffer,1);
}
static void LICEJPEG_EmitMsg(j_common_ptr cinfo, int msg_level) { }
static void LICEJPEG_FmtMsg(j_common_ptr cinfo, char *) { }
static void LICEJPEG_OutMsg(j_common_ptr cinfo) { }
static void LICEJPEG_reset_error_mgr(j_common_ptr cinfo)
{
cinfo->err->num_warnings = 0;
cinfo->err->msg_code = 0;
}
bool LICE_WriteJPG(const char *filename, LICE_IBitmap *bmp, int quality, bool force_baseline)
{
if (!bmp || !filename) return false;
FILE *fp=NULL;
#if defined(_WIN32) && !defined(WDL_NO_SUPPORT_UTF8)
#ifdef WDL_SUPPORT_WIN9X
if (GetVersion()<0x80000000)
#endif
{
WCHAR wf[2048];
if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,wf,2048))
fp = _wfopen(wf,L"wb");
}
#endif
if (!fp) fp = fopen(filename,"wb");
if (!fp) return false;
struct jpeg_compress_struct cinfo;
struct my_error_mgr jerr={0,};
jerr.pub.error_exit = LICEJPEG_Error;
jerr.pub.emit_message = LICEJPEG_EmitMsg;
jerr.pub.output_message = LICEJPEG_OutMsg;
jerr.pub.format_message = LICEJPEG_FmtMsg;
jerr.pub.reset_error_mgr = LICEJPEG_reset_error_mgr;
cinfo.err = &jerr.pub;
unsigned char *buf = NULL;
if (setjmp(jerr.setjmp_buffer))
{
jpeg_destroy_compress(&cinfo);
if (fp) fclose(fp);
free(buf);
return false;
}
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, fp);
cinfo.image_width = bmp->getWidth(); /* image width and height, in pixels */
cinfo.image_height = bmp->getHeight();
cinfo.input_components = 3; /* # of color components per pixel */
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, !!force_baseline);
jpeg_start_compress(&cinfo, TRUE);
buf = (unsigned char *)malloc(cinfo.image_width * 3);
LICE_pixel_chan *rd = (LICE_pixel_chan *)bmp->getBits();
int rowspan = bmp->getRowSpan()*4;
if (bmp->isFlipped())
{
rd += rowspan*(bmp->getHeight()-1);
rowspan=-rowspan;
}
while (cinfo.next_scanline < cinfo.image_height)
{
unsigned char *outp=buf;
LICE_pixel_chan *rdp = rd;
int x=cinfo.image_width;
while(x--)
{
outp[0] = rdp[LICE_PIXEL_R];
outp[1] = rdp[LICE_PIXEL_G];
outp[2] = rdp[LICE_PIXEL_B];
outp+=3;
rdp+=4;
}
jpeg_write_scanlines(&cinfo, &buf, 1);
rd+=rowspan;
}
free(buf);
buf=0;
jpeg_finish_compress(&cinfo);
if (fp) fclose(fp);
fp=0;
jpeg_destroy_compress(&cinfo);
return true;
}

View File

@@ -0,0 +1,673 @@
#include <stdio.h>
#include <stdlib.h>
#include "lice_lcf.h"
#include "../filewrite.h"
#include "../fileread.h"
#define LCF_VERSION 0x11CEb001
LICECaptureCompressor::LICECaptureCompressor(const char *outfn, int w, int h, int interval, int bsize_w, int bsize_h)
{
m_inframes = m_outframes=0;
m_file = new WDL_FileWrite(outfn,1,512*1024);
if (!m_file->IsOpen()) { delete m_file; m_file=0; }
memset(&m_compstream,0,sizeof(m_compstream));
if (m_file)
{
if (deflateInit(&m_compstream,9)!=Z_OK)
{
delete m_file;
m_file=0;
}
}
m_inbytes=0;
m_outsize=0;
m_w=w;
m_h=h;
m_interval=interval;
m_bsize_w=bsize_w;
m_bsize_h=bsize_h;
m_state=0;
m_which=0;
m_outchunkpos=0;
m_numcols = (m_w+bsize_w-1) / (bsize_w>0?bsize_w:1);
if (m_numcols<1) m_numcols=1;
m_numrows = (m_h+bsize_h-1)/ (bsize_h>0?bsize_h:1);
m_current_block_srcsize=0;
}
void LICECaptureCompressor::OnFrame(LICE_IBitmap *fr, int delta_t_ms)
{
if (fr)
{
if (fr->getWidth()!=m_w || fr->getHeight()!=m_h) return;
frameRec *rec = m_framelists[m_which].Get(m_state);
if (!rec)
{
rec = new frameRec(m_w*m_h);
m_framelists[m_which].Add(rec);
}
rec->delta_t_ms=delta_t_ms;
BitmapToFrameRec(fr,rec);
m_state++;
m_inframes++;
}
bool isLastBlock = m_state >= m_interval || !fr;
if (m_framelists[!m_which].GetSize())
{
int compressTo;
if (isLastBlock) compressTo = m_numcols*m_numrows;
else compressTo = (m_state * m_numcols*m_numrows) / m_interval;
frameRec **list = m_framelists[!m_which].GetList();
int list_size = m_framelists[!m_which].GetSize();
// compress some data
int chunkpos = m_outchunkpos;
while (chunkpos < compressTo)
{
int xpos = (chunkpos%m_numcols) * m_bsize_w;
int ypos = (chunkpos/m_numcols) * m_bsize_h;
int wid = m_w-xpos;
int hei = m_h-ypos;
if (wid > m_bsize_w) wid=m_bsize_w;
if (hei > m_bsize_h) hei=m_bsize_h;
int i;
int rdoffs = xpos + ypos*m_w;
int rdspan = m_w;
int repeat_cnt=0;
for(i=0;i<list_size; i++)
{
unsigned short *rd = list[i]->data + rdoffs;
if (i&&repeat_cnt<255)
{
unsigned short *rd1=rd;
unsigned short *rd2=list[i-1]->data+rdoffs;
int a=hei;
while(a--)
{
if (memcmp(rd1,rd2,wid*sizeof(short))) break;
rd1+=rdspan;
rd2+=rdspan;
}
if (a<0)
{
repeat_cnt++;
continue;
}
}
if (i || repeat_cnt)
{
unsigned char c = (unsigned char)repeat_cnt;
DeflateBlock(&c,1,false);
repeat_cnt=0;
}
int a=hei;
while (a--)
{
DeflateBlock(rd,wid*sizeof(short),false);
rd+=rdspan;
}
}
if (repeat_cnt)
{
unsigned char c = (unsigned char)repeat_cnt;
DeflateBlock(&c,1,false);
}
chunkpos++;
}
m_outchunkpos=chunkpos;
}
if (isLastBlock)
{
if (m_framelists[!m_which].GetSize())
{
m_outframes += m_framelists[!m_which].GetSize();
DeflateBlock(NULL,0,true);
deflateReset(&m_compstream);
m_hdrqueue.Clear();
AddHdrInt(LCF_VERSION);
AddHdrInt(16);
AddHdrInt(m_w);
AddHdrInt(m_h);
AddHdrInt(m_bsize_w);
AddHdrInt(m_bsize_h);
int nf = m_framelists[!m_which].GetSize();
AddHdrInt(nf);
int sz = m_current_block.Available();
AddHdrInt(sz);
int uncomp_sz = m_current_block_srcsize;
AddHdrInt(uncomp_sz);
{
int x;
for(x=0;x<nf;x++)
{
AddHdrInt(m_framelists[!m_which].Get(x)->delta_t_ms);
}
}
m_file->Write(m_hdrqueue.Get(),m_hdrqueue.Available());
m_outsize += m_hdrqueue.Available();
m_file->Write(m_current_block.Get(),sz);
m_outsize += sz;
m_current_block.Clear();
m_current_block_srcsize=0;
}
int old_state=m_state;
m_state=0;
m_outchunkpos=0;
m_which=!m_which;
if (old_state>0 && !fr)
{
while (m_framelists[!m_which].GetSize() > old_state)
m_framelists[!m_which].Delete(m_framelists[!m_which].GetSize()-1,true);
OnFrame(NULL,0);
}
if (!fr)
{
m_framelists[0].Empty(true);
m_framelists[1].Empty(true);
}
}
}
void LICECaptureCompressor::BitmapToFrameRec(LICE_IBitmap *fr, frameRec *dest)
{
unsigned short *outptr = dest->data;
const LICE_pixel *p = fr->getBits();
int span = fr->getRowSpan();
if (fr->isFlipped())
{
p+=(fr->getHeight()-1)*span;
span=-span;
}
int h = fr->getHeight(),w=fr->getWidth();
while (h--)
{
int x=w;
const LICE_pixel *sp = p;
while (x--)
{
LICE_pixel pix = *sp++;
*outptr++ = (((int)LICE_GETR(pix)&0xF8)>>3) | (((int)LICE_GETG(pix)&0xFC)<<3) | (((int)LICE_GETB(pix)&0xF8)<<8);
}
p += span;
}
}
void LICECaptureCompressor::DeflateBlock(void *data, int data_size, bool flush)
{
m_current_block_srcsize += data_size;
m_inbytes += data_size;
int bytesout=0;
m_compstream.next_in = (unsigned char *)data;
m_compstream.avail_in = data_size;
for (;;)
{
int add_sz = data_size+32768;
m_compstream.next_out = (unsigned char *)m_current_block.Add(NULL,add_sz);
m_compstream.avail_out = add_sz;
int e = deflate(&m_compstream,flush?Z_FULL_FLUSH:Z_NO_FLUSH);
m_current_block.Add(NULL,-(int)m_compstream.avail_out);
bytesout+=add_sz-m_compstream.avail_out;
if (e != Z_OK)
{
break;
}
if (!m_compstream.avail_in && (!flush || add_sz==(int)m_compstream.avail_out)) break;
}
m_outsize += bytesout;
}
LICECaptureCompressor::~LICECaptureCompressor()
{
// process any pending frames
if (m_file)
{
OnFrame(NULL,0);
deflateEnd(&m_compstream);
}
delete m_file;
m_framelists[0].Empty(true);
m_framelists[1].Empty(true);
}
//////////////////////////////////////////
///////DECOMPRESS
//////////////////////////////////////////
LICECaptureDecompressor::LICECaptureDecompressor(const char *fn, bool want_seekable) : m_workbm(0,0,1)
{
m_bytes_read=0;
m_file_length_ms=0;
m_rd_which=0;
m_frameidx=0;
memset(&m_compstream,0,sizeof(m_compstream));
memset(&m_curhdr,0,sizeof(m_curhdr));
m_file = new WDL_FileRead(fn,2,1024*1024);
if (m_file->IsOpen())
{
if (inflateInit(&m_compstream)!=Z_OK)
{
delete m_file;
m_file=0;
}
if (m_file)
{
m_file_frame_info.Clear();
m_file_length_ms=0;
if (want_seekable)
{
unsigned int lastpos = 0;
int first_frame_delay = 0;
while (ReadHdr(0))
{
m_file_frame_info.Add(&lastpos,1);
unsigned int mst = m_file_length_ms;
if (m_frame_deltas[0].GetSize())
{
if (lastpos > 0)
mst += m_frame_deltas[0].Get()[0]-first_frame_delay; // TOC is by time of first frames, ignore first delay when seeking
else
first_frame_delay = m_frame_deltas[0].Get()[0];
}
m_file_frame_info.Add(&mst,1);
int x;
for(x=0;x<m_frame_deltas[0].GetSize();x++)
{
m_file_length_ms+=m_frame_deltas[0].Get()[x];
}
m_file->SetPosition(lastpos = (unsigned int)(m_file->GetPosition() + m_curhdr[0].cdata_left));
}
}
Seek(0);
}
}
if (m_curhdr[m_rd_which].bpp!=16)
{
delete m_file;
m_file=0;
}
}
LICECaptureDecompressor::~LICECaptureDecompressor()
{
inflateEnd(&m_compstream);
delete m_file;
}
bool LICECaptureDecompressor::NextFrame() // TRUE if out of frames
{
if (++m_frameidx >= m_frame_deltas[m_rd_which].GetSize())
{
m_rd_which=!m_rd_which;
DecompressBlock(m_rd_which,1.0);
if (!ReadHdr(!m_rd_which))
memset(&m_curhdr[!m_rd_which],0,sizeof(m_curhdr[!m_rd_which]));
m_frameidx=0;
if (!m_curhdr[m_rd_which].bpp) return false;
DecodeSlices();
}
else
DecompressBlock(!m_rd_which,m_frameidx/(double)m_frame_deltas[m_rd_which].GetSize());
return false;
}
int LICECaptureDecompressor::Seek(unsigned int offset_ms)
{
memset(m_curhdr,0,sizeof(m_curhdr));
if (!m_file) return -1;
int rval=0;
unsigned int seekpos=0;
m_frameidx=0;
if (offset_ms>0&&m_file_frame_info.GetSize())
{
int x;
for(x=0;x<m_file_frame_info.GetSize()-2;x+=2)
{
if (offset_ms < m_file_frame_info.Get()[x+2+1]) break;
}
seekpos = m_file_frame_info.Get()[x];
offset_ms -= m_file_frame_info.Get()[x+1];
// figure out the best place to seek
}
else
{
if (offset_ms>0) rval=-1;
offset_ms=0;
}
m_rd_which=0;
m_file->SetPosition(seekpos);
if (!ReadHdr(m_rd_which)||!DecompressBlock(m_rd_which,1.0))
{
rval=-1;
memset(&m_curhdr,0,sizeof(m_curhdr));
}
else
{
if (offset_ms>0 && rval==0)
{
int x;
for (x = 1; x < m_frame_deltas[m_rd_which].GetSize(); x++)
{
if (offset_ms < m_frame_deltas[m_rd_which].Get()[x])
{
rval = offset_ms;
break;
}
offset_ms -= m_frame_deltas[m_rd_which].Get()[x];
}
m_frameidx=x-1;
}
if (!ReadHdr(!m_rd_which))
memset(&m_curhdr[!m_rd_which],0,sizeof(m_curhdr[!m_rd_which]));
DecodeSlices();
}
return rval;
}
bool LICECaptureDecompressor::ReadHdr(int whdr) // todo: eventually make this read/decompress the next header as it goes
{
m_tmp.Clear();
int hdr_sz = (4*9);
if (m_file->Read(m_tmp.Add(NULL,hdr_sz),hdr_sz)!=hdr_sz) return false;
m_bytes_read+=hdr_sz;
int ver=0;
m_tmp.GetTFromLE(&ver);
if (ver !=LCF_VERSION) return false;
m_tmp.GetTFromLE(&m_curhdr[whdr].bpp);
m_tmp.GetTFromLE(&m_curhdr[whdr].w);
m_tmp.GetTFromLE(&m_curhdr[whdr].h);
m_tmp.GetTFromLE(&m_curhdr[whdr].bsize_w);
m_tmp.GetTFromLE(&m_curhdr[whdr].bsize_h);
int nf=0;
m_tmp.GetTFromLE(&nf);
int csize=0;
m_tmp.GetTFromLE(&csize);
int dsize=0;
m_tmp.GetTFromLE(&dsize);
if (nf<1 || nf > 1024) return false;
m_frame_deltas[whdr].Resize(nf);
if (m_frame_deltas[whdr].GetSize()!=nf) return false;
if (m_file->Read(m_frame_deltas[whdr].Get(),nf*4)!=nf*4) return false;
m_bytes_read+=nf*4;
int x;
for(x=0;x<nf;x++)
{
WDL_Queue::WDL_Queue__bswap_buffer(m_frame_deltas[whdr].Get()+x,4);
}
m_curhdr[whdr].cdata_left = csize;
inflateReset(&m_compstream);
m_compstream.avail_out = dsize;
m_compstream.next_out = (unsigned char *)m_decompdata[whdr].Resize(dsize,false);
if (m_decompdata[whdr].GetSize()!=dsize) return false;
return true;
}
bool LICECaptureDecompressor::DecompressBlock(int whdr, double percent)
{
if (m_compstream.avail_out)
{
unsigned char buf[16384];
for (;;)
{
if (percent<1.0&&m_decompdata[whdr].GetSize())
{
double p = ((m_decompdata[whdr].GetSize()-m_compstream.avail_out)/(double)m_decompdata[whdr].GetSize());
if (p>percent) break;
}
m_compstream.next_in = buf;
m_compstream.avail_in = m_curhdr[whdr].cdata_left;
if (m_compstream.avail_in > (int)sizeof(buf)) m_compstream.avail_in=(int)sizeof(buf);
m_compstream.avail_in = m_file->Read(buf,m_compstream.avail_in);
m_bytes_read+=m_compstream.avail_in;
m_curhdr[whdr].cdata_left -= m_compstream.avail_in;
int e = inflate(&m_compstream,0);
if (e != Z_OK&&e!=Z_STREAM_END)
{
// printf("inflate error: %d (%d/%d)\n",e,m_compstream.avail_in, m_curhdr[whdr].cdata_left);
return !m_compstream.avail_out;
}
if (!m_compstream.avail_out && !m_compstream.avail_in) break;
}
m_compstream.next_in = NULL;
}
return true;
}
int LICECaptureDecompressor::GetTimeToNextFrame()
{
int nf = m_frame_deltas[m_rd_which].GetSize();
int fidx = m_frameidx;
if (fidx<0&& nf) return m_frame_deltas[m_rd_which].Get()[0];
if (fidx+1 < nf) return m_frame_deltas[m_rd_which].Get()[fidx+1];
if (m_curhdr[!m_rd_which].bpp && m_frame_deltas[!m_rd_which].GetSize())
return m_frame_deltas[!m_rd_which].Get()[0];
return 100;
}
void LICECaptureDecompressor::DecodeSlices()
{
int nf = m_frame_deltas[m_rd_which].GetSize();
unsigned char *sp = (unsigned char *)m_decompdata[m_rd_which].Get();
int sp_left = m_decompdata[m_rd_which].GetSize();
hdrType *hdr = m_curhdr+m_rd_which;
int ns_x = (hdr->w + hdr->bsize_w-1)/hdr->bsize_w;
int ns_y = (hdr->h + hdr->bsize_h-1)/hdr->bsize_h;
int ns_frame = ns_x*ns_y;
void **slicelist = m_slices.Resize(nf * ns_frame);
// format of sp is:
// nf slices
// each slice is :
// initial value
// repeat cnt
// frame
// repeat cnt
// ..
int ypos,
toth=hdr->h,
totw=hdr->w;
int bytespersample = (hdr->bpp+7)/8;
for (ypos = 0; ypos < toth; ypos+=hdr->bsize_h)
{
int hei = toth-ypos;
if (hei>hdr->bsize_h) hei=hdr->bsize_h;
int xpos;
for (xpos=0; xpos<totw; xpos+=hdr->bsize_w)
{
int wid = totw-xpos;
if (wid>hdr->bsize_w) wid=hdr->bsize_w;
int sz1=wid*hei*bytespersample;
int slicewritepos = 0,i = 0;
void *lvalid = NULL;
while (i<nf&&sp_left>0)
{
if (lvalid)
{
unsigned char c = *sp++;
sp_left--;
while (c-->0 && i++ < nf)
{
// repeat last slice
slicelist[slicewritepos] = lvalid;
slicewritepos += ns_frame;
}
}
if (i<nf)
{
lvalid = slicelist[slicewritepos] = sp;
slicewritepos += ns_frame;
sp += sz1;
sp_left -= sz1;
i++;
}
}
if( sp_left < 0)
{
m_slices.Resize(0);
return;
}
slicelist++;
}
}
}
LICE_IBitmap *LICECaptureDecompressor::GetCurrentFrame()
{
int nf = m_frame_deltas[m_rd_which].GetSize();
int fidx = m_frameidx;
hdrType *hdr = m_curhdr+m_rd_which;
if (fidx >=0 && fidx < nf && m_slices.GetSize() && hdr->bsize_w && hdr->bsize_h)
{
int ns_x = (hdr->w + hdr->bsize_w-1)/hdr->bsize_w;
int ns_y = (hdr->h + hdr->bsize_h-1)/hdr->bsize_h;
int ns_frame = ns_x*ns_y;
if (m_slices.GetSize() != ns_frame*nf)
return NULL; // invalid slices
if (hdr->bpp == 16)
{
m_workbm.resize(hdr->w,hdr->h);
//unsigned short *
// format of m_decompdata is:
// nf frames of slice1, nf frames of slice2, etc
LICE_pixel *pout = m_workbm.getBits();
int span = m_workbm.getRowSpan();
int ypos,
toth=hdr->h,
totw=hdr->w;
void **sliceptr = m_slices.Get() + ns_frame * fidx;
for (ypos = 0; ypos < toth; ypos+=hdr->bsize_h)
{
int hei = toth-ypos;
if (hei>hdr->bsize_h) hei=hdr->bsize_h;
int xpos;
for (xpos=0; xpos<totw; xpos+=hdr->bsize_w)
{
int wid = totw-xpos;
if (wid>hdr->bsize_w) wid=hdr->bsize_w;
unsigned short *rdptr = (unsigned short *)*sliceptr;
sliceptr++;
LICE_pixel *dest = pout + xpos + ypos*span;
int y;
for (y=0;y<hei;y++)
{
int x=wid;
LICE_pixel *wr = dest;
while (x--)
{
unsigned short px = *rdptr++;
*wr++ = LICE_RGBA((px<<3)&0xF8,(px>>3)&0xFC,(px>>8)&0xF8,255);
}
dest+=span;
}
}
}
return &m_workbm;
}
}
return NULL;
}

View File

@@ -0,0 +1,111 @@
#ifndef _LICE_LCF_H_
#define _LICE_LCF_H_
#include "../zlib/zlib.h"
#include "lice.h"
#include "../ptrlist.h"
#include "../queue.h"
class WDL_FileWrite;
class WDL_FileRead;
class LICECaptureCompressor
{
public:
LICECaptureCompressor(const char *outfn, int w, int h, int interval=20, int bsize_w=128, int bsize_h=16);
~LICECaptureCompressor();
bool IsOpen() { return !!m_file; }
void OnFrame(LICE_IBitmap *fr, int delta_t_ms);
WDL_INT64 GetOutSize() { return m_outsize; }
WDL_INT64 GetInSize() { return m_inbytes; }
private:
WDL_FileWrite *m_file;
WDL_INT64 m_outsize,m_inbytes;
int m_inframes, m_outframes;
int m_w,m_h,m_interval,m_bsize_w,m_bsize_h;
struct frameRec
{
frameRec(int sz) { data=(unsigned short *)malloc(sz*sizeof(short)); delta_t_ms=0; }
~frameRec() { free(data); }
unsigned short *data; // shorts
int delta_t_ms; // time (ms) since last frame
};
WDL_PtrList<frameRec> m_framelists[2];
WDL_Queue m_current_block;
WDL_Queue m_hdrqueue;
int m_state, m_which,m_outchunkpos,m_numrows,m_numcols;
int m_current_block_srcsize;
z_stream m_compstream;
void BitmapToFrameRec(LICE_IBitmap *fr, frameRec *dest);
void DeflateBlock(void *data, int data_size, bool flush);
void AddHdrInt(int a) { m_hdrqueue.AddToLE(&a); }
};
class LICECaptureDecompressor
{
public:
LICECaptureDecompressor(const char *fn, bool want_seekable=false);
~LICECaptureDecompressor();
bool IsOpen() { return !!m_file; }
// only supported if want_seekable=true
int GetLength() { return m_file_length_ms; } // length in ms
int Seek(unsigned int offset_ms); // return -1 on fail (out of range), or >0 to tell you how far into the frame you seeked (0=exact hit)
bool NextFrame(); // TRUE if out of frames
LICE_IBitmap *GetCurrentFrame(); // can return NULL if error
int GetTimeToNextFrame(); // delta in ms
int GetWidth(){ return m_curhdr[m_rd_which].w; }
int GetHeight(){ return m_curhdr[m_rd_which].h; }
int m_bytes_read; // increases for statistics, caller can clear
private:
LICE_MemBitmap m_workbm;
struct hdrType
{
int bpp;
int w, h;
int bsize_w, bsize_h;
int cdata_left;
} m_curhdr[2];
int m_rd_which;
int m_frameidx;
bool ReadHdr(int whdr);
bool DecompressBlock(int whdr, double percent=1.0);
z_stream m_compstream;
WDL_Queue m_tmp;
WDL_FileRead *m_file;
unsigned int m_file_length_ms;
WDL_TypedQueue<unsigned int> m_file_frame_info; //pairs of offset_bytes, offset_ms
WDL_TypedBuf<int> m_frame_deltas[2];
WDL_HeapBuf m_decompdata[2];
WDL_TypedBuf<void *> m_slices; // indexed by [frame][slice]
void DecodeSlices();
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,625 @@
#ifndef WDL_NO_DEFINE_MINMAX
#define WDL_NO_DEFINE_MINMAX
#endif
#include "lice.h"
#include <stdio.h>
#include <math.h>
#include "../projectcontext.h"
#include "../lineparse.h"
#include "../ptrlist.h"
#include "../assocarray.h"
#define PI 3.1415926535897932384626433832795
static inline int chartohex(char c)
{
if (c >= '0' && c<='9') return c-'0';
else if (c>='A' && c<='F') return 10 + c - 'A';
else if (c>='a' && c<='f') return 10 + c - 'a';
return -1;
}
static int __boolval(const char *p, int defval)
{
if (!stricmp(p,"yes") ||
!stricmp(p,"true") ||
!stricmp(p,"on") ||
atoi(p)>0) return 1;
if (!stricmp(p,"no") ||
!stricmp(p,"false") ||
!stricmp(p,"off") ||
!stricmp(p,"0")) return 0;
return defval;
}
static LICE_pixel __colorval(const char *p, LICE_pixel def)
{
const size_t lp = strlen(p);
if (lp == 3)
{
int r = chartohex(p[0]);
int g = chartohex(p[1]);
int b = chartohex(p[2]);
if (r>=0&&g>=0&&b>=0)
def = LICE_RGBA(r+(r<<4),g+(g<<4),b+(b<<4),255);
}
else if (lp == 6||lp==8)
{
int r = chartohex(p[0]), r2 = chartohex(p[1]);
int g = chartohex(p[2]), g2 = chartohex(p[3]);
int b = chartohex(p[4]), b2 = chartohex(p[5]);
int a = 0xf, a2=0xf;
if (lp==8) { a=chartohex(p[6]); a2=chartohex(p[7]); }
if (r>=0&&g>=0&&b>=0&&r2>=0&&g2>=0&&b2>=0&&a>=0&&a2>=0)
def = LICE_RGBA((r<<4)+r2,(g<<4)+g2,(b<<4)+b2,(a<<4)+a2);
}
return def;
}
class lvgRenderState
{
public:
lvgRenderState()
{
m_color=LICE_RGBA(255,255,255,255);
m_alpha=1.0f;
m_blend = LICE_BLIT_MODE_COPY;
m_aa = false;
}
~lvgRenderState() { }
LICE_pixel m_color;
float m_alpha;
int m_blend;
bool m_aa;
WDL_TypedBuf<bool> m_aa_stack;
WDL_TypedBuf<float> m_alpha_stack;
WDL_TypedBuf<LICE_pixel> m_color_stack;
WDL_TypedBuf<int> m_blend_stack;
/////////
void parsealpha(const char *p)
{
int idx=0;
if (*p == '-') idx++;
if (p[idx] == '.' || (p[idx] >= '0' && p[idx] <= '9'))
m_alpha = (float)atof(p);
}
void parseaa(const char *p)
{
int a = __boolval(p,-1);
if (a>=0) m_aa = !!a;
}
void parseblend(const char *p)
{
if (!stricmp(p,"copy")) m_blend = LICE_BLIT_MODE_COPY;
else if (!stricmp(p,"add")) m_blend = LICE_BLIT_MODE_ADD;
else if (!stricmp(p,"dodge")) m_blend = LICE_BLIT_MODE_DODGE;
else if (!stricmp(p,"mul")||!stricmp(p,"multiply")) m_blend = LICE_BLIT_MODE_MUL;
else if (!stricmp(p,"overlay")) m_blend = LICE_BLIT_MODE_MUL;
else if (!stricmp(p,"hsvadj")) m_blend = LICE_BLIT_MODE_HSVADJ;
}
void parsecolor(const char *p)
{
m_color = __colorval(p,m_color);
}
#define DEF_PUSHPOP(name,defpopval) \
void push##name() { int sz=m_##name##_stack.GetSize(); m_##name##_stack.Resize(sz+1,false)[sz] = m_##name; } \
void pop##name() { int sz = m_##name##_stack.GetSize()-1; m_##name = sz>=0 ? m_##name##_stack.Get()[sz] : defpopval; m_##name##_stack.Resize(sz,false); }
DEF_PUSHPOP(color,LICE_RGBA(0,0,0,255))
DEF_PUSHPOP(alpha,1.0f)
DEF_PUSHPOP(aa,false)
DEF_PUSHPOP(blend,LICE_BLIT_MODE_COPY)
#undef DEF_PUSHPOP
bool processAttributeLine(LineParser *lp)
{
int i,numtok=lp->getnumtokens();
switch (lp->gettoken_enum(0,"color\0"
"alpha\0"
"aa\0"
"blend\0"
"\0"))
{
#define PROCTYPE(v,name) \
case v: for (i=1;i<numtok;i++) { \
const char *p = lp->gettoken_str(i); \
if (!stricmp(p,"push")) push##name(); \
else if (!stricmp(p,"pop")) pop##name(); \
else parse##name(p); \
} \
return true;
PROCTYPE(0,color)
PROCTYPE(1,alpha)
PROCTYPE(2,aa)
PROCTYPE(3,blend)
#undef PROCTYPE
}
return false;
}
};
class lvgImageCtx
{
public:
lvgImageCtx(lvgImageCtx *par) : m_images(true,deleteThis)
{
m_in_render=false;
m_par=par;
m_cachedImage=0;
m_base_w=0;
m_base_h=0;
}
~lvgImageCtx()
{
delete m_cachedImage;
m_lines.Empty(true,free);
}
WDL_PtrList<char> m_lines;
LICE_IBitmap *m_cachedImage;
lvgImageCtx *m_par;
WDL_StringKeyedArray<lvgImageCtx *> m_images;
int m_base_w,m_base_h;
bool m_in_render;
void render(lvgRenderState *rstate, int wantw, int wanth);
private:
static void deleteThis(lvgImageCtx *t) { delete t; }
double parsecoord(const char *p, double scale, bool round)
{
if (!*p) return 0;
if (p[0] == 'a' && p[1]) return atoi(p+1);
if (p[0] == 'w')
{
scale = m_cachedImage ? m_cachedImage->getWidth() : 0.0;
p++;
}
else if (p[0] == 'h')
{
scale = m_cachedImage ? m_cachedImage->getHeight() : 0.0;
p++;
}
return atof(p) * scale + (round ? 0.5 : 0.0);
}
void processLvgLine(LineParser *lp, lvgRenderState *state, LICE_IBitmap *bm, double xscale, double yscale);
};
#define DECL_OPT(type, cfunc) \
static type getoption_##type(LineParser *lp, int startidx, const char *name, type def) { \
const size_t namelen = strlen(name); \
for(;startidx<lp->getnumtokens();startidx++) { \
const char *p=lp->gettoken_str(startidx); \
if (!strnicmp(name,p,namelen) && p[namelen]=='=') return cfunc(p+namelen+1,def); \
} \
return def; \
}
static int __intval(const char *p, int def) { return atoi(p); }
static double __dblval(const char *p, double def) { return atof(p); }
DECL_OPT(bool,!!__boolval)
DECL_OPT(int,__intval)
DECL_OPT(double,__dblval)
DECL_OPT(LICE_pixel,__colorval)
#undef DECL_OPT
void lvgImageCtx::processLvgLine(LineParser *lp, lvgRenderState *state, LICE_IBitmap *bm, double xscale, double yscale)
{
if (state->processAttributeLine(lp)) return;
int numtok = lp->getnumtokens();
const char *tok = lp->gettoken_str(0);
if (!stricmp(tok,"line"))
{
int i;
float lx,ly;
for (i = 1; i < numtok-1; i+= 2)
{
const char *p=lp->gettoken_str(i);
if (strstr(p,"=")) break;
float x=(float)parsecoord(p,xscale,false);
p=lp->gettoken_str(i+1);
if (strstr(p,"=")) break;
float y=(float)parsecoord(p,yscale,false);
if (i!=1) LICE_FLine(bm,lx,ly,x,y,state->m_color,state->m_alpha,state->m_blend,state->m_aa);
lx=x;
ly=y;
}
}
else if (!stricmp(tok,"circle"))
{
if (numtok>=4)
{
float x=(float)parsecoord(lp->gettoken_str(1),xscale,false);
float y=(float)parsecoord(lp->gettoken_str(2),yscale,false);
float r=(float)(atof(lp->gettoken_str(3))*lice_min(xscale,yscale));
if (getoption_bool(lp,1,"fill",false))
{
LICE_FillCircle(bm,x,y,r,state->m_color,state->m_alpha,state->m_blend,state->m_aa);
}
else
LICE_Circle(bm,x,y,r,state->m_color,state->m_alpha,state->m_blend,state->m_aa);
}
}
else if (!stricmp(tok,"arc"))
{
if (numtok>=6)
{
float x=(float)parsecoord(lp->gettoken_str(1),xscale,false);
float y=(float)parsecoord(lp->gettoken_str(2),yscale,false);
float r=(float)(atof(lp->gettoken_str(3))*lice_min(xscale,yscale));
float a1=(float)(atof(lp->gettoken_str(4))*PI/180.0);
float a2=(float)(atof(lp->gettoken_str(5))*PI/180.0);
LICE_Arc(bm,x,y,r,a1,a2,state->m_color,state->m_alpha,state->m_blend,state->m_aa);
}
}
else if (!stricmp(tok,"fill"))
{
if (numtok>=3) // fill x y [cmask=xxxxxx kmask=xxxxxxx]
{
LICE_pixel cmask = getoption_LICE_pixel(lp,1,"cmask",LICE_RGBA(255,255,255,0));
LICE_pixel kmask = getoption_LICE_pixel(lp,1,"kmask",LICE_RGBA(0,0,0,0));
int x = (int)parsecoord(lp->gettoken_str(1),xscale,true);
int y = (int)parsecoord(lp->gettoken_str(2),yscale,true);
LICE_SimpleFill(bm,x,y,state->m_color,cmask,kmask);
}
}
else if (!stricmp(tok,"rect"))
{
if (numtok>=5) // rect x y w h [dcdx=xxxxxxxx dcdy=xxxxxxxxx dcdxscale=1.0 dcdyscale=1.0]
{
LICE_pixel dcdx = getoption_LICE_pixel(lp,1,"dcdx",LICE_RGBA(0x80,0x80,0x80,0x80));
LICE_pixel dcdy = getoption_LICE_pixel(lp,1,"dcdy",LICE_RGBA(0x80,0x80,0x80,0x80));
double dcdxsc = getoption_double(lp,1,"dcdxscale",1.0);
double dcdysc = getoption_double(lp,1,"dcdyscale",1.0);
// todo: any options?
int x = (int)parsecoord(lp->gettoken_str(1),xscale,true);
int y = (int)parsecoord(lp->gettoken_str(2),yscale,true);
int w = (int)parsecoord(lp->gettoken_str(3),xscale,true);
int h = (int)parsecoord(lp->gettoken_str(4),yscale,true);
if (w>0 && h>0)
{
if (dcdx!=LICE_RGBA(0x80,0x80,0x80,0x80) ||
dcdy!=LICE_RGBA(0x80,0x80,0x80,0x80))
{
LICE_pixel sc = state->m_color;
dcdxsc /= w*128.0;
dcdysc /= h*128.0;
LICE_GradRect(bm,x,y,w,h,
(float)(LICE_GETR(sc)/255.0),
(float)(LICE_GETG(sc)/255.0),
(float)(LICE_GETB(sc)/255.0),
(float)(LICE_GETA(sc)/255.0*state->m_alpha),
(float)(((int)LICE_GETR(dcdx)-0x80)*dcdxsc),
(float)(((int)LICE_GETG(dcdx)-0x80)*dcdxsc),
(float)(((int)LICE_GETB(dcdx)-0x80)*dcdxsc),
(float)(((int)LICE_GETA(dcdx)-0x80)*dcdxsc),
(float)(((int)LICE_GETR(dcdy)-0x80)*dcdysc),
(float)(((int)LICE_GETG(dcdy)-0x80)*dcdysc),
(float)(((int)LICE_GETB(dcdy)-0x80)*dcdysc),
(float)(((int)LICE_GETA(dcdy)-0x80)*dcdysc),
state->m_blend);
}
else
LICE_FillRect(bm,x,y,w,h,state->m_color,state->m_alpha,state->m_blend);
}
}
}
else if (!stricmp(tok,"rerender"))
{
if (numtok>=2)
{
int forcew=getoption_int(lp,1,"w",0),forceh=getoption_int(lp,1,"h",0);
bool useState=getoption_bool(lp,1,"usestate",false);
lvgImageCtx *scan = this;
while (scan)
{
lvgImageCtx *p = scan->m_images.Get(lp->gettoken_str(1));
if (p)
{
if (!p->m_in_render)
{
p->m_in_render=true;
p->render(useState ? state : NULL,forcew,forceh);
p->m_in_render=false;
}
break;
}
scan=scan->m_par;
}
}
}
else if (!stricmp(tok,"blit"))
{
if (numtok>=3) // blit image x y [options]
{
LICE_IBitmap *src=NULL;
lvgImageCtx *scan = this;
const char *rd = lp->gettoken_str(1);
while (!strnicmp(rd,"parent:",7)) { scan = scan ? scan->m_par : NULL; rd += 7; }
if (!stricmp(rd,"parent"))
{
if (scan) scan=scan->m_par;
if (scan) src=scan->m_cachedImage;
}
else if (!stricmp(rd,"self"))
{
if (scan) src=scan->m_cachedImage;
}
else while (scan&&!src)
{
lvgImageCtx *p = scan->m_images.Get(rd);
if (p)
{
if (!p->m_cachedImage && !p->m_in_render)
{
p->m_in_render=true;
p->render(NULL,0,0);
p->m_in_render=false;
}
src = p->m_cachedImage;
break;
}
scan=scan->m_par;
}
if (src)
{
int x = (int)parsecoord(lp->gettoken_str(2),xscale,true);
int y = (int)parsecoord(lp->gettoken_str(3),yscale,true);
// these will be options filter= srcalpha= w= h= scale=
bool filter=getoption_bool(lp,1,"filter",true);
bool usesrcalpha = getoption_bool(lp,1,"srcalpha",true);
int w = getoption_int(lp,1,"w",src->getWidth());
int h = getoption_int(lp,1,"h",src->getHeight());
double sc = getoption_double(lp,1,"scale",1.0f);
if (fabs(sc-1.0)>0.0000000001)
{
w = (int)(w*sc+0.5);
h = (int)(h*sc+0.5);
}
// double ang = getoption_double(lp,1,"rotate",0.0) * PI / 180.0;
float sx=(float)getoption_double(lp,1,"srcx",0.0);
float sy=(float)getoption_double(lp,1,"srcy",0.0);
float sw=(float)getoption_double(lp,1,"srcw",src->getWidth());
float sh=(float)getoption_double(lp,1,"srch",src->getHeight());
// if (fabs(ang)>0.0001) LICE_RotatedBlit(bm,src,x,y,w,h,sx,sy,sw,sh,ang,true,state->m_alpha,state->m_blend,0,0);
//else
LICE_ScaledBlit(bm,src,x,y,w,h,sx,sy,sw,sh,
state->m_alpha,state->m_blend|(filter ? LICE_BLIT_FILTER_BILINEAR : 0)|(usesrcalpha ? LICE_BLIT_USE_ALPHA : 0));
}
}
}
}
void lvgImageCtx::render(lvgRenderState *rstate, int wantw, int wanth)
{
if (wantw<1) wantw = m_base_w;
if (wanth<1) wanth = m_base_h;
if (wantw<1||wanth<1)
{
if (m_cachedImage) m_cachedImage->resize(0,0);
return;
}
if (!m_cachedImage) m_cachedImage = new LICE_MemBitmap(wantw,wanth);
else m_cachedImage->resize(wantw,wanth);
LICE_Clear(m_cachedImage,LICE_RGBA(0,0,0,0));
lvgRenderState rs;
if (rstate) rs = *rstate;
double xscale = wantw / lice_max(m_base_w,1);
double yscale = wanth / lice_max(m_base_h,1);
int x;
bool comment_state=false;
LineParser lp(comment_state);
for (x=0;x<m_lines.GetSize();x++)
{
if (!lp.parse(m_lines.Get(x)) && lp.getnumtokens()>0)
processLvgLine(&lp,&rs,m_cachedImage,xscale,yscale);
}
}
void *LICE_GetSubLVG(void *lvg, const char *subname)
{
if (!lvg||!subname||!*subname) return NULL;
lvgImageCtx *t = (lvgImageCtx *)lvg;
return t->m_images.Get(subname);
}
LICE_IBitmap *LICE_RenderLVG(void *lvg, int reqw, int reqh, LICE_IBitmap *bmOut)
{
lvgImageCtx *t = (lvgImageCtx *)lvg;
if (!t || !t->m_lines.GetSize() || t->m_in_render) return NULL;
if (bmOut)
{
delete t->m_cachedImage;
t->m_cachedImage = bmOut;
}
else if (!t->m_cachedImage) t->m_cachedImage = new LICE_MemBitmap;
t->m_in_render=true;
t->render(NULL,reqw,reqh);
t->m_in_render=false;
LICE_IBitmap *ret = t->m_cachedImage;
t->m_cachedImage=NULL;
return ret;
}
void LICE_DestroyLVG(void *lvg)
{
lvgImageCtx *t = (lvgImageCtx *)lvg;
if (t && !t->m_par) delete t;
}
class lvgRdContext : public ProjectStateContext
{
public:
lvgRdContext(FILE *fp) { m_fp=fp; }
virtual ~lvgRdContext() { }
virtual void AddLine(const char *fmt, ...) {};
virtual int GetLine(char *buf, int buflen) // returns -1 on eof
{
if (!m_fp) return -1;
for (;;)
{
buf[0]=0;
fgets(buf,buflen,m_fp);
if (!buf[0]) return -1;
char *p=buf;
while (*p) p++;
while (p>buf && (p[-1] == '\r' || p[-1]=='\n')) p--;
*p=0;
if (*buf) return 0;
}
}
virtual WDL_INT64 GetOutputSize() { return 0; }
virtual int GetTempFlag() { return 0; }
virtual void SetTempFlag(int flag) {}
FILE *m_fp;
};
void *LICE_LoadLVGFromContext(ProjectStateContext *ctx, const char *nameInfo, int defw, int defh)
{
if (!ctx) return NULL;
bool err=false;
int ignoreBlockCnt=0;
lvgImageCtx *retimg = new lvgImageCtx(NULL);
lvgImageCtx *curimg = NULL;
if (nameInfo)
{
curimg = retimg;
curimg->m_base_w = defw;
curimg->m_base_h = defh;
}
while (!err)
{
char line[4096];
line[0]=0;
if (ctx->GetLine(line,sizeof(line))) break;
char *p=line;
while (*p == ' ' || *p == '\t') p++;
if (!*p) continue;
if (ignoreBlockCnt>0)
{
if (*p == '<') ignoreBlockCnt++;
else if (*p == '>') ignoreBlockCnt--;
}
else
{
if (*p == '<')
{
bool comment_state=false;
LineParser lp(comment_state);
if (!lp.parse(p)&&lp.getnumtokens()>=2 && !strcmp(lp.gettoken_str(0),"<LVG"))
{
if (!curimg)
{
// lp.gettoken_str(1) = version info string?
curimg = retimg;
}
else
{
lvgImageCtx *img = new lvgImageCtx(curimg);
curimg->m_images.Insert(lp.gettoken_str(1),img);
curimg = img;
}
curimg->m_base_w = lp.gettoken_int(2);
curimg->m_base_h = lp.gettoken_int(3);
}
else ignoreBlockCnt++;
}
else if (curimg)
{
if (*p == '>')
{
curimg = curimg->m_par;
if (!curimg) break; // success!
}
else
{
curimg->m_lines.Add(strdup(p));
}
}
if (!curimg) err=true; // <LVG must be first non-whitespace line
}
}
if (err)
{
delete retimg;
return 0;
}
return retimg;
}
void *LICE_LoadLVG(const char *filename)
{
FILE *fp=NULL;
#if defined(_WIN32) && !defined(WDL_NO_SUPPORT_UTF8)
#ifdef WDL_SUPPORT_WIN9X
if (GetVersion()<0x80000000)
#endif
{
WCHAR wf[2048];
if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,wf,2048))
fp = _wfopen(wf,L"rb");
}
#endif
if (!fp) fp = WDL_fopenA(filename,"rb");
if (fp)
{
lvgRdContext ctx(fp);
void *p = LICE_LoadLVGFromContext(&ctx,NULL,0,0);
fclose(fp);
return p;
}
return 0;
}

View File

@@ -0,0 +1,469 @@
#include "lice.h"
#include "../ptrlist.h"
#include "../wdltypes.h"
#define OCTREE_DEPTH 5 // every depth level adds 3 bits of RGB colorspace (depth 8 => 24-bit RGB)
struct ONode
{
WDL_INT64 colorcount; // number of color instances at or below this node
WDL_INT64 sumrgb[3];
int childflag; // 0=leaf, >0=index of single child, <0=branch
int leafidx; // populated at the end
ONode* next; // for OTree::branches
ONode* children[8];
};
struct OTree
{
int maxcolors;
int leafcount;
ONode* trunk;
ONode* branches[OCTREE_DEPTH]; // linked lists of branches for each level of the tree
ONode* spares;
LICE_pixel* palette; // populated at the end
bool palette_valid;
};
int LICE_BuildPalette(LICE_IBitmap* bmp, LICE_pixel* palette, int maxcolors)
{
void* tree = LICE_CreateOctree(maxcolors);
LICE_BuildOctree(tree, bmp);
int sz = LICE_ExtractOctreePalette(tree, palette);
LICE_DestroyOctree(tree);
return sz;
}
static void AddColorToTree(OTree*, const LICE_pixel_chan *rgb);
static int FindColorInTree(OTree*, const LICE_pixel_chan *rgb);
static int PruneTree(OTree*);
static void DeleteNode(OTree*, ONode*, ONode **delete_to);
static int CollectLeaves(OTree*);
static int CollectNodeLeaves(ONode* node, LICE_pixel* palette, int colorcount);
void* LICE_CreateOctree(int maxcolors)
{
OTree* tree = new OTree;
memset(tree, 0, sizeof(OTree));
tree->maxcolors = maxcolors;
tree->trunk = new ONode;
memset(tree->trunk, 0, sizeof(ONode));
tree->spares = NULL;
return tree;
}
void LICE_ResetOctree(void *octree, int maxc)
{
OTree* tree = (OTree*)octree;
if (!tree) return;
if (maxc > tree->maxcolors)
{
free(tree->palette);
tree->palette=0;
}
DeleteNode(tree, tree->trunk, &tree->spares);
tree->leafcount = 0;
tree->maxcolors = maxc;
tree->palette_valid=false;
memset(tree->branches,0,sizeof(tree->branches));
tree->trunk=tree->spares;
if (tree->trunk) tree->spares = tree->trunk->next;
else tree->trunk = new ONode;
memset(tree->trunk, 0, sizeof(ONode));
}
void LICE_DestroyOctree(void* octree)
{
OTree* tree = (OTree*)octree;
if (!tree) return;
DeleteNode(tree, tree->trunk, NULL);
ONode *p = tree->spares;
while (p)
{
ONode *del = p;
p = p->next;
delete del;
}
free(tree->palette);
delete tree;
}
int LICE_BuildOctree(void* octree, LICE_IBitmap* bmp)
{
OTree* tree = (OTree*)octree;
if (!tree || !bmp) return 0;
tree->palette_valid = false;
int y;
const int h=bmp->getHeight();
const int w=bmp->getWidth();
const int rowspan = bmp->getRowSpan();
const LICE_pixel *bits = bmp->getBits();
for (y = 0; y < h; ++y)
{
const LICE_pixel *px = bits+y*rowspan;
int x=w;
while (x--)
{
AddColorToTree(tree, (const LICE_pixel_chan*)px);
if (tree->leafcount > tree->maxcolors) PruneTree(tree);
px++;
}
}
return tree->leafcount;
}
int LICE_BuildOctreeForAlpha(void* octree, LICE_IBitmap* bmp, unsigned int minalpha)
{
OTree* tree = (OTree*)octree;
if (!tree || !bmp) return 0;
tree->palette_valid = false;
int y;
const int h=bmp->getHeight();
const int w=bmp->getWidth();
const int rowspan = bmp->getRowSpan();
const LICE_pixel *bits = bmp->getBits();
int pxcnt=0;
for (y = 0; y < h; ++y)
{
const LICE_pixel *px = bits+y*rowspan;
int x=w;
while (x--)
{
if (px[LICE_PIXEL_A] >= minalpha)
{
AddColorToTree(tree, (const LICE_pixel_chan*)px);
if (tree->leafcount > tree->maxcolors) PruneTree(tree);
pxcnt++;
}
px++;
}
}
return pxcnt;
}
int LICE_BuildOctreeForDiff(void* octree, LICE_IBitmap* bmp, LICE_IBitmap* refbmp, LICE_pixel mask)
{
OTree* tree = (OTree*)octree;
if (!tree || !bmp || !refbmp) return 0;
tree->palette_valid=false;
int y;
const int h=lice_min(bmp->getHeight(),refbmp->getHeight());
const int w=lice_min(bmp->getWidth(),refbmp->getWidth());
int rowspan = bmp->getRowSpan();
int rowspan2 = refbmp->getRowSpan();
const LICE_pixel *bits = bmp->getBits();
const LICE_pixel *bits2 = refbmp->getBits();
if (bmp->isFlipped())
{
bits += rowspan * (bmp->getHeight()-1);
rowspan = -rowspan;
}
if (refbmp->isFlipped())
{
bits2 += rowspan2 * (refbmp->getHeight()-1);
rowspan2 = -rowspan2;
}
int pxcnt=0;
for (y = 0; y < h; ++y)
{
const LICE_pixel * px = bits+y*rowspan;
const LICE_pixel * px2 = bits2+y*rowspan2;
int x=w;
while (x--)
{
if ((*px ^ *px2) & mask)
{
AddColorToTree(tree, (const LICE_pixel_chan *)px);
if (tree->leafcount > tree->maxcolors) PruneTree(tree);
pxcnt++;
}
px++;
px2++;
}
}
return pxcnt;
}
int LICE_FindInOctree(void* octree, LICE_pixel color)
{
OTree* tree = (OTree*)octree;
if (!tree) return 0;
if (!tree->palette_valid) CollectLeaves(tree);
return FindColorInTree(tree, (const LICE_pixel_chan *)&color);
}
int LICE_ExtractOctreePalette(void* octree, LICE_pixel* palette)
{
OTree* tree = (OTree*)octree;
if (!tree || !palette) return 0;
if (!tree->palette_valid) CollectLeaves(tree);
if (tree->palette) memcpy(palette, tree->palette, tree->maxcolors*sizeof(LICE_pixel));
return tree->leafcount;
}
void LICE_TestPalette(LICE_IBitmap* bmp, LICE_pixel* palette, int numcolors)
{
int x, y;
for (y = 0; y < bmp->getHeight(); ++y)
{
LICE_pixel* px = bmp->getBits()+y*bmp->getRowSpan();
for (x = 0; x < bmp->getWidth(); ++x)
{
const LICE_pixel col = px[x];
const int rgb[3] = { (int)LICE_GETR(col), (int)LICE_GETG(col), (int)LICE_GETB(col) };
int minerr = 0x7FFFFFFF;
int bestcol=-1;
int i;
for (i = 0; i < numcolors; ++i)
{
const LICE_pixel palcol = palette[i];
const int rerr[3] = { rgb[0]-(int)LICE_GETR(palcol), rgb[1]-(int)LICE_GETG(palcol), rgb[2]-(int)LICE_GETB(palcol) };
const int err = rerr[0]*rerr[0]+rerr[1]*rerr[1]+rerr[2]*rerr[2];
if (err < minerr)
{
bestcol=i;
minerr=err;
}
}
px[x] = palette[bestcol];
}
}
}
void AddColorToTree(OTree* tree, const LICE_pixel_chan *rgb)
{
ONode* p = tree->trunk;
p->colorcount++;
int i;
const unsigned char r = rgb[LICE_PIXEL_R];
const unsigned char g = rgb[LICE_PIXEL_G];
const unsigned char b = rgb[LICE_PIXEL_B];
for (i = OCTREE_DEPTH-1; i >= 0; --i)
{
const int j = i+8-OCTREE_DEPTH;
const unsigned char idx = (((r>>(j-2))&4))|(((g>>(j-1))&2))|((b>>j)&1);
ONode* np = p->children[idx];
bool isleaf = false;
if (np)
{
isleaf = !np->childflag;
}
else // add node
{
if (!p->childflag) // first time down this path
{
p->childflag=idx+1;
}
else if (p->childflag > 0) // creating a new branch
{
p->childflag = -1;
p->next = tree->branches[i];
tree->branches[i] = p;
}
// else multiple branch, which we don't care about
np=tree->spares;
if (np) tree->spares = np->next;
else np = new ONode;
p->children[idx] = np;
memset(np, 0, sizeof(ONode));
}
np->sumrgb[0] += r;
np->sumrgb[1] += g;
np->sumrgb[2] += b;
np->colorcount++;
if (isleaf) return;
p=np; // continue downward
}
// p is a new leaf at the bottom
tree->leafcount++;
}
int FindColorInTree(OTree* tree, const LICE_pixel_chan *rgb)
{
ONode* p = tree->trunk;
int i;
const unsigned char r=rgb[LICE_PIXEL_R];
const unsigned char g=rgb[LICE_PIXEL_G];
const unsigned char b=rgb[LICE_PIXEL_B];
for (i = OCTREE_DEPTH-1; i >= 0; --i)
{
if (!p->childflag) break;
const int j = i+8-OCTREE_DEPTH;
const unsigned char idx = (((r>>(j-2))&4))|(((g>>(j-1))&2))|((b>>j)&1);
ONode* np = p->children[idx];
if (!np) break;
p = np;
}
return p->leafidx;
}
int PruneTree(OTree* tree)
{
ONode* branch=0;
int i;
for (i = 0; i < OCTREE_DEPTH; ++i) // prune at the furthest level from the trunk
{
branch = tree->branches[i];
if (branch)
{
tree->branches[i] = branch->next;
branch->next=0;
break;
}
}
if (branch)
{
for (i = 0; i < 8; ++i)
{
if (branch->children[i])
{
DeleteNode(tree, branch->children[i],&tree->spares);
branch->children[i]=0;
}
}
branch->childflag=0; // now it's a leaf
tree->leafcount++;
}
return tree->leafcount;
}
int CollectLeaves(OTree* tree)
{
if (!tree->palette) tree->palette = (LICE_pixel*)malloc(tree->maxcolors*sizeof(LICE_pixel));
if (!tree->palette) return 0;
int sz = CollectNodeLeaves(tree->trunk, tree->palette, 0);
memset(tree->palette+sz, 0, (tree->maxcolors-sz)*sizeof(LICE_pixel));
tree->palette_valid = true;
return sz;
}
int CollectNodeLeaves(ONode* p, LICE_pixel* palette, int colorcount)
{
if (!p->childflag)
{
p->leafidx = colorcount;
int r = (int)((double)p->sumrgb[0]/(double)p->colorcount);
int g = (int)((double)p->sumrgb[1]/(double)p->colorcount);
int b = (int)((double)p->sumrgb[2]/(double)p->colorcount);
palette[colorcount++] = LICE_RGBA(r, g, b, 255);
}
else
{
if (p->childflag > 0)
{
colorcount = CollectNodeLeaves(p->children[p->childflag-1], palette, colorcount);
}
else
{
int i;
for (i = 0; i < 8; ++i)
{
if (p->children[i])
{
colorcount = CollectNodeLeaves(p->children[i], palette, colorcount);
}
}
}
// this is a branch or passthrough node, record the index
// of any downtree leaf here so that we can return it for
// color lookups that want to diverge off this node
p->leafidx = colorcount-1;
}
// colorcount should == leafcount
return colorcount;
}
void DeleteNode(OTree* tree, ONode* p, ONode **delete_to)
{
if (!p->childflag)
{
tree->leafcount--;
}
else if (p->childflag > 0)
{
DeleteNode(tree, p->children[p->childflag-1],delete_to);
}
else
{
int i;
for (i = 0; i < 8; ++i)
{
if (p->children[i])
{
DeleteNode(tree, p->children[i],delete_to);
}
}
}
if (delete_to)
{
p->next = *delete_to;
*delete_to = p;
}
else
{
delete p;
}
}

View File

@@ -0,0 +1,118 @@
/*
Cockos WDL - LICE - Lightweight Image Compositing Engine
Copyright (C) 2007 and later, Cockos Incorporated
File: lice_pcx.cpp (PCX loading for LICE)
See lice.h for license and other information
*/
#include "lice.h"
#include "../wdltypes.h"
#include <stdio.h>
// note: you'd never really want to use PCX files, but in case you do...
LICE_IBitmap *LICE_LoadPCX(const char *filename, LICE_IBitmap *_bmp)
{
FILE *fp = WDL_fopenA(filename,"rb");
if(!fp) return 0;
fgetc(fp);
if (fgetc(fp) != 5) { fclose(fp); return NULL; }
if (fgetc(fp) != 1) { fclose(fp); return NULL; }
if (fgetc(fp) != 8) { fclose(fp); return NULL; }
int sx = fgetc(fp); sx += fgetc(fp)<<8;
int sy = fgetc(fp); sy += fgetc(fp)<<8;
int ex = fgetc(fp); ex += fgetc(fp)<<8;
int ey = fgetc(fp); ey += fgetc(fp)<<8;
unsigned char pal[768];
fseek(fp,-769,SEEK_END);
if (fgetc(fp) != 12) { fclose(fp); return NULL; }
if (fread(pal,1,768,fp) != 768 || feof(fp))
{
fclose(fp);
return NULL;
}
LICE_IBitmap *usebmp = NULL;
if (_bmp) (usebmp=_bmp)->resize(ex-sx+1,ey-sy+1);
else usebmp = new WDL_NEW LICE_MemBitmap(ex-sx+1,ey-sy+1);
if (!usebmp || usebmp->getWidth() != (ex-sx+1) || usebmp->getHeight() != (ey-sy+1))
{
if (usebmp != _bmp) delete usebmp;
fclose(fp);
return NULL;
}
fseek(fp,128,SEEK_SET);
LICE_Clear(usebmp,0);
int y = usebmp->getHeight();
int w = usebmp->getWidth();
int rowspan = usebmp->getRowSpan();
LICE_pixel *pout = usebmp->getBits();
if (usebmp->isFlipped())
{
pout += rowspan*(y-1);
rowspan=-rowspan;
}
while (y--)
{
int xpos = 0;
while (xpos < w)
{
int c = fgetc(fp);
if (c&~255) break;
if ((c & 192) == 192)
{
int oc = (fgetc(fp))&255;
LICE_pixel t=LICE_RGBA(pal[oc*3],pal[oc*3+1],pal[oc*3+2],255);
c&=63;
while (c-- && xpos<w) pout[xpos++] = t;
}
else pout[xpos++] = LICE_RGBA(pal[c*3],pal[c*3+1],pal[c*3+2],255);
}
pout+=rowspan;
}
fclose(fp);
return usebmp;
}
class LICE_PCXLoader
{
public:
_LICE_ImageLoader_rec rec;
LICE_PCXLoader()
{
rec.loadfunc = loadfunc;
rec.get_extlist = get_extlist;
rec._next = LICE_ImageLoader_list;
LICE_ImageLoader_list = &rec;
}
static LICE_IBitmap *loadfunc(const char *filename, bool checkFileName, LICE_IBitmap *bmpbase)
{
if (checkFileName)
{
const char *p=filename;
while (*p)p++;
while (p>filename && *p != '\\' && *p != '/' && *p != '.') p--;
if (stricmp(p,".pcx")) return 0;
}
return LICE_LoadPCX(filename,bmpbase);
}
static const char *get_extlist()
{
return "PCX files (*.PCX)\0*.PCX\0";
}
};
LICE_PCXLoader LICE_pcxldr;

View File

@@ -0,0 +1,375 @@
/*
Cockos WDL - LICE - Lightweight Image Compositing Engine
Copyright (C) 2007 and later, Cockos Incorporated
File: lice_png.cpp (PNG loading for LICE)
See lice.h for license and other information
*/
#include "lice.h"
#include "../wdltypes.h"
#include <stdio.h>
#include "../libpng/png.h"
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h> // for loading images from embedded resource
#endif
LICE_IBitmap *LICE_LoadPNG(const char *filename, LICE_IBitmap *bmp)
{
FILE *fp = NULL;
#if defined(_WIN32) && !defined(WDL_NO_SUPPORT_UTF8)
#ifdef WDL_SUPPORT_WIN9X
if (GetVersion()<0x80000000)
#endif
{
WCHAR wf[2048];
if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,wf,2048))
fp = _wfopen(wf,L"rb");
}
#endif
if (!fp) fp = WDL_fopenA(filename,"rb");
if (!fp) return 0;
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png_ptr)
{
fclose(fp);
return 0;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr)
{
png_destroy_read_struct(&png_ptr, NULL, NULL);
fclose(fp);
return 0;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(fp);
return 0;
}
png_init_io(png_ptr, fp);
png_read_info(png_ptr, info_ptr);
unsigned int width, height;
int bit_depth, color_type, interlace_type, compression_type, filter_method;
png_get_IHDR(png_ptr, info_ptr, &width, &height,
&bit_depth, &color_type, &interlace_type,
&compression_type, &filter_method);
//convert whatever it is to RGBA
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
{
png_set_tRNS_to_alpha(png_ptr);
color_type |= PNG_COLOR_MASK_ALPHA;
}
if (bit_depth == 16)
png_set_strip_16(png_ptr);
if (bit_depth < 8)
png_set_packing(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
if (color_type & PNG_COLOR_MASK_ALPHA)
png_set_swap_alpha(png_ptr);
else
png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE);
LICE_IBitmap *delbmp = NULL;
if (bmp) bmp->resize(width,height);
else delbmp = bmp = new WDL_NEW LICE_MemBitmap(width,height);
if (!bmp || bmp->getWidth() != (int)width || bmp->getHeight() != (int)height)
{
delete delbmp;
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
fclose(fp);
return 0;
}
unsigned char **row_pointers=(unsigned char **)malloc(height*sizeof(unsigned char *));;
LICE_pixel *srcptr = bmp->getBits();
int dsrcptr=bmp->getRowSpan();
if (bmp->isFlipped())
{
srcptr += dsrcptr*(bmp->getHeight()-1);
dsrcptr=-dsrcptr;
}
unsigned int i;
for(i=0;i<height;i++)
{
row_pointers[i]=(unsigned char *)srcptr;
srcptr+=dsrcptr;
}
png_read_image(png_ptr, row_pointers);
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
fclose(fp);
#if !(LICE_PIXEL_A == 0 && LICE_PIXEL_R == 1 && LICE_PIXEL_G == 2 && LICE_PIXEL_B == 3)
for(i=0;i<height;i++)
{
unsigned char *bp = row_pointers[i];
int j=width;
while (j-->0)
{
unsigned char a = bp[0];
unsigned char r = bp[1];
unsigned char g = bp[2];
unsigned char b = bp[3];
((LICE_pixel*)bp)[0] = LICE_RGBA(r,g,b,a);
bp+=4;
}
}
#endif
free(row_pointers);
return bmp;
}
typedef struct
{
unsigned char *data;
int len;
} pngReadStruct;
static void staticPngReadFunc(png_structp png_ptr, png_bytep data, png_size_t length)
{
pngReadStruct *readStruct = (pngReadStruct *)png_get_io_ptr(png_ptr);
memset(data, 0, length);
int l = (int)length;
if (l > readStruct->len) l = readStruct->len;
memcpy(data, readStruct->data, l);
readStruct->data += l;
readStruct->len -= l;
}
#ifndef _WIN32
LICE_IBitmap *LICE_LoadPNGFromNamedResource(const char *name, LICE_IBitmap *bmp) // returns a bitmap (bmp if nonzero) on success
{
char buf[2048];
buf[0]=0;
if (strlen(name)>400) return NULL; // max name for this is 400 chars
#ifdef __APPLE__
CFBundleRef bund = CFBundleGetMainBundle();
if (bund)
{
CFURLRef url=CFBundleCopyBundleURL(bund);
if (url)
{
CFURLGetFileSystemRepresentation(url,true,(UInt8*)buf,sizeof(buf)-512);
CFRelease(url);
}
}
if (!buf[0]) return 0;
strcat(buf,"/Contents/Resources/");
#else
int sz = readlink("/proc/self/exe", buf, sizeof(buf)-512);
if (sz < 1)
{
static char tmp;
// this will likely not work if the program was launched with a relative path
// and the cwd has changed, but give it a try anyway
Dl_info inf={0,};
if (dladdr(&tmp,&inf) && inf.dli_fname)
sz = (int) strlen(inf.dli_fname);
else
sz = 0;
}
if ((unsigned int)sz >= sizeof(buf)-512) sz = sizeof(buf)-512-1;
buf[sz]=0;
char *p = buf;
while (*p) p++;
while (p > buf && *p != '/') p--;
*p=0;
strcat(buf,"/Resources/");
#endif // !__APPLE__
strcat(buf,name);
return LICE_LoadPNG(buf,bmp);
}
#endif
LICE_IBitmap *LICE_LoadPNGFromMemory(const void *data_in, int buflen, LICE_IBitmap *bmp)
{
if (buflen<8) return NULL;
unsigned char *data = (unsigned char *)(void*)data_in;
if(png_sig_cmp(data, 0, 8)) return NULL;
pngReadStruct readStruct = {data, buflen};
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png_ptr)
{
return 0;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr)
{
png_destroy_read_struct(&png_ptr, NULL, NULL);
return 0;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return 0;
}
png_set_read_fn(png_ptr, &readStruct, staticPngReadFunc);
png_read_info(png_ptr, info_ptr);
unsigned int width, height;
int bit_depth, color_type, interlace_type, compression_type, filter_method;
png_get_IHDR(png_ptr, info_ptr, &width, &height,
&bit_depth, &color_type, &interlace_type,
&compression_type, &filter_method);
//convert whatever it is to RGBA
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
{
png_set_tRNS_to_alpha(png_ptr);
color_type |= PNG_COLOR_MASK_ALPHA;
}
if (bit_depth == 16)
png_set_strip_16(png_ptr);
if (bit_depth < 8)
png_set_packing(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
if (color_type & PNG_COLOR_MASK_ALPHA)
png_set_swap_alpha(png_ptr);
else
png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE);
LICE_IBitmap *delbmp = NULL;
if (bmp) bmp->resize(width,height);
else delbmp = bmp = new WDL_NEW LICE_MemBitmap(width,height);
if (!bmp || bmp->getWidth() != (int)width || bmp->getHeight() != (int)height)
{
delete delbmp;
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
return 0;
}
unsigned char **row_pointers=(unsigned char **)malloc(height*sizeof(unsigned char *));;
LICE_pixel *srcptr = bmp->getBits();
int dsrcptr=bmp->getRowSpan();
unsigned int i;
for(i=0;i<height;i++)
{
row_pointers[i]=(unsigned char *)srcptr;
srcptr+=dsrcptr;
}
png_read_image(png_ptr, row_pointers);
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
//put shit in correct order
#if !(LICE_PIXEL_A == 0 && LICE_PIXEL_R == 1 && LICE_PIXEL_G == 2 && LICE_PIXEL_B == 3)
for(i=0;i<height;i++)
{
unsigned char *bp = row_pointers[i];
int j=width;
while (j-->0)
{
unsigned char a = bp[0];
unsigned char r = bp[1];
unsigned char g = bp[2];
unsigned char b = bp[3];
((LICE_pixel*)bp)[0] = LICE_RGBA(r,g,b,a);
bp+=4;
}
}
#endif
free(row_pointers);
return bmp;
}
LICE_IBitmap *LICE_LoadPNGFromResource(HINSTANCE hInst, const char *resid, LICE_IBitmap *bmp)
{
#ifdef _WIN32
HRSRC hResource = FindResource(hInst, resid, "PNG");
if(!hResource) return NULL;
DWORD imageSize = SizeofResource(hInst, hResource);
if(imageSize < 8) return NULL;
HGLOBAL res = LoadResource(hInst, hResource);
const void* pResourceData = LockResource(res);
if(!pResourceData) return NULL;
LICE_IBitmap * ret = LICE_LoadPNGFromMemory(pResourceData,imageSize,bmp);
// todo : cleanup res??
return ret;
#else
return 0;
#endif
}
class LICE_PNGLoader
{
public:
_LICE_ImageLoader_rec rec;
LICE_PNGLoader()
{
rec.loadfunc = loadfunc;
rec.get_extlist = get_extlist;
rec._next = LICE_ImageLoader_list;
LICE_ImageLoader_list = &rec;
}
static LICE_IBitmap *loadfunc(const char *filename, bool checkFileName, LICE_IBitmap *bmpbase)
{
if (checkFileName)
{
const char *p=filename;
while (*p)p++;
while (p>filename && *p != '\\' && *p != '/' && *p != '.') p--;
if (stricmp(p,".png")) return 0;
}
return LICE_LoadPNG(filename,bmpbase);
}
static const char *get_extlist()
{
return "PNG files (*.PNG)\0*.PNG\0";
}
};
LICE_PNGLoader LICE_pngldr;

View File

@@ -0,0 +1,133 @@
/*
Cockos WDL - LICE - Lightweight Image Compositing Engine
Copyright (C) 2007 and later, Cockos Incorporated
File: lice_png_write.cpp (PNG saving for LICE)
See lice.h for license and other information
*/
#include "lice.h"
#include <stdio.h>
#include "../libpng/png.h"
bool LICE_WritePNG(const char *filename, LICE_IBitmap *bmp, bool wantalpha /*=true*/)
{
if (!bmp || !filename) return false;
/*
** Joshua Teitelbaum 1/1/2008
** Gifted to cockos for toe nail clippings.
**
** JF> tweaked some
*/
png_structp png_ptr=NULL;
png_infop info_ptr=NULL;
unsigned char *rowbuf=NULL;
FILE *fp=NULL;
#if defined(_WIN32) && !defined(WDL_NO_SUPPORT_UTF8)
#ifdef WDL_SUPPORT_WIN9X
if (GetVersion()<0x80000000)
#endif
{
WCHAR wf[2048];
if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,wf,2048))
fp = _wfopen(wf,L"wb");
}
#endif
if (!fp) fp = fopen(filename,"wb");
if (fp == NULL) return false;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose(fp);
return false;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fclose(fp);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
return false;
}
if (setjmp(png_jmpbuf(png_ptr))) {
/* If we get here, we had a problem reading the file */
if (fp) fclose(fp);
fp=0;
free(rowbuf);
rowbuf=0;
png_destroy_write_struct(&png_ptr, &info_ptr);
return false;
}
png_init_io(png_ptr, fp);
int width=bmp->getWidth();
int height = bmp->getHeight();
#define BITDEPTH 8
png_set_IHDR(png_ptr, info_ptr, width, height, BITDEPTH, wantalpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_write_info(png_ptr, info_ptr);
png_set_bgr(png_ptr);
// kill alpha channel bytes if not wanted
if (!wantalpha) png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
LICE_pixel *ptr=(LICE_pixel *)bmp->getBits();
int rowspan=bmp->getRowSpan();
if (bmp->isFlipped())
{
ptr+=rowspan*(bmp->getHeight()-1);
rowspan=-rowspan;
}
if (LICE_PIXEL_B != 0 || LICE_PIXEL_G != 1 || LICE_PIXEL_R != 2 || LICE_PIXEL_A != 3)
{
rowbuf=(unsigned char *)malloc(width*4);
int k;
for (k = 0; k < height; k++)
{
int x;
unsigned char *bout = rowbuf;
LICE_pixel_chan *bin = (LICE_pixel_chan *) ptr;
for(x=0;x<width;x++)
{
bout[0] = bin[LICE_PIXEL_B];
bout[1] = bin[LICE_PIXEL_G];
bout[2] = bin[LICE_PIXEL_R];
bout[3] = bin[LICE_PIXEL_A];
bout+=4;
bin+=4;
}
png_write_row(png_ptr, (unsigned char *)rowbuf);
ptr += rowspan;
}
free(rowbuf);
rowbuf=0;
}
else
{
int k;
for (k = 0; k < height; k++)
{
png_write_row(png_ptr, (unsigned char *)ptr);
ptr += rowspan;
}
}
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
if (fp) fclose(fp);
fp=0;
return true;
}

View File

@@ -0,0 +1,351 @@
/*
Cockos WDL - LICE - Lightweight Image Compositing Engine
Copyright (C) 2007 and later, Cockos Incorporated
File: lice_texgen.cpp (LICE texture generator routines)
See lice.h for license and other information
*/
#ifndef WDL_NO_DEFINE_MINMAX
#define WDL_NO_DEFINE_MINMAX
#endif
#include "lice.h"
#include <math.h>
void LICE_TexGen_Marble(LICE_IBitmap *dest, const RECT *rect, float rv, float gv, float bv, float intensity)
{
int span=dest->getRowSpan();
int w = dest->getWidth();
int h = dest->getHeight();
int x = 0;
int y = 0;
if(rect)
{
x = rect->left;
y = rect->top;
w = rect->right - rect->left;
h = rect->bottom - rect->top;
}
if (x<0) { w+=x; x=0; }
if (y<0) { h+=y; y=0; }
const int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
if (w<1 || h < 1 || x >= destbm_w || y >= destbm_h) return;
if (w>destbm_w-x) w=destbm_w-x;
if (h>destbm_h-y) h=destbm_h-y;
LICE_pixel *startp = dest->getBits();
if (dest->isFlipped())
{
startp += x + (dest->getHeight()-1-y)*span;
span=-span;
}
else startp += x + y*span;
//simple 16bit marble noise generator
#define ROL(x,y) ((x<<(y))|(((unsigned short)x)>>(16-(y))))
#define ROR(x,y) ((((unsigned short)x)>>(y))|(x<<(16-(y))))
intensity/=1024.0f;
int maxc = 0;
{
LICE_pixel *p = startp;
short n1 = 0, n2 = 0;
for(int i=0;i<h;i++)
{
for(int j=0;j<w;j++)
{
n1 += n2;
n1 = ROL(n1, n2&0xf);
n2 += 2;
n2 = ROR(n2, 1);
int val = (int)(n1*intensity)+1;
LICE_pixel c = w;
LICE_pixel c2 = w/2;
if(i>0)
{
c = p[j-span];
if(j==0)
c2 = p[(w-1)-span];
else
c2 = p[(j-1)-span];
}
int pix = (((c + c2)/2) + val);
if(pix>maxc) maxc = pix;
p[j] = pix;
}
p+=span;
}
}
//normalize values and apply gamma
{
LICE_pixel *p = startp;
float sc=255.0f/maxc;
for(int i=0;i<h;i++)
{
for(int j=0;j<w;j++)
{
float col = (float)fabs(p[j]*sc);
p[j] = LICE_RGBA((int)(col*rv),(int)(col*gv),(int)(col*bv),255);
}
p+=span;
}
}
}
//standard perlin noise implementation
#if 1
int m_noiseTab[512];
void initNoise()
{
static int init = 0;
if(!init)
{
const int permutation[] = { 151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
};
for (int i=0; i < 256 ; i++)
m_noiseTab[256+i] = m_noiseTab[i] = permutation[i];
init = 1;
}
}
static __inline float fade(float t)
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
static __inline float lerp(float t, float a, float b)
{
return a + t * (b - a);
}
static __inline float grad(int hash, float x, float y)
{
//convert lo 4 bits of hash code into 12 gradient directions
int h = hash & 15;
float u = h<8 ? x : y,
v = h<4 ? y : h==12||h==14 ? x : 0;
return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
}
static float noise(float x, float y)
{
//find unit cube that contains point
int X = (int)floor(x) & 255, Y = (int)floor(y) & 255;
//find relative x,y,z of point in cube
x -= (float)floor(x);
y -= (float)floor(y);
//compute fade curves for each of x,y,z
float u = fade(x), v = fade(y);
//hash coordinates of the 8 cube corners
int A = m_noiseTab[X ]+Y, AA = m_noiseTab[A], AB = m_noiseTab[A+1],
B = m_noiseTab[X+1]+Y, BA = m_noiseTab[B], BB = m_noiseTab[B+1];
//and add blended results from 8 corners of cube
return lerp(v, lerp(u, grad(m_noiseTab[AA ], x , y ),
grad(m_noiseTab[BA ], x-1, y )),
lerp(u, grad(m_noiseTab[AB ], x , y-1 ),
grad(m_noiseTab[BB ], x-1, y-1 )));
}
#else
//faster implementation but way lower quality
#define noiseWidth 128
#define noiseHeight 128
float m_noiseTab[noiseWidth][noiseHeight];
void initNoise()
{
static int init = 0;
if(init) return;
for (int x = 0; x < noiseWidth; x++)
for (int y = 0; y < noiseHeight; y++)
{
m_noiseTab[x][y] = (float)(rand() % 32768) / 32768.0;
}
init = 1;
}
float noise(float x, float y)
{
//x*=noiseWidth;
//y*=noiseHeight;
//get fractional part of x and y
float fractX = x - (int)x;
float fractY = y - (int)y;
//wrap around
int x1 = ((int)x + noiseWidth) % noiseWidth;
int y1 = ((int)y + noiseHeight) % noiseHeight;
//neighbor values
int x2 = (x1 + noiseWidth - 1) % noiseWidth;
int y2 = (y1 + noiseHeight - 1) % noiseHeight;
//smooth the noise with bilinear interpolation
float value = 0.0;
value += fractX * fractY * m_noiseTab[x1][y1];
value += fractX * (1 - fractY) * m_noiseTab[x1][y2];
value += (1 - fractX) * fractY * m_noiseTab[x2][y1];
value += (1 - fractX) * (1 - fractY) * m_noiseTab[x2][y2];
return value;
}
#endif
void LICE_TexGen_Noise(LICE_IBitmap *dest, const RECT *rect, float rv, float gv, float bv, float intensity, int mode, int smooth)
{
initNoise();
int span=dest->getRowSpan();
int w = dest->getWidth();
int h = dest->getHeight();
int dx = 0;
int dy = 0;
if(rect)
{
dx = rect->left;
dy = rect->top;
w = rect->right - rect->left;
h = rect->bottom - rect->top;
}
if (dx<0) { w+=dx; dx=0; }
if (dy<0) { h+=dy; dy=0; }
const int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
if (w<1 || h < 1 || dx >= destbm_w || dy >= destbm_h) return;
if (w>destbm_w-dx) w=destbm_w-dx;
if (h>destbm_h-dy) h=destbm_h-dy;
LICE_pixel *startp = dest->getBits();
if (dest->isFlipped())
{
startp += dx + (dest->getHeight()-1-dy)*span;
span=-span;
}
else startp += dx + dy*span;
{
LICE_pixel *p = startp;
for(int i=0;i<h;i++)
{
for(int j=0;j<w;j++)
{
float x = (float)j/w*16*intensity;
float y = (float)i/h*16*intensity;
float val = 0;
int size = smooth;
while(size>=1)
{
switch(mode)
{
case NOISE_MODE_NORMAL: val += noise(x/size, y/size)*size; break;
case NOISE_MODE_WOOD: val += (float)cos( x/size + noise(x/size,y/size) )*size/2; break;
}
size /= 2;
}
float col = (float)fabs(val/smooth)*255;
if(col>255) col=255;
p[j] = LICE_RGBA((int)(col*rv),(int)(col*gv),(int)(col*bv),255);
}
p+=span;
}
}
}
static float turbulence(int x, int y, float size, float isize)
{
float value = 0.0;
const float initialSize = isize;
while(size >= 1)
{
value += noise(x * isize, y * isize) * size;
size *= 0.5f;
isize *= 2.0f;
}
return(128.0f * value * initialSize);
}
void LICE_TexGen_CircNoise(LICE_IBitmap *dest, const RECT *rect, float rv, float gv, float bv, float nrings, float power, int size)
{
initNoise();
int span=dest->getRowSpan();
int w = dest->getWidth();
int h = dest->getHeight();
int x = 0;
int y = 0;
if(rect)
{
x = rect->left;
y = rect->top;
w = rect->right - rect->left;
h = rect->bottom - rect->top;
}
if (x<0) { w+=x; x=0; }
if (y<0) { h+=y; y=0; }
const int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
if (w<1 || h < 1 || x >= destbm_w || y >= destbm_h) return;
if (w>destbm_w-x) w=destbm_w-x;
if (h>destbm_h-y) h=destbm_h-y;
LICE_pixel *startp = dest->getBits();
if (dest->isFlipped())
{
startp += x + (dest->getHeight()-1-y)*span;
span=-span;
}
else startp += x + y*span;
float xyPeriod = nrings;
float turbPower = power;
const float iturbSize = 1.0f/(float)size;
const float turbSize = (float)size;
{
LICE_pixel *p = startp;
for(int i=0;i<h;i++)
{
for(int j=0;j<w;j++)
{
float xValue = ((float)j - w / 2) / w;
float yValue = ((float)i - h / 2) / h;
float distValue = (float) (sqrt(xValue * xValue + yValue * yValue) + turbPower * turbulence(j, i, turbSize, iturbSize) / 256.0);
float col = (float)fabs(256.0 * sin(2 * xyPeriod * distValue * 3.14159));
p[j] = LICE_RGBA((int)(col*rv),(int)(col*bv),(int)(col*gv),255);
}
p+=span;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,274 @@
#ifndef _LICE_TEXT_H_
#define _LICE_TEXT_H_
#include "lice.h"
#ifndef _WIN32
#include "../swell/swell.h"
#endif
#include "../heapbuf.h"
#define LICE_FONT_FLAG_VERTICAL 1 // rotate text to vertical (do not set the windows font to vertical though)
#define LICE_FONT_FLAG_VERTICAL_BOTTOMUP 2
#define LICE_FONT_FLAG_PRECALCALL 4
//#define LICE_FONT_FLAG_ALLOW_NATIVE 8
#define LICE_FONT_FLAG_FORCE_NATIVE 1024
#define LICE_FONT_FLAG_FX_BLUR 16
#define LICE_FONT_FLAG_FX_INVERT 32
#define LICE_FONT_FLAG_FX_MONO 64 // faster but no AA/etc
#define LICE_FONT_FLAG_FX_SHADOW 128 // these imply MONO
#define LICE_FONT_FLAG_FX_OUTLINE 256
#define LICE_FONT_FLAG_OWNS_HFONT 512
// could do a mask for these flags
#define LICE_FONT_FLAGS_HAS_FX(flag) \
(flag&(LICE_FONT_FLAG_VERTICAL|LICE_FONT_FLAG_VERTICAL_BOTTOMUP| \
LICE_FONT_FLAG_FX_BLUR|LICE_FONT_FLAG_FX_INVERT|LICE_FONT_FLAG_FX_MONO| \
LICE_FONT_FLAG_FX_SHADOW|LICE_FONT_FLAG_FX_OUTLINE))
#define LICE_DT_NEEDALPHA 0x80000000 // include in DrawText() if the output alpha channel is important
#define LICE_DT_USEFGALPHA 0x40000000 // uses alpha channel in fg color
class LICE_IFont
{
public:
virtual ~LICE_IFont() {}
virtual void SetFromHFont(HFONT font, int flags=0)=0; // hfont must REMAIN valid, unless LICE_FONT_FLAG_PRECALCALL or LICE_FONT_FLAG_OWNS_HFONT set (OWNS means LICE_IFont will clean up hfont on font change or exit)
virtual LICE_pixel SetTextColor(LICE_pixel color)=0;
virtual LICE_pixel SetBkColor(LICE_pixel color)=0;
virtual LICE_pixel SetEffectColor(LICE_pixel color)=0;
virtual int SetBkMode(int bkmode)=0;
virtual void SetCombineMode(int combine, float alpha=1.0f)=0;
virtual int DrawText(LICE_IBitmap *bm, const char *str, int strcnt, RECT *rect, UINT dtFlags)=0;
virtual LICE_pixel GetTextColor()=0;
virtual HFONT GetHFont()=0;
virtual int GetLineHeight()=0;
virtual void SetLineSpacingAdjust(int amt)=0;
};
#ifndef LICE_TEXT_NO_DECLARE_CACHEDFONT
class LICE_CachedFont : public LICE_IFont
{
public:
LICE_CachedFont();
virtual ~LICE_CachedFont();
virtual void SetFromHFont(HFONT font, int flags=0);
virtual LICE_pixel SetTextColor(LICE_pixel color) { LICE_pixel ret=m_fg; m_fg=color; return ret; }
virtual LICE_pixel SetBkColor(LICE_pixel color) { LICE_pixel ret=m_bg; m_bg=color; return ret; }
virtual LICE_pixel SetEffectColor(LICE_pixel color) { LICE_pixel ret=m_effectcol; m_effectcol=color; return ret; }
virtual int SetBkMode(int bkmode) { int bk = m_bgmode; m_bgmode=bkmode; return bk; }
virtual void SetCombineMode(int combine, float alpha=1.0f) { m_comb=combine; m_alpha=alpha; }
virtual int DrawText(LICE_IBitmap *bm, const char *str, int strcnt, RECT *rect, UINT dtFlags)
{
return DrawTextImpl(bm,str,strcnt,rect,dtFlags);
}
virtual LICE_pixel GetTextColor() { return m_fg; }
virtual HFONT GetHFont() { return m_font; }
virtual int GetLineHeight() { return m_line_height; }
virtual void SetLineSpacingAdjust(int amt) { m_lsadj=amt; }
protected:
virtual bool DrawGlyph(LICE_IBitmap *bm, unsigned short c, int xpos, int ypos, const RECT *clipR);
int DrawTextImpl(LICE_IBitmap *bm, const char *str, int strcnt, RECT *rect, UINT dtFlags); // cause swell defines DrawText to SWELL_DrawText etc
bool RenderGlyph(unsigned short idx);
const char *NextWordBreak(const char *str, int strcnt, int w);
LICE_pixel m_fg,m_bg,m_effectcol;
int m_bgmode;
int m_comb;
float m_alpha;
int m_flags;
int m_line_height,m_lsadj;
struct charEnt
{
int base_offset; // offset in m_cachestore+1, so 1=offset0, 0=unset, -1=failed to render
int width, height;
int advance;
int charid; // used by m_extracharlist
int left_extra;
};
charEnt *findChar(unsigned short c);
charEnt m_lowchars[128]; // first 128 chars cached here
WDL_TypedBuf<charEnt> m_extracharlist;
WDL_TypedBuf<unsigned char> m_cachestore;
static int _charSortFunc(const void *a, const void *b);
HFONT m_font;
};
#endif // !LICE_TEXT_NO_DECLARE_CACHEDFONT
#ifndef LICE_TEXT_NO_MULTIDPI
class __LICE_dpiAwareFont : public LICE_IFont
{
struct rec {
LICE_IFont *cache;
int sz;
};
WDL_TypedBuf<rec> m_list; // used entries are at end of list, most recently used last. sz=0 for unused
int (*m_getflags)(int);
int m_flags;
LICE_pixel m_fg, m_bg, m_effectcol;
int m_bgmode, m_comb;
float m_alpha;
int m_lsadj;
public:
LOGFONT m_lf;
// LICE_IFont interface
virtual void SetFromHFont(HFONT font, int flags=0) { }
virtual LICE_pixel SetTextColor(LICE_pixel color) { LICE_pixel ret=m_fg; m_fg=color; return ret; }
virtual LICE_pixel SetBkColor(LICE_pixel color) { LICE_pixel ret=m_bg; m_bg=color; return ret; }
virtual LICE_pixel SetEffectColor(LICE_pixel color) { LICE_pixel ret=m_effectcol; m_effectcol=color; return ret; }
virtual int SetBkMode(int bkmode) { int bk = m_bgmode; m_bgmode=bkmode; return bk; }
virtual void SetCombineMode(int combine, float alpha=1.0f) { m_comb=combine; m_alpha=alpha; }
virtual int DrawText(LICE_IBitmap *bm, const char *str, int strcnt, RECT *rect, UINT dtFlags)
{
LICE_IFont *f = get(bm);
if (!f) return 0;
if (!(dtFlags & DT_CALCRECT))
{
f->SetTextColor(m_fg);
f->SetBkColor(m_bg);
f->SetEffectColor(m_effectcol);
f->SetBkMode(m_bgmode);
f->SetCombineMode(m_comb,m_alpha);
f->SetLineSpacingAdjust(m_lsadj);
}
return f->DrawText(bm,str,strcnt,rect,dtFlags);
}
virtual LICE_pixel GetTextColor() { return m_fg; }
virtual HFONT GetHFont() { return NULL; }
virtual int GetLineHeight() { return GetLineHeightDPI(NULL); }
virtual void SetLineSpacingAdjust(int amt) { m_lsadj=amt; }
__LICE_dpiAwareFont(int maxsz)
{
memset(&m_lf,0,sizeof(m_lf));
m_getflags = NULL;
m_flags=0;
m_fg=m_bg=m_effectcol=0;
m_bgmode=TRANSPARENT;
m_comb=0;
m_alpha=1.0;
m_lsadj=0;
rec *l = m_list.ResizeOK(maxsz);
if (l) memset(l,0,sizeof(*l)*maxsz);
}
~__LICE_dpiAwareFont()
{
for (int x = 0; x < m_list.GetSize(); x ++) delete m_list.Get()[x].cache;
}
void SetFromLogFont(LOGFONT *lf, int (*get_flags)(int))
{
m_lf = *lf;
m_getflags = get_flags;
m_flags = get_flags ? get_flags(0) : 0;
clear();
}
void clear()
{
int x = m_list.GetSize()-1;
rec *t = m_list.Get();
while (x>=0 && t[x].sz) t[x--].sz=0;
}
LICE_IFont *get_for_sc(int fsc)
{
int use_flag = m_getflags ? m_getflags(0) & ~LICE_FONT_FLAG_PRECALCALL : 0;
if (m_flags != use_flag)
{
m_flags = use_flag;
clear();
}
int ht = m_lf.lfHeight, ht2 = m_lf.lfWidth;
if (fsc && fsc != 256)
{
ht = (ht * fsc) / 256;
ht2 = (ht2 * fsc) / 256;
use_flag |= LICE_FONT_FLAG_FORCE_NATIVE;
}
int x = m_list.GetSize()-1;
rec *t = m_list.Get();
while (x>=0 && t[x].sz != ht && t[x].sz) x--;
if (x<0) t[x=0].sz = 0; // if list full, use oldest item
// move to end of list
if (x != m_list.GetSize()-1)
{
rec tmp = t[x];
m_list.Delete(x);
m_list.Add(tmp);
}
t = m_list.Get() + m_list.GetSize() - 1;
if (!t->cache) t->cache = __CreateFont();
if (!t->sz && t->cache)
{
t->sz = ht;
LOGFONT lf = m_lf;
lf.lfHeight = ht;
lf.lfWidth = ht2;
#ifdef _WIN32
if (!(m_flags & LICE_FONT_FLAG_FORCE_NATIVE) && abs(lf.lfHeight) <= 14) lf.lfQuality = NONANTIALIASED_QUALITY;
#endif
t->cache->SetFromHFont(CreateFontIndirect(&lf), LICE_FONT_FLAG_OWNS_HFONT | use_flag);
}
return t->cache;
}
LICE_IFont *get(LICE_IBitmap *bm)
{
return get_for_sc(bm ? (int)bm->Extended(LICE_EXT_GET_ANY_SCALING,NULL) : 0);
}
int GetLineHeightDPI(LICE_IBitmap *bm)
{
LICE_IFont *f = get(bm);
return f ? f->GetLineHeight() : 10;
}
virtual LICE_IFont *__CreateFont()=0;
};
template<class BASEFONT> class LICE_dpiAwareFont : public __LICE_dpiAwareFont {
public:
LICE_dpiAwareFont(int max) : __LICE_dpiAwareFont(max) { }
virtual LICE_IFont *__CreateFont() { return new BASEFONT; }
};
#endif//LICE_TEXT_NO_MULTIDPI
#endif//_LICE_TEXT_H_

File diff suppressed because it is too large Load Diff

5
oversampling/WDL/lice/test/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
Win32/Debug/
Win32/Release/
x64/Debug/
x64/Release/

View File

@@ -0,0 +1,68 @@
CFLAGS=-O2 -g -Wall
LFLAGS=
CC=gcc
CXX=g++
WDL_PATH=../..
CFLAGS += -D_FILE_OFFSET_BITS=64
ifdef NOSWELL
CFLAGS += -D_LICE_NO_SYSBITMAPS_
SWELL_OBJS =
else
CFLAGS += -DSWELL_LICE_GDI
ifdef GDK2
CFLAGS += -DSWELL_TARGET_GDK=2 $(shell pkg-config --cflags gdk-2.0)
LFLAGS += $(shell pkg-config --libs gdk-2.0) -lX11 -lXi
else
CFLAGS += -DSWELL_TARGET_GDK=3 $(shell pkg-config --cflags gdk-3.0)
LFLAGS += $(shell pkg-config --libs gdk-3.0) -lX11 -lXi
endif
ifndef NOFREETYPE
CFLAGS += -DSWELL_FREETYPE $(shell pkg-config --cflags freetype2)
LFLAGS += $(shell pkg-config --libs freetype2)
endif
SWELL_OBJS = swell-wnd-generic.o swell-gdi-lice.o swell.o swell-misc-generic.o \
swell-dlg-generic.o swell-menu-generic.o swell-kb-generic.o \
swell-gdi-generic.o swell-ini.o swell-generic-gdk.o \
swell-appstub-generic.o swell-miscdlg-generic.o
LFLAGS += -ldl
vpath %.cpp $(WDL_PATH)/swell
endif
CXXFLAGS=$(CFLAGS)
vpath %.c $(WDL_PATH)/zlib $(WDL_PATH)/libpng $(WDL_PATH)/jpeglib $(WDL_PATH)/giflib
vpath %.cpp $(WDL_PATH)/lice $(WDL_PATH)/plush2
ZLIB_OBJS = compress.o adler32.o crc32.o deflate.o infback.o inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o ioapi.o zip.o unzip.o
PNGLIB_OBJS = png.o pngerror.o pngget.o pngmem.o pngpread.o pngread.o pngrio.o pngrtran.o pngrutil.o pngset.o pngtrans.o
JPEGLIB_OBJS = jcomapi.o jdapimin.o jdapistd.o jdatadst.o jdatasrc.o jdcoefct.o jdcolor.o jddctmgr.o jdhuff.o jdinput.o jdmainct.o jdmarker.o \
jdmaster.o jdmerge.o jdphuff.o jdpostct.o jdsample.o jerror.o jfdctflt.o jfdctfst.o jfdctint.o jidctflt.o jidctfst.o jidctint.o \
jidctred.o jmemmgr.o jmemnobs.o jquant1.o jquant2.o jutils.o
GIFLIB_OBJS = dgif_lib.o egif_lib.o gifalloc.o gif_hash.o
LICEOBJS = lice.o lice_gif.o lice_gif_write.o lice_image.o lice_jpg.o lice_png.o lice_pcx.o lice_palette.o lice_line.o lice_arc.o lice_text.o lice_textnew.o lice_texgen.o lice_colorspace.o
PLUSH_OBJS = pl_cam.o pl_make.o pl_math.o pl_obj.o pl_putface.o pl_read_3ds.o pl_read_cob.o pl_read_jaw.o pl_spline.o
.phony: clean default
default: test
test: $(LICEOBJS) $(JPEGLIB_OBJS) $(PNGLIB_OBJS) $(ZLIB_OBJS) $(GIFLIB_OBJS) $(SWELL_OBJS) $(PLUSH_OBJS) main.o fly.o
$(CXX) $(CFLAGS) -o $@ $^ $(LFLAGS)
imgs2gif: $(LICEOBJS) $(JPEGLIB_OBJS) $(PNGLIB_OBJS) $(ZLIB_OBJS) $(GIFLIB_OBJS) $(SWELL_OBJS) imgs2gif.o
$(CXX) $(CFLAGS) -o $@ $^ $(LFLAGS)
clean:
-rm $(LICEOBJS) $(JPEGLIB_OBJS) $(PNGLIB_OBJS) $(ZLIB_OBJS) $(GIFLIB_OBJS) imgs2gif.o imgs2gif $(SWELL_OBJS) $(PLUSH_OBJS) test main.o fly.o

File diff suppressed because it is too large Load Diff