Start of variable support. Not working properly yet.
This commit is contained in:
parent
ffe9b5224d
commit
06ca429d82
3 changed files with 592 additions and 256 deletions
|
@ -37,10 +37,30 @@ enum ParserKeywordE {
|
||||||
PARSE_PALETTE,
|
PARSE_PALETTE,
|
||||||
PARSE_PLOT,
|
PARSE_PLOT,
|
||||||
PARSE_RECTANGLE,
|
PARSE_RECTANGLE,
|
||||||
PARSE_RESET
|
PARSE_RESET,
|
||||||
|
// After this are keywords for things that aren't commands but still need to emit bytecode.
|
||||||
|
PARSE_MATH,
|
||||||
|
PARSE_LABEL
|
||||||
};
|
};
|
||||||
typedef enum ParserKeywordE ParserKeywordT;
|
typedef enum ParserKeywordE ParserKeywordT;
|
||||||
|
|
||||||
|
enum ParserMathE {
|
||||||
|
MATH_NONE = 0,
|
||||||
|
MATH_ASSIGN,
|
||||||
|
MATH_ADD,
|
||||||
|
MATH_SUBTRACT,
|
||||||
|
MATH_MULTIPLY,
|
||||||
|
MATH_DIVIDE,
|
||||||
|
MATH_MOD,
|
||||||
|
MATH_POW,
|
||||||
|
MATH_SQRT,
|
||||||
|
MATH_ABS,
|
||||||
|
MATH_COS,
|
||||||
|
MATH_SIN,
|
||||||
|
MATH_TAN
|
||||||
|
};
|
||||||
|
typedef enum ParserMathE ParserMathT;
|
||||||
|
|
||||||
|
|
||||||
typedef struct PointS {
|
typedef struct PointS {
|
||||||
int x;
|
int x;
|
||||||
|
|
306
src/vecparse.c
306
src/vecparse.c
|
@ -20,24 +20,33 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "vecparse.h"
|
#include "vecparse.h"
|
||||||
|
|
||||||
|
|
||||||
typedef struct CommandsS {
|
#define IS_NUMBER(n) (n & 0x8000 ? TRUE : FALSE)
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct KeywordsS {
|
||||||
char *command;
|
char *command;
|
||||||
ParserKeywordT keyword;
|
ParserKeywordT id;
|
||||||
} CommandsT;
|
} KeywordsT;
|
||||||
|
|
||||||
|
typedef struct OperatorsS {
|
||||||
|
char *operator;
|
||||||
|
ParserMathT id;
|
||||||
|
} OperatorsT;
|
||||||
|
|
||||||
|
|
||||||
static void ensureBufferSize(VecByteCodeT *bytecode, int needed);
|
static void ensureBufferSize(VecByteCodeT *bytecode, int needed);
|
||||||
static void outputByte(VecByteCodeT *bytecode, unsigned char byte);
|
static void outputByte(VecByteCodeT *bytecode, unsigned short word);
|
||||||
static void outputWord(VecByteCodeT *bytecode, unsigned short word);
|
static void outputWord(VecByteCodeT *bytecode, unsigned short word);
|
||||||
static gboolean parserGetNextValue(char *token, char **valueEnd, int *x);
|
static gboolean parserGetNextValue(char *token, char **valueEnd, char **variables, int *x);
|
||||||
static gboolean parserGetWord(char *word, char **tokenEnd);
|
static gboolean parserGetWord(char *word, char **tokenEnd);
|
||||||
static gboolean parserGetX(char **tokenEnd, int *x);
|
static gboolean parserGetX(char **tokenEnd, char **variables, int *x);
|
||||||
static gboolean parserGetXY(char **tokenEnd, int *x, int *y);
|
static gboolean parserGetXY(char **tokenEnd, char **variables, int *x, int *y);
|
||||||
static gboolean parserGetXYZ(char **tokenEnd, int *x, int *y, int *z);
|
static gboolean parserGetXYZ(char **tokenEnd, char **variables, int *x, int *y, int *z);
|
||||||
|
|
||||||
|
|
||||||
static void ensureBufferSize(VecByteCodeT *bytecode, int needed) {
|
static void ensureBufferSize(VecByteCodeT *bytecode, int needed) {
|
||||||
|
@ -55,8 +64,16 @@ static void ensureBufferSize(VecByteCodeT *bytecode, int needed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void outputByte(VecByteCodeT *bytecode, unsigned char byte) {
|
static void outputByte(VecByteCodeT *bytecode, unsigned short word) {
|
||||||
|
unsigned char byte = (unsigned char)word;
|
||||||
|
|
||||||
ensureBufferSize(bytecode, 1);
|
ensureBufferSize(bytecode, 1);
|
||||||
|
|
||||||
|
// If the word passed in is a variable, set the MSb in the byte as well.
|
||||||
|
if (word & 0x8000) {
|
||||||
|
byte |= 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
bytecode->bytes[bytecode->length++] = byte;
|
bytecode->bytes[bytecode->length++] = byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,18 +85,45 @@ static void outputWord(VecByteCodeT *bytecode, unsigned short word) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean parserGetNextValue(char *token, char **valueEnd, int *x) {
|
static gboolean parserGetNextValue(char *token, char **valueEnd, char **variables, int *x) {
|
||||||
char *value;
|
char *value;
|
||||||
char *endPtr = NULL;
|
char *endPtr = NULL;
|
||||||
|
int index;
|
||||||
|
|
||||||
// Return next value in a comma separated list.
|
// Return next value in a comma separated list.
|
||||||
//***TODO*** Variable support.
|
|
||||||
|
|
||||||
value = strtok_r(token, ",", valueEnd);
|
value = strtok_r(token, ",", valueEnd);
|
||||||
if (value == NULL) return FALSE;
|
if (value == NULL) return FALSE;
|
||||||
|
|
||||||
|
// Is it a variable or number?
|
||||||
|
if (strlen(value) > 1 && value[0] == '%') {
|
||||||
|
|
||||||
|
// It's a variable. Do we know it?
|
||||||
|
*x = -1;
|
||||||
|
for (index=0; index<arrlen(variables); index++) {
|
||||||
|
if (strcasecmp(variables[index], value) == 0) {
|
||||||
|
*x = index; // Found.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*x < 0) return FALSE;
|
||||||
|
// Set MSb to indicate it's a variable.
|
||||||
|
*x |= 0x8000;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// It's a number.
|
||||||
errno = 0; endPtr = NULL;
|
errno = 0; endPtr = NULL;
|
||||||
*x = (int)strtol(value, &endPtr, 10);
|
*x = (int)strtol(value, &endPtr, 10);
|
||||||
if (errno != 0 || *endPtr != 0) return FALSE;
|
if (errno != 0 || *endPtr != 0) return FALSE;
|
||||||
|
// Is it negative? If so, we need it in our format.
|
||||||
|
if (*x < 0) {
|
||||||
|
*x = -*x;
|
||||||
|
*x |= 0x4000;
|
||||||
|
}
|
||||||
|
// Ensure MSb is cleared so we know it's a number.
|
||||||
|
*x &= 0x7fff;
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -98,24 +142,52 @@ static gboolean parserGetWord(char *word, char **tokenEnd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean parserGetX(char **tokenEnd, int *x) {
|
static gboolean parserGetX(char **tokenEnd, char **variables, int *x) {
|
||||||
char *value;
|
char *value;
|
||||||
char *endPtr = NULL;
|
char *endPtr = NULL;
|
||||||
|
int index;
|
||||||
|
|
||||||
// Return single value.
|
// Return single value.
|
||||||
//***TODO*** Variable support.
|
|
||||||
|
|
||||||
value = strtok_r(NULL, " ", tokenEnd);
|
value = strtok_r(NULL, " ", tokenEnd);
|
||||||
if (value == NULL) return FALSE;
|
if (value == NULL) return FALSE;
|
||||||
errno = 0; endPtr = NULL;
|
|
||||||
|
// Is it a variable or number?
|
||||||
|
if (strlen(value) > 1 && value[0] == '%') {
|
||||||
|
|
||||||
|
// It's a variable. Do we know it?
|
||||||
|
*x = -1;
|
||||||
|
for (index=0; index<arrlen(variables); index++) {
|
||||||
|
if (strcasecmp(variables[index], value) == 0) {
|
||||||
|
*x = index; // Found.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*x < 0) return FALSE;
|
||||||
|
// Set MSb to indicate it's a variable.
|
||||||
|
*x |= 0x8000;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// It's a number.
|
||||||
|
errno = 0;
|
||||||
|
endPtr = NULL;
|
||||||
*x = (int)strtol(value, &endPtr, 10);
|
*x = (int)strtol(value, &endPtr, 10);
|
||||||
if (errno != 0 || *endPtr != 0) return FALSE;
|
if (errno != 0 || *endPtr != 0) return FALSE;
|
||||||
|
// Is it negative? If so, we need it in our format.
|
||||||
|
if (*x < 0) {
|
||||||
|
*x = -*x;
|
||||||
|
*x |= 0x4000;
|
||||||
|
}
|
||||||
|
// Ensure MSb is cleared so we know it's a number.
|
||||||
|
*x &= 0x7fff;
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean parserGetXY(char **tokenEnd, int *x, int *y) {
|
static gboolean parserGetXY(char **tokenEnd, char **variables, int *x, int *y) {
|
||||||
char *token;
|
char *token;
|
||||||
char *valueEnd;
|
char *valueEnd;
|
||||||
|
|
||||||
|
@ -124,14 +196,14 @@ static gboolean parserGetXY(char **tokenEnd, int *x, int *y) {
|
||||||
token = strtok_r(NULL, " ", tokenEnd);
|
token = strtok_r(NULL, " ", tokenEnd);
|
||||||
if (token == NULL) return FALSE;
|
if (token == NULL) return FALSE;
|
||||||
|
|
||||||
if (!parserGetNextValue(token, &valueEnd, x)) return FALSE;
|
if (!parserGetNextValue(token, &valueEnd, variables, x)) return FALSE;
|
||||||
if (!parserGetNextValue(NULL, &valueEnd, y)) return FALSE;
|
if (!parserGetNextValue(NULL, &valueEnd, variables, y)) return FALSE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean parserGetXYZ(char **tokenEnd, int *x, int *y, int *z) {
|
static gboolean parserGetXYZ(char **tokenEnd, char **variables, int *x, int *y, int *z) {
|
||||||
char *token;
|
char *token;
|
||||||
char *valueEnd;
|
char *valueEnd;
|
||||||
|
|
||||||
|
@ -140,16 +212,16 @@ static gboolean parserGetXYZ(char **tokenEnd, int *x, int *y, int *z) {
|
||||||
token = strtok_r(NULL, " ", tokenEnd);
|
token = strtok_r(NULL, " ", tokenEnd);
|
||||||
if (token == NULL) return FALSE;
|
if (token == NULL) return FALSE;
|
||||||
|
|
||||||
if (!parserGetNextValue(token, &valueEnd, x)) return FALSE;
|
if (!parserGetNextValue(token, &valueEnd, variables, x)) return FALSE;
|
||||||
if (!parserGetNextValue(NULL, &valueEnd, y)) return FALSE;
|
if (!parserGetNextValue(NULL, &valueEnd, variables, y)) return FALSE;
|
||||||
if (!parserGetNextValue(NULL, &valueEnd, z)) return FALSE;
|
if (!parserGetNextValue(NULL, &valueEnd, variables, z)) return FALSE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
int command;
|
int keyword;
|
||||||
char *line;
|
char *line;
|
||||||
char *lineEnd;
|
char *lineEnd;
|
||||||
gboolean lineOkay;
|
gboolean lineOkay;
|
||||||
|
@ -164,8 +236,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
PointT p1;
|
PointT p1;
|
||||||
PointT p2;
|
PointT p2;
|
||||||
PointT *points = NULL;
|
PointT *points = NULL;
|
||||||
|
char **variables = NULL;
|
||||||
int result = -1; // Returns -1 on success or line number of first error.
|
int result = -1; // Returns -1 on success or line number of first error.
|
||||||
CommandsT commands[] = {
|
KeywordsT commands[] = {
|
||||||
{ "BOX", PARSE_BOX },
|
{ "BOX", PARSE_BOX },
|
||||||
{ "CIRCLE", PARSE_CIRCLE },
|
{ "CIRCLE", PARSE_CIRCLE },
|
||||||
{ "CLEAR", PARSE_CLEAR },
|
{ "CLEAR", PARSE_CLEAR },
|
||||||
|
@ -180,6 +253,21 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
{ "RESET", PARSE_RESET },
|
{ "RESET", PARSE_RESET },
|
||||||
{ NULL, PARSE_NONE }
|
{ NULL, PARSE_NONE }
|
||||||
};
|
};
|
||||||
|
OperatorsT math[] = {
|
||||||
|
{ "=", MATH_ASSIGN },
|
||||||
|
{ "+", MATH_ADD },
|
||||||
|
{ "-", MATH_SUBTRACT },
|
||||||
|
{ "*", MATH_MULTIPLY },
|
||||||
|
{ "/", MATH_DIVIDE },
|
||||||
|
{ "MOD", MATH_MOD },
|
||||||
|
{ "POW", MATH_POW },
|
||||||
|
{ "SQRT", MATH_SQRT },
|
||||||
|
{ "ABS", MATH_ABS },
|
||||||
|
{ "COS", MATH_COS },
|
||||||
|
{ "SIN", MATH_SIN },
|
||||||
|
{ "TAN", MATH_TAN },
|
||||||
|
{ NULL, MATH_NONE }
|
||||||
|
};
|
||||||
|
|
||||||
// Parse code.
|
// Parse code.
|
||||||
lineNumber = 0;
|
lineNumber = 0;
|
||||||
|
@ -189,14 +277,64 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
// Get the first token on the line.
|
// Get the first token on the line.
|
||||||
token = strtok_r(line, " ", &tokenEnd);
|
token = strtok_r(line, " ", &tokenEnd);
|
||||||
|
|
||||||
// Is this something we care about?
|
// Is this something we care about? It'll be math, a label, or a keyword.
|
||||||
command = 0;
|
|
||||||
lineOkay = FALSE;
|
lineOkay = FALSE;
|
||||||
while (commands[command].command) {
|
|
||||||
if (strcasecmp(commands[command].command, token) == 0) {
|
// Is it math?
|
||||||
|
if (strlen(token) > 1 && token[0] == '%') {
|
||||||
|
|
||||||
|
// We're doing some kind of math.
|
||||||
|
|
||||||
|
// Look up variable index in table, or add it if needed.
|
||||||
|
// Variable index is stored in y1 for later.
|
||||||
|
y1 = -1;
|
||||||
|
for (y2=0; y2<arrlen(variables); y2++) {
|
||||||
|
if (strcasecmp(variables[y2], token) == 0) {
|
||||||
|
y1 = y2; // Found.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (y1 < 0) {
|
||||||
|
// Variable is not yet known. Add it to list.
|
||||||
|
arrput(variables, token);
|
||||||
|
y1 = arrlen(variables) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the operator.
|
||||||
|
token = strtok_r(NULL, " ", &tokenEnd);
|
||||||
|
if (token != NULL) {
|
||||||
|
keyword = 0;
|
||||||
|
while (math[keyword].operator) {
|
||||||
|
if (strcasecmp(math[keyword].operator, token) == 0) {
|
||||||
|
// Yep! Gather arguments and generate bytecode.
|
||||||
|
if (!parserGetX(&tokenEnd, variables, &x1)) break;
|
||||||
|
outputByte(bytecode, PARSE_MATH);
|
||||||
|
outputByte(bytecode, y1);
|
||||||
|
outputByte(bytecode, math[keyword].id);
|
||||||
|
outputWord(bytecode, x1);
|
||||||
|
lineOkay = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
keyword++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // doing math
|
||||||
|
|
||||||
|
// Is it a label?
|
||||||
|
if (strlen(token) > 1 && token[strlen(token) - 1] == ':') {
|
||||||
|
|
||||||
|
// It's a label.
|
||||||
|
|
||||||
|
} else { // doing a label
|
||||||
|
|
||||||
|
// It's a keyword.
|
||||||
|
keyword = 0;
|
||||||
|
while (commands[keyword].command) {
|
||||||
|
if (strcasecmp(commands[keyword].command, token) == 0) {
|
||||||
|
|
||||||
// Yep! Gather arguments and generate bytecode.
|
// Yep! Gather arguments and generate bytecode.
|
||||||
switch (commands[command].keyword) {
|
switch (commands[keyword].id) {
|
||||||
|
|
||||||
case PARSE_NONE:
|
case PARSE_NONE:
|
||||||
// Won't happen, but silences an error.
|
// Won't happen, but silences an error.
|
||||||
|
@ -204,11 +342,15 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_BOX:
|
case PARSE_BOX:
|
||||||
// Box (value),(value) to (value),(value)
|
// Box (value),(value) to (value),(value)
|
||||||
if (!parserGetXY(&tokenEnd, &x1, &y1)) break;
|
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
|
||||||
if (!parserGetWord("TO", &tokenEnd)) break;
|
if (!parserGetWord("TO", &tokenEnd)) break;
|
||||||
if (!parserGetXY(&tokenEnd, &x2, &y2)) break;
|
if (!parserGetXY(&tokenEnd, variables, &x2, &y2)) break;
|
||||||
if (x2 < x1 || x1 < 0 || x2 < 0 || x1 > 319 || x2 > 319) break;
|
if (IS_NUMBER(x1) && IS_NUMBER(x2) && x2 < x1) break;
|
||||||
if (y2 < y1 || y1 < 0 || y2 < 0 || y1 > 199 || y2 > 199) break;
|
if (IS_NUMBER(x1) && (x1 < 0 || x1 > 319)) break;
|
||||||
|
if (IS_NUMBER(x2) && (x2 < 0 || x2 > 319)) break;
|
||||||
|
if (IS_NUMBER(y1) && IS_NUMBER(y2) && y2 < y1) break;
|
||||||
|
if (IS_NUMBER(y1) && (y1 < 0 || y1 > 199)) break;
|
||||||
|
if (IS_NUMBER(y2) && (y2 < 0 || y2 > 199)) break;
|
||||||
outputByte(bytecode, PARSE_BOX);
|
outputByte(bytecode, PARSE_BOX);
|
||||||
outputWord(bytecode, x1);
|
outputWord(bytecode, x1);
|
||||||
outputWord(bytecode, y1);
|
outputWord(bytecode, y1);
|
||||||
|
@ -219,11 +361,11 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_CIRCLE:
|
case PARSE_CIRCLE:
|
||||||
// Circle (value) at (value),(value)
|
// Circle (value) at (value),(value)
|
||||||
if (!parserGetX(&tokenEnd, &y2)) break;
|
if (!parserGetX(&tokenEnd, variables, &y2)) break;
|
||||||
if (!parserGetWord("AT", &tokenEnd)) break;
|
if (!parserGetWord("AT", &tokenEnd)) break;
|
||||||
if (!parserGetXY(&tokenEnd, &x1, &y1)) break;
|
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
|
||||||
if (x1 < 0 || x1 > 319) break;
|
if (IS_NUMBER(x1) && (x1 < 0 || x1 > 319)) break;
|
||||||
if (y1 < 0 || y1 > 199) break;
|
if (IS_NUMBER(y1) && (y1 < 0 || y1 > 199)) break;
|
||||||
outputByte(bytecode, PARSE_CIRCLE);
|
outputByte(bytecode, PARSE_CIRCLE);
|
||||||
outputWord(bytecode, y2);
|
outputWord(bytecode, y2);
|
||||||
outputWord(bytecode, x1);
|
outputWord(bytecode, x1);
|
||||||
|
@ -238,8 +380,8 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_COLOR:
|
case PARSE_COLOR:
|
||||||
// Color (short)
|
// Color (short)
|
||||||
if (!parserGetX(&tokenEnd, &x1)) break;
|
if (!parserGetX(&tokenEnd, variables, &x1)) break;
|
||||||
if (x1 < 0 || x1 > 15) break;
|
if (IS_NUMBER(x1) && (x1 < 0 || x1 > 15)) break;
|
||||||
outputByte(bytecode, PARSE_COLOR);
|
outputByte(bytecode, PARSE_COLOR);
|
||||||
outputByte(bytecode, x1);
|
outputByte(bytecode, x1);
|
||||||
lineOkay = TRUE;
|
lineOkay = TRUE;
|
||||||
|
@ -255,11 +397,15 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_ELLIPSE:
|
case PARSE_ELLIPSE:
|
||||||
// Ellipse (value),(value) to (value),(value)
|
// Ellipse (value),(value) to (value),(value)
|
||||||
if (!parserGetXY(&tokenEnd, &x1, &y1)) break;
|
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
|
||||||
if (!parserGetWord("TO", &tokenEnd)) break;
|
if (!parserGetWord("TO", &tokenEnd)) break;
|
||||||
if (!parserGetXY(&tokenEnd, &x2, &y2)) break;
|
if (!parserGetXY(&tokenEnd, variables, &x2, &y2)) break;
|
||||||
if (x2 < x1 || x1 < 0 || x2 < 0 || x1 > 319 || x2 > 319) break;
|
if (IS_NUMBER(x1) && IS_NUMBER(x2) && x2 < x1) break;
|
||||||
if (y2 < y1 || y1 < 0 || y2 < 0 || y1 > 199 || y2 > 199) break;
|
if (IS_NUMBER(x1) && (x1 < 0 || x1 > 319)) break;
|
||||||
|
if (IS_NUMBER(x2) && (x2 < 0 || x2 > 319)) break;
|
||||||
|
if (IS_NUMBER(y1) && IS_NUMBER(y2) && y2 < y1) break;
|
||||||
|
if (IS_NUMBER(y1) && (y1 < 0 || y1 > 199)) break;
|
||||||
|
if (IS_NUMBER(y2) && (y2 < 0 || y2 > 199)) break;
|
||||||
outputByte(bytecode, PARSE_ELLIPSE);
|
outputByte(bytecode, PARSE_ELLIPSE);
|
||||||
outputWord(bytecode, x1);
|
outputWord(bytecode, x1);
|
||||||
outputWord(bytecode, y1);
|
outputWord(bytecode, y1);
|
||||||
|
@ -270,14 +416,14 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_FILL:
|
case PARSE_FILL:
|
||||||
// Fill (value),(value) {to (value}
|
// Fill (value),(value) {to (value}
|
||||||
if (!parserGetXY(&tokenEnd, &x1, &y1)) break;
|
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
|
||||||
if (x1 < 0 || x1 > 319) break;
|
if (IS_NUMBER(x1) && (x1 < 0 || x1 > 319)) break;
|
||||||
if (y1 < 0 || y1 > 199) break;
|
if (IS_NUMBER(y1) && (y1 < 0 || y1 > 199)) break;
|
||||||
// Do they want to fill to a certain color? Or over the current color?
|
// Do they want to fill to a certain color? Or over the current color?
|
||||||
x2 = 16; // 16 == Fill, otherwise FillTo
|
x2 = 16; // 16 == Fill, otherwise FillTo
|
||||||
if (parserGetWord("TO", &tokenEnd)) {
|
if (parserGetWord("TO", &tokenEnd)) {
|
||||||
if (!parserGetX(&tokenEnd, &x2)) break;
|
if (!parserGetX(&tokenEnd, variables, &x2)) break;
|
||||||
if (x2 < 0 || x2 > 15) break;
|
if (IS_NUMBER(x2) && (x2 < 0 || x2 > 15)) break;
|
||||||
}
|
}
|
||||||
outputByte(bytecode, PARSE_FILL);
|
outputByte(bytecode, PARSE_FILL);
|
||||||
outputWord(bytecode, x1);
|
outputWord(bytecode, x1);
|
||||||
|
@ -286,21 +432,25 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
lineOkay = TRUE;
|
lineOkay = TRUE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PARSE_LABEL:
|
||||||
|
// Won't happen.
|
||||||
|
break;
|
||||||
|
|
||||||
case PARSE_LINE:
|
case PARSE_LINE:
|
||||||
// Line (value),(value) to (value),(value) [to ...]
|
// Line (value),(value) to (value),(value) [to ...]
|
||||||
points = NULL;
|
points = NULL;
|
||||||
if (!parserGetXY(&tokenEnd, &p1.x, &p1.y)) break;
|
if (!parserGetXY(&tokenEnd, variables, &p1.x, &p1.y)) break;
|
||||||
if (!parserGetWord("TO", &tokenEnd)) break;
|
if (!parserGetWord("TO", &tokenEnd)) break;
|
||||||
if (!parserGetXY(&tokenEnd, &p2.x, &p2.y)) break;
|
if (!parserGetXY(&tokenEnd, variables, &p2.x, &p2.y)) break;
|
||||||
if (p1.x < 0 || p1.x > 319) break;
|
if (IS_NUMBER(p1.x) && (p1.x < 0 || p1.x > 319)) break;
|
||||||
if (p1.y < 0 || p1.y > 199) break;
|
if (IS_NUMBER(p1.y) && (p1.y < 0 || p1.y > 199)) break;
|
||||||
if (p2.x < 0 || p2.x > 319) break;
|
if (IS_NUMBER(p2.x) && (p2.x < 0 || p2.x > 319)) break;
|
||||||
if (p2.y < 0 || p2.y > 199) break;
|
if (IS_NUMBER(p2.y) && (p2.y < 0 || p2.y > 199)) break;
|
||||||
arrput(points, p1);
|
arrput(points, p1);
|
||||||
arrput(points, p2);
|
arrput(points, p2);
|
||||||
isOkay = TRUE;
|
isOkay = TRUE;
|
||||||
while (parserGetWord("TO", &tokenEnd)) {
|
while (parserGetWord("TO", &tokenEnd)) {
|
||||||
if (!parserGetXY(&tokenEnd, &p1.x, &p1.y)) {
|
if (!parserGetXY(&tokenEnd, variables, &p1.x, &p1.y)) {
|
||||||
// Error. Unwind array.
|
// Error. Unwind array.
|
||||||
while (arrlen(points) > 0) {
|
while (arrlen(points) > 0) {
|
||||||
arrdel(points, 0);
|
arrdel(points, 0);
|
||||||
|
@ -314,7 +464,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
if (isOkay) {
|
if (isOkay) {
|
||||||
outputByte(bytecode, PARSE_LINE);
|
outputByte(bytecode, PARSE_LINE);
|
||||||
outputWord(bytecode, arrlen(points));
|
outputWord(bytecode, arrlen(points));
|
||||||
for (x1=0; x1<arrlen(points); x1++) {
|
for (x1 = 0; x1 < arrlen(points); x1++) {
|
||||||
outputWord(bytecode, points[x1].x);
|
outputWord(bytecode, points[x1].x);
|
||||||
outputWord(bytecode, points[x1].y);
|
outputWord(bytecode, points[x1].y);
|
||||||
}
|
}
|
||||||
|
@ -327,15 +477,19 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PARSE_MATH:
|
||||||
|
// Won't happen.
|
||||||
|
break;
|
||||||
|
|
||||||
case PARSE_PALETTE:
|
case PARSE_PALETTE:
|
||||||
// Palette (short) AS (short),(short),(short)
|
// Palette (short) AS (short),(short),(short)
|
||||||
if (!parserGetX(&tokenEnd, &x1)) break;
|
if (!parserGetX(&tokenEnd, variables, &x1)) break;
|
||||||
if (!parserGetWord("AS", &tokenEnd)) break;
|
if (!parserGetWord("AS", &tokenEnd)) break;
|
||||||
if (!parserGetXYZ(&tokenEnd, &x2, &y1, &y2)) break;
|
if (!parserGetXYZ(&tokenEnd, variables, &x2, &y1, &y2)) break;
|
||||||
if (x1 < 0 || x1 > 15) break;
|
if (IS_NUMBER(x1) && (x1 < 0 || x1 > 15)) break;
|
||||||
if (x2 < 0 || x2 > 15) break;
|
if (IS_NUMBER(x2) && (x2 < 0 || x2 > 15)) break;
|
||||||
if (y1 < 0 || y1 > 15) break;
|
if (IS_NUMBER(y1) && (y1 < 0 || y1 > 15)) break;
|
||||||
if (y2 < 0 || y2 > 15) break;
|
if (IS_NUMBER(y2) && (y2 < 0 || y2 > 15)) break;
|
||||||
outputByte(bytecode, PARSE_PALETTE);
|
outputByte(bytecode, PARSE_PALETTE);
|
||||||
outputByte(bytecode, x1);
|
outputByte(bytecode, x1);
|
||||||
outputByte(bytecode, x2);
|
outputByte(bytecode, x2);
|
||||||
|
@ -346,9 +500,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_PLOT:
|
case PARSE_PLOT:
|
||||||
// Plot (value),(value)
|
// Plot (value),(value)
|
||||||
if (!parserGetXY(&tokenEnd, &x1, &y1)) break;
|
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
|
||||||
if (x1 < 0 || x1 > 319) break;
|
if (IS_NUMBER(x1) && (x1 < 0 || x1 > 319)) break;
|
||||||
if (y1 < 0 || y1 > 199) break;
|
if (IS_NUMBER(y1) && (y1 < 0 || y1 > 199)) break;
|
||||||
outputByte(bytecode, PARSE_PLOT);
|
outputByte(bytecode, PARSE_PLOT);
|
||||||
outputWord(bytecode, x1);
|
outputWord(bytecode, x1);
|
||||||
outputWord(bytecode, y1);
|
outputWord(bytecode, y1);
|
||||||
|
@ -357,11 +511,15 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_RECTANGLE:
|
case PARSE_RECTANGLE:
|
||||||
// Rectangle (value),(value) to (value),(value)
|
// Rectangle (value),(value) to (value),(value)
|
||||||
if (!parserGetXY(&tokenEnd, &x1, &y1)) break;
|
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
|
||||||
if (!parserGetWord("TO", &tokenEnd)) break;
|
if (!parserGetWord("TO", &tokenEnd)) break;
|
||||||
if (!parserGetXY(&tokenEnd, &x2, &y2)) break;
|
if (!parserGetXY(&tokenEnd, variables, &x2, &y2)) break;
|
||||||
if (x2 < x1 || x1 < 0 || x2 < 0 || x1 > 319 || x2 > 319) break;
|
if (IS_NUMBER(x1) && IS_NUMBER(x2) && x2 < x1) break;
|
||||||
if (y2 < y1 || y1 < 0 || y2 < 0 || y1 > 199 || y2 > 199) break;
|
if (IS_NUMBER(x1) && (x1 < 0 || x1 > 319)) break;
|
||||||
|
if (IS_NUMBER(x2) && (x2 < 0 || x2 > 319)) break;
|
||||||
|
if (IS_NUMBER(y1) && IS_NUMBER(y2) && y2 < y1) break;
|
||||||
|
if (IS_NUMBER(y1) && (y1 < 0 || y1 > 199)) break;
|
||||||
|
if (IS_NUMBER(y2) && (y2 < 0 || y2 > 199)) break;
|
||||||
outputByte(bytecode, PARSE_RECTANGLE);
|
outputByte(bytecode, PARSE_RECTANGLE);
|
||||||
outputWord(bytecode, x1);
|
outputWord(bytecode, x1);
|
||||||
outputWord(bytecode, y1);
|
outputWord(bytecode, y1);
|
||||||
|
@ -377,16 +535,20 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
} // switch
|
} // switch
|
||||||
|
|
||||||
// Stop looking for this command - we handled it.
|
// Stop looking for this keyword - we handled it.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Keep looking until we find this command or run out of commands.
|
// Keep looking until we find this keyword or run out of commands.
|
||||||
command++;
|
keyword++;
|
||||||
} // command match
|
} // keyword match
|
||||||
|
|
||||||
} // loop over commands
|
} // loop over commands
|
||||||
|
|
||||||
|
} // label
|
||||||
|
|
||||||
|
} // math
|
||||||
|
|
||||||
// Is everything still okay?
|
// Is everything still okay?
|
||||||
if (!lineOkay) {
|
if (!lineOkay) {
|
||||||
// Nope - error.
|
// Nope - error.
|
||||||
|
|
230
src/vector.c
230
src/vector.c
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <math.h>
|
||||||
#include "scintillaHeaders.h"
|
#include "scintillaHeaders.h"
|
||||||
#include "gladeVector.h"
|
#include "gladeVector.h"
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
|
@ -59,23 +59,42 @@ typedef struct VectorDataS {
|
||||||
cairo_surface_t *trace;
|
cairo_surface_t *trace;
|
||||||
jlContextT *jlc;
|
jlContextT *jlc;
|
||||||
double traceImagePercent;
|
double traceImagePercent;
|
||||||
|
float *variables;
|
||||||
} VectorDataT;
|
} VectorDataT;
|
||||||
|
|
||||||
|
|
||||||
static int _nextEditorId = 0;
|
static int _nextEditorId = 0;
|
||||||
|
|
||||||
|
|
||||||
|
static int byte(VectorDataT *self, unsigned char byte);
|
||||||
EVENT gboolean drawVectorImageDraw(GtkWidget *widget, cairo_t *cr, gpointer userData);
|
EVENT gboolean drawVectorImageDraw(GtkWidget *widget, cairo_t *cr, gpointer userData);
|
||||||
EVENT void drawVectorImageClick(GtkWidget *object, GdkEventButton *event, gpointer userData);
|
EVENT void drawVectorImageClick(GtkWidget *object, GdkEventButton *event, gpointer userData);
|
||||||
EVENT void editorVectorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotification *notifyData, gpointer userData);
|
EVENT void editorVectorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotification *notifyData, gpointer userData);
|
||||||
EVENT void fileVectorTraceImageFileSet(GtkWidget *object, gpointer userData);
|
EVENT void fileVectorTraceImageFileSet(GtkWidget *object, gpointer userData);
|
||||||
|
static int getWord(VecByteCodeT *bytecode, int *index);
|
||||||
EVENT void menuVectorFileClose(GtkWidget *object, gpointer userData);
|
EVENT void menuVectorFileClose(GtkWidget *object, gpointer userData);
|
||||||
static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self);
|
static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self);
|
||||||
EVENT void scaleVectorTraceImageValueChanged(GtkWidget *object, gpointer userData);
|
EVENT void scaleVectorTraceImageValueChanged(GtkWidget *object, gpointer userData);
|
||||||
|
static float variable(VectorDataT *self, unsigned char byte);
|
||||||
|
static int word(VectorDataT *self, unsigned short word);
|
||||||
EVENT gboolean winVectorClose(GtkWidget *object, gpointer userData);
|
EVENT gboolean winVectorClose(GtkWidget *object, gpointer userData);
|
||||||
static void winVectorDelete(gpointer userData);
|
static void winVectorDelete(gpointer userData);
|
||||||
|
|
||||||
|
|
||||||
|
static int byte(VectorDataT *self, unsigned char byte) {
|
||||||
|
int value;
|
||||||
|
// Decode our weird byte format, look up variables, and return sane numbers.
|
||||||
|
// Is this a variable?
|
||||||
|
if (byte & 0x80) {
|
||||||
|
value = variable(self, byte);
|
||||||
|
} else {
|
||||||
|
// Bytes can't be negative in our world, so just return it.
|
||||||
|
value = byte;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
EVENT gboolean drawVectorImageDraw(GtkWidget *widget, cairo_t *cr, gpointer userData) {
|
EVENT gboolean drawVectorImageDraw(GtkWidget *widget, cairo_t *cr, gpointer userData) {
|
||||||
VectorDataT *self = (VectorDataT *)userData;
|
VectorDataT *self = (VectorDataT *)userData;
|
||||||
int width = cairo_image_surface_get_width(self->surface);
|
int width = cairo_image_surface_get_width(self->surface);
|
||||||
|
@ -180,12 +199,12 @@ EVENT void editorVectorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotifi
|
||||||
SSM(SCI_MARKERADD, lineNumber, MARKER_ERROR_ARROW);
|
SSM(SCI_MARKERADD, lineNumber, MARKER_ERROR_ARROW);
|
||||||
SSM(SCI_MARKERADD, lineNumber, MARKER_ERROR_HIGHLIGHT);
|
SSM(SCI_MARKERADD, lineNumber, MARKER_ERROR_HIGHLIGHT);
|
||||||
} else {
|
} else {
|
||||||
// All good!
|
|
||||||
renderBytecode(&byteCode, self);
|
|
||||||
//***DEBUG***
|
//***DEBUG***
|
||||||
FILE *out = fopen("bytecode.bin", "wb");
|
FILE *out = fopen("bytecode.bin", "wb");
|
||||||
fwrite(byteCode.bytes, byteCode.length, 1, out);
|
fwrite(byteCode.bytes, byteCode.length, 1, out);
|
||||||
fclose(out);
|
fclose(out);
|
||||||
|
// All good!
|
||||||
|
renderBytecode(&byteCode, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release bytecode.
|
// Release bytecode.
|
||||||
|
@ -208,6 +227,18 @@ EVENT void editorVectorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotifi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int getWord(VecByteCodeT *bytecode, int *index) {
|
||||||
|
int word;
|
||||||
|
|
||||||
|
word = bytecode->bytes[*index] << 8;
|
||||||
|
*index = *index + 1;
|
||||||
|
word += bytecode->bytes[*index];
|
||||||
|
*index = *index + 1;
|
||||||
|
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
EVENT void fileVectorTraceImageFileSet(GtkWidget *object, gpointer userData) {
|
EVENT void fileVectorTraceImageFileSet(GtkWidget *object, gpointer userData) {
|
||||||
VectorDataT *self = (VectorDataT *)userData;
|
VectorDataT *self = (VectorDataT *)userData;
|
||||||
char *filename;
|
char *filename;
|
||||||
|
@ -282,9 +313,13 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) {
|
||||||
int y2;
|
int y2;
|
||||||
int count;
|
int count;
|
||||||
int i;
|
int i;
|
||||||
|
float f1;
|
||||||
|
float f2;
|
||||||
|
|
||||||
#define GET_BYTE (bytecode->bytes[index++])
|
#define GET_BYTE (bytecode->bytes[index++])
|
||||||
#define GET_WORD ((bytecode->bytes[index++] << 8) + bytecode->bytes[index++])
|
#define GET_WORD getWord(bytecode, &index)
|
||||||
|
|
||||||
|
self->variables = NULL;
|
||||||
|
|
||||||
while (index < bytecode->length) {
|
while (index < bytecode->length) {
|
||||||
switch (bytecode->bytes[index++]) {
|
switch (bytecode->bytes[index++]) {
|
||||||
|
@ -294,18 +329,18 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PARSE_BOX:
|
case PARSE_BOX:
|
||||||
x1 = GET_WORD;
|
x1 = word(self, GET_WORD);
|
||||||
y1 = GET_WORD;
|
y1 = word(self, GET_WORD);
|
||||||
x2 = GET_WORD;
|
x2 = word(self, GET_WORD);
|
||||||
y2 = GET_WORD;
|
y2 = word(self, GET_WORD);
|
||||||
printf("Box %d,%d to %d,%d\n", x1, y1, x2, y2);
|
printf("Box %d,%d to %d,%d\n", x1, y1, x2, y2);
|
||||||
jlDrawBox(self->jlc, x1, y1, x2, y2);
|
jlDrawBox(self->jlc, x1, y1, x2, y2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PARSE_CIRCLE:
|
case PARSE_CIRCLE:
|
||||||
y2 = GET_WORD;
|
y2 = word(self, GET_WORD);
|
||||||
x1 = GET_WORD;
|
x1 = word(self, GET_WORD);
|
||||||
y1 = GET_WORD;
|
y1 = word(self, GET_WORD);
|
||||||
printf("Circle %d at %d,%d\n", y2, x1, y1);
|
printf("Circle %d at %d,%d\n", y2, x1, y1);
|
||||||
jlDrawCircle(self->jlc, x1, y1, y2);
|
jlDrawCircle(self->jlc, x1, y1, y2);
|
||||||
break;
|
break;
|
||||||
|
@ -316,28 +351,28 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PARSE_COLOR:
|
case PARSE_COLOR:
|
||||||
x1 = GET_BYTE;
|
x1 = byte(self, GET_BYTE);
|
||||||
printf("Color %d\n", x1);
|
printf("Color %d\n", x1);
|
||||||
jlDrawColorSet(self->jlc, x1);
|
jlDrawColorSet(self->jlc, x1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PARSE_COMMENT:
|
case PARSE_COMMENT:
|
||||||
// Nothing to do!
|
// Won't happen. Nothing to do!
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PARSE_ELLIPSE:
|
case PARSE_ELLIPSE:
|
||||||
x1 = GET_WORD;
|
x1 = word(self, GET_WORD);
|
||||||
y1 = GET_WORD;
|
y1 = word(self, GET_WORD);
|
||||||
x2 = GET_WORD;
|
x2 = word(self, GET_WORD);
|
||||||
y2 = GET_WORD;
|
y2 = word(self, GET_WORD);
|
||||||
printf("Ellipse %d,%d to %d,%d\n", x1, y1, x2, y2);
|
printf("Ellipse %d,%d to %d,%d\n", x1, y1, x2, y2);
|
||||||
jlDrawEllipse(self->jlc, x1, y1, x2, y2);
|
jlDrawEllipse(self->jlc, x1, y1, x2, y2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PARSE_FILL:
|
case PARSE_FILL:
|
||||||
x1 = GET_WORD;
|
x1 = word(self, GET_WORD);
|
||||||
y1 = GET_WORD;
|
y1 = word(self, GET_WORD);
|
||||||
x2 = GET_BYTE;
|
x2 = byte(self, GET_BYTE);
|
||||||
if (x2 > 15) {
|
if (x2 > 15) {
|
||||||
printf("Fill %d,%d\n", x1, y1);
|
printf("Fill %d,%d\n", x1, y1);
|
||||||
jlDrawFill(self->jlc, x1, y1);
|
jlDrawFill(self->jlc, x1, y1);
|
||||||
|
@ -347,14 +382,17 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PARSE_LABEL:
|
||||||
|
break;
|
||||||
|
|
||||||
case PARSE_LINE:
|
case PARSE_LINE:
|
||||||
count = GET_WORD;
|
count = word(self, GET_WORD);
|
||||||
x1 = GET_WORD;
|
x1 = word(self, GET_WORD);
|
||||||
y1 = GET_WORD;
|
y1 = word(self, GET_WORD);
|
||||||
printf("Line %d,%d", x1, y1);
|
printf("Line %d,%d", x1, y1);
|
||||||
for (i=0; i<count - 1; i++) {
|
for (i=0; i<count - 1; i++) {
|
||||||
x2 = GET_WORD;
|
x2 = word(self, GET_WORD);
|
||||||
y2 = GET_WORD;
|
y2 = word(self, GET_WORD);
|
||||||
printf(" to %d,%d", x2, y2);
|
printf(" to %d,%d", x2, y2);
|
||||||
jlDrawLine(self->jlc, x1, y1, x2, y2);
|
jlDrawLine(self->jlc, x1, y1, x2, y2);
|
||||||
x1 = x2;
|
x1 = x2;
|
||||||
|
@ -363,27 +401,97 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PARSE_MATH:
|
||||||
|
x1 = GET_BYTE; // var index
|
||||||
|
y1 = GET_BYTE; // operand
|
||||||
|
x2 = GET_WORD; // Possible variable
|
||||||
|
if (x2 & 0x8000) {
|
||||||
|
f2 = variable(self, x2);
|
||||||
|
} else {
|
||||||
|
f2 = x2;
|
||||||
|
}
|
||||||
|
f1 = variable(self, x1);
|
||||||
|
switch (y1) {
|
||||||
|
case MATH_NONE:
|
||||||
|
// Well, none!
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATH_ASSIGN:
|
||||||
|
f1 = f2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATH_ADD:
|
||||||
|
f1 += f2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATH_SUBTRACT:
|
||||||
|
f1 -= f2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATH_MULTIPLY:
|
||||||
|
f1 *= f2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATH_DIVIDE:
|
||||||
|
f1 /= f2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATH_MOD:
|
||||||
|
f1 = modff(f1, &f2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATH_POW:
|
||||||
|
f1 = powf(f1, f2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATH_SQRT:
|
||||||
|
f1 = sqrtf(f2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATH_ABS:
|
||||||
|
f1 = fabsf(f2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATH_COS:
|
||||||
|
f1 = cosf(f2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATH_SIN:
|
||||||
|
f1 = sinf(f2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATH_TAN:
|
||||||
|
f1 = tanf(f2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Make sure we have enough slots for this variable.
|
||||||
|
while (arrlen(self->variables) <= x1) {
|
||||||
|
arrput(self->variables, 0.0f);
|
||||||
|
}
|
||||||
|
self->variables[x1] = f1;
|
||||||
|
break;
|
||||||
|
|
||||||
case PARSE_PALETTE:
|
case PARSE_PALETTE:
|
||||||
x1 = GET_BYTE;
|
x1 = byte(self, GET_BYTE);
|
||||||
x2 = GET_BYTE;
|
x2 = byte(self, GET_BYTE);
|
||||||
y1 = GET_BYTE;
|
y1 = byte(self, GET_BYTE);
|
||||||
y2 = GET_BYTE;
|
y2 = byte(self, GET_BYTE);
|
||||||
printf("Palette %d as %d,%d,%d\n", x1, x2, y1, y2);
|
printf("Palette %d as %d,%d,%d\n", x1, x2, y1, y2);
|
||||||
jlPaletteSet(self->jlc, x1, x2, y1, y2);
|
jlPaletteSet(self->jlc, x1, x2, y1, y2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PARSE_PLOT:
|
case PARSE_PLOT:
|
||||||
x1 = GET_WORD;
|
x1 = word(self, GET_WORD);
|
||||||
y1 = GET_WORD;
|
y1 = word(self, GET_WORD);
|
||||||
printf("Plot %d,%d\n", x1, y1);
|
printf("Plot %d,%d\n", x1, y1);
|
||||||
jlDrawPixelSet(self->jlc, x1, y1);
|
jlDrawPixelSet(self->jlc, x1, y1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PARSE_RECTANGLE:
|
case PARSE_RECTANGLE:
|
||||||
x1 = GET_WORD;
|
x1 = word(self, GET_WORD);
|
||||||
y1 = GET_WORD;
|
y1 = word(self, GET_WORD);
|
||||||
x2 = GET_WORD;
|
x2 = word(self, GET_WORD);
|
||||||
y2 = GET_WORD;
|
y2 = word(self, GET_WORD);
|
||||||
printf("Rectangle %d,%d to %d,%d\n", x1, y1, x2, y2);
|
printf("Rectangle %d,%d to %d,%d\n", x1, y1, x2, y2);
|
||||||
jlDrawBoxFilled(self->jlc, x1, y1, x2, y2);
|
jlDrawBoxFilled(self->jlc, x1, y1, x2, y2);
|
||||||
break;
|
break;
|
||||||
|
@ -399,6 +507,12 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) {
|
||||||
} // switch
|
} // switch
|
||||||
} // while
|
} // while
|
||||||
|
|
||||||
|
// Clear variables.
|
||||||
|
while (arrlen(self->variables) > 0) {
|
||||||
|
arrdel(self->variables, 0);
|
||||||
|
}
|
||||||
|
arrfree(self->variables);
|
||||||
|
|
||||||
// Refresh widget.
|
// Refresh widget.
|
||||||
gtk_widget_queue_draw(self->drawVectorImage);
|
gtk_widget_queue_draw(self->drawVectorImage);
|
||||||
}
|
}
|
||||||
|
@ -416,6 +530,43 @@ EVENT void scaleVectorTraceImageValueChanged(GtkWidget *object, gpointer userDat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float variable(VectorDataT *self, unsigned char byte) {
|
||||||
|
int value;
|
||||||
|
|
||||||
|
// Clear possibly set variable flag.
|
||||||
|
byte &= 0xbf;
|
||||||
|
|
||||||
|
// Look up variable and return value.
|
||||||
|
if (byte < arrlen(self->variables)) {
|
||||||
|
value = self->variables[byte];
|
||||||
|
} else {
|
||||||
|
// We don't know this variable yet. Be like BASIC.
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int word(VectorDataT *self, unsigned short word) {
|
||||||
|
int value;
|
||||||
|
// Decode our weird word format, look up variables, and return sane numbers.
|
||||||
|
// Is this a variable?
|
||||||
|
if (word & 0x8000) {
|
||||||
|
value = variable(self, word);
|
||||||
|
} else {
|
||||||
|
// Is it negative?
|
||||||
|
if (word & 0x4000) {
|
||||||
|
// Clear the negative flag and actually negate it.
|
||||||
|
value = 0 - (word & 0xbfff);
|
||||||
|
} else {
|
||||||
|
// Just a boring number, copy it out.
|
||||||
|
value = word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
EVENT gboolean winVectorClose(GtkWidget *object, gpointer userData) {
|
EVENT gboolean winVectorClose(GtkWidget *object, gpointer userData) {
|
||||||
// userData is not reliable due to menuVectorFileClose and util indirectly calling us.
|
// userData is not reliable due to menuVectorFileClose and util indirectly calling us.
|
||||||
VectorDataT *self = (VectorDataT *)utilGetWindowData(object);
|
VectorDataT *self = (VectorDataT *)utilGetWindowData(object);
|
||||||
|
@ -511,10 +662,13 @@ void winVectorCreate(void) {
|
||||||
// Debug
|
// Debug
|
||||||
SSM(SCI_INSERTTEXT, 0, (sptr_t)
|
SSM(SCI_INSERTTEXT, 0, (sptr_t)
|
||||||
"reset\n"
|
"reset\n"
|
||||||
"palette 15 as 15,0,0\n"
|
"%red = 15\n"
|
||||||
"color 15\n"
|
"palette %red as 15,0,0\n"
|
||||||
|
"color %red\n"
|
||||||
"box 0,0 to 319,199\n"
|
"box 0,0 to 319,199\n"
|
||||||
"color 14\n"
|
"%yellow = %red\n"
|
||||||
|
"%yellow - 1\n"
|
||||||
|
"color %yellow\n"
|
||||||
"line 27,22 to 289,24 to 297,169 to 27,166 to 27,23\n"
|
"line 27,22 to 289,24 to 297,169 to 27,166 to 27,23\n"
|
||||||
"color 11\n"
|
"color 11\n"
|
||||||
"circle 50 at 159,95\n"
|
"circle 50 at 159,95\n"
|
||||||
|
|
Loading…
Add table
Reference in a new issue