SquirrelJME/SquirrelJME

View on GitHub
modules/launcher/src/main/java/cc/squirreljme/runtime/launcher/ui/SplashScreenImage.java

Summary

Maintainability
A
0 mins
Test Coverage
// -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
// ---------------------------------------------------------------------------
// Multi-Phasic Applications: SquirrelJME
//     Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
// ---------------------------------------------------------------------------
// SquirrelJME is under the Mozilla Public License Version 2.0.
// See license.mkd for licensing and copyright information.
// ---------------------------------------------------------------------------

package cc.squirreljme.runtime.launcher.ui;

import cc.squirreljme.jvm.mle.constants.UIPixelFormat;
import cc.squirreljme.runtime.cldc.SquirrelJME;
import cc.squirreljme.runtime.lcdui.mle.PencilGraphics;
import java.io.IOException;
import java.io.InputStream;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

/**
 * Handles the splash screen image.
 *
 * @since 2024/01/28
 */
public class SplashScreenImage
{
    /** The copyright string. */
    public static final String COPYRIGHT =
        "https://squirreljme.cc/\n" +
        "(C) 2013-2024 Stephanie Gawroriski\n" +
        "TM  2016-2024 Stephanie Gawroriski\n" +
        "License: Mozilla Public License 2.0!\n" +
        "Donate to me on Patreon:\n" +
        "*** https://www.patreon.com/SquirrelJME! ***";
    
    /** The ending splash color. */
    public static final int END_COLOR =
        0xF5A9B8;
    
    /** The splash image height. */
    public static final int HEIGHT =
        320;
    
    /** The starting splash color. */
    public static final int START_COLOR =
        0x5BCEFA;
    
    /** The splash image width. */
    public static final int WIDTH =
        240;
    
    /** The font used for drawing. */
    private final Font _verFont;
    
    /** The height for text. */
    final int _verHeight;
    
    /** The font used for copyright. */
    private final Font _copyFont;
    
    /** Copyright X position. */
    private final int _copyX;
    
    /** Y position for the copyright. */
    private final int _copyY;
    
    /** Loading bar Y position. */
    private final int _loadingBarY;
    
    /** Loading string X position. */
    private final int _loadingStrX;
    
    /** Loading String Y position. */
    private final int _loadingStrY;
    
    /**
     * Initializes the base splash information.
     *
     * @since 2024/01/28
     */
    public SplashScreenImage()
    {
        // Height of the screen
        int width = SplashScreenImage.WIDTH;
        int height = SplashScreenImage.HEIGHT;
        int centerX = width / 2;
        int centerY = height / 2;
        
        // Version number font
        Font verFont = Font.getFont("sansserif", 0, 16);
        int verHeight = verFont.getPixelSize();
        this._verFont = verFont;
        this._verHeight = verHeight;
        
        // Copyright font
        this._copyFont = Font.getFont("sansserif", 0, 12);
        this._copyX = 2;
        this._copyY = height - 2;
        
        // Loading
        this._loadingBarY = centerY + (height / 8) + (verHeight / 2);
        this._loadingStrX = centerX;
        this._loadingStrY = this._loadingBarY + (verHeight / 2);
    }
    
    /**
     * Generates the splash screen.
     *
     * @return The resultant image data.
     * @since 2024/01/28
     */
    public int[] generateSplash()
    {
        // Image is completely operated with using raw data
        int np = SplashScreenImage.WIDTH * SplashScreenImage.HEIGHT;
        int[] image = new int[np];
        
        // Text will be drawn using the advanced graphics since it can
        // operate on integer buffers directly
        Graphics g = PencilGraphics.hardwareGraphics(
            UIPixelFormat.INT_RGB888, 
            SplashScreenImage.WIDTH, SplashScreenImage.HEIGHT,
            image, 0, null, 0, 0,
            SplashScreenImage.WIDTH, SplashScreenImage.HEIGHT);
        
        // Load splash image onto the data
        try (InputStream relaxedIn = SplashScreen.class
                .getResourceAsStream("relaxedpixel.xpm");
             InputStream logoIn = SplashScreen.class
                .getResourceAsStream("logo.xpm"))
        {
            // Load in the relaxed pixel art of Lex and the logo
            Image relaxedPixel = Image.createImage(relaxedIn);
            Image logoPixel = Image.createImage(logoIn);
            
            // Draw gradient
            SplashScreenImage.drawGradient(g,
                SplashScreenImage.START_COLOR, SplashScreenImage.END_COLOR,
                SplashScreenImage.WIDTH, SplashScreenImage.HEIGHT);
            
            // Draw into the pixel buffer
            g.setBlendingMode(Graphics.SRC_OVER);
            g.drawImage(relaxedPixel,
                SplashScreenImage.WIDTH >> 1, SplashScreenImage.HEIGHT,
                Graphics.BOTTOM | Graphics.HCENTER);
            
            // Draw the logo on top of everything
            g.drawImage(logoPixel,
                SplashScreenImage.WIDTH >> 1, 0,
                Graphics.TOP | Graphics.HCENTER);
        }
        catch (IOException e)
        {
            // Print it but otherwise it is ignored
            e.printStackTrace();
        }
        
        // Draw copyright at the bottom
        this.drawCopyright(g, false);
        
        // Return the resultant image
        return image;
    }
    
    /**
     * Draws the copyright text onto the given graphics.
     *
     * @param __g The graphics to draw onto.
     * @param __swip Should "SquirrelJME Loading..." be drawn?
     * @throws NullPointerException On null arguments.
     * @since 2019/06/29
     */
    public void drawCopyright(Graphics __g, boolean __swip)
        throws NullPointerException
    {
        if (__g == null)
            throw new NullPointerException("NARG");
        
        // Draw version number
        __g.setAlphaColor(255, 0, 0, 0);
        __g.setFont(this._verFont);
        __g.drawString(SquirrelJME.RUNTIME_VERSION, 238, 48,
            Graphics.RIGHT | Graphics.TOP);
        
        // Draw loading and the SquirrelJME string?
        if (__swip)
        {
            // SquirrelJME String
            __g.drawString("SquirrelJME", 2, 2,
                Graphics.TOP | Graphics.LEFT);
            
            // Loading...
            __g.drawString("Loading...",
                this._loadingStrX, this._loadingStrY,
                Graphics.VCENTER | Graphics.HCENTER);
        }
        
        // Set properties
        __g.setFont(this._copyFont);
        
        // Draw a black drop-shadow, this makes the lighter front easier to
        // see regardless of what is on the background
        int copyX = this._copyX;
        int copyY = this._copyY;
        __g.setColor(0x000000);
        __g.drawString(SplashScreenImage.COPYRIGHT, copyX - 1, copyY,
            Graphics.BOTTOM | Graphics.LEFT);
        __g.drawString(SplashScreenImage.COPYRIGHT, copyX + 1, copyY,
            Graphics.BOTTOM | Graphics.LEFT);
        __g.drawString(SplashScreenImage.COPYRIGHT, copyX, copyY - 1,
            Graphics.BOTTOM | Graphics.LEFT);
        __g.drawString(SplashScreenImage.COPYRIGHT, copyX, copyY + 1,
            Graphics.BOTTOM | Graphics.LEFT);
        
        // Then draw the frontal white text
        __g.setColor(0xFFFFFF);
        __g.drawString(SplashScreenImage.COPYRIGHT, copyX, copyY,
            Graphics.BOTTOM | Graphics.LEFT);
    }
    
    /**
     * Draws a gradient.
     * 
     * @param __g The graphics to draw into.
     * @param __startColor The starting color.
     * @param __endColor The ending color.
     * @param __width The width.
     * @param __height The height.
     * @since 2022/01/26
     */
    public static void drawGradient(Graphics __g, int __startColor,
        int __endColor, int __width, int __height)
    {
        // Decompose the starting color
        int atR = ((__startColor >>> 16) & 0xFF) << 8;
        int atG = ((__startColor >>> 8) & 0xFF) << 8;
        int atB = ((__startColor) & 0xFF) << 8;
        
        // Determine the additive for the three colors
        int addR = ((((__endColor >>> 16) & 0xFF) << 8) - atR) /
            __height;
        int addG = ((((__endColor >>> 8) & 0xFF) << 8) - atG) /
            __height;
        int addB = ((((__endColor) & 0xFF) << 8) - atB) /
            __height;
        
        // Draw for each row height
        for (int y = 0; y < __height; y++)
        {
            // Set the next color to use
            __g.setAlphaColor(0xFF,
                atR >>> 8, atG >>> 8, atB >>> 8);
            
            // Draw line
            __g.drawLine(0, y,
                __width, y);
            
            // Determine the next color to use
            atR += addR;
            atG += addG;
            atB += addB;
        }
    }
}