newrpl/firmware/ui_render.c
2020-01-21 18:34:44 -05:00

257 lines
6.4 KiB
C

/*
* Copyright (c) 2014-2015, Claudio Lapilli and the newRPL Team
* All rights reserved.
* This file is released under the 3-clause BSD license.
* See the file LICENSE.txt that shipped with this distribution.
*/
#include <newrpl.h>
#include <ui.h>
#include <libraries.h>
#define NEXT_ENTRY (halCacheEntry&0xffff)
#define CACHE_FULL 0x10000
#define INC_NEXT_ENTRY ((halCacheEntry+1)&(0xffff0000|(MAX_RENDERCACHE_ENTRIES-1)))
#define MAX_BMP_WIDTH 524 // MAXIMUM WIDTH OF A BITMAP TO RENDER AN OBJECT = 4 SCREENS
#define MAX_BMP_HEIGHT 320 // MAXIMUM HEIGHT OF A BITMAP TO RENDER AN OBJECT = 4 SCREENS
// INVALIDATE ALL CACHE ENTRIES
void uiClearRenderCache()
{
halCacheEntry = 0;
}
// ADD AN ENTRY TO THE CACHE
void uiAddCacheEntry(WORDPTR object, WORDPTR bitmap, UNIFONT ** font)
{
if(GCFlags & GC_COMPLETED) {
uiClearRenderCache();
GCFlags = 0;
}
halCacheContents[NEXT_ENTRY * 3] = object;
halCacheContents[NEXT_ENTRY * 3 + 1] = bitmap;
halCacheContents[NEXT_ENTRY * 3 + 2] = (WORDPTR) font;
halCacheEntry = INC_NEXT_ENTRY;
if(NEXT_ENTRY == 0)
halCacheEntry |= CACHE_FULL;
}
void uiUpdateOrAddCacheEntry(WORDPTR object, WORDPTR bitmap, UNIFONT ** font)
{
if(GCFlags & GC_COMPLETED) {
uiClearRenderCache();
GCFlags = 0;
}
int k;
int limit =
(halCacheEntry & CACHE_FULL) ? MAX_RENDERCACHE_ENTRIES : NEXT_ENTRY;
limit *= 3;
for(k = 0; k < limit; k += 3) {
if(halCacheContents[k] == object) {
halCacheContents[k + 1] = bitmap;
halCacheContents[k + 2] = (WORDPTR) font;
return;
}
}
halCacheContents[NEXT_ENTRY * 3] = object;
halCacheContents[NEXT_ENTRY * 3 + 1] = bitmap;
halCacheContents[NEXT_ENTRY * 3 + 2] = (WORDPTR) font;
halCacheEntry = INC_NEXT_ENTRY;
if(NEXT_ENTRY == 0)
halCacheEntry |= CACHE_FULL;
}
// USE AN ENTRY IN THE CACHE
WORDPTR uiFindCacheEntry(WORDPTR object, UNIFONT ** font)
{
if(GCFlags & GC_COMPLETED) {
uiClearRenderCache();
GCFlags = 0;
return 0;
}
int k;
int limit =
(halCacheEntry & CACHE_FULL) ? MAX_RENDERCACHE_ENTRIES : NEXT_ENTRY;
limit *= 3;
for(k = 0; k < limit; k += 3) {
if(halCacheContents[k] == object) {
if(halCacheContents[k + 2] == (WORDPTR) font)
return halCacheContents[k + 1];
}
}
return 0;
}
// ALLOCATE NEW BITMAP OBJECT, THIS IS HARDWARE DEPENDENT AS IT USES THE DEFAULT SCREEN COLOR MODE
WORDPTR uiAllocNewBitmap(BINT width, BINT height)
{
BINT bits = DEFAULTBITSPERPIXEL * width * height;
bits += 31;
bits >>= 5;
WORDPTR newobj = rplAllocTempOb(bits + 2);
if(!newobj)
return 0;
newobj[0] = MKPROLOG(DOBITMAP + DEFAULTBITMAPMODE, bits + 2);
newobj[1] = width;
newobj[2] = height;
return newobj;
}
// RENDER AN OBJECT TO THE GIVEN DRAWSURFACE, USE CACHE IF POSSIBLE
void uiDrawObject(WORDPTR object, DRAWSURFACE * scr, UNIFONT ** font)
{
// FIRST, CHECK IF THE OBJECT IS IN THE CACHE
WORDPTR bmp = uiRenderObject(object, font);
if(bmp) {
// COPY IT TO DESTINATION
DRAWSURFACE tsurf;
tsurf.addr = (int *)(bmp + 3);
tsurf.width = bmp[1];
tsurf.clipx = 0;
tsurf.clipx2 = bmp[1] - 1;
tsurf.clipy = 0;
tsurf.clipy2 = bmp[2] - 1;
tsurf.x = 0;
tsurf.y = 0;
ggl_bitbltclip(scr, &tsurf, bmp[1], bmp[2]);
return;
}
// DRAW DIRECTLY, DON'T CACHE SOMETHING WE COULDN'T RENDER
WORDPTR string = (WORDPTR) invalid_string;
// NOW PRINT THE STRING OBJECT
BINT nchars = rplStrSize(string);
BYTEPTR charptr = (BYTEPTR) (string + 1);
DrawTextN(scr->x, scr->y, (char *)charptr, (char *)charptr + nchars, *font,
15, scr);
}
// RENDER AN OBJECT TO A BITMAP, USE CACHE IF POSSIBLE
WORDPTR uiRenderObject(WORDPTR object, UNIFONT ** font)
{
// FIRST, CHECK IF THE OBJECT IS IN THE CACHE
WORDPTR bmp = uiFindCacheEntry(object, font);
if(bmp)
return bmp;
// OBJECT WAS NOT IN CACHE, RENDER IT AND ADD IT TO CACHE
// TODO: CHANGE DECOMPILE INTO PROPER DISPLAY FUNCTION
WORDPTR string;
string = rplDecompile(object, DECOMP_NOHINTS);
if(!string)
string = (WORDPTR) invalid_string;
// NOW PRINT THE STRING OBJECT
BINT nchars = rplStrSize(string);
BYTEPTR charptr = (BYTEPTR) (string + 1);
BINT numwidth =
StringWidthN((char *)charptr, (char *)charptr + nchars, *font);
if(numwidth > MAX_BMP_WIDTH)
numwidth = MAX_BMP_WIDTH;
ScratchPointer1 = string;
WORDPTR newbmp = uiAllocNewBitmap(numwidth, (*font)->BitmapHeight);
if(newbmp) {
// RELOAD ALL POINTERS IN CASE THERE WAS A GC
string = ScratchPointer1;
charptr = (BYTEPTR) (string + 1);
// CLEAR THE BITMAP FIRST
memsetw(newbmp + 3, 0, OBJSIZE(*newbmp) - 2);
// DRAW TO CACHE FIRST, THEN BITBLT TO SCREEN
DRAWSURFACE tsurf;
tsurf.addr = (int *)(newbmp + 3);
tsurf.width = numwidth;
tsurf.clipx = 0;
tsurf.clipx2 = numwidth - 1;
tsurf.clipy = 0;
tsurf.clipy2 = (*font)->BitmapHeight - 1;
tsurf.x = 0;
tsurf.y = 0;
DrawTextN(0, 0, (char *)charptr, (char *)charptr + nchars, *font, 15,
&tsurf);
// AND ADD TO CACHE
uiAddCacheEntry(object, newbmp, font);
return newbmp;
}
else {
// CAN'T CACHE, DRAW DIRECTLY
return 0;
}
}
// DRAW A BITMAP INTO THE SURFACE. MUST BE SYSTEM-DEFAULT BITMAP
void uiDrawBitmap(WORDPTR bmp, DRAWSURFACE * scr)
{
if(bmp && ISBITMAP(*bmp)) {
// COPY IT TO DESTINATION
DRAWSURFACE tsurf;
tsurf.addr = (int *)(bmp + 3);
tsurf.width = bmp[1];
tsurf.clipx = 0;
tsurf.clipx2 = bmp[1] - 1;
tsurf.clipy = 0;
tsurf.clipy2 = bmp[2] - 1;
tsurf.x = 0;
tsurf.y = 0;
ggl_bitbltclip(scr, &tsurf, bmp[1], bmp[2]);
}
else {
// DRAW DIRECTLY, SOMETHING WE COULDN'T RENDER
WORDPTR string = (WORDPTR) invalid_string;
// NOW PRINT THE STRING OBJECT
BINT nchars = rplStrSize(string);
BYTEPTR charptr = (BYTEPTR) (string + 1);
DrawTextN(scr->x, scr->y, (char *)charptr, (char *)charptr + nchars,
*halScreen.FontArray[FONT_STACK], 15, scr);
}
}