scummvm/engines/twine/redraw.cpp
2020-10-24 16:12:55 +02:00

861 lines
25 KiB
C++

/** @file redraw.cpp
@brief
This file contains engine redraw actions routines
TwinEngine: a Little Big Adventure engine
Copyright (C) 2013 The TwinEngine team
Copyright (C) 2008-2013 Prequengine team
Copyright (C) 2002-2007 The TwinEngine team
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 "redraw.h"
#include "sdlengine.h"
#include "lbaengine.h"
#include "renderer.h"
#include "interface.h"
#include "screens.h"
#include "grid.h"
#include "scene.h"
#include "actor.h"
#include "hqrdepack.h"
#include "resources.h"
#include "menu.h"
#include "animations.h"
#include "keyboard.h"
#include "movements.h"
#include "text.h"
#include "collision.h"
#include "sound.h"
#ifdef GAMEMOD
#include "debug.scene.h"
#endif
typedef struct RedrawStruct {
uint16 left;
uint16 top;
uint16 right;
uint16 bottom;
} RedrawStruct;
RedrawStruct currentRedrawList[300];
RedrawStruct nextRedrawList[300];
typedef struct DrawListStruct {
int16 posValue;
uint16 index; // field_2
uint16 X;
uint16 Y;
uint16 Z;
uint16 field_A;
uint16 field_C;
uint16 field_E;
uint16 field_10;
} DrawListStruct;
/** Draw list array to grab the necessary */
DrawListStruct drawList[150];
int16 overlayRotation = 0;
/** Add a certain region to the current redraw list array
@param left start width to redraw the region
@param top start height to redraw the region
@param right end width to redraw the region
@param bottom end height to redraw the region */
void addRedrawCurrentArea(int32 left, int32 top, int32 right, int32 bottom) {
int32 area;
int32 i = 0;
int32 leftValue;
int32 rightValue;
int32 topValue;
int32 bottomValue;
area = (right - left) * (bottom - top);
while (i < numOfRedrawBox) {
if (currentRedrawList[i].left >= left)
leftValue = left;
else
leftValue = currentRedrawList[i].left;
if (currentRedrawList[i].right <= right)
rightValue = right;
else
rightValue = currentRedrawList[i].right;
if (currentRedrawList[i].top >= top)
topValue = top;
else
topValue = currentRedrawList[i].top;
if (currentRedrawList[i].bottom <= bottom)
bottomValue = bottom;
else
bottomValue = currentRedrawList[i].bottom;
if ((rightValue - leftValue) *(bottomValue - topValue) < ((currentRedrawList[i].bottom - currentRedrawList[i].top) *(currentRedrawList[i].right - currentRedrawList[i].left) + area)) {
currentRedrawList[i].left = leftValue;
currentRedrawList[i].top = topValue;
currentRedrawList[i].right = rightValue;
currentRedrawList[i].bottom = bottomValue;
if (currentRedrawList[i].bottom >= SCREEN_WIDTH)
currentRedrawList[i].bottom = SCREEN_TEXTLIMIT_BOTTOM;
return;
}
i++;
};
currentRedrawList[i].left = left;
currentRedrawList[i].top = top;
currentRedrawList[i].right = right;
currentRedrawList[i].bottom = bottom;
if (currentRedrawList[i].bottom >= SCREEN_WIDTH)
currentRedrawList[i].bottom = SCREEN_TEXTLIMIT_BOTTOM;
numOfRedrawBox++;
}
/** Add a certain region to redraw list array
@param left start width to redraw the region
@param top start height to redraw the region
@param right end width to redraw the region
@param bottom end height to redraw the region */
void addRedrawArea(int32 left, int32 top, int32 right, int32 bottom) {
if (left < 0)
left = 0;
if (top < 0)
top = 0;
if (right >= SCREEN_WIDTH)
right = SCREEN_TEXTLIMIT_RIGHT;
if (bottom >= SCREEN_HEIGHT)
bottom = SCREEN_TEXTLIMIT_BOTTOM;
if (left > right || top > bottom)
return;
nextRedrawList[currNumOfRedrawBox].left = left;
nextRedrawList[currNumOfRedrawBox].top = top;
nextRedrawList[currNumOfRedrawBox].right = right;
nextRedrawList[currNumOfRedrawBox].bottom = bottom;
currNumOfRedrawBox++;
addRedrawCurrentArea(left, top, right, bottom);
}
/** Move next regions to the current redraw list */
void moveNextAreas() {
int32 i;
numOfRedrawBox = 0;
for (i = 0; i < currNumOfRedrawBox; i++) {
addRedrawCurrentArea(nextRedrawList[i].left, nextRedrawList[i].top, nextRedrawList[i].right, nextRedrawList[i].bottom);
}
}
/** Flip currentRedrawList regions in the screen
This only updates small areas in the screen so few CPU processor is used */
void flipRedrawAreas() {
int32 i;
for (i = 0; i < numOfRedrawBox; i++) { // redraw areas on screen
copyBlockPhys(currentRedrawList[i].left, currentRedrawList[i].top, currentRedrawList[i].right, currentRedrawList[i].bottom);
}
numOfRedrawBox = 0;
for (i = 0; i < currNumOfRedrawBox; i++) { //setup the redraw areas for next display
addRedrawCurrentArea(nextRedrawList[i].left, nextRedrawList[i].top, nextRedrawList[i].right, nextRedrawList[i].bottom);
}
}
/** Blit/Update all screen regions in the currentRedrawList */
void blitBackgroundAreas() {
int32 i;
RedrawStruct* currentArea;
currentArea = currentRedrawList;
for (i = 0; i < numOfRedrawBox; i++) {
blitBox(currentArea->left, currentArea->top, currentArea->right, currentArea->bottom, (int8 *) workVideoBuffer, currentArea->left, currentArea->top, (int8 *) frontVideoBuffer);
currentArea++;
}
}
/** Sort drawing list struct ordered as the first objects appear in the top left corner of the screen
@param list drawing list variable which contains information of the drawing objects
@param listSize number of drawing objects in the list */
void sortDrawingList(DrawListStruct *list, int32 listSize) {
int32 i;
int32 j;
DrawListStruct tempStruct;
for (i = 0; i < listSize - 1; i++) {
for (j = 0; j < listSize - 1 - i; j++) {
if (list[j+1].posValue < list[j].posValue) {
memcpy(&tempStruct, &list[j+1], sizeof(DrawListStruct));
memcpy(&list[j+1], &list[j], sizeof(DrawListStruct));
memcpy(&list[j], &tempStruct, sizeof(DrawListStruct));
}
}
}
}
/** */
void addOverlay(int16 type, int16 info0, int16 X, int16 Y, int16 info1, int16 posType, int16 lifeTime) {
int32 i;
for (i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
OverlayListStruct *overlay = &overlayList[i];
if (overlay->info0 == -1) {
overlay->type = type;
overlay->info0 = info0;
overlay->X = X;
overlay->Y = Y;
overlay->info1 = info1;
overlay->posType = posType;
overlay->lifeTime = lbaTime + lifeTime * 50;
return;
}
}
}
/** */
void updateOverlayTypePosition(int16 X1, int16 Y1, int16 X2, int16 Y2) {
int32 i;
int16 newX, newY;
newX = X2 - X1;
newY = Y2 - Y1;
for (i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
OverlayListStruct *overlay = &overlayList[i];
if (overlay->type == koFollowActor) {
overlay->X = newX;
overlay->Y = newY;
}
}
}
/** This is responsible for the entire game screen redraw
@param bgRedraw true if we want to redraw background grid, false if we want to update certain screen areas */
void redrawEngineActions(int32 bgRedraw) { // fullRedraw
int16 tmpProjPosX;
int16 tmpProjPosY;
int32 i;
int32 tmpVal;
int32 modelActorPos; // arg_1A
int32 spriteActorPos; // top6
int32 shadowActorPos; // top2
int32 drawListPos; // a12
ActorStruct *actor;
tmpProjPosX = projPosXScreen;
tmpProjPosY = projPosYScreen;
resetClip();
if (bgRedraw) {
freezeTime();
if (needChangeScene != -1 && needChangeScene != -2)
fadeOut(paletteRGBA);
clearScreen();
redrawGrid();
updateOverlayTypePosition(tmpProjPosX, tmpProjPosY, projPosXScreen, projPosYScreen);
copyScreen(frontVideoBuffer, workVideoBuffer);
if (needChangeScene != -1 && needChangeScene != -2) {
fadeIn(paletteRGBA);
setPalette(paletteRGBA);
}
} else {
blitBackgroundAreas();
}
// first loop
modelActorPos = 0;
drawListPos = 0;
spriteActorPos = 0x1000;
shadowActorPos = 0x0C00;
// Process actors drawing list
for (modelActorPos = 0; modelActorPos < sceneNumActors; modelActorPos++, spriteActorPos++, shadowActorPos++) {
actor = &sceneActors[modelActorPos];
actor->dynamicFlags.bIsVisible = 0; // reset visible state
if ((useCellingGrid == -1) || actor->Y <= (*(int16 *)(cellingGridIdx*24 + (int8 *)sceneZones + 8))) {
// no redraw required
if (actor->staticFlags.bIsBackgrounded && bgRedraw == 0) {
// get actor position on screen
projectPositionOnScreen(actor->X - cameraX, actor->Y - cameraY, actor->Z - cameraZ);
// check if actor is visible on screen, otherwise don't display it
if (projPosX > -50 && projPosX < 680 && projPosY > -30 && projPosY < 580) {
actor->dynamicFlags.bIsVisible = 1;
}
} else {
// if the actor isn't set as hidden
if (actor->entity != -1 && !(actor->staticFlags.bIsHidden)) {
// get actor position on screen
projectPositionOnScreen(actor->X - cameraX, actor->Y - cameraY, actor->Z - cameraZ);
if ((actor->staticFlags.bUsesClipping && projPosX > -112 && projPosX < 752 && projPosY > -50 && projPosY < 651) ||
((!actor->staticFlags.bUsesClipping) && projPosX > -50 && projPosX < 680 && projPosY > -30 && projPosY < 580)) {
tmpVal = actor->Z + actor->X - cameraX - cameraZ;
// if actor is above another actor
if (actor->standOn != -1) {
tmpVal = sceneActors[actor->standOn].X - cameraX + sceneActors[actor->standOn].Z - cameraZ + 2;
}
if (actor->staticFlags.bIsSpriteActor) {
drawList[drawListPos].index = spriteActorPos; // > 0x1000
if (actor->staticFlags.bUsesClipping) {
tmpVal = actor->lastX - cameraX + actor->lastZ - cameraZ;
}
} else {
drawList[drawListPos].index = modelActorPos;
}
drawList[drawListPos].posValue = tmpVal;
drawListPos++;
// if use shadows
if (cfgfile.ShadowMode != 0 && !(actor->staticFlags.bDoesntCastShadow)) {
if (actor->standOn != -1) {
shadowX = actor->X;
shadowY = actor->Y - 1;
shadowZ = actor->Z;
} else {
getShadowPosition(actor->X, actor->Y, actor->Z);
}
tmpVal--;
drawList[drawListPos].posValue = tmpVal; // save the shadow entry in the drawList
drawList[drawListPos].index = 0xC00; // shadowActorPos
drawList[drawListPos].X = shadowX;
drawList[drawListPos].Y = shadowY;
drawList[drawListPos].Z = shadowZ;
drawList[drawListPos].field_A = 2;
drawListPos++;
}
}
}
}
}
}
// second loop
for (i = 0; i < EXTRA_MAX_ENTRIES; i++) {
ExtraListStruct *extra = &extraList[i];
if (extra->info0 != -1) {
if (extra->type & 0x400) {
if (lbaTime - extra->lifeTime > 35) {
extra->lifeTime = lbaTime;
extra->type &= 0xFBFF;
// FIXME make constant for sample index
playSample(11, 0x1000, 1, extra->X, extra->Y, extra->Z, -1);
}
} else {
if ((extra->type & 1) || (extra->type & 0x40) || (extra->actorIdx + extra->lifeTime - 150 < lbaTime) || (!((lbaTime + extra->lifeTime) & 8))) {
projectPositionOnScreen(extra->X - cameraX, extra->Y - cameraY, extra->Z - cameraZ);
if (projPosX > -50 && projPosX < 680 && projPosY > -30 && projPosY < 580) {
drawList[drawListPos].posValue = extra->X - cameraX + extra->Z - cameraZ;
drawList[drawListPos].index = 0x1800 + i;
drawListPos++;
if (cfgfile.ShadowMode == 2 && !(extra->info0 & 0x8000)) {
getShadowPosition(extra->X, extra->Y, extra->Z);
drawList[drawListPos].posValue = extra->X - cameraX + extra->Z - cameraZ - 1;
drawList[drawListPos].index = 0xC00;
drawList[drawListPos].X = shadowX;
drawList[drawListPos].Y = shadowY;
drawList[drawListPos].Z = shadowZ;
drawList[drawListPos].field_A = 0;
drawListPos++;
}
}
}
}
}
}
sortDrawingList(drawList, drawListPos);
currNumOfRedrawBox = 0;
// if has something to draw
if (drawListPos > 0) {
int32 pos = 0;
uint32 flags;
int32 actorIdx;
ActorStruct *actor;
do {
actorIdx = drawList[pos].index & 0x3FF;
actor = &sceneActors[actorIdx];
flags = ((uint32) drawList[pos].index) & 0xFC00;
// Drawing actors
if (flags < 0xC00) {
if (!flags) {
setModelAnimation(actor->animPosition, animTable[actor->previousAnimIdx], bodyTable[actor->entity], &actor->animTimerData);
if (!renderIsoModel(actor->X - cameraX, actor->Y - cameraY, actor->Z - cameraZ, 0, actor->angle, 0, bodyTable[actor->entity])) {
if (renderLeft < 0)
renderLeft = SCREEN_TEXTLIMIT_LEFT;
if (renderTop < 0)
renderTop = SCREEN_TEXTLIMIT_TOP;
if (renderRight >= SCREEN_WIDTH)
renderRight = SCREEN_TEXTLIMIT_RIGHT;
if (renderBottom >= SCREEN_HEIGHT)
renderBottom = SCREEN_TEXTLIMIT_BOTTOM;
setClip(renderLeft, renderTop, renderRight, renderBottom);
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
int32 tempX;
int32 tempY;
int32 tempZ;
actor->dynamicFlags.bIsVisible = 1;
tempX = (actor->X + 0x100) >> 9;
tempY = actor->Y >> 8;
if (actor->brickShape & 0x7F)
tempY++;
tempZ = (actor->Z + 0x100) >> 9;
drawOverModelActor(tempX, tempY, tempZ);
if(cropBottomScreen) {
renderBottom = textWindowBottom = cropBottomScreen + 10;
}
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
if (actor->staticFlags.bIsBackgrounded && bgRedraw == 1) {
blitBox(textWindowLeft, textWindowTop, renderRight, renderBottom, (int8 *) frontVideoBuffer, textWindowLeft, textWindowTop, (int8 *) workVideoBuffer);
}
}
}
}
}
// Drawing shadows
else if (flags == 0xC00 && !cropBottomScreen) {
int32 spriteWidth, spriteHeight, tmpX, tmpY, tmpZ;
DrawListStruct shadow = drawList[pos];
// get actor position on screen
projectPositionOnScreen(shadow.X - cameraX, shadow.Y - cameraY, shadow.Z - cameraZ);
getSpriteSize(shadow.field_A, &spriteWidth, &spriteHeight, spriteShadowPtr);
// calculate sprite size and position on screen
renderLeft = projPosX - (spriteWidth / 2);
renderTop = projPosY - (spriteHeight / 2);
renderRight = projPosX + (spriteWidth / 2);
renderBottom = projPosY + (spriteHeight / 2);
setClip(renderLeft, renderTop, renderRight, renderBottom);
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
drawSprite(shadow.field_A, renderLeft, renderTop, spriteShadowPtr);
}
tmpX = (shadow.X + 0x100) >> 9;
tmpY = shadow.Y >> 8;
tmpZ = (shadow.Z + 0x100) >> 9;
drawOverModelActor(tmpX, tmpY, tmpZ);
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
// show clipping area
//drawBox(renderLeft, renderTop, renderRight, renderBottom);
}
// Drawing unknown
else if (flags < 0x1000) {
// TODO reverse this part of the code
}
// Drawing sprite actors
else if (flags == 0x1000) {
int32 spriteWidth, spriteHeight;
uint8 *spritePtr = spriteTable[actor->entity];
// get actor position on screen
projectPositionOnScreen(actor->X - cameraX, actor->Y - cameraY, actor->Z - cameraZ);
getSpriteSize(0, &spriteWidth, &spriteHeight, spritePtr);
// calculate sprite position on screen
renderLeft = projPosX + *((int16 *)(spriteBoundingBoxPtr + (actor->entity * 16)));
renderTop = projPosY + *((int16 *)(spriteBoundingBoxPtr + (actor->entity * 16) + 2));
renderRight = renderLeft + spriteWidth;
renderBottom = renderTop + spriteHeight;
if (actor->staticFlags.bUsesClipping) {
setClip(projPosXScreen + actor->info0, projPosYScreen + actor->info1, projPosXScreen + actor->info2, projPosYScreen + actor->info3);
} else {
setClip(renderLeft, renderTop, renderRight, renderBottom);
}
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
drawSprite(0, renderLeft, renderTop, spritePtr);
actor->dynamicFlags.bIsVisible = 1;
if (actor->staticFlags.bUsesClipping) {
drawOverSpriteActor((actor->lastX + 0x100) >> 9, actor->lastY >> 8, (actor->lastZ + 0x100) >> 9);
} else {
int32 tmpX, tmpY, tmpZ;
tmpX = (actor->X + actor->boudingBox.X.topRight + 0x100) >> 9;
tmpY = actor->Y >> 8;
if (actor->brickShape & 0x7F) {
tmpY++;
}
tmpZ = (actor->Z + actor->boudingBox.Z.topRight + 0x100) >> 9;
drawOverSpriteActor(tmpX, tmpY, tmpZ);
}
addRedrawArea(textWindowLeft, textWindowTop, textWindowRight, textWindowBottom);
if (actor->staticFlags.bIsBackgrounded && bgRedraw == 1) {
blitBox(textWindowLeft, textWindowTop, textWindowRight, textWindowBottom, (int8 *) frontVideoBuffer, textWindowLeft, textWindowTop, (int8 *) workVideoBuffer);
}
// show clipping area
//drawBox(renderLeft, renderTop, renderRight, renderBottom);
}
}
// Drawing extras
else if (flags == 0x1800) {
ExtraListStruct *extra = &extraList[actorIdx];
projectPositionOnScreen(extra->X - cameraX, extra->Y - cameraY, extra->Z - cameraZ);
if (extra->info0 & 0x8000) {
drawExtraSpecial(actorIdx, projPosX, projPosY);
} else {
int32 spriteWidth, spriteHeight;
getSpriteSize(0, &spriteWidth, &spriteHeight, spriteTable[extra->info0]);
// calculate sprite position on screen
renderLeft = projPosX + *(int16 *)(spriteBoundingBoxPtr + extra->info0 * 16);
renderTop = projPosY + *(int16 *)(spriteBoundingBoxPtr + extra->info0 * 16 + 2);
renderRight = renderLeft + spriteWidth;
renderBottom = renderTop + spriteHeight;
drawSprite(0, renderLeft, renderTop, spriteTable[extra->info0]);
}
setClip(renderLeft, renderTop, renderRight, renderBottom);
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
int32 tmpX, tmpY, tmpZ;
tmpX = (drawList[pos].X + 0x100) >> 9;
tmpY = drawList[pos].Y >> 8;
tmpZ = (drawList[pos].Z + 0x100) >> 9;
drawOverModelActor(tmpX, tmpY, tmpZ);
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
// show clipping area
//drawBox(renderLeft, renderTop, renderRight, renderBottom);
}
}
resetClip();
pos++;
} while (pos < drawListPos);
}
#ifdef GAMEMOD
displayZones(skipIntro);
#endif
for (i = 0; i < OVERLAY_MAX_ENTRIES; i++) {
OverlayListStruct *overlay = &overlayList[i];
if (overlay->info0 != -1) {
// process position overlay
switch(overlay->posType) {
case koNormal:
if (lbaTime >= overlay->lifeTime) {
overlay->info0 = -1;
continue;
}
break;
case koFollowActor: {
ActorStruct *actor = &sceneActors[overlay->info1];
projectPositionOnScreen(actor->X - cameraX, actor->Y + actor->boudingBox.Y.topRight - cameraY, actor->Z - cameraZ);
overlay->X = projPosX;
overlay->Y = projPosY;
if (lbaTime >= overlay->lifeTime) {
overlay->info0 = -1;
continue;
}
}
break;
}
// process overlay type
switch(overlay->type) {
case koSprite: {
int16 offsetX, offsetY;
int32 spriteWidth, spriteHeight;
uint8 *spritePtr = spriteTable[overlay->info0];
getSpriteSize(0, &spriteWidth, &spriteHeight, spritePtr);
offsetX = *((int16 *)(spriteBoundingBoxPtr + (overlay->info0 * 16)));
offsetY = *((int16 *)(spriteBoundingBoxPtr + (overlay->info0 * 16) + 2));
renderLeft = offsetX + overlay->X;
renderTop = offsetY + overlay->Y;
renderRight = renderLeft + spriteWidth;
renderBottom = renderTop + spriteHeight;
drawSprite(0, renderLeft, renderTop, spritePtr);
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
}
}
break;
case koNumber: {
int32 textLength, textHeight;
int8 text[10];
sprintf(text, "%d", overlay->info0);
textLength = getTextSize(text);
textHeight = 48;
renderLeft = overlay->X - (textLength/2);
renderTop = overlay->Y - 24;
renderRight = overlay->X + (textLength/2);
renderBottom = overlay->Y + textHeight;
setClip(renderLeft, renderTop, renderRight, renderBottom);
setFontColor(overlay->info1);
drawText(renderLeft, renderTop, text);
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
}
}
break;
case koNumberRange: {
int32 textLength, textHeight, range;
int8 text[10];
range = getAverageValue(overlay->info1, overlay->info0, 100, overlay->lifeTime - lbaTime - 50);
sprintf(text, "%d", range);
textLength = getTextSize(text);
textHeight = 48;
renderLeft = overlay->X - (textLength/2);
renderTop = overlay->Y - 24;
renderRight = overlay->X + (textLength/2);
renderBottom = overlay->Y + textHeight;
setClip(renderLeft, renderTop, renderRight, renderBottom);
setFontColor(155);
drawText(renderLeft, renderTop, text);
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
}
}
break;
case koInventoryItem: {
int32 item = overlay->info0;
drawSplittedBox(10, 10, 69, 69, 0);
setClip(10, 10, 69, 69);
prepareIsoModel(inventoryTable[item]);
setCameraPosition(40, 40, 128, 200, 200);
setCameraAngle(0, 0, 0, 60, 0, 0, 16000);
overlayRotation += 1; // overlayRotation += 8;
renderIsoModel(0, 0, 0, 0, overlayRotation, 0, inventoryTable[item]);
drawBox(10, 10, 69, 69);
addRedrawArea(10, 10, 69, 69);
initEngineProjections();
}
break;
case koText: {
int32 textLength, textHeight;
int8 text[256];
getMenuText(overlay->info0, text);
textLength = getTextSize(text);
textHeight = 48;
renderLeft = overlay->X - (textLength/2);
renderTop = overlay->Y - 24;
renderRight = overlay->X + (textLength/2);
renderBottom = overlay->Y + textHeight;
if(renderLeft < 0) {
renderLeft = 0;
}
if(renderTop < 0) {
renderTop = 0;
}
if(renderRight > SCREEN_TEXTLIMIT_RIGHT) {
renderRight = SCREEN_TEXTLIMIT_RIGHT;
}
if(renderBottom > SCREEN_TEXTLIMIT_BOTTOM) {
renderBottom = SCREEN_TEXTLIMIT_BOTTOM;
}
setClip(renderLeft, renderTop, renderRight, renderBottom);
setFontColor(sceneActors[overlay->info1].talkColor);
drawText(renderLeft, renderTop, text);
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
addRedrawArea(textWindowLeft, textWindowTop, renderRight, renderBottom);
}
}
break;
}
}
}
resetClip();
// make celling grid fade
// need to be here to fade after drawing all actors in scene
if (needChangeScene == -2) {
crossFade(frontVideoBuffer, paletteRGBA);
needChangeScene = -1;
}
if (bgRedraw) {
flip();
moveNextAreas();
unfreezeTime();
} else {
flipRedrawAreas();
}
if (lockPalette) {
if (useAlternatePalette) {
fadeToPal(paletteRGBA);
} else {
fadeToPal(mainPaletteRGBA);
}
lockPalette = 0;
}
if (zoomScreen) {
//zoomScreenScale();
}
}
void drawBubble(int32 actorIdx) {
int32 spriteWidth, spriteHeight;
uint8 *spritePtr;
ActorStruct *actor = &sceneActors[actorIdx];
// get actor position on screen
projectPositionOnScreen(actor->X - cameraX, actor->Y + actor->boudingBox.Y.topRight - cameraY, actor->Z - cameraZ);
if (actorIdx != bubbleActor) {
bubbleSpriteIndex = bubbleSpriteIndex ^ 1;
bubbleActor = actorIdx;
}
spritePtr = spriteTable[bubbleSpriteIndex];
getSpriteSize(0, &spriteWidth, &spriteHeight, spritePtr);
// calculate sprite position on screen
if (bubbleSpriteIndex == SPRITEHQR_DIAG_BUBBLE_RIGHT) {
renderLeft = projPosX + 10;
} else {
renderLeft = projPosX - 10 - spriteWidth;
}
renderTop = projPosY - 20;
renderRight = spriteWidth + renderLeft - 1;
renderBottom = spriteHeight + renderTop - 1;
setClip(renderLeft, renderTop, renderRight, renderBottom);
drawSprite(0, renderLeft, renderTop, spritePtr);
if (textWindowLeft <= textWindowRight && textWindowTop <= textWindowBottom) {
copyBlockPhys(renderLeft, renderTop, renderRight, renderBottom);
}
resetClip();
}
void zoomScreenScale() {
int h, w;
uint8 * dest;
uint8 * zoomWorkVideoBuffer = (uint8 *) malloc((SCREEN_WIDTH * SCREEN_HEIGHT) * sizeof(uint8));
memcpy(zoomWorkVideoBuffer, workVideoBuffer, SCREEN_WIDTH*SCREEN_HEIGHT);
dest = workVideoBuffer;
for (h = 0; h < SCREEN_HEIGHT; h++) {
for (w = 0; w < SCREEN_WIDTH; w++) {
*dest++ = *zoomWorkVideoBuffer;
*dest++ = *zoomWorkVideoBuffer++;
}
//memcpy(dest, dest - SCREEN_WIDTH, SCREEN_WIDTH);
//dest += SCREEN_WIDTH;
}
copyScreen(workVideoBuffer, frontVideoBuffer);
//free(zoomWorkVideoBuffer);
}