X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fvideo%2Fdrawing_context.cpp;h=90cb1db285afdd6fdbebef3548d8981b25a71cb6;hb=53209e9747f4c830eeeb926d3a44918ed86621ba;hp=8633956dc8c4c10d2f41126411be2bc36cf6958d;hpb=20478842796ab18418ca69966047148dfacdf27a;p=supertux.git diff --git a/src/video/drawing_context.cpp b/src/video/drawing_context.cpp index 8633956dc..90cb1db28 100644 --- a/src/video/drawing_context.cpp +++ b/src/video/drawing_context.cpp @@ -1,12 +1,10 @@ -// $Id$ -// // SuperTux // Copyright (C) 2006 Matthias Braun // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,90 +12,23 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#include +// along with this program. If not, see . -#include #include -#include -#include -#include -#include -#include -#include -#include - -#include "drawing_context.hpp" -#include "surface.hpp" -#include "font.hpp" -#include "main.hpp" -#include "gameconfig.hpp" -#include "glutil.hpp" -#include "texture.hpp" -#include "texture_manager.hpp" -#include "obstack/obstackpp.hpp" -#define LIGHTMAP_DIV 5 - -enum RequestType -{ - SURFACE, SURFACE_PART, TEXT, GRADIENT, FILLRECT, LIGHTMAPREQUEST, GETLIGHT -}; - -struct SurfacePartRequest -{ - const Surface* surface; - Vector source, size; -}; - -struct TextRequest -{ - const Font* font; - std::string text; - FontAlignment alignment; -}; - -struct GradientRequest -{ - Color top, bottom; - Vector size; -}; - -struct FillRectRequest -{ - Color color; - Vector size; -}; - -struct DrawingRequest -{ - RequestType type; - Vector pos; - - int layer; - DrawingEffect drawing_effect; - float alpha; - Blend blend; - float angle; - Color color; - - void* request_data; - - DrawingRequest() - : angle(0.0f), - color(1.0f, 1.0f, 1.0f, 1.0f) - {} +#include - bool operator<(const DrawingRequest& other) const - { - return layer < other.layer; - } -}; +#include "video/drawing_context.hpp" -struct GetLightRequest -{ - Color* color_ptr; -}; +#include "obstack/obstackpp.hpp" +#include "supertux/gameconfig.hpp" +#include "supertux/globals.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_systems.hpp" static inline int next_po2(int val) { @@ -108,33 +39,42 @@ static inline int next_po2(int val) return result; } -DrawingContext::DrawingContext() - : ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL), screenshot_requested(false) +DrawingContext::DrawingContext() : + renderer(0), + lightmap(0), + 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) { - screen = SDL_GetVideoSurface(); - - lightmap_width = screen->w / LIGHTMAP_DIV; - lightmap_height = screen->h / LIGHTMAP_DIV; - unsigned int width = next_po2(lightmap_width); - unsigned int height = next_po2(lightmap_height); - - lightmap = new Texture(width, height, GL_RGB); - - lightmap_uv_right = static_cast(lightmap_width) / static_cast(width); - lightmap_uv_bottom = static_cast(lightmap_height) / static_cast(height); - texture_manager->register_texture(lightmap); - requests = &drawing_requests; - obstack_init(&obst); } DrawingContext::~DrawingContext() { + delete renderer; + delete lightmap; + obstack_free(&obst, NULL); +} - texture_manager->remove_texture(lightmap); +void +DrawingContext::init_renderer() +{ + delete renderer; delete lightmap; + + renderer = new_renderer(); + lightmap = new_lightmap(); } void @@ -146,12 +86,13 @@ DrawingContext::draw_surface(const Surface* surface, const Vector& 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->get_width() < 0 - || request->pos.y + surface->get_height() < 0) + || request->pos.x + surface->get_width() < 0 + || request->pos.y + surface->get_height() < 0) return; request->layer = layer; @@ -168,19 +109,20 @@ DrawingContext::draw_surface(const Surface* surface, const Vector& position, void DrawingContext::draw_surface(const Surface* surface, const Vector& position, - int layer) + int layer) { draw_surface(surface, position, 0.0f, Color(1.0f, 1.0f, 1.0f), Blend(), layer); } void DrawingContext::draw_surface_part(const Surface* surface, const Vector& source, - const Vector& size, const Vector& dest, int layer) + const Vector& size, const Vector& dest, int layer) { assert(surface != 0); DrawingRequest* request = new(obst) DrawingRequest(); + request->target = target; request->type = SURFACE_PART; request->pos = transform.apply(dest); request->layer = layer; @@ -214,15 +156,17 @@ DrawingContext::draw_surface_part(const Surface* surface, const Vector& source, void DrawingContext::draw_text(const Font* font, const std::string& text, - const Vector& position, FontAlignment alignment, int layer) + const Vector& position, FontAlignment alignment, int layer, Color color) { 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; @@ -235,10 +179,10 @@ DrawingContext::draw_text(const Font* font, const std::string& text, void DrawingContext::draw_center_text(const Font* font, const std::string& text, - const Vector& position, int layer) + const Vector& position, int layer, Color color) { draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y), - ALIGN_CENTER, layer); + ALIGN_CENTER, layer, color); } void @@ -246,6 +190,7 @@ DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer) { DrawingRequest* request = new(obst) DrawingRequest(); + request->target = target; request->type = GRADIENT; request->pos = Vector(0,0); request->layer = layer; @@ -267,6 +212,7 @@ DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size, { DrawingRequest* request = new(obst) DrawingRequest(); + request->target = target; request->type = FILLRECT; request->pos = transform.apply(topleft); request->layer = layer; @@ -278,6 +224,7 @@ DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size, fillrectrequest->size = size; fillrectrequest->color = color; fillrectrequest->color.alpha = color.alpha * transform.alpha; + fillrectrequest->radius = 0.0f; request->request_data = fillrectrequest; requests->push_back(request); @@ -287,11 +234,18 @@ void DrawingContext::draw_filled_rect(const Rect& rect, const Color& color, int layer) { + draw_filled_rect(rect, color, 0.0f, layer); +} + +void +DrawingContext::draw_filled_rect(const Rect& rect, const Color& color, float radius, int layer) +{ DrawingRequest* request = new(obst) DrawingRequest(); - request->type = FILLRECT; - request->pos = transform.apply(rect.p1); - request->layer = layer; + 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; @@ -300,9 +254,33 @@ DrawingContext::draw_filled_rect(const Rect& rect, const Color& color, 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); + requests->push_back(request); +} + +void +DrawingContext::draw_inverse_ellipse(const Vector& pos, const Vector& size, const Color& color, int layer) +{ + DrawingRequest* request = new(obst) DrawingRequest(); + + request->target = target; + request->type = INVERSEELLIPSE; + request->pos = transform.apply(pos); + request->layer = layer; + + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; + + 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); } void @@ -315,12 +293,13 @@ DrawingContext::get_light(const Vector& position, Color* color) } DrawingRequest* request = new(obst) DrawingRequest(); + request->target = target; request->type = GETLIGHT; request->pos = transform.apply(position); //There is no light offscreen. if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT - || request->pos.x < 0 || request->pos.y < 0){ + || request->pos.x < 0 || request->pos.y < 0){ *color = Color( 0, 0, 0); return; } @@ -333,120 +312,6 @@ DrawingContext::get_light(const Vector& position, Color* color) } void -DrawingContext::get_light(const DrawingRequest& request) const -{ - const GetLightRequest* getlightrequest - = (GetLightRequest*) request.request_data; - - float pixels[3]; - for( int i = 0; i<3; i++) - pixels[i] = 0.0f; //set to black - - float posX = request.pos.x * lightmap_width / SCREEN_WIDTH; - float posY = screen->h - request.pos.y * lightmap_height / SCREEN_HEIGHT; - glReadPixels((GLint) posX, (GLint) posY , 1, 1, GL_RGB, GL_FLOAT, pixels); - *(getlightrequest->color_ptr) = Color( pixels[0], pixels[1], pixels[2]); - //printf("get_light %f/%f =>%f/%f r%f g%f b%f\n", request.pos.x, request.pos.y, posX, posY, pixels[0], pixels[1], pixels[2]); -} - -void -DrawingContext::draw_surface_part(const DrawingRequest& request) const -{ - const SurfacePartRequest* surfacepartrequest - = (SurfacePartRequest*) request.request_data; - - surfacepartrequest->surface->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); -} - -void -DrawingContext::draw_gradient(const DrawingRequest& request) const -{ - const GradientRequest* gradientrequest - = (GradientRequest*) request.request_data; - const Color& top = gradientrequest->top; - const Color& bottom = gradientrequest->bottom; - - glDisable(GL_TEXTURE_2D); - glBegin(GL_QUADS); - glColor4f(top.red, top.green, top.blue, top.alpha); - glVertex2f(0, 0); - glVertex2f(SCREEN_WIDTH, 0); - glColor4f(bottom.red, bottom.green, bottom.blue, bottom.alpha); - glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT); - glVertex2f(0, SCREEN_HEIGHT); - glEnd(); - glEnable(GL_TEXTURE_2D); - glColor4f(1, 1, 1, 1); -} - -void -DrawingContext::draw_text(const DrawingRequest& request) const -{ - const TextRequest* textrequest = (TextRequest*) request.request_data; - - textrequest->font->draw(textrequest->text, request.pos, - textrequest->alignment, request.drawing_effect, request.alpha); -} - -void -DrawingContext::draw_filled_rect(const DrawingRequest& request) const -{ - const FillRectRequest* fillrectrequest - = (FillRectRequest*) request.request_data; - - float x = request.pos.x; - float y = request.pos.y; - float w = fillrectrequest->size.x; - float h = fillrectrequest->size.y; - - glDisable(GL_TEXTURE_2D); - glColor4f(fillrectrequest->color.red, fillrectrequest->color.green, - fillrectrequest->color.blue, fillrectrequest->color.alpha); - - glBegin(GL_QUADS); - glVertex2f(x, y); - glVertex2f(x+w, y); - glVertex2f(x+w, y+h); - glVertex2f(x, y+h); - glEnd(); - glEnable(GL_TEXTURE_2D); - - glColor4f(1, 1, 1, 1); -} - -void -DrawingContext::draw_lightmap(const DrawingRequest& request) const -{ - const Texture* texture = reinterpret_cast (request.request_data); - - // multiple the lightmap with the framebuffer - glBlendFunc(GL_DST_COLOR, GL_ZERO); - - glBindTexture(GL_TEXTURE_2D, texture->get_handle()); - glBegin(GL_QUADS); - - glTexCoord2f(0, lightmap_uv_bottom); - glVertex2f(0, 0); - - glTexCoord2f(lightmap_uv_right, lightmap_uv_bottom); - glVertex2f(SCREEN_WIDTH, 0); - - glTexCoord2f(lightmap_uv_right, 0); - glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT); - - glTexCoord2f(0, 0); - glVertex2f(0, SCREEN_HEIGHT); - - glEnd(); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -} - -void DrawingContext::do_drawing() { #ifdef DEBUG @@ -462,58 +327,33 @@ DrawingContext::do_drawing() // PART1: create lightmap if(use_lightmap) { - glViewport(0, screen->h - lightmap_height, lightmap_width, lightmap_height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glClearColor( ambient_color.red, ambient_color.green, ambient_color.blue, 1 ); - glClear(GL_COLOR_BUFFER_BIT); + lightmap->start_draw(ambient_color); handle_drawing_requests(lightmap_requests); - lightmap_requests.clear(); - - glDisable(GL_BLEND); - glBindTexture(GL_TEXTURE_2D, lightmap->get_handle()); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, screen->h - lightmap_height, lightmap_width, lightmap_height); - - glViewport(0, 0, screen->w, screen->h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glEnable(GL_BLEND); + lightmap->end_draw(); - // add a lightmap drawing request into the queue DrawingRequest* request = new(obst) DrawingRequest(); - request->type = LIGHTMAPREQUEST; + request->target = NORMAL; + request->type = DRAW_LIGHTMAP; request->layer = LAYER_HUD - 1; - request->request_data = lightmap; - requests->push_back(request); + drawing_requests.push_back(request); } + lightmap_requests.clear(); - //glClear(GL_COLOR_BUFFER_BIT); handle_drawing_requests(drawing_requests); drawing_requests.clear(); obstack_free(&obst, NULL); obstack_init(&obst); - assert_gl("drawing"); // if a screenshot was requested, take one if (screenshot_requested) { - do_take_screenshot(); + renderer->do_take_screenshot(); screenshot_requested = false; } - SDL_GL_SwapBuffers(); + renderer->flip(); } class RequestPtrCompare - : public std::binary_function { public: bool operator()(const DrawingRequest* r1, const DrawingRequest* r2) const @@ -523,7 +363,7 @@ public: }; void -DrawingContext::handle_drawing_requests(DrawingRequests& requests) const +DrawingContext::handle_drawing_requests(DrawingRequests& requests) { std::stable_sort(requests.begin(), requests.end(), RequestPtrCompare()); @@ -531,39 +371,70 @@ DrawingContext::handle_drawing_requests(DrawingRequests& requests) const for(i = requests.begin(); i != requests.end(); ++i) { const DrawingRequest& request = **i; - switch(request.type) { - case SURFACE: - { - const Surface* surface = (const Surface*) request.request_data; - if (request.angle == 0.0f && - request.color.red == 1.0f && request.color.green == 1.0f && - request.color.blue == 1.0f && request.color.alpha == 1.0f) { - surface->draw(request.pos.x, request.pos.y, request.alpha, - request.drawing_effect); - } else { - surface->draw(request.pos.x, request.pos.y, - request.alpha, request.angle, request.color, - request.blend, request.drawing_effect); + 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 = (TextRequest*) 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 SURFACE_PART: - draw_surface_part(request); - break; - case GRADIENT: - draw_gradient(request); - break; - case TEXT: - draw_text(request); - break; - case FILLRECT: - draw_filled_rect(request); - break; - case LIGHTMAPREQUEST: - draw_lightmap(request); - break; - case GETLIGHT: - get_light(request); + 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 = (TextRequest*) 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; } } @@ -640,67 +511,9 @@ DrawingContext::set_ambient_color( Color new_color ) } void -DrawingContext::do_take_screenshot() -{ - // [Christoph] TODO: Yes, this method also takes care of the actual disk I/O. Split it? - - // create surface to hold screenshot - #if SDL_BYTEORDER == SDL_BIG_ENDIAN - SDL_Surface* shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x00FF0000, 0x0000FF00, 0x000000FF, 0); - #else - SDL_Surface* shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0); - #endif - if (!shot_surf) { - log_warning << "Could not create RGB Surface to contain screenshot" << std::endl; - return; - } - - // read pixels into array - char* pixels = new char[3 * SCREEN_WIDTH * SCREEN_HEIGHT]; - if (!pixels) { - log_warning << "Could not allocate memory to store screenshot" << std::endl; - SDL_FreeSurface(shot_surf); - return; - } - glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels); - - // copy array line-by-line - for (int i = 0; i < SCREEN_HEIGHT; i++) { - char* src = pixels + (3 * SCREEN_WIDTH * (SCREEN_HEIGHT - i - 1)); - char* dst = ((char*)shot_surf->pixels) + i * shot_surf->pitch; - memcpy(dst, src, 3 * SCREEN_WIDTH); - } - - // free array - delete[](pixels); - - // save screenshot - static const std::string writeDir = PHYSFS_getWriteDir(); - static const std::string dirSep = PHYSFS_getDirSeparator(); - static const std::string baseName = "screenshot"; - static const std::string fileExt = ".bmp"; - std::string fullFilename; - for (int num = 0; num < 1000; num++) { - std::ostringstream oss; - oss << baseName; - oss << std::setw(3) << std::setfill('0') << num; - oss << fileExt; - std::string fileName = oss.str(); - fullFilename = writeDir + dirSep + fileName; - if (!PHYSFS_exists(fileName.c_str())) { - SDL_SaveBMP(shot_surf, fullFilename.c_str()); - log_debug << "Wrote screenshot to \"" << fullFilename << "\"" << std::endl; - SDL_FreeSurface(shot_surf); - return; - } - } - log_warning << "Did not save screenshot, because all files up to \"" << fullFilename << "\" already existed" << std::endl; - SDL_FreeSurface(shot_surf); -} - -void DrawingContext::take_screenshot() { screenshot_requested = true; } +/* EOF */