summaryrefslogtreecommitdiff
path: root/src/libs/graphics/drawable.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/graphics/drawable.c')
-rw-r--r--src/libs/graphics/drawable.c501
1 files changed, 501 insertions, 0 deletions
diff --git a/src/libs/graphics/drawable.c b/src/libs/graphics/drawable.c
new file mode 100644
index 0000000..9766bc7
--- /dev/null
+++ b/src/libs/graphics/drawable.c
@@ -0,0 +1,501 @@
+//Copyright Paul Reiche, Fred Ford. 1992-2002
+
+/*
+ * 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 distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * 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 "libs/gfxlib.h"
+#include "libs/graphics/context.h"
+#include "libs/graphics/drawable.h"
+#include "libs/graphics/tfb_draw.h"
+#include "libs/memlib.h"
+#include "tfb_draw.h"
+#include <math.h>
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif
+
+FRAME _CurFramePtr;
+
+FRAME
+SetContextFGFrame (FRAME Frame)
+{
+ FRAME LastFrame;
+
+ if (Frame != (LastFrame = (FRAME)_CurFramePtr))
+ {
+ if (LastFrame)
+ DeactivateDrawable ();
+
+ _CurFramePtr = Frame;
+ if (_CurFramePtr)
+ ActivateDrawable ();
+
+ if (ContextActive ())
+ {
+ SwitchContextFGFrame (Frame);
+ }
+ }
+
+ return (LastFrame);
+}
+
+FRAME
+GetContextFGFrame (void)
+{
+ return _CurFramePtr;
+}
+
+static DRAWABLE
+request_drawable (COUNT NumFrames, DRAWABLE_TYPE DrawableType,
+ CREATE_FLAGS flags, SIZE width, SIZE height)
+{
+ DRAWABLE Drawable;
+ COUNT i;
+
+ Drawable = AllocDrawable (NumFrames);
+ if (!Drawable)
+ return NULL;
+
+ Drawable->Flags = flags;
+ Drawable->MaxIndex = NumFrames - 1;
+
+ for (i = 0; i < NumFrames; ++i)
+ {
+ FRAME FramePtr = &Drawable->Frame[i];
+
+ if (DrawableType == RAM_DRAWABLE && width > 0 && height > 0)
+ {
+ FramePtr->image = TFB_DrawImage_New (TFB_DrawCanvas_New_TrueColor (
+ width, height, (flags & WANT_ALPHA) ? TRUE : FALSE));
+ }
+
+ FramePtr->Type = DrawableType;
+ FramePtr->Index = i;
+ SetFrameBounds (FramePtr, width, height);
+ }
+
+ return Drawable;
+}
+
+DRAWABLE
+CreateDisplay (CREATE_FLAGS CreateFlags, SIZE *pwidth, SIZE *pheight)
+{
+ DRAWABLE Drawable;
+
+ // TODO: ScreenWidth and ScreenHeight should be passed in
+ // instead of returned.
+ Drawable = request_drawable (1, SCREEN_DRAWABLE,
+ (CreateFlags & (WANT_PIXMAP | WANT_MASK)),
+ ScreenWidth, ScreenHeight);
+ if (Drawable)
+ {
+ FRAME F;
+
+ F = CaptureDrawable (Drawable);
+ if (F == 0)
+ DestroyDrawable (Drawable);
+ else
+ {
+ *pwidth = GetFrameWidth (F);
+ *pheight = GetFrameHeight (F);
+
+ ReleaseDrawable (F);
+ return (Drawable);
+ }
+ }
+
+ *pwidth = *pheight = 0;
+ return (0);
+}
+
+DRAWABLE
+AllocDrawable (COUNT n)
+{
+ DRAWABLE Drawable;
+ Drawable = (DRAWABLE) HCalloc(sizeof (DRAWABLE_DESC));
+ if (Drawable)
+ {
+ int i;
+ Drawable->Frame = (FRAME)HMalloc (sizeof (FRAME_DESC) * n);
+ if (Drawable->Frame == NULL)
+ {
+ HFree (Drawable);
+ return NULL;
+ }
+
+ /* Zero out the newly allocated frames, since HMalloc doesn't have
+ * MEM_ZEROINIT. */
+ for (i = 0; i < n; i++) {
+ FRAME F;
+ F = &Drawable->Frame[i];
+ F->parent = Drawable;
+ F->Type = 0;
+ F->Index = 0;
+ F->image = 0;
+ F->Bounds.width = 0;
+ F->Bounds.height = 0;
+ F->HotSpot.x = 0;
+ F->HotSpot.y = 0;
+ }
+ }
+ return Drawable;
+}
+
+DRAWABLE
+CreateDrawable (CREATE_FLAGS CreateFlags, SIZE width, SIZE height, COUNT
+ num_frames)
+{
+ DRAWABLE Drawable;
+
+ Drawable = request_drawable (num_frames, RAM_DRAWABLE,
+ (CreateFlags & (WANT_MASK | WANT_PIXMAP
+ | WANT_ALPHA | MAPPED_TO_DISPLAY)),
+ width, height);
+ if (Drawable)
+ {
+ FRAME F;
+
+ F = CaptureDrawable (Drawable);
+ if (F)
+ {
+ ReleaseDrawable (F);
+
+ return (Drawable);
+ }
+ }
+
+ return (0);
+}
+
+BOOLEAN
+DestroyDrawable (DRAWABLE Drawable)
+{
+ if (_CurFramePtr && (Drawable == _CurFramePtr->parent))
+ SetContextFGFrame ((FRAME)NULL);
+
+ if (Drawable)
+ {
+ FreeDrawable (Drawable);
+
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+BOOLEAN
+GetFrameRect (FRAME FramePtr, RECT *pRect)
+{
+ if (FramePtr)
+ {
+ pRect->corner.x = -FramePtr->HotSpot.x;
+ pRect->corner.y = -FramePtr->HotSpot.y;
+ pRect->extent = GetFrameBounds (FramePtr);
+
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+HOT_SPOT
+SetFrameHot (FRAME FramePtr, HOT_SPOT HotSpot)
+{
+ if (FramePtr)
+ {
+ HOT_SPOT OldHot;
+
+ OldHot = FramePtr->HotSpot;
+ FramePtr->HotSpot = HotSpot;
+
+ return (OldHot);
+ }
+
+ return (MAKE_HOT_SPOT (0, 0));
+}
+
+HOT_SPOT
+GetFrameHot (FRAME FramePtr)
+{
+ if (FramePtr)
+ {
+ return FramePtr->HotSpot;
+ }
+
+ return (MAKE_HOT_SPOT (0, 0));
+}
+
+DRAWABLE
+RotateFrame (FRAME Frame, int angle_deg)
+{
+ DRAWABLE Drawable;
+ FRAME RotFramePtr;
+ double dx, dy;
+ double d;
+ double angle = angle_deg * M_PI / 180;
+
+ if (!Frame)
+ return NULL;
+
+ assert (Frame->Type != SCREEN_DRAWABLE);
+
+ Drawable = request_drawable (1, RAM_DRAWABLE, WANT_PIXMAP, 0, 0);
+ if (!Drawable)
+ return 0;
+ RotFramePtr = CaptureDrawable (Drawable);
+ if (!RotFramePtr)
+ {
+ FreeDrawable (Drawable);
+ return 0;
+ }
+
+ RotFramePtr->image = TFB_DrawImage_New_Rotated (
+ Frame->image, angle_deg);
+ SetFrameBounds (RotFramePtr, RotFramePtr->image->extent.width,
+ RotFramePtr->image->extent.height);
+
+ /* now we need to rotate the hot-spot, eww */
+ dx = Frame->HotSpot.x - (GetFrameWidth (Frame) / 2);
+ dy = Frame->HotSpot.y - (GetFrameHeight (Frame) / 2);
+ d = sqrt ((double)dx*dx + (double)dy*dy);
+ if ((int)d != 0)
+ {
+ double organg = atan2 (-dy, dx);
+ dx = cos (organg + angle) * d;
+ dy = -sin (organg + angle) * d;
+ }
+ RotFramePtr->HotSpot.x = (GetFrameWidth (RotFramePtr) / 2) + (int)dx;
+ RotFramePtr->HotSpot.y = (GetFrameHeight (RotFramePtr) / 2) + (int)dy;
+
+ ReleaseDrawable (RotFramePtr);
+
+ return Drawable;
+}
+
+// color.a is ignored
+void
+SetFrameTransparentColor (FRAME frame, Color color)
+{
+ TFB_Image *img;
+
+ if (!frame)
+ return;
+
+ assert (frame->Type != SCREEN_DRAWABLE);
+
+ img = frame->image;
+ LockMutex (img->mutex);
+
+ // TODO: This should defer to TFB_DrawImage instead
+ TFB_DrawCanvas_SetTransparentColor (img->NormalImg, color, FALSE);
+
+ UnlockMutex (img->mutex);
+}
+
+Color
+GetFramePixel (FRAME frame, POINT pixelPt)
+{
+ TFB_Image *img;
+ Color ret;
+
+ if (!frame)
+ return BUILD_COLOR_RGBA (0, 0, 0, 0);
+
+ assert (frame->Type != SCREEN_DRAWABLE);
+
+ img = frame->image;
+ LockMutex (img->mutex);
+
+ // TODO: This should defer to TFB_DrawImage instead
+ ret = TFB_DrawCanvas_GetPixel (img->NormalImg, pixelPt.x, pixelPt.y);
+
+ UnlockMutex (img->mutex);
+
+ return ret;
+}
+
+static FRAME
+makeMatchingFrame (FRAME frame, int width, int height)
+{
+ DRAWABLE drawable;
+ FRAME newFrame;
+ CREATE_FLAGS flags;
+
+ flags = GetFrameParentDrawable (frame)->Flags;
+ drawable = CreateDrawable (flags, width, height, 1);
+ if (!drawable)
+ return NULL;
+ newFrame = CaptureDrawable (drawable);
+ if (!newFrame)
+ {
+ FreeDrawable (drawable);
+ return NULL;
+ }
+
+ return newFrame;
+}
+
+// Creates an new DRAWABLE containing a copy of specified FRAME's rect
+// Source FRAME must not be a SCREEN_DRAWABLE
+DRAWABLE
+CopyFrameRect (FRAME frame, const RECT *area)
+{
+ FRAME newFrame;
+ POINT nullPt = MAKE_POINT (0, 0);
+
+ if (!frame)
+ return NULL;
+
+ assert (frame->Type != SCREEN_DRAWABLE);
+
+ newFrame = makeMatchingFrame (frame, area->extent.width,
+ area->extent.height);
+ if (!newFrame)
+ return NULL;
+
+ TFB_DrawImage_CopyRect (frame->image, area, newFrame->image, nullPt);
+
+ return ReleaseDrawable (newFrame);
+}
+
+// Creates an new DRAWABLE mostly identical to specified FRAME
+// Source FRAME must not be a SCREEN_DRAWABLE
+DRAWABLE
+CloneFrame (FRAME frame)
+{
+ FRAME newFrame;
+ RECT r;
+
+ if (!frame)
+ return NULL;
+
+ assert (frame->Type != SCREEN_DRAWABLE);
+
+ GetFrameRect (frame, &r);
+ r.corner.x = 0;
+ r.corner.y = 0;
+
+ newFrame = CaptureDrawable (CopyFrameRect (frame, &r));
+ if (!newFrame)
+ return NULL;
+
+ // copy the hot-spot
+ newFrame->HotSpot = frame->HotSpot;
+
+ return ReleaseDrawable (newFrame);
+}
+
+// Creates a new DRAWABLE of specified size and scales the passed
+// frame onto it. The aspect ratio is not preserved.
+DRAWABLE
+RescaleFrame (FRAME frame, int width, int height)
+{
+ FRAME newFrame;
+ TFB_Image *img;
+ TFB_Canvas src, dst;
+
+ if (!frame)
+ return NULL;
+
+ assert (frame->Type != SCREEN_DRAWABLE);
+
+ newFrame = makeMatchingFrame (frame, width, height);
+ if (!newFrame)
+ return NULL;
+
+ // scale the hot-spot
+ newFrame->HotSpot.x = frame->HotSpot.x * width / frame->Bounds.width;
+ newFrame->HotSpot.y = frame->HotSpot.y * height / frame->Bounds.height;
+
+ img = frame->image;
+ LockMutex (img->mutex);
+ // NOTE: We do not lock the target image because nothing has a
+ // reference to it yet!
+ src = img->NormalImg;
+ dst = newFrame->image->NormalImg;
+ TFB_DrawCanvas_Rescale_Nearest (src, dst, -1, NULL, NULL, NULL);
+
+ UnlockMutex (img->mutex);
+
+ return ReleaseDrawable (newFrame);
+}
+
+BOOLEAN
+ReadFramePixelColors (FRAME frame, Color *pixels, int width, int height)
+{
+ TFB_Image *img;
+
+ if (!frame)
+ return FALSE;
+
+ assert (frame->Type != SCREEN_DRAWABLE);
+
+ // TODO: Do we need to lock the img->mutex here?
+ img = frame->image;
+ return TFB_DrawCanvas_GetPixelColors (img->NormalImg, pixels,
+ width, height);
+}
+
+// Warning: this functions bypasses DCQ, which is why it is not a DrawXXX
+BOOLEAN
+WriteFramePixelColors (FRAME frame, const Color *pixels, int width, int height)
+{
+ TFB_Image *img;
+
+ if (!frame)
+ return FALSE;
+
+ assert (frame->Type != SCREEN_DRAWABLE);
+
+ // TODO: Do we need to lock the img->mutex here?
+ img = frame->image;
+ return TFB_DrawCanvas_SetPixelColors (img->NormalImg, pixels,
+ width, height);
+}
+
+BOOLEAN
+ReadFramePixelIndexes (FRAME frame, BYTE *pixels, int width, int height)
+{
+ TFB_Image *img;
+
+ if (!frame)
+ return FALSE;
+
+ assert (frame->Type != SCREEN_DRAWABLE);
+
+ // TODO: Do we need to lock the img->mutex here?
+ img = frame->image;
+ return TFB_DrawCanvas_GetPixelIndexes (img->NormalImg, pixels,
+ width, height);
+}
+
+// Warning: this functions bypasses DCQ, which is why it is not a DrawXXX
+BOOLEAN
+WriteFramePixelIndexes (FRAME frame, const BYTE *pixels, int width, int height)
+{
+ TFB_Image *img;
+
+ if (!frame)
+ return FALSE;
+
+ assert (frame->Type != SCREEN_DRAWABLE);
+
+ // TODO: Do we need to lock the img->mutex here?
+ img = frame->image;
+ return TFB_DrawCanvas_SetPixelIndexes (img->NormalImg, pixels,
+ width, height);
+}