void DrawingContext::draw_surface(SurfacePtr surface, const Vector& position, float angle, const Color& color, const Blend& blend, int layer) { assert(surface != 0); DrawingRequest* request = new(obst) DrawingRequest(); request->target = target; request->type = SURFACE; request->pos = transform.apply(position); if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT || request->pos.x + surface->get_width() < 0 || request->pos.y + surface->get_height() < 0) return; request->layer = layer; request->drawing_effect = transform.drawing_effect; request->alpha = transform.alpha; request->angle = angle; request->color = color; request->blend = blend; SurfaceRequest* surfacerequest = new(obst) SurfaceRequest(); surfacerequest->surface = surface.get(); request->request_data = surfacerequest; requests->push_back(request); }
void Canvas::draw_surface(const SurfacePtr& surface, const Vector& position, float angle, const Color& color, const Blend& blend, int layer) { if (!surface) return; const auto& cliprect = m_context.get_cliprect(); // discard clipped surface if (position.x > cliprect.get_right() || position.y > cliprect.get_bottom() || position.x + static_cast<float>(surface->get_width()) < cliprect.get_left() || position.y + static_cast<float>(surface->get_height()) < cliprect.get_top()) return; auto request = new(m_obst) TextureRequest(); request->type = TEXTURE; request->layer = layer; request->flip = m_context.transform().flip ^ surface->get_flip(); request->alpha = m_context.transform().alpha; request->blend = blend; request->srcrects.emplace_back(Rectf(surface->get_region())); request->dstrects.emplace_back(Rectf(apply_translate(position), Size(surface->get_width(), surface->get_height()))); request->angles.emplace_back(angle); request->texture = surface->get_texture().get(); request->displacement_texture = surface->get_displacement_texture().get(); request->color = color; m_requests.push_back(request); }
void draw_particles() { glPushMatrix(); glMultMatrixf(get_modelview().matrix); OpenGLState state; state.bind_texture(surface->get_texture()); state.set_blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); state.enable(GL_BLEND); state.activate(); glBegin(GL_QUADS); for(ParticleSystem::Particles::iterator i = psys.begin(); i != psys.end(); ++i) { if (i->t != -1.0f) { float p = 1.0f - psys.get_progress(i->t); Color color(psys.get_color_start().r * p + psys.get_color_stop().r * (1.0f - p), psys.get_color_start().g * p + psys.get_color_stop().g * (1.0f - p), psys.get_color_start().b * p + psys.get_color_stop().b * (1.0f - p), psys.get_color_start().a * p + psys.get_color_stop().a * (1.0f - p)); // scale float scale = psys.get_size_start() + psys.get_progress(i->t) * (psys.get_size_stop() - psys.get_size_start()); float width = surface->get_width() * scale; float height = surface->get_height() * scale; // rotate float x_rot = width/2; float y_rot = height/2; if (i->angle != 0) { float s = sinf(math::pi * i->angle/180.0f); float c = cosf(math::pi * i->angle/180.0f); x_rot = (width/2) * c - (height/2) * s; y_rot = (width/2) * s + (height/2) * c; } glColor4f(color.r, color.g, color.b, color.a); glTexCoord2f(0, 0); glVertex2f(i->x - x_rot, i->y - y_rot); glTexCoord2f(1, 0); glVertex2f(i->x + y_rot, i->y - x_rot); glTexCoord2f(1, 1); glVertex2f(i->x + x_rot, i->y + y_rot); glTexCoord2f(0, 1); glVertex2f(i->x - y_rot, i->y + x_rot); } } glEnd(); glPopMatrix(); }
int main(int argc, char** argv) { if (argc != 3) { std::cout << "Usage: " << argv[0] << " FILENAME" << std::endl; return -1; } Uint32 flags = SDL_INIT_VIDEO | SDL_INIT_JOYSTICK; if (SDL_Init(flags) < 0) { std::stringstream msg; msg << "Couldn't initialize SDL: " << SDL_GetError(); throw std::runtime_error(msg.str()); } else { atexit(SDL_Quit); SDL_EnableUNICODE(1); } Size window_size(1024, 576); OpenGLWindow window("Image Blur", window_size, window_size); SDL_ShowCursor(SDL_DISABLE); SurfaceManager surface_manager; FramebufferPtr framebuffer = Framebuffer::create_hdr(window_size.width, window_size.height); SurfacePtr surface = Surface::create(Pathname(argv[1], Pathname::kSysPath)); SurfacePtr surface_2 = Surface::create(Pathname(argv[2], Pathname::kSysPath)); float ray_length = 3.0f; Vector2f pos; Vector2f last_pos; int t = 0; std::vector<Vector2f> buffer(16); std::vector<Vector2f>::size_type buffer_pos = 0; bool quit = false; while(!quit) { SDL_Event event; last_pos = pos; while(SDL_PollEvent(&event)) { switch(event.type) { case SDL_QUIT: // FIXME: This should be a bit more gentle, but will do for now std::cout << "Ctrl-c or Window-close pressed, game is going to quit" << std::endl; quit = true; break; case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE) { quit = true; } break; case SDL_MOUSEBUTTONDOWN: if (event.button.button == 1) { ray_length *= 1.0f/1.4f; } else if (event.button.button == 3) { ray_length *= 1.4f; } std::cout << ray_length << std::endl; break; case SDL_MOUSEMOTION: //std::cout << event.motion.x << ", " << event.motion.y << std::endl; last_pos = pos; pos = Vector2f(1024.0f - static_cast<float>(event.motion.x), 576.0f - static_cast<float>(event.motion.y)); break; default: break; } } t += 30; //ray_length = sin(t/1000.0f); buffer[buffer_pos % buffer.size()] = pos; buffer_pos += 1; Display::push_framebuffer(framebuffer); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (true) { if (false) { for(size_t i = 0; i < std::min(buffer_pos, buffer.size()); ++i) { size_t idx = (buffer_pos - buffer.size() + i) % buffer.size(); pos = buffer[idx]; float n = static_cast<float>(buffer.size()); if (false) { // after image motion blur n = static_cast<float>(i) / ((n * n + n) / 2.0f); } else { // simple trail, doesn't fade out n = 1.0f / n; } surface->draw(SurfaceDrawingParameters() .set_scale(1.0f) .set_pos(pos - Vector2f(surface->get_width()/2, surface->get_height()/2)) .set_blend_func(GL_SRC_ALPHA, GL_ONE) .set_color(Color(1.0f, 1.0f, 1.0f, n))); } } else { int n = 32; for(int i = 0; i < n; ++i) { surface->draw(SurfaceDrawingParameters() .set_scale(1.0f) .set_pos((static_cast<float>(i)/static_cast<float>(n-1)) * pos + (static_cast<float>(n-i-1)/static_cast<float>(n-1)) * last_pos - Vector2f(surface->get_width()/2, surface->get_height()/2)) .set_blend_func(GL_SRC_ALPHA, GL_ONE) .set_color(Color(1.0f, 1.0f, 1.0f, 1.0f / static_cast<float>(n)))); } } } else { int n = 100; for(int i = 0; i < n; ++i) { float scale = 1.0f + static_cast<float>(i) / static_cast<float>(n) * ray_length; if (true) surface->draw(SurfaceDrawingParameters() .set_scale(scale) .set_pos(Vector2f(512, 288) - Vector2f(surface->get_width()/2 * scale, surface->get_height()/2 * scale) + (Vector2f(512, 288) - pos) * scale * 3.0f) .set_blend_func(GL_SRC_ALPHA, GL_ONE) .set_color(Color(1.0f, 1.0f, 1.0f, static_cast<float>(1)/static_cast<float>(n)))); if (false && i == 1) { scale = 1.0f; //std::cout << "Black: " << pos << std::endl; surface_2->draw(SurfaceDrawingParameters() .set_scale(scale) .set_pos(Vector2f(512, 288) - Vector2f(surface_2->get_width()/2 * scale, surface_2->get_height()/2 * scale) + (Vector2f(512, 288) - pos) * scale * 3.0f) .set_blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) .set_color(Color(1.0f, 1.0f, 1.0f, 1.0f))); } } } Display::pop_framebuffer(); if (true) { glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, framebuffer->get_handle()); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); glBlitFramebufferEXT(0, 0, framebuffer->get_width(), framebuffer->get_height(), 0, 0, framebuffer->get_width(), framebuffer->get_height(), GL_COLOR_BUFFER_BIT, GL_LINEAR /*NEAREST*/); glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); } SDL_GL_SwapBuffers(); SDL_Delay(20); } return 0; }
void Canvas::draw_surface_scaled(const SurfacePtr& surface, const Rectf& dstrect, int layer, const PaintStyle& style) { draw_surface_part(surface, Rectf(0.0f, 0.0f, static_cast<float>(surface->get_width()), static_cast<float>(surface->get_height())), dstrect, layer, style); }
void Statistics::draw_endseq_panel(DrawingContext& context, Statistics* best_stats, SurfacePtr backdrop) { // skip draw if stats were declared invalid if (!valid) return; // abort if we have no backdrop if (!backdrop) return; // no sense drawing stats if there are none if (total_coins + total_badguys + total_secrets == 0) return; int box_w = 220+110+110; int box_h = 30+20+20+20; int box_x = (int)((SCREEN_WIDTH - box_w) / 2); int box_y = (int)(SCREEN_HEIGHT / 2) - box_h; int bd_w = (int)backdrop->get_width(); int bd_h = (int)backdrop->get_height(); int bd_x = (int)((SCREEN_WIDTH - bd_w) / 2); int bd_y = box_y + (box_h / 2) - (bd_h / 2); int col1_x = box_x; int col2_x = col1_x+200; int col3_x = col2_x+130; int row1_y = box_y; int row2_y = row1_y+30; int row3_y = row2_y+20; int row4_y = row3_y+20; int row5_y = row4_y+20; context.push_transform(); context.set_alpha(0.5); context.draw_surface(backdrop, Vector(bd_x, bd_y), LAYER_HUD); context.pop_transform(); context.draw_text(Resources::normal_font, _("You"), Vector(col2_x, row1_y), ALIGN_LEFT, LAYER_HUD, Statistics::header_color); if (best_stats) context.draw_text(Resources::normal_font, _("Best"), Vector(col3_x, row1_y), ALIGN_LEFT, LAYER_HUD, Statistics::header_color); context.draw_text(Resources::normal_font, _("Coins"), Vector(col2_x-16, row3_y), ALIGN_RIGHT, LAYER_HUD, Statistics::header_color); context.draw_text(Resources::normal_font, coins_to_string(coins, total_coins), Vector(col2_x, row3_y), ALIGN_LEFT, LAYER_HUD, Statistics::text_color); if (best_stats) { int coins_best = (best_stats->coins > coins) ? best_stats->coins : coins; int total_coins_best = (best_stats->total_coins > total_coins) ? best_stats->total_coins : total_coins; context.draw_text(Resources::normal_font, coins_to_string(coins_best, total_coins_best), Vector(col3_x, row3_y), ALIGN_LEFT, LAYER_HUD, Statistics::text_color); } context.draw_text(Resources::normal_font, _("Badguys"), Vector(col2_x-16, row4_y), ALIGN_RIGHT, LAYER_HUD, Statistics::header_color); context.draw_text(Resources::normal_font, frags_to_string(badguys, total_badguys), Vector(col2_x, row4_y), ALIGN_LEFT, LAYER_HUD, Statistics::text_color); if (best_stats) { int badguys_best = (best_stats->badguys > badguys) ? best_stats->badguys : badguys; int total_badguys_best = (best_stats->total_badguys > total_badguys) ? best_stats->total_badguys : total_badguys; context.draw_text(Resources::normal_font, frags_to_string(badguys_best, total_badguys_best), Vector(col3_x, row4_y), ALIGN_LEFT, LAYER_HUD, Statistics::text_color); } context.draw_text(Resources::normal_font, _("Secrets"), Vector(col2_x-16, row5_y), ALIGN_RIGHT, LAYER_HUD, Statistics::header_color); context.draw_text(Resources::normal_font, secrets_to_string(secrets, total_secrets), Vector(col2_x, row5_y), ALIGN_LEFT, LAYER_HUD, Statistics::text_color); if (best_stats) { int secrets_best = (best_stats->secrets > secrets) ? best_stats->secrets : secrets; int total_secrets_best = (best_stats->total_secrets > total_secrets) ? best_stats->total_secrets : total_secrets; context.draw_text(Resources::normal_font, secrets_to_string(secrets_best, total_secrets_best), Vector(col3_x, row5_y), ALIGN_LEFT, LAYER_HUD, Statistics::text_color); } context.draw_text(Resources::normal_font, _("Time"), Vector(col2_x-16, row2_y), ALIGN_RIGHT, LAYER_HUD, Statistics::header_color); context.draw_text(Resources::normal_font, time_to_string(time), Vector(col2_x, row2_y), ALIGN_LEFT, LAYER_HUD, Statistics::text_color); if (best_stats) { float time_best = (best_stats->time < time) ? best_stats->time : time; context.draw_text(Resources::normal_font, time_to_string(time_best), Vector(col3_x, row2_y), ALIGN_LEFT, LAYER_HUD, Statistics::text_color); } }
void TileMap::draw(DrawingContext& context) { // skip draw if current opacity is 0.0 if (current_alpha == 0.0) return; context.push_transform(); if(draw_target != DrawingContext::NORMAL) { context.push_target(); context.set_target(draw_target); } if(drawing_effect != 0) context.set_drawing_effect(drawing_effect); if(current_alpha != 1.0) context.set_alpha(current_alpha); /* Force the translation to be an integer so that the tiles appear sharper. * For consistency (i.e., to avoid 1-pixel gaps), this needs to be done even * for solid tilemaps that are guaranteed to have speed 1. * FIXME Force integer translation for all graphics, not just tilemaps. */ float trans_x = roundf(context.get_translation().x); float trans_y = roundf(context.get_translation().y); context.set_translation(Vector(int(trans_x * speed_x), int(trans_y * speed_y))); Rectf draw_rect = Rectf(context.get_translation(), context.get_translation() + Vector(SCREEN_WIDTH, SCREEN_HEIGHT)); Rect t_draw_rect = get_tiles_overlapping(draw_rect); // Make sure the tilemap is within draw view if (t_draw_rect.is_valid()) { Vector start = get_tile_position(t_draw_rect.left, t_draw_rect.top); Vector pos; int tx, ty; for(pos.x = start.x, tx = t_draw_rect.left; tx < t_draw_rect.right; pos.x += 32, ++tx) { for(pos.y = start.y, ty = t_draw_rect.top; ty < t_draw_rect.bottom; pos.y += 32, ++ty) { int index = ty*width + tx; assert (index >= 0); assert (index < (width * height)); if (tiles[index] == 0) continue; const Tile* tile = tileset->get(tiles[index]); assert(tile != 0); tile->draw(context, pos, z_pos, current_tint); } /* for (pos y) */ } /* for (pos x) */ /* Make sure that tiles with images larger than 32x32 that overlap * the draw rect will be drawn, even if their tile position does * not fall within the draw rect. */ static const int EXTENDING_TILES = 32; int ex_left = std::max(0, t_draw_rect.left-EXTENDING_TILES); int ex_top = std::max(0, t_draw_rect.top-EXTENDING_TILES); Vector ex_start = get_tile_position(ex_left, ex_top); for (pos.x = start.x, tx = t_draw_rect.left; tx < t_draw_rect.right; pos.x += 32, ++tx) { for (pos.y = ex_start.y, ty = ex_top; ty < t_draw_rect.top; pos.y += 32, ++ty) { int index = ty*width + tx; assert (index >= 0); assert (index < (width * height)); if (tiles[index] == 0) continue; const Tile* tile = tileset->get(tiles[index]); assert(tile != 0); SurfacePtr image = tile->get_current_image(); if (image) { int h = image->get_height(); if (h <= 32) continue; if (pos.y + h > start.y) tile->draw(context, pos, z_pos, current_tint); } } } for (pos.x = ex_start.x, tx = ex_left; tx < t_draw_rect.right; pos.x += 32, ++tx) { for(pos.y = ex_start.y, ty = ex_top; ty < t_draw_rect.bottom; pos.y += 32, ++ty) { int index = ty*width + tx; assert (index >= 0); assert (index < (width * height)); if (tiles[index] == 0) continue; const Tile* tile = tileset->get(tiles[index]); assert(tile != 0); SurfacePtr image = tile->get_current_image(); if (image) { int w = image->get_width(); int h = image->get_height(); if (w <= 32 && h <= 32) continue; if (pos.x + w > start.x && pos.y + h > start.y) tile->draw(context, pos, z_pos, current_tint); } } } } if(draw_target != DrawingContext::NORMAL) { context.pop_target(); } context.pop_transform(); }
void SpriteData::parse_action(const ReaderMapping& lisp, const std::string& basedir) { auto action = std::unique_ptr<Action>(new Action); if(!lisp.get("name", action->name)) { if(!actions.empty()) throw std::runtime_error( "If there are more than one action, they need names!"); } std::vector<float> hitbox; if (lisp.get("hitbox", hitbox)) { switch(hitbox.size()) { case 4: action->hitbox_h = hitbox[3]; action->hitbox_w = hitbox[2]; //fall-through case 2: action->y_offset = hitbox[1]; action->x_offset = hitbox[0]; break; default: throw std::runtime_error("hitbox should specify 2/4 coordinates"); } } lisp.get("z-order", action->z_order); lisp.get("fps", action->fps); std::string mirror_action; if (lisp.get("mirror-action", mirror_action)) { const Action* act_tmp = get_action(mirror_action); if(act_tmp == NULL) { std::ostringstream msg; msg << "Could not mirror action. Action not found: \"" << mirror_action << "\"\n" << "Mirror actions must be defined after the real one!"; throw std::runtime_error(msg.str()); } else { float max_w = 0; float max_h = 0; for(int i = 0; static_cast<unsigned int>(i) < act_tmp->surfaces.size(); i++) { SurfacePtr surface = act_tmp->surfaces[i]->clone(); surface->hflip(); max_w = std::max(max_w, (float) surface->get_width()); max_h = std::max(max_h, (float) surface->get_height()); action->surfaces.push_back(surface); } if (action->hitbox_w < 1) action->hitbox_w = max_w - action->x_offset; if (action->hitbox_h < 1) action->hitbox_h = max_h - action->y_offset; } } else { // Load images std::vector<std::string> images; if(!lisp.get("images", images)) { std::stringstream msg; msg << "Sprite '" << name << "' contains no images in action '" << action->name << "'."; throw std::runtime_error(msg.str()); } else { float max_w = 0; float max_h = 0; for(std::vector<std::string>::size_type i = 0; i < images.size(); i++) { SurfacePtr surface = Surface::create(basedir + images[i]); max_w = std::max(max_w, (float) surface->get_width()); max_h = std::max(max_h, (float) surface->get_height()); action->surfaces.push_back(surface); } if (action->hitbox_w < 1) action->hitbox_w = max_w - action->x_offset; if (action->hitbox_h < 1) action->hitbox_h = max_h - action->y_offset; } } actions[action->name] = std::move(action); }