Commit 5df87d79 authored by 昌润 叶's avatar 昌润 叶
Browse files

task1

parent 0df2cf64
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${default}"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"windowsSdkVersion": "10.0.22000.0",
"compileCommands": "${workspaceFolder}/build/compile_commands.json"
}
],
"version": 4
}
\ No newline at end of file
cmake_minimum_required (VERSION 3.2)
project (main)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
aux_source_directory (src SRC_LIST)
include_directories (include)
add_executable (main ${SRC_LIST})
\ No newline at end of file
/*
* File: exception.h
* Version: 1.0
* Last modified on Sun Jul 24 10:26:20 1994 by eroberts
* -----------------------------------------------------
* The exception package provides a general exception
* handling mechanism for use with C that is portable
* across a variety of compilers and operating systems.
*/
#ifndef _exception_h
#define _exception_h
/*
* Overview:
* --------
* The exception package makes it possible for clients to
* specify a handler for an exceptional conditions in a
* syntactically readable way. As a client, your first step
* is to declare an exception condition name by declaring
* a variable of type exception, as in
*
* exception MyException;
*
* Normal visibility rules apply, so that you should declare
* the exception variable at the appropriate level. For
* example, if an exception is local to an implementation,
* it should be declared statically within that module. If
* an exception condition is shared by many modules, the
* exception variable should be declared in an interface
* and exported to all clients that need it. This package
* defines and exports the exception ErrorException, which
* is likely to be sufficient for many clients.
*
* The basic functionality of exceptions is that one piece
* of code can "raise" an exception so that it can then be
* "handled" by special code in a dynamically enclosing
* section of the program. Exceptions are raised by calling
* the pseudo-function raise with the exception name, as in
*
* raise(MyException);
*
* Exceptions are handled using the "try" statement
* (actually implemented using macros), which has the form:
*
* try {
* . . . statements in the body of the block . . .
* except(exception1)
* . . . statements to handle exception 1 . . .
* except(exception2)
* . . . statements to handle exception 2 . . .
* except(ANY)
* . . . statements to handle any exception . . .
* } endtry
*
* Any number of except clauses may appear (up to a
* maximum defined by the constant MaxExceptionsPerScope),
* and the ANY clause is optional.
*
* When the program encounters the "try" statement, the
* statements in the body are executed. If no exception
* conditions are raised during that execution, either
* in this block or by a function call nested inside
* this block, control passes to the end of the "try"
* statement when the last statement in the block is
* executed. If an exception is raised during the
* dynamic execution of the block, control immediately
* passes to the statements in the appropriate except
* clause. Only the statements in that clause are
* executed; no break statement is required to exit
* the block. If no handler for the raised exception
* appears anywhere in the control history, the program
* exits with an error.
*
* Examples of use:
*
* 1. Catching errors.
*
* The following code fragment traps calls to Error, so
* that the program does not quit but instead returns
* to the top-level read-and-execute loop.
*
* while (TRUE) {
* try {
* printf("> ");
* cmd = ReadCommand();
* ExecuteCommand(cmd);
* except(ErrorException)
* -- additional handling code, if any --
* } endtry
* }
*
* If either ReadCommand or ExecuteCommand calls Error,
* control will be passed back to the main loop, after
* executing any additional handler code. (The error
* message is printed by the Error routine, so it is
* often the case that no additional work is needed.)
*
* 2. Handling control-C
*
* The following code extends the example above so that
* typing ^C also returns to top-level.
*
* #include <signal.h>
*
* static exception ControlCException;
* static int errorCount = 0;
* static int ControlCHandler();
*
* main()
* {
* string cmd;
*
* signal(SIGINT, ControlCHandler);
* while (TRUE) {
* try {
* printf("> ");
* cmd = ReadCommand();
* ExecuteCommand(cmd);
* except(ControlCException);
* printf("^C\n");
* signal(SIGINT, ControlCHandler);
* except(ErrorException)
* errorCount++;
* } endtry
* }
* }
*
* static int ControlCHandler()
* {
* raise(ControlCException);
* }
*/
/*
* Actual interface specification
* ------------------------------
* Most of the implementation of the exception mechanism is
* actually done in the macros defined by this file.
* Clients should ordinarily be able to read the description
* above and ignore the detailed code below.
*/
#include <setjmp.h>
#include <string.h>
#include "genlib.h"
/* Define parameters and error status indicators */
#define MaxExceptionsPerScope 10
#define ETooManyExceptClauses 101
#define EUnhandledException 102
/* Codes to keep track of the state of the try handler */
#define ES_Initialize 0
#define ES_EvalBody 1
#define ES_Exception 2
/*
* Type: exception
* ---------------
* Exceptions are specified by their address, so that the
* actual structure does not matter. Strings are used here
* so that exporters of exceptions can store the exception
* name for the use of debuggers and other tools.
*/
typedef struct { string name; } exception;
/*
* Type: context_block
* -------------------
* This structure is used internally to maintain a chain of
* exception scopes on the control stack.
*/
typedef struct ctx_block {
jmp_buf jmp;
int nx;
exception *array[MaxExceptionsPerScope];
exception *id;
void *value;
string name;
struct ctx_block *link;
} context_block;
/* Declare the built-in exceptions */
extern exception ErrorException;
extern exception ANY;
/* Declare a global pointer to the context stack */
extern context_block *exceptionStack;
/*
* Function: RaiseException
* Usage: RaiseException(&e, name, value);
* ---------------------------------------
* This function is called by the raise macro and does the
* work necessary to raise the exception. See the exception.c file
* for details. Clients do not ordinarily call this directly.
*/
void RaiseException(exception *e, string name, void *value);
/*
* Function: HandlerExists
* Usage: if (HandlerExists(&e)) ...
* ---------------------------------
* Determines whether a handler exists for an exception in
* the dynamically enclosing scope. Intended only for use
* by special clients, such as the Error package.
*/
bool HandlerExists(exception *e);
/* Define the pseudo-functions for raise and try */
#define raise(e) RaiseException(&e, #e, NULL)
#define try \
{ \
jmp_buf _tmpbuf; \
context_block _ctx; \
volatile int _es; \
_es = ES_Initialize; \
_ctx.nx = 0; \
_ctx.link = exceptionStack; \
exceptionStack = (context_block *) &_ctx; \
if (setjmp(_tmpbuf) != 0) _es = ES_Exception; \
memcpy((void *) _ctx.jmp, (void *) _tmpbuf, sizeof(jmp_buf)); \
while (1) { \
if (_es == ES_EvalBody)
#define except(e) \
if (_es == ES_EvalBody) exceptionStack = _ctx.link; \
break; \
} \
if (_es == ES_Initialize) { \
if (_ctx.nx >= MaxExceptionsPerScope) \
exit(ETooManyExceptClauses); \
_ctx.array[_ctx.nx++] = &e; \
} else if (_ctx.id == &e || &e == &ANY) { \
exceptionStack = _ctx.link;
#define endtry \
if (_es != ES_Initialize) break; \
_es = ES_EvalBody; \
} \
}
#define GetExceptionName() _ctx.name
#define GetExceptionValue() _ctx.value
#define GetCurrentException() _ctx.id
#endif
/*
* File: extgraph.h
* Version: 3.0
* Last modified on Tue Oct 4 11:24:41 1994 by eroberts
* -----------------------------------------------------
* This interface is the extended graphics interface.
* It includes all of the facilities in graphics.h, plus
* several additional functions that are designed to
* support more sophisticated, interactive graphics.
*/
#ifndef _extgraph_h
#define _extgraph_h
#include "genlib.h"
/* Exported functions */
/* Section 1 -- Basic functions from graphics.h */
#include "graphics.h"
/* Section 2 -- Elliptical arcs */
/*
* Function: DrawEllipticalArc
* Usage: DrawEllipticalArc(rx, ry, start, sweep);
* -----------------------------------------------
* This procedure draws an elliptical arc. It is exactly
* the same in its operation as DrawArc in the graphics.h
* interface, except that the radius is different along the
* two axes.
*/
void DrawEllipticalArc(double rx, double ry,
double start, double sweep);
/* Section 3 -- Graphical regions*/
/*
* Functions: StartFilledRegion, EndFilledRegion
* Usage: StartFilledRegion(density);
* . . . other calls . . .
* EndFilledRegion();
* ------------------------------
* These calls make it possible to draw filled shapes on the
* display. After calling StartFilledRegion, any calls to
* DrawLine and DrawArc are used to create a shape definition
* and do not appear on the screen until EndFilledRegion is
* called. The lines and arcs must be consecutive, in the
* sense that each new element must start where the last
* one ended. MovePen calls may occur at the beginning
* or the end of the region, but not in the interior. When
* EndFilledRegion is called, the entire region appears on the
* screen, with its interior filled in. The density parameter
* is a number between 0 and 1 and indicates how the dot density
* to be used for the fill pattern. If density is 1, the shape
* will be filled in a solid color; if it is 0, the fill will be
* invisible. In between, the implementation will use a dot
* pattern that colors some of the screen dots but not others.
*/
void StartFilledRegion(double density);
void EndFilledRegion(void);
/* Section 4 -- String functions */
/*
* Function: DrawTextString
* Usage: DrawTextString(text);
* ----------------------------
* This function displays the string text at the current point
* in the current font and size. The current point is updated
* so that the next DrawTextString command would continue from
* the next character position. The string may not include the
* newline character.
*/
void DrawTextString(string text);
/*
* Function: TextStringWidth
* Usage: w = TextStringWidth(text);
* ---------------------------------
* This function returns the width of the text string if displayed
* at the current font and size.
*/
double TextStringWidth(string text);
/*
* Function: SetFont
* Usage: SetFont(font);
* ---------------------
* This function sets a new font according to the font string,
* which is case-independent. Different systems support different
* fonts, although common ones like "Times" and "Courier" are often
* supported. Initially, the font is set to "Default" which is
* always supported, although the underlying font is system
* dependent. If the font name is unrecognized, no error is
* generated, and the font remains unchanged. If you need to
* detect this condition, you can call GetFont to see if the
* change took effect. By not generating an error in this case,
* programs become more portable.
*/
void SetFont(string font);
/*
* Function: GetFont
* Usage: font = GetFont();
* ------------------------
* This function returns the current font name as a string.
*/
string GetFont(void);
/*
* Function: SetPointSize
* Usage: SetPointSize(size);
* --------------------------
* This function sets a new point size. If the point size is
* not supported for a particular font, the closest existing
* size is selected.
*/
void SetPointSize(int size);
/*
* Function: GetPointSize
* Usage: size = GetPointSize();
* -----------------------------
* This function returns the current point size.
*/
int GetPointSize(void);
/*
* Text style constants
* --------------------
* The constants Bold and Italic are used in the SetStyle
* command to specify the desired text style. They may also
* be used in combination by adding these constants together,
* as in Bold + Italic. The constant Normal indicates the
* default style.
*/
#define Normal 0
#define Bold 1
#define Italic 2
/*
* Function: SetStyle
* Usage: SetStyle(style);
* -----------------------
* This function establishes the current style properties
* for text based on the parameter style, which is an integer
* representing the sum of any of the text style constants.
*/
void SetStyle(int style);
/*
* Function: GetStyle
* Usage: style = GetStyle();
* --------------------------
* This function returns the current style.
*/
int GetStyle(void);
/*
* Functions: GetFontAscent, GetFontDescent, GetFontHeight
* Usage: ascent = GetFontAscent();
* descent = GetFontDescent();
* height = GetFontHeight();
* -------------------------------------------------------
* These functions return properties of the current font that are
* used to calculate how to position text vertically on the page.
* The ascent of a font is the distance from the baseline to the
* top of the largest character; the descent is the maximum
* distance any character extends below the baseline. The height
* is the total distance between two lines of text, including the
* interline space (which is called leading).
*
* Examples:
* To change the value of y so that it indicates the next text
* line, you need to execute
*
* y -= GetFontHeight();
*
* To center text vertically around the coordinate y, you need
* to start the pen at
*
* y - GetFontAscent() / 2
*/
double GetFontAscent(void);
double GetFontDescent(void);
double GetFontHeight(void);
/* Section 5 -- Mouse support */
/*
* Functions: GetMouseX, GetMouseY
* Usage: x = GetMouseX();
* y = GetMouseY();
* -------------------------------
* These functions return the x and y coordinates of the mouse,
* respectively. The coordinate values are real numbers measured
* in inches from the origin and therefore match the drawing
* coordinates.
*/
double GetMouseX(void);
double GetMouseY(void);
/*
* Functions: MouseButtonIsDown
* Usage: if (MouseButtonIsDown()) . . .
* -------------------------------------
* This function returns TRUE if the mouse button is currently
* down. For maximum compatibility among implementations, the
* mouse is assumed to have one button. If the mouse has more
* than one button, this function returns TRUE if any button
* is down.
*/
bool MouseButtonIsDown(void);
/*
* Functions: WaitForMouseDown, WaitForMouseUp
* Usage: WaitForMouseDown();
* WaitForMouseUp();
* -------------------------------------------
* The WaitForMouseDown function waits until the mouse button
* is pressed and then returns. WaitForMouseUp waits for the
* button to be released.
*/
void WaitForMouseDown(void);
void WaitForMouseUp(void);
/* Section 6 -- Color support */
/*
* Function: HasColor
* Usage: if (HasColor()) . . .
* ----------------------------
* This function returns TRUE if the graphics window can display a
* color image. Note that this condition is stronger than simply
* checking whether a color display is available. Because color
* windows require more memory than black and white ones, this
* function will return FALSE with a color screen if there is
* not enough memory to store a colored image. On the Macintosh,
* for example, it is usually necessary to increase the partition
* size to at least 1MB before color windows can be created.
*/
bool HasColor(void);
/*
* Function: SetPenColor
* Usage: SetPenColor(color);
* --------------------------
* This function sets the color of the pen used for any drawing,
* including lines, text, and filled regions. The color is a
* string, which will ordinarily be one of the following
* predefined color names:
*
* Black, Dark Gray, Gray, Light Gray, White,
* Red, Yellow, Green, Cyan, Blue, Magenta
*
* The first line corresponds to standard gray scales and the
* second to the primary and secondary colors of light. The
* built-in set is limited to these colors because they are
* likely to be the same on all hardware devices. For finer
* color control, you can use the DefineColor function to
* create new color names as well.
*/
void SetPenColor(string color);
/*
* Function: GetPenColor
* Usage: color = GetPenColor();
* -----------------------------
* This function returns the current pen color as a string.
*/
string GetPenColor(void);
/*
* Function: SetPenSize
* Usage: SetPenSize(size);
* -----------------------------------------
* This function sets the size(in pixels) of the pen used for any drawing.
*/
void SetPenSize(int size);
/*
* Function: GetPenSize
* Usage: size = GetPenSize();
* -----------------------------------------
* This function returns the size(in pixels) of the pen used for any drawing.
*/
int GetPenSize(void);
/*
* Function: DefineColor
* Usage: DefineColor(name, red, green, blue);
* -------------------------------------------
* This function allows the client to define a new color name
* by supplying intensity levels for the colors red, green,
* and blue, which are the primary colors of light. The
* color values are provided as real numbers between 0 and 1,
* indicating the intensity of that color. For example,
* the predefined color Magenta has full intensity red and
* blue but no green and is therefore defined as:
*
* DefineColor("Magenta", 1, 0, 1);
*
* DefineColor allows you to create intermediate colors on
* many displays, although the results vary significantly
* depending on the hardware. For example, the following
* usually gives a reasonable approximation of brown:
*
* DefineColor("Brown", .35, .20, .05);
*/
void DefineColor(string name,
double red, double green, double blue);
/* Section 7 -- Miscellaneous functions */
/*
* Function: SetEraseMode
* Usage: SetEraseMode(TRUE);
* SetEraseMode(FALSE);
* ---------------------------
* The SetEraseMode function sets the value of the internal
* erasing flag. Setting this flag is similar to setting the
* color to "White" in its effect but does not affect the
* current color setting. When erase mode is set to FALSE,
* normal drawing is restored, using the current color.
*/
void SetEraseMode(bool mode);
/*
* Function: GetEraseMode
* Usage: mode = GetEraseMode();
* -----------------------------
* This function returns the current state of the erase mode flag.
*/
bool GetEraseMode(void);
/*
* Function: SetWindowTitle
* Usage: SetWindowTitle(title);
* -----------------------------
* This function sets the title of the graphics window, if such
* an operation is possible on the display. If it is not possible
* for a particular implementation, the call is simply ignored.
* This function may be called prior to the InitGraphics call to
* set the initial name of the window.
*/
void SetWindowTitle(string title);
/*
* Function: GetWindowTitle
* Usage: title = GetWindowTitle();
* --------------------------------
* This function returns the title of the graphics window. If the
* implementation does not support titles, this call returns the
* empty string.
*/
string GetWindowTitle(void);
/*
* Function: UpdateDisplay
* Usage: UpdateDisplay();
* -----------------------
* This function initiates an immediate update of the graphics
* window and is necessary for animation. Ordinarily, the
* graphics window is updated only when the program waits for
* user input.
*/
void UpdateDisplay(void);
/*
* Function: Pause
* Usage: Pause(seconds);
* ----------------------
* The Pause function updates the graphics window and then
* pauses for the indicated number of seconds. This function
* is useful for animation where the motion would otherwise
* be too fast.
*/
void Pause(double seconds);
/*
* Function: ExitGraphics
* Usage: ExitGraphics();
* ----------------------
* The ExitGraphics function closes the graphics window and
* exits from the application without waiting for any additional
* user interaction.
*/
void ExitGraphics(void);
/*
* Functions: SaveGraphicsState, RestoreGraphicsState
* Usage: SaveGraphicsState();
* . . . graphical operations . . .
* RestoreGraphicsState();
* ---------------------------------------------------
* The SaveGraphicsState function saves the current graphics
* state (the current pen position, the font, the point size,
* and the erase mode flag) internally, so that they can be
* restored by the next RestoreGraphicsState call. These two
* functions must be used in pairs but may be nested to any depth.
*/
void SaveGraphicsState(void);
void RestoreGraphicsState(void);
/*
* Functions: GetFullScreenWidth, GetFullScreenHeight
* Usage: width = GetFullScreenWidth();
* height = GetFullScreenHeight();
* --------------------------------------
* These functions return the height and width of the entire
* display screen, not the graphics window. Their only
* significant use is for applications that need to adjust
* the size of the graphics window based on available screen
* space. These functions may be called before InitGraphics
* has been called.
*/
double GetFullScreenWidth(void);
double GetFullScreenHeight(void);
/*
* Functions: SetWindowSize
* Usage: SetWindowSize(width, height);
* ------------------------------------
* This function sets the window size to the indicated dimensions,
* if possible. This function should be called before the graphics
* window is created by InitGraphics. Attempts to change the size
* of an existing window are ignored by most implementations. This
* function should be used sparingly because it reduces the
* portability of applications, particularly if the client
* requests more space than is available on the screen.
*/
void SetWindowSize(double width, double height);
/*
* Functions: GetXResolution, GetYResolution
* Usage: xres = GetXResolution();
* yres = GetYResolution();
* -----------------------------------------
* These functions return the number of pixels per inch along
* each of the coordinate directions and are useful for applications
* in which it is important for short distances to be represented
* uniformly in terms of dot spacing. Even though the x and y
* resolutions are the same for most displays, clients should
* not rely on this property.
*
* Note: Lines in the graphics library are one pixel unit wide and
* have a length that is always one pixel longer than you might
* expect. For example, the function call
*
* DrawLine(2 / GetXResolution(), 0);
*
* draws a line from the current point to the point two pixels
* further right, which results in a line of three pixels.
*/
double GetXResolution(void);
double GetYResolution(void);
/*pixels to inches*/
double ScaleXInches(int x);
double ScaleYInches(int y);
#endif
/*
* File: gcalloc.h
* Version: 1.0
* Last modified on Wed Sep 21 16:21:37 1994 by eroberts
* -----------------------------------------------------
* This file is a stub version of the interface for a
* garbage-collecting allocator that will be part of
* a future library release. When the garbage-collecting
* allocator is in use, the memory returned by the GetBlock
* and FreeBlock functions in genlib.h can be traced and
* collected automatically when it is no longer accessible.
*
* The garbage-collecting allocator is not part of the
* current cslib distribution. Even so, functions in the
* other libraries call the ProtectVariable and ProtectBlock
* functions, so that they will continue to work when the
* full library is released. Those functions are implemented
* in genlib.c.
*/
#ifndef _gcalloc_h
#define _gcalloc_h
/*
* Macro: ProtectVariable
* Usage: ProtectVariable(v);
* --------------------------
* This macro registers a global variable with the allocation
* system, so that the variable is traced when the garbage
* collector is used. This operation needs is implemented
* in genlib.c so that code can be written to function correctly
* whether or not the garbage-collecting allocator is loaded.
*/
#define ProtectVariable(v) ProtectBlock(&v, sizeof v)
/*
* Function: ProtectBlock
* Usage: ProtectBlock(ptr, nbytes);
* ---------------------------------
* This function is not usually called by clients (who will
* ordinarily use ProtectVariable instead), but has the
* effect of protecting the block of memory beginning at
* ptr and extending for nbytes from the garbage collector.
*/
void ProtectBlock(void *ptr, size_t nbytes);
/*
* Global linkage variable: _acb
* -----------------------------
* This variable is used to hold the allocation control block
* that provides the linkage between this package and the
* dynamic allocator. The reason for using the structure
* as a linkage is so that the garbage-collecting allocator
* need not even be loaded if it is not explicitly called.
*/
typedef struct {
void *(*allocMethod)(size_t nbytes);
void (*freeMethod)(void *ptr);
void (*protectMethod)(void *ptr, size_t nbytes);
} *_GCControlBlock;
extern _GCControlBlock _acb;
#endif
/*
* File: genlib.h
* Version: 1.0
* Last modified on Sun Jul 24 10:32:49 1994 by eroberts
* -----------------------------------------------------
* This file contains several definitions that form the
* core of a general-purpose ANSI C library developed by Eric
* Roberts. The goal of this library is to provide a basic
* set of tools and conventions that increase the readability
* of C programs, particularly as they are used in a teaching
* environment.
*
* The basic definitions provided by genlib.h are:
*
* 1. Declarations for several new "primitive" types
* (most importantly bool and string) that are
* used throughout the other libraries and
* applications as fundamental types.
*
* 2. A new set of functions for memory allocation.
*
* 3. A function for error handling.
*
* 4. A repeat statement for loops with interior exits.
*/
#ifndef _genlib_h
#define _genlib_h
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
/* Section 1 -- Define new "primitive" types */
/*
* Type: bool
* ----------
* This type has two values, FALSE and TRUE, which are equal to 0
* and 1, respectively. Most of the advantage of defining this type
* comes from readability because it allows the programmer to
* provide documentation that a variable will take on only one of
* these two values. Designing a portable representation, however,
* is surprisingly hard, because many libraries and some compilers
* define these names. The definitions are usually compatible but
* may still be flagged as errors.
*/
#ifdef THINK_C
typedef int bool;
#else
# ifdef TRUE
# ifndef bool
# define bool int
# endif
# else
# ifdef bool
# define FALSE 0
# define TRUE 1
# else
typedef enum {FALSE, TRUE} bool;
# endif
# endif
#endif
/*
* Type: string
* ------------
* The type string is identical to the type char *, which is
* traditionally used in C programs. The main point of defining a
* new type is to improve program readability. At the abstraction
* levels at which the type string is used, it is usually not
* important to take the string apart into its component characters.
* Declaring it as a string emphasizes this atomicity.
*/
typedef char *string;
/*
* Type: stream
* ------------
* Like string, the stream type is used to provide additional
* readability and is defined to be equivalent to FILE *
* (which is particularly confusing because it violates
* standard case conventions). This type is not used in
* the text but is preserved in genlib.h, so it is possible
* to teach all of CS1 without exposing any pointers.
*/
typedef FILE *stream;
/*
* Constant: UNDEFINED
* -------------------
* Besides NULL, the only other constant of pointer type is
* UNDEFINED, which is used in certain packages as a special
* sentinel to indicate an undefined pointer value. In many
* such contexts, NULL is a legitimate data value and is
* therefore inappropriate as a sentinel.
*/
#define UNDEFINED ((void *) undefined_object)
extern char undefined_object[];
/* Section 2 -- Memory allocation */
/*
* General notes:
* --------------
* These functions provide a common interface for memory
* allocation. All functions in the library that allocate
* memory do so using GetBlock and FreeBlock. Even though
* the ANSI standard defines malloc and free for the same
* purpose, using GetBlock and FreeBlock provides greater
* compatibility with non-ANSI implementations, automatic
* out-of-memory error detection, and the possibility of
* substituting a garbage-collecting allocator.
*/
/*
* Function: GetBlock
* Usage: ptr = (type) GetBlock(nbytes);
* -------------------------------------
* GetBlock allocates a block of memory of the given size. If
* no memory is available, GetBlock generates an error.
*/
void *GetBlock(size_t nbytes);
/*
* Function: FreeBlock
* Usage: FreeBlock(ptr);
* ----------------------
* FreeBlock frees the memory associated with ptr, which must
* have been allocated using GetBlock, New, or NewArray.
*/
void FreeBlock(void *ptr);
/*
* Macro: New
* Usage: p = New(pointer-type);
* -----------------------------
* The New pseudofunction allocates enough space to hold an
* object of the type to which pointer-type points and returns
* a pointer to the newly allocated pointer. Note that
* "New" is different from the "new" operator used in C++;
* the former takes a pointer type and the latter takes the
* target type.
*/
#define New(type) ((type) GetBlock(sizeof *((type) NULL)))
/*
* Macro: NewArray
* Usage: p = NewArray(n, element-type);
* -------------------------------------
* NewArray allocates enough space to hold an array of n
* values of the specified element type.
*/
#define NewArray(n, type) ((type *) GetBlock((n) * sizeof (type)))
/* Section 3 -- Basic error handling */
/*
* Function: Error
* Usage: Error(msg, ...)
* ----------------------
* Error generates an error string, expanding % constructions
* appearing in the error message string just as printf does.
* If an error handler exception has been introduced (see the
* "exception.h" facility), the ErrorException exception is
* raised with the expanded error string as argument. If
* there is no ErrorException defined, the program exits
* with a status code indicating failure (as given by the
* constant ErrorExitStatus). The length of the error
* message string following expansion must not exceed
* MaxErrorMessage, and it is the client's responsibility
* to ensure this.
*/
void Error(string msg, ...);
/* Section 4 -- The repeat pseudo-statement */
/*
* Statement form: repeat { ... }
* ------------------------------
* Some instructors who have taught CS1 using this library
* have found that using
*
* while (TRUE)
*
* to initiate a loop with an interior exit is confusing to
* students, particularly when it comes at the beginning of
* the course. This macro defines "repeat" as an infinite
* loop construct for instructors who find it easier to
* explain, although it is not used in the text. Similar
* macro definitions are common in industry.
*/
#define repeat for (;;)
#endif
/*
* File: graphics.h
* Version: 1.0
* Last modified on Mon Jun 6 11:03:27 1994 by eroberts
* -----------------------------------------------------
* This interface provides access to a simple library of
* functions that make it possible to draw lines and arcs
* on the screen. This interface presents a portable
* abstraction that can be used with a variety of window
* systems implemented on different hardware platforms.
*/
#ifndef _graphics_h
#define _graphics_h
/*
* Overview
* --------
* This library provides several functions for drawing lines
* and circular arcs in a region of the screen that is
* defined as the "graphics window." Once drawn, these
* lines and arcs stay in their position, which means that
* the package can only be used for static pictures and not
* for animation.
*
* Individual points within the window are specified by
* giving their x and y coordinates. These coordinates are
* real numbers measured in inches, with the origin in the
* lower left corner, as it is in traditional mathematics.
*
* The calls available in the package are listed below. More
* complete descriptions are included with each function
* description.
*
* InitGraphics();
* MovePen(x, y);
* DrawLine(dx, dy);
* DrawArc(r, start, sweep);
* width = GetWindowWidth();
* height = GetWindowHeight();
* x = GetCurrentX();
* y = GetCurrentY();
*/
/*
* Function: InitGraphics
* Usage: InitGraphics();
* ----------------------
* This procedure creates the graphics window on the screen.
* The call to InitGraphics must precede any calls to other
* functions in this package and must also precede any printf
* output. In most cases, the InitGraphics call is the first
* statement in the function main.
*/
void InitGraphics(void);
void InitConsole(void);
/*
* Function: MovePen
* Usage: MovePen(x, y);
* ---------------------
* This procedure moves the current point to the position
* (x, y), without drawing a line. The model is that of
* the pen being lifted off the graphics window surface and
* then moved to its new position.
*/
void MovePen(double x, double y);
/*
* Function: DrawLine
* Usage: DrawLine(dx, dy);
* ------------------------
* This procedure draws a line extending from the current
* point by moving the pen dx inches in the x direction
* and dy inches in the y direction. The final position
* becomes the new current point.
*/
void DrawLine(double dx, double dy);
/*
* Function: DrawArc
* Usage: DrawArc(r, start, sweep);
* --------------------------------
* This procedure draws a circular arc, which always begins
* at the current point. The arc itself has radius r, and
* starts at the angle specified by the parameter start,
* relative to the center of the circle. This angle is
* measured in degrees counterclockwise from the 3 o'clock
* position along the x-axis, as in traditional mathematics.
* For example, if start is 0, the arc begins at the 3 o'clock
* position; if start is 90, the arc begins at the 12 o'clock
* position; and so on. The fraction of the circle drawn is
* specified by the parameter sweep, which is also measured in
* degrees. If sweep is 360, DrawArc draws a complete circle;
* if sweep is 90, it draws a quarter of a circle. If the value
* of sweep is positive, the arc is drawn counterclockwise from
* the current point. If sweep is negative, the arc is drawn
* clockwise from the current point. The current point at the
* end of the DrawArc operation is the final position of the pen
* along the arc.
*
* Examples:
* DrawArc(r, 0, 360) Draws a circle to the left of the
* current point.
* DrawArc(r, 90, 180) Draws the left half of a semicircle
* starting from the 12 o'clock position.
* DrawArc(r, 0, 90) Draws a quarter circle from the 3
* o'clock to the 12 o'clock position.
* DrawArc(r, 0, -90) Draws a quarter circle from the 3
* o'clock to the 6 o'clock position.
* DrawArc(r, -90, -90) Draws a quarter circle from the 6
* o'clock to the 9 o'clock position.
*/
void DrawArc(double r, double start, double sweep);
/*
* Functions: GetWindowWidth, GetWindowHeight
* Usage: width = GetWindowWidth();
* height = GetWindowHeight();
* ------------------------------------------
* These functions return the width and height of the graphics
* window, in inches.
*/
double GetWindowWidth(void);
double GetWindowHeight(void);
/*
* Functions: GetCurrentX, GetCurrentY
* Usage: x = GetCurrentX();
* y = GetCurrentY();
* -----------------------------------
* These functions return the current x and y positions.
*/
double GetCurrentX(void);
double GetCurrentY(void);
void Main();
typedef enum
{
NO_BUTTON = 0,
LEFT_BUTTON,
MIDDLE_BUTTON,
RIGHT_BUTTON
} ACL_Mouse_Button;
typedef enum
{
BUTTON_DOWN,
BUTTON_DOUBLECLICK,
BUTTON_UP,
ROLL_UP,
ROLL_DOWN,
MOUSEMOVE
} ACL_Mouse_Event;
typedef enum
{
KEY_DOWN,
KEY_UP
} ACL_Keyboard_Event;
typedef void (*KeyboardEventCallback) (int key,int event);
typedef void (*CharEventCallback) (char c);
typedef void (*MouseEventCallback) (int x, int y, int button, int event);
typedef void (*TimerEventCallback) (int timerID);
void registerKeyboardEvent(KeyboardEventCallback callback);
void registerCharEvent(CharEventCallback callback);
void registerMouseEvent(MouseEventCallback callback);
void registerTimerEvent(TimerEventCallback callback);
void cancelKeyboardEvent();
void cancelCharEvent();
void cancelMouseEvent();
void cancelTimerEvent();
#endif
#ifndef _MAZE_H
#define _MAZE_H
#include "graphics.h"
#include "extgraph.h"
#include "genlib.h"
#include "simpio.h"
#include "conio.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
#include <windows.h>
#include <olectl.h>
#include <mmsystem.h>
#include <wingdi.h>
#include <ole2.h>
#include <ocidl.h>
#include <winuser.h>
#define ROUTE 1
#define WALL 0
static rank = 0;
static Height = 60, Width = 50;
void maze_generate(int x, int y, int **maze);
void maze_draw(int **maze);
void maze_init(int **maze);
void maze_end(int **maze);
#endif
/*
* File: random.h
* Version: 1.0
* Last modified on Fri Jul 22 16:44:36 1994 by eroberts
* -----------------------------------------------------
* This interface provides several functions for generating
* pseudo-random numbers.
*/
#ifndef _random_h
#define _random_h
#include "genlib.h"
#include <stdlib.h>
/*
* Constant: RAND_MAX
* ------------------
* Unfortunately, several libraries that supposedly conform to
* the ANSI standard do not define RAND_MAX in <stdlib.h>. To
* reduce portability problems, this interface defines RAND_MAX
* to be the largest positive integer if it is undefined.
*/
#ifndef RAND_MAX
# define RAND_MAX ((int) ((unsigned) ~0 >> 1))
#endif
/*
* Function: Randomize
* Usage: Randomize();
* -------------------
* This function sets the random seed so that the random sequence
* is unpredictable. During the debugging phase, it is best not
* to call this function, so that program behavior is repeatable.
*/
void Randomize(void);
/*
* Function: RandomInteger
* Usage: n = RandomInteger(low, high);
* ------------------------------------
* This function returns a random integer in the range low to high,
* inclusive.
*/
int RandomInteger(int low, int high);
/*
* Function: RandomReal
* Usage: d = RandomReal(low, high);
* ---------------------------------
* This function returns a random real number in the half-open
* interval [low .. high), meaning that the result is always
* greater than or equal to low but strictly less than high.
*/
double RandomReal(double low, double high);
/*
* Function: RandomChance
* Usage: if (RandomChance(p)) . . .
* ---------------------------------
* The RandomChance function returns TRUE with the probability
* indicated by p, which should be a floating-point number between
* 0 (meaning never) and 1 (meaning always). For example, calling
* RandomChance(.30) returns TRUE 30 percent of the time.
*/
bool RandomChance(double p);
#endif
/*
* File: simpio.h
* Version: 1.0
* Last modified on Wed Apr 27 07:29:13 1994 by eroberts
* -----------------------------------------------------
* This interface provides access to a simple package of
* functions that simplify the reading of input data.
*/
#ifndef _simpio_h
#define _simpio_h
#include "genlib.h"
/*
* Function: GetInteger
* Usage: i = GetInteger();
* ------------------------
* GetInteger reads a line of text from standard input and scans
* it as an integer. The integer value is returned. If an
* integer cannot be scanned or if more characters follow the
* number, the user is given a chance to retry.
*/
int GetInteger(void);
/*
* Function: GetLong
* Usage: l = GetLong();
* ---------------------
* GetLong reads a line of text from standard input and scans
* it as a long integer. The value is returned as a long.
* If an integer cannot be scanned or if more characters follow
* the number, the user is given a chance to retry.
*/
long GetLong(void);
/*
* Function: GetReal
* Usage: x = GetReal();
* ---------------------
* GetReal reads a line of text from standard input and scans
* it as a double. If the number cannot be scanned or if extra
* characters follow after the number ends, the user is given
* a chance to reenter the value.
*/
double GetReal(void);
/*
* Function: GetLine
* Usage: s = GetLine();
* ---------------------
* GetLine reads a line of text from standard input and returns
* the line as a string. The newline character that terminates
* the input is not stored as part of the string.
*/
string GetLine(void);
/*
* Function: ReadLine
* Usage: s = ReadLine(infile);
* ----------------------------
* ReadLine reads a line of text from the input file and
* returns the line as a string. The newline character
* that terminates the input is not stored as part of the
* string. The ReadLine function returns NULL if infile
* is at the end-of-file position.
*/
string ReadLine(FILE *infile);
#endif
/*
* File: strlib.h
* Version: 1.0
* Last modified on Fri Jul 15 14:10:40 1994 by eroberts
* -----------------------------------------------------
* The strlib.h file defines the interface for a simple
* string library. In the context of this package, strings
* are considered to be an abstract data type, which means
* that the client relies only on the operations defined for
* the type and not on the underlying representation.
*/
/*
* Cautionary note:
* ----------------
* Although this interface provides an extremely convenient
* abstraction for working with strings, it is not appropriate
* for all applications. In this interface, the functions that
* return string values (such as Concat and SubString) do so
* by allocating new memory. Over time, a program that uses
* this package will consume increasing amounts of memory
* and eventually exhaust the available supply. If you are
* writing a program that runs for a short time and stops,
* the fact that the package consumes memory is not a problem.
* If, however, you are writing an application that must run
* for an extended period of time, using this package requires
* that you make some provision for freeing any allocated
* storage.
*/
#ifndef _strlib_h
#define _strlib_h
#include "genlib.h"
/* Section 1 -- Basic string operations */
/*
* Function: Concat
* Usage: s = Concat(s1, s2);
* --------------------------
* This function concatenates two strings by joining them end
* to end. For example, Concat("ABC", "DE") returns the string
* "ABCDE".
*/
string Concat(string s1, string s2);
/*
* Function: IthChar
* Usage: ch = IthChar(s, i);
* --------------------------
* This function returns the character at position i in the
* string s. It is included in the library to make the type
* string a true abstract type in the sense that all of the
* necessary operations can be invoked using functions. Calling
* IthChar(s, i) is like selecting s[i], except that IthChar
* checks to see if i is within the range of legal index
* positions, which extend from 0 to StringLength(s).
* IthChar(s, StringLength(s)) returns the null character
* at the end of the string.
*/
char IthChar(string s, int i);
/*
* Function: SubString
* Usage: t = SubString(s, p1, p2);
* --------------------------------
* SubString returns a copy of the substring of s consisting
* of the characters between index positions p1 and p2,
* inclusive. The following special cases apply:
*
* 1. If p1 is less than 0, it is assumed to be 0.
* 2. If p2 is greater than the index of the last string
* position, which is StringLength(s) - 1, then p2 is
* set equal to StringLength(s) - 1.
* 3. If p2 < p1, SubString returns the empty string.
*/
string SubString(string s, int p1, int p2);
/*
* Function: CharToString
* Usage: s = CharToString(ch);
* ----------------------------
* This function takes a single character and returns a
* one-character string consisting of that character. The
* CharToString function is useful, for example, if you
* need to concatenate a string and a character. Since
* Concat requires two strings, you must first convert
* the character into a string.
*/
string CharToString(char ch);
/*
* Function: StringLength
* Usage: len = StringLength(s);
* -----------------------------
* This function returns the length of s.
*/
int StringLength(string s);
/*
* Function: CopyString
* Usage: newstr = CopyString(s);
* ------------------------------
* CopyString copies the string s into dynamically allocated
* storage and returns the new string. This function is not
* ordinarily required if this package is used on its own,
* but is often necessary when you are working with more than
* one string package.
*/
string CopyString(string s);
/* Section 2 -- String comparison functions */
/*
* Function: StringEqual
* Usage: if (StringEqual(s1, s2)) ...
* -----------------------------------
* This function returns TRUE if the strings s1 and s2 are
* equal. For the strings to be considered equal, every
* character in one string must precisely match the
* corresponding character in the other. Uppercase and
* lowercase characters are considered to be different.
*/
bool StringEqual(string s1, string s2);
/*
* Function: StringCompare
* Usage: if (StringCompare(s1, s2) < 0) ...
* -----------------------------------------
* This function returns a number less than 0 if string s1
* comes before s2 in alphabetical order, 0 if they are equal,
* and a number greater than 0 if s1 comes after s2. The
* ordering is determined by the internal representation used
* for characters, which is usually ASCII.
*/
int StringCompare(string s1, string s2);
/* Section 3 -- Search functions */
/*
* Function: FindChar
* Usage: p = FindChar(ch, text, start);
* -------------------------------------
* Beginning at position start in the string text, this
* function searches for the character ch and returns the
* first index at which it appears or -1 if no match is
* found.
*/
int FindChar(char ch, string text, int start);
/*
* Function: FindString
* Usage: p = FindString(str, text, start);
* ----------------------------------------
* Beginning at position start in the string text, this
* function searches for the string str and returns the
* first index at which it appears or -1 if no match is
* found.
*/
int FindString(string str, string text, int start);
/* Section 4 -- Case-conversion functions */
/*
* Function: ConvertToLowerCase
* Usage: s = ConvertToLowerCase(s);
* ---------------------------------
* This function returns a new string with all
* alphabetic characters converted to lower case.
*/
string ConvertToLowerCase(string s);
/*
* Function: ConvertToUpperCase
* Usage: s = ConvertToUpperCase(s);
* ---------------------------------
* This function returns a new string with all
* alphabetic characters converted to upper case.
*/
string ConvertToUpperCase(string s);
/* Section 5 -- Functions for converting numbers to strings */
/*
* Function: IntegerToString
* Usage: s = IntegerToString(n);
* ------------------------------
* This function converts an integer into the corresponding
* string of digits. For example, IntegerToString(123)
* returns "123" as a string.
*/
string IntegerToString(int n);
/*
* Function: StringToInteger
* Usage: n = StringToInteger(s);
* ------------------------------
* This function converts a string of digits into an integer.
* If the string is not a legal integer or contains extraneous
* characters, StringToInteger signals an error condition.
*/
int StringToInteger(string s);
/*
* Function: RealToString
* Usage: s = RealToString(d);
* ---------------------------
* This function converts a floating-point number into the
* corresponding string form. For example, calling
* RealToString(23.45) returns "23.45". The conversion is
* the same as that used for "%G" format in printf.
*/
string RealToString(double d);
/*
* Function: StringToReal
* Usage: d = StringToReal(s);
* ---------------------------
* This function converts a string representing a real number
* into its corresponding value. If the string is not a
* legal floating-point number or if it contains extraneous
* characters, StringToReal signals an error condition.
*/
double StringToReal(string s);
#endif
/*
* File: exception.c
* Version: 1.0
* Last modified on Sun Jul 24 10:28:11 1994 by eroberts
* -----------------------------------------------------
* This file implements the C exception handler. Much of the
* real work is done in the exception.h header file.
*/
#include <stdio.h>
#include <stdarg.h>
#include "genlib.h"
#include "gcalloc.h"
#include "exception.h"
/*
* Constant: MaxUnhandledMessage
* -----------------------------
* This constant should be large enough to accommodate the
* unhandled exception message, including the exception name.
*/
#define MaxUnhandledMessage 100
/* Publically accessible exceptions */
exception ANY = { "ANY" };
exception ErrorException = { "ErrorException" };
/*
* Global variable: exceptionStack
* -------------------------------
* This variable is the head pointer to a linked list of
* context blocks that act as the exception stack. The chain
* pointer is referenced by the macros in exception.h and must
* therefore be exported, but clients should not reference it
* directly.
*/
context_block *exceptionStack = NULL;
/* Private function prototypes */
static context_block *FindHandler(exception *e);
/* Public entries */
/*
* Function: RaiseException
* ------------------------
* This function operates by finding an appropriate handler
* and then using longjmp to return to the context stored
* there after resetting the exception stack. If no handler
* exists, the function notes an unhandled exception. Much
* of the complexity comes from the fact that allocation
* within the exception handler may fail.
*/
void RaiseException(exception *e, string name, void *value)
{
context_block *cb;
char errbuf[MaxUnhandledMessage + 1];
string errmsg;
int errlen;
cb = FindHandler(e);
if (cb == NULL) {
sprintf(errbuf, "Unhandled exception (%.30s)", name);
errlen = strlen(errbuf);
if (_acb == NULL) {
errmsg = malloc(errlen + 1);
} else {
errmsg = _acb->allocMethod(errlen + 1);
}
if (errmsg == NULL) {
errmsg = "Unhandled exception: unknown";
} else {
strcpy(errmsg, errbuf);
}
Error(errmsg);
}
exceptionStack = cb;
cb->id = e;
cb->value = value;
cb->name = name;
longjmp(cb->jmp, ES_Exception);
}
/*
* Function: HandlerExists
* -----------------------
* This public entry is used primarily by the Error function
* to determine if ErrorException has been trapped, although
* it is available to other clients as well.
*/
bool HandlerExists(exception *e)
{
return (FindHandler(e) != NULL);
}
/* Private functions */
/*
* Function: FindHandler
* ---------------------
* This function searches the exception stack to find the
* first active handler for the indicated exception. If a
* match is found, the context block pointer is returned.
* If not, FindHandler returns NULL.
*/
static context_block *FindHandler(exception *e)
{
context_block *cb;
exception *t;
int i;
for (cb = exceptionStack; cb != NULL; cb = cb->link) {
for (i = 0; i < cb->nx; i++) {
t = cb->array[i];
if (t == e || t == &ANY) return (cb);
}
}
return (NULL);
}
/*
* File: genlib.c
* Version: 1.0
* Last modified on Sun Jul 24 10:29:46 1994 by eroberts
* -----------------------------------------------------
* This file implements the general C library package. See the
* interface description in genlib.h for details.
*/
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <stdarg.h>
#include "genlib.h"
#include "gcalloc.h"
#include "exception.h"
/*
* Constants:
* ----------
* ErrorExitStatus -- Status value used in exit call
* MaxErrorMessage -- Longest error message allowed
*/
#define ErrorExitStatus 1
#define MaxErrorMessage 500
/* Section 1 -- Define new "primitive" types */
/*
* Constant: UNDEFINED
* -------------------
* This entry defines the target of the UNDEFINED constant.
*/
char undefined_object[] = "UNDEFINED";
/* Section 2 -- Memory allocation */
/*
* Implementation notes:
* ---------------------
* The code for the memory allocator is divided between
* genlib.c and gcalloc.c, and the division strategy may at
* first seem unnatural, since the function ProtectBlock is
* declared in gcalloc.h but defined here in genlib.c. The
* intention is to minimize the size of object files
* produced by linkers that search a library for modules
* that are actually referenced. The libraries themselves
* need to call ProtectBlock (usually through the macro
* ProtectVariable), but will not require the actual code
* for the allocator unless InitGCAllocator is explicitly
* called.
*/
/*
* Global variable: _acb
* ---------------------
* This variable is used to hold a method suite that makes it
* easy to substitute a garbage-collecting allocator for the
* ANSI allocator.
*/
_GCControlBlock _acb = NULL;
/* Memory allocation implementation */
void *GetBlock(size_t nbytes)
{
void *result;
if (_acb == NULL) {
result = malloc(nbytes);
} else {
result = _acb->allocMethod(nbytes);
}
if (result == NULL) Error("No memory available");
return (result);
}
void FreeBlock(void *ptr)
{
if (_acb == NULL) {
free(ptr);
} else {
_acb->freeMethod(ptr);
}
}
void ProtectBlock(void *ptr, size_t nbytes)
{
if (_acb != NULL) _acb->protectMethod(ptr, nbytes);
}
/* Section 3 -- Basic error handling */
/*
* Implementation notes: Error
* ---------------------------
* Writing the Error function requires some care, since it is
* called in circumstances in which parts of the system may be
* broken. In particular, it is not acceptable for Error to
* call GetBlock, since the error condition may be that the
* system is out of memory, in which case calling GetBlock would
* fail. The error string should be allocated dynamically,
* so that this function can be used in reentrant code.
* Note that it is critical to exit if the length bound for
* an error message is exceeded, since this error almost
* certainly corrupts the stack.
*/
void Error(string msg, ...)
{
va_list args;
char errbuf[MaxErrorMessage + 1];
string errmsg;
int errlen;
va_start(args, msg);
vsprintf(errbuf, msg, args);
va_end(args);
errlen = strlen(errbuf);
if (errlen > MaxErrorMessage) {
fprintf(stderr, "Error: Error Message too long\n");
exit(ErrorExitStatus);
}
if (_acb == NULL) {
errmsg = malloc(errlen + 1);
} else {
errmsg = _acb->allocMethod(errlen + 1);
}
if (errmsg == NULL) {
errmsg = "No memory available";
} else {
strcpy(errmsg, errbuf);
}
if (HandlerExists(&ErrorException)) {
RaiseException(&ErrorException, "ErrorException", errmsg);
} else {
fprintf(stderr, "Error: %s\n", errmsg);
exit(ErrorExitStatus);
}
}
/*
* File: graphics.c
* Version: 3.1
* Last modified on Thu Feb 23 13:39:32 1995 by eroberts
* -----------------------------------------------------
* This file implements the graphics.h and extgraph.h interfaces
* for the Borland/Windows platform.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <conio.h>
#include <windows.h>
#include <time.h>
#include <wincon.h>
#include <Windows.h>
#include "genlib.h"
#include "gcalloc.h"
#include "strlib.h"
#include "extgraph.h"
/*
* Parameters
* ----------
* DesiredWidth -- Desired width of the graphics window
* DesiredHeight -- Desired height of the graphics window
* DefaultSize -- Default point size
* MaxTitle -- Maximum window title length
* MaxFontName -- Maximum font name length
* MaxFonts -- Maximum number of fonts
* LeftMargin -- Margin from left of screen to both windows
* RightMargin -- Minimum margin to right of windows
* TopMargin -- Margin from top of screen to graphics window
* BottomMargin -- Minimum margin from bottom of screen to console window
* WindowSep -- Separation between graphics and console windows
* ConsoleHeight -- Height of the console window (pixels)
* MinConsoleScale -- Smallest acceptable scale factor for the console
* PStartSize -- Starting size for polygon (must be greater than 1)
* MaxColors -- Maximum number of color names allowed
* MinColors -- Minimum number of colors the device must support
* GWClassName -- Class name of the graphics window
* DefaultFont -- Font that serves as the "Default" font
*/
#define DesiredWidth 10.0
#define DesiredHeight 7.0
#define DefaultSize 12
#define MaxTitle 75
#define MaxFontName 50
#define MaxFonts 100
#define LeftMargin 0/*10*/
#define RightMargin 25
#define TopMargin 0
#define BottomMargin 30
#define WindowSep 5
#define ConsoleHeight 110
#define MinConsoleScale 0.8
#define PStartSize 50
#define MaxColors 256
#define MinColors 16
#define GWClassName "Graphics Window"
#define DefaultFont "System"
/*
* Other constants
* ---------------
* LargeInt -- Integer too large for a coordinate value
* Epsilon -- Small arithmetic offset to reduce aliasing/banding
* Pi -- Mathematical constant pi
* AnyButton -- Union of all mouse buttons
*/
#define LargeInt 16000
#define Epsilon 0.00000000001
#define Pi 3.1415926535
#define AnyButton (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON)
KeyboardEventCallback g_keyboard = NULL;
MouseEventCallback g_mouse = NULL;
TimerEventCallback g_timer = NULL;
CharEventCallback g_char = NULL;
/*
* Type: graphicsStateT
* --------------------
* This structure holds the variables that make up the graphics state.
*/
typedef struct graphicsStateT {
double cx, cy;
string font;
int size;
int style;
bool erase;
int color;
struct graphicsStateT *link;
} *graphicsStateT;
/*
* Type: fontEntryT
* ----------------
* This structure holds the data for a font.
*/
typedef struct {
string name;
int size, style;
int points, ascent, descent, height;
HFONT font;
} fontEntryT;
/*
* Type: regionStateT
* ------------------
* The region assembly process has the character of a finite state
* machine with the following four states:
*
* NoRegion Region has not yet been started
* RegionStarting Region is started but no line segments yet
* RegionActive First line segment appears
* PenHasMoved Pen has moved during definition
*
* The current state determines whether other operations are legal
* at that point.
*/
typedef enum {
NoRegion, RegionStarting, RegionActive, PenHasMoved
} regionStateT;
/*
* Type: colorEntryT
* -----------------
* This type is used for the entries in the color table.
*/
typedef struct {
string name;
double red, green, blue;
} colorEntryT;
/*
* Static table: fillList
* ----------------------
* This table contains the bitmap patterns for the various density
* values. Adding more patterns to this list increases the
* precision with which the client can control fill patterns.
* Note that this bitmap is inverted from that used on most
* systems, with 0 indicating foreground and 1 indicating background.
*/
static short fillList[][8] = {
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
{ 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD },
{ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA },
{ 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
};
#define NFills (sizeof fillList / sizeof fillList[0])
/*
* Global variables
* ----------------
* initialized -- TRUE if initialization has been done
* pauseOnExit -- TRUE if library should pause when exiting
* consoleWindow -- Window handle for console window
* graphicsWindow -- Window handoe for graphics window
* gdc -- Graphics DC (screen)
* osdc -- Offscreen DC (memory backup)
* osbits -- Offscreen bitmap
* drawPen -- Pen used for drawing
* erasePen -- Pen used for erasing
* nullPen -- Pen used for filling
* drawColor -- Color used for drawing
* eraseColor -- Color used for erasing
* windowTitle -- Current window title (initialized statically)
* xResolution -- Horizontal resolution of screen (dots per inch)
* yResolution -- Vertical resolution of screen (dots per inch)
* windowWidth -- Width of graphics window (inches)
* windowHeight -- Height of graphics window (inches)
* pixelWidth -- Width of graphics window (pixels)
* pixelHeight -- Height of graphics window (pixels)
* fontTable -- Table of stored fonts
* nFonts -- Number of fonts in fontTable
* currentFont -- Index of current font in fontTable
* regionState -- Current state of the region
* regionDensity -- Fill density to apply to region
* polygonPoints -- Array of points used in current region
* nPolygonPoints -- Number of active points
* polygonSize -- Number of allocated points
* polygonBounds -- Bounding box of polygon
* colorTable -- Table of defined colors
* nColors -- Number of defined colors
* previousColor -- Last color index set
* stateStack -- Stack of graphicStateT blocks
* cx, cy -- Current coordinates | These
* eraseMode -- Setting of erase flag | variables
* textFont -- Current font | consititute
* textStyle -- Current style | the current
* pointSize -- Current point size | graphics
* penColor -- Color of pen | state
*/
static int penSize = 1;
static bool initialized = FALSE;
static bool pauseOnExit = TRUE;
static HWND consoleWindow, graphicsWindow;
static HDC gdc, osdc;
static HBITMAP osBits;
static HPEN drawPen, erasePen, nullPen;
static COLORREF drawColor, eraseColor;
static PAINTSTRUCT ps;
static string windowTitle = "Graphics Window";
static double xResolution, yResolution;
static double windowWidth = DesiredWidth;
static double windowHeight = DesiredHeight;
static int pixelWidth, pixelHeight;
static fontEntryT fontTable[MaxFonts];
static int nFonts;
static int currentFont;
static regionStateT regionState;
static double regionDensity;
static POINT *polygonPoints;
static int nPolygonPoints;
static int polygonSize;
static RECT polygonBounds;
static HBITMAP fillBitmaps[NFills];
static colorEntryT colorTable[MaxColors];
static int nColors;
static int previousColor;
static graphicsStateT stateStack;
static double cx, cy;
static bool eraseMode;
static string textFont;
static int textStyle;
static int pointSize;
static int penColor;
static int mouseX, mouseY;
static bool mouseButton = FALSE;
/* Private function prototypes */
static void InitCheck(void);
static void InitGraphicsState(void);
static void InitDisplay(void);
static void InitDrawingTools(void);
static void DisplayExit(void);
static HWND FindConsoleWindow(void);
static BOOL CALLBACK EnumerateProc(HWND window, LPARAM clientData);
static void RegisterWindowClass(void);
static LONG FAR PASCAL GraphicsEventProc(HWND w, UINT msg,
WPARAM p1, LPARAM p2);
static void CheckEvents(void);
static void DoUpdate(void);
static void DisplayClear(void);
static void PrepareToDraw(void);
static void DisplayLine(double x, double y, double dx, double dy);
static void DisplayArc(double xc, double yc, double rx, double ry,
double start, double sweep);
static void RenderArc(double x, double y, double rx, double ry,
double start, double sweep);
static void DisplayText(double x, double y, string text);
static void DisplayFont(string font, int size, int style);
static int FindExistingFont(string name, int size, int style);
static void SetLineBB(RECT *rp, double x, double y, double dx, double dy);
static void SetArcBB(RECT *rp, double xc, double yc,
double rx, double ry, double start, double sweep);
static void SetTextBB(RECT *rp, double x, double y, string text);
static void StartPolygon(void);
static void AddSegment(int x0, int y0, int x1, int y1);
static void DisplayPolygon(void);
static void AddPolygonPoint(int x, int y);
static void InitColors(void);
static int FindColorName(string name);
static bool StringMatch(string s1, string s2);
static bool PrefixMatch(string prefix, string str);
static int RectWidth(RECT *rp);
static int RectHeight(RECT *rp);
static void SetRectFromSize(RECT *rp, int x, int y, int width, int height);
static double Radians(double degrees);
static int Round(double x);
static double InchesX(int x);
static double InchesY(int y);
static int PixelsX(double x);
static int PixelsY(double y);
static int ScaleX(double x);
static int ScaleY(double y);
static int Min(int x, int y);
static int Max(int x, int y);
/* Exported entries */
/* Section 1 -- Basic functions from graphics.h */
void InitGraphics(void)
{
if (!initialized) {
initialized = TRUE;
ProtectVariable(stateStack);
ProtectVariable(windowTitle);
ProtectVariable(textFont);
InitColors();
InitDisplay();
}
DisplayClear();
InitGraphicsState();
}
void MovePen(double x, double y)
{
InitCheck();
if (regionState == RegionActive) regionState = PenHasMoved;
cx = x;
cy = y;
}
void DrawLine(double dx, double dy)
{
InitCheck();
switch (regionState) {
case NoRegion:
DisplayLine(cx, cy, dx, dy);
break;
case RegionStarting: case RegionActive:
DisplayLine(cx, cy, dx, dy);
regionState = RegionActive;
break;
case PenHasMoved:
Error("Region segments must be contiguous");
}
cx += dx;
cy += dy;
}
void DrawArc(double r, double start, double sweep)
{
DrawEllipticalArc(r, r, start, sweep);
}
double GetWindowWidth(void)
{
InitCheck();
return (windowWidth);
}
double GetWindowHeight(void)
{
InitCheck();
return (windowHeight);
}
double GetCurrentX(void)
{
InitCheck();
return (cx);
}
double GetCurrentY(void)
{
InitCheck();
return (cy);
}
/* Section 2 -- Elliptical arcs */
void DrawEllipticalArc(double rx, double ry,
double start, double sweep)
{
double x, y;
InitCheck();
x = cx + rx * cos(Radians(start + 180));
y = cy + ry * sin(Radians(start + 180));
switch (regionState) {
case NoRegion:
DisplayArc(x, y, rx, ry, start, sweep);
break;
case RegionStarting: case RegionActive:
RenderArc(x, y, rx, ry, start, sweep);
regionState = RegionActive;
break;
case PenHasMoved:
Error("Region segments must be contiguous");
}
cx = x + rx * cos(Radians(start + sweep));
cy = y + ry * sin(Radians(start + sweep));
}
/* Section 3 -- Graphical structures */
void StartFilledRegion(double grayScale)
{
InitCheck();
if (regionState != NoRegion) {
Error("Region is already in progress");
}
if (grayScale < 0 || grayScale > 1) {
Error("Gray scale for regions must be between 0 and 1");
}
regionState = RegionStarting;
regionDensity = grayScale;
StartPolygon();
}
void EndFilledRegion(void)
{
InitCheck();
if (regionState == NoRegion) {
Error("EndFilledRegion without StartFilledRegion");
}
DisplayPolygon();
regionState = NoRegion;
}
/* Section 4 -- String functions */
void DrawTextString(string text)
{
InitCheck();
if (regionState != NoRegion) {
Error("Text strings are illegal inside a region");
}
DisplayText(cx, cy, text);
cx += TextStringWidth(text);
}
double TextStringWidth(string text)
{
RECT r;
InitCheck();
SetTextBB(&r, cx, cy, text);
return (InchesX(RectWidth(&r)));
}
void SetFont(string font)
{
InitCheck();
DisplayFont(font, pointSize, textStyle);
}
string GetFont(void)
{
InitCheck();
return (CopyString(textFont));
}
void SetPointSize(int size)
{
InitCheck();
DisplayFont(textFont, size, textStyle);
}
int GetPointSize(void)
{
InitCheck();
return (pointSize);
}
void SetStyle(int style)
{
InitCheck();
DisplayFont(textFont, pointSize, style);
}
int GetStyle(void)
{
InitCheck();
return (textStyle);
}
double GetFontAscent(void)
{
InitCheck();
return (InchesY(fontTable[currentFont].ascent));
}
double GetFontDescent(void)
{
InitCheck();
return (InchesY(fontTable[currentFont].descent));
}
double GetFontHeight(void)
{
InitCheck();
return (InchesY(fontTable[currentFont].height));
}
/* Section 5 -- Mouse support */
double GetMouseX(void)
{
InitCheck();
CheckEvents();
return (InchesX(mouseX));
}
double GetMouseY(void)
{
InitCheck();
CheckEvents();
return (windowHeight - InchesY(mouseY));
}
bool MouseButtonIsDown(void)
{
InitCheck();
CheckEvents();
return (mouseButton);
}
void WaitForMouseDown(void)
{
MSG msg;
UpdateDisplay();
while (!mouseButton) {
if (GetMessage(&msg, graphicsWindow, 0, 0) == 0) exit(0);
DispatchMessage(&msg);
}
}
void WaitForMouseUp(void)
{
MSG msg;
UpdateDisplay();
while (mouseButton) {
if (GetMessage(&msg, graphicsWindow, 0, 0) == 0) exit(0);
DispatchMessage(&msg);
}
}
/* Section 6 -- Color support */
bool HasColor(void)
{
InitCheck();
return (GetDeviceCaps(gdc, NUMCOLORS) >= MinColors);
}
void SetPenColor(string color)
{
int cindex;
InitCheck();
cindex = FindColorName(color);
if (cindex == -1) Error("Undefined color: %s", color);
penColor = cindex;
}
string GetPenColor(void)
{
InitCheck();
return (CopyString(colorTable[penColor].name));
}
void DefineColor(string name,
double red, double green, double blue)
{
int cindex;
InitCheck();
if (red < 0 || red > 1 || green < 0 || green > 1 || blue < 0 || blue > 1) {
Error("DefineColor: All color intensities must be between 0 and 1");
}
cindex = FindColorName(name);
if (cindex == -1) {
if (nColors == MaxColors) Error("DefineColor: Too many colors");
cindex = nColors++;
}
colorTable[cindex].name = CopyString(name);
colorTable[cindex].red = red;
colorTable[cindex].green = green;
colorTable[cindex].blue = blue;
}
/* Section 7 -- Miscellaneous functions */
void SetPenSize(int size)
{
penSize = size;
}
int GetPenSize(void)
{
return penSize;
}
void SetEraseMode(bool mode)
{
InitCheck();
eraseMode = mode;
}
bool GetEraseMode(void)
{
InitCheck();
return (eraseMode);
}
void SetWindowTitle(string title)
{
windowTitle = CopyString(title);
if (initialized) {
SetWindowText(graphicsWindow, windowTitle);
}
}
string GetWindowTitle(void)
{
return (CopyString(windowTitle));
}
void UpdateDisplay(void)
{
InitCheck();
CheckEvents();
DoUpdate();
}
void Pause(double seconds)
{
double finish;
UpdateDisplay();
finish = (double) clock() / CLK_TCK + seconds;
while (((double) clock() / CLK_TCK) < finish);
}
void ExitGraphics(void)
{
pauseOnExit = FALSE;
exit(0);
}
void SaveGraphicsState(void)
{
graphicsStateT sb;
InitCheck();
sb = New(graphicsStateT);
sb->cx = cx;
sb->cy = cy;
sb->font = textFont;
sb->size = pointSize;
sb->style = textStyle;
sb->erase = eraseMode;
sb->color = penColor;
sb->link = stateStack;
stateStack = sb;
}
void RestoreGraphicsState(void)
{
graphicsStateT sb;
InitCheck();
if (stateStack == NULL) {
Error("RestoreGraphicsState called before SaveGraphicsState");
}
sb = stateStack;
cx = sb->cx;
cy = sb->cy;
textFont = sb->font;
pointSize = sb->size;
textStyle = sb->style;
eraseMode = sb->erase;
penColor = sb->color;
DisplayFont(textFont, pointSize, textStyle);
stateStack = sb->link;
FreeBlock(sb);
}
double GetFullScreenWidth(void)
{
HWND desktop;
RECT bounds;
desktop = GetDesktopWindow();
GetWindowRect(desktop, &bounds);
return ((double) RectWidth(&bounds) / GetXResolution());
}
double GetFullScreenHeight(void)
{
HWND desktop;
RECT bounds;
desktop = GetDesktopWindow();
GetWindowRect(desktop, &bounds);
return ((double) RectHeight(&bounds) / GetYResolution());
}
void SetWindowSize(double width, double height)
{
if (initialized) return;
windowWidth = width;
windowHeight = height;
}
double GetXResolution(void)
{
HWND desktop;
HDC dc;
int xdpi;
if (initialized) return (xResolution);
desktop = GetDesktopWindow();
dc = GetDC(desktop);
xdpi = GetDeviceCaps(dc, LOGPIXELSX);
ReleaseDC(desktop, dc);
return (xdpi);
}
double GetYResolution(void)
{
HWND desktop;
HDC dc;
int ydpi;
if (initialized) return (yResolution);
desktop = GetDesktopWindow();
dc = GetDC(desktop);
ydpi = GetDeviceCaps(dc, LOGPIXELSY);
ReleaseDC(desktop, dc);
return (ydpi);
}
/* Private functions */
/*
* Function: InitCheck
* Usage: InitCheck();
* -------------------
* This function merely ensures that the package has been
* initialized before the client functions are called.
*/
static void InitCheck(void)
{
if (!initialized) Error("InitGraphics has not been called");
}
/*
* Function: InitGraphicsState
* Usage: InitGraphicsState();
* ---------------------------
* This function initializes the graphics state elements to
* their default values. Because the erase mode and font
* information are also maintained in the display state,
* InitGraphicsState must call functions to ensure that these
* values are initialized there as well.
*/
static void InitGraphicsState(void)
{
cx = cy = 0;
eraseMode = FALSE;
textFont = "Default";
pointSize = DefaultSize;
textStyle = Normal;
stateStack = NULL;
regionState = NoRegion;
DisplayFont(textFont, pointSize, textStyle);
}
void InitConsole(void)
{
AllocConsole();
freopen("CONIN$", "r+t", stdin);
freopen("CONOUT$", "w+t", stdout);
}
void repaint()
{
InvalidateRect(graphicsWindow, NULL, 1);
UpdateWindow(graphicsWindow);
}
/*
* Function: InitDisplay
* Usage: InitDisplay();
* ---------------------
* This function does everything necessary to initialize the display.
* In this implementation, the graphics window is created as an
* overlapping child of the console window, which has been created
* by EasyWin. As a child of the console, the window automatically
* gets events whenever the console window is waiting for events,
* simplifying the logic of the implementation considerably. Most
* of the InitDisplay implementation is concerned with calculating
* the new tiling geometry, after which the function creates the
* new window and an offscreen bitmap to use as a target for any
* rendering. When the window gets a Paint event in the event
* procedure GraphicsEventProc, all it has to do is copy the
* bits from the offscreen bitmap onto the screen.
*/
static void InitDisplay(void)
{
RECT bounds, consoleRect, graphicsRect;
double screenHeight, screenWidth, xSpace, ySpace;
double xScale, yScale, scaleFactor;
DWORD style;
int top, dx, dy, cWidth;
/*clrscr();*/
system("cls");
atexit(DisplayExit);
/* RegisterWindowClass();*/
consoleWindow = FindConsoleWindow();
initialized = FALSE;
xResolution = GetXResolution();
yResolution = GetYResolution();
initialized = TRUE;
screenWidth = GetFullScreenWidth();
screenHeight = GetFullScreenHeight();
xSpace = screenWidth - InchesX(LeftMargin + RightMargin);
ySpace = screenHeight - InchesX(TopMargin + BottomMargin) - InchesX(ConsoleHeight + WindowSep);
xScale = yScale = 1.0;
if (windowWidth > xSpace) xScale = xSpace / windowWidth;
if (windowHeight > ySpace) yScale = ySpace / windowHeight;
scaleFactor = (xScale < yScale) ? xScale : yScale;
if (scaleFactor > MinConsoleScale) {
cWidth = PixelsX(DesiredWidth * scaleFactor);
} else {
cWidth = PixelsX(DesiredWidth * MinConsoleScale);
}
xResolution *= scaleFactor;
yResolution *= scaleFactor;
SetRectFromSize(&graphicsRect, LeftMargin, TopMargin,
PixelsX(windowWidth), PixelsY(windowHeight));
style = WS_OVERLAPPEDWINDOW & ~(WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
g_keyboard = NULL;
g_mouse = NULL;
g_timer = NULL;
WNDCLASS wndcls;
wndcls.cbClsExtra = 0;
wndcls.cbWndExtra = 0;
wndcls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndcls.hCursor = LoadCursor(NULL, IDC_ARROW);
wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndcls.hInstance = NULL;
wndcls.lpfnWndProc = GraphicsEventProc;
wndcls.lpszClassName = "Graphics Window";
wndcls.lpszMenuName = NULL;
wndcls.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wndcls);
graphicsWindow = CreateWindow(
GWClassName,
windowTitle,
style,
graphicsRect.left,
graphicsRect.top,
RectWidth(&graphicsRect),
RectHeight(&graphicsRect),
/*consoleWindow*/ NULL,
(HMENU) NULL,
(HINSTANCE) NULL,
(LPSTR) NULL);
if (graphicsWindow == NULL) {
printf("InitGraphics: CreateGraphicsWindow failed.\n");
}
GetClientRect(graphicsWindow, &bounds);
dx = RectWidth(&graphicsRect) - RectWidth(&bounds);
dy = RectHeight(&graphicsRect) - RectHeight(&bounds);
SetWindowPos(graphicsWindow, HWND_TOP,
graphicsRect.left, graphicsRect.top,
RectWidth(&graphicsRect) + dx,
RectHeight(&graphicsRect) + dy, 0);
gdc = GetDC(graphicsWindow);
GetClientRect(graphicsWindow, &bounds);
pixelWidth = RectWidth(&bounds);
pixelHeight = RectHeight(&bounds);
ShowWindow(graphicsWindow, SW_SHOWNORMAL);
UpdateWindow(graphicsWindow);
osdc = CreateCompatibleDC(gdc);
if (osdc == NULL) {
Error("Internal error: Can't create offscreen device");
}
osBits = CreateCompatibleBitmap(gdc, pixelWidth, pixelHeight);
if (osBits == NULL) {
Error("Internal error: Can't create offscreen bitmap");
}
(void) SelectObject(osdc, osBits);
top = TopMargin + WindowSep + PixelsY(windowHeight) + dy;
/*
SetRectFromSize(&consoleRect, LeftMargin, top,
cWidth + dx, ConsoleHeight);
SetWindowText(consoleWindow, "Console Window");
SetWindowPos(consoleWindow, HWND_TOP,
consoleRect.left, consoleRect.top,
RectWidth(&consoleRect), RectHeight(&consoleRect), 0);
*/
InitDrawingTools();
}
/*
* Function: InitDrawingTools
* Usage: InitDrawingTools();
* --------------------------
* This function initializes all of the standard objects used for
* drawing except for fonts, which are initialized dynamically by
* the DisplayFont procedure. This function creates the
* foreground/background colors, the drawing pens, and the brushes
* for filled regions.
*/
static void InitDrawingTools(void)
{
int i;
nFonts = 0;
previousColor = 0;
drawColor = RGB(0, 0, 0);
eraseColor = RGB(255, 255, 255);
drawPen = (HPEN) CreatePen(PS_SOLID, penSize, drawColor);
erasePen = (HPEN) CreatePen(PS_SOLID, penSize, eraseColor);
nullPen = (HPEN) GetStockObject(NULL_PEN);
if (drawPen == NULL || erasePen == NULL || nullPen == NULL) {
Error("Internal error: Can't initialize pens");
}
for (i = 0; i < NFills; i++) {
fillBitmaps[i] = CreateBitmap(8, 8, 1, 1, fillList[i]);
}
SelectObject(osdc, drawPen);
}
/*
* Function: DisplayExit
* Usage: DisplayExit();
* ---------------------
* This function is called when the program exits and waits for the
* user to type a carriage return. After reading and ignoring the
* return key, this function frees the window system handles and
* destroys the console window, thereby exiting the program.
*/
static void DisplayExit(void)
{
int i;
if (pauseOnExit) (void) getchar();
DeleteDC(osdc);
DeleteDC(gdc);
DestroyWindow(consoleWindow);
DestroyWindow(graphicsWindow);
DeleteObject(drawPen);
DeleteObject(erasePen);
DeleteObject(nullPen);
for (i = 0; i < nFonts; i++) {
DeleteObject(fontTable[i].font);
}
for (i = 0; i < NFills; i++) {
DeleteObject(fillBitmaps[i]);
}
}
/*
* Function: FindConsoleWindow
* Usage: window = FindConsoleWindow();
* ------------------------------------
* The EasyWin package makes almost everything about the graphics
* package easy in the Borland world. The only thing that is hard
* is getting the handle of the window used for the console in the
* first place. This function finds the console window handle by
* enumerating the windows and looking for the first one whose
* title ends with .EXE, which the EasyWin package puts there.
*/
static HWND FindConsoleWindow(void)
{
HWND result;
EnumWindows(EnumerateProc, (LPARAM) &result);
return (result);
}
/*
* Function: EnumerateProc
* Usage: Not called directly
* --------------------------
* This callback procedure is used by the FindConsoleWindow
* call to find the window whose title ends with .EXE.
*/
static BOOL CALLBACK EnumerateProc(HWND window, LPARAM clientData)
{
HWND *wptr;
char title[MaxTitle];
bool ok;
wptr = (HWND *) clientData;
ok = GetWindowText(window, title, MaxTitle-1);
if (ok && strcmp(title + strlen(title) - 4, ".EXE")==0) {
*wptr = window;
return (0);
}
return (1);
}
/*
* Function: RegisterWindowClass
* Usage: RegisterWindowClass();
* -----------------------------
* This function registers the window class used for the graphics
* window.
*/
static void RegisterWindowClass(void)
{
WNDCLASS wcApp;
wcApp.lpszClassName = GWClassName;
wcApp.hInstance = NULL;
wcApp.lpfnWndProc = GraphicsEventProc;
wcApp.hCursor = NULL;
wcApp.hIcon = NULL;
wcApp.lpszMenuName = NULL;
wcApp.hbrBackground = GetStockObject(WHITE_BRUSH);
wcApp.style = CS_HREDRAW | CS_VREDRAW;
wcApp.cbClsExtra = wcApp.cbWndExtra = 0;
if (!RegisterClass(&wcApp)) {
Error("Internal error: RegisterClass failed\n");
}
}
/*
* Function: GraphicsEventProc
* Usage: Not called directly
* --------------------------
* This function is called when an event is received for the
* graphics window. The only event this package needs to handle
* is the paint event, which forces a screen update.
*/
static LONG FAR PASCAL GraphicsEventProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_PAINT:
DoUpdate();
return 0;
case WM_CHAR:
if (g_char != NULL)
g_char((char) wParam);
return 0;
case WM_KEYDOWN:
if (g_keyboard != NULL)
g_keyboard((int) wParam,KEY_DOWN);
return 0;
case WM_KEYUP:
if(g_keyboard != NULL)
g_keyboard((int) wParam,KEY_UP);
return 0;
case WM_LBUTTONDOWN:
if (g_mouse != NULL)
g_mouse((int) LOWORD(lParam), (int) HIWORD(lParam), LEFT_BUTTON, BUTTON_DOWN);
return 0;
case WM_LBUTTONUP:
if (g_mouse != NULL)
g_mouse((int) LOWORD(lParam), (int) HIWORD(lParam), LEFT_BUTTON, BUTTON_UP);
return 0;
case WM_LBUTTONDBLCLK:
if (g_mouse != NULL)
g_mouse((int) LOWORD(lParam), (int) HIWORD(lParam), LEFT_BUTTON, BUTTON_DOUBLECLICK);
return 0;
case WM_MBUTTONDOWN:
if (g_mouse != NULL)
g_mouse((int) LOWORD(lParam), (int) HIWORD(lParam), MIDDLE_BUTTON, BUTTON_DOWN);
return 0;
case WM_MBUTTONUP:
if (g_mouse != NULL)
g_mouse((int) LOWORD(lParam), (int) HIWORD(lParam), MIDDLE_BUTTON, BUTTON_UP);
return 0;
case WM_MBUTTONDBLCLK:
if (g_mouse != NULL)
g_mouse((int) LOWORD(lParam), (int) HIWORD(lParam), MIDDLE_BUTTON, BUTTON_DOUBLECLICK);
return 0;
case WM_RBUTTONDOWN:
if (g_mouse != NULL)
g_mouse((int) LOWORD(lParam), (int) HIWORD(lParam), RIGHT_BUTTON, BUTTON_DOWN);
return 0;
case WM_RBUTTONUP:
if (g_mouse != NULL)
g_mouse((int) LOWORD(lParam), (int) HIWORD(lParam), RIGHT_BUTTON, BUTTON_UP);
return 0;
case WM_RBUTTONDBLCLK:
if (g_mouse != NULL)
g_mouse((int) LOWORD(lParam), (int) HIWORD(lParam), RIGHT_BUTTON, BUTTON_DOUBLECLICK);
return 0;
case WM_MOUSEMOVE:
if(g_mouse != NULL)
g_mouse((int) LOWORD(lParam), (int) HIWORD(lParam), MOUSEMOVE, MOUSEMOVE);
return 0;
case WM_MOUSEWHEEL:
if(g_mouse == NULL)
return 0;
if(HIWORD(wParam) == 120)
g_mouse((int) LOWORD(lParam), (int) HIWORD(lParam),MIDDLE_BUTTON,ROLL_UP);
else if(HIWORD(wParam)==65416)
g_mouse((int) LOWORD(lParam), (int) HIWORD(lParam),MIDDLE_BUTTON,ROLL_DOWN);
return 0;
case WM_TIMER:
if (g_timer != NULL)
g_timer(wParam);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
/*
if (msg == WM_PAINT) {
DoUpdate();
return (0L);
}
if (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) {
mouseX = LOWORD(lParam);
mouseY = HIWORD(lParam);
mouseButton = (wParam & AnyButton) != 0;
return (0L);
}
if(msg == WM_DESTROY)
{
PostQuitMessage(0);
return 0;
}
return (DefWindowProc(hwnd, msg, wParam, lParam));
*/
}
/*
* Function: CheckEvents
* Usage: CheckEvents();
* ---------------------
* This function is called from inside the mouse query functions to
* ensure that pending events are processed.
*/
static void CheckEvents(void)
{
MSG msg;
while (PeekMessage(&msg, graphicsWindow, 0, 0, PM_REMOVE) != 0) {
DispatchMessage(&msg);
}
}
/*
* Function: DoUpdate
* Usage: DoUpdate();
* ------------------
* This function redraws the graphics window by copying bits from
* the offscreen bitmap behind the osdc device context into the
* actual display context.
*/
static void DoUpdate(void)
{
HDC dc;
dc = BeginPaint(graphicsWindow, &ps);
BitBlt(dc, 0, 0, pixelWidth, pixelHeight, osdc, 0, 0, SRCCOPY);
EndPaint(graphicsWindow, &ps);
}
/*
* Function: DisplayClear
* Usage: DisplayClear();
* ----------------------
* This function clears all the bits in the offscreen bitmap.
*/
static void DisplayClear(void)
{
RECT r;
SetRect(&r, 0, 0, pixelWidth, pixelHeight);
InvalidateRect(graphicsWindow, &r, TRUE);
BitBlt(osdc, 0, 0, pixelWidth, pixelHeight, osdc, 0, 0, WHITENESS);
}
/*
* Function: PrepareToDraw
* Usage: PrepareToDraw();
* -----------------------
* This function must be called before any rendering operation
* to ensure the pen modes and colors are correctly set.
*/
static void PrepareToDraw(void)
{
int red, green, blue;
/*
HPEN oldPen;
*/
if (eraseMode) {
DeleteObject(erasePen);
erasePen = (HPEN) CreatePen(PS_SOLID, penSize, eraseColor);
(void) SelectObject(osdc, erasePen);
SetTextColor(osdc, eraseColor);
} else {
if (penColor != previousColor) {
red = colorTable[penColor].red * 256 - Epsilon;
green = colorTable[penColor].green * 256 - Epsilon;
blue = colorTable[penColor].blue * 256 - Epsilon;
drawColor = RGB(red, green, blue);
previousColor = penColor;
}
DeleteObject(drawPen);
drawPen = (HPEN) CreatePen(PS_SOLID, penSize, drawColor);
(void) SelectObject(osdc, drawPen);
(void) SetTextColor(osdc, drawColor);
}
}
/*
* Function: DisplayLine
* Usage: DisplayLine(x, y, dx, dy);
* ---------------------------------
* This function renders a line into the offscreen bitmap. If the
* region is started, it adds the line to the developing polygonal
* region instead.
*/
static void DisplayLine(double x, double y, double dx, double dy)
{
int x0, y0, x1, y1;
RECT r;
PrepareToDraw();
x0 = ScaleX(x);
y0 = ScaleY(y);
x1 = ScaleX(x + dx);
y1 = ScaleY(y + dy);
if (regionState == NoRegion) {
SetLineBB(&r, x, y, dx, dy);
InvalidateRect(graphicsWindow, &r, TRUE);
MoveToEx(osdc, x0, y0, NULL);
LineTo(osdc, x1, y1);
} else {
AddSegment(x0, y0, x1, y1);
}
}
/*
* Function: DisplayArc
* Usage: DisplayArc(xc, yc, rx, ry, start, sweep);
* ------------------------------------------------
* This function is used to draw an arc. The arguments are slightly
* different from those in the client interface because xc and yc
* designate the center. This function is only called if a region
* is not being assembled; if it is, the package calls RenderArc
* instead.
*/
static void DisplayArc(double xc, double yc, double rx, double ry,
double start, double sweep)
{
RECT r;
int xmax, xmin, ymax, ymin;
int ix0, iy0, ix1, iy1;
PrepareToDraw();
SetArcBB(&r, xc, yc, rx, ry, start, sweep);
InvalidateRect(graphicsWindow, &r, TRUE);
xmin = ScaleX(xc - rx);
ymin = ScaleY(yc + ry);
xmax = xmin + PixelsX(2 * rx);
ymax = ymin + PixelsX(2 * ry);
if (sweep < 0) {
start += sweep;
sweep = -sweep;
}
if (start < 0) {
start = 360 - fmod(-start, 360);
} else {
start = fmod(start, 360);
}
ix0 = ScaleX(xc + rx * cos(Radians(start)));
iy0 = ScaleY(yc + ry * sin(Radians(start)));
ix1 = ScaleX(xc + rx * cos(Radians(start + sweep)));
iy1 = ScaleY(yc + ry * sin(Radians(start + sweep)));
Arc(osdc, xmin, ymin, xmax, ymax, ix0, iy0, ix1, iy1);
}
/*
* Function: RenderArc
* Usage: RenderArc(xc, yc, rx, ry, start, sweep);
* -----------------------------------------------
* This function is identical to DisplayArc except that, instead
* of calling the Arc function, RenderArc simulates the arc by
* constructing a path of consecutive segments, which are added
* to the current polygonal region.
*/
static void RenderArc(double x, double y, double rx, double ry,
double start, double sweep)
{
double t, mint, maxt, dt, maxd;
int ix0, iy0, ix1, iy1;
PrepareToDraw();
if (sweep < 0) {
start += sweep;
sweep = -sweep;
}
if (fabs(rx) > fabs(ry)) {
maxd = fabs(rx);
} else {
maxd = fabs(rx);
}
dt = atan2(InchesY(1), maxd);
mint = Radians(start);
maxt = Radians(start + sweep);
ix0 = ScaleX(x + rx * cos(mint));
iy0 = ScaleY(y + ry * sin(mint));
for (t = mint + dt; t < maxt; t += dt) {
if (t > maxt - dt / 2) t = maxt;
ix1 = ScaleX(x + rx * cos(t));
iy1 = ScaleY(y + ry * sin(t));
AddSegment(ix0, iy0, ix1, iy1);
ix0 = ix1;
iy0 = iy1;
}
}
/*
* Function: DisplayText
* Usage: DisplayText(x, y, text);
* -------------------------------
* This function displays a text string at (x, y) in the current
* font and size. The hard work is done in DisplayFont.
*/
static void DisplayText(double x, double y, string text)
{
RECT r;
PrepareToDraw();
SetTextBB(&r, x, y, text);
InvalidateRect(graphicsWindow, &r, TRUE);
SetBkMode(osdc, TRANSPARENT);
TextOut(osdc, ScaleX(x), ScaleY(y) - fontTable[currentFont].ascent, text, strlen(text));
SetBkMode(osdc, OPAQUE);
}
/*
* Function: DisplayFont
* Usage: DisplayFont(font, size, style);
* --------------------------------------
* This function updates the font information used for drawing
* text. The program first uses FindExistingFont to see
* if the desired font/size pair has been entered in the table,
* in which case the program uses the stored handle of the font.
* If not, the program uses CreateFont to try to create an
* appropriate font, accepting only those whose typeface
* matches the desired font string. If an acceptable font
* is found, its data is entered into the font table.
*/
static void DisplayFont(string font, int size, int style)
{
char fontBuffer[MaxFontName + 1];
char faceName[MaxFontName + 1];
string fontName;
HFONT newFont, oldFont;
TEXTMETRIC metrics;
int i, fontIndex;
for (i = 0; (fontBuffer[i] = tolower(font[i])) != '\0'; i++);
if (StringEqual("default", fontBuffer)) {
fontName = DefaultFont;
} else {
fontName = fontBuffer;
}
fontIndex = FindExistingFont(fontName, size, style);
if (fontIndex == -1) {
newFont =
CreateFont(-size, 0, 0, 0,
(style & Bold) ? FW_BOLD : FW_NORMAL,
(style & Italic) != 0,
0, 0, 0, 0, 0, 0, 0, fontName);
if (newFont != NULL) {
oldFont = (HFONT) SelectObject(osdc, newFont);
GetTextFace(osdc, MaxFontName, faceName);
if (PrefixMatch(fontName, faceName)
&& GetTextMetrics(osdc, &metrics)) {
if (nFonts == MaxFonts) Error("Too many fonts loaded");
fontIndex = nFonts++;
fontTable[fontIndex].name = CopyString(fontName);
fontTable[fontIndex].size = size;
fontTable[fontIndex].style = style;
fontTable[fontIndex].font = newFont;
fontTable[fontIndex].ascent = metrics.tmAscent;
fontTable[fontIndex].descent = metrics.tmDescent;
fontTable[fontIndex].height =
metrics.tmHeight + metrics.tmExternalLeading;
fontTable[fontIndex].points =
metrics.tmHeight - metrics.tmInternalLeading;
currentFont = fontIndex;
textFont = CopyString(font);
pointSize = fontTable[fontIndex].points;
textStyle = style;
} else {
(void) SelectObject(osdc, oldFont);
}
}
} else {
(void) SelectObject(osdc, fontTable[fontIndex].font);
currentFont = fontIndex;
textFont = CopyString(font);
pointSize = fontTable[fontIndex].points;
textStyle = style;
}
}
/*
* Function: FindExistingFont
* Usage: fontIndex = FindExistingFont(name, size, style);
* -------------------------------------------------------
* This function searches the font table for a matching font
* entry. The function returns the matching table index or -1 if
* no match is found, The caller has already converted the name
* to lower case to preserve the case-insensitivity requirement.
*/
static int FindExistingFont(string name, int size, int style)
{
int i;
for (i = 0; i < nFonts; i++) {
if (StringEqual(name, fontTable[i].name)
&& size == fontTable[i].size
&& style == fontTable[i].style) return (i);
}
return (-1);
}
/*
* Function: SetLineBB
* Usage: SetLineBB(&rect, x, y, dx, dy);
* --------------------------------------
* This function sets the rectangle dimensions to the bounding
* box of the line.
*/
static void SetLineBB(RECT *rp, double x, double y, double dx, double dy)
{
int x0, y0, x1, y1;
x0 = ScaleX(x);
y0 = ScaleY(y);
x1 = ScaleX(x + dx);
y1 = ScaleY(y + dy);
rp->top = Min(y0, y1);
rp->bottom = Max(y0, y1) + 1;
rp->left = Min(x0, x1);
rp->right = Max(x0, x1) + 1;
}
/*
* Function: SetArcBB
* Usage: SetArcBB(&rect, xc, yc, rx, ry, start, sweep);
* -----------------------------------------------------
* This function sets the rectangle dimensions to the bounding
* box of the arc segment specified by the remaining arguments.
*/
static void SetArcBB(RECT *rp, double xc, double yc,
double rx, double ry, double start, double sweep)
{
int xmax, xmin, ymax, ymin;
int xl, xr, yt, yb;
int ix0, iy0, ix1, iy1;
xmin = ScaleX(xc - rx);
ymin = ScaleY(yc + ry);
xmax = xmin + PixelsX(2 * rx);
ymax = ymin + PixelsX(2 * ry);
if (sweep < 0) {
start += sweep;
sweep = -sweep;
}
if (sweep >= 360) {
SetRect(rp, xmin, ymin, xmax, ymax);
return;
}
if (start < 0) {
start = 360 - fmod(-start, 360);
} else {
start = fmod(start, 360);
}
ix0 = ScaleX(xc + rx * cos(Radians(start)));
iy0 = ScaleY(yc + ry * sin(Radians(start)));
ix1 = ScaleX(xc + rx * cos(Radians(start + sweep)));
iy1 = ScaleY(yc + ry * sin(Radians(start + sweep)));
if (start + sweep > 360) {
xr = xmax;
} else {
xr = Max(ix0, ix1);
}
start = fmod(start + 270, 360);
if (start + sweep > 360) {
yt = ymin;
} else {
yt = Min(iy0, iy1);
}
start = fmod(start + 270, 360);
if (start + sweep > 360) {
xl = xmin;
} else {
xl = Min(ix0, ix1);
}
start = fmod(start + 270, 360);
if (start + sweep > 360) {
yb = ymax;
} else {
yb = Max(iy0, iy1);
}
SetRect(rp, xl, yt, xr, yb);
}
/*
* Function: SetTextBB
* Usage: SetTextBB(&rect, x, y, text);
* -------------------------------------
* This function sets the rectangle dimensions to the bounding
* box of the text string using the current font and size.
*/
static void SetTextBB(RECT *rp, double x, double y, string text)
{
SIZE textSize;
int ix, iy;
if (!GetTextExtentPoint(osdc, text, strlen(text), &textSize)) {
Error("Internal error: Text size calculation failed");
}
ix = ScaleX(x);
iy = ScaleY(y);
SetRect(rp, ix, iy - textSize.cy + fontTable[currentFont].descent,
ix + textSize.cx, iy + fontTable[currentFont].descent);
}
/*
* Functions: StartPolygon, AddSegment, EndPolygon
* Usage: StartPolygon();
* AddSegment(x0, y0, x1, y1);
* AddSegment(x1, y1, x2, y2);
* . . .
* DisplayPolygon();
* ----------------------------------
* These functions implement the notion of a region in the PC
* world, where the easiest shape to fill is a polygon. Calling
* StartPolygon initializes the array polygonPoints so that
* subsequent calls to AddSegment will add points to it.
* The points in the polygon are assumed to be contiguous,
* because the client interface checks for this property.
* Because polygons involving arcs can be quite large, the
* AddSegment code extends the polygonPoints list if needed
* by doubling the size of the array. All storage is freed
* after calling DisplayPolygon.
*/
static void StartPolygon(void)
{
polygonPoints = NewArray(PStartSize, POINT);
polygonSize = PStartSize;
nPolygonPoints = 0;
SetRect(&polygonBounds, LargeInt, LargeInt, 0, 0);
}
static void AddSegment(int x0, int y0, int x1, int y1)
{
if (nPolygonPoints == 0) AddPolygonPoint(x0, y0);
AddPolygonPoint(x1, y1);
}
static void DisplayPolygon(void)
{
int px;
HBRUSH brush, oldBrush;
HPEN oldPen, fillPen;
PrepareToDraw();
InvalidateRect(graphicsWindow, &polygonBounds, TRUE);
if (eraseMode) {
px = 0;
fillPen = erasePen;
} else {
px = regionDensity * (NFills - 1) + 0.5 - Epsilon;
fillPen = drawPen;
}
oldPen = (HPEN) SelectObject(osdc, fillPen);
brush = CreatePatternBrush(fillBitmaps[px]);
if (brush == NULL) {
Error("Internal error: Can't load brush");
}
oldBrush = (HBRUSH) SelectObject(osdc, brush);
Polygon(osdc, polygonPoints, nPolygonPoints);
(void) SelectObject(osdc, oldPen);
if (oldBrush != NULL) (void) SelectObject(osdc, oldBrush);
FreeBlock(polygonPoints);
DeleteObject(brush);
}
/*
* Function: AddPolygonPoint
* Usage: AddPolygonPoint(x, y);
* -----------------------------
* AddPolygonPoint acts as a helper function for AddSegment. This
* function does the work, but AddSegment has a more easily understood
* interface.
*/
static void AddPolygonPoint(int x, int y)
{
POINT *newPolygon;
int i;
if (nPolygonPoints >= polygonSize) {
polygonSize *= 2;
newPolygon = NewArray(polygonSize, POINT);
for (i = 0; i < nPolygonPoints; i++) {
newPolygon[i] = polygonPoints[i];
}
FreeBlock(polygonPoints);
polygonPoints = newPolygon;
}
polygonBounds.left = Min(polygonBounds.left, x);
polygonBounds.right = Max(polygonBounds.right, x);
polygonBounds.top = Min(polygonBounds.top, y);
polygonBounds.bottom = Max(polygonBounds.bottom, y);
polygonPoints[nPolygonPoints].x = x;
polygonPoints[nPolygonPoints].y = y;
nPolygonPoints++;
}
/*
* Function: InitColors
* Usage: InitColors();
* --------------------
* This function defines the built-in colors.
*/
static void InitColors(void)
{
nColors = 0;
DefineColor("Black", 0, 0, 0);
DefineColor("Dark Gray", .35, .35, .35);
DefineColor("Gray", .6, .6, .6);
DefineColor("Light Gray", .75, .75, .75);
DefineColor("White", 1, 1, 1);
DefineColor("Brown", .35, .20, .05);
DefineColor("Red", 1, 0, 0);
DefineColor("Orange", 1, .40, .1);
DefineColor("Yellow", 1, 1, 0);
DefineColor("Green", 0, 1, 0);
DefineColor("Blue", 0, 0, 1);
DefineColor("Violet", .93, .5, .93);
DefineColor("Magenta", 1, 0, 1);
DefineColor("Cyan", 0, 1, 1);
}
/*
* Function: FindColorName
* Usage: index = FindColorName(name);
* -----------------------------------
* This function returns the index of the named color in the
* color table, or -1 if the color does not exist.
*/
static int FindColorName(string name)
{
int i;
for (i = 0; i < nColors; i++) {
if (StringMatch(name, colorTable[i].name)) return (i);
}
return (-1);
}
/*
* Utility functions
* -----------------
* This section contains several extremely short utility functions
* that improve the readability of the code.
*/
/*
* Function: StringMatch
* Usage: if (StringMatch(s1, s2)) . . .
* -------------------------------------
* This function returns TRUE if two strings are equal, ignoring
* case distinctions.
*/
static bool StringMatch(string s1, string s2)
{
register char *cp1, *cp2;
cp1 = s1;
cp2 = s2;
while (tolower(*cp1) == tolower(*cp2)) {
if (*cp1 == '\0') return (TRUE);
cp1++;
cp2++;
}
return (FALSE);
}
/*
* Function: PrefixMatch
* Usage: if (PrefixMatch(prefix, str)) . . .
* -------------------------------------------------
* This function returns TRUE if prefix is the initial substring
* of str, ignoring differences in case.
*/
static bool PrefixMatch(char *prefix, char *str)
{
while (*prefix != '\0') {
if (tolower(*prefix++) != tolower(*str++)) return (FALSE);
}
return (TRUE);
}
/*
* Functions: RectWidth, RectHeight
* Usage: w = RectWidth(&r);
* h = RectHeight(&r);
* --------------------------------
* These functions return the width and height of a rectangle.
*/
static int RectWidth(RECT *rp)
{
return (rp->right - rp->left);
}
static int RectHeight(RECT *rp)
{
return (rp->bottom - rp->top);
}
/*
* Functions: SetRectFromSize
* Usage: SetRectFromSize(&r, x, y, width, height);
* ------------------------------------------------
* This function is similar to SetRect except that it takes width
* and height parameters rather than right and bottom.
*/
static void SetRectFromSize(RECT *rp, int x, int y, int width, int height)
{
SetRect(rp, x, y, x + width, y + height);
}
/*
* Function: Radians
* Usage: radians = Radians(degrees);
* ----------------------------------
* This functions convert an angle in degrees to radians.
*/
static double Radians(double degrees)
{
return (degrees * Pi / 180);
}
/*
* Function: Round
* Usage: n = Round(x);
* --------------------
* This function rounds a double to the nearest integer.
*/
static int Round(double x)
{
return ((int) floor(x + 0.5));
}
/*
* Functions: InchesX, InchesY
* Usage: inches = InchesX(pixels);
* inches = InchesY(pixels);
* --------------------------------
* These functions convert distances measured in pixels to inches.
* Because the resolution may not be uniform in the horizontal and
* vertical directions, the coordinates are treated separately.
*/
static double InchesX(int x)
{
return ((double) x / xResolution);
}
static double InchesY(int y)
{
return ((double) y / yResolution);
}
/*
* Functions: PixelsX, PixelsY
* Usage: pixels = PixelsX(inches);
* pixels = PixelsY(inches);
* --------------------------------
* These functions convert distances measured in inches to pixels.
*/
static int PixelsX(double x)
{
return (Round(x * xResolution + Epsilon));
}
static int PixelsY(double y)
{
return (Round(y * yResolution + Epsilon));
}
/*
* Functions: ScaleX, ScaleY
* Usage: pixels = ScaleX(inches);
* pixels = ScaleY(inches);
* --------------------------------
* These functions are like PixelsX and PixelsY but convert coordinates
* rather than lengths. The difference is that y-coordinate values must
* be inverted top to bottom to support the cartesian coordinates of
* the graphics.h model.
*/
static int ScaleX(double x)
{
return (PixelsX(x));
}
static int ScaleY(double y)
{
return (PixelsY(windowHeight - y));
}
/*
* Functions: Min, Max
* Usage: min = Min(x, y);
* max = Max(x, y);
* -----------------------
* These functions find the minimum and maximum of two integers.
*/
static int Min(int x, int y)
{
return ((x < y) ? x : y);
}
static int Max(int x, int y)
{
return ((x > y) ? x : y);
}
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
MSG messages; /* Here messages to the application are saved */
Main();
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
FreeConsole();
return messages.wParam;;
}
void registerKeyboardEvent(KeyboardEventCallback callback)
{
g_keyboard = callback;
}
void registerCharEvent(CharEventCallback callback)
{
g_char = callback;
}
void registerMouseEvent(MouseEventCallback callback)
{
g_mouse = callback;
}
void registerTimerEvent(TimerEventCallback callback)
{
g_timer = callback;
}
void cancelKeyboardEvent()
{
g_keyboard = NULL;
}
void cancelCharEvent()
{
g_char = NULL;
}
void cancelMouseEvent()
{
g_mouse = NULL;
}
void cancelTimerEvent()
{
g_timer = NULL;
}
void startTimer(int id,int timeinterval)
{
SetTimer(graphicsWindow, id, timeinterval, NULL);
}
void cancelTimer(int id)
{
KillTimer(graphicsWindow, id);
}
double ScaleXInches(int x) /*x coordinate from pixels to inches*/
{
return (double)x/GetXResolution();
}
double ScaleYInches(int y)/*y coordinate from pixels to inches*/
{
return GetWindowHeight()-(double)y/GetYResolution();
}
#include "maze.h"
void Main()
{
SetWindowTitle("Maze Game");
SetWindowSize(100,100);
InitGraphics();
int i, j, x, y, min;
srand(time(0));
int **Maze = (int**)malloc(Height * sizeof(int *));
for (i = 0; i < Height; i++)
{
Maze[i] = (int*)calloc(Width, sizeof(int));
}
if (Height > Width)
{
min = Width;
}
x = rand() % min;
y = rand() % min;
maze_init(Maze);
maze_generate(x, y, Maze);
maze_end(Maze);
maze_draw(Maze);
for (i = 0; i < Height; i++) free(Maze[i]);
free(Maze);
}
#include "maze.h"
void maze_draw(int **maze)
{
int i, j, fillflag;
double x = 0, y = GetWindowHeight();
double w = GetWindowWidth()/Width, h = GetWindowHeight()/Height;
for (i = 0; i < Height; i++)
{
for (j = 0; j < Width; j++)
{
if (maze[i][j] == WALL)
{
fillflag = 1;
}
else fillflag = 0;
MovePen(x, y);
if( fillflag ) StartFilledRegion(1);
{
SetPenColor("Blue");
DrawLine(0, -h);
DrawLine(w, 0);
DrawLine(0, h);
DrawLine(-w, 0);
}
SetPenColor("Red");
if( fillflag ) EndFilledRegion();
x += w;
}
x = 0;
y -= h;
}
}
#include "maze.h"
void maze_end(int **maze)
{
int i;
maze[2][1] = ROUTE;
for (i = Height - 3; i >= 0; i--)
{
if (maze[i][Width - 3] == ROUTE) {
maze[i][Width - 2] = ROUTE;
break;
}
}
for (i = 2; i <= Height - 1; i++)
{
if (maze[i][2] == ROUTE) {
maze[i][1] = ROUTE;
break;
}
}
}
#include "maze.h"
void maze_generate(int x, int y, int **maze)
{
maze[y][x] = ROUTE;
int i, j, k, mx, my, r, t, length, omx, omy, c;
int d[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
for (i = 0; i < 4; i++)
{
r = rand() % 4;
t = d[0][0];
d[0][0] = d[r][0];
d[r][0] = t;
t = d[0][1];
d[0][1] = d[r][1];
d[r][1] = t;
}
for (i = 0; i < 4; i++)
{
mx = x;
my = y;
if (rank == 0)
{
length = 1;
}
else
{
length = 1 + rand() % rank;
}
while (length > 0)
{
mx += d[i][0];
my += d[i][1];
if (maze[my][mx] == ROUTE)
{
break;
}
c = 0;
for (j = 0; j < 4; j++)
{
omx = mx + d[j][0];
omy = my + d[j][1];
if (maze[omy][omx] == ROUTE)
{
c++;
}
}
if (c > 1)
{
break;
}
length--;
maze[my][mx] = ROUTE;
}
if (length <= 0)
{
maze_generate(mx, my, maze);
}
}
}
#include "maze.h"
void maze_init(int **maze)
{
int i;
for (i = 0; i < Height; i++)
{
maze[i][0] = ROUTE;
maze[i][Width - 1] = ROUTE;
}
for (i = 0; i < Width; i++)
{
maze[0][i] = ROUTE;
maze[Height - 1][i] = ROUTE;
}
}
/*
* File: random.c
* Version: 1.0
* Last modified on Mon Sep 13 10:42:45 1993 by eroberts
* -----------------------------------------------------
* This file implements the random.h interface.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "genlib.h"
#include "random.h"
/*
* Function: Randomize
* -------------------
* This function operates by setting the random number
* seed to the current time. The srand function is
* provided by the <stdlib.h> library and requires an
* integer argument. The time function is provided
* by <time.h>.
*/
void Randomize(void)
{
srand((int) time(NULL));
}
/*
* Function: RandomInteger
* -----------------------
* This function first obtains a random integer in
* the range [0..RAND_MAX] by applying four steps:
* (1) Generate a real number between 0 and 1.
* (2) Scale it to the appropriate range size.
* (3) Truncate the value to an integer.
* (4) Translate it to the appropriate starting point.
*/
int RandomInteger(int low, int high)
{
int k;
double d;
d = (double) rand() / ((double) RAND_MAX + 1);
k = (int) (d * (high - low + 1));
return (low + k);
}
/*
* Function: RandomReal
* --------------------
* The implementation of RandomReal is similar to that
* of RandomInteger, without the truncation step.
*/
double RandomReal(double low, double high)
{
double d;
d = (double) rand() / ((double) RAND_MAX + 1);
return (low + d * (high - low));
}
/*
* Function: RandomChance
* ----------------------
* This function uses RandomReal to generate a number
* between 0 and 100, which it then compares to p.
*/
bool RandomChance(double p)
{
return (RandomReal(0, 1) < p);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment