From bfbe9e43e108f6816c17b9b7764b75284ac78313 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 14 Dec 2011 19:27:22 -0500 Subject: Re-think colors. Color is a property of light, and thus doesn't include information about transparency. But canvas pixels and object pigments represent a color and a degree of transparency. The new type dmnsn_tcolor/ TColor encapsulates that information. Also, fix the transparent shadow implementation. --- libdimension-python/dimension.pxd | 36 +++++++----- libdimension-python/dimension.pyx | 110 +++++++++++++++++++++++++------------ libdimension-python/tests/color.py | 12 +--- 3 files changed, 99 insertions(+), 59 deletions(-) (limited to 'libdimension-python') diff --git a/libdimension-python/dimension.pxd b/libdimension-python/dimension.pxd index 94966f3..0d0fcc4 100644 --- a/libdimension-python/dimension.pxd +++ b/libdimension-python/dimension.pxd @@ -43,8 +43,7 @@ cdef extern from "../libdimension/dimension.h": # Arrays # ########## - ctypedef struct dmnsn_array: - pass + ctypedef struct dmnsn_array dmnsn_array *dmnsn_new_array(size_t objsize) void dmnsn_delete_array(dmnsn_array *array) @@ -148,12 +147,8 @@ cdef extern from "../libdimension/dimension.h": double R double G double B - double trans - double filter dmnsn_color dmnsn_new_color(double R, double G, double B) - dmnsn_color dmnsn_new_color5(double R, double G, double B, - double trans, double filter) double dmnsn_sRGB_gamma(double Clinear) dmnsn_color dmnsn_color_to_sRGB(dmnsn_color color) @@ -162,11 +157,11 @@ cdef extern from "../libdimension/dimension.h": double dmnsn_color_intensity(dmnsn_color color) dmnsn_color dmnsn_color_add(dmnsn_color color1, dmnsn_color color2) + dmnsn_color dmnsn_color_sub(dmnsn_color color1, dmnsn_color color2) dmnsn_color dmnsn_color_mul(double n, dmnsn_color color) dmnsn_color dmnsn_black dmnsn_color dmnsn_white - dmnsn_color dmnsn_clear dmnsn_color dmnsn_red dmnsn_color dmnsn_green dmnsn_color dmnsn_blue @@ -175,6 +170,18 @@ cdef extern from "../libdimension/dimension.h": dmnsn_color dmnsn_yellow dmnsn_color dmnsn_cyan + ctypedef struct dmnsn_tcolor: + dmnsn_color c + double T + double F + + dmnsn_tcolor dmnsn_new_tcolor(dmnsn_color c, double T, double F) + dmnsn_tcolor DMNSN_TCOLOR(dmnsn_color c) + dmnsn_tcolor dmnsn_new_tcolor5(double R, double G, double B, + double T, double F) + + dmnsn_tcolor dmnsn_clear + ############ # Canvases # ############ @@ -186,11 +193,11 @@ cdef extern from "../libdimension/dimension.h": dmnsn_canvas *dmnsn_new_canvas(size_t width, size_t height) void dmnsn_delete_canvas(dmnsn_canvas *canvas) - dmnsn_color dmnsn_canvas_get_pixel(dmnsn_canvas *canvas, size_t x, size_t y) + dmnsn_tcolor dmnsn_canvas_get_pixel(dmnsn_canvas *canvas, size_t x, size_t y) void dmnsn_canvas_set_pixel(dmnsn_canvas *canvas, size_t x, size_t y, - dmnsn_color color) + dmnsn_tcolor tcolor) - void dmnsn_canvas_clear(dmnsn_canvas *canvas, dmnsn_color color) + void dmnsn_canvas_clear(dmnsn_canvas *canvas, dmnsn_tcolor tcolor) int dmnsn_png_optimize_canvas(dmnsn_canvas *canvas) int dmnsn_png_write_canvas(dmnsn_canvas *canvas, FILE *file) @@ -234,7 +241,7 @@ cdef extern from "../libdimension/dimension.h": ctypedef struct dmnsn_pigment: dmnsn_matrix trans - dmnsn_color quick_color + dmnsn_tcolor quick_color ctypedef enum dmnsn_pigment_map_flags: DMNSN_PIGMENT_MAP_REGULAR @@ -242,7 +249,7 @@ cdef extern from "../libdimension/dimension.h": void dmnsn_delete_pigment(dmnsn_pigment *pigment) - dmnsn_pigment *dmnsn_new_solid_pigment(dmnsn_color color) + dmnsn_pigment *dmnsn_new_solid_pigment(dmnsn_tcolor tcolor) dmnsn_pigment *dmnsn_new_canvas_pigment(dmnsn_canvas *canvas) dmnsn_pigment *dmnsn_new_pigment_map_pigment(dmnsn_pattern *pattern, dmnsn_map *map, @@ -270,7 +277,7 @@ cdef extern from "../libdimension/dimension.h": void dmnsn_finish_cascade(dmnsn_finish *default_finish, dmnsn_finish *finish) - dmnsn_ambient *dmnsn_new_basic_ambient(dmnsn_color ambient) + dmnsn_ambient *dmnsn_new_ambient(dmnsn_color ambient) dmnsn_diffuse *dmnsn_new_lambertian(double diffuse) dmnsn_specular *dmnsn_new_phong(double specular, double exp) dmnsn_reflection *dmnsn_new_basic_reflection(dmnsn_color min, dmnsn_color max, @@ -332,7 +339,8 @@ cdef extern from "../libdimension/dimension.h": # Lights # ########## - ctypedef struct dmnsn_light + ctypedef struct dmnsn_light: + dmnsn_vector x0 dmnsn_light *dmnsn_new_light() void dmnsn_delete_light(dmnsn_light *light) diff --git a/libdimension-python/dimension.pyx b/libdimension-python/dimension.pyx index 8e48a5c..1e79620 100644 --- a/libdimension-python/dimension.pyx +++ b/libdimension-python/dimension.pyx @@ -408,13 +408,11 @@ cdef class _BaseColor: red -- The red component green -- The green component blue -- The blue component - trans -- The transparency of the color, 0.0 meaning opaque (default 0.0) - filter -- How filtered the transparency is (default 0.0) Alternatively, you can pass another Color, a gray intensity like 0.5, or a - tuple or other sequence (red, green, blue[, trans[, filter]]). + tuple or other sequence (red, green, blue). """ - if len(args) == 1: + if len(args) == 1 and len(kwargs) == 0: if isinstance(args[0], _BaseColor): self._clin = (<_BaseColor>args[0])._clin self._unlinearize() @@ -428,9 +426,8 @@ cdef class _BaseColor: self._linearize() - def _real_init(self, double red, double green, double blue, - double trans = 0.0, double filter = 0.0): - self._c = dmnsn_new_color5(red, green, blue, trans, filter) + def _real_init(self, double red, double green, double blue): + self._c = dmnsn_new_color(red, green, blue) property red: """The red component.""" @@ -444,14 +441,6 @@ cdef class _BaseColor: """The blue component.""" def __get__(self): return self._c.B - property trans: - """The transparency of the color.""" - def __get__(self): - return self._c.trans - property filter: - """How filtered the transparency is.""" - def __get__(self): - return self._c.filter def intensity(self): return dmnsn_color_intensity(self._c) @@ -489,10 +478,7 @@ cdef class _BaseColor: cdef double rdiff = clhs.red - crhs.red cdef double gdiff = clhs.green - crhs.green cdef double bdiff = clhs.blue - crhs.blue - cdef double tdiff = clhs.trans - crhs.trans - cdef double fdiff = clhs.filter - crhs.filter - cdef double sum = rdiff*rdiff + gdiff*gdiff + bdiff*bdiff \ - + tdiff*tdiff + fdiff*fdiff + cdef double sum = rdiff*rdiff + gdiff*gdiff + bdiff*bdiff equal = sqrt(sum) < dmnsn_epsilon if op == 2: # == return equal @@ -502,17 +488,11 @@ cdef class _BaseColor: return NotImplemented def __repr__(self): - return "dimension.%s(%r, %r, %r, %r, %r)" % \ - (type(self).__name__, self.red, self.green, self.blue, self.trans, - self.filter) + return "dimension.%s(%r, %r, %r)" % \ + (type(self).__name__, self.red, self.green, self.blue) def __str__(self): - if self.trans >= dmnsn_epsilon: - return "%s<%s, %s, %s, trans = %s, filter = %s>" % \ - (type(self).__name__, - self.red, self.green, self.blue, self.trans, self.filter) - else: - return "%s<%s, %s, %s>" % \ - (type(self).__name__, self.red, self.green, self.blue) + return "%s<%s, %s, %s>" % \ + (type(self).__name__, self.red, self.green, self.blue) cdef class Color(_BaseColor): """ @@ -551,7 +531,6 @@ cdef _BaseColor _Color(dmnsn_color c, type t): Black = _Color(dmnsn_black, Color) White = _Color(dmnsn_white, Color) -Clear = _Color(dmnsn_clear, Color) Red = _Color(dmnsn_red, Color) Green = _Color(dmnsn_green, Color) Blue = _Color(dmnsn_blue, Color) @@ -560,6 +539,65 @@ Orange = _Color(dmnsn_orange, Color) Yellow = _Color(dmnsn_yellow, Color) Cyan = _Color(dmnsn_cyan, Color) +cdef class TColor: + """ + A transparent color. + + This type is used for representing pigments and pixels, as it carries color as + well as transparency information. + """ + cdef dmnsn_tcolor _tc + + def __init__(self, *args, **kwargs): + """ + Create a transparent color. + + Keyword arguments: + color -- The Color() (or sRGB()) component + trans -- The transparency component + filter -- The proportion of the transparency that is filtered + + Alternatively, you can pass another TColor. + """ + if len(args) == 1 and len(kwargs) == 0: + if isinstance(args[0], TColor): + self._tc = (args[0])._tc + else: + self._real_init(*args, **kwargs) + else: + self._real_init(*args, **kwargs) + + def _real_init(self, color, double trans = 0, double filter = 0): + self._tc = dmnsn_new_tcolor(Color(color)._clin, trans, filter) + + property color: + """The color component.""" + def __get__(self): + return _Color(self._tc.c, Color) + property trans: + """The transparency component.""" + def __get__(self): + return self._tc.T + property filter: + """The filter proportion.""" + def __get__(self): + return self._tc.F + + def __repr__(self): + return "dimension.TColor(%r, %r, %r)" % \ + (self.color, self.trans, self.filter) + def __str__(self): + return "TColor<%s, %s, %s>" % \ + (self.color, self.trans, self.filter) + +cdef TColor _TColor(dmnsn_tcolor tc): + """Wrap a TColor around a dmnsn_tcolor.""" + cdef TColor self = TColor.__new__(TColor) + self._tc = tc + return self + +Clear = _TColor(dmnsn_clear) + ############ # Canvases # ############ @@ -612,7 +650,7 @@ cdef class Canvas: def clear(self, c): """Clear a canvas with a solid color.""" - dmnsn_canvas_clear(self._canvas, Color(c)._c) + dmnsn_canvas_clear(self._canvas, TColor(c)._tc) def write_PNG(self, path): """Export the canvas as a PNG file.""" @@ -660,10 +698,10 @@ cdef class _CanvasProxy: return self._canvas.height def __getitem__(self, int y): self._bounds_check(y) - return _Color(dmnsn_canvas_get_pixel(self._canvas, self._x, y), Color) + return _TColor(dmnsn_canvas_get_pixel(self._canvas, self._x, y)) def __setitem__(self, int y, color): self._bounds_check(y) - dmnsn_canvas_set_pixel(self._canvas, self._x, y, Color(color)._c) + dmnsn_canvas_set_pixel(self._canvas, self._x, y, TColor(color)._tc) def _bounds_check(self, int y): if y < 0 or y >= self._canvas.height: @@ -734,9 +772,9 @@ cdef class Pigment(_Transformable): self._pigment = (quick_color)._pigment DMNSN_INCREF(self._pigment) else: - self._pigment = dmnsn_new_solid_pigment(Color(quick_color)._c) + self._pigment = dmnsn_new_solid_pigment(TColor(quick_color)._tc) else: - self._pigment.quick_color = Color(quick_color)._c + self._pigment.quick_color = TColor(quick_color)._tc def __dealloc__(self): dmnsn_delete_pigment(self._pigment) @@ -858,7 +896,7 @@ cdef class Ambient(Finish): Keyword arguments: color -- the color and intensity of the ambient light """ - self._finish.ambient = dmnsn_new_basic_ambient(Color(color)._c) + self._finish.ambient = dmnsn_new_ambient(Color(color)._c) cdef class Diffuse(Finish): """Lambertian diffuse reflection.""" diff --git a/libdimension-python/tests/color.py b/libdimension-python/tests/color.py index 9482545..8bf1836 100755 --- a/libdimension-python/tests/color.py +++ b/libdimension-python/tests/color.py @@ -24,21 +24,15 @@ from dimension import * # Treat warnings as errors for tests die_on_warnings(True) -c = Color(0, 0.5, 1, trans = 0.5, filter = 0.35) -assert repr(c) == "dimension.Color(0.0, 0.5, 1.0, 0.5, 0.35)", repr(c) -assert str(c) == "Color<0.0, 0.5, 1.0, trans = 0.5, filter = 0.35>", str(c) +c = Color(0, 0.5, 1) +assert repr(c) == "dimension.Color(0.0, 0.5, 1.0)", repr(c) +assert str(c) == "Color<0.0, 0.5, 1.0>", str(c) assert c.red == 0, c.red assert c.green == 0.5, c.green assert c.blue == 1, c.blue -assert c.trans == 0.5, c.filter -assert c.filter == 0.35, c.trans - -c = Color(1, 0.5, 0) -assert str(c) == "Color<1.0, 0.5, 0.0>", str(c) assert Black == Color(0, 0, 0), Black assert White == Color(1, 1, 1), White -assert Clear == Color(0, 0, 0, trans = 1), Clear assert Red == Color(1, 0, 0), Red assert Green == Color(0, 1, 0), Green assert Blue == Color(0, 0, 1), Blue -- cgit v1.2.3