summaryrefslogtreecommitdiff
path: root/src/libs/graphics/tfb_draw.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/graphics/tfb_draw.c')
-rw-r--r--src/libs/graphics/tfb_draw.c493
1 files changed, 493 insertions, 0 deletions
diff --git a/src/libs/graphics/tfb_draw.c b/src/libs/graphics/tfb_draw.c
new file mode 100644
index 0000000..1ac3c34
--- /dev/null
+++ b/src/libs/graphics/tfb_draw.c
@@ -0,0 +1,493 @@
+/*
+ * 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 "gfx_common.h"
+#include "tfb_draw.h"
+#include "drawcmd.h"
+#include "libs/log.h"
+#include "libs/memlib.h"
+
+
+static const HOT_SPOT NullHs = {0, 0};
+
+void
+TFB_DrawScreen_Line (int x1, int y1, int x2, int y2, Color color,
+ DrawMode mode, SCREEN dest)
+{
+ TFB_DrawCommand DC;
+
+ DC.Type = TFB_DRAWCOMMANDTYPE_LINE;
+ DC.data.line.x1 = x1;
+ DC.data.line.y1 = y1;
+ DC.data.line.x2 = x2;
+ DC.data.line.y2 = y2;
+ DC.data.line.color = color;
+ DC.data.line.drawMode = mode;
+ DC.data.line.destBuffer = dest;
+
+ TFB_EnqueueDrawCommand (&DC);
+}
+
+void
+TFB_DrawScreen_Rect (RECT *rect, Color color, DrawMode mode, SCREEN dest)
+{
+ RECT locRect;
+ TFB_DrawCommand DC;
+
+ if (!rect)
+ {
+ locRect.corner.x = locRect.corner.y = 0;
+ locRect.extent.width = ScreenWidth;
+ locRect.extent.height = ScreenHeight;
+ rect = &locRect;
+ }
+
+ DC.Type = TFB_DRAWCOMMANDTYPE_RECTANGLE;
+ DC.data.rect.rect = *rect;
+ DC.data.rect.color = color;
+ DC.data.rect.drawMode = mode;
+ DC.data.rect.destBuffer = dest;
+
+ TFB_EnqueueDrawCommand (&DC);
+}
+
+void
+TFB_DrawScreen_Image (TFB_Image *img, int x, int y, int scale,
+ int scaleMode, TFB_ColorMap *cmap, DrawMode mode, SCREEN dest)
+{
+ TFB_DrawCommand DC;
+
+ DC.Type = TFB_DRAWCOMMANDTYPE_IMAGE;
+ DC.data.image.image = img;
+ DC.data.image.colormap = cmap;
+ DC.data.image.x = x;
+ DC.data.image.y = y;
+ DC.data.image.scale = (scale == GSCALE_IDENTITY) ? 0 : scale;
+ DC.data.image.scaleMode = scaleMode;
+ DC.data.image.drawMode = mode;
+ DC.data.image.destBuffer = dest;
+
+ TFB_EnqueueDrawCommand (&DC);
+}
+
+void
+TFB_DrawScreen_FilledImage (TFB_Image *img, int x, int y, int scale,
+ int scaleMode, Color color, DrawMode mode, SCREEN dest)
+{
+ TFB_DrawCommand DC;
+
+ DC.Type = TFB_DRAWCOMMANDTYPE_FILLEDIMAGE;
+ DC.data.filledimage.image = img;
+ DC.data.filledimage.x = x;
+ DC.data.filledimage.y = y;
+ DC.data.filledimage.scale = (scale == GSCALE_IDENTITY) ? 0 : scale;
+ DC.data.filledimage.scaleMode = scaleMode;
+ DC.data.filledimage.color = color;
+ DC.data.filledimage.drawMode = mode;
+ DC.data.filledimage.destBuffer = dest;
+
+ TFB_EnqueueDrawCommand (&DC);
+}
+
+void
+TFB_DrawScreen_FontChar (TFB_Char *fontChar, TFB_Image *backing,
+ int x, int y, DrawMode mode, SCREEN dest)
+{
+ TFB_DrawCommand DC;
+
+ DC.Type = TFB_DRAWCOMMANDTYPE_FONTCHAR;
+ DC.data.fontchar.fontchar = fontChar;
+ DC.data.fontchar.backing = backing;
+ DC.data.fontchar.x = x;
+ DC.data.fontchar.y = y;
+ DC.data.fontchar.drawMode = mode;
+ DC.data.fontchar.destBuffer = dest;
+
+ TFB_EnqueueDrawCommand (&DC);
+}
+
+void
+TFB_DrawScreen_CopyToImage (TFB_Image *img, const RECT *r, SCREEN src)
+{
+ TFB_DrawCommand DC;
+
+ DC.Type = TFB_DRAWCOMMANDTYPE_COPYTOIMAGE;
+ DC.data.copytoimage.rect = *r;
+ DC.data.copytoimage.image = img;
+ DC.data.copytoimage.srcBuffer = src;
+
+ TFB_EnqueueDrawCommand (&DC);
+}
+
+void
+TFB_DrawScreen_Copy (const RECT *r, SCREEN src, SCREEN dest)
+{
+ RECT locRect;
+ TFB_DrawCommand DC;
+
+ if (!r)
+ {
+ locRect.corner.x = locRect.corner.y = 0;
+ locRect.extent.width = ScreenWidth;
+ locRect.extent.height = ScreenHeight;
+ r = &locRect;
+ }
+
+ DC.Type = TFB_DRAWCOMMANDTYPE_COPY;
+ DC.data.copy.rect = *r;
+ DC.data.copy.srcBuffer = src;
+ DC.data.copy.destBuffer = dest;
+
+ TFB_EnqueueDrawCommand (&DC);
+}
+
+void
+TFB_DrawScreen_SetMipmap (TFB_Image *img, TFB_Image *mmimg, int hotx, int hoty)
+{
+ TFB_DrawCommand DC;
+
+ DC.Type = TFB_DRAWCOMMANDTYPE_SETMIPMAP;
+ DC.data.setmipmap.image = img;
+ DC.data.setmipmap.mipmap = mmimg;
+ DC.data.setmipmap.hotx = hotx;
+ DC.data.setmipmap.hoty = hoty;
+
+ TFB_EnqueueDrawCommand (&DC);
+}
+
+void
+TFB_DrawScreen_DeleteImage (TFB_Image *img)
+{
+ if (img)
+ {
+ TFB_DrawCommand DC;
+
+ DC.Type = TFB_DRAWCOMMANDTYPE_DELETEIMAGE;
+ DC.data.deleteimage.image = img;
+
+ TFB_EnqueueDrawCommand (&DC);
+ }
+}
+
+void
+TFB_DrawScreen_DeleteData (void *data)
+ // data must be a result of HXalloc() call
+{
+ if (data)
+ {
+ TFB_DrawCommand DC;
+
+ DC.Type = TFB_DRAWCOMMANDTYPE_DELETEDATA;
+ DC.data.deletedata.data = data;
+
+ TFB_EnqueueDrawCommand (&DC);
+ }
+}
+
+void
+TFB_DrawScreen_WaitForSignal (void)
+{
+ TFB_DrawCommand DrawCommand;
+ Semaphore s;
+ s = GetMyThreadLocal ()->flushSem;
+ DrawCommand.Type = TFB_DRAWCOMMANDTYPE_SENDSIGNAL;
+ DrawCommand.data.sendsignal.sem = s;
+ Lock_DCQ (1);
+ TFB_BatchReset ();
+ TFB_EnqueueDrawCommand (&DrawCommand);
+ Unlock_DCQ();
+ SetSemaphore (s);
+}
+
+void
+TFB_DrawScreen_ReinitVideo (int driver, int flags, int width, int height)
+{
+ TFB_DrawCommand DrawCommand;
+ DrawCommand.Type = TFB_DRAWCOMMANDTYPE_REINITVIDEO;
+ DrawCommand.data.reinitvideo.driver = driver;
+ DrawCommand.data.reinitvideo.flags = flags;
+ DrawCommand.data.reinitvideo.width = width;
+ DrawCommand.data.reinitvideo.height = height;
+ TFB_EnqueueDrawCommand (&DrawCommand);
+}
+
+void
+TFB_DrawScreen_Callback (void (*callback) (void *arg), void *arg)
+{
+ TFB_DrawCommand DrawCommand;
+ DrawCommand.Type = TFB_DRAWCOMMANDTYPE_CALLBACK;
+ DrawCommand.data.callback.callback = callback;
+ DrawCommand.data.callback.arg = arg;
+ TFB_EnqueueDrawCommand(&DrawCommand);
+}
+
+void
+TFB_DrawImage_Line (int x1, int y1, int x2, int y2, Color color,
+ DrawMode mode, TFB_Image *target)
+{
+ LockMutex (target->mutex);
+ TFB_DrawCanvas_Line (x1, y1, x2, y2, color, mode, target->NormalImg);
+ target->dirty = TRUE;
+ UnlockMutex (target->mutex);
+}
+
+void
+TFB_DrawImage_Rect (RECT *rect, Color color, DrawMode mode, TFB_Image *target)
+{
+ LockMutex (target->mutex);
+ TFB_DrawCanvas_Rect (rect, color, mode, target->NormalImg);
+ target->dirty = TRUE;
+ UnlockMutex (target->mutex);
+}
+
+void
+TFB_DrawImage_Image (TFB_Image *img, int x, int y, int scale,
+ int scaleMode, TFB_ColorMap *cmap, DrawMode mode, TFB_Image *target)
+{
+ LockMutex (target->mutex);
+ TFB_DrawCanvas_Image (img, x, y, scale, scaleMode, cmap,
+ mode, target->NormalImg);
+ target->dirty = TRUE;
+ UnlockMutex (target->mutex);
+}
+
+void
+TFB_DrawImage_FilledImage (TFB_Image *img, int x, int y, int scale,
+ int scaleMode, Color color, DrawMode mode, TFB_Image *target)
+{
+ LockMutex (target->mutex);
+ TFB_DrawCanvas_FilledImage (img, x, y, scale, scaleMode, color,
+ mode, target->NormalImg);
+ target->dirty = TRUE;
+ UnlockMutex (target->mutex);
+}
+
+void
+TFB_DrawImage_FontChar (TFB_Char *fontChar, TFB_Image *backing,
+ int x, int y, DrawMode mode, TFB_Image *target)
+{
+ LockMutex (target->mutex);
+ TFB_DrawCanvas_FontChar (fontChar, backing, x, y, mode, target->NormalImg);
+ target->dirty = TRUE;
+ UnlockMutex (target->mutex);
+}
+
+
+TFB_Image *
+TFB_DrawImage_New (TFB_Canvas canvas)
+{
+ TFB_Image *img = HMalloc (sizeof (TFB_Image));
+ img->mutex = CreateMutex ("image lock", SYNC_CLASS_VIDEO);
+ img->ScaledImg = NULL;
+ img->MipmapImg = NULL;
+ img->FilledImg = NULL;
+ img->colormap_index = -1;
+ img->colormap_version = 0;
+ img->NormalHs = NullHs;
+ img->MipmapHs = NullHs;
+ img->last_scale_hs = NullHs;
+ img->last_scale_type = -1;
+ img->last_scale = 0;
+ img->dirty = FALSE;
+ TFB_DrawCanvas_GetExtent (canvas, &img->extent);
+
+ if (TFB_DrawCanvas_IsPaletted (canvas))
+ {
+ img->NormalImg = canvas;
+ }
+ else
+ {
+ img->NormalImg = TFB_DrawCanvas_ToScreenFormat (canvas);
+ }
+
+ return img;
+}
+
+TFB_Image*
+TFB_DrawImage_CreateForScreen (int w, int h, BOOLEAN withalpha)
+{
+ TFB_Image* img = HMalloc (sizeof (TFB_Image));
+ img->mutex = CreateMutex ("image lock", SYNC_CLASS_VIDEO);
+ img->ScaledImg = NULL;
+ img->MipmapImg = NULL;
+ img->FilledImg = NULL;
+ img->colormap_index = -1;
+ img->colormap_version = 0;
+ img->NormalHs = NullHs;
+ img->MipmapHs = NullHs;
+ img->last_scale_hs = NullHs;
+ img->last_scale_type = -1;
+ img->last_scale = 0;
+ img->extent.width = w;
+ img->extent.height = h;
+
+ img->NormalImg = TFB_DrawCanvas_New_ForScreen (w, h, withalpha);
+
+ return img;
+}
+
+TFB_Image *
+TFB_DrawImage_New_Rotated (TFB_Image *img, int angle)
+{
+ TFB_Canvas dst;
+ EXTENT size;
+ TFB_Image* newimg;
+
+ /* sanity check */
+ if (!img->NormalImg)
+ {
+ log_add (log_Warning, "TFB_DrawImage_New_Rotated: "
+ "source canvas is NULL! Failing.");
+ return NULL;
+ }
+
+ TFB_DrawCanvas_GetRotatedExtent (img->NormalImg, angle, &size);
+ dst = TFB_DrawCanvas_New_RotationTarget (img->NormalImg, angle);
+ if (!dst)
+ {
+ log_add (log_Warning, "TFB_DrawImage_New_Rotated: "
+ "rotation target canvas not created! Failing.");
+ return NULL;
+ }
+ TFB_DrawCanvas_Rotate (img->NormalImg, dst, angle, size);
+
+ newimg = TFB_DrawImage_New (dst);
+ return newimg;
+}
+
+void
+TFB_DrawImage_SetMipmap (TFB_Image *img, TFB_Image *mmimg, int hotx, int hoty)
+{
+ bool imgpal;
+ bool mmpal;
+
+ if (!img || !mmimg)
+ return;
+
+ LockMutex (img->mutex);
+ LockMutex (mmimg->mutex);
+
+ // Either both images must be using the same colormap, or mipmap image
+ // must not be paletted. This restriction is due to the current
+ // implementation of fill-stamp, which replaces the palette with
+ // fill color.
+ imgpal = TFB_DrawCanvas_IsPaletted (img->NormalImg);
+ mmpal = TFB_DrawCanvas_IsPaletted (mmimg->NormalImg);
+ if (!mmpal || (mmpal && imgpal &&
+ img->colormap_index == mmimg->colormap_index))
+ {
+ img->MipmapImg = mmimg->NormalImg;
+ img->MipmapHs.x = hotx;
+ img->MipmapHs.y = hoty;
+ }
+ else
+ {
+ img->MipmapImg = NULL;
+ }
+
+ UnlockMutex (mmimg->mutex);
+ UnlockMutex (img->mutex);
+}
+
+void
+TFB_DrawImage_Delete (TFB_Image *image)
+{
+ if (image == 0)
+ {
+ log_add (log_Warning, "INTERNAL ERROR: Tried to delete a null image!");
+ /* Should we die here? */
+ return;
+ }
+ LockMutex (image->mutex);
+
+ TFB_DrawCanvas_Delete (image->NormalImg);
+
+ if (image->ScaledImg)
+ {
+ TFB_DrawCanvas_Delete (image->ScaledImg);
+ image->ScaledImg = 0;
+ }
+
+ if (image->FilledImg)
+ {
+ TFB_DrawCanvas_Delete (image->FilledImg);
+ image->FilledImg = 0;
+ }
+
+ UnlockMutex (image->mutex);
+ DestroyMutex (image->mutex);
+
+ HFree (image);
+}
+
+void
+TFB_DrawImage_FixScaling (TFB_Image *image, int target, int type)
+{
+ if (image->dirty || !image->ScaledImg ||
+ target != image->last_scale ||
+ type != image->last_scale_type)
+ {
+ image->dirty = FALSE;
+ image->ScaledImg = TFB_DrawCanvas_New_ScaleTarget (image->NormalImg,
+ image->ScaledImg, type, image->last_scale_type);
+
+ if (type == TFB_SCALE_NEAREST)
+ TFB_DrawCanvas_Rescale_Nearest (image->NormalImg,
+ image->ScaledImg, target, &image->NormalHs,
+ &image->extent, &image->last_scale_hs);
+ else if (type == TFB_SCALE_BILINEAR)
+ TFB_DrawCanvas_Rescale_Bilinear (image->NormalImg,
+ image->ScaledImg, target, &image->NormalHs,
+ &image->extent, &image->last_scale_hs);
+ else
+ TFB_DrawCanvas_Rescale_Trilinear (image->NormalImg,
+ image->MipmapImg, image->ScaledImg, target,
+ &image->NormalHs, &image->MipmapHs,
+ &image->extent, &image->last_scale_hs);
+
+ image->last_scale_type = type;
+ image->last_scale = target;
+ }
+}
+
+BOOLEAN
+TFB_DrawImage_Intersect (TFB_Image *img1, POINT img1org,
+ TFB_Image *img2, POINT img2org, const RECT *interRect)
+{
+ BOOLEAN ret;
+
+ LockMutex (img1->mutex);
+ LockMutex (img2->mutex);
+ ret = TFB_DrawCanvas_Intersect (img1->NormalImg, img1org,
+ img2->NormalImg, img2org, interRect);
+ UnlockMutex (img2->mutex);
+ UnlockMutex (img1->mutex);
+
+ return ret;
+}
+
+void
+TFB_DrawImage_CopyRect (TFB_Image *source, const RECT *srcRect,
+ TFB_Image *target, POINT dstPt)
+{
+ LockMutex (source->mutex);
+ LockMutex (target->mutex);
+ TFB_DrawCanvas_CopyRect (source->NormalImg, srcRect,
+ target->NormalImg, dstPt);
+ target->dirty = TRUE;
+ UnlockMutex (target->mutex);
+ UnlockMutex (source->mutex);
+}