4
#ifndef SDL_VIDEO_OPENGL_ES
9
#include "concurrent_cache.hpp"
10
#include "filesystem.hpp"
11
#include "foreach.hpp"
12
#include "formula.hpp"
13
#include "formula_callable.hpp"
14
#include "formula_function.hpp"
15
#include "hi_res_timer.hpp"
16
#include "surface.hpp"
17
#include "surface_cache.hpp"
18
#include "surface_formula.hpp"
19
#include "unit_test.hpp"
21
using namespace graphics;
22
using namespace game_logic;
26
typedef std::pair<surface, std::string> cache_key;
27
typedef concurrent_cache<cache_key, surface> cache_map;
30
static cache_map instance;
34
class rgba_function : public function_expression {
36
explicit rgba_function(surface surf, const args_list& args)
37
: function_expression("rgba", args, 4), surf_(surf) {
41
variant execute(const formula_callable& variables) const {
42
return variant(SDL_MapRGBA(surf_->format,
43
Uint8(args()[0]->evaluate(variables).as_int()),
44
Uint8(args()[1]->evaluate(variables).as_int()),
45
Uint8(args()[2]->evaluate(variables).as_int()),
46
Uint8(args()[3]->evaluate(variables).as_int())));
51
class surface_formula_symbol_table : public function_symbol_table
54
explicit surface_formula_symbol_table(surface surf) : surf_(surf)
56
expression_ptr create_function(
57
const std::string& fn,
58
const std::vector<expression_ptr>& args,
59
const formula_callable_definition* callable_def) const;
64
expression_ptr surface_formula_symbol_table::create_function(
65
const std::string& fn,
66
const std::vector<expression_ptr>& args,
67
const formula_callable_definition* callable_def) const
70
return expression_ptr(new rgba_function(surf_, args));
72
return function_symbol_table::create_function(fn, args, callable_def);
76
class pixel_callable : public game_logic::formula_callable {
78
pixel_callable(const surface& surf, Uint32 pixel)
80
SDL_GetRGBA(pixel, surf->format, &r, &g, &b, &a);
81
static const unsigned char AlphaPixel[] = {0x6f, 0x6d, 0x51};
82
if(r == AlphaPixel[0] && g == AlphaPixel[1] && b == AlphaPixel[2]) {
87
bool is_alpha() const { return a == 0; }
89
variant get_value(const std::string& key) const {
90
switch(*key.c_str()) {
91
case 'r': return variant(r);
92
case 'g': return variant(g);
93
case 'b': return variant(b);
94
case 'a': return variant(a);
95
default: return variant();
102
void run_formula(surface surf, const std::string& algo)
104
const hi_res_timer timer("run_formula");
106
const int ticks = SDL_GetTicks();
107
surface_formula_symbol_table table(surf);
108
game_logic::formula f(algo, &table);
110
if(SDL_MUSTLOCK(surf.get())) {
111
const int res = SDL_LockSurface(surf.get());
117
std::map<Uint32, Uint32> pixel_map;
119
Uint32* pixels = reinterpret_cast<Uint32*>(surf->pixels);
120
Uint32* end_pixels = pixels + surf->w*surf->h;
122
Uint32 AlphaPixel = SDL_MapRGBA(surf->format, 0x6f, 0x6d, 0x51, 0x0);
125
while(pixels != end_pixels) {
126
if(((*pixels)&(~surf->format->Amask)) == AlphaPixel) {
130
std::map<Uint32, Uint32>::const_iterator itor = pixel_map.find(*pixels);
131
if(itor == pixel_map.end()) {
132
pixel_callable p(surf, *pixels);
133
Uint32 result = f.execute(p).as_int();
134
pixel_map[*pixels] = result;
137
*pixels = itor->second;
143
SDL_UnlockSurface(surf.get());
149
surface get_surface_formula(surface input, const std::string& algo)
155
cache_key key(input, algo);
156
surface surf = cache().get(key);
157
if(surf.get() == NULL) {
158
surf = input.clone();
159
run_formula(surf, algo);
160
cache().put(key, surf);
167
typedef std::map<std::pair<std::string, GLuint>, GLuint> shader_object_map;
168
shader_object_map shader_object_cache;
170
typedef std::map<std::pair<std::vector<std::string>,std::vector<std::string> >, GLuint> shader_map;
171
shader_map shader_cache;
173
void check_shader_errors(const std::string& fname, GLuint shader)
175
#ifndef SDL_VIDEO_OPENGL_ES
177
glGetShaderiv(shader, GL_COMPILE_STATUS, &value);
178
if(value == GL_FALSE) {
181
glGetShaderInfoLog(shader, sizeof(buf), &len, buf);
182
std::string errors(buf, buf + len);
183
ASSERT_LOG(false, "COMPILE ERROR IN SHADER " << fname << ": " << errors);
188
GLuint compile_shader(const std::string& shader_file, GLuint type)
190
GLuint& id = shader_object_cache[std::make_pair(shader_file, type)];
194
#ifndef SDL_VIDEO_OPENGL_ES
195
id = glCreateShader(type);
197
const std::string file_data = sys::read_file("data/shaders/" + shader_file);
199
const char* file_str = file_data.c_str();
200
glShaderSource(id, 1, &file_str, NULL);
203
check_shader_errors(shader_file, id);
213
GLuint get_gl_shader(const std::vector<std::string>& vertex_shader_file,
214
const std::vector<std::string>& fragment_shader_file)
216
#ifndef SDL_VIDEO_OPENGL_ES
217
if(vertex_shader_file.empty() || fragment_shader_file.empty()) {
221
shader_map::iterator itor = shader_cache.find(std::make_pair(vertex_shader_file, fragment_shader_file));
222
if(itor != shader_cache.end()) {
226
std::vector<GLuint> shader_objects;
227
foreach(const std::string& shader_file, vertex_shader_file) {
228
shader_objects.push_back(compile_shader(shader_file, GL_VERTEX_SHADER));
231
foreach(const std::string& shader_file, fragment_shader_file) {
232
shader_objects.push_back(compile_shader(shader_file, GL_FRAGMENT_SHADER));
235
GLuint program_id = glCreateProgram();
237
foreach(GLuint shader_id, shader_objects) {
238
glAttachShader(program_id, shader_id);
241
glLinkProgram(program_id);
243
GLint link_status = 0;
244
glGetProgramiv(program_id, GL_LINK_STATUS, &link_status);
245
if(link_status != GL_TRUE) {
248
glGetProgramInfoLog(program_id, sizeof(buf), &len, buf);
249
std::string errors(buf, buf + len);
250
ASSERT_LOG(false, "LINK ERROR IN SHADER PROGRAM: " << errors);
253
shader_cache[std::make_pair(vertex_shader_file, fragment_shader_file)] = program_id;
263
BENCHMARK(surface_formula)
265
surface s(graphics::surface_cache::get("characters/frogatto-spritesheet1.png"));
268
surface target(SDL_CreateRGBSurface(SDL_SWSURFACE,s->w,s->h,32,SURFACE_MASK));
269
SDL_BlitSurface(s.get(), NULL, target.get(), NULL);
271
const std::string algo("rgba(b,r,g,a)");
273
run_formula(target, algo);
277
BENCHMARK(pixel_table)
279
//This is some hard coded test data. It gives the set of pixels in
280
//the input image, and the pixels we want to map to.
281
const Uint32 PixelsFrom[] = {0xFF00FFFF, 0xFFFFFFFF, 0x9772FF13, 0xFF002145, 0x00FFFFFF, 0x94FF28FF };
282
const Uint32 PixelsTo[] = {0x00FF0000, 0xFF00FFFF, 0xFFFFFFFF, 0x9772FF13, 0xFF002145, 0x00FFFFFF };
283
const int NumColors = sizeof(PixelsFrom)/sizeof(*PixelsFrom);
285
//Set up an image of a million pixels in size. Set all values to values
286
//in the 'pixels from' range.
287
std::vector<Uint32> image(1000000);
288
for(int n = 0; n != image.size(); ++n) {
289
image[n] = PixelsFrom[n%NumColors];
292
//set up our table mapping pixels from -> pixels to.
293
typedef std::map<Uint32, Uint32> PixelTable;
295
for(int n = 0; n != NumColors; ++n) {
296
table.insert(std::pair<Uint32, Uint32>(PixelsFrom[n], PixelsTo[n]));
299
//now go over the image and map all source pixels to their destinations.
300
//this is the part that we want to benchmark.
302
for(int n = 0; n != image.size(); ++n) {
303
image[n] = table[image[n]];