From 7f6002caba3f0a6749820c2772161caf55b8d267 Mon Sep 17 00:00:00 2001 From: neonloop Date: Fri, 7 May 2021 20:00:12 +0000 Subject: Initial commit (uqm-0.8.0) --- src/libs/graphics/tfb_draw.c | 493 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 493 insertions(+) create mode 100644 src/libs/graphics/tfb_draw.c (limited to 'src/libs/graphics/tfb_draw.c') 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); +} -- cgit v1.2.3