Hi,
After, um ... four (?) hours of hacking, I'm proud to present you my new
SDL surface patch. I tryed to use second form of
CL_SurfaceTarget::draw() :
virtual void draw(
CL_Surface_Generic *attributes,
CL_Surface_DrawParams1 *params1,
CL_GraphicContext *gc);
I choosed this one because it supports rotation & translation hotspot.
The main difficulty was to find the correct arguments from attributes
and params1 ! I found a bug in CL_SurfaceTarget : last_angle was'n saved
(so the old optimisation hack wasn't usefull :-P).
The main difficulty was to understand that params1.destX[0] can be the
bottom right corner ! So I use min/max functions to find the top left
and bottom right corner. With this I can correctly calculate destination
size and position.
The second difficulty was to extract one frame from a SDL_Surface. After
one half hour I understood that alpha was set to zero or something like
that (try without "SDL_SetAlpha (surface, 0, 255);" line in
surface_sdl.cpp ;-)).
I had a very mad performance problem : it was because "frame extractor"
was called on every draw(). It's now "cached" in CL_SurfaceSDL::extract
structure.
Other problem : a sprite contains many frames, but only CL_SpriteGeneric
contains correct informations (angle, scale, etc.). So I had to hack
CL_Surface code to syncronise the frame with the correct values :-/
// Stupid patch because of Sprite class
impl->angle=params2->rotate_angle;
impl->scale_x=params2->scale_x;
impl->scale_y=params2->scale_y;
// End of stupid patch
I think that another solution should be used here.
---
I don't think that it's really a great idea to have so much
CL_SurfaceTarget::draw() functions. It's really not clear ! I was very
difficult for me to find correct values because some are lost because
two draw() calls (DrawParams2 -> DrawParams1 : I lost angle and
scale_x/y arguments, which _should_ be in arguments, but they are not
always correct :-/).
---
The patch is relative from ClanLib version "CVS 2004-08-10".
I can understand that you really hate space instead <tab>, and that you
doesn't want to install SDL just to try my patch, but please read it ! I
need some comments !
Excume me for the space but I'm too tired to run some regexp after 2pm
:-P
---
I remove CL_SurfaceTarget::calc_hotspot from .h file and move it to .cpp
file. I think that g++ is intelligent enough to read my "inline"
keyword, no ? I also replace calc_hotspot_x/y #define by function.
---
resourcedata_sprite_description.cpp isn't perfect. I found a mistake :
when "size" attribute (<sprite><image><grid size="..." (...)/>), the
current code doesn't check if both parts are corrects. So, you can have
only a correct width :-( And width & height are not set to 1 by default
(which is said is the documentation) .... Ok, here you have another
patch. But I think that the code should contains other bugs.
Bye, Haypo
--- cl_old/Sources/Display/surface.cpp 2004-05-06 14:36:01.000000000 +0200
+++ cl_cvs/Sources/Display/surface.cpp 2004-09-23 02:08:40.000000000 +0200
@@ -212,6 +212,13 @@
CL_GraphicContext *gc)
{
if (gc == 0) gc = CL_Display::get_current_window()->get_gc();
+
+ // Stupid patch because of Sprite class
+ impl->angle=params2->rotate_angle;
+ impl->scale_x=params2->scale_x;
+ impl->scale_y=params2->scale_y;
+ // End of stupid patch
+
impl->target->draw(
impl,
params2,
--- cl_old/Sources/Display/sprite.cpp 2004-05-11 23:25:35.000000000 +0200
+++ cl_cvs/Sources/Display/sprite.cpp 2004-09-23 02:06:18.000000000 +0200
@@ -508,8 +508,10 @@
static CL_Surface_DrawParams2 params2;
params2.srcX = frame.position.left;
params2.srcY = frame.position.top;
+
params2.srcWidth = frame.position.get_width();
params2.srcHeight = frame.position.get_height();
+
params2.destX = x;
params2.destY = y;
params2.destZ = 0.0;
@@ -540,44 +542,7 @@
void CL_Sprite::draw(
const CL_Rect &dest,
CL_GraphicContext *gc)
-{
- if(impl->finished == false || impl->show_on_finish != show_blank)
- {
- CL_Sprite_Generic::SpriteFrame &frame = impl->frames[impl->current_frame];
-
- if (gc == 0) gc = CL_Display::get_current_window()->get_gc();
-
- static CL_Surface_DrawParams2 params2;
- params2.srcX = frame.position.left;
- params2.srcY = frame.position.top;
- params2.srcWidth = frame.position.get_width();
- params2.srcHeight = frame.position.get_height();
- params2.destX = dest.left;
- params2.destY = dest.top;
- params2.destZ = 0.0;
- params2.red = impl->red;
- params2.green = impl->green;
- params2.blue = impl->blue;
- params2.alpha = impl->alpha;
- params2.blend_src = impl->blend_src;
- params2.blend_dest = impl->blend_dest;
- params2.scale_x = dest.get_width()/float(frame.position.get_width());
- params2.scale_y = dest.get_height()/float(frame.position.get_height());
- params2.translate_origin = impl->translation_origin;
- params2.translate_x = impl->translation_hotspot.x + frame.offset.x;
- params2.translate_y = impl->translation_hotspot.y + frame.offset.y;
- params2.rotate_angle = impl->angle - impl->base_angle;
- params2.rotate_pitch = impl->angle_pitch;
- params2.rotate_yaw = impl->angle_yaw;
- params2.rotate_origin = impl->rotation_origin;
- params2.rotate_x = impl->rotation_hotspot.x + frame.offset.x;
- params2.rotate_y = impl->rotation_hotspot.y + frame.offset.y;
-
- frame.surface.draw(
- ¶ms2,
- gc);
- }
-}
+{ this->draw(dest.left, dest.top, gc); }
float CL_Sprite::update(float time_elapsed)
{
--- cl_old/Sources/Display/surface_target.cpp 2004-05-22 18:23:25.000000000 +0200
+++ cl_cvs/Sources/Display/surface_target.cpp 2004-09-23 00:55:36.000000000 +0200
@@ -23,6 +23,49 @@
#include "surface_target.h"
#include "API/Display/surface.h"
+#if defined(INLINE_CALC_ROTATE_XY)
+
+#define calc_rotate_x(px,py,rotation_hotspot_x,rotation_hotspot_y,rotate_x_x,rotate_y_x) \
+ (rotation_hotspot_x + (px-rotation_hotspot_x) * rotate_x_x + (py-rotation_hotspot_y) * rotate_y_x)
+
+#define calc_rotate_y(px,py,rotation_hotspot_x,rotation_hotspot_y,rotate_x_y,rotate_y_y) \
+ (rotation_hotspot_y + (px-rotation_hotspot_x) * rotate_x_y + (py-rotation_hotspot_y) * rotate_y_y)
+
+#else
+
+double calc_rotate_x(
+const double &px,
+const double &py,
+const double &rotation_hotspot_x,
+const double &rotation_hotspot_y,
+const double &rotate_x_x,
+const double &rotate_y_x)
+{
+ return
+ rotation_hotspot_x
+ +(px-rotation_hotspot_x) * rotate_x_x
+ + (py-rotation_hotspot_y) * rotate_y_x
+ ;
+}
+
+double calc_rotate_y(
+const double &px,
+const double &py,
+const double &rotation_hotspot_x,
+const double &rotation_hotspot_y,
+const double &rotate_x_y,
+const double &rotate_y_y)
+{
+ return
+ rotation_hotspot_y
+ +(px-rotation_hotspot_x) * rotate_x_y
+ +(py-rotation_hotspot_y) * rotate_y_y
+ ;
+}
+
+#endif
+
+
/////////////////////////////////////////////////////////////////////////////
// CL_Surface_Target construction:
@@ -110,6 +153,17 @@
{
static CL_Surface_DrawParams1 params1;
+ // Calculate final source rectangle points for render:
+
+ params1.srcX[0] = params2->srcX;
+ params1.srcY[0] = params2->srcY;
+ params1.srcX[1] = params2->srcX+params2->srcWidth;
+ params1.srcY[1] = params2->srcY;
+ params1.srcX[2] = params2->srcX+params2->srcWidth;
+ params1.srcY[2] = params2->srcY+params2->srcHeight;
+ params1.srcX[3] = params2->srcX;
+ params1.srcY[3] = params2->srcY+params2->srcHeight;
+
// Calculate unit vectors for rotated surface:
// (cached for speed reasons)
static double vect_rotate_x[2] = { 1.0, 0.0 };
@@ -118,6 +172,7 @@
if (last_angle != params2->rotate_angle)
{
+ last_angle = params2->rotate_angle;
if (params2->rotate_angle == 0.0)
{
vect_rotate_x[0] = 1.0;
@@ -151,22 +206,11 @@
double angle_rad = 3.1415926f*params2->rotate_angle/180;
vect_rotate_x[0] = cos(angle_rad);
vect_rotate_x[1] = sin(angle_rad);
- vect_rotate_y[0] = cos(3.1415926f/2+angle_rad);
- vect_rotate_y[1] = sin(3.1415926f/2+angle_rad);
+ vect_rotate_y[0] = -sin(angle_rad); // cos(x+pi/2)
+ vect_rotate_y[1] = cos(angle_rad); //sin(x+pi/2)
}
}
- // Calculate final source rectangle points for render:
-
- params1.srcX[0] = params2->srcX;
- params1.srcY[0] = params2->srcY;
- params1.srcX[1] = params2->srcX+params2->srcWidth;
- params1.srcY[1] = params2->srcY;
- params1.srcX[2] = params2->srcX+params2->srcWidth;
- params1.srcY[2] = params2->srcY+params2->srcHeight;
- params1.srcX[3] = params2->srcX;
- params1.srcY[3] = params2->srcY+params2->srcHeight;
-
// Calculate final destination rectangle points for surface rectangle:
if (params2->rotate_angle == 0.0)
@@ -186,7 +230,9 @@
params1.destX[0] = calc_rotate_x(t_params1->pixDestX, t_params1->pixDestY, t_params1->rotation_hotspot.x, t_params1->rotation_hotspot.y, vect_rotate_x[0], vect_rotate_y[0]);
params1.destY[0] = calc_rotate_y(t_params1->pixDestX, t_params1->pixDestY, t_params1->rotation_hotspot.x, t_params1->rotation_hotspot.y, vect_rotate_x[1], vect_rotate_y[1]);
params1.destX[1] = calc_rotate_x(t_params1->pixDestX+t_params1->destWidth, t_params1->pixDestY, t_params1->rotation_hotspot.x, t_params1->rotation_hotspot.y, vect_rotate_x[0], vect_rotate_y[0]);
+
params1.destY[1] = calc_rotate_y(t_params1->pixDestX+t_params1->destWidth, t_params1->pixDestY, t_params1->rotation_hotspot.x, t_params1->rotation_hotspot.y, vect_rotate_x[1], vect_rotate_y[1]);
+
params1.destX[2] = calc_rotate_x(t_params1->pixDestX+t_params1->destWidth, t_params1->pixDestY+t_params1->destHeight, t_params1->rotation_hotspot.x, t_params1->rotation_hotspot.y, vect_rotate_x[0], vect_rotate_y[0]);
params1.destY[2] = calc_rotate_y(t_params1->pixDestX+t_params1->destWidth, t_params1->pixDestY+t_params1->destHeight, t_params1->rotation_hotspot.x, t_params1->rotation_hotspot.y, vect_rotate_x[1], vect_rotate_y[1]);
params1.destX[3] = calc_rotate_x(t_params1->pixDestX, t_params1->pixDestY+t_params1->destHeight, t_params1->rotation_hotspot.x, t_params1->rotation_hotspot.y, vect_rotate_x[0], vect_rotate_y[0]);
@@ -251,5 +297,42 @@
if (ref_count == 0) delete this;
}
+CL_Pointf CL_Surface_Target::calc_hotspot
+(CL_Origin origin, float hotspot_x, float hotspot_y,
+ float size_width, float size_height)
+{
+ switch(origin)
+ {
+ case origin_top_left:
+ default:
+ return CL_Pointf(-hotspot_x, hotspot_y);
+ break;
+ case origin_top_center:
+ return CL_Pointf(size_width / 2 - hotspot_x, -hotspot_y);
+ break;
+ case origin_top_right:
+ return CL_Pointf(size_width - hotspot_x, -hotspot_y);
+ break;
+ case origin_center_left:
+ return CL_Pointf(-hotspot_x, size_height / 2 - hotspot_y);
+ break;
+ case origin_center:
+ return CL_Pointf(size_width / 2 - hotspot_x, size_height / 2 - hotspot_y);
+ break;
+ case origin_center_right:
+ return CL_Pointf(size_width - hotspot_x, size_height / 2 - hotspot_y);
+ break;
+ case origin_bottom_left:
+ return CL_Pointf(-hotspot_x, size_height - hotspot_y);
+ break;
+ case origin_bottom_center:
+ return CL_Pointf(size_width / 2 - hotspot_x, size_height - hotspot_y);
+ break;
+ case origin_bottom_right:
+ return CL_Pointf(size_width - hotspot_x, size_height - hotspot_y);
+ break;
+ }
+}
+
/////////////////////////////////////////////////////////////////////////////
// Implementation:
--- cl_old/Sources/Display/surface_target.h 2004-04-24 02:09:49.000000000 +0200
+++ cl_cvs/Sources/Display/surface_target.h 2004-09-22 21:26:21.000000000 +0200
@@ -98,77 +98,10 @@
void release_ref();
// inlined this function for performance reasons.
- CL_Pointf calc_hotspot(CL_Origin origin, float hotspot_x, float hotspot_y, float size_width, float size_height)
- {
- switch(origin)
- {
- case origin_top_left:
- default:
- return CL_Pointf(-hotspot_x, hotspot_y);
- break;
- case origin_top_center:
- return CL_Pointf(size_width / 2 - hotspot_x, -hotspot_y);
- break;
- case origin_top_right:
- return CL_Pointf(size_width - hotspot_x, -hotspot_y);
- break;
- case origin_center_left:
- return CL_Pointf(-hotspot_x, size_height / 2 - hotspot_y);
- break;
- case origin_center:
- return CL_Pointf(size_width / 2 - hotspot_x, size_height / 2 - hotspot_y);
- break;
- case origin_center_right:
- return CL_Pointf(size_width - hotspot_x, size_height / 2 - hotspot_y);
- break;
- case origin_bottom_left:
- return CL_Pointf(-hotspot_x, size_height - hotspot_y);
- break;
- case origin_bottom_center:
- return CL_Pointf(size_width / 2 - hotspot_x, size_height - hotspot_y);
- break;
- case origin_bottom_right:
- return CL_Pointf(size_width - hotspot_x, size_height - hotspot_y);
- break;
- }
- }
+ inline CL_Pointf CL_Surface_Target::calc_hotspot
+ (CL_Origin origin, float hotspot_x, float hotspot_y,
+ float size_width, float size_height);
- #define calc_rotate_x(px,py,rotation_hotspot_x,rotation_hotspot_y,rotate_x_x,rotate_y_x) \
- (rotation_hotspot_x + (px-rotation_hotspot_x) * rotate_x_x + (py-rotation_hotspot_y) * rotate_y_x)
-
- #define calc_rotate_y(px,py,rotation_hotspot_x,rotation_hotspot_y,rotate_x_y,rotate_y_y) \
- (rotation_hotspot_y + (px-rotation_hotspot_x) * rotate_x_y + (py-rotation_hotspot_y) * rotate_y_y)
-
-/*
-
- double calc_rotate_x(
- const double &px,
- const double &py,
- const double &rotation_hotspot_x,
- const double &rotation_hotspot_y,
- const double &rotate_x_x,
- const double &rotate_y_x)
- {
- return
- rotation_hotspot_x +
- (px-rotation_hotspot_x) * rotate_x_x +
- (py-rotation_hotspot_y) * rotate_y_x;
- }
-
- double calc_rotate_y(
- const double &px,
- const double &py,
- const double &rotation_hotspot_x,
- const double &rotation_hotspot_y,
- const double &rotate_x_y,
- const double &rotate_y_y)
- {
- return
- rotation_hotspot_y +
- (px-rotation_hotspot_x) * rotate_x_y +
- (py-rotation_hotspot_y) * rotate_y_y;
- }
-*/
//! Implementation:
private:
int ref_count;
--- cl_old/Sources/SDL/surface_sdl.cpp 2004-05-06 23:15:20.000000000 +0200
+++ cl_cvs/Sources/SDL/surface_sdl.cpp 2004-09-23 01:50:40.000000000 +0200
@@ -43,6 +43,8 @@
bool delete_provider,
int flag)
{
+ extract.surface = NULL;
+
// TODO: Use flag
surface = 0;
SDL_Surface *tmp = 0;
@@ -160,8 +162,8 @@
CL_Surface_SDL::~CL_Surface_SDL()
{
- if(surface != 0)
- SDL_FreeSurface(surface);
+ SDL_FreeSurface(extract.surface);
+ if(surface != 0) SDL_FreeSurface(surface);
}
/////////////////////////////////////////////////////////////////////////////
@@ -241,57 +243,95 @@
{
}
-void CL_Surface_SDL::draw(
- CL_Surface_Generic *attributes,
- CL_Surface_DrawParams1 *params1,
- CL_GraphicContext *gc)
+double min_double (double a,double b,double c, double d)
{
- // todo: move SDL code from other draws to this one.
+ double min=a;
+ if (b<min) min=b;
+ if (c<min) min=c;
+ if (d<min) min=d;
+ return min;
}
+double max_double (double a,double b,double c, double d)
+{
+ double max=a;
+ if (max<b) max=b;
+ if (max<c) max=c;
+ if (max<d) max=d;
+ return max;
+}
+
void CL_Surface_SDL::draw(
CL_Surface_Generic *attributes,
- CL_Surface_DrawParams2 *params2,
- CL_Surface_TargetDrawParams1 *t_params1,
- CL_GraphicContext *context)
+ CL_Surface_DrawParams1 *params1,
+ CL_GraphicContext *gc)
{
- SDL_Rect source = {params2->srcX, params2->srcY, params2->srcWidth, params2->srcHeight};
+ Sint16 min_src_x = params1->srcX[0];
+ Sint16 max_src_x = params1->srcX[1];
+ Sint16 src_width = max_src_x-min_src_x;
+
+ Sint16 min_src_y = params1->srcY[0];
+ Sint16 max_src_y = params1->srcY[2];
+ Sint16 src_height = max_src_y-min_src_y;
+
+ SDL_Rect source = {
+ min_src_x,
+ min_src_y,
+ src_width,
+ src_height};
+
+ // Extract the current frame of the whole texture
+ if ((extract.surface == NULL)
+ || (extract.rect.x != source.x)
+ || (extract.rect.y != source.y)
+ || (extract.rect.w != source.w)
+ || (extract.rect.h != source.h)) {
+ SDL_FreeSurface (extract.surface);
+ extract.rect = source;
+ SDL_Rect milieu = {0, 0, source.w, source.h};
+ extract.surface = SDL_CreateRGBSurface
+ (SDL_SWSURFACE,milieu.w,milieu.h,32,
+ surface->format->Rmask, surface->format->Gmask,
+ surface->format->Bmask, surface->format->Amask);
+ SDL_SetAlpha (surface, 0, 255);
+ SDL_BlitSurface (surface, &source, extract.surface, &milieu);
+ }
- SDL_Rect dst = {
- static_cast<Sint16>(t_params1->pixDestX + context->get_modelview().get_origin_x()),
- static_cast<Sint16>(t_params1->pixDestY + context->get_modelview().get_origin_y()),
- static_cast<Sint16>(t_params1->destWidth),
- static_cast<Sint16>(t_params1->destHeight)
- };
+ SDL_Surface *out = extract.surface;
+ bool free_out=false;
- if (t_params1->destWidth == params2->srcWidth && t_params1->destHeight == params2->srcHeight)
- {
- if(surface->format->BitsPerPixel > 8)
- {
- Uint8 a = (Uint8)(attributes->alpha * 255);
- SDL_SetAlpha(surface,SDL_RLEACCEL|SDL_SRCALPHA,a);
- }
- SDL_BlitSurface(surface,&source,SDL_GetVideoSurface(),&dst);
+ // Need rotation or scale ?
+ if ((attributes->angle != 0) || (attributes->scale_x != 1.0)) {
+ SDL_Surface *rotozoomed = rotozoomSurface
+ (extract.surface, -attributes->angle,attributes->scale_x, SMOOTHING_ON);
+ if(rotozoomed->format->BitsPerPixel > 8) {
+ Uint8 a = (Uint8)(attributes->alpha * 255);
+ SDL_SetAlpha(rotozoomed ,SDL_RLEACCEL|SDL_SRCALPHA,a);
+ }
+ free_out = true;
+ out = rotozoomed;
}
- else
- {
-#ifdef HAVE_LIBSDL_GFX
- SDL_Surface *zoom = zoomSurface (surface, t_params1->destWidth/params2->srcWidth, t_params1->destHeight/params2->srcHeight, SMOOTHING_ON);
- if(zoom->format->BitsPerPixel > 8)
- {
- Uint8 a = (Uint8)(attributes->alpha * 255);
- SDL_SetAlpha(zoom ,SDL_RLEACCEL|SDL_SRCALPHA,a);
- }
- SDL_BlitSurface(zoom,&source,SDL_GetVideoSurface(),&dst);
+ // Calculate destination rectangle
+ float min_dest_x = min_double(params1->destX[0],params1->destX[1],params1->destX[2],params1->destX[3]);
+ float max_dest_x = max_double(params1->destX[0],params1->destX[1],params1->destX[2],params1->destX[3]);
+ float dest_width = max_dest_x-min_dest_x;
+
+ float min_dest_y = min_double(params1->destY[0],params1->destY[1],params1->destY[2],params1->destY[3]);
+ float max_dest_y = max_double(params1->destY[0],params1->destY[1],params1->destY[2],params1->destY[3]);
+ float dest_height = max_dest_y-min_dest_y;
+ SDL_Rect dst = {
+ static_cast<Sint16>(min_dest_x+gc->get_modelview().get_origin_x()),
+ static_cast<Sint16>(min_dest_y+gc->get_modelview().get_origin_y()),
+ static_cast<Sint16>(dest_width),
+ static_cast<Sint16>(dest_height)};
+
+ // Blit the surface to screen
+ source.w = out->w;
+ source.h = out->h;
+ SDL_BlitSurface(out,NULL,SDL_GetVideoSurface(),&dst);
- SDL_FreeSurface(zoom);
-#else
- CL_Log::log("debug",
- "Error: clanSDL not compiled with SDL_gfx library, zooming not possible.\n"
- "Error: see: http://www.ferzkopp.net/~aschiffler/Software/SDL_gfx-2.0/\n");
-#endif
- }
+ if (free_out) SDL_FreeSurface(out);
}
/////////////////////////////////////////////////////////////////////////////
--- cl_old/Sources/SDL/surface_sdl.h 2004-04-24 02:09:49.000000000 +0200
+++ cl_cvs/Sources/SDL/surface_sdl.h 2004-09-23 01:50:30.000000000 +0200
@@ -69,18 +69,15 @@
CL_Surface_DrawParams1 *params1,
CL_GraphicContext *gc);
- //: Draw surface on screen.
- virtual void draw(
- CL_Surface_Generic *attributes,
- CL_Surface_DrawParams2 *params2,
- CL_Surface_TargetDrawParams1 *t_params1,
- CL_GraphicContext *context);
-
//! Implementation:
private:
CL_Sizef screen_size;
SDL_Surface *surface;
+ struct {
+ SDL_Surface *surface;
+ SDL_Rect rect;
+ } extract;
};
#endif
--- cl_old/Sources/Display/resourcedata_sprite_description.cpp 2004-05-11 23:21:33.000000000 +0200
+++ cl_cvs/Sources/Display/resourcedata_sprite_description.cpp 2004-09-23 01:23:54.000000000 +0200
@@ -119,12 +119,14 @@
int yspacing = 0;
std::vector<std::string> image_size = CL_String::tokenize(grid_element.get_attribute("size"), ",");
- int width = 0;
- if (image_size.size() > 0)
+ int width = 1;
+ int height = 1;
+ if (image_size.size() == 2) {
width = atoi(image_size[0].c_str());
- int height = 0;
- if (image_size.size() > 1)
height = atoi(image_size[1].c_str());
+ } else {
+ throw CL_Error("Resource '" + resource.get_name() + "' has incorrect array attribute, must be \"X,Y\"!");
+ }
if (grid_element.has_attribute("pos"))
{