rays 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +8 -0
- data/README +4 -0
- data/Rakefile +72 -0
- data/VERSION +1 -0
- data/ext/rays/bitmap.cpp +322 -0
- data/ext/rays/extconf.rb +61 -0
- data/ext/rays/font.cpp +125 -0
- data/ext/rays/image.cpp +166 -0
- data/ext/rays/native.cpp +24 -0
- data/ext/rays/painter.cpp +573 -0
- data/ext/rays/rays.cpp +61 -0
- data/ext/rays/rays.h +39 -0
- data/ext/rays/texture.cpp +130 -0
- data/include/rays.h +20 -0
- data/include/rays/bitmap.h +80 -0
- data/include/rays/colorspace.h +101 -0
- data/include/rays/defs.h +33 -0
- data/include/rays/font.h +49 -0
- data/include/rays/helpers.h +37 -0
- data/include/rays/image.h +68 -0
- data/include/rays/opengl.h +15 -0
- data/include/rays/painter.h +179 -0
- data/include/rays/rays.h +19 -0
- data/include/rays/ruby.h +15 -0
- data/include/rays/ruby/bitmap.h +39 -0
- data/include/rays/ruby/font.h +39 -0
- data/include/rays/ruby/image.h +39 -0
- data/include/rays/ruby/painter.h +39 -0
- data/include/rays/ruby/rays.h +21 -0
- data/include/rays/ruby/texture.h +39 -0
- data/include/rays/texture.h +56 -0
- data/include/rays/transform.h +35 -0
- data/lib/rays.rb +9 -0
- data/lib/rays/autoinit.rb +10 -0
- data/lib/rays/bitmap.rb +25 -0
- data/lib/rays/image.rb +15 -0
- data/lib/rays/module.rb +30 -0
- data/lib/rays/painter.rb +99 -0
- data/lib/rays/texture.rb +15 -0
- data/rays.gemspec +54 -0
- data/src/cocoa/bitmap.mm +286 -0
- data/src/cocoa/font.mm +193 -0
- data/src/cocoa/helpers.h +26 -0
- data/src/cocoa/helpers.mm +25 -0
- data/src/cocoa/rays.mm +40 -0
- data/src/colorspace.cpp +183 -0
- data/src/helpers.cpp +22 -0
- data/src/image.cpp +133 -0
- data/src/painter.cpp +769 -0
- data/src/texture.cpp +360 -0
- data/src/transform.cpp +88 -0
- data/src/win32/bitmap.cpp +212 -0
- data/src/win32/font.cpp +99 -0
- data/src/win32/gdi.cpp +771 -0
- data/src/win32/gdi.h +226 -0
- data/src/win32/rays.cpp +36 -0
- data/support.rb +58 -0
- data/task/ext.rake +41 -0
- data/task/gem.rake +33 -0
- data/task/git.rake +22 -0
- data/task/lib.rake +54 -0
- data/test/helpers.rb +15 -0
- data/test/test_painter.rb +11 -0
- data/test/test_rays.rb +19 -0
- data/test/test_texture.rb +11 -0
- metadata +153 -0
data/src/cocoa/helpers.h
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
// -*- c++ -*-
|
2
|
+
#pragma once
|
3
|
+
#ifndef __RAYS_COCOA_HELPERS_H__
|
4
|
+
#define __RAYS_COCOA_HELPERS_H__
|
5
|
+
|
6
|
+
|
7
|
+
#include <boost/shared_ptr.hpp>
|
8
|
+
#include <CoreFoundation/CoreFoundation.h>
|
9
|
+
|
10
|
+
|
11
|
+
namespace Rays
|
12
|
+
{
|
13
|
+
|
14
|
+
|
15
|
+
void safe_cfrelease (CFTypeRef ref);
|
16
|
+
|
17
|
+
|
18
|
+
typedef boost::shared_ptr<const __CFString> CFString;
|
19
|
+
|
20
|
+
CFString cfstring (const char* str);
|
21
|
+
|
22
|
+
|
23
|
+
}// Rays
|
24
|
+
|
25
|
+
|
26
|
+
#endif//EOH
|
@@ -0,0 +1,25 @@
|
|
1
|
+
// -*- objc -*-
|
2
|
+
#include "helpers.h"
|
3
|
+
|
4
|
+
|
5
|
+
namespace Rays
|
6
|
+
{
|
7
|
+
|
8
|
+
|
9
|
+
void
|
10
|
+
safe_cfrelease (CFTypeRef ref)
|
11
|
+
{
|
12
|
+
if (ref) CFRelease(ref);
|
13
|
+
}
|
14
|
+
|
15
|
+
|
16
|
+
CFString
|
17
|
+
cfstring (const char* str)
|
18
|
+
{
|
19
|
+
CFStringRef ref = CFStringCreateWithCString(
|
20
|
+
kCFAllocatorDefault, str, kCFStringEncodingUTF8);
|
21
|
+
return CFString(ref, safe_cfrelease);
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
}// Rays
|
data/src/cocoa/rays.mm
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
// -*- objc -*-
|
2
|
+
#include "rays/rays.h"
|
3
|
+
|
4
|
+
|
5
|
+
#import <Cocoa/Cocoa.h>
|
6
|
+
|
7
|
+
|
8
|
+
namespace Rays
|
9
|
+
{
|
10
|
+
|
11
|
+
|
12
|
+
namespace global
|
13
|
+
{
|
14
|
+
|
15
|
+
|
16
|
+
static NSAutoreleasePool* pool = nil;
|
17
|
+
|
18
|
+
|
19
|
+
}// global
|
20
|
+
|
21
|
+
|
22
|
+
bool
|
23
|
+
init ()
|
24
|
+
{
|
25
|
+
if (global::pool) return false;
|
26
|
+
global::pool = [[NSAutoreleasePool alloc] init];
|
27
|
+
return true;
|
28
|
+
}
|
29
|
+
|
30
|
+
bool
|
31
|
+
fin ()
|
32
|
+
{
|
33
|
+
if (!global::pool) return false;
|
34
|
+
[global::pool release];
|
35
|
+
global::pool = nil;
|
36
|
+
return true;
|
37
|
+
}
|
38
|
+
|
39
|
+
|
40
|
+
}// Rays
|
data/src/colorspace.cpp
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
#include "rays/colorspace.h"
|
2
|
+
|
3
|
+
|
4
|
+
#include <rays/helpers.h>
|
5
|
+
|
6
|
+
|
7
|
+
namespace Rays
|
8
|
+
{
|
9
|
+
|
10
|
+
|
11
|
+
enum
|
12
|
+
{
|
13
|
+
|
14
|
+
FIRST = GRAY_8, LAST = ABGR_float,
|
15
|
+
|
16
|
+
GRAY_FIRST = GRAY_8, GRAY_LAST = GRAY_float,
|
17
|
+
|
18
|
+
RGB_FIRST = RGB_888, RGB_LAST = ABGR_float,
|
19
|
+
|
20
|
+
FLOAT_SECOND = RGB_float, FLOAT_LAST = ABGR_float,
|
21
|
+
|
22
|
+
};
|
23
|
+
|
24
|
+
|
25
|
+
ColorSpace::ColorSpace ()
|
26
|
+
: type_(COLORSPACE_UNKNOWN), premult(false)
|
27
|
+
{
|
28
|
+
}
|
29
|
+
|
30
|
+
ColorSpace::ColorSpace (ColorSpaceType type, bool premultiplied)
|
31
|
+
: type_(type), premult(premultiplied)
|
32
|
+
{
|
33
|
+
}
|
34
|
+
|
35
|
+
ColorSpaceType
|
36
|
+
ColorSpace::type () const
|
37
|
+
{
|
38
|
+
return type_;
|
39
|
+
}
|
40
|
+
|
41
|
+
int
|
42
|
+
ColorSpace::bpc () const
|
43
|
+
{
|
44
|
+
static const int BPPS[] =
|
45
|
+
{
|
46
|
+
0, // UNKNOWN
|
47
|
+
8, 16, 24, 32, 32, // GRAY
|
48
|
+
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // RGB(A), BGR(A)
|
49
|
+
32, 32, 32, 32, 32, 32, // RGB(A), BGR(A) float
|
50
|
+
};
|
51
|
+
if (type_ < 0 || COLORSPACE_LAST <= type_) return BPPS[UNKNOWN];
|
52
|
+
return BPPS[type_];
|
53
|
+
}
|
54
|
+
|
55
|
+
int
|
56
|
+
ColorSpace::Bpc () const
|
57
|
+
{
|
58
|
+
return bit2byte(bpc());
|
59
|
+
}
|
60
|
+
|
61
|
+
int
|
62
|
+
ColorSpace::bpp () const
|
63
|
+
{
|
64
|
+
static const int BPPS[] =
|
65
|
+
{
|
66
|
+
0, // UNKNOWN
|
67
|
+
8, 16, 24, 32, 32, // GRAY
|
68
|
+
24, 32, 32, 32, 32, // RGB(A)
|
69
|
+
24, 32, 32, 32, 32, // BGR(A)
|
70
|
+
96, 128, 128, // RGB(A) float
|
71
|
+
96, 128, 128, // BGR(A) float
|
72
|
+
};
|
73
|
+
if (type_ < 0 || COLORSPACE_LAST <= type_) return BPPS[UNKNOWN];
|
74
|
+
return BPPS[type_];
|
75
|
+
}
|
76
|
+
|
77
|
+
int
|
78
|
+
ColorSpace::Bpp () const
|
79
|
+
{
|
80
|
+
return bit2byte(bpp());
|
81
|
+
}
|
82
|
+
|
83
|
+
int
|
84
|
+
ColorSpace::alpha_pos () const
|
85
|
+
{
|
86
|
+
return is_alpha_last() ? 3 : 0;
|
87
|
+
}
|
88
|
+
|
89
|
+
bool
|
90
|
+
ColorSpace::is_gray () const
|
91
|
+
{
|
92
|
+
return GRAY_FIRST <= (int) type_ && (int) type_ <= GRAY_LAST;
|
93
|
+
}
|
94
|
+
|
95
|
+
bool
|
96
|
+
ColorSpace::is_rgb () const
|
97
|
+
{
|
98
|
+
return
|
99
|
+
(RGB_888 <= type_ && type_ <= XRGB_8888) ||
|
100
|
+
(RGB_float <= type_ && type_ <= ARGB_float);
|
101
|
+
}
|
102
|
+
|
103
|
+
bool
|
104
|
+
ColorSpace::is_bgr () const
|
105
|
+
{
|
106
|
+
return
|
107
|
+
(BGR_888 <= type_ && type_ <= XBGR_8888) ||
|
108
|
+
(BGR_float <= type_ && type_ <= ABGR_float);
|
109
|
+
}
|
110
|
+
|
111
|
+
bool
|
112
|
+
ColorSpace::is_float () const
|
113
|
+
{
|
114
|
+
return
|
115
|
+
type_ == GRAY_float ||
|
116
|
+
(FLOAT_SECOND <= (int) type_ && (int) type_ <= FLOAT_LAST);
|
117
|
+
}
|
118
|
+
|
119
|
+
bool
|
120
|
+
ColorSpace::has_alpha () const
|
121
|
+
{
|
122
|
+
return
|
123
|
+
type_ == RGBA_8888 || type_ == ARGB_8888 ||
|
124
|
+
type_ == BGRA_8888 || type_ == ABGR_8888 ||
|
125
|
+
type_ == RGBA_float || type_ == ARGB_float ||
|
126
|
+
type_ == BGRA_float || type_ == ABGR_float;
|
127
|
+
}
|
128
|
+
|
129
|
+
bool
|
130
|
+
ColorSpace::has_skip () const
|
131
|
+
{
|
132
|
+
return
|
133
|
+
type_ == RGBX_8888 || type_ == XRGB_8888 ||
|
134
|
+
type_ == BGRX_8888 || type_ == XBGR_8888;
|
135
|
+
}
|
136
|
+
|
137
|
+
bool
|
138
|
+
ColorSpace::is_alpha_first () const
|
139
|
+
{
|
140
|
+
return
|
141
|
+
type_ == ARGB_8888 || type_ == ABGR_8888 ||
|
142
|
+
type_ == ARGB_float || type_ == ABGR_float;
|
143
|
+
}
|
144
|
+
|
145
|
+
bool
|
146
|
+
ColorSpace::is_alpha_last () const
|
147
|
+
{
|
148
|
+
return
|
149
|
+
type_ == RGBA_8888 || type_ == BGRA_8888 ||
|
150
|
+
type_ == RGBA_float || type_ == BGRA_float;
|
151
|
+
}
|
152
|
+
|
153
|
+
bool
|
154
|
+
ColorSpace::is_skip_first () const
|
155
|
+
{
|
156
|
+
return type_ == XRGB_8888 || type_ == XBGR_8888;
|
157
|
+
}
|
158
|
+
|
159
|
+
bool
|
160
|
+
ColorSpace::is_skip_last () const
|
161
|
+
{
|
162
|
+
return type_ == RGBX_8888 || type_ == BGRX_8888;
|
163
|
+
}
|
164
|
+
|
165
|
+
bool
|
166
|
+
ColorSpace::is_premult () const
|
167
|
+
{
|
168
|
+
return premult;
|
169
|
+
}
|
170
|
+
|
171
|
+
ColorSpace::operator bool () const
|
172
|
+
{
|
173
|
+
return FIRST <= (int) type_ && (int) type_ <= LAST;
|
174
|
+
}
|
175
|
+
|
176
|
+
bool
|
177
|
+
ColorSpace::operator ! () const
|
178
|
+
{
|
179
|
+
return !operator bool();
|
180
|
+
}
|
181
|
+
|
182
|
+
|
183
|
+
}// Rays
|
data/src/helpers.cpp
ADDED
data/src/image.cpp
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
#include "rays/image.h"
|
2
|
+
|
3
|
+
|
4
|
+
#include <rays/bitmap.h>
|
5
|
+
#include <rays/texture.h>
|
6
|
+
|
7
|
+
|
8
|
+
namespace Rays
|
9
|
+
{
|
10
|
+
|
11
|
+
|
12
|
+
struct Image::Data
|
13
|
+
{
|
14
|
+
|
15
|
+
Bitmap bitmap;
|
16
|
+
|
17
|
+
bool alphatex;
|
18
|
+
|
19
|
+
mutable Texture texture;
|
20
|
+
|
21
|
+
Data ()
|
22
|
+
: alphatex(false)
|
23
|
+
{
|
24
|
+
}
|
25
|
+
|
26
|
+
};// Image::Data
|
27
|
+
|
28
|
+
|
29
|
+
Image::Image ()
|
30
|
+
{
|
31
|
+
}
|
32
|
+
|
33
|
+
Image::Image (
|
34
|
+
int width, int height, const ColorSpace& cs,
|
35
|
+
bool alphatex)
|
36
|
+
{
|
37
|
+
self->bitmap = Bitmap(width, height, cs);
|
38
|
+
self->alphatex = alphatex;
|
39
|
+
}
|
40
|
+
|
41
|
+
Image::Image (const Bitmap& bitmap, bool alphatex)
|
42
|
+
{
|
43
|
+
self->bitmap = bitmap;
|
44
|
+
self->alphatex = alphatex;
|
45
|
+
}
|
46
|
+
|
47
|
+
Image::~Image ()
|
48
|
+
{
|
49
|
+
}
|
50
|
+
|
51
|
+
int
|
52
|
+
Image::width () const
|
53
|
+
{
|
54
|
+
return self->bitmap.width();
|
55
|
+
}
|
56
|
+
|
57
|
+
int
|
58
|
+
Image::height () const
|
59
|
+
{
|
60
|
+
return self->bitmap.height();
|
61
|
+
}
|
62
|
+
|
63
|
+
const ColorSpace&
|
64
|
+
Image::color_space () const
|
65
|
+
{
|
66
|
+
return self->bitmap.color_space();
|
67
|
+
}
|
68
|
+
|
69
|
+
bool
|
70
|
+
Image::alpha_texture () const
|
71
|
+
{
|
72
|
+
return self->alphatex;
|
73
|
+
}
|
74
|
+
|
75
|
+
Bitmap&
|
76
|
+
Image::bitmap ()
|
77
|
+
{
|
78
|
+
return self->bitmap;
|
79
|
+
}
|
80
|
+
|
81
|
+
const Bitmap&
|
82
|
+
Image::bitmap () const
|
83
|
+
{
|
84
|
+
return const_cast<Image*>(this)->bitmap();
|
85
|
+
}
|
86
|
+
|
87
|
+
Texture&
|
88
|
+
Image::texture ()
|
89
|
+
{
|
90
|
+
if (
|
91
|
+
self->bitmap &&
|
92
|
+
(!self->texture || self->bitmap.dirty()))
|
93
|
+
{
|
94
|
+
self->texture = Texture(self->bitmap, self->alphatex);
|
95
|
+
self->bitmap.set_dirty(false);
|
96
|
+
}
|
97
|
+
|
98
|
+
return self->texture;
|
99
|
+
}
|
100
|
+
|
101
|
+
const Texture&
|
102
|
+
Image::texture () const
|
103
|
+
{
|
104
|
+
return const_cast<Image*>(this)->texture();
|
105
|
+
}
|
106
|
+
|
107
|
+
Image::operator bool () const
|
108
|
+
{
|
109
|
+
return !!self->bitmap;
|
110
|
+
}
|
111
|
+
|
112
|
+
bool
|
113
|
+
Image::operator ! () const
|
114
|
+
{
|
115
|
+
return !operator bool();
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
bool
|
120
|
+
load_image (Image* image, const char* path, bool alphatex)
|
121
|
+
{
|
122
|
+
if (!image || !path) return false;
|
123
|
+
|
124
|
+
Bitmap bitmap;
|
125
|
+
if (!load_bitmap(&bitmap, path))
|
126
|
+
return false;
|
127
|
+
|
128
|
+
*image = Image(bitmap, alphatex);
|
129
|
+
return *image;
|
130
|
+
}
|
131
|
+
|
132
|
+
|
133
|
+
}// Rays
|
data/src/painter.cpp
ADDED
@@ -0,0 +1,769 @@
|
|
1
|
+
#include "rays/painter.h"
|
2
|
+
|
3
|
+
|
4
|
+
#include <math.h>
|
5
|
+
#include <algorithm>
|
6
|
+
#include <rays/bitmap.h>
|
7
|
+
#include <rays/texture.h>
|
8
|
+
#include <rays/image.h>
|
9
|
+
|
10
|
+
|
11
|
+
namespace Rays
|
12
|
+
{
|
13
|
+
|
14
|
+
|
15
|
+
static const float PI = 3.141592653589793238462643383279f;
|
16
|
+
|
17
|
+
static const float PI_2 = PI * 2;
|
18
|
+
|
19
|
+
|
20
|
+
static void
|
21
|
+
gl_clear_error ()
|
22
|
+
{
|
23
|
+
glGetError();
|
24
|
+
}
|
25
|
+
|
26
|
+
static bool
|
27
|
+
gl_no_error ()
|
28
|
+
{
|
29
|
+
return glGetError() == GL_NO_ERROR;
|
30
|
+
}
|
31
|
+
|
32
|
+
|
33
|
+
struct Rect
|
34
|
+
{
|
35
|
+
|
36
|
+
coord x, y, width, height;
|
37
|
+
|
38
|
+
Rect ()
|
39
|
+
: x(0), y(0), width(0), height(0)
|
40
|
+
{
|
41
|
+
}
|
42
|
+
|
43
|
+
coord left () const
|
44
|
+
{
|
45
|
+
return x;
|
46
|
+
}
|
47
|
+
|
48
|
+
coord top () const
|
49
|
+
{
|
50
|
+
return y;
|
51
|
+
}
|
52
|
+
|
53
|
+
coord right () const
|
54
|
+
{
|
55
|
+
return x + width - 1;
|
56
|
+
}
|
57
|
+
|
58
|
+
coord bottom () const
|
59
|
+
{
|
60
|
+
return y + height - 1;
|
61
|
+
}
|
62
|
+
|
63
|
+
void set (coord x, coord y, coord width, coord height)
|
64
|
+
{
|
65
|
+
this->x = x;
|
66
|
+
this->y = y;
|
67
|
+
this->width = width;
|
68
|
+
this->height = height;
|
69
|
+
}
|
70
|
+
|
71
|
+
bool get (coord* x, coord* y, coord* width, coord* height)
|
72
|
+
{
|
73
|
+
if (!x && !y && !width && !height)
|
74
|
+
return false;
|
75
|
+
|
76
|
+
if (x) *x = this->x;
|
77
|
+
if (y) *y = this->y;
|
78
|
+
if (width) *width = this->width;
|
79
|
+
if (height) *height = this->height;
|
80
|
+
return true;
|
81
|
+
}
|
82
|
+
|
83
|
+
coord* array () const {return (coord*) this;}
|
84
|
+
|
85
|
+
operator bool () const
|
86
|
+
{
|
87
|
+
return width >= 0 && height >= 0;
|
88
|
+
}
|
89
|
+
|
90
|
+
bool operator ! () const
|
91
|
+
{
|
92
|
+
return !operator bool();
|
93
|
+
}
|
94
|
+
|
95
|
+
};// Rect
|
96
|
+
|
97
|
+
|
98
|
+
struct Color
|
99
|
+
{
|
100
|
+
|
101
|
+
float red, green, blue, alpha;
|
102
|
+
|
103
|
+
Color ()
|
104
|
+
: red(0), green(0), blue(0), alpha(0)
|
105
|
+
{
|
106
|
+
}
|
107
|
+
|
108
|
+
void set (float red, float green, float blue, float alpha)
|
109
|
+
{
|
110
|
+
this->red = red;
|
111
|
+
this->green = green;
|
112
|
+
this->blue = blue;
|
113
|
+
this->alpha = alpha;
|
114
|
+
}
|
115
|
+
|
116
|
+
bool get (float* red, float* green, float* blue, float* alpha) const
|
117
|
+
{
|
118
|
+
if (!red && !green && !blue && !alpha) return false;
|
119
|
+
if (red) *red = this->red;
|
120
|
+
if (green) *green = this->green;
|
121
|
+
if (blue) *blue = this->blue;
|
122
|
+
if (alpha) *alpha = this->alpha;
|
123
|
+
return true;
|
124
|
+
}
|
125
|
+
|
126
|
+
float* array () const {return (float*) this;}
|
127
|
+
|
128
|
+
};// Color
|
129
|
+
|
130
|
+
|
131
|
+
struct Painter::Data
|
132
|
+
{
|
133
|
+
|
134
|
+
Rect viewport, clip;
|
135
|
+
|
136
|
+
Color clear, colors[2];
|
137
|
+
|
138
|
+
bool painting, drawing, clipping;
|
139
|
+
|
140
|
+
Image textimage;
|
141
|
+
|
142
|
+
Data ()
|
143
|
+
: painting(false), drawing(false), clipping(false),
|
144
|
+
textimage(1, 1, GRAY, true)
|
145
|
+
{
|
146
|
+
}
|
147
|
+
|
148
|
+
bool use_color (size_t i) const
|
149
|
+
{
|
150
|
+
gl_clear_error();
|
151
|
+
|
152
|
+
const Color& c = colors[i];
|
153
|
+
if (c.alpha <= 0) return false;
|
154
|
+
|
155
|
+
glColor4fv(c.array());
|
156
|
+
return gl_no_error();
|
157
|
+
}
|
158
|
+
|
159
|
+
bool update_clip ()
|
160
|
+
{
|
161
|
+
gl_clear_error();
|
162
|
+
|
163
|
+
if (clip)
|
164
|
+
{
|
165
|
+
if (clipping) return true;
|
166
|
+
glEnable(GL_SCISSOR_TEST);
|
167
|
+
clipping = true;
|
168
|
+
}
|
169
|
+
else
|
170
|
+
{
|
171
|
+
if (!clipping) return true;
|
172
|
+
glDisable(GL_SCISSOR_TEST);
|
173
|
+
clipping = false;
|
174
|
+
}
|
175
|
+
|
176
|
+
return gl_no_error();
|
177
|
+
}
|
178
|
+
|
179
|
+
};// Painter::Data
|
180
|
+
|
181
|
+
|
182
|
+
enum ColorOrder
|
183
|
+
{
|
184
|
+
|
185
|
+
FILL = 0, STROKE
|
186
|
+
|
187
|
+
};// ColorOrder
|
188
|
+
|
189
|
+
|
190
|
+
Painter::Painter ()
|
191
|
+
{
|
192
|
+
}
|
193
|
+
|
194
|
+
Painter::~Painter ()
|
195
|
+
{
|
196
|
+
}
|
197
|
+
|
198
|
+
bool
|
199
|
+
Painter::canvas (coord x, coord y, coord width, coord height)
|
200
|
+
{
|
201
|
+
if (self->painting || width < 0 || height < 0)
|
202
|
+
return false;
|
203
|
+
|
204
|
+
self->viewport.set(x, y, width, height);
|
205
|
+
|
206
|
+
glViewport(
|
207
|
+
(int) self->viewport.x, (int) self->viewport.y,
|
208
|
+
(int) self->viewport.width, (int) self->viewport.height);
|
209
|
+
|
210
|
+
glMatrixMode(GL_PROJECTION);
|
211
|
+
glLoadIdentity();
|
212
|
+
|
213
|
+
glOrtho(
|
214
|
+
self->viewport.left(), self->viewport.right(),
|
215
|
+
self->viewport.top(), self->viewport.bottom(),
|
216
|
+
-100, 100);
|
217
|
+
glRotatef(180, 1, 0, 0);
|
218
|
+
glTranslatef(0, -self->viewport.height, 0);
|
219
|
+
|
220
|
+
glMatrixMode(GL_MODELVIEW);
|
221
|
+
glLoadIdentity();
|
222
|
+
|
223
|
+
return true;
|
224
|
+
}
|
225
|
+
|
226
|
+
bool
|
227
|
+
Painter::begin ()
|
228
|
+
{
|
229
|
+
if (self->painting) return false;
|
230
|
+
|
231
|
+
glEnable(GL_CULL_FACE);
|
232
|
+
glEnable(GL_BLEND);
|
233
|
+
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
234
|
+
|
235
|
+
self->painting = true;
|
236
|
+
|
237
|
+
no_clip();
|
238
|
+
clear();
|
239
|
+
|
240
|
+
return push();
|
241
|
+
}
|
242
|
+
|
243
|
+
bool
|
244
|
+
Painter::end ()
|
245
|
+
{
|
246
|
+
if (!self->painting) return false;
|
247
|
+
|
248
|
+
pop();
|
249
|
+
|
250
|
+
self->painting = false;
|
251
|
+
|
252
|
+
glDisable(GL_BLEND);
|
253
|
+
glDisable(GL_CULL_FACE);
|
254
|
+
|
255
|
+
return true;
|
256
|
+
}
|
257
|
+
|
258
|
+
bool
|
259
|
+
Painter::push ()
|
260
|
+
{
|
261
|
+
glPushMatrix();
|
262
|
+
return true;
|
263
|
+
}
|
264
|
+
|
265
|
+
bool
|
266
|
+
Painter::pop ()
|
267
|
+
{
|
268
|
+
glPopMatrix();
|
269
|
+
return true;
|
270
|
+
}
|
271
|
+
|
272
|
+
|
273
|
+
bool
|
274
|
+
Painter::line (coord x1, coord y1, coord x2, coord y2)
|
275
|
+
{
|
276
|
+
if (!self->painting || !self->use_color(STROKE))
|
277
|
+
return true;
|
278
|
+
|
279
|
+
if (!begin_shape(LINES)) return false;
|
280
|
+
bool ret =
|
281
|
+
vertex(x1, y1) &&
|
282
|
+
vertex(x2, y2);
|
283
|
+
if (!end_shape()) return false;
|
284
|
+
|
285
|
+
return ret;
|
286
|
+
}
|
287
|
+
|
288
|
+
bool
|
289
|
+
Painter::rect (coord x, coord y, coord width, coord height)
|
290
|
+
{
|
291
|
+
static const ShapeType TYPES[] = {QUADS, LINE_LOOP};
|
292
|
+
|
293
|
+
if (!self->painting) return false;
|
294
|
+
|
295
|
+
coord x2 = x + width;
|
296
|
+
coord y2 = y + height;
|
297
|
+
|
298
|
+
bool ret = true;
|
299
|
+
for (int i = 0; i < 2; ++i)
|
300
|
+
{
|
301
|
+
if (!self->use_color(i)) continue;
|
302
|
+
|
303
|
+
if (!begin_shape(TYPES[i])) return false;
|
304
|
+
ret &=
|
305
|
+
vertex(x, y) &&
|
306
|
+
vertex(x, y2) &&
|
307
|
+
vertex(x2, y2) &&
|
308
|
+
vertex(x2, y);
|
309
|
+
if (!end_shape()) return false;
|
310
|
+
}
|
311
|
+
|
312
|
+
return ret;
|
313
|
+
}
|
314
|
+
|
315
|
+
static bool
|
316
|
+
draw_ellipse (
|
317
|
+
Painter* painter,
|
318
|
+
coord x, coord y, coord width, coord height,
|
319
|
+
float angle_from, float angle_to, coord radius_min,
|
320
|
+
uint nsegment)
|
321
|
+
{
|
322
|
+
if (!painter || !painter->self->painting)
|
323
|
+
return false;
|
324
|
+
|
325
|
+
if (height == 0) height = width;
|
326
|
+
|
327
|
+
coord radius_x = width / 2;
|
328
|
+
coord radius_y = height / 2;
|
329
|
+
coord radius_x_min = radius_x * radius_min;
|
330
|
+
coord radius_y_min = radius_y * radius_min;
|
331
|
+
float from = angle_from / 360.f;
|
332
|
+
float to = angle_to / 360.f;
|
333
|
+
bool hole = radius_min != 0;
|
334
|
+
ShapeType types[] =
|
335
|
+
{
|
336
|
+
hole ? TRIANGLE_STRIP : TRIANGLE_FAN,
|
337
|
+
LINE_LOOP
|
338
|
+
};
|
339
|
+
|
340
|
+
x += radius_x;
|
341
|
+
y += radius_y;
|
342
|
+
|
343
|
+
bool ret = true;
|
344
|
+
for (int i = 0; i < 2; ++i)
|
345
|
+
{
|
346
|
+
if (!painter->self->use_color(i)) continue;
|
347
|
+
|
348
|
+
if (!painter->begin_shape(types[i])) return false;
|
349
|
+
|
350
|
+
if (!hole)
|
351
|
+
ret &= painter->vertex(x, y);
|
352
|
+
|
353
|
+
for (int seg = 0; seg <= (int) nsegment; ++seg)
|
354
|
+
{
|
355
|
+
float pos = (float) seg / (float) nsegment;
|
356
|
+
float radian = (from + (to - from) * pos) * PI_2;
|
357
|
+
float xx = cos(radian);
|
358
|
+
float yy = -sin(radian);
|
359
|
+
if (hole)
|
360
|
+
ret &= painter->vertex(x + xx * radius_x_min, y + yy * radius_y_min);
|
361
|
+
ret &= painter->vertex(x + xx * radius_x, y + yy * radius_y);
|
362
|
+
}
|
363
|
+
|
364
|
+
if (!painter->end_shape()) return false;
|
365
|
+
}
|
366
|
+
|
367
|
+
return ret;
|
368
|
+
}
|
369
|
+
|
370
|
+
static const uint ELLIPSE_NSEGMENT = 32;
|
371
|
+
|
372
|
+
bool
|
373
|
+
Painter::ellipse (
|
374
|
+
coord x, coord y, coord width, coord height, coord radius_min,
|
375
|
+
uint nsegment)
|
376
|
+
{
|
377
|
+
if (nsegment <= 0) nsegment = ELLIPSE_NSEGMENT;
|
378
|
+
return draw_ellipse(
|
379
|
+
this, x, y, width, height, 0, 360, radius_min, nsegment);
|
380
|
+
}
|
381
|
+
|
382
|
+
bool
|
383
|
+
Painter::arc (
|
384
|
+
coord x, coord y, coord width, coord height,
|
385
|
+
float angle_from, float angle_to, coord radius_min,
|
386
|
+
uint nsegment)
|
387
|
+
{
|
388
|
+
if (nsegment <= 0) nsegment = ELLIPSE_NSEGMENT;
|
389
|
+
return draw_ellipse(
|
390
|
+
this, x, y, width, height, angle_from, angle_to, radius_min, nsegment);
|
391
|
+
}
|
392
|
+
|
393
|
+
static bool
|
394
|
+
draw_image (
|
395
|
+
Painter* painter, const Texture& tex,
|
396
|
+
float s_min, float t_min, float s_max, float t_max,
|
397
|
+
coord x, coord y, coord width, coord height,
|
398
|
+
bool nostroke = false)
|
399
|
+
{
|
400
|
+
static const ShapeType TYPES[] = {QUADS, LINE_LOOP};
|
401
|
+
|
402
|
+
assert(tex);
|
403
|
+
|
404
|
+
if (!painter || !painter->self->painting)
|
405
|
+
return false;
|
406
|
+
|
407
|
+
coord x2 = x + width;
|
408
|
+
coord y2 = y + height;
|
409
|
+
|
410
|
+
glEnable(GL_TEXTURE_2D);
|
411
|
+
painter->texture(tex);
|
412
|
+
|
413
|
+
bool ret = true;
|
414
|
+
for (int i = 0; i < 2; ++i)
|
415
|
+
{
|
416
|
+
if (
|
417
|
+
(nostroke && TYPES[i] == LINE_LOOP) ||
|
418
|
+
!painter->self->use_color(i))
|
419
|
+
{
|
420
|
+
continue;
|
421
|
+
}
|
422
|
+
|
423
|
+
if (!painter->begin_shape(TYPES[i])) return false;
|
424
|
+
ret &=
|
425
|
+
painter->vertex(x, y, s_min, t_min) &&
|
426
|
+
painter->vertex(x, y2, s_min, t_max) &&
|
427
|
+
painter->vertex(x2, y2, s_max, t_max) &&
|
428
|
+
painter->vertex(x2, y, s_max, t_min);
|
429
|
+
if (!painter->end_shape()) return false;
|
430
|
+
}
|
431
|
+
|
432
|
+
painter->no_texture();
|
433
|
+
glDisable(GL_TEXTURE_2D);
|
434
|
+
|
435
|
+
return ret;
|
436
|
+
}
|
437
|
+
|
438
|
+
bool
|
439
|
+
Painter::image (const Image& image_, coord x, coord y)
|
440
|
+
{
|
441
|
+
if (!image_) return false;
|
442
|
+
|
443
|
+
const Texture& tex = image_.texture();
|
444
|
+
if (!tex) return false;
|
445
|
+
|
446
|
+
return draw_image(
|
447
|
+
this, tex,
|
448
|
+
0, 0, tex.s_max(), tex.t_max(),
|
449
|
+
x, y, tex.width(), tex.height());
|
450
|
+
}
|
451
|
+
|
452
|
+
bool
|
453
|
+
Painter::image (
|
454
|
+
const Image& image_, coord x, coord y, coord width, coord height)
|
455
|
+
{
|
456
|
+
if (!image_) return false;
|
457
|
+
|
458
|
+
const Texture& tex = image_.texture();
|
459
|
+
if (!tex) return false;
|
460
|
+
|
461
|
+
return draw_image(
|
462
|
+
this, tex,
|
463
|
+
0, 0, tex.s_max(), tex.t_max(),
|
464
|
+
x, y, width, height);
|
465
|
+
}
|
466
|
+
|
467
|
+
bool
|
468
|
+
Painter::image (
|
469
|
+
const Image& image_,
|
470
|
+
coord src_x, coord src_y, coord src_width, coord src_height,
|
471
|
+
coord dest_x, coord dest_y)
|
472
|
+
{
|
473
|
+
if (!image_) return false;
|
474
|
+
|
475
|
+
const Texture& tex = image_.texture();
|
476
|
+
if (!tex) return false;
|
477
|
+
|
478
|
+
coord dest_width = tex.width(), dest_height = tex.height();
|
479
|
+
float s = tex.s_max() / dest_width, t = tex.t_max() / dest_height;
|
480
|
+
return draw_image(
|
481
|
+
this, tex,
|
482
|
+
src_x * s, src_y * t, src_width * s, src_height * t,
|
483
|
+
dest_x, dest_y, dest_width, dest_height);
|
484
|
+
}
|
485
|
+
|
486
|
+
bool
|
487
|
+
Painter::image (
|
488
|
+
const Image& image_,
|
489
|
+
coord src_x, coord src_y, coord src_width, coord src_height,
|
490
|
+
coord dest_x, coord dest_y, coord dest_width, coord dest_height)
|
491
|
+
{
|
492
|
+
if (!image_) return false;
|
493
|
+
|
494
|
+
const Texture& tex = image_.texture();
|
495
|
+
if (!tex) return false;
|
496
|
+
|
497
|
+
float s = tex.s_max() / tex.width();
|
498
|
+
float t = tex.t_max() / tex.height();
|
499
|
+
return draw_image(
|
500
|
+
this, tex,
|
501
|
+
src_x * s, src_y * t, src_width * s, src_height * t,
|
502
|
+
dest_x, dest_y, dest_width, dest_height);
|
503
|
+
}
|
504
|
+
|
505
|
+
static bool
|
506
|
+
draw_text (
|
507
|
+
Painter* painter, const char* str, coord str_width, coord str_height,
|
508
|
+
coord x, coord y, coord width, coord height,
|
509
|
+
const Font& font)
|
510
|
+
{
|
511
|
+
assert(str && *str != '\0' && font);
|
512
|
+
|
513
|
+
if (!painter || !painter->self->painting)
|
514
|
+
return false;
|
515
|
+
|
516
|
+
Painter::Data* self = painter->self.get();
|
517
|
+
|
518
|
+
if (
|
519
|
+
self->textimage.width() < str_width ||
|
520
|
+
self->textimage.height() < str_height)
|
521
|
+
{
|
522
|
+
coord w = std::max((coord) self->textimage.width(), str_width);
|
523
|
+
coord h = std::max((coord) self->textimage.height(), str_height);
|
524
|
+
self->textimage = Image(
|
525
|
+
w + 1, h + 1, self->textimage.color_space(),
|
526
|
+
self->textimage.alpha_texture());
|
527
|
+
}
|
528
|
+
|
529
|
+
if (!self->textimage) return false;
|
530
|
+
|
531
|
+
if (!draw_string(&self->textimage.bitmap(), str, 0, 0, font))
|
532
|
+
return false;
|
533
|
+
|
534
|
+
const Texture& tex = self->textimage.texture();
|
535
|
+
if (!tex) return false;
|
536
|
+
|
537
|
+
float s = tex.s_max() / tex.width();
|
538
|
+
float t = tex.t_max() / tex.height();
|
539
|
+
return draw_image(
|
540
|
+
painter, tex,
|
541
|
+
0, 0, str_width * s, str_height * t,
|
542
|
+
x, y, width, height,
|
543
|
+
true);
|
544
|
+
}
|
545
|
+
|
546
|
+
bool
|
547
|
+
Painter::text (const char* str, coord x, coord y, const Font& font)
|
548
|
+
{
|
549
|
+
if (!str || !font) return false;
|
550
|
+
|
551
|
+
if (*str == '\0') return true;
|
552
|
+
|
553
|
+
coord w = 0, h = 0;
|
554
|
+
if (!font.get_extent(&w, &h, str))
|
555
|
+
return false;
|
556
|
+
|
557
|
+
return draw_text(
|
558
|
+
this, str, w, h, x, y, w, h, font);
|
559
|
+
}
|
560
|
+
|
561
|
+
bool
|
562
|
+
Painter::text (
|
563
|
+
const char* str, coord x, coord y, coord width, coord height,
|
564
|
+
const Font& font)
|
565
|
+
{
|
566
|
+
if (!str || !font) return false;
|
567
|
+
|
568
|
+
if (*str == '\0') return true;
|
569
|
+
|
570
|
+
coord w = 0, h = 0;
|
571
|
+
if (!font.get_extent(&w, &h, str))
|
572
|
+
return false;
|
573
|
+
|
574
|
+
return draw_text(this, str, w, h, x, y, width, height, font);
|
575
|
+
}
|
576
|
+
|
577
|
+
bool
|
578
|
+
Painter::clear ()
|
579
|
+
{
|
580
|
+
if (!self->painting) return false;
|
581
|
+
|
582
|
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
583
|
+
return true;
|
584
|
+
}
|
585
|
+
|
586
|
+
bool
|
587
|
+
Painter::get_clear (float* red, float* green, float* blue, float* alpha)
|
588
|
+
{
|
589
|
+
return self->clear.get(red, green, blue, alpha);
|
590
|
+
}
|
591
|
+
|
592
|
+
bool
|
593
|
+
Painter::set_clear (float red, float green, float blue, float alpha)
|
594
|
+
{
|
595
|
+
self->clear.set(red, green, blue, alpha);
|
596
|
+
glClearColor(red, green, blue, alpha);
|
597
|
+
return true;
|
598
|
+
}
|
599
|
+
|
600
|
+
bool
|
601
|
+
Painter::no_clear ()
|
602
|
+
{
|
603
|
+
return set_clear(
|
604
|
+
self->clear.red, self->clear.green, self->clear.blue, 0);
|
605
|
+
}
|
606
|
+
|
607
|
+
bool
|
608
|
+
Painter::get_fill (float* red, float* green, float* blue, float* alpha)
|
609
|
+
{
|
610
|
+
return self->colors[FILL].get(red, green, blue, alpha);
|
611
|
+
}
|
612
|
+
|
613
|
+
bool
|
614
|
+
Painter::set_fill (float red, float green, float blue, float alpha)
|
615
|
+
{
|
616
|
+
self->colors[FILL].set(red, green, blue, alpha);
|
617
|
+
return true;
|
618
|
+
}
|
619
|
+
|
620
|
+
bool
|
621
|
+
Painter::no_fill ()
|
622
|
+
{
|
623
|
+
self->colors[FILL].alpha = 0;
|
624
|
+
return true;
|
625
|
+
}
|
626
|
+
|
627
|
+
bool
|
628
|
+
Painter::get_stroke (float* red, float* green, float* blue, float* alpha)
|
629
|
+
{
|
630
|
+
return self->colors[STROKE].get(red, green, blue, alpha);
|
631
|
+
}
|
632
|
+
|
633
|
+
bool
|
634
|
+
Painter::set_stroke (float red, float green, float blue, float alpha)
|
635
|
+
{
|
636
|
+
self->colors[STROKE].set(red, green, blue, alpha);
|
637
|
+
return true;
|
638
|
+
}
|
639
|
+
|
640
|
+
bool
|
641
|
+
Painter::no_stroke ()
|
642
|
+
{
|
643
|
+
self->colors[STROKE].alpha = 0;
|
644
|
+
return true;
|
645
|
+
}
|
646
|
+
|
647
|
+
bool
|
648
|
+
Painter::get_clip (coord* x, coord* y, coord* width, coord* height)
|
649
|
+
{
|
650
|
+
return self->clip.get(x, y, width, height);
|
651
|
+
}
|
652
|
+
|
653
|
+
bool
|
654
|
+
Painter::set_clip (coord x, coord y, coord width, coord height)
|
655
|
+
{
|
656
|
+
self->clip.set(x, y, width, height);
|
657
|
+
if (!self->update_clip())
|
658
|
+
return false;
|
659
|
+
|
660
|
+
if (self->clip)
|
661
|
+
{
|
662
|
+
glScissor(
|
663
|
+
self->clip.x, -self->clip.y, self->clip.width, self->clip.height);
|
664
|
+
}
|
665
|
+
|
666
|
+
return true;
|
667
|
+
}
|
668
|
+
|
669
|
+
bool
|
670
|
+
Painter::no_clip ()
|
671
|
+
{
|
672
|
+
return set_clip(0, 0, -1, -1);
|
673
|
+
}
|
674
|
+
|
675
|
+
|
676
|
+
bool
|
677
|
+
Painter::begin_shape (ShapeType type)
|
678
|
+
{
|
679
|
+
if (!self->painting || self->drawing)
|
680
|
+
return false;
|
681
|
+
|
682
|
+
glBegin(type);
|
683
|
+
|
684
|
+
self->drawing = true;
|
685
|
+
return true;
|
686
|
+
}
|
687
|
+
|
688
|
+
bool
|
689
|
+
Painter::end_shape ()
|
690
|
+
{
|
691
|
+
if (!self->painting || !self->drawing)
|
692
|
+
return false;
|
693
|
+
|
694
|
+
glEnd();
|
695
|
+
|
696
|
+
self->drawing = false;
|
697
|
+
return true;
|
698
|
+
}
|
699
|
+
|
700
|
+
bool
|
701
|
+
Painter::color (float red, float green, float blue, float alpha)
|
702
|
+
{
|
703
|
+
if (!self->drawing) return false;
|
704
|
+
|
705
|
+
glColor4f(red, green, blue, alpha);
|
706
|
+
return true;
|
707
|
+
}
|
708
|
+
|
709
|
+
bool
|
710
|
+
Painter::texture (const Texture& tex)
|
711
|
+
{
|
712
|
+
if (!self->drawing) return false;
|
713
|
+
|
714
|
+
glBindTexture(GL_TEXTURE_2D, tex ? tex.id() : 0);
|
715
|
+
return true;
|
716
|
+
}
|
717
|
+
|
718
|
+
bool
|
719
|
+
Painter::no_texture ()
|
720
|
+
{
|
721
|
+
if (!self->drawing) return false;
|
722
|
+
|
723
|
+
glBindTexture(GL_TEXTURE_2D, 0);
|
724
|
+
return true;
|
725
|
+
}
|
726
|
+
|
727
|
+
bool
|
728
|
+
Painter::vertex (coord x, coord y)
|
729
|
+
{
|
730
|
+
return vertex(x, y, 0);
|
731
|
+
}
|
732
|
+
|
733
|
+
bool
|
734
|
+
Painter::vertex (coord x, coord y, coord z)
|
735
|
+
{
|
736
|
+
if (!self->drawing) return false;
|
737
|
+
|
738
|
+
glVertex3f(x, y, z);
|
739
|
+
return true;
|
740
|
+
}
|
741
|
+
|
742
|
+
bool
|
743
|
+
Painter::vertex (coord x, coord y, coord texcoord_s, coord texcoord_t)
|
744
|
+
{
|
745
|
+
return vertex(x, y, 0, texcoord_s, texcoord_t);
|
746
|
+
}
|
747
|
+
|
748
|
+
bool
|
749
|
+
Painter::vertex (coord x, coord y, coord z, coord texcoord_s, coord texcoord_t)
|
750
|
+
{
|
751
|
+
if (!self->drawing) return false;
|
752
|
+
|
753
|
+
glTexCoord2f(texcoord_s, texcoord_t);
|
754
|
+
return vertex(x, y, z);
|
755
|
+
}
|
756
|
+
|
757
|
+
Painter::operator bool () const
|
758
|
+
{
|
759
|
+
return self->viewport;
|
760
|
+
}
|
761
|
+
|
762
|
+
bool
|
763
|
+
Painter::operator ! () const
|
764
|
+
{
|
765
|
+
return !operator bool();
|
766
|
+
}
|
767
|
+
|
768
|
+
|
769
|
+
}// Rays
|