X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fvideo%2Fdrawing_context.cpp;h=faa95ddf58486b97cdf06b202aeeb6289eba98c6;hb=6492679a300bff2c17505c5d9bc9d333eeba384d;hp=15e8863936860bd059a02c0a81650442a0178db0;hpb=60908c905544776c376421b8d3e12eeb936c068f;p=supertux.git diff --git a/src/video/drawing_context.cpp b/src/video/drawing_context.cpp index 15e886393..faa95ddf5 100644 --- a/src/video/drawing_context.cpp +++ b/src/video/drawing_context.cpp @@ -1,12 +1,10 @@ -// $Id: drawing_context.cpp 2334 2005-04-04 16:26:14Z grumbel $ +// SuperTux +// Copyright (C) 2006 Matthias Braun // -// SuperTux - A Jump'n Run -// Copyright (C) 2004 Matthias Braun +// along with this program. If not, see . -#include -#include -#include +#include "video/drawing_context.hpp" -#include "drawing_context.h" -#include "surface.h" -#include "font.h" -#include "main.h" -#include "gameconfig.h" +#include +#include -DrawingContext::DrawingContext(SDL_Surface* targetsurface) +#include "math/sizef.hpp" +#include "supertux/gameconfig.hpp" +#include "supertux/globals.hpp" +#include "util/obstackpp.hpp" +#include "video/drawing_request.hpp" +#include "video/lightmap.hpp" +#include "video/renderer.hpp" +#include "video/surface.hpp" +#include "video/texture.hpp" +#include "video/texture_manager.hpp" +#include "video/video_system.hpp" + +DrawingContext::DrawingContext(VideoSystem& video_system_) : + video_system(video_system_), + transformstack(), + transform(), + blend_stack(), + blend_mode(), + drawing_requests(), + lightmap_requests(), + requests(), + ambient_color(1.0f, 1.0f, 1.0f, 1.0f), + target(NORMAL), + target_stack(), + obst(), + screenshot_requested(false) { - if(targetsurface) { - screen = targetsurface; - } else { - screen = SDL_GetVideoSurface(); - } + requests = &drawing_requests; + obstack_init(&obst); } DrawingContext::~DrawingContext() { + clear_drawing_requests(lightmap_requests); + clear_drawing_requests(drawing_requests); + + obstack_free(&obst, NULL); +} + +void +DrawingContext::clear_drawing_requests(DrawingRequests& requests_) +{ + for(auto& request : requests_) + { + if (request->request_data) + { + request->request_data->~DrawingRequestData(); + } + request->~DrawingRequest(); + } + requests_.clear(); } void -DrawingContext::draw_surface(const Surface* surface, const Vector& position, - int layer, uint32_t drawing_effect) +DrawingContext::draw_surface(SurfacePtr surface, const Vector& position, + float angle, const Color& color, const Blend& blend, + int layer) { assert(surface != 0); - - DrawingRequest request; - request.type = SURFACE; - request.pos = transform.apply(position); + 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->w < 0 || request.pos.y + surface->h < 0) + 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 | drawing_effect; - request.zoom = transform.zoom; - request.alpha = transform.alpha; - request.request_data = const_cast (surface); + request->layer = layer; + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; + request->angle = angle; + request->color = color; + request->blend = blend; - drawingrequests.push_back(request); + SurfaceRequest* surfacerequest = new(obst) SurfaceRequest(); + surfacerequest->surface = surface.get(); + request->request_data = surfacerequest; + + requests->push_back(request); } void -DrawingContext::draw_surface_part(const Surface* surface, const Vector& source, - const Vector& size, const Vector& dest, int layer, uint32_t drawing_effect) +DrawingContext::draw_surface(SurfacePtr surface, const Vector& position, + int layer) +{ + draw_surface(surface, position, 0.0f, Color(1.0f, 1.0f, 1.0f), Blend(), layer); +} + +void +DrawingContext::draw_surface_part(SurfacePtr surface, + const Rectf& srcrect, const Rectf& dstrect, + int layer) { assert(surface != 0); - DrawingRequest request; - - request.type = SURFACE_PART; - request.pos = transform.apply(dest); - request.layer = layer; - request.drawing_effect = transform.drawing_effect | drawing_effect; - request.alpha = transform.alpha; - - SurfacePartRequest* surfacepartrequest = new SurfacePartRequest(); - surfacepartrequest->size = size; - surfacepartrequest->source = source; - surfacepartrequest->surface = surface; - - // clip on screen borders - if(request.pos.x < 0) { - surfacepartrequest->size.x += request.pos.x; - if(surfacepartrequest->size.x <= 0) - return; - surfacepartrequest->source.x -= request.pos.x; - request.pos.x = 0; - } - if(request.pos.y < 0) { - surfacepartrequest->size.y += request.pos.y; - if(surfacepartrequest->size.y <= 0) - return; - surfacepartrequest->source.y -= request.pos.y; - request.pos.y = 0; - } - request.request_data = surfacepartrequest; + DrawingRequest* request = new(obst) DrawingRequest(); + + request->target = target; + request->type = SURFACE_PART; + request->pos = transform.apply(dstrect.p1); + request->layer = layer; + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; + + SurfacePartRequest* surfacepartrequest = new(obst) SurfacePartRequest(); + surfacepartrequest->srcrect = srcrect; + surfacepartrequest->dstsize = dstrect.get_size(); + surfacepartrequest->surface = surface.get(); - drawingrequests.push_back(request); + request->request_data = surfacepartrequest; + + requests->push_back(request); } void -DrawingContext::draw_text(const Font* font, const std::string& text, - const Vector& position, FontAlignment alignment, int layer, - uint32_t drawing_effect) +DrawingContext::draw_text(FontPtr font, const std::string& text, + const Vector& position, FontAlignment alignment, int layer, Color color) { - DrawingRequest request; - - request.type = TEXT; - request.pos = transform.apply(position); - request.layer = layer; - request.drawing_effect = transform.drawing_effect | drawing_effect; - request.zoom = transform.zoom; - request.alpha = transform.alpha; - - TextRequest* textrequest = new TextRequest; - textrequest->font = font; + DrawingRequest* request = new(obst) DrawingRequest(); + + request->target = target; + request->type = TEXT; + request->pos = transform.apply(position); + request->layer = layer; + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; + request->color = color; + + TextRequest* textrequest = new(obst) TextRequest(); + textrequest->font = font.get(); textrequest->text = text; textrequest->alignment = alignment; - request.request_data = textrequest; + request->request_data = textrequest; - drawingrequests.push_back(request); + requests->push_back(request); } void -DrawingContext::draw_center_text(const Font* font, const std::string& text, - const Vector& position, int layer, uint32_t drawing_effect) +DrawingContext::draw_center_text(FontPtr font, const std::string& text, + const Vector& position, int layer, Color color) { draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y), - CENTER_ALLIGN, layer, drawing_effect); + ALIGN_CENTER, layer, color); } void -DrawingContext::draw_gradient(Color top, Color bottom, int layer) +DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer) { - DrawingRequest request; + DrawingRequest* request = new(obst) DrawingRequest(); - request.type = GRADIENT; - request.pos = Vector(0,0); - request.layer = layer; + request->target = target; + request->type = GRADIENT; + request->pos = Vector(0,0); + request->layer = layer; - request.drawing_effect = transform.drawing_effect; - request.zoom = transform.zoom; - request.alpha = transform.alpha; + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; - GradientRequest* gradientrequest = new GradientRequest; + GradientRequest* gradientrequest = new(obst) GradientRequest(); gradientrequest->top = top; gradientrequest->bottom = bottom; - request.request_data = gradientrequest; + request->request_data = gradientrequest; - drawingrequests.push_back(request); + requests->push_back(request); } void DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size, - Color color, int layer) + const Color& color, int layer) { - DrawingRequest request; + DrawingRequest* request = new(obst) DrawingRequest(); - request.type = FILLRECT; - request.pos = transform.apply(topleft); - request.layer = layer; + request->target = target; + request->type = FILLRECT; + request->pos = transform.apply(topleft); + request->layer = layer; - request.drawing_effect = transform.drawing_effect; - request.zoom = transform.zoom; - request.alpha = transform.alpha; + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; - FillRectRequest* fillrectrequest = new FillRectRequest; + FillRectRequest* fillrectrequest = new(obst) FillRectRequest(); fillrectrequest->size = size; fillrectrequest->color = color; - request.request_data = fillrectrequest; + fillrectrequest->color.alpha = color.alpha * transform.alpha; + fillrectrequest->radius = 0.0f; + request->request_data = fillrectrequest; - drawingrequests.push_back(request); + requests->push_back(request); } void -DrawingContext::draw_surface_part(DrawingRequest& request) +DrawingContext::draw_filled_rect(const Rectf& rect, const Color& color, + int layer) { - SurfacePartRequest* surfacepartrequest - = (SurfacePartRequest*) request.request_data; - - surfacepartrequest->surface->impl->draw_part( - surfacepartrequest->source.x, surfacepartrequest->source.y, - request.pos.x, request.pos.y, - surfacepartrequest->size.x, surfacepartrequest->size.y, request.alpha, - request.drawing_effect); - - delete surfacepartrequest; + draw_filled_rect(rect, color, 0.0f, layer); } void -DrawingContext::draw_gradient(DrawingRequest& request) +DrawingContext::draw_filled_rect(const Rectf& rect, const Color& color, float radius, int layer) { - GradientRequest* gradientrequest = (GradientRequest*) request.request_data; - const Color& top = gradientrequest->top; - const Color& bottom = gradientrequest->bottom; - -#ifndef NOOPENGL - if(config->use_gl) - { - glBegin(GL_QUADS); - glColor3ub(top.red, top.green, top.blue); - glVertex2f(0, 0); - glVertex2f(SCREEN_WIDTH, 0); - glColor3ub(bottom.red, bottom.green, bottom.blue); - glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT); - glVertex2f(0, SCREEN_HEIGHT); - glEnd(); - } - else - { -#endif - if(&top == &bottom) - { - fillrect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, top.red, top.green, top.blue); - } - else - { - float redstep = (float(bottom.red)-float(top.red)) / float(SCREEN_HEIGHT); - float greenstep = (float(bottom.green)-float(top.green)) / float(SCREEN_HEIGHT); - float bluestep = (float(bottom.blue) - float(top.blue)) / float(SCREEN_HEIGHT); - - for(float y = 0; y < SCREEN_HEIGHT; y += 2) - fillrect(0, (int)y, SCREEN_WIDTH, 2, - int(float(top.red) + redstep * y), - int(float(top.green) + greenstep * y), - int(float(top.blue) + bluestep * y), 255); - } -#ifndef NOOPENGL + DrawingRequest* request = new(obst) DrawingRequest(); - } -#endif + request->target = target; + request->type = FILLRECT; + request->pos = transform.apply(rect.p1); + request->layer = layer; + + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; - delete gradientrequest; + FillRectRequest* fillrectrequest = new(obst) FillRectRequest; + fillrectrequest->size = Vector(rect.get_width(), rect.get_height()); + fillrectrequest->color = color; + fillrectrequest->color.alpha = color.alpha * transform.alpha; + fillrectrequest->radius = radius; + request->request_data = fillrectrequest; + + requests->push_back(request); } void -DrawingContext::draw_text(DrawingRequest& request) +DrawingContext::draw_inverse_ellipse(const Vector& pos, const Vector& size, const Color& color, int layer) { - TextRequest* textrequest = (TextRequest*) request.request_data; + DrawingRequest* request = new(obst) DrawingRequest(); + + request->target = target; + request->type = INVERSEELLIPSE; + request->pos = transform.apply(pos); + request->layer = layer; - textrequest->font->draw(textrequest->text, request.pos, - textrequest->alignment, request.drawing_effect, request.alpha); + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; - delete textrequest; + InverseEllipseRequest* ellipse = new(obst)InverseEllipseRequest; + + ellipse->color = color; + ellipse->color.alpha = color.alpha * transform.alpha; + ellipse->size = size; + request->request_data = ellipse; + + requests->push_back(request); +} + +Rectf +DrawingContext::get_cliprect() const +{ + return Rectf(get_translation().x, get_translation().y, + get_translation().x + SCREEN_WIDTH, + get_translation().y + SCREEN_HEIGHT); } void -DrawingContext::draw_filled_rect(DrawingRequest& request) +DrawingContext::get_light(const Vector& position, Color* color) { - FillRectRequest* fillrectrequest = (FillRectRequest*) request.request_data; + if( ambient_color.red == 1.0f && ambient_color.green == 1.0f + && ambient_color.blue == 1.0f ) { + *color = Color( 1.0f, 1.0f, 1.0f); + return; + } - float x = request.pos.x; - float y = request.pos.y; - float w = fillrectrequest->size.x; - float h = fillrectrequest->size.y; + DrawingRequest* request = new(obst) DrawingRequest(); + request->target = target; + request->type = GETLIGHT; + request->pos = transform.apply(position); -#ifndef NOOPENGL - if(config->use_gl) - { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4ub(fillrectrequest->color.red, fillrectrequest->color.green, - fillrectrequest->color.blue, fillrectrequest->color.alpha); - - glBegin(GL_POLYGON); - glVertex2f(x, y); - glVertex2f(x+w, y); - glVertex2f(x+w, y+h); - glVertex2f(x, y+h); - glEnd(); - glDisable(GL_BLEND); - } - else - { -#endif - SDL_Rect src, rect; - SDL_Surface *temp = NULL; - - rect.x = (int)x; - rect.y = (int)y; - rect.w = (int)w; - rect.h = (int)h; - - if(fillrectrequest->color.alpha != 255) - { - temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel, - screen->format->Rmask, - screen->format->Gmask, - screen->format->Bmask, - screen->format->Amask); - - - src.x = 0; - src.y = 0; - src.w = rect.w; - src.h = rect.h; - - SDL_FillRect(temp, &src, SDL_MapRGB(screen->format, - fillrectrequest->color.red, fillrectrequest->color.green, - fillrectrequest->color.blue)); - - SDL_SetAlpha(temp, SDL_SRCALPHA, fillrectrequest->color.alpha); - - SDL_BlitSurface(temp,0,screen,&rect); - - SDL_FreeSurface(temp); - } - else - SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, - fillrectrequest->color.red, fillrectrequest->color.green, - fillrectrequest->color.blue)); - -#ifndef NOOPENGL - - } -#endif + //There is no light offscreen. + if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT + || request->pos.x < 0 || request->pos.y < 0){ + *color = Color( 0, 0, 0); + return; + } - delete fillrectrequest; + request->layer = LAYER_GUI; //make sure all get_light requests are handled last. + GetLightRequest* getlightrequest = new(obst) GetLightRequest(); + getlightrequest->color_ptr = color; + request->request_data = getlightrequest; + lightmap_requests.push_back(request); } void DrawingContext::do_drawing() { -#ifdef DEBUG assert(transformstack.empty()); -#endif + assert(target_stack.empty()); transformstack.clear(); - - std::stable_sort(drawingrequests.begin(), drawingrequests.end()); - - for(DrawingRequests::iterator i = drawingrequests.begin(); - i != drawingrequests.end(); ++i) { - switch(i->type) { - case SURFACE: - { - const Surface* surface = (const Surface*) i->request_data; - - if(i->zoom != 1.0) - surface->impl->draw_stretched(i->pos.x * i->zoom, i->pos.y * i->zoom, - (int)(surface->w * i->zoom), (int)(surface->h * i->zoom), - i->alpha, i->drawing_effect); - else - surface->impl->draw(i->pos.x, i->pos.y, i->alpha, i->drawing_effect); - break; - } - case SURFACE_PART: - draw_surface_part(*i); - break; - case GRADIENT: - draw_gradient(*i); - break; - case TEXT: - draw_text(*i); + target_stack.clear(); + + //Use Lightmap if ambient color is not white. + bool use_lightmap = ( ambient_color.red != 1.0f || + ambient_color.green != 1.0f || + ambient_color.blue != 1.0f ); + + // PART1: create lightmap + if(use_lightmap) { + Lightmap& lightmap = video_system.get_lightmap(); + + lightmap.start_draw(ambient_color); + handle_drawing_requests(lightmap_requests); + lightmap.end_draw(); + + DrawingRequest* request = new(obst) DrawingRequest(); + request->target = NORMAL; + request->type = DRAW_LIGHTMAP; + request->layer = LAYER_HUD - 1; + drawing_requests.push_back(request); + } + + Renderer& renderer = video_system.get_renderer(); + renderer.start_draw(); + handle_drawing_requests(drawing_requests); + renderer.end_draw(); + + clear_drawing_requests(lightmap_requests); + clear_drawing_requests(drawing_requests); + + obstack_free(&obst, NULL); + obstack_init(&obst); + + // if a screenshot was requested, take one + if (screenshot_requested) { + renderer.do_take_screenshot(); + screenshot_requested = false; + } + + renderer.flip(); +} + +class RequestPtrCompare +{ +public: + bool operator()(const DrawingRequest* r1, const DrawingRequest* r2) const + { + return *r1 < *r2; + } +}; + +void +DrawingContext::handle_drawing_requests(DrawingRequests& requests_) +{ + std::stable_sort(requests_.begin(), requests_.end(), RequestPtrCompare()); + + Renderer& renderer = video_system.get_renderer(); + Lightmap& lightmap = video_system.get_lightmap(); + + DrawingRequests::const_iterator i; + for(i = requests_.begin(); i != requests_.end(); ++i) { + const DrawingRequest& request = **i; + + switch(request.target) { + case NORMAL: + switch(request.type) { + case SURFACE: + renderer.draw_surface(request); + break; + case SURFACE_PART: + renderer.draw_surface_part(request); + break; + case GRADIENT: + renderer.draw_gradient(request); + break; + case TEXT: + { + const TextRequest* textrequest = static_cast(request.request_data); + textrequest->font->draw(&renderer, textrequest->text, request.pos, + textrequest->alignment, request.drawing_effect, request.color, request.alpha); + } + break; + case FILLRECT: + renderer.draw_filled_rect(request); + break; + case INVERSEELLIPSE: + renderer.draw_inverse_ellipse(request); + break; + case DRAW_LIGHTMAP: + lightmap.do_draw(); + break; + case GETLIGHT: + lightmap.get_light(request); + break; + } break; - case FILLRECT: - draw_filled_rect(*i); + case LIGHTMAP: + switch(request.type) { + case SURFACE: + lightmap.draw_surface(request); + break; + case SURFACE_PART: + lightmap.draw_surface_part(request); + break; + case GRADIENT: + lightmap.draw_gradient(request); + break; + case TEXT: + { + const TextRequest* textrequest = static_cast(request.request_data); + textrequest->font->draw(&renderer, textrequest->text, request.pos, + textrequest->alignment, request.drawing_effect, request.color, request.alpha); + } + break; + case FILLRECT: + lightmap.draw_filled_rect(request); + break; + case INVERSEELLIPSE: + assert(!"InverseEllipse doesn't make sense on the lightmap"); + break; + case DRAW_LIGHTMAP: + lightmap.do_draw(); + break; + case GETLIGHT: + lightmap.get_light(request); + break; + } break; } } - - // update screen - if(config->use_gl) - SDL_GL_SwapBuffers(); - else - SDL_Flip(screen); - - drawingrequests.clear(); } void @@ -389,19 +456,64 @@ DrawingContext::pop_transform() } void -DrawingContext::set_drawing_effect(int effect) +DrawingContext::set_drawing_effect(DrawingEffect effect) { transform.drawing_effect = effect; } -void -DrawingContext::set_zooming(float zoom) +DrawingEffect +DrawingContext::get_drawing_effect() const { - transform.zoom = zoom; + return transform.drawing_effect; } void -DrawingContext::set_alpha(int alpha) +DrawingContext::set_alpha(float alpha) { transform.alpha = alpha; } + +float +DrawingContext::get_alpha() const +{ + return transform.alpha; +} + +void +DrawingContext::push_target() +{ + target_stack.push_back(target); +} + +void +DrawingContext::pop_target() +{ + set_target(target_stack.back()); + target_stack.pop_back(); +} + +void +DrawingContext::set_target(Target target_) +{ + this->target = target_; + if(target_ == LIGHTMAP) { + requests = &lightmap_requests; + } else { + assert(target_ == NORMAL); + requests = &drawing_requests; + } +} + +void +DrawingContext::set_ambient_color( Color new_color ) +{ + ambient_color = new_color; +} + +void +DrawingContext::take_screenshot() +{ + screenshot_requested = true; +} + +/* EOF */