| 1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
| 2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
| 3 | #include "BsASTFX.h" |
| 4 | #include "BsMMAlloc.h" |
| 5 | #include <assert.h> |
| 6 | |
| 7 | OptionInfo OPTION_LOOKUP[] = |
| 8 | { |
| 9 | { OT_None, ODT_Int }, |
| 10 | { OT_Options, ODT_Complex }, |
| 11 | { OT_Separable, ODT_Bool }, |
| 12 | { OT_Priority, ODT_Int }, |
| 13 | { OT_Sort, ODT_Int }, |
| 14 | { OT_Transparent, ODT_Bool }, |
| 15 | { OT_Shader, ODT_Complex }, |
| 16 | { OT_SubShader, ODT_Complex }, |
| 17 | { OT_Mixin, ODT_String }, |
| 18 | { OT_Raster, ODT_Complex }, |
| 19 | { OT_Depth, ODT_Complex }, |
| 20 | { OT_Stencil, ODT_Complex }, |
| 21 | { OT_Blend, ODT_Complex }, |
| 22 | { OT_FeatureSet, ODT_String }, |
| 23 | { OT_Pass, ODT_Complex }, |
| 24 | { OT_FillMode, ODT_Int }, |
| 25 | { OT_CullMode, ODT_Int }, |
| 26 | { OT_DepthBias, ODT_Float }, |
| 27 | { OT_SDepthBias, ODT_Float }, |
| 28 | { OT_DepthClip, ODT_Bool }, |
| 29 | { OT_Scissor, ODT_Bool }, |
| 30 | { OT_Multisample, ODT_Bool }, |
| 31 | { OT_AALine, ODT_Bool }, |
| 32 | { OT_DepthRead, ODT_Bool }, |
| 33 | { OT_DepthWrite, ODT_Bool }, |
| 34 | { OT_CompareFunc, ODT_Int }, |
| 35 | { OT_StencilReadMask, ODT_Int }, |
| 36 | { OT_StencilWriteMask, ODT_Int }, |
| 37 | { OT_StencilOpFront, ODT_Complex }, |
| 38 | { OT_StencilOpBack, ODT_Complex }, |
| 39 | { OT_PassOp, ODT_Int }, |
| 40 | { OT_Fail, ODT_Int }, |
| 41 | { OT_ZFail, ODT_Int }, |
| 42 | { OT_AlphaToCoverage, ODT_Bool }, |
| 43 | { OT_IndependantBlend, ODT_Bool }, |
| 44 | { OT_Target, ODT_Complex }, |
| 45 | { OT_Index, ODT_Int }, |
| 46 | { OT_Enabled, ODT_Bool }, |
| 47 | { OT_Color, ODT_Complex }, |
| 48 | { OT_Alpha, ODT_Complex }, |
| 49 | { OT_WriteMask, ODT_Int }, |
| 50 | { OT_Source, ODT_Int }, |
| 51 | { OT_Dest, ODT_Int }, |
| 52 | { OT_Op, ODT_Int }, |
| 53 | { OT_Identifier, ODT_String }, |
| 54 | { OT_Code, ODT_Complex }, |
| 55 | { OT_StencilRef, ODT_Int }, |
| 56 | { OT_Tags, ODT_Complex }, |
| 57 | { OT_TagValue, ODT_String }, |
| 58 | { OT_Variations, ODT_Complex }, |
| 59 | { OT_Variation, ODT_Complex }, |
| 60 | { OT_VariationValue, ODT_Int }, |
| 61 | { OT_Forward, ODT_Bool }, |
| 62 | { OT_Attributes, ODT_Complex }, |
| 63 | { OT_AttrName, ODT_String }, |
| 64 | { OT_VariationOption, ODT_Complex }, |
| 65 | { OT_AttrShow, ODT_Int }, |
| 66 | }; |
| 67 | |
| 68 | NodeOptions* nodeOptionsCreate(void* context) |
| 69 | { |
| 70 | static const int BUFFER_SIZE = 5; |
| 71 | |
| 72 | NodeOptions* options = (NodeOptions*)mmalloc(context, sizeof(NodeOptions)); |
| 73 | options->count = 0; |
| 74 | options->bufferSize = BUFFER_SIZE; |
| 75 | |
| 76 | options->entries = (NodeOption*)mmalloc(context, sizeof(NodeOption) * options->bufferSize); |
| 77 | memset(options->entries, 0, sizeof(NodeOption) * options->bufferSize); |
| 78 | |
| 79 | return options; |
| 80 | } |
| 81 | |
| 82 | void nodeOptionDelete(NodeOption* option) |
| 83 | { |
| 84 | if (OPTION_LOOKUP[(int)option->type].dataType == ODT_Complex) |
| 85 | { |
| 86 | nodeDelete(option->value.nodePtr); |
| 87 | option->value.nodePtr = 0; |
| 88 | } |
| 89 | else if (OPTION_LOOKUP[(int)option->type].dataType == ODT_String) |
| 90 | { |
| 91 | mmfree((void*)option->value.strValue); |
| 92 | option->value.strValue = 0; |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | void nodeOptionsDelete(NodeOptions* options) |
| 97 | { |
| 98 | int i = 0; |
| 99 | |
| 100 | for (i = 0; i < options->count; i++) |
| 101 | nodeOptionDelete(&options->entries[i]); |
| 102 | |
| 103 | mmfree(options->entries); |
| 104 | mmfree(options); |
| 105 | } |
| 106 | |
| 107 | void nodeOptionsResize(void* context, NodeOptions* options, int size) |
| 108 | { |
| 109 | NodeOption* originalEntries = options->entries; |
| 110 | int originalSize = options->bufferSize; |
| 111 | int elementsToCopy = originalSize; |
| 112 | int sizeToCopy = 0; |
| 113 | |
| 114 | options->bufferSize = size; |
| 115 | if (options->count > options->bufferSize) |
| 116 | options->count = options->bufferSize; |
| 117 | |
| 118 | if (elementsToCopy > size) |
| 119 | elementsToCopy = size; |
| 120 | |
| 121 | sizeToCopy = elementsToCopy * sizeof(NodeOption); |
| 122 | |
| 123 | options->entries = (NodeOption*)mmalloc(context, sizeof(NodeOption) * options->bufferSize); |
| 124 | |
| 125 | memcpy(options->entries, originalEntries, sizeToCopy); |
| 126 | memset(options->entries + elementsToCopy, 0, sizeof(NodeOption) * options->bufferSize - sizeToCopy); |
| 127 | |
| 128 | mmfree(originalEntries); |
| 129 | } |
| 130 | |
| 131 | void nodeOptionsGrowIfNeeded(void* context, NodeOptions* options) |
| 132 | { |
| 133 | static const int BUFFER_GROW = 10; |
| 134 | |
| 135 | if (options->count == options->bufferSize) |
| 136 | nodeOptionsResize(context, options, options->bufferSize + BUFFER_GROW); |
| 137 | } |
| 138 | |
| 139 | void nodeOptionsAdd(void* context, NodeOptions* options, const NodeOption* option) |
| 140 | { |
| 141 | nodeOptionsGrowIfNeeded(context, options); |
| 142 | |
| 143 | options->entries[options->count] = *option; |
| 144 | options->count++; |
| 145 | } |
| 146 | |
| 147 | ASTFXNode* nodeCreate(void* context, NodeType type) |
| 148 | { |
| 149 | ASTFXNode* node = (ASTFXNode*)mmalloc(context, sizeof(ASTFXNode)); |
| 150 | node->options = nodeOptionsCreate(context); |
| 151 | node->type = type; |
| 152 | |
| 153 | return node; |
| 154 | } |
| 155 | |
| 156 | void nodeDelete(ASTFXNode* node) |
| 157 | { |
| 158 | nodeOptionsDelete(node->options); |
| 159 | |
| 160 | mmfree(node); |
| 161 | } |
| 162 | |
| 163 | void nodePush(ParseState* parseState, ASTFXNode* node) |
| 164 | { |
| 165 | NodeLink* linkNode = (NodeLink*)mmalloc(parseState->memContext, sizeof(NodeLink)); |
| 166 | linkNode->next = parseState->nodeStack; |
| 167 | linkNode->node = node; |
| 168 | |
| 169 | parseState->nodeStack = linkNode; |
| 170 | parseState->topNode = node; |
| 171 | } |
| 172 | |
| 173 | void nodePop(ParseState* parseState) |
| 174 | { |
| 175 | if (!parseState->nodeStack) |
| 176 | return; |
| 177 | |
| 178 | NodeLink* toRemove = parseState->nodeStack; |
| 179 | parseState->nodeStack = toRemove->next; |
| 180 | |
| 181 | if (parseState->nodeStack) |
| 182 | parseState->topNode = parseState->nodeStack->node; |
| 183 | else |
| 184 | parseState->topNode = 0; |
| 185 | |
| 186 | mmfree(toRemove); |
| 187 | } |
| 188 | |
| 189 | void beginCodeBlock(ParseState* parseState, RawCodeType type) |
| 190 | { |
| 191 | RawCode* rawCodeBlock = (RawCode*)mmalloc(parseState->memContext, sizeof(RawCode)); |
| 192 | rawCodeBlock->index = parseState->numRawCodeBlocks[type]; |
| 193 | rawCodeBlock->size = 0; |
| 194 | rawCodeBlock->capacity = 4096; |
| 195 | rawCodeBlock->code = mmalloc(parseState->memContext, rawCodeBlock->capacity); |
| 196 | rawCodeBlock->next = parseState->rawCodeBlock[type]; |
| 197 | |
| 198 | parseState->numRawCodeBlocks[type]++; |
| 199 | parseState->rawCodeBlock[type] = rawCodeBlock; |
| 200 | |
| 201 | // Insert defines for code-blocks as we don't perform pre-processing within code blocks but we still want outer defines |
| 202 | // to be recognized by them (Performing pre-processing for code blocks is problematic because it would require parsing |
| 203 | // of all the language syntax in order to properly handle macro replacement). |
| 204 | for (int i = 0; i < parseState->numDefines; i++) |
| 205 | { |
| 206 | const char* define = "#define " ; |
| 207 | |
| 208 | appendCodeBlock(parseState, type, define, (int)strlen(define)); |
| 209 | appendCodeBlock(parseState, type, parseState->defines[i].name, (int)strlen(parseState->defines[i].name)); |
| 210 | |
| 211 | if (parseState->defines[i].expr != 0) |
| 212 | { |
| 213 | appendCodeBlock(parseState, type, " " , 1); |
| 214 | appendCodeBlock(parseState, type, parseState->defines[i].expr, (int)strlen(parseState->defines[i].expr)); |
| 215 | } |
| 216 | |
| 217 | appendCodeBlock(parseState, type, "\n" , 1); |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | void appendCodeBlock(ParseState* parseState, RawCodeType type, const char* value, int size) |
| 222 | { |
| 223 | RawCode* rawCode = parseState->rawCodeBlock[type]; |
| 224 | |
| 225 | if ((rawCode->size + size) > rawCode->capacity) |
| 226 | { |
| 227 | int newCapacity = rawCode->capacity; |
| 228 | do |
| 229 | { |
| 230 | newCapacity *= 2; |
| 231 | } while ((rawCode->size + size) > newCapacity); |
| 232 | |
| 233 | char* newBuffer = mmalloc(parseState->memContext, newCapacity); |
| 234 | memcpy(newBuffer, rawCode->code, rawCode->size); |
| 235 | mmfree(rawCode->code); |
| 236 | |
| 237 | rawCode->code = newBuffer; |
| 238 | rawCode->capacity = newCapacity; |
| 239 | } |
| 240 | |
| 241 | memcpy(&rawCode->code[rawCode->size], value, size); |
| 242 | rawCode->size += size; |
| 243 | } |
| 244 | |
| 245 | int getCodeBlockIndex(ParseState* parseState, RawCodeType type) |
| 246 | { |
| 247 | return parseState->rawCodeBlock[type]->index; |
| 248 | } |
| 249 | |
| 250 | char* getCurrentFilename(ParseState* parseState) |
| 251 | { |
| 252 | if (!parseState->includeStack) |
| 253 | return NULL; |
| 254 | |
| 255 | return parseState->includeStack->data->filename; |
| 256 | } |
| 257 | |
| 258 | void addDefine(ParseState* parseState, const char* value) |
| 259 | { |
| 260 | int defineIdx = parseState->numDefines; |
| 261 | parseState->numDefines++; |
| 262 | |
| 263 | if(parseState->numDefines > parseState->defineCapacity) |
| 264 | { |
| 265 | int newCapacity = parseState->defineCapacity * 2; |
| 266 | DefineEntry* newDefines = mmalloc(parseState->memContext, newCapacity * sizeof(DefineEntry)); |
| 267 | |
| 268 | memcpy(newDefines, parseState->defines, parseState->defineCapacity * sizeof(DefineEntry)); |
| 269 | |
| 270 | mmfree(parseState->defines); |
| 271 | parseState->defines = newDefines; |
| 272 | parseState->defineCapacity = newCapacity; |
| 273 | } |
| 274 | |
| 275 | parseState->defines[defineIdx].name = mmalloc_strdup(parseState->memContext, value); |
| 276 | parseState->defines[defineIdx].expr = 0; |
| 277 | } |
| 278 | |
| 279 | void addDefineExpr(ParseState* parseState, const char* value) |
| 280 | { |
| 281 | int defineIdx = parseState->numDefines - 1; |
| 282 | if(defineIdx < 0) |
| 283 | { |
| 284 | assert(0); |
| 285 | return; |
| 286 | } |
| 287 | |
| 288 | parseState->defines[defineIdx].expr = mmalloc_strdup(parseState->memContext, value); |
| 289 | } |
| 290 | |
| 291 | int hasDefine(ParseState* parseState, const char* value) |
| 292 | { |
| 293 | for (int i = 0; i < parseState->numDefines; i++) |
| 294 | { |
| 295 | if (strcmp(parseState->defines[i].name, value) == 0) |
| 296 | return 1; |
| 297 | } |
| 298 | |
| 299 | return 0; |
| 300 | } |
| 301 | |
| 302 | int isDefineEnabled(ParseState* parseState, const char* value) |
| 303 | { |
| 304 | for (int i = 0; i < parseState->numDefines; i++) |
| 305 | { |
| 306 | if (strcmp(parseState->defines[i].name, value) == 0) |
| 307 | { |
| 308 | if(parseState->defines[i].expr == 0) |
| 309 | return 0; |
| 310 | |
| 311 | int val = atoi(parseState->defines[i].expr); |
| 312 | return val != 0; |
| 313 | } |
| 314 | } |
| 315 | |
| 316 | return 0; |
| 317 | } |
| 318 | |
| 319 | void removeDefine(ParseState* parseState, const char* value) |
| 320 | { |
| 321 | for (int i = 0; i < parseState->numDefines; i++) |
| 322 | { |
| 323 | if (strcmp(parseState->defines[i].name, value) == 0) |
| 324 | { |
| 325 | int remaining = parseState->numDefines - (i + 1); |
| 326 | |
| 327 | if(remaining > 0) |
| 328 | memcpy(&parseState->defines[i], &parseState->defines[i + 1], remaining * sizeof(DefineEntry)); |
| 329 | |
| 330 | parseState->numDefines--; |
| 331 | } |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | int pushConditionalDef(ParseState* parseState, int state) |
| 336 | { |
| 337 | ConditionalData* conditional = mmalloc(parseState->memContext, sizeof(ConditionalData)); |
| 338 | conditional->enabled = state && (parseState->conditionalStack == 0 || parseState->conditionalStack->enabled); |
| 339 | conditional->selfEnabled = state; |
| 340 | conditional->name = NULL; |
| 341 | conditional->op = CO_None; |
| 342 | conditional->value = NULL; |
| 343 | conditional->next = parseState->conditionalStack; |
| 344 | |
| 345 | parseState->conditionalStack = conditional; |
| 346 | |
| 347 | return conditional->enabled; |
| 348 | } |
| 349 | |
| 350 | void pushConditional(ParseState* parseState, const char* name) |
| 351 | { |
| 352 | ConditionalData* conditional = mmalloc(parseState->memContext, sizeof(ConditionalData)); |
| 353 | conditional->enabled = (parseState->conditionalStack == 0 || parseState->conditionalStack->enabled); |
| 354 | conditional->selfEnabled = 0; |
| 355 | conditional->op = CO_None; |
| 356 | conditional->value = NULL; |
| 357 | conditional->name = NULL; |
| 358 | conditional->next = parseState->conditionalStack; |
| 359 | |
| 360 | if(name) |
| 361 | conditional->name = mmalloc_strdup(parseState->memContext, name); |
| 362 | |
| 363 | parseState->conditionalStack = conditional; |
| 364 | } |
| 365 | |
| 366 | void setConditional(ParseState* parseState, const char* name) |
| 367 | { |
| 368 | assert(parseState->conditionalStack > 0); |
| 369 | |
| 370 | ConditionalData* conditional = parseState->conditionalStack; |
| 371 | ConditionalData* parent = conditional->next; |
| 372 | |
| 373 | conditional->name = mmalloc_strdup(parseState->memContext, name); |
| 374 | conditional->enabled = (parent == 0 || parent->enabled); |
| 375 | conditional->selfEnabled = 0; |
| 376 | } |
| 377 | |
| 378 | void setConditionalOp(ParseState* parseState, ConditionalOp op) |
| 379 | { |
| 380 | assert(parseState->conditionalStack > 0); |
| 381 | |
| 382 | ConditionalData* conditional = parseState->conditionalStack; |
| 383 | conditional->op = op; |
| 384 | } |
| 385 | |
| 386 | void setConditionalVal(ParseState* parseState, const char* value) |
| 387 | { |
| 388 | assert(parseState->conditionalStack > 0); |
| 389 | |
| 390 | ConditionalData* conditional = parseState->conditionalStack; |
| 391 | conditional->value = mmalloc_strdup(parseState->memContext, value); |
| 392 | } |
| 393 | |
| 394 | int evalConditional(ParseState* parseState) |
| 395 | { |
| 396 | assert(parseState->conditionalStack > 0); |
| 397 | |
| 398 | ConditionalData* conditional = parseState->conditionalStack; |
| 399 | if(!conditional->name) |
| 400 | { |
| 401 | conditional->enabled = 0; |
| 402 | return 0; |
| 403 | } |
| 404 | |
| 405 | int myVal = 1; |
| 406 | if(conditional->value) |
| 407 | myVal = atoi(conditional->value); |
| 408 | |
| 409 | for (int i = 0; i < parseState->numDefines; i++) |
| 410 | { |
| 411 | if (strcmp(parseState->defines[i].name, conditional->name) == 0) |
| 412 | { |
| 413 | int val = 0; |
| 414 | if(parseState->defines[i].expr) |
| 415 | val = atoi(parseState->defines[i].expr); |
| 416 | |
| 417 | switch(conditional->op) |
| 418 | { |
| 419 | default: |
| 420 | case CO_None: conditional->selfEnabled = val != 0; break; |
| 421 | case CO_Equals: conditional->selfEnabled = myVal == val; break; |
| 422 | case CO_NotEquals: conditional->selfEnabled = myVal != val; break; |
| 423 | case CO_Lesser: conditional->selfEnabled = val < myVal; break; |
| 424 | case CO_Greater: conditional->selfEnabled = val > myVal; break; |
| 425 | case CO_LesserEqual: conditional->selfEnabled = val <= myVal; break; |
| 426 | case CO_GreaterEqual: conditional->selfEnabled = val >= myVal; break; |
| 427 | } |
| 428 | } |
| 429 | } |
| 430 | |
| 431 | conditional->enabled &= conditional->selfEnabled; |
| 432 | return conditional->enabled; |
| 433 | } |
| 434 | |
| 435 | int setConditionalState(ParseState* parseState, int state) |
| 436 | { |
| 437 | if (parseState->conditionalStack == 0) |
| 438 | return 1; |
| 439 | |
| 440 | ConditionalData* conditional = parseState->conditionalStack; |
| 441 | ConditionalData* parent = conditional->next; |
| 442 | |
| 443 | conditional->enabled = state && (parent == 0 || parent->enabled); |
| 444 | conditional->selfEnabled = state; |
| 445 | |
| 446 | return conditional->enabled; |
| 447 | } |
| 448 | |
| 449 | int switchConditional(ParseState* parseState) |
| 450 | { |
| 451 | if (parseState->conditionalStack == 0) |
| 452 | return 1; |
| 453 | |
| 454 | ConditionalData* conditional = parseState->conditionalStack; |
| 455 | return setConditionalState(parseState, !conditional->selfEnabled); |
| 456 | } |
| 457 | |
| 458 | int popConditional(ParseState* parseState) |
| 459 | { |
| 460 | if (parseState->conditionalStack == 0) |
| 461 | return 1; |
| 462 | |
| 463 | ConditionalData* conditional = parseState->conditionalStack; |
| 464 | parseState->conditionalStack = conditional->next; |
| 465 | |
| 466 | if(conditional->value) |
| 467 | mmfree(conditional->value); |
| 468 | |
| 469 | if(conditional->name) |
| 470 | mmfree(conditional->name); |
| 471 | |
| 472 | mmfree(conditional); |
| 473 | |
| 474 | return parseState->conditionalStack == 0 || parseState->conditionalStack->enabled; |
| 475 | } |
| 476 | |
| 477 | ParseState* parseStateCreate() |
| 478 | { |
| 479 | ParseState* parseState = (ParseState*)malloc(sizeof(ParseState)); |
| 480 | parseState->memContext = mmalloc_new_context(); |
| 481 | parseState->rootNode = nodeCreate(parseState->memContext, NT_Root); |
| 482 | parseState->topNode = 0; |
| 483 | parseState->nodeStack = 0; |
| 484 | parseState->includeStack = 0; |
| 485 | parseState->includes = 0; |
| 486 | parseState->rawCodeBlock[0] = 0; |
| 487 | parseState->rawCodeBlock[1] = 0; |
| 488 | parseState->numRawCodeBlocks[0] = 0; |
| 489 | parseState->numRawCodeBlocks[1] = 0; |
| 490 | parseState->numOpenBrackets = 0; |
| 491 | |
| 492 | parseState->hasError = 0; |
| 493 | parseState->errorLine = 0; |
| 494 | parseState->errorColumn = 0; |
| 495 | parseState->errorMessage = 0; |
| 496 | parseState->errorFile = 0; |
| 497 | |
| 498 | parseState->conditionalStack = 0; |
| 499 | parseState->defineCapacity = 10; |
| 500 | parseState->numDefines = 0; |
| 501 | parseState->defines = mmalloc(parseState->memContext, parseState->defineCapacity * sizeof(DefineEntry)); |
| 502 | |
| 503 | nodePush(parseState, parseState->rootNode); |
| 504 | |
| 505 | return parseState; |
| 506 | } |
| 507 | |
| 508 | void parseStateDelete(ParseState* parseState) |
| 509 | { |
| 510 | while (parseState->nodeStack != 0) |
| 511 | nodePop(parseState); |
| 512 | |
| 513 | nodeDelete(parseState->rootNode); |
| 514 | mmalloc_free_context(parseState->memContext); |
| 515 | |
| 516 | free(parseState); |
| 517 | } |