protected void OnGridMotionSubOverlaysSelectionChanged(object sender, EventArgs e)
        {
            SubOverlay selectedItem = gridMotionSubOverlays.SelectedItem;

            avMotionSubOverlayAnimation.DataSource =
                (selectedItem != null) ? selectedItem.Animation : null;
        }
Exemple #2
0
        private void gridMotionSubOverlays_SelectionChanged(object sender, EventArgs e)
        {
            SubOverlay selectedItem = gridMotionSubOverlays.SelectedItem;

            if (selectedItem != null)
            {
                avMotionSubOverlayAnimation.DataSource = selectedItem.Animation;
            }
        }
        protected void Calculate(
            ObjectBase Data,
            BgfBitmap MainFrame,
            bool UseViewerFrame   = true,
            bool ApplyYOffset     = true,
            byte RootHotspotIndex = 0,
            Real Quality          = DEFAULTQUALITY,
            bool ScalePow2        = false,
            uint Width            = 0,
            uint Height           = 0,
            bool CenterVertical   = false,
            bool CenterHorizontal = false,
            bool IsCustomShrink   = false,
            Real CustomShrink     = 1.0f)
        {
            BgfBitmap        mainFrame    = MainFrame;
            BgfFile          mainResource = Data.Resource;
            byte             mainColor    = Data.ColorTranslation;
            BgfBitmap        subOvFrame;
            BgfBitmapHotspot subOvHotspot;
            SubOverlay       subOvParent;
            BgfBitmap        subOvParentFrame;
            BgfBitmapHotspot subOvParentHotspot;
            bool             rootSpotFound = false;

            // use custom compose root (suboverlay=mainoverlay)
            // if it's not found, fallback to full compose
            if (RootHotspotIndex > 0)
            {
                SubOverlay subOv = Data.GetSubOverlayByHotspot(RootHotspotIndex);

                if (subOv != null)
                {
                    rootSpotFound = true;

                    if (UseViewerFrame)
                    {
                        mainFrame = subOv.ViewerFrame;
                    }
                    else
                    {
                        mainFrame = subOv.FrontFrame;
                    }

                    mainResource = subOv.Resource;
                    mainColor    = subOv.ColorTranslation;
                }
            }

            if (mainFrame != null && mainResource != null)
            {
                Bgf       = mainFrame;
                BgfColor  = mainColor;
                size.X    = (Real)mainFrame.Width / (Real)mainResource.ShrinkFactor;
                size.Y    = (Real)mainFrame.Height / (Real)mainResource.ShrinkFactor;
                origin.X  = (Real)mainFrame.XOffset / (Real)mainResource.ShrinkFactor;
                origin.Y  = (Real)mainFrame.YOffset / (Real)mainResource.ShrinkFactor;
                MaxShrink = mainResource.ShrinkFactor;

                // used to calculate the boundingbox
                V2 min = new V2(Origin.X, Origin.Y);
                V2 max = new V2(Size.X, Size.Y);
                if (ApplyYOffset)
                {
                    if (origin.X > 0.0f)
                    {
                        max.X += origin.X;
                    }
                    if (origin.Y > 0.0f)
                    {
                        max.Y += origin.Y;
                    }
                }
                else
                {
                    max += origin;
                }

                Real x, y;

                // walk suboverlay structure
                foreach (SubOverlay subOv in Data.CurrentSubOverlays)
                {
                    if (UseViewerFrame)
                    {
                        subOvFrame   = subOv.ViewerFrame;
                        subOvHotspot = subOv.ViewerHotspot;
                        subOvParent  = subOv.ViewerParent;
                    }
                    else
                    {
                        subOvFrame   = subOv.FrontFrame;
                        subOvHotspot = subOv.FrontHotspot;
                        subOvParent  = subOv.FrontParent;
                    }

                    bool isSubRoot = (subOvParent != null && subOvParent.HotSpot == RootHotspotIndex);

                    if (subOv.Resource != null &&
                        subOvFrame != null &&
                        subOvHotspot != null &&
                        (RootHotspotIndex <= 0 || !rootSpotFound || isSubRoot))
                    {
                        SubOverlay.RenderInfo subOvInfo = new SubOverlay.RenderInfo();

                        // save subov & bitmap
                        subOvInfo.SubOverlay = subOv;
                        subOvInfo.Bgf        = subOvFrame;

                        // calculate the size of this suboverlay
                        subOvInfo.Size.X = (Real)subOvFrame.Width / (Real)subOv.Resource.ShrinkFactor;
                        subOvInfo.Size.Y = (Real)subOvFrame.Height / (Real)subOv.Resource.ShrinkFactor;

                        // update maxshrink if greater
                        if (subOv.Resource.ShrinkFactor > MaxShrink)
                        {
                            MaxShrink = subOv.Resource.ShrinkFactor;
                        }

                        // CASE 1: SubOverlay on mainoverlay
                        if (subOvParent == null || isSubRoot)
                        {
                            // calculate the origin of this suboverlay on the mainoverlay
                            subOvInfo.Origin.X = mainFrame.XOffset
                                                 + ((Real)subOvHotspot.X)
                                                 + ((Real)subOvFrame.XOffset);

                            subOvInfo.Origin.Y = mainFrame.YOffset
                                                 + ((Real)subOvHotspot.Y)
                                                 + ((Real)subOvFrame.YOffset);

                            subOvInfo.Origin.X /= mainResource.ShrinkFactor;
                            subOvInfo.Origin.Y /= mainResource.ShrinkFactor;

                            // determine type of hotspot
                            if (subOvHotspot.Index < 0)
                            {
                                subOvInfo.HotspotType = HotSpotType.HOTSPOT_UNDER;
                            }
                            else
                            {
                                subOvInfo.HotspotType = HotSpotType.HOTSPOT_OVER;
                            }
                        }

                        // CASE 2: SubOverlay on SubOverlay on MainOverlay
                        else
                        {
                            if (UseViewerFrame)
                            {
                                subOvParentFrame   = subOvParent.ViewerFrame;
                                subOvParentHotspot = subOvParent.ViewerHotspot;
                            }
                            else
                            {
                                subOvParentFrame   = subOvParent.FrontFrame;
                                subOvParentHotspot = subOvParent.FrontHotspot;
                            }

                            if (subOvParentHotspot != null &&
                                subOvParentFrame != null &&
                                subOvParent.Resource != null)
                            {
                                // calculate the origin of this suboverlay on the suboverlay on the mainoverlay
                                subOvInfo.Origin.X =
                                    (mainFrame.XOffset +
                                     (Real)subOvParentHotspot.X +
                                     (Real)subOvParentFrame.XOffset) / (Real)mainResource.ShrinkFactor;

                                subOvInfo.Origin.X +=
                                    ((Real)subOvHotspot.X +
                                     (Real)subOvFrame.XOffset) / (Real)subOvParent.Resource.ShrinkFactor;

                                subOvInfo.Origin.Y =
                                    (mainFrame.YOffset +
                                     (Real)subOvParentHotspot.Y +
                                     (Real)subOvParentFrame.YOffset) / (Real)mainResource.ShrinkFactor;

                                subOvInfo.Origin.Y +=
                                    ((Real)subOvHotspot.Y +
                                     (Real)subOvFrame.YOffset) / (Real)subOvParent.Resource.ShrinkFactor;

                                // determine type of nested hotspot
                                if (subOvParentHotspot.Index > 0 && subOvHotspot.Index > 0)
                                {
                                    subOvInfo.HotspotType = HotSpotType.HOTSPOT_OVEROVER;
                                }

                                else if (subOvParentHotspot.Index > 0 && subOvHotspot.Index < 0)
                                {
                                    subOvInfo.HotspotType = HotSpotType.HOTSPOT_OVERUNDER;
                                }

                                else if (subOvParentHotspot.Index < 0 && subOvHotspot.Index > 0)
                                {
                                    subOvInfo.HotspotType = HotSpotType.HOTSPOT_UNDEROVER;
                                }

                                else if (subOvParentHotspot.Index < 0 && subOvHotspot.Index < 0)
                                {
                                    subOvInfo.HotspotType = HotSpotType.HOTSPOT_UNDERUNDER;
                                }
                            }
                        }

                        // update max boundingbox
                        if (subOvInfo.Origin.X < min.X)
                        {
                            min.X = subOvInfo.Origin.X;
                        }

                        if (subOvInfo.Origin.Y < min.Y)
                        {
                            min.Y = subOvInfo.Origin.Y;
                        }

                        x = subOvInfo.Origin.X + subOvInfo.Size.X;
                        y = subOvInfo.Origin.Y + subOvInfo.Size.Y;

                        if (x > max.X)
                        {
                            max.X = x;
                        }

                        if (y > max.Y)
                        {
                            max.Y = y;
                        }

                        // save info for this suboverlay
                        SubBgf.Add(subOvInfo);
                    }
                }

                // get dimension from boundingbox
                dimension.X = Math.Abs(max.X - min.X);
                dimension.Y = Math.Abs(max.Y - min.Y);

                // move all origins so minimum hits 0/0
                // preparation for drawing (pixel origin is 0/0)
                Translate(-min);

                // get the center of the dimension box
                // this is also the center of our image after the translate above
                V2 bbCenter = dimension * 0.5f;

                // get the center of the main overlay
                V2 mainOriginCenter = Origin + (Size * 0.5f);

                // move the x center of the main overlay to the x center of dimensionbox
                V2 centerMove = new V2(bbCenter.X - mainOriginCenter.X, 0.0f);
                Translate(centerMove);

                // since this moves a part outside the dimension box
                // we need to add this size of the move to the dimension,
                // to the right AND left side, so our centering above stays centered
                // then we remove to the center.
                V2 center = new V2(Math.Abs(centerMove.X), 0.0f);
                dimension.X += center.X * 2.0f;
                Translate(center);

                // scale so highest resolution resource has 1:1 ratio (no downscale)
                // or to user provided shrink value
                Scale(IsCustomShrink ? CustomShrink : (Real)MaxShrink);

                // user defined sizes
                if (Width > 0 && Height > 0)
                {
                    // use user given size
                    V2 userSize = new V2(Width, Height);

                    // scale so we use at least all pixels either from upscaled width or height
                    ScaleToBox(userSize, CenterHorizontal, CenterVertical, !IsCustomShrink);
                }
                else
                {
                    Real maxQuality = Quality * QUALITYBASE;
                    Real ratioX     = maxQuality / dimension.X;
                    Real ratioY     = maxQuality / dimension.Y;

                    if (ratioX <= ratioY && ratioX < 1.0f)
                    {
                        Scale(ratioX);
                    }
                    else if (ratioX > ratioY && ratioY < 1.0f)
                    {
                        Scale(ratioY);
                    }

                    // scale up to pow2 if set
                    if (ScalePow2)
                    {
                        // get next power of 2 size
                        V2 pow2Size = new V2(
                            MathUtil.NextPowerOf2((uint)System.Math.Ceiling(dimension.X)),
                            MathUtil.NextPowerOf2((uint)System.Math.Ceiling(dimension.Y)));

                        // scale so we use at least all pixels either from upscaled width or height
                        ScaleToBox(pow2Size, CenterHorizontal, CenterVertical, !IsCustomShrink);
                    }
                }

                // calculate the world-size (shrink=1) of the composed object from dimension, uv-coordinates and scaling
                worldsize.X = (uvend.X * dimension.X) / Scaling;
                worldsize.Y = (uvend.Y * dimension.Y) / Scaling;
            }
        }
Exemple #4
0
        public void ProcessRequest(HttpContext context)
        {
            // --------------------------------------------------------------------------------------------
            // 1) PARSE URL PARAMETERS
            // --------------------------------------------------------------------------------------------

            // See Global.asax:
            //  object/{scale}/{file}/{group}/{palette}/{angle}
            RouteValueDictionary parms = context.Request.RequestContext.RouteData.Values;
            string parmScale           = parms.ContainsKey("scale")   ? (string)parms["scale"]   : null;
            string parmFile            = parms.ContainsKey("file")    ? (string)parms["file"]    : null;
            string parmGroup           = parms.ContainsKey("group")   ? (string)parms["group"]   : null;
            string parmPalette         = parms.ContainsKey("palette") ? (string)parms["palette"] : null;
            string parmAngle           = parms.ContainsKey("angle")   ? (string)parms["angle"]   : null;

            BgfCache.Entry entry;
            ushort         scale;
            byte           paletteidx = 0;
            ushort         angle      = 0;

            // verify that minimum parameters are valid/in range and bgf exists
            // angle ranges from [0-7] and are multiples of 512
            if (!UInt16.TryParse(parmScale, out scale) || scale < MINSCALE || scale > MAXSCALE ||
                !Byte.TryParse(parmPalette, out paletteidx) ||
                !UInt16.TryParse(parmAngle, out angle) || angle > 7 ||
                String.IsNullOrEmpty(parmFile) || !BgfCache.GetBGF(parmFile, out entry))
            {
                context.Response.StatusCode = 404;
                return;
            }

            // multiply by 512 and remove full periods from angle
            angle = (ushort)((angle << 9) % GeometryConstants.MAXANGLE);

            // parse animation
            Animation anim = Animation.ExtractAnimation(parmGroup, '-');

            if (anim == null || !anim.IsValid(entry.Bgf.FrameSets.Count))
            {
                context.Response.StatusCode = 404;
                return;
            }

            // stores the latest lastmodified of main and all subov
            DateTime lastModified = entry.LastModified;

            // read suboverlay array params from query parameters:
            //  object/..../?subov={file};{group};{palette};{hotspot}&subov=...
            string[] parmSubOverlays = context.Request.Params.GetValues("s");

            if (parmSubOverlays != null)
            {
                foreach (string s in parmSubOverlays)
                {
                    string[] subOvParms = s.Split(';');

                    BgfCache.Entry bgfSubOv;
                    byte           subOvPalette;
                    byte           subOvHotspot;

                    if (subOvParms == null || subOvParms.Length < 4 ||
                        String.IsNullOrEmpty(subOvParms[0]) ||
                        String.IsNullOrEmpty(subOvParms[1]) ||
                        !byte.TryParse(subOvParms[2], out subOvPalette) ||
                        !byte.TryParse(subOvParms[3], out subOvHotspot) || subOvHotspot > 127 ||
                        !BgfCache.GetBGF(subOvParms[0], out bgfSubOv))
                    {
                        context.Response.StatusCode = 404;
                        return;
                    }

                    // get suboverlay animation
                    Animation subOvAnim = Animation.ExtractAnimation(subOvParms[1], '-');
                    if (subOvAnim == null || !subOvAnim.IsValid(bgfSubOv.Bgf.FrameSets.Count))
                    {
                        context.Response.StatusCode = 404;
                        return;
                    }

                    // create suboverlay
                    SubOverlay subOv = new SubOverlay(0, subOvAnim, subOvHotspot, subOvPalette, 0);

                    // set bgf resource
                    subOv.Resource = bgfSubOv.Bgf;

                    // update lastModified if subov is newer
                    if (bgfSubOv.LastModified > lastModified)
                    {
                        lastModified = bgfSubOv.LastModified;
                    }

                    // add to gameobject's suboverlays
                    gameObject.SubOverlays.Add(subOv);
                }
            }

            // --------------------------------------------------------------------------------------------
            // 2) SET CACHE HEADERS AND COMPARE FOR 304 RETURN
            // --------------------------------------------------------------------------------------------

            // set cache behaviour
            context.Response.Cache.SetCacheability(HttpCacheability.Public);
            context.Response.Cache.VaryByParams["*"] = false;
            context.Response.Cache.SetLastModified(lastModified);

            // set return type
            context.Response.ContentType = "image/png";
            context.Response.AddHeader("Content-Disposition", "inline; filename=object.png");

            // check if client has valid cached version (returns 304)

            /*DateTime dateIfModifiedSince;
             * string modSince = context.Request.Headers["If-Modified-Since"];
             *
             * // try to parse received client header
             * bool parseOk = DateTime.TryParse(
             *  modSince, CultureInfo.CurrentCulture,
             *  DateTimeStyles.AdjustToUniversal, out dateIfModifiedSince);
             *
             * // send 304 and stop if last file write equals client's cache timestamp
             * if (parseOk && dateIfModifiedSince == lastModified)
             * {
             *  context.Response.SuppressContent = true;
             *  context.Response.StatusCode = 304;
             *  return;
             * }*/

            // --------------------------------------------------------------------------------------------
            // 3) PREPARE RESPONSE
            // --------------------------------------------------------------------------------------------

            // set parsed/created values on game object
            gameObject.Resource         = entry.Bgf;
            gameObject.ColorTranslation = paletteidx;
            gameObject.Animation        = anim;
            gameObject.ViewerAngle      = angle;

            // set imagecomposer scale/shrink
            imageComposer.CustomShrink = (float)scale * 0.1f;

            // tick object (triggers image recreation)
            gameObject.Tick(0, 1);

            if (imageComposer.Image == null)
            {
                context.Response.StatusCode = 404;
                return;
            }

            // --------------------------------------------------------------------------------------------
            // 4) CREATE RESPONSE AND FINISH
            // --------------------------------------------------------------------------------------------

            // write image as png
            imageComposer.Image.Save(context.Response.OutputStream, ImageFormat.Png);

            // clear
            imageComposer.Image.Dispose();
            gameObject.SubOverlays.Clear();
        }
Exemple #5
0
        public void ProcessRequest(HttpContext context)
        {
            // --------------------------------------------------------------------------------------------
            // 1) PARSE URL PARAMETERS
            // --------------------------------------------------------------------------------------------

            // See Global.asax:
            //  render/{width}/{height}/{scale}/{file}/{anim}/{palette}/{angle}
            RouteValueDictionary parms = context.Request.RequestContext.RouteData.Values;
            string parmWidth           = parms.ContainsKey("width")   ? (string)parms["width"]   : null;
            string parmHeight          = parms.ContainsKey("height")  ? (string)parms["height"]  : null;
            string parmScale           = parms.ContainsKey("scale")   ? (string)parms["scale"]   : null;
            string parmFile            = parms.ContainsKey("file")    ? (string)parms["file"]    : null;
            string parmAnim            = parms.ContainsKey("anim")    ? (string)parms["anim"]    : null;
            string parmPalette         = parms.ContainsKey("palette") ? (string)parms["palette"] : null;
            string parmAngle           = parms.ContainsKey("angle")   ? (string)parms["angle"]   : null;

            BgfCache.Entry entry;
            byte           paletteidx;
            ushort         angle;
            ushort         width;
            ushort         height;
            ushort         scale;

            // verify that minimum parameters are valid/in range and bgf exists
            // angle ranges from [0-7] and are multiples of 512
            if (!UInt16.TryParse(parmWidth, out width) || width < MINWIDTH || width > MAXWIDTH ||
                !UInt16.TryParse(parmHeight, out height) || height < MINHEIGHT || height > MAXHEIGHT ||
                !UInt16.TryParse(parmScale, out scale) || scale < MINSCALE || scale > MAXSCALE ||
                !Byte.TryParse(parmPalette, out paletteidx) ||
                !UInt16.TryParse(parmAngle, out angle) || angle > 7 ||
                String.IsNullOrEmpty(parmFile) || !BgfCache.GetBGF(parmFile, out entry))
            {
                Finish(context, 404);
                return;
            }

            // multiply by 512 and remove full periods from angle
            angle = (ushort)((angle << 9) % GeometryConstants.MAXANGLE);

            // parse animation
            Animation anim = Animation.ExtractAnimation(parmAnim, '-');

            if (anim == null || !anim.IsValid(entry.Bgf.FrameSets.Count))
            {
                Finish(context, 404);
                return;
            }

            // set groupmax
            anim.GroupMax = entry.Bgf.FrameSets.Count;

            // stores the latest lastmodified of main and all subov
            DateTime lastModified = entry.LastModified;

            // set parsed/created values on game-object
            ObjectBase gameObject = new ObjectBase();

            gameObject.OverlayFileRID   = entry.Num;
            gameObject.Resource         = entry.Bgf;
            gameObject.ColorTranslation = paletteidx;
            gameObject.Animation        = anim;
            gameObject.ViewerAngle      = angle;

            // read suboverlay array params from query parameters:
            //  object/..../?subov={file};{anim};{palette};{hotspot}&subov=...
            string[] parmSubOverlays = context.Request.Params.GetValues("s");
            if (parmSubOverlays != null)
            {
                foreach (string s in parmSubOverlays)
                {
                    string[] subOvParms = s.Split(';');

                    BgfCache.Entry bgfSubOv;
                    byte           subOvPalette;
                    byte           subOvHotspot;

                    if (subOvParms == null || subOvParms.Length < 4 ||
                        String.IsNullOrEmpty(subOvParms[0]) ||
                        String.IsNullOrEmpty(subOvParms[1]) ||
                        !byte.TryParse(subOvParms[2], out subOvPalette) ||
                        !byte.TryParse(subOvParms[3], out subOvHotspot) || subOvHotspot > 127 ||
                        !BgfCache.GetBGF(subOvParms[0], out bgfSubOv))
                    {
                        Finish(context, 404);
                        return;
                    }

                    // get suboverlay animation
                    Animation subOvAnim = Animation.ExtractAnimation(subOvParms[1], '-');
                    if (subOvAnim == null || !subOvAnim.IsValid(bgfSubOv.Bgf.FrameSets.Count))
                    {
                        Finish(context, 404);
                        return;
                    }

                    // set group max
                    subOvAnim.GroupMax = bgfSubOv.Bgf.FrameSets.Count;

                    // create suboverlay
                    SubOverlay subOv = new SubOverlay(0, subOvAnim, subOvHotspot, subOvPalette, 0);

                    // set bgf resource
                    subOv.ResourceID = entry.Num;
                    subOv.Resource   = bgfSubOv.Bgf;

                    // update lastModified if subov is newer
                    if (bgfSubOv.LastModified > lastModified)
                    {
                        lastModified = bgfSubOv.LastModified;
                    }

                    // add to gameobject's suboverlays
                    gameObject.SubOverlays.Add(subOv);
                }
            }

            // --------------------------------------------------------------------------------------------
            // 2) SET CACHE HEADERS AND COMPARE FOR 304 RETURN
            // --------------------------------------------------------------------------------------------

            // set cache behaviour
            context.Response.Cache.SetCacheability(HttpCacheability.Public);
            context.Response.Cache.VaryByParams["*"] = false;
            context.Response.Cache.SetLastModified(lastModified);

            // set return type
            context.Response.ContentType = "image/gif";
            context.Response.AddHeader("Content-Disposition", "inline; filename=object.gif");

            // check if client has valid cached version (returns 304)

            /*DateTime dateIfModifiedSince;
             * string modSince = context.Request.Headers["If-Modified-Since"];
             *
             * // try to parse received client header
             * bool parseOk = DateTime.TryParse(
             *  modSince, CultureInfo.CurrentCulture,
             *  DateTimeStyles.AdjustToUniversal, out dateIfModifiedSince);
             *
             * // send 304 and stop if last file write equals client's cache timestamp
             * if (parseOk && dateIfModifiedSince == lastModified)
             * {
             *  context.Response.SuppressContent = true;
             *  Finish(context, 304);
             *  return;
             * }*/

            // --------------------------------------------------------------------------------------------
            // 3) PREPARE RESPONSE
            // --------------------------------------------------------------------------------------------

            // set gif instance size
            gif.CanvasWidth  = width;
            gif.CanvasHeight = height;

            // set imagecomposer size and shrink
            imageComposer.Width        = width;
            imageComposer.Height       = height;
            imageComposer.CustomShrink = (float)scale * 0.1f;

            // set gameobject (causes initial frame)
            imageComposer.DataSource = gameObject;

            // run animationlength in 1 ms steps (causes new image events)
            for (int i = 0; i < gameObject.AnimationLength + 10; i++)
            {
                tick += 1.0;
                gameObject.Tick(tick, 1.0);
            }

            // handle single frame case
            if (gif.Frames.Count == 0 && frame != null)
            {
                gif.Frames.Add(frame);
            }

            // --------------------------------------------------------------------------------------------
            // 4) CREATE RESPONSE AND FINISH
            // --------------------------------------------------------------------------------------------

            // write the gif to output stream
            gif.Write(context.Response.OutputStream);

            // cleanup
            Finish(context);
        }