Added graphics context debugging function.

Plus small cleanups.



git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3302 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
Meep-Eep
2009-11-14 22:17:24 +00:00
parent acbb2f7b25
commit 823c756b3c
17 changed files with 648 additions and 83 deletions
+1
View File
@@ -1,4 +1,5 @@
Changes towards version 0.7:
- Added graphics context debugging function - SvdB
- Thread down-throttling and game sleep when inactive (currently disabled),
(bug #1070), from Flandry
- Internal changes: GOOD_GUY/BAD_GUY ship flags retired - Alex
+16 -5
View File
@@ -6,11 +6,15 @@ require the game to be in a specific state.
The function debugKeyPressed() in uqmdebug.c is called when the debug key
is pressed. This function is a suitable place to put various debugging
calls.
There is also a global variable 'debugHook', which can be set to a function
to be called the next iteration of the main game loop (which will occur
when the current activity (IP, HyperSpace, Communication, Battle) changes.
By setting this, a function can be called from the main loop, thereby
eliminating threading issues that may otherwise arrise.
There are also global variables 'debugHook' and 'doInputDebugHook',
which can be set to a function to be called from the Starcon2Main thread.
If if is set, 'debugHook' is called the next iteration of the main game loop
(which will occur when the current activity (IP, HyperSpace, Communication,
Battle) changes. The game will be in a well defined state here.
If 'doInputDebugHook' is set, the function it is set to is called from
doInput(), which is called all throughout the game.
By setting one of these hooks, a function can be called from the Starcon2Main
thread, thereby eliminating threading issues that may otherwise arrise.
The debug key can be specified in user's override.cfg by adding a line
with a text similar to "debug.1 = STRING:key F12".
An interactive way to access various debugging code, similar to
@@ -56,6 +60,13 @@ listed below:
This function is not defined in sc2code/uqmdebug.h, but in libs/uio.h.
This function can interactively (tty-based) display information on
the state of the uio file system, and modifications can be made.
- the function dumpStrings()
This function prints all the game strings, and is useful to check whether
the various string bases, as defined in gamestr.h, are correct.
- the function debugContexts()
Prints and visually displays the various graphics contexts.
This function should only be called from doInputDebugHook(), as threading
issues would otherwise arrise.
The first version of this document was created by Serge van den Boom,
+16 -1
View File
@@ -169,8 +169,11 @@ extern void UninitGraphics (void);
extern CONTEXT SetContext (CONTEXT Context);
extern COLOR SetContextForeGroundColor (COLOR Color);
extern COLOR GetContextForeGroundColor (void);
extern COLOR SetContextBackGroundColor (COLOR Color);
extern COLOR GetContextBackGroundColor (void);
extern FRAME SetContextFGFrame (FRAME Frame);
extern FRAME GetContextFGFrame (void);
extern BOOLEAN SetContextClipping (BOOLEAN ClipStatus);
extern BOOLEAN SetContextClipRect (RECT *pRect);
extern BOOLEAN GetContextClipRect (RECT *pRect);
@@ -191,7 +194,13 @@ extern void UnbatchGraphics (void);
extern void FlushGraphics (void);
extern void ClearBackGround (RECT *pClipRect);
extern void ClearDrawable (void);
extern CONTEXT CreateContext (void);
#ifdef DEBUG
extern CONTEXT CreateContextAux (const char *name);
#define CreateContext(name) CreateContextAux((name))
#else /* if !defined(DEBUG) */
extern CONTEXT CreateContextAux (void);
#define CreateContext(name) CreateContextAux()
#endif /* !defined(DEBUG) */
extern BOOLEAN DestroyContext (CONTEXT ContextRef);
extern DRAWABLE CreateDisplay (CREATE_FLAGS CreateFlags, SIZE *pwidth,
SIZE *pheight);
@@ -199,6 +208,12 @@ extern DRAWABLE CreateDrawable (CREATE_FLAGS CreateFlags, SIZE width,
SIZE height, COUNT num_frames);
extern BOOLEAN DestroyDrawable (DRAWABLE Drawable);
extern BOOLEAN GetFrameRect (FRAME Frame, RECT *pRect);
#ifdef DEBUG
extern const char *GetContextName (CONTEXT context);
extern CONTEXT GetFirstContext (void);
extern CONTEXT GetNextContext (CONTEXT context);
extern size_t GetContextCount (void);
#endif /* DEBUG */
extern HOT_SPOT SetFrameHot (FRAME Frame, HOT_SPOT HotSpot);
extern HOT_SPOT GetFrameHot (FRAME Frame);
+94 -11
View File
@@ -22,6 +22,14 @@
GRAPHICS_STATUS _GraphicsStatusFlags;
CONTEXT _pCurContext;
#ifdef DEBUG
// We keep track of all contexts
CONTEXT firstContext;
// The first one in the list.
CONTEXT *contextEnd = &firstContext;
// Where to put the next context.
#endif
PRIMITIVE _locPrim;
FONT _CurFontPtr;
@@ -37,12 +45,10 @@ SetContext (CONTEXT Context)
if (LastContext)
{
UnsetContextFlags (
MAKE_WORD (0, GRAPHICS_ACTIVE | DRAWABLE_ACTIVE)
);
MAKE_WORD (0, GRAPHICS_ACTIVE | DRAWABLE_ACTIVE));
SetContextFlags (
MAKE_WORD (0, _GraphicsStatusFlags
& (GRAPHICS_ACTIVE | DRAWABLE_ACTIVE))
);
& (GRAPHICS_ACTIVE | DRAWABLE_ACTIVE)));
DeactivateContext ();
}
@@ -65,17 +71,29 @@ SetContext (CONTEXT Context)
return (LastContext);
}
#ifdef DEBUG
CONTEXT
CreateContext (void)
CreateContextAux (const char *name)
#else /* if !defined(DEBUG) */
CONTEXT
CreateContextAux (void)
#endif /* !defined(DEBUG) */
{
CONTEXT NewContext;
NewContext = AllocContext ();
if (NewContext)
{
/* initialize context */
CONTEXT OldContext;
/* initialize context */
#ifdef DEBUG
NewContext->name = name;
NewContext->next = NULL;
*contextEnd = NewContext;
contextEnd = &NewContext->next;
#endif /* DEBUG */
OldContext = SetContext (NewContext);
SetContextForeGroundColor (
BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F));
@@ -85,9 +103,25 @@ CreateContext (void)
SetContext (OldContext);
}
return (NewContext);
return NewContext;
}
#ifdef DEBUG
// Loop through the list of context to the pointer which points to the
// specified context. This is either 'firstContext' or the address of
// the 'next' field of some other context.
static CONTEXT *
FindContextPtr (CONTEXT context) {
CONTEXT *ptr;
for (ptr = &firstContext; *ptr != NULL; ptr = &(*ptr)->next) {
if (*ptr == context)
break;
}
return ptr;
}
#endif /* DEBUG */
BOOLEAN
DestroyContext (CONTEXT ContextRef)
{
@@ -97,6 +131,16 @@ DestroyContext (CONTEXT ContextRef)
if (_pCurContext && _pCurContext == ContextRef)
SetContext ((CONTEXT)0);
#ifdef DEBUG
// Unlink the context.
{
CONTEXT *contextPtr = FindContextPtr (ContextRef);
if (contextEnd == &ContextRef->next)
contextEnd = contextPtr;
*contextPtr = ContextRef->next;
}
#endif /* DEBUG */
FreeContext (ContextRef);
return TRUE;
}
@@ -109,7 +153,8 @@ SetContextForeGroundColor (COLOR Color)
if (!ContextActive ())
return (BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F));
if ((oldColor = _get_context_fg_color ()) != Color)
oldColor = _get_context_fg_color ();
if (oldColor != Color)
{
SwitchContextForeGroundColor (Color);
@@ -123,6 +168,15 @@ SetContextForeGroundColor (COLOR Color)
return (oldColor);
}
COLOR
GetContextForeGroundColor (void)
{
if (!ContextActive ())
return (BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F));
return _get_context_fg_color ();
}
COLOR
SetContextBackGroundColor (COLOR Color)
{
@@ -131,14 +185,22 @@ SetContextBackGroundColor (COLOR Color)
if (!ContextActive ())
return (BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x00), 0x00));
if ((oldColor = _get_context_bg_color ()) != Color)
{
oldColor = _get_context_bg_color ();
if (oldColor != Color)
SwitchContextBackGroundColor (Color);
}
return (oldColor);
}
COLOR
GetContextBackGroundColor (void)
{
if (!ContextActive ())
return (BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x00), 0x00));
return _get_context_bg_color ();
}
BOOLEAN
SetContextClipping (BOOLEAN ClipStatus)
{
@@ -249,3 +311,24 @@ FixContextFontEffect (void)
_pCurContext->FontBacking = img;
UnsetContextFBkFlags (FBK_DIRTY);
}
#ifdef DEBUG
const char *
GetContextName (CONTEXT context)
{
return context->name;
}
CONTEXT
GetFirstContext (void)
{
return firstContext;
}
CONTEXT
GetNextContext (CONTEXT context)
{
return context->next;
}
#endif /* DEBUG */
+4
View File
@@ -40,6 +40,10 @@ struct context_desc
TFB_Image *FontBacking;
FBK_FLAGS BackingFlags;
#ifdef DEBUG
const char *name;
CONTEXT next;
#endif
};
#define AllocContext() HCalloc (sizeof (CONTEXT_DESC))
+6
View File
@@ -51,6 +51,12 @@ SetContextFGFrame (FRAME Frame)
return (LastFrame);
}
FRAME
GetContextFGFrame (void)
{
return _CurFramePtr;
}
DRAWABLE
CreateDisplay (CREATE_FLAGS CreateFlags, SIZE *pwidth, SIZE *pheight)
{
+2 -2
View File
@@ -1266,7 +1266,7 @@ HailAlien (void)
SubtitleText.align = CommData.AlienTextAlign;
// init subtitle cache context
TextCacheContext = CreateContext ();
TextCacheContext = CreateContext ("TextCacheContext");
TextCacheFrame = CaptureDrawable (
CreateDrawable (WANT_PIXMAP, SIS_SCREEN_WIDTH,
SIS_SCREEN_HEIGHT - SLIDER_Y - SLIDER_HEIGHT + 2, 1));
@@ -1287,7 +1287,7 @@ HailAlien (void)
{
RECT r;
TaskContext = CreateContext ();
TaskContext = CreateContext ("TaskContext");
SetContext (TaskContext);
SetContextFGFrame (Screen);
GetFrameRect (CommData.AlienFrame, &r);
+2 -2
View File
@@ -315,8 +315,8 @@ credit_roll_task (void *data)
TextBack = BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x00), 0x00);
TextFore = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F);
LocalContext = CreateContext ();
DrawContext = CreateContext ();
LocalContext = CreateContext ("Credits.LocalContext");
DrawContext = CreateContext ("Credits.DrawContext");
total_h = disp_h = SCREEN_HEIGHT;
+14
View File
@@ -28,6 +28,7 @@
#include "settings.h"
#include "sounds.h"
#include "tactrans.h"
#include "uqmdebug.h"
#include "libs/inplib.h"
#include "libs/timelib.h"
#include "libs/threadlib.h"
@@ -352,6 +353,19 @@ DoInput (void *pInputState, BOOLEAN resetInput)
UpdateInputState ();
#ifdef DEBUG
if (doInputDebugHook != NULL)
{
void (*saveDebugHook) (void);
saveDebugHook = doInputDebugHook;
doInputDebugHook = NULL;
// No further debugHook calls unless the called
// function resets doInputDebugHook.
(*saveDebugHook) ();
continue;
}
#endif
#if DEMO_MODE || CREATE_JOURNAL
if (ArrowInput != DemoInput)
#endif
+1 -1
View File
@@ -125,7 +125,7 @@ CreateRadar (void)
RECT r;
CONTEXT OldContext;
RadarContext = CreateContext ();
RadarContext = CreateContext ("RadarContext");
OldContext = SetContext (RadarContext);
SetContextFGFrame (Screen);
r.corner.x = RADAR_X;
+1 -1
View File
@@ -110,7 +110,7 @@ GenerateChmmr (BYTE control)
CaptureStringTable (
LoadStringTable (CHMMR_BASE_STRTAB));
ScanContext = CreateContext ();
ScanContext = CreateContext ("genchmmr.ScanContext");
SetContext (ScanContext);
SetContextFGFrame (Screen);
r.corner.x = (SIS_ORG_X + SIS_SCREEN_WIDTH) - MAP_WIDTH;
+1 -1
View File
@@ -152,7 +152,7 @@ LoadPlanet (FRAME SurfDefFrame)
StopMusic ();
TaskContext = CreateContext ();
TaskContext = CreateContext ("TaskContext");
pPlanetDesc = pSolarSysState->pOrbitalDesc;
+1 -1
View File
@@ -1164,7 +1164,7 @@ ScanSystem (void)
(MAP_HEIGHT >> 1) << MAG_SHIFT;
LockMutex (GraphicsLock);
ScanContext = CreateContext ();
ScanContext = CreateContext ("ScanContext");
SetContext (ScanContext);
initPlanetLocationImage (&MenuState);
+4 -4
View File
@@ -96,7 +96,7 @@ LoadKernel (int argc, char *argv[])
InitSound (argc, argv);
InitVideoPlayer (TRUE);
ScreenContext = CreateContext ();
ScreenContext = CreateContext ("ScreenContext");
if (ScreenContext == NULL)
return FALSE;
@@ -158,7 +158,7 @@ InitContexts (void)
{
RECT r;
StatusContext = CreateContext ();
StatusContext = CreateContext ("StatusContext");
if (StatusContext == NULL)
return FALSE;
@@ -170,11 +170,11 @@ InitContexts (void)
r.extent.height = STATUS_HEIGHT;
SetContextClipRect (&r);
SpaceContext = CreateContext ();
SpaceContext = CreateContext ("SpaceContext");
if (SpaceContext == NULL)
return FALSE;
OffScreenContext = CreateContext ();
OffScreenContext = CreateContext ("OffScreenContext");
if (OffScreenContext == NULL)
return FALSE;
+51 -47
View File
@@ -761,7 +761,8 @@ DrawStorageBays (BOOLEAN Refresh)
--i;
}
r.extent.height = (4 * j + (STORAGE_BAY_CAPACITY - 1)) / STORAGE_BAY_CAPACITY;
r.extent.height = (4 * j + (STORAGE_BAY_CAPACITY - 1)) /
STORAGE_BAY_CAPACITY;
if (r.extent.height)
{
r.corner.y += 4 - r.extent.height;
@@ -876,14 +877,11 @@ DeltaSISGauges (SIZE crew_delta, SIZE fuel_delta, int resunit_delta)
s.origin.y = 0;
for (i = 0; i < NUM_DRIVE_SLOTS; ++i)
{
BYTE which_piece;
if ((which_piece =
GLOBAL_SIS (DriveSlots[i])) < EMPTY_SLOT)
BYTE which_piece = GLOBAL_SIS (DriveSlots[i]);
if (which_piece < EMPTY_SLOT)
{
s.frame = SetAbsFrameIndex (
FlagStatFrame, which_piece + 1 + 0
);
FlagStatFrame, which_piece + 1 + 0);
DrawStamp (&s);
s.frame = IncFrameIndex (s.frame);
DrawStamp (&s);
@@ -894,14 +892,11 @@ DeltaSISGauges (SIZE crew_delta, SIZE fuel_delta, int resunit_delta)
s.origin.y = 0;
for (i = 0; i < NUM_JET_SLOTS; ++i)
{
BYTE which_piece;
if ((which_piece =
GLOBAL_SIS (JetSlots[i])) < EMPTY_SLOT)
BYTE which_piece = GLOBAL_SIS (JetSlots[i]);
if (which_piece < EMPTY_SLOT)
{
s.frame = SetAbsFrameIndex (
FlagStatFrame, which_piece + 1 + 1
);
FlagStatFrame, which_piece + 1 + 1);
DrawStamp (&s);
s.frame = IncFrameIndex (s.frame);
DrawStamp (&s);
@@ -913,14 +908,11 @@ DeltaSISGauges (SIZE crew_delta, SIZE fuel_delta, int resunit_delta)
s.origin.x = 1; // This properly centers the modules.
for (i = 0; i < NUM_MODULE_SLOTS; ++i)
{
BYTE which_piece;
if ((which_piece =
GLOBAL_SIS (ModuleSlots[i])) < EMPTY_SLOT)
BYTE which_piece = GLOBAL_SIS (ModuleSlots[i]);
if (which_piece < EMPTY_SLOT)
{
s.frame = SetAbsFrameIndex (
FlagStatFrame, which_piece + 1 + 2
);
FlagStatFrame, which_piece + 1 + 2);
DrawStamp (&s);
}
@@ -996,22 +988,25 @@ DeltaSISGauges (SIZE crew_delta, SIZE fuel_delta, int resunit_delta)
old_coarse_fuel = (COUNT)~0;
else
{
DWORD FuelCapacity;
old_coarse_fuel = (COUNT)(
GLOBAL_SIS (FuelOnBoard) / FUEL_TANK_SCALE
);
GLOBAL_SIS (FuelOnBoard) / FUEL_TANK_SCALE);
if (fuel_delta < 0
&& GLOBAL_SIS (FuelOnBoard) <= (DWORD)-fuel_delta)
{
GLOBAL_SIS (FuelOnBoard) = 0;
else if ((GLOBAL_SIS (FuelOnBoard) += fuel_delta) >
(FuelCapacity = GetFTankCapacity (NULL)))
}
else
{
DWORD FuelCapacity = GetFTankCapacity (NULL);
GLOBAL_SIS (FuelOnBoard) += fuel_delta;
if (GLOBAL_SIS (FuelOnBoard) > FuelCapacity)
GLOBAL_SIS (FuelOnBoard) = FuelCapacity;
}
}
new_coarse_fuel = (COUNT)(
GLOBAL_SIS (FuelOnBoard) / FUEL_TANK_SCALE
);
GLOBAL_SIS (FuelOnBoard) / FUEL_TANK_SCALE);
if (new_coarse_fuel != old_coarse_fuel)
{
sprintf (buf, "%u", new_coarse_fuel);
@@ -1122,8 +1117,7 @@ GetCPodCapacity (POINT *ppt)
SetContextForeGroundColor (crew_rows[which_row]);
else
SetContextForeGroundColor (
BUILD_COLOR (MAKE_RGB15 (0x05, 0x10, 0x05), 0x65)
);
BUILD_COLOR (MAKE_RGB15 (0x05, 0x10, 0x05), 0x65));
}
capacity += CREW_POD_CAPACITY;
@@ -1169,7 +1163,8 @@ GetSBayCapacity (POINT *ppt)
};
bay_remainder = GLOBAL_SIS (TotalElementMass) - capacity;
if ((which_row = bay_remainder / SBAY_MASS_PER_ROW) == 0)
which_row = bay_remainder / SBAY_MASS_PER_ROW;
if (which_row == 0)
SetContextForeGroundColor (BLACK_COLOR);
else
SetContextForeGroundColor (color_bars[--which_row]);
@@ -1184,7 +1179,7 @@ GetSBayCapacity (POINT *ppt)
x -= SHIP_PIECE_OFFSET;
} while (slot--);
return (capacity);
return capacity;
}
DWORD
@@ -1229,8 +1224,7 @@ GetFTankCapacity (POINT *ppt)
which_row = (COUNT)(
(GLOBAL_SIS (FuelOnBoard) - capacity)
* MAX_FUEL_BARS / HEFUEL_TANK_CAPACITY
);
* MAX_FUEL_BARS / HEFUEL_TANK_CAPACITY);
ppt->x = x + 1;
if (volume == FUEL_TANK_CAPACITY)
ppt->y = 27 - which_row;
@@ -1247,7 +1241,7 @@ GetFTankCapacity (POINT *ppt)
x -= SHIP_PIECE_OFFSET;
} while (slot--);
return (capacity);
return capacity;
}
COUNT
@@ -1281,7 +1275,7 @@ CountSISPieces (BYTE piece_type)
}
}
return (num_pieces);
return num_pieces;
}
void
@@ -1356,6 +1350,7 @@ DrawAutoPilotMessage (BOOLEAN Reset)
Task flash_task = 0;
RECT flash_rect;
static FRAME flash_screen_frame = 0;
// The original contents of the flash rectangle.
static int flash_changed;
Mutex flash_mutex = 0;
// XXX: these are currently defined in libs/graphics/sdl/3do_getbody.c
@@ -1369,25 +1364,25 @@ flash_rect_func (void *data)
#define NORMAL_STRENGTH 4
#define NORMAL_F_STRENGTH 0
#define CACHE_SIZE 10
DWORD TimeIn, WaitTime;
SIZE strength, fstrength, incr;
DWORD TimeIn;
const DWORD WaitTime = ONE_SECOND / 16;
SIZE strength;
RECT cached_rect;
FRAME cached_screen_frame = 0;
Task task = (Task)data;
int cached[CACHE_SIZE];
bool cached[CACHE_SIZE];
STAMP cached_stamp[CACHE_SIZE];
int i;
// Init cache
for (i = 0; i < CACHE_SIZE; i++)
{
cached[i] = 0;
cached[i] = false;
cached_stamp[i].frame = 0;
}
fstrength = NORMAL_F_STRENGTH;
incr = 1;
strength = NORMAL_STRENGTH;
TimeIn = GetTimeCounter ();
WaitTime = ONE_SECOND / 16;
while (!Task_ReadState(task, TASK_EXIT))
{
CONTEXT OldContext;
@@ -1411,10 +1406,12 @@ flash_rect_func (void *data)
arith_frame_blit (flash_screen_frame, &screen_rect,
cached_screen_frame, NULL, 0, 0);
UnlockMutex (flash_mutex);
// Clear the cache.
for (i = 0; i < CACHE_SIZE; i++)
{
cached[i] = 0;
if(cached_stamp[i].frame)
cached[i] = false;
if (cached_stamp[i].frame)
DestroyDrawable (ReleaseDrawable (cached_stamp[i].frame));
cached_stamp[i].frame = 0;
}
@@ -1436,7 +1433,7 @@ flash_rect_func (void *data)
{
RECT tmp_rect = cached_rect;
pStamp = &cached_stamp[strength - MIN_STRENGTH];
cached[strength - MIN_STRENGTH] = 1;
cached[strength - MIN_STRENGTH] = true;
pStamp->frame = CaptureDrawable (CreateDrawable (WANT_PIXMAP,
cached_rect.extent.width, cached_rect.extent.height,
1));
@@ -1451,11 +1448,12 @@ flash_rect_func (void *data)
arith_frame_blit (cached_screen_frame, &tmp_rect,
pStamp->frame, &tmp_rect, strength, 4);
}
LockMutex (GraphicsLock);
OldContext = SetContext (ScreenContext);
SetContextClipRect (&cached_rect);
// flash changed_can't be modified while GraphicSem is held
if (! flash_changed)
if (!flash_changed)
DrawStamp (pStamp);
SetContextClipRect (NULL); // this will flush whatever
SetContext (OldContext);
@@ -1465,6 +1463,8 @@ flash_rect_func (void *data)
SleepThreadUntil (TimeIn + WaitTime);
TimeIn = GetTimeCounter ();
}
// Clear cache
{
if (cached_screen_frame)
DestroyDrawable (ReleaseDrawable (cached_screen_frame));
@@ -1480,7 +1480,7 @@ flash_rect_func (void *data)
UnlockMutex (flash_mutex);
FinishTask (task);
return(0);
return 0;
}
void
@@ -1490,7 +1490,7 @@ SetFlashRect (RECT *pRect)
CONTEXT OldContext;
int create_flash = 0;
if (! flash_mutex)
if (!flash_mutex)
flash_mutex = CreateMutex ("FlashRect Lock",
SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
@@ -1525,6 +1525,7 @@ SetFlashRect (RECT *pRect)
if (pRect == 0 || pRect->extent.width == 0)
{
// End the flashing.
flash_rect1.extent.width = 0;
if (flash_task)
{
@@ -1550,8 +1551,10 @@ SetFlashRect (RECT *pRect)
|| old_r.corner.x != flash_rect.corner.x
|| old_r.corner.y != flash_rect.corner.y))
{
// We had a flash rectangle, and now a different one is set.
if (flash_screen_frame)
{
// The screen contents may have changed; we grab a new copy.
STAMP old_s;
old_s.origin.x = old_r.corner.x;
old_s.origin.y = old_r.corner.y;
@@ -1566,6 +1569,7 @@ SetFlashRect (RECT *pRect)
if (flash_rect.extent.width)
{
// A new flash rectangle is set.
// Copy the original contents of the rectangle from the screen.
if (flash_screen_frame)
DestroyDrawable (ReleaseDrawable (flash_screen_frame));
+422 -5
View File
@@ -20,6 +20,7 @@
#include "build.h"
#include "colors.h"
#include "controls.h"
#include "clock.h"
#include "encount.h"
#include "element.h"
@@ -68,6 +69,7 @@ static void dumpPlanetTypeCallback (int index, const PlanetFrame *planet,
BOOLEAN instantMove = FALSE;
BOOLEAN disableInteractivity = FALSE;
void (* volatile debugHook) (void) = NULL;
void (* volatile doInputDebugHook) (void) = NULL;
void
@@ -118,6 +120,12 @@ debugKeyPressed (void)
// main loop. Calling it from here would give threading
// problems.
// Graphical and textual:
//doInputDebugHook = debugContexts;
// This will cause debugContexts to be called from the
// Starcon2Main thread, from DoInput(). Calling it from here
// would give threading problems.
// Interactive:
// uio_debugInteractive(stdin, stdout, stderr);
}
@@ -755,6 +763,7 @@ dumpUniverse (FILE *out)
UniverseRecurse (&universeRecurseArg);
}
// Must be called from the main thread.
void
dumpUniverseToFile (void)
{
@@ -1162,6 +1171,7 @@ tallyResources (FILE *out)
UniverseRecurse (&universeRecurseArg);
}
// Must be called from the main thread.
void
tallyResourcesToFile (void)
{
@@ -1459,7 +1469,8 @@ depositQualityString (BYTE quality)
// playerNr should be 0 or 1
STARSHIP*
findPlayerShip (SIZE playerNr) {
findPlayerShip (SIZE playerNr)
{
HELEMENT hElement, hNextElement;
for (hElement = GetHeadElement (); hElement; hElement = hNextElement)
@@ -1486,7 +1497,8 @@ findPlayerShip (SIZE playerNr) {
////////////////////////////////////////////////////////////////////////////
void
resetCrewBattle(void) {
resetCrewBattle (void)
{
STARSHIP *StarShipPtr;
COUNT delta;
CONTEXT OldContext;
@@ -1508,7 +1520,8 @@ resetCrewBattle(void) {
}
void
resetEnergyBattle(void) {
resetEnergyBattle (void)
{
STARSHIP *StarShipPtr;
COUNT delta;
CONTEXT OldContext;
@@ -1534,7 +1547,8 @@ resetEnergyBattle(void) {
// This function should help in making sure that gamestr.h matches
// gamestrings.txt.
void
dumpStrings(FILE *out) {
dumpStrings (FILE *out)
{
#define STRINGIZE(a) #a
#define MAKE_STRING_CATEGORY(prefix) \
{ \
@@ -1603,6 +1617,409 @@ dumpStrings(FILE *out) {
}
}
////////////////////////////////////////////////////////////////////////////
static COLOR
hsvaToRgba (double hue, double sat, double val, BYTE alpha) {
assert (hue >= 0.0 && hue < 360.0);
assert (sat >= 0 && sat <= 1.0);
assert (val >= 0 && val <= 1.0);
/*fprintf(stderr, "hsva = (%.1f, %.2f, %.2f, %.2d)\n",
hue, sat, val, alpha);*/
unsigned int hi = (int) (hue / 60.0);
double f = (hue / 60.0) - ((int) (hue / 60.0));
double p = val * (1.0 - sat);
double q = val * (1.0 - f * sat);
double t = val * (1.0 - (1.0 - f * sat));
// Convert p, q, t, and v from [0..1] to [0..255]
BYTE pb = (BYTE) (p * 255.0 + 0.5);
BYTE qb = (BYTE) (q * 255.0 + 0.5);
BYTE tb = (BYTE) (t * 255.0 + 0.5);
BYTE vb = (BYTE) (val * 255.0 + 0.5);
assert (hi < 6);
switch (hi) {
case 0: return BUILD_COLOR_RGBA (vb, tb, pb, alpha);
case 1: return BUILD_COLOR_RGBA (qb, vb, pb, alpha);
case 2: return BUILD_COLOR_RGBA (pb, vb, tb, alpha);
case 3: return BUILD_COLOR_RGBA (pb, qb, vb, alpha);
case 4: return BUILD_COLOR_RGBA (tb, pb, vb, alpha);
case 5: return BUILD_COLOR_RGBA (vb, pb, qb, alpha);
}
// Should not happen.
return BUILD_COLOR_RGBA (0, 0, 0, alpha);
}
// Work-around: colors returned by BUILD_COLOR_RGBA are not usable to draw
// with.
static DWORD
fixColorRgba (FRAME frame, COLOR col)
{
#if 0
extern DWORD frame_mapRGBA (FRAME FramePtr, BYTE r, BYTE g, BYTE b,
BYTE a);
BYTE r = (col & 0xff000000) >> 24;
BYTE g = (col & 0x00ff0000) >> 16;
BYTE b = (col & 0x0000ff00) >> 8;
BYTE a = (col & 0x000000ff) >> 0;
return (DWORD) frame_mapRGBA (frame, r, g, b, a);
#endif
BYTE r = (col & 0xff000000) >> 24;
BYTE g = (col & 0x00ff0000) >> 16;
BYTE b = (col & 0x0000ff00) >> 8;
(void) frame;
return BUILD_COLOR (MAKE_RGB15 (r >> 3, g >> 3, b >> 3) ,0);
}
// Workaround. DrawFilledRectangle() doesn't handle transparency.
// We use a temporary frame to achieve the same thing.
static void
DrawFilledRectangleTransparent (RECT *rect, BYTE alpha)
{
extern void arith_frame_blit (FRAME srcFrame, const RECT *rsrc,
FRAME dstFrame, const RECT *rdst, int num, int denom);
RECT absRect;
FRAME orgRectFrame;
COLOR fillColor;
// Create a rectangle from 'rect', but with (0, 0) as origin.
absRect.corner.x = 0;
absRect.corner.y = 0;
absRect.extent = rect->extent;
// Create a new temporary FRAME to store the contents of the original
// rectangle in.
orgRectFrame = CaptureDrawable (CreateDrawable (
WANT_PIXMAP, rect->extent.width, rect->extent.height, 1));
// Copy the original rectangle, faded.
arith_frame_blit (GetContextFGFrame (), rect, orgRectFrame, &absRect,
255 - alpha, 255);
// Apply the transparency to the colour.
fillColor = GetContextForeGroundColor ();
#if 0 /* 32 bits RGBA */
fillColor =
(((((fillColor & 0xff000000) >> 24) * alpha + 127) / 255) << 24) |
(((((fillColor & 0x00ff0000) >> 16) * alpha + 127) / 255) << 16) |
(((((fillColor & 0x0000ff00) >> 8) * alpha + 127) / 255) << 8);
*/
#endif
/* 15 bits RGB + index: */
fillColor =
(((((fillColor & 0x007c0000) >> 18) * alpha + 15) / 31) << 18) |
(((((fillColor & 0x0003e000) >> 13) * alpha + 15) / 31) << 13) |
(((((fillColor & 0x00001f00) >> 8) * alpha + 15) / 31) << 8) |
(fillColor & 0x000000ff);
// Fill the frame with fillColor
{
COLOR oldFgColor = SetContextForeGroundColor (fillColor);
DrawFilledRectangle (rect);
SetContextForeGroundColor (oldFgColor);
FlushGraphics ();
// Not really necessary for the Context for which this
// function is called, but if this function is ever used
// to draw directly to the screen, this will be needed
// to make sure the rectangle is drawn before the
// arith_frame_blit() call, which is immediate.
}
// Blend in the original rectangle.
arith_frame_blit (orgRectFrame, &absRect, GetContextFGFrame (), rect,
1, -1);
// Destroy the temporary frame
DestroyDrawable (ReleaseDrawable (orgRectFrame));
}
// Returns true iff this context has a visible FRAME.
static bool
isContextVisible (CONTEXT context)
{
FRAME contextFrame;
// Save the original context.
CONTEXT oldContext = SetContext (context);
// Get the frame of the specified context.
contextFrame = GetContextFGFrame ();
// Restore the original context.
SetContext (oldContext);
return contextFrame == Screen;
}
static size_t
countVisibleContexts (void)
{
size_t contextCount;
CONTEXT context;
contextCount = 0;
for (context = GetFirstContext (); context != NULL;
context = GetNextContext (context))
{
if (!isContextVisible (context))
continue;
contextCount++;
}
return contextCount;
}
static void
drawContext (CONTEXT context, double hue /* no pun intended */)
{
FRAME drawFrame;
CONTEXT oldContext;
FONT oldFont;
COLOR oldFgCol;
COLOR rectCol;
COLOR lineCol;
COLOR textCol;
bool haveClippingRect;
RECT rect;
LINE line;
TEXT text;
POINT p1, p2, p3, p4;
drawFrame = GetContextFGFrame ();
rectCol = (COLOR) fixColorRgba (drawFrame,
hsvaToRgba (hue, 1.0, 0.5, 127));
lineCol = (COLOR) fixColorRgba (drawFrame,
hsvaToRgba (hue, 1.0, 1.0, 0));
textCol = lineCol;
// Save the original context.
oldContext = SetContext (context);
// Get the clipping rectangle of the specified context.
haveClippingRect = GetContextClipRect (&rect);
// Switch back the old context; we're going to draw in it.
(void) SetContext (oldContext);
if (!haveClippingRect)
{
rect.corner.x = 0;
rect.corner.y = 0;
rect.extent.width = ScreenWidth;
rect.extent.height = ScreenHeight;
}
p1 = rect.corner;
p2.x = rect.corner.x + rect.extent.width - 1;
p2.y = rect.corner.y;
p3.x = rect.corner.x;
p3.y = rect.corner.y + rect.extent.height - 1;
p4.x = rect.corner.x + rect.extent.width - 1;
p4.y = rect.corner.y + rect.extent.height - 1;
oldFgCol = SetContextForeGroundColor (rectCol);
DrawFilledRectangleTransparent (&rect, 63);
SetContextForeGroundColor (lineCol);
line.first = p1; line.second = p2; DrawLine (&line);
line.first = p2; line.second = p4; DrawLine (&line);
line.first = p1; line.second = p3; DrawLine (&line);
line.first = p3; line.second = p4; DrawLine (&line);
line.first = p1; line.second = p4; DrawLine (&line);
line.first = p2; line.second = p3; DrawLine (&line);
// Gimme C'99! So I can do:
// DrawLine ((LINE) { .first = p1, .second = p2 })
oldFont = SetContextFont (TinyFont);
SetContextForeGroundColor (textCol);
text.baseline.x = (p1.x + (p2.x + 1)) / 2;
text.baseline.y = p1.y + 8;
text.pStr = GetContextName (context);
text.align = ALIGN_CENTER;
text.CharCount = (COUNT) ~0;
font_DrawText (&text);
(void) SetContextForeGroundColor (oldFgCol);
(void) SetContextFont (oldFont);
}
static void
describeContext (FILE *out, const CONTEXT context) {
RECT rect;
CONTEXT oldContext = SetContext (context);
GetContextClipRect (&rect);
fprintf(out, "Context '%s':\n"
"\tClipRect = (%d, %d)-(%d, %d) (%d x %d)\n",
GetContextName (context),
rect.corner.x, rect.corner.y,
rect.corner.x + rect.extent.width,
rect.corner.y + rect.extent.height,
rect.extent.width, rect.extent.height);
SetContext (oldContext);
}
typedef struct wait_state
{
// standard state required by DoInput
BOOLEAN (*InputFunc) (struct wait_state *self);
COUNT MenuRepeatDelay;
} WAIT_STATE;
// Maybe move to elsewhere, where it can be reused?
static BOOLEAN
waitForKey (struct wait_state *self) {
if (PulsedInputState.menu[KEY_MENU_SELECT] ||
PulsedInputState.menu[KEY_MENU_CANCEL])
return FALSE;
SleepThread (ONE_SECOND / 20);
(void) self;
return TRUE;
}
// Maybe move to elsewhere, where it can be reused?
static FRAME
getScreen (void)
{
CONTEXT oldContext = SetContext (ScreenContext);
FRAME savedFrame;
RECT screenRect;
screenRect.corner.x = 0;
screenRect.corner.y = 0;
screenRect.extent.width = ScreenWidth;
screenRect.extent.height = ScreenHeight;
savedFrame = CaptureDrawable (LoadDisplayPixmap (&screenRect, (FRAME) 0));
(void) SetContext (oldContext);
return savedFrame;
}
static void
putScreen (FRAME savedFrame) {
STAMP stamp;
CONTEXT oldContext = SetContext (ScreenContext);
stamp.origin.x = 0;
stamp.origin.y = 0;
stamp.frame = savedFrame;
DrawStamp (&stamp);
(void) SetContext (oldContext);
}
// Show the contexts on the screen.
// Must be called from the main thread.
void
debugContexts (void)
{
extern void arith_frame_blit (FRAME srcFrame, const RECT *rsrc,
FRAME dstFrame, const RECT *rdst, int num, int denom);
static volatile bool inDebugContexts = false;
// Prevent this function from being called from within itself.
CONTEXT orgContext;
CONTEXT debugDrawContext;
// We're going to use this context to draw in.
FRAME debugDrawFrame;
double hueIncrement;
size_t visibleContextI;
CONTEXT context;
size_t contextCount;
FRAME savedScreen;
// Prevent this function from being called from within itself.
if (inDebugContexts)
return;
inDebugContexts = true;
contextCount = countVisibleContexts ();
if (contextCount == 0)
goto out;
LockMutex (GraphicsLock);
savedScreen = getScreen ();
//UnlockMutex (GraphicsLock);
FlushGraphics ();
// Make sure that the screen has actually been captured,
// before we use the frame.
// Create a new frame to draw on.
debugDrawContext = CreateContext ("debugDrawContext");
debugDrawFrame = CaptureDrawable (CreateDrawable (
WANT_PIXMAP /*| WANT_ALPHA*/, ScreenWidth, ScreenHeight, 1));
orgContext = SetContext (debugDrawContext);
SetContextFGFrame (debugDrawFrame);
// Fill the new frame with a copy of the original.
arith_frame_blit (savedScreen, NULL, debugDrawFrame, NULL, 1, 1);
hueIncrement = 360.0 / contextCount;
//LockMutex (GraphicsLock);
visibleContextI = 0;
for (context = GetFirstContext (); context != NULL;
context = GetNextContext (context))
{
if (context == debugDrawContext) {
// Skip our own context.
continue;
}
if (isContextVisible (context))
{
// Only draw the visible contexts.
drawContext (context, visibleContextI * hueIncrement);
visibleContextI++;
}
describeContext (stderr, context);
}
// Blit the final debugging frame to the screen.
putScreen (debugDrawFrame);
UnlockMutex (GraphicsLock);
// Wait for a key:
{
WAIT_STATE state;
state.InputFunc = waitForKey;
DoInput(&state, TRUE);
}
SetContext (orgContext);
// Destroy the debugging frame and context.
DestroyContext (debugDrawContext);
// This does nothing with the drawable set with
// SetContextFGFrame().
DestroyDrawable (ReleaseDrawable (debugDrawFrame));
LockMutex (GraphicsLock);
putScreen (savedScreen);
UnlockMutex (GraphicsLock);
DestroyDrawable (ReleaseDrawable (savedScreen));
out:
inDebugContexts = false;
}
#endif /* DEBUG */
+11 -1
View File
@@ -29,9 +29,14 @@
// functions are a no-op.
extern BOOLEAN disableInteractivity;
// If a function is assigned to this, it will be called from the main loop.
// If a function is assigned to this, it will be called from the
// Starcon2Main thread, in the main game loop.
extern void (* volatile debugHook) (void);
// If a function is assigned to this, it will be called from the
// Starcon2Main thread, in doInput().
extern void (* volatile doInputDebugHook) (void);
// Called when the debug key (symbol 'Debug' in the keys.cfg) is pressed.
void debugKeyPressed (void);
@@ -180,6 +185,11 @@ extern BOOLEAN instantMove;
void dumpStrings(FILE *out);
// Graphically and textually show all the contexts.
// Should be called from debugHook.
void debugContexts (void);
// To add some day:
// - a function to fast forward the game clock to a specifiable time.